Skip to content

Commit

Permalink
replace from/flat with concat
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelficarra committed May 31, 2024
1 parent 9fe81f9 commit edbc19b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 144 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"scripts": {
"build": "tsc",
"spec": "ecmarkup --mark-effects --load-biblio @tc39/ecma262-biblio --load-biblio ./proposal-iterator-helpers-biblio.json --write-biblio biblio.json --lint-spec --strict spec.emu --assets-dir dist dist/index.html",
"test": "node --test test"
"test": "node --test test/index.mjs"
},
"repository": {
"type": "git",
Expand Down
47 changes: 2 additions & 45 deletions spec.emu
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,9 @@ location: https://tc39.es/proposal-iterator-sequencing/
copyright: false
</pre>

<emu-clause id="sec-iterator.from">
<h1>Iterator.from ( ..._items_ )</h1>
<emu-clause id="sec-iterator.concat">
<h1>Iterator.concat ( ..._items_ )</h1>
<emu-alg>
1. If the number of elements in _items_ is 1, then
1. Let _iter_ be the first element of _items_.
1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_iter_, ~iterate-strings~).
1. Let _hasInstance_ be ? OrdinaryHasInstance(%Iterator%, _iteratorRecord_.[[Iterator]]).
1. If _hasInstance_ is *true*, then
1. Return _iteratorRecord_.[[Iterator]].
1. Let _wrapper_ be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
1. Set _wrapper_.[[Iterated]] to _iteratorRecord_.
1. Return _wrapper_.
1. Let _closure_ be a new Abstract Closure with no parameters that captures _items_ and performs the following steps when called:
1. Repeat, while _items_ is not empty,
1. Let _iter_ be the first element of _items_.
Expand All @@ -39,37 +30,3 @@ copyright: false
1. Return CreateIteratorFromClosure(_closure_, *"Iterator Helper"*, %IteratorHelperPrototype%, « »).
</emu-alg>
</emu-clause>

<emu-clause id="sec-iteratorprototype.flat">
<h1>Iterator.prototype.flat ( )</h1>
<p>This method performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. If _O_ is not an Object, throw a *TypeError* exception.
1. Let _iterated_ be ? GetIteratorDirect(_O_).
1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and performs the following steps when called:
1. Repeat,
1. Let _next_ be ? IteratorStep(_iterated_).
1. If _next_ is *false*, return *undefined*.
1. Let _value_ be ? IteratorValue(_next_).
1. Let _innerIterator_ be Completion(GetIteratorFlattenable(_value_, ~reject-strings~)).
1. IfAbruptCloseIterator(_innerIterator_, _iterated_).
1. Let _innerAlive_ be *true*.
1. Repeat, while _innerAlive_ is *true*,
1. Let _innerNext_ be Completion(IteratorStep(_innerIterator_)).
1. IfAbruptCloseIterator(_innerNext_, _iterated_).
1. If _innerNext_ is *false*, then
1. Set _innerAlive_ to *false*.
1. Else,
1. Let _innerValue_ be Completion(IteratorValue(_innerNext_)).
1. IfAbruptCloseIterator(_innerValue_, _iterated_).
1. Let _completion_ be Completion(Yield(_innerValue_)).
1. If _completion_ is an abrupt completion, then
1. Let _backupCompletion_ be Completion(IteratorClose(_innerIterator_, _completion_)).
1. IfAbruptCloseIterator(_backupCompletion_, _iterated_).
1. Return ? IteratorClose(_completion_, _iterated_).
1. Let _result_ be CreateIteratorFromClosure(_closure_, *"Iterator Helper"*, %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
1. Set _result_.[[UnderlyingIterator]] to _iterated_.
1. Return _result_.
</emu-alg>
</emu-clause>
60 changes: 13 additions & 47 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function getIteratorFlattenable(obj: any, stringHandling: 'iterate-strings' | 'r
if (stringHandling === 'reject-strings' || typeof obj != 'string') {
throw new TypeError;
}
obj = Object(obj);
}
let iter = Symbol.iterator in obj ? obj[Symbol.iterator]() : obj as Iterator<unknown>;
if (Object(iter) !== iter) {
Expand All @@ -21,10 +22,6 @@ function getIteratorFlattenable(obj: any, stringHandling: 'iterate-strings' | 'r
return iter;
}

function isObject(obj: unknown): obj is Object {
return Object(obj) === obj;
}

type IteratorOrIterable<A> = Iterable<A> | Iterator<A>
interface Iterable<T> {
[Symbol.iterator](): Iterator<T, unknown, unknown>;
Expand All @@ -34,56 +31,25 @@ function liftIterator<A>(iter: Iterator<A>): Iterable<A> {
return { [Symbol.iterator]() { return iter; } };
}

// function concatImpl<A>(iterators: IteratorOrIterable<IteratorOrIterable<A>>): Generator<A>
// function concatImpl(iterators: IteratorOrIterable<IteratorOrIterable<unknown>>): Generator<unknown>
// function* concatImpl(iterators: unknown): Generator<unknown> {
// for (const iter of liftIterator(getIteratorFlattenable(iterators, 'reject-strings'))) {
// yield* liftIterator(getIteratorFlattenable(iter, 'reject-strings'));
// }
// }

function fromImpl<A>(...iterators: Array<IteratorOrIterable<A>>): Generator<A>
function fromImpl(): Generator<never>
function fromImpl<A>(iteratorA: IteratorOrIterable<A>): Generator<A>
function fromImpl<A, B>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>): Generator<A | B>
function fromImpl<A, B, C>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>): Generator<A | B | C>
function fromImpl<A, B, C, D>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>): Generator<A | B | C | D>
function fromImpl<A, B, C, D, E>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>, iteratorE: IteratorOrIterable<E>): Generator<A | B | C | D | E>
function fromImpl(...iterators: Array<IteratorOrIterable<unknown>>): Generator<unknown>
function* fromImpl(...iterators: Array<unknown>): Generator<unknown> {
function concatImpl<A>(...iterators: Array<IteratorOrIterable<A>>): Generator<A>
function concatImpl(): Generator<never>
function concatImpl<A>(iteratorA: IteratorOrIterable<A>): Generator<A>
function concatImpl<A, B>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>): Generator<A | B>
function concatImpl<A, B, C>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>): Generator<A | B | C>
function concatImpl<A, B, C, D>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>): Generator<A | B | C | D>
function concatImpl<A, B, C, D, E>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>, iteratorE: IteratorOrIterable<E>): Generator<A | B | C | D | E>
function concatImpl(...iterators: Array<IteratorOrIterable<unknown>>): Generator<unknown>
function* concatImpl(...iterators: Array<unknown>): Generator<unknown> {
for (const iter of iterators) {
yield* liftIterator(getIteratorFlattenable(iter, 'iterate-strings'));
}
}

