Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / builtin / AsyncIteration.js
bloba482d35ae9d273b0a855dc24ff37dd6f1cf27200
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 function AsyncIteratorIdentity() {
6   return this;
9 function AsyncGeneratorNext(val) {
10   assert(
11     IsAsyncGeneratorObject(this),
12     "ThisArgument must be a generator object for async generators"
13   );
14   return resumeGenerator(this, val, "next");
17 function AsyncGeneratorThrow(val) {
18   assert(
19     IsAsyncGeneratorObject(this),
20     "ThisArgument must be a generator object for async generators"
21   );
22   return resumeGenerator(this, val, "throw");
25 function AsyncGeneratorReturn(val) {
26   assert(
27     IsAsyncGeneratorObject(this),
28     "ThisArgument must be a generator object for async generators"
29   );
30   return resumeGenerator(this, val, "return");
33 /* ECMA262 7.4.7 AsyncIteratorClose */
34 async function AsyncIteratorClose(iteratorRecord, value) {
35   // Step 3.
36   var iterator = iteratorRecord.iterator;
37   // Step 4.
38   var returnMethod = iterator.return;
39   // Step 5.
40   if (!IsNullOrUndefined(returnMethod)) {
41     var result = await callContentFunction(returnMethod, iterator);
42     // Step 8.
43     if (!IsObject(result)) {
44       ThrowTypeError(JSMSG_OBJECT_REQUIRED, DecompileArg(0, result));
45     }
46   }
47   // Step 5b & 9.
48   return value;
51 /* Iterator Helpers proposal 1.1.1 */
52 function GetIteratorDirect(obj) {
53   // Step 1.
54   if (!IsObject(obj)) {
55     ThrowTypeError(JSMSG_OBJECT_REQUIRED, DecompileArg(0, obj));
56   }
58   // Step 2.
59   var nextMethod = obj.next;
60   // Step 3.
61   if (!IsCallable(nextMethod)) {
62     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, nextMethod));
63   }
65   // Steps 4-5.
66   return {
67     iterator: obj,
68     nextMethod,
69     done: false,
70   };
73 /* Iterator Helpers proposal 1.1.1 */
74 function GetAsyncIteratorDirectWrapper(obj) {
75   // Step 1.
76   if (!IsObject(obj)) {
77     ThrowTypeError(JSMSG_OBJECT_REQUIRED, obj);
78   }
80   // Step 2.
81   var nextMethod = obj.next;
82   // Step 3.
83   if (!IsCallable(nextMethod)) {
84     ThrowTypeError(JSMSG_NOT_FUNCTION, nextMethod);
85   }
87   // Steps 4-5.
88   return {
89     // Use a named function expression instead of a method definition, so
90     // we don't create an inferred name for this function at runtime.
91     [GetBuiltinSymbol("asyncIterator")]: function AsyncIteratorMethod() {
92       return this;
93     },
94     next(value) {
95       return callContentFunction(nextMethod, obj, value);
96     },
97     async return(value) {
98       var returnMethod = obj.return;
99       if (!IsNullOrUndefined(returnMethod)) {
100         return callContentFunction(returnMethod, obj, value);
101       }
102       return { done: true, value };
103     },
104   };
107 /* AsyncIteratorHelper object prototype methods. */
108 function AsyncIteratorHelperNext(value) {
109   var O = this;
110   if (!IsObject(O) || (O = GuardToAsyncIteratorHelper(O)) === null) {
111     return callFunction(
112       CallAsyncIteratorHelperMethodIfWrapped,
113       this,
114       value,
115       "AsyncIteratorHelperNext"
116     );
117   }
118   var generator = UnsafeGetReservedSlot(
119     O,
120     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT
121   );
122   return callFunction(IntrinsicAsyncGeneratorNext, generator, value);
125 function AsyncIteratorHelperReturn(value) {
126   var O = this;
127   if (!IsObject(O) || (O = GuardToAsyncIteratorHelper(O)) === null) {
128     return callFunction(
129       CallAsyncIteratorHelperMethodIfWrapped,
130       this,
131       value,
132       "AsyncIteratorHelperReturn"
133     );
134   }
135   var generator = UnsafeGetReservedSlot(
136     O,
137     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT
138   );
139   return callFunction(IntrinsicAsyncGeneratorReturn, generator, value);
142 function AsyncIteratorHelperThrow(value) {
143   var O = this;
144   if (!IsObject(O) || (O = GuardToAsyncIteratorHelper(O)) === null) {
145     return callFunction(
146       CallAsyncIteratorHelperMethodIfWrapped,
147       this,
148       value,
149       "AsyncIteratorHelperThrow"
150     );
151   }
152   var generator = UnsafeGetReservedSlot(
153     O,
154     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT
155   );
156   return callFunction(IntrinsicAsyncGeneratorThrow, generator, value);
159 // AsyncIterator lazy Iterator Helper methods
160 // Iterator Helpers proposal 2.1.6.2-2.1.6.7
162 // The AsyncIterator lazy methods are structured closely to how the Iterator
163 // lazy methods are. See builtin/Iterator.js for the reasoning.
165 /* Iterator Helpers proposal 2.1.6.2 Prelude */
166 function AsyncIteratorMap(mapper) {
167   // Step 1.
168   var iterated = GetIteratorDirect(this);
170   // Step 2.
171   if (!IsCallable(mapper)) {
172     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper));
173   }
175   var iteratorHelper = NewAsyncIteratorHelper();
176   var generator = AsyncIteratorMapGenerator(iterated, mapper);
177   callFunction(IntrinsicAsyncGeneratorNext, generator);
178   UnsafeSetReservedSlot(
179     iteratorHelper,
180     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
181     generator
182   );
183   return iteratorHelper;
186 /* Iterator Helpers proposal 2.1.6.2 Body */
187 async function* AsyncIteratorMapGenerator(iterated, mapper) {
188   // Step 1.
189   var lastValue;
190   // Step 2.
191   var needClose = true;
192   try {
193     yield;
194     needClose = false;
196     for (
197       var next = await IteratorNext(iterated, lastValue);
198       !next.done;
199       next = await IteratorNext(iterated, lastValue)
200     ) {
201       // Step c.
202       var value = next.value;
204       // Steps d-i.
205       needClose = true;
206       lastValue = yield callContentFunction(mapper, undefined, value);
207       needClose = false;
208     }
209   } finally {
210     if (needClose) {
211       AsyncIteratorClose(iterated);
212     }
213   }
216 /* Iterator Helpers proposal 2.1.6.3 Prelude */
217 function AsyncIteratorFilter(filterer) {
218   // Step 1.
219   var iterated = GetIteratorDirect(this);
221   // Step 2.
222   if (!IsCallable(filterer)) {
223     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, filterer));
224   }
226   var iteratorHelper = NewAsyncIteratorHelper();
227   var generator = AsyncIteratorFilterGenerator(iterated, filterer);
228   callFunction(IntrinsicAsyncGeneratorNext, generator);
229   UnsafeSetReservedSlot(
230     iteratorHelper,
231     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
232     generator
233   );
234   return iteratorHelper;
237 /* Iterator Helpers proposal 2.1.6.3 Body */
238 async function* AsyncIteratorFilterGenerator(iterated, filterer) {
239   // Step 1.
240   var lastValue;
241   // Step 2.
242   var needClose = true;
243   try {
244     yield;
245     needClose = false;
247     for (
248       var next = await IteratorNext(iterated, lastValue);
249       !next.done;
250       next = await IteratorNext(iterated, lastValue)
251     ) {
252       // Step c.
253       var value = next.value;
255       // Steps d-h.
256       needClose = true;
257       if (await callContentFunction(filterer, undefined, value)) {
258         lastValue = yield value;
259       }
260       needClose = false;
261     }
262   } finally {
263     if (needClose) {
264       AsyncIteratorClose(iterated);
265     }
266   }
269 /* Iterator Helpers proposal 2.1.6.4 Prelude */
270 function AsyncIteratorTake(limit) {
271   // Step 1.
272   var iterated = GetIteratorDirect(this);
274   // Step 2.
275   var remaining = ToInteger(limit);
276   // Step 3.
277   if (remaining < 0) {
278     ThrowRangeError(JSMSG_NEGATIVE_LIMIT);
279   }
281   var iteratorHelper = NewAsyncIteratorHelper();
282   var generator = AsyncIteratorTakeGenerator(iterated, remaining);
283   callFunction(IntrinsicAsyncGeneratorNext, generator);
284   UnsafeSetReservedSlot(
285     iteratorHelper,
286     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
287     generator
288   );
289   return iteratorHelper;
292 /* Iterator Helpers proposal 2.1.6.4 Body */
293 async function* AsyncIteratorTakeGenerator(iterated, remaining) {
294   // Step 1.
295   var lastValue;
296   // Step 2.
297   var needClose = true;
298   try {
299     yield;
300     needClose = false;
302     for (; remaining > 0; remaining--) {
303       var next = await IteratorNext(iterated, lastValue);
304       if (next.done) {
305         return undefined;
306       }
308       var value = next.value;
310       needClose = true;
311       lastValue = yield value;
312       needClose = false;
313     }
314   } finally {
315     if (needClose) {
316       AsyncIteratorClose(iterated, undefined);
317     }
318   }
320   return AsyncIteratorClose(iterated, undefined);
323 /* Iterator Helpers proposal 2.1.6.5 Prelude */
324 function AsyncIteratorDrop(limit) {
325   // Step 1.
326   var iterated = GetIteratorDirect(this);
328   // Step 2.
329   var remaining = ToInteger(limit);
330   // Step 3.
331   if (remaining < 0) {
332     ThrowRangeError(JSMSG_NEGATIVE_LIMIT);
333   }
335   var iteratorHelper = NewAsyncIteratorHelper();
336   var generator = AsyncIteratorDropGenerator(iterated, remaining);
337   callFunction(IntrinsicAsyncGeneratorNext, generator);
338   UnsafeSetReservedSlot(
339     iteratorHelper,
340     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
341     generator
342   );
343   return iteratorHelper;
346 /* Iterator Helpers proposal 2.1.6.5 Body */
347 async function* AsyncIteratorDropGenerator(iterated, remaining) {
348   var needClose = true;
349   try {
350     yield;
351     needClose = false;
353     // Step 1.
354     for (; remaining > 0; remaining--) {
355       var next = await IteratorNext(iterated);
356       if (next.done) {
357         return;
358       }
359     }
361     // Step 2.
362     var lastValue;
363     // Step 3.
364     for (
365       var next = await IteratorNext(iterated, lastValue);
366       !next.done;
367       next = await IteratorNext(iterated, lastValue)
368     ) {
369       // Steps c-d.
370       var value = next.value;
372       needClose = true;
373       lastValue = yield value;
374       needClose = false;
375     }
376   } finally {
377     if (needClose) {
378       AsyncIteratorClose(iterated);
379     }
380   }
383 /* Iterator Helpers proposal 2.1.6.6 Prelude */
384 function AsyncIteratorAsIndexedPairs() {
385   // Step 1.
386   var iterated = GetIteratorDirect(this);
388   var iteratorHelper = NewAsyncIteratorHelper();
389   var generator = AsyncIteratorAsIndexedPairsGenerator(iterated);
390   callFunction(IntrinsicAsyncGeneratorNext, generator);
391   UnsafeSetReservedSlot(
392     iteratorHelper,
393     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
394     generator
395   );
396   return iteratorHelper;
399 /* Iterator Helpers proposal 2.1.6.6 Body */
400 async function* AsyncIteratorAsIndexedPairsGenerator(iterated) {
401   var needClose = true;
402   try {
403     yield;
404     needClose = false;
406     // Step 2.
407     var lastValue;
408     // Step 3.
409     for (
410       var next = await IteratorNext(iterated, lastValue), index = 0;
411       !next.done;
412       next = await IteratorNext(iterated, lastValue), index++
413     ) {
414       // Steps c-g.
415       var value = next.value;
417       needClose = true;
418       lastValue = yield [index, value];
419       needClose = false;
420     }
421   } finally {
422     if (needClose) {
423       AsyncIteratorClose(iterated);
424     }
425   }
428 /* Iterator Helpers proposal 2.1.6.7 Prelude */
429 function AsyncIteratorFlatMap(mapper) {
430   // Step 1.
431   var iterated = GetIteratorDirect(this);
433   // Step 2.
434   if (!IsCallable(mapper)) {
435     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper));
436   }
438   var iteratorHelper = NewAsyncIteratorHelper();
439   var generator = AsyncIteratorFlatMapGenerator(iterated, mapper);
440   callFunction(IntrinsicAsyncGeneratorNext, generator);
441   UnsafeSetReservedSlot(
442     iteratorHelper,
443     ASYNC_ITERATOR_HELPER_GENERATOR_SLOT,
444     generator
445   );
446   return iteratorHelper;
449 /* Iterator Helpers proposal 2.1.6.7 Body */
450 async function* AsyncIteratorFlatMapGenerator(iterated, mapper) {
451   var needClose = true;
452   try {
453     yield;
454     needClose = false;
456     // Step 1.
457     for (
458       var next = await IteratorNext(iterated);
459       !next.done;
460       next = await IteratorNext(iterated)
461     ) {
462       // Step c.
463       var value = next.value;
465       needClose = true;
466       // Step d.
467       var mapped = await callContentFunction(mapper, undefined, value);
468       // Steps f-k.
469       for await (var innerValue of allowContentIter(mapped)) {
470         yield innerValue;
471       }
472       needClose = false;
473     }
474   } finally {
475     if (needClose) {
476       AsyncIteratorClose(iterated);
477     }
478   }
481 /* Iterator Helpers proposal 2.1.6.8 */
482 async function AsyncIteratorReduce(reducer /*, initialValue*/) {
483   // Step 1.
484   var iterated = GetAsyncIteratorDirectWrapper(this);
486   // Step 2.
487   if (!IsCallable(reducer)) {
488     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, reducer));
489   }
491   // Step 3.
492   var accumulator;
493   if (ArgumentsLength() === 1) {
494     // Step a.
495     var next = await callContentFunction(iterated.next, iterated);
496     if (!IsObject(next)) {
497       ThrowTypeError(JSMSG_OBJECT_REQUIRED, DecompileArg(0, next));
498     }
499     // Step b.
500     if (next.done) {
501       ThrowTypeError(JSMSG_EMPTY_ITERATOR_REDUCE);
502     }
503     // Step c.
504     accumulator = next.value;
505   } else {
506     // Step 4.
507     accumulator = GetArgument(1);
508   }
510   // Step 5.
511   for await (var value of allowContentIter(iterated)) {
512     // Steps d-h.
513     accumulator = await callContentFunction(
514       reducer,
515       undefined,
516       accumulator,
517       value
518     );
519   }
520   // Step 5b.
521   return accumulator;
524 /* Iterator Helpers proposal 2.1.6.9 */
525 async function AsyncIteratorToArray() {
526   // Step 1.
527   var iterated = { [GetBuiltinSymbol("asyncIterator")]: () => this };
528   // Step 2.
529   var items = [];
530   var index = 0;
531   // Step 3.
532   for await (var value of allowContentIter(iterated)) {
533     // Step d.
534     DefineDataProperty(items, index++, value);
535   }
536   // Step 3b.
537   return items;
540 /* Iterator Helpers proposal 2.1.6.10 */
541 async function AsyncIteratorForEach(fn) {
542   // Step 1.
543   var iterated = GetAsyncIteratorDirectWrapper(this);
545   // Step 2.
546   if (!IsCallable(fn)) {
547     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn));
548   }
550   // Step 3.
551   for await (var value of allowContentIter(iterated)) {
552     // Steps d-g.
553     await callContentFunction(fn, undefined, value);
554   }
557 /* Iterator Helpers proposal 2.1.6.11 */
558 async function AsyncIteratorSome(fn) {
559   // Step 1.
560   var iterated = GetAsyncIteratorDirectWrapper(this);
562   // Step 2.
563   if (!IsCallable(fn)) {
564     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn));
565   }
567   // Step 3.
568   for await (var value of allowContentIter(iterated)) {
569     // Steps d-h.
570     if (await callContentFunction(fn, undefined, value)) {
571       return true;
572     }
573   }
574   // Step 3b.
575   return false;
578 /* Iterator Helpers proposal 2.1.6.12 */
579 async function AsyncIteratorEvery(fn) {
580   // Step 1.
581   var iterated = GetAsyncIteratorDirectWrapper(this);
583   // Step 2.
584   if (!IsCallable(fn)) {
585     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn));
586   }
588   // Step 3.
589   for await (var value of allowContentIter(iterated)) {
590     // Steps d-h.
591     if (!(await callContentFunction(fn, undefined, value))) {
592       return false;
593     }
594   }
595   // Step 3b.
596   return true;
599 /* Iterator Helpers proposal 2.1.6.13 */
600 async function AsyncIteratorFind(fn) {
601   // Step 1.
602   var iterated = GetAsyncIteratorDirectWrapper(this);
604   // Step 2.
605   if (!IsCallable(fn)) {
606     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn));
607   }
609   // Step 3.
610   for await (var value of allowContentIter(iterated)) {
611     // Steps d-h.
612     if (await callContentFunction(fn, undefined, value)) {
613       return value;
614     }
615   }