Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #229: flatMap supports returning both iterables and iterators #233

Merged
merged 8 commits into from Oct 19, 2022
68 changes: 43 additions & 25 deletions spec.html
Expand Up @@ -248,6 +248,39 @@ <h1>
1. Return _iteratorRecord_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-getiteratorflattenable" type="abstract operation">
<h1>
GetIteratorFlattenable (
_obj_: an ECMAScript language value,
_hint_: ~sync~ or ~async~,
): either a normal completion containing an Iterator Record or a throw completion
</h1>
<dl class="header">
</dl>
<emu-alg>
1. If _obj_ is not an Object, throw a *TypeError* exception.
1. Let _alreadyAsync_ be *false*.
1. Let _method_ be *undefined*.
1. If _hint_ is ~async~, then
1. Set _method_ to ? Get(_obj_, @@asyncIterator).
1. Set _alreadyAsync_ to *true*.
1. If IsCallable(_method_) is *false*, then
1. Set _method_ to ? Get(_obj_, @@iterator).
1. Set _alreadyAsync_ to *false*.
1. If IsCallable(_method_) is *false*, then
1. Let _iterator_ be _obj_.
1. Set _alreadyAsync_ to *true*.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this variable name is confusing, since _iterator_ isn't already async here, it just shouldn't be made async later (if i'm understanding right)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only applicable in the _hint_ is ~async~ path. The iterator is assumed to be async if we're trying to get an async iterator. I could have guarded this assignment for clarity, but it wouldn't change the result.

1. Else,
1. Let _iterator_ be ? Call(_method_, _obj_).
1. Let _nextMethod_ be ? GetV(_iterator_, *"next"*).
1. If IsCallable(_nextMethod_) is *false*, throw a *TypeError* exception.
1. Let _iteratorRecord_ be the Iterator Record { [[Iterator]]: _iterator_, [[NextMethod]]: _nextMethod_, [[Done]]: *false* }.
1. If _hint_ is ~async~ and _alreadyAsync_ is *false*, then
1. Return CreateAsyncFromSyncIterator(_iteratorRecord_).
1. Return _iteratorRecord_.
</emu-alg>
</emu-clause>
</emu-clause>
</emu-clause>

Expand Down Expand Up @@ -310,14 +343,10 @@ <h1>Iterator.prototype</h1>
<emu-clause id="sec-iterator.from">
<h1>Iterator.from ( _O_ )</h1>
<emu-alg>
1. Let _usingIterator_ be ? GetMethod(_O_, @@iterator).
1. If _usingIterator_ is not *undefined*, then
1. Let _iteratorRecord_ be ? GetIterator(_O_, ~sync~, _usingIterator_).
1. If IsCallable(_iteratorRecord_.[[NextMethod]]) is *false*, throw a *TypeError* exception.
1. Let _hasInstance_ be ? OrdinaryHasInstance(%Iterator%, _iteratorRecord_.[[Iterator]]).
1. If _hasInstance_ is *true*, then
1. Return _iteratorRecord_.[[Iterator]].
1. Else, Let _iteratorRecord_ be ? GetIteratorDirect(_O_).
1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_O_, ~sync~).
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_.
Expand Down Expand Up @@ -392,21 +421,10 @@ <h1>AsyncIterator.prototype</h1>
<emu-clause id="sec-asynciterator.from">
<h1>AsyncIterator.from ( _O_ )</h1>
<emu-alg>
1. Let _usingIterator_ be ? GetMethod(_O_, @@asyncIterator).
1. Let _iteratorRecord_ be *undefined*.
1. If _usingIterator_ is not *undefined*, then
1. Set _iteratorRecord_ to ? GetIterator(_O_, ~async~, _usingIterator_).
1. If IsCallable(_iteratorRecord_.[[NextMethod]]) is *false*, throw a *TypeError* exception.
1. Let _hasInstance_ be ? OrdinaryHasInstance(%AsyncIterator%, _iteratorRecord_.[[Iterator]]).
1. If _hasInstance_ is *true*, then
1. Return _iteratorRecord_.[[Iterator]].
1. If _iteratorRecord_ is *undefined*, then
1. Set _usingIterator_ to ? GetMethod(_O_, @@iterator).
1. If _usingIterator_ is not *undefined*, then
1. Let _syncIteratorRecord_ be ? GetIterator(_O_, ~sync~, _usingIterator_).
1. If IsCallable(_syncIteratorRecord_.[[NextMethod]]) is *false*, throw a *TypeError* exception.
1. Set _iteratorRecord_ to CreateAsyncFromSyncIterator(_syncIteratorRecord_).
1. If _iteratorRecord_ is *undefined*, set _iteratorRecord_ to ? GetIteratorDirect(_O_).
1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_O_, ~async~).
1. Let _hasInstance_ be ? OrdinaryHasInstance(%AsyncIterator%, _iteratorRecord_.[[Iterator]]).
1. If _hasInstance_ is *true*, then
1. Return _iteratorRecord_.[[Iterator]].
1. Let _wrapper_ be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »).
1. Set _wrapper_.[[AsyncIterated]] to _iteratorRecord_.
1. Return _wrapper_.
Expand Down Expand Up @@ -651,7 +669,7 @@ <h1>Iterator.prototype.flatMap ( _mapper_ )</h1>
1. Let _value_ be ? IteratorValue(_next_).
1. Let _mapped_ be Completion(Call(_mapper_, *undefined*, « _value_, 𝔽(_counter_) »)).
1. IfAbruptCloseIterator(_mapped_, _iterated_).
1. Let _innerIterator_ be Completion(GetIterator(_mapped_, ~sync~)).
1. Let _innerIterator_ be Completion(GetIteratorFlattenable(_mapped_, ~sync~)).
1. IfAbruptCloseIterator(_innerIterator_, _iterated_).
1. Let _innerAlive_ be *true*.
1. Repeat, while _innerAlive_ is *true*,
Expand Down Expand Up @@ -928,7 +946,7 @@ <h1>AsyncIterator.prototype.flatMap ( _mapper_ )</h1>
1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
1. Set _mapped_ to Completion(Await(_mapped_)).
1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
1. Let _innerIterator_ be Completion(GetIterator(_mapped_, ~async~)).
1. Let _innerIterator_ be Completion(GetIteratorFlattenable(_mapped_, ~async~)).
1. IfAbruptCloseAsyncIterator(_innerIterator_, _iterated_).
1. Let _innerAlive_ be *true*.
1. Repeat, while _innerAlive_ is *true*,
Expand Down