function flatImpl<A>(this: Iterator<A>): Generator<A>
function* flatImpl(this: unknown): Generator<unknown> {
for (const iter of liftIterator(this as Iterator<unknown>)) {
yield* liftIterator(getIteratorFlattenable(iter, 'reject-strings'));
}
}

// NOTE: this line makes concat non-constructible, and gives it the appropriate name and length
// const concat = (iterators: IteratorOrIterable<IteratorOrIterable<unknown>>) => concatImpl(iterators);
// Object.defineProperty(Iterator, 'concat', {
// configurable: true,
// writable: true,
// enumerable: false,
// value: concat,
// });

// NOTE: this line makes from non-constructible, and gives it the appropriate name and length
const from = (...iterators: Array<IteratorOrIterable<unknown>>) => fromImpl(...iterators);
Object.defineProperty(Iterator, 'from', {
const concat = (...iterators: Array<IteratorOrIterable<unknown>>) => concatImpl(...iterators);
Object.defineProperty(Iterator, 'concat', {
configurable: true,
writable: true,
enumerable: false,
value: from,
value: concat,
});

Object.defineProperty(IteratorPrototype, 'flat', {
configurable: true,
writable: true,
enumerable: false,
value: flatImpl,
});
86 changes: 35 additions & 51 deletions test/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,57 @@ import { test } from 'node:test';
import * as assert from 'node:assert/strict';
import '../lib/index.js';

// test('concat', async t => {
// assert.deepEqual(
// Array.from(Iterator.concat([])),
// [],
// );
// assert.deepEqual(
// Array.from(Iterator.concat([
// [0, 1, 2],
// ])),
// [0, 1, 2],
// );
// assert.deepEqual(
// Array.from(Iterator.concat([
// [0, 1, 2],
// [3, 4, 5],
// ])),
// [0, 1, 2, 3, 4, 5],
// );
// });

test('from', async t => {
test('concat', async t => {
assert.deepEqual(
Array.from(Iterator.from()),
Array.from(Iterator.concat()),
[],
);
assert.deepEqual(
Array.from(Iterator.from(
Array.from(Iterator.concat(
[0, 1, 2],
)),
[0, 1, 2],
);
assert.deepEqual(
Array.from(Iterator.from(
Array.from(Iterator.concat(
[0, 1, 2],
[3, 4, 5],
)),
[0, 1, 2, 3, 4, 5],
);
assert.deepEqual(
Array.from(Iterator.concat(
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
)),
[0, 1, 2, 3, 4, 5, 6, 7, 8],
);
});

function* p(n) {
for (let count = n; count > 0; --count) {
yield n;
}
}

function* nats() {
let n = 0;
while (true) {
yield n;
++n;
}
}

function* take(n, iter) {
for (let count = 0; count < n; ++count) {
let result = iter.next();
if (result.done) break;
yield result.value;
}
}
test('concat iterates strings', async t => {
assert.deepEqual(
Array.from(Iterator.concat("ab", "cd")),
["a", "b", "c", "d"],
);
});

test('flat', async t => {
test('concat bare iterators', async t => {
let count = 0;
const iter = {
next() {
if (count < 6) {
return { done: false, value: count++ };
} else {
return { done: true };
}
},
};
assert.deepEqual(
Array.from(take(10, [
p(3), p(0), p(1), nats()
].values().flat())),
[3, 3, 3, 1, 0, 1, 2, 3, 4, 5],
Array.from(Iterator.concat(
iter,
iter,
)),
[0, 1, 2, 3, 4, 5],
);
});
});

0 comments on commit edbc19b

Please sign in to comment.