From cd906f0d0511e107f7a4624d49d55283caed0997 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Fri, 9 Sep 2022 17:02:18 -0600 Subject: [PATCH 1/6] fixes #229: flatMap supports returning both iterables and iterators --- spec.html | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index 420dd8f..59bc651 100644 --- a/spec.html +++ b/spec.html @@ -149,6 +149,37 @@

1. Return _iteratorRecord_. + + +

+ GetIteratorFlattenable ( + _obj_: an ECMAScript language value, + optional _hint_: ~sync~ or ~async~, + ): either a normal completion containing an Iterator Record or a throw completion +

+
+
+ + 1. If _hint_ is not present, set _hint_ to ~sync~. + 1. If _iterator_ is either *undefined* or *null*, throw a *TypeError* exception. + 1. Let _method_ be *undefined*. + 1. If _hint_ is ~async~, then + 1. Set _method_ to ? GetV(_obj_, @@asyncIterator). + 1. If IsCallable(_method_) is *false*, then + 1. Set _method_ to ? GetV(_obj_, @@iterator). + 1. If IsCallable(_method_) is *false*, then + 1. Let _iterator_ be _obj_. + 1. Else, + 1. Let _iterator_ be ? Call(_method_, _obj_). + 1. If _iterator_ is not an Object, throw a *TypeError* exception. + 1. Let _nextMethod_ be ? Get(_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~, then + 1. Return CreateAsyncFromSyncIterator(_iteratorRecord_). + 1. Return _iteratorRecord_. + +
@@ -560,7 +591,7 @@

Iterator.prototype.flatMap ( _mapper_ )

1. Let _value_ be ? IteratorValue(_next_). 1. Let _mapped_ be Completion(Call(_mapper_, *undefined*, « _value_ »)). 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*, @@ -828,7 +859,7 @@

AsyncIterator.prototype.flatMap ( _mapper_ )

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*, From 7f368440146eb15b90e6d7f45060cbd490e892c2 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Mon, 12 Sep 2022 22:22:48 -0600 Subject: [PATCH 2/6] only CreateAsyncFromSyncIterator when necessary --- spec.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec.html b/spec.html index 59bc651..ccf4229 100644 --- a/spec.html +++ b/spec.html @@ -162,20 +162,24 @@

1. If _hint_ is not present, set _hint_ to ~sync~. 1. If _iterator_ is either *undefined* or *null*, throw a *TypeError* exception. + 1. Let _alreadyAsync_ be *false*. 1. Let _method_ be *undefined*. 1. If _hint_ is ~async~, then 1. Set _method_ to ? GetV(_obj_, @@asyncIterator). + 1. Set _alreadyAsync_ to *true*. 1. If IsCallable(_method_) is *false*, then 1. Set _method_ to ? GetV(_obj_, @@iterator). + 1. Set _alreadyAsync_ to *false*. 1. If IsCallable(_method_) is *false*, then 1. Let _iterator_ be _obj_. + 1. Set _alreadyAsync_ to *true*. 1. Else, 1. Let _iterator_ be ? Call(_method_, _obj_). 1. If _iterator_ is not an Object, throw a *TypeError* exception. 1. Let _nextMethod_ be ? Get(_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~, then + 1. If _hint_ is ~async~ and _alreadyAsync_ is *false*, then 1. Return CreateAsyncFromSyncIterator(_iteratorRecord_). 1. Return _iteratorRecord_. From 57725e349a342ffd0cb64c3cc6edcb3d2f8b8ca9 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Fri, 23 Sep 2022 15:56:30 -0600 Subject: [PATCH 3/6] update --- spec.html | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/spec.html b/spec.html index ccf4229..f7123aa 100644 --- a/spec.html +++ b/spec.html @@ -154,29 +154,27 @@

GetIteratorFlattenable ( _obj_: an ECMAScript language value, - optional _hint_: ~sync~ or ~async~, + _hint_: ~sync~ or ~async~, ): either a normal completion containing an Iterator Record or a throw completion

- 1. If _hint_ is not present, set _hint_ to ~sync~. - 1. If _iterator_ is either *undefined* or *null*, throw a *TypeError* exception. + 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 ? GetV(_obj_, @@asyncIterator). + 1. Set _method_ to ? Get(_obj_, @@asyncIterator). 1. Set _alreadyAsync_ to *true*. 1. If IsCallable(_method_) is *false*, then - 1. Set _method_ to ? GetV(_obj_, @@iterator). + 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*. 1. Else, 1. Let _iterator_ be ? Call(_method_, _obj_). - 1. If _iterator_ is not an Object, throw a *TypeError* exception. - 1. Let _nextMethod_ be ? Get(_iterator_, *"next"*). + 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 @@ -246,14 +244,10 @@

Iterator.prototype

Iterator.from ( _O_ )

- 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(_mapped_, ~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_. @@ -328,21 +322,7 @@

AsyncIterator.prototype

AsyncIterator.from ( _O_ )

- 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(_mapped_, ~sync~). 1. Let _wrapper_ be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »). 1. Set _wrapper_.[[AsyncIterated]] to _iteratorRecord_. 1. Return _wrapper_. From a808e488a1d2f0e68184b16397d84806125e0c6c Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Fri, 23 Sep 2022 16:05:10 -0600 Subject: [PATCH 4/6] accidentally dropped the fast path --- spec.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec.html b/spec.html index f7123aa..6a308f0 100644 --- a/spec.html +++ b/spec.html @@ -323,6 +323,9 @@

AsyncIterator.prototype

AsyncIterator.from ( _O_ )

1. Let _iteratorRecord_ be GetIteratorFlattenable(_mapped_, ~sync~). + 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_. From 267fa975bca8870ecea62a9e4f80d74dfd182895 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Fri, 23 Sep 2022 16:21:39 -0600 Subject: [PATCH 5/6] fix editorial issues --- spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index 6a308f0..7c8888f 100644 --- a/spec.html +++ b/spec.html @@ -244,7 +244,7 @@

Iterator.prototype

Iterator.from ( _O_ )

- 1. Let _iteratorRecord_ be GetIteratorFlattenable(_mapped_, ~sync~). + 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]]. @@ -322,7 +322,7 @@

AsyncIterator.prototype

AsyncIterator.from ( _O_ )

- 1. Let _iteratorRecord_ be GetIteratorFlattenable(_mapped_, ~sync~). + 1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_O_, ~sync~). 1. Let _hasInstance_ be ? OrdinaryHasInstance(%AsyncIterator%, _iteratorRecord_.[[Iterator]]). 1. If _hasInstance_ is *true*, then 1. Return _iteratorRecord_.[[Iterator]]. From 938a6a00b5c040e353fe6fcd51698ca7feb066a4 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Mon, 26 Sep 2022 09:44:44 -0600 Subject: [PATCH 6/6] oops, async --- spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.html b/spec.html index 7c8888f..b1419a6 100644 --- a/spec.html +++ b/spec.html @@ -322,7 +322,7 @@

AsyncIterator.prototype

AsyncIterator.from ( _O_ )

- 1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_O_, ~sync~). + 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]].