Skip to content

Commit

Permalink
Iterator Helpers (#2818)
Browse files Browse the repository at this point in the history
drop:

property descriptor
name
length
[[Prototype]]
is a function
is not constructible
result instanceof Iterator
limit is given a non-primitive that needs to be converted to a number
  through valueOf
  through toString (array)
limit coercion to number throws
limit converts to NaN
  same as limit not supplied
limit behaves properly
  limit < number of values
  limit = number of values
  limit > number of values
gets the next method from the underlying iterator only once
underlying iterator has throwing next getter
underlying iterator next throws when advancing past dropped items
underlying iterator is advanced after calling drop
underlying iterator is closed after calling drop
underlying iterator is already closed
underlying iterator next returns non-object
underlying iterator next returns object with throwing done/value getters
underlying iterator return is never called when result iterator is closed

every:

property descriptor
name
length
[[Prototype]]
is a function
is callable
is not constructible
result is a Boolean
predicate is non-callable
iterator already exhausted
called on non-object
called on object with "next" method
called on object with non-callable "next" method
predicate returns non-Boolean
predicate returns truthy for all iterated values
  returns true
predicate returns truthy for some iterated values but then falsey for at least one iterated value
  returns false
  iteration stops
  iterator is closed
predicate returns falsey immediately
  returns false
  iteration stops
  iterator is closed
predicate throws
  every throws
  iterator is closed
predicate throws then iterator close also throws
predicate this value is undefined
predicate is passed the yielded value as the first parameter and a counter as second parameter
gets the next method from the iterator only once
iterator has throwing next getter
iterator has throwing return getter
iterator next throws
iterator return throws
iterator next returns non-object
iterator next returns object with throwing done/value getters

Co-authored-by: Michael Ficarra <mficarra@shapesecurity.com>
Co-authored-by: Jordan Harband <ljharb@gmail.com>
  • Loading branch information
3 people authored Jun 15, 2023
1 parent e337fc9 commit dfc7ce4
Show file tree
Hide file tree
Showing 374 changed files with 10,452 additions and 37 deletions.
4 changes: 4 additions & 0 deletions features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ String.prototype.toWellFormed
# https://github.com/tc39/proposal-json-parse-with-source
json-parse-with-source

# Iterator Helpers
# https://github.com/tc39/proposal-iterator-helpers
iterator-helpers

## Standard language features
#
# Language features that have been included in a published version of the
Expand Down
11 changes: 11 additions & 0 deletions test/built-ins/Iterator/constructor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-iterator-constructor
description: >
The Iterator constructor is a built-in function
features: [iterator-helpers]
---*/

assert.sameValue(typeof Iterator, 'function', 'The value of `typeof Iterator` is "function"');
12 changes: 12 additions & 0 deletions test/built-ins/Iterator/from/callable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from is callable
features: [iterator-helpers]
---*/
function* g() {}

Iterator.from(g());
Iterator.from.call(null, g());
46 changes: 46 additions & 0 deletions test/built-ins/Iterator/from/get-next-method-only-once.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2023 Michael Ficarra. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Gets the next method from the underlying iterator only once
info: |
Iterator.from ( O )
2. Let iteratorRecord be ? GetIteratorFlattenable(O).
features: [iterator-helpers]
flags: []
---*/
let nextGets = 0;
let nextCalls = 0;

class CountingIterator {
get next() {
++nextGets;
let iter = (function* () {
for (let i = 1; i < 5; ++i) {
yield i;
}
})();
return function () {
++nextCalls;
return iter.next();
};
}
}

let iterator = new CountingIterator();

assert.sameValue(nextGets, 0, 'The value of `nextGets` is 0');
assert.sameValue(nextCalls, 0, 'The value of `nextCalls` is 0');

iterator = Iterator.from(iterator);

assert.sameValue(nextGets, 1, 'The value of `nextGets` is 1');
assert.sameValue(nextCalls, 0, 'The value of `nextCalls` is 0');

iterator.toArray();

assert.sameValue(nextGets, 1, 'The value of `nextGets` is 1');
assert.sameValue(nextCalls, 5, 'The value of `nextCalls` is 5');
25 changes: 25 additions & 0 deletions test/built-ins/Iterator/from/get-next-method-throws.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2023 Michael Ficarra. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Underlying iterator has throwing next getter
info: |
Iterator.from ( O )
4. Let iterated be ? GetIteratorDirect(O).
features: [iterator-helpers]
flags: []
---*/
class ThrowingIterator {
get next() {
throw new Test262Error();
}
}

let iterator = new ThrowingIterator();

assert.throws(Test262Error, function () {
Iterator.from(iterator);
});
10 changes: 10 additions & 0 deletions test/built-ins/Iterator/from/is-function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from is a built-in function
features: [iterator-helpers]
---*/

assert.sameValue(typeof Iterator.from, 'function', 'The value of `typeof Iterator.from` is "function"');
39 changes: 39 additions & 0 deletions test/built-ins/Iterator/from/iterable-primitives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (C) 2023 Michael Ficarra. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from does not respect the iterability of any primitive except Strings
info: |
Iterator.from ( O )
1. If O is a String, set O to ! ToObject(O).
2. Let iteratorRecord be ? GetIteratorFlattenable(O).
includes: [compareArray.js]
features: [iterator-helpers]
flags: []
---*/

function* g() {
yield 0;
}

Number.prototype[Symbol.iterator] = function* () {
let i = 0;
let target = this >>> 0;
while (i < target) {
yield i;
++i;
}
};

assert.compareArray(Array.from(5), [0, 1, 2, 3, 4]);

assert.throws(TypeError, function () {
Iterator.from(5);
});

assert.compareArray(Array.from(Iterator.from(new Number(5))), [0, 1, 2, 3, 4]);

assert.compareArray(Array.from(Iterator.from('string')), ['s', 't', 'r', 'i', 'n', 'g']);
51 changes: 51 additions & 0 deletions test/built-ins/Iterator/from/iterable-to-iterator-fallback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (C) 2023 Michael Ficarra. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from falls back to treating its parameter as an iterator if the Symbol.iterator property is null/undefined
info: |
Iterator.from ( O )
includes: [compareArray.js]
features: [iterator-helpers]
flags: []
---*/

function* g() {
yield 0;
yield 1;
yield 2;
}

let iter = (function () {
let n = g();
return {
[Symbol.iterator]: 0,
next: () => n.next(),
};
})();

assert.throws(TypeError, function () {
Iterator.from(iter);
});

iter = (function () {
let n = g();
return {
[Symbol.iterator]: null,
next: () => n.next(),
};
})();

assert.compareArray(Array.from(Iterator.from(iter)), [0, 1, 2]);

iter = (function () {
let n = g();
return {
[Symbol.iterator]: undefined,
next: () => n.next(),
};
})();

assert.compareArray(Array.from(Iterator.from(iter)), [0, 1, 2]);
22 changes: 22 additions & 0 deletions test/built-ins/Iterator/from/length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from has a "length" property whose value is 1.
info: |
ECMAScript Standard Built-in Objects
Unless otherwise specified, the length property of a built-in
Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
false, [[Configurable]]: true }.
features: [iterator-helpers]
includes: [propertyHelper.js]
---*/

