iterator-zip-iteration-iterator-step-value-abrupt-completion.js (3951B)
1 // Copyright (C) 2025 André Bargull. All rights reserved. 2 // This code is governed by the BSD license found in the LICENSE file. 3 4 /*--- 5 esid: sec-iterator.zipkeyed 6 description: > 7 Handle abrupt completion from IteratorStepValue in IteratorZip. 8 info: | 9 Iterator.zipKeyed ( iterables [ , options ] ) 10 ... 11 16. Return IteratorZip(iters, mode, padding, finishResults). 12 13 IteratorZip ( iters, mode, padding, finishResults ) 14 3. Let closure be a new Abstract Closure with no parameters that captures 15 iters, iterCount, openIters, mode, padding, and finishResults, and 16 performs the following steps when called: 17 ... 18 b. Repeat, 19 ... 20 iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do 21 ... 22 3. Else, 23 a. Let result be Completion(IteratorStepValue(iter)). 24 b. If result is an abrupt completion, then 25 i. Remove iter from openIters. 26 ii. Return ? IteratorCloseAll(openIters, result). 27 ... 28 d. If result is done, then 29 i. Remove iter from openIters. 30 ... 31 32 IteratorCloseAll ( iters, completion ) 33 1. For each element iter of iters, in reverse List order, do 34 a. Set completion to Completion(IteratorClose(iter, completion)). 35 2. Return ? completion. 36 37 IteratorClose ( iteratorRecord, completion ) 38 1. Assert: iteratorRecord.[[Iterator]] is an Object. 39 2. Let iterator be iteratorRecord.[[Iterator]]. 40 3. Let innerResult be Completion(GetMethod(iterator, "return")). 41 4. If innerResult is a normal completion, then 42 a. Let return be innerResult.[[Value]]. 43 b. If return is undefined, return ? completion. 44 c. Set innerResult to Completion(Call(return, iterator)). 45 5. If completion is a throw completion, return ? completion. 46 ... 47 includes: [compareArray.js] 48 features: [joint-iteration] 49 ---*/ 50 51 var modes = [ 52 "shortest", 53 "longest", 54 "strict", 55 ]; 56 57 function ExpectedError() {} 58 59 var log = []; 60 61 var first = { 62 next() { 63 log.push("call first next"); 64 throw new ExpectedError(); 65 }, 66 return() { 67 log.push("unexpected call first return"); 68 } 69 }; 70 71 var second = { 72 next() { 73 log.push("unexpected call second next"); 74 }, 75 return() { 76 // Called with the correct receiver and no arguments. 77 assert.sameValue(this, second); 78 assert.sameValue(arguments.length, 0); 79 80 // NB: Log after above asserts, because failures aren't propagated. 81 log.push("call second return"); 82 83 // IteratorClose ignores new exceptions when called with a Throw completion. 84 throw new Test262Error(); 85 } 86 }; 87 88 var third = { 89 next() { 90 log.push("unexpected call third next"); 91 }, 92 return() { 93 // Called with the correct receiver and no arguments. 94 assert.sameValue(this, third); 95 assert.sameValue(arguments.length, 0); 96 97 // NB: Log after above asserts, because failures aren't propagated. 98 log.push("call third return"); 99 100 // IteratorClose ignores new exceptions when called with a Throw completion. 101 throw new Test262Error(); 102 } 103 }; 104 105 // Empty iterator to ensure |return| is not called for closed iterators. 106 var empty = { 107 next() { 108 log.push("call empty next"); 109 return {done: true}; 110 }, 111 return() { 112 log.push("unexpected call empty return"); 113 } 114 }; 115 116 for (var mode of modes) { 117 var it = Iterator.zipKeyed({first, second, third}, {mode}); 118 119 assert.throws(ExpectedError, function() { 120 it.next(); 121 }); 122 123 assert.compareArray(log, [ 124 "call first next", 125 "call third return", 126 "call second return", 127 ]); 128 129 // Clear log. 130 log.length = 0; 131 } 132 133 // This case applies only when mode is "longest". 134 var it = Iterator.zipKeyed({empty, first, second, third}, {mode: "longest"}); 135 136 assert.throws(ExpectedError, function() { 137 it.next(); 138 }); 139 140 assert.compareArray(log, [ 141 "call empty next", 142 "call first next", 143 "call third return", 144 "call second return", 145 ]); 146 147 reportCompare(0, 0);