Test IteratorZip iteration for zip

This commit is contained in:
André Bargull 2025-07-03 08:38:35 +02:00 committed by Philip Chimento
parent 7b03494c04
commit 4f3a15bdb4
8 changed files with 1024 additions and 0 deletions

View File

@ -0,0 +1,116 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorStep in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
v. Let completion be Completion(Yield(results)).
vi. If completion is an abrupt completion, then
1. Return ? IteratorCloseAll(openIters, completion).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
function ExpectedError() {}
var log = [];
var first = {
next() {
log.push("call first next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, first);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call first return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var second = {
next() {
log.push("call second next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, second);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call second return");
throw new ExpectedError();
}
};
var third = {
next() {
log.push("call third next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
return {};
}
};
var it = Iterator.zip([first, second, third]);
it.next();
assert.throws(ExpectedError, function() {
it.return();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call third next",
"call third return",
"call second return",
"call first return",
]);

View File

@ -0,0 +1,145 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorStepValue in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
a. Let result be Completion(IteratorStepValue(iter)).
b. If result is an abrupt completion, then
i. Remove iter from openIters.
ii. Return ? IteratorCloseAll(openIters, result).
...
d. If result is done, then
i. Remove iter from openIters.
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
var modes = [
"shortest",
"longest",
"strict",
];
function ExpectedError() {}
var log = [];
var first = {
next() {
log.push("call first next");
throw new ExpectedError();
},
return() {
log.push("unexpected call first return");
}
};
var second = {
next() {
log.push("unexpected call second next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, second);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call second return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var third = {
next() {
log.push("unexpected call third next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
// Empty iterator to ensure |return| is not called for closed iterators.
var empty = {
next() {
log.push("call empty next");
return {done: true};
},
return() {
log.push("unexpected call empty return");
}
};
for (var mode of modes) {
var it = Iterator.zip([first, second, third], {mode});
assert.throws(ExpectedError, function() {
it.next();
});
assert.compareArray(log, [
"call first next",
"call third return",
"call second return",
]);
// Clear log.
log.length = 0;
}
// This case applies only when mode is "longest".
var it = Iterator.zip([empty, first, second, third], {mode: "longest"});
assert.throws(ExpectedError, function() {
it.next();
});
assert.compareArray(log, [
"call empty next",
"call first next",
"call third return",
"call second return",
]);

View File

@ -0,0 +1,127 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorStep in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
v. Let completion be Completion(Yield(results)).
vi. If completion is an abrupt completion, then
1. Return ? IteratorCloseAll(openIters, completion).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
function ExpectedError() {}
var log = [];
var first = {
next() {
log.push("call first next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, first);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call first return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var second = {
next() {
log.push("call second next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, second);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call second return");
throw new ExpectedError();
}
};
var third = {
next() {
log.push("call third next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
return {};
}
};
var fourth = {
next() {
log.push("call fourth next");
return {done: true};
},
return() {
log.push("unexpected call fourth return");
}
};
var it = Iterator.zip([first, second, third, fourth], {mode: "longest"});
it.next();
assert.throws(ExpectedError, function() {
it.return();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call third next",
"call fourth next",
"call third return",
"call second return",
"call first return",
]);

View File

@ -0,0 +1,125 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorCloseAll in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
...
d. If result is done, then
i. Remove iter from openIters.
ii. If mode is "shortest", then
i. Return ? IteratorCloseAll(openIters, ReturnCompletion(undefined)).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
function ExpectedError() {}
var log = [];
var first = {
next() {
log.push("call first next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, first);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call first return");
return {};
}
};
var second = {
next() {
log.push("call second next");
return {done: true};
},
return() {
log.push("unexpected call second return");
}
};
var third = {
next() {
log.push("unexpected call third next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var fourth = {
next() {
log.push("unexpected call fourth next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, fourth);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call fourth return");
throw new ExpectedError();
}
};
var it = Iterator.zip([first, second, third, fourth], {mode: "shortest"});
assert.throws(ExpectedError, function() {
it.next();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call fourth return",
"call third return",
"call first return",
]);

View File

@ -0,0 +1,108 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorCloseAll in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
...
d. If result is done, then
i. Remove iter from openIters.
...
iii. Else if mode is "strict", then
i. If i 0, then
i. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
var log = [];
var first = {
next() {
log.push("call first next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, first);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call first return");
return {};
}
};
var second = {
next() {
log.push("call second next");
return {done: true};
},
return() {
log.push("unexpected call second return");
}
};
var third = {
next() {
log.push("unexpected call third next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var it = Iterator.zip([first, second, third], {mode: "strict"});
assert.throws(TypeError, function() {
it.next();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call third return",
"call first return",
]);

View File

@ -0,0 +1,123 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorCloseAll in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
...
d. If result is done, then
i. Remove iter from openIters.
...
iii. Else if mode is "strict", then
...
ii. For each integer k such that 1 k < iterCount, in ascending order, do
...
iv. Else,
i. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
var log = [];
var first = {
next() {
log.push("call first next");
return {done: true};
},
return() {
log.push("unexpected call first return");
}
};
var second = {
next() {
log.push("call second next");
return {done: true};
},
return() {
log.push("unexpected call second return");
}
};
var third = {
next() {
log.push("call third next");
return {done: false};
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var fourth = {
next() {
log.push("unexpected call fourth next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, fourth);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call fourth return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var it = Iterator.zip([first, second, third, fourth], {mode: "strict"});
assert.throws(TypeError, function() {
it.next();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call third next",
"call fourth return",
"call third return",
]);

View File

@ -0,0 +1,125 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Handle abrupt completion from IteratorStep in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
...
d. If result is done, then
i. Remove iter from openIters.
...
iii. Else if mode is "strict", then
...
ii. For each integer k such that 1 k < iterCount, in ascending order, do
...
ii. Let open be Completion(IteratorStep(iters[k])).
iii. If open is an abrupt completion, then
i. Remove iters[k] from openIters.
ii. Return ? IteratorCloseAll(openIters, open).
...
IteratorCloseAll ( iters, completion )
1. For each element iter of iters, in reverse List order, do
a. Set completion to Completion(IteratorClose(iter, completion)).
2. Return ? completion.
IteratorClose ( iteratorRecord, completion )
1. Assert: iteratorRecord.[[Iterator]] is an Object.
2. Let iterator be iteratorRecord.[[Iterator]].
3. Let innerResult be Completion(GetMethod(iterator, "return")).
4. If innerResult is a normal completion, then
a. Let return be innerResult.[[Value]].
b. If return is undefined, return ? completion.
c. Set innerResult to Completion(Call(return, iterator)).
5. If completion is a throw completion, return ? completion.
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
function ExpectedError() {}
var log = [];
var first = {
next() {
log.push("call first next");
return {done: true};
},
return() {
log.push("unexpected call first return");
}
};
var second = {
next() {
log.push("call second next");
throw new ExpectedError();
},
return() {
log.push("unexpected call second return");
}
};
var third = {
next() {
log.push("unexpected call third next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, third);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call third return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var fourth = {
next() {
log.push("unexpected call fourth next");
},
return() {
// Called with the correct receiver and no arguments.
assert.sameValue(this, fourth);
assert.sameValue(arguments.length, 0);
// NB: Log after above asserts, because failures aren't propagated.
log.push("call fourth return");
// IteratorClose ignores new exceptions when called with a Throw completion.
throw new Test262Error();
}
};
var it = Iterator.zip([first, second, third, fourth], {mode: "strict"});
assert.throws(ExpectedError, function() {
it.next();
});
assert.compareArray(log, [
"call first next",
"call second next",
"call fourth return",
"call third return",
]);

View File

@ -0,0 +1,155 @@
// Copyright (C) 2025 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.zip
description: >
Perform iteration in IteratorZip.
info: |
Iterator.zip ( iterables [ , options ] )
...
16. Return IteratorZip(iters, mode, padding, finishResults).
IteratorZip ( iters, mode, padding, finishResults )
3. Let closure be a new Abstract Closure with no parameters that captures
iters, iterCount, openIters, mode, padding, and finishResults, and
performs the following steps when called:
...
b. Repeat,
...
iii. For each integer i such that 0 i < iterCount, in ascending order, do
...
3. Else,
a. Let result be Completion(IteratorStepValue(iter)).
...
includes: [compareArray.js]
features: [joint-iteration]
---*/
var modes = [
"shortest",
"longest",
"strict",
];
function makeIterator(log, name, elements) {
var elementsIter = elements.values();
var iterator = {
next() {
log.push(`call ${name} next`);
// Called with the correct receiver and no arguments.
assert.sameValue(this, iterator);
assert.sameValue(arguments.length, 0);
var result = elementsIter.next();
return {
get done() {
log.push(`get ${name}.result.done`);
return result.done;
},
get value() {
log.push(`get ${name}.result.value`);
return result.value;
},
};
},
return() {
log.push(`call ${name} return`);
// Called with the correct receiver and no arguments.
assert.sameValue(this, iterator);
assert.sameValue(arguments.length, 0);
return {
get done() {
log.push(`unexpected get ${name}.result.done`);
return result.done;
},
get value() {
log.push(`unexpected get ${name}.result.value`);
return result.value;
},
};
}
};
return iterator;
}
for (var mode of modes) {
var log = [];
var iterables = [
makeIterator(log, "first", [1, 2, 3]),
makeIterator(log, "second", [4, 5, 6]),
makeIterator(log, "third", [7, 8, 9]),
];
var it = Iterator.zip(iterables, {mode});
log.push("start");
for (var v of it) {
log.push("loop");
}
var expected = [
"start",
"call first next",
"get first.result.done",
"get first.result.value",
"call second next",
"get second.result.done",
"get second.result.value",
"call third next",
"get third.result.done",
"get third.result.value",
"loop",
"call first next",
"get first.result.done",
"get first.result.value",
"call second next",
"get second.result.done",
"get second.result.value",
"call third next",
"get third.result.done",
"get third.result.value",
"loop",
"call first next",
"get first.result.done",
"get first.result.value",
"call second next",
"get second.result.done",
"get second.result.value",
"call third next",
"get third.result.done",
"get third.result.value",
"loop",
];
switch (mode) {
case "shortest": {
expected.push(
"call first next",
"get first.result.done",
"call third return",
"call second return",
);
break;
}
case "longest":
case "strict": {
expected.push(
"call first next",
"get first.result.done",
"call second next",
"get second.result.done",
"call third next",
"get third.result.done",
);
break;
}
}
assert.compareArray(log, expected);
}