verifyProperty(Iterator.from, 'length', {
value: 1,
writable: false,
enumerable: false,
configurable: true,
});
29 changes: 29 additions & 0 deletions test/built-ins/Iterator/from/name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
The "name" property of Iterator.from
info: |
17 ECMAScript Standard Built-in Objects
Every built-in Function object, including constructors, that is not
identified as an anonymous function has a name property whose value is a
String. Unless otherwise specified, this value is the name that is given to
the function in this specification.
...
Unless otherwise specified, the name property of a built-in Function
object, if it exists, has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
features: [iterator-helpers]
includes: [propertyHelper.js]
---*/

verifyProperty(Iterator.from, 'name', {
value: 'from',
writable: false,
enumerable: false,
configurable: true,
});
23 changes: 23 additions & 0 deletions test/built-ins/Iterator/from/non-constructible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from is not constructible.
Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function.
features: [iterator-helpers]
---*/
function* g() {}

assert.throws(TypeError, () => {
new Iterator.from();
});

assert.throws(TypeError, () => {
new Iterator.from(g());
});

assert.throws(TypeError, () => {
new class extends Iterator {}.from(g());
});
38 changes: 38 additions & 0 deletions test/built-ins/Iterator/from/primitives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (C) 2023 Michael Ficarra. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Iterator.from throws on primitives (except Strings)
info: |
Iterator.from ( O )
features: [iterator-helpers]
flags: []
---*/

assert.throws(TypeError, function () {
Iterator.from(null);
});

assert.throws(TypeError, function () {
Iterator.from(undefined);
});

assert.throws(TypeError, function () {
Iterator.from(0);
});

assert.throws(TypeError, function () {
Iterator.from(0n);
});

assert.throws(TypeError, function () {
Iterator.from(true);
});

assert.throws(TypeError, function () {
Iterator.from(Symbol());
});

Iterator.from('string');
26 changes: 26 additions & 0 deletions test/built-ins/Iterator/from/prop-desc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
Property descriptor of Iterator.from
info: |
Iterator.from
* is the initial value of the Iterator.from property of the global object.
17 ECMAScript Standard Built-in Objects
Every other data property described in clauses 18 through 26 and in Annex B.2
has the attributes { [[Writable]]: true, [[Enumerable]]: false,
[[Configurable]]: true } unless otherwise specified.
features: [globalThis, iterator-helpers]
includes: [propertyHelper.js]
---*/

verifyProperty(Iterator, 'from', {
value: Iterator.from,
writable: true,
enumerable: false,
configurable: true,
});
15 changes: 15 additions & 0 deletions test/built-ins/Iterator/from/proto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-iterator.from
description: >
The value of the [[Prototype]] internal slot of Iterator.from is the
intrinsic object %FunctionPrototype%.
features: [iterator-helpers]
---*/

assert.sameValue(
Object.getPrototypeOf(Iterator.from),
Function.prototype,
'Object.getPrototypeOf(Iterator.from) must return the value of Function.prototype'
);
Loading

0 comments on commit dfc7ce4

Please sign in to comment.