AsyncIteration.js (14743B)
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/. */ 4 5 function AsyncIteratorIdentity() { 6 return this; 7 } 8 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"); 15 } 16 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"); 23 } 24 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"); 31 } 32 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; 49 } 50 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 } 57 58 // Step 2. 59 var nextMethod = obj.next; 60 // Step 3. 61 if (!IsCallable(nextMethod)) { 62 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, nextMethod)); 63 } 64 65 // Steps 4-5. 66 return { 67 iterator: obj, 68 nextMethod, 69 done: false, 70 }; 71 } 72 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 } 79 80 // Step 2. 81 var nextMethod = obj.next; 82 // Step 3. 83 if (!IsCallable(nextMethod)) { 84 ThrowTypeError(JSMSG_NOT_FUNCTION, nextMethod); 85 } 86 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 }; 105 } 106 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); 123 } 124 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); 140 } 141 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); 157 } 158 159 // AsyncIterator lazy Iterator Helper methods 160 // Iterator Helpers proposal 2.1.6.2-2.1.6.7 161 // 162 // The AsyncIterator lazy methods are structured closely to how the Iterator 163 // lazy methods are. See builtin/Iterator.js for the reasoning. 164 165 /* Iterator Helpers proposal 2.1.6.2 Prelude */ 166 function AsyncIteratorMap(mapper) { 167 // Step 1. 168 var iterated = GetIteratorDirect(this); 169 170 // Step 2. 171 if (!IsCallable(mapper)) { 172 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper)); 173 } 174 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; 184 } 185 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; 195 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; 203 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 } 214 } 215 216 /* Iterator Helpers proposal 2.1.6.3 Prelude */ 217 function AsyncIteratorFilter(filterer) { 218 // Step 1. 219 var iterated = GetIteratorDirect(this); 220 221 // Step 2. 222 if (!IsCallable(filterer)) { 223 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, filterer)); 224 } 225 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; 235 } 236 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; 246 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; 254 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 } 267 } 268 269 /* Iterator Helpers proposal 2.1.6.4 Prelude */ 270 function AsyncIteratorTake(limit) { 271 // Step 1. 272 var iterated = GetIteratorDirect(this); 273 274 // Step 2. 275 var remaining = ToInteger(limit); 276 // Step 3. 277 if (remaining < 0) { 278 ThrowRangeError(JSMSG_NEGATIVE_LIMIT); 279 } 280 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; 290 } 291 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; 301 302 for (; remaining > 0; remaining--) { 303 var next = await IteratorNext(iterated, lastValue); 304 if (next.done) { 305 return undefined; 306 } 307 308 var value = next.value; 309 310 needClose = true; 311 lastValue = yield value; 312 needClose = false; 313 } 314 } finally { 315 if (needClose) { 316 AsyncIteratorClose(iterated, undefined); 317 } 318 } 319 320 return AsyncIteratorClose(iterated, undefined); 321 } 322 323 /* Iterator Helpers proposal 2.1.6.5 Prelude */ 324 function AsyncIteratorDrop(limit) { 325 // Step 1. 326 var iterated = GetIteratorDirect(this); 327 328 // Step 2. 329 var remaining = ToInteger(limit); 330 // Step 3. 331 if (remaining < 0) { 332 ThrowRangeError(JSMSG_NEGATIVE_LIMIT); 333 } 334 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; 344 } 345 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; 352 353 // Step 1. 354 for (; remaining > 0; remaining--) { 355 var next = await IteratorNext(iterated); 356 if (next.done) { 357 return; 358 } 359 } 360 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; 371 372 needClose = true; 373 lastValue = yield value; 374 needClose = false; 375 } 376 } finally { 377 if (needClose) { 378 AsyncIteratorClose(iterated); 379 } 380 } 381 } 382 383 /* Iterator Helpers proposal 2.1.6.6 Prelude */ 384 function AsyncIteratorAsIndexedPairs() { 385 // Step 1. 386 var iterated = GetIteratorDirect(this); 387 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; 397 } 398 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; 405 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; 416 417 needClose = true; 418 lastValue = yield [index, value]; 419 needClose = false; 420 } 421 } finally { 422 if (needClose) { 423 AsyncIteratorClose(iterated); 424 } 425 } 426 } 427 428 /* Iterator Helpers proposal 2.1.6.7 Prelude */ 429 function AsyncIteratorFlatMap(mapper) { 430 // Step 1. 431 var iterated = GetIteratorDirect(this); 432 433 // Step 2. 434 if (!IsCallable(mapper)) { 435 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper)); 436 } 437 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; 447 } 448 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; 455 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; 464 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 } 479 } 480 481 /* Iterator Helpers proposal 2.1.6.8 */ 482 async function AsyncIteratorReduce(reducer /*, initialValue*/) { 483 // Step 1. 484 var iterated = GetAsyncIteratorDirectWrapper(this); 485 486 // Step 2. 487 if (!IsCallable(reducer)) { 488 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, reducer)); 489 } 490 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 } 509 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; 522 } 523 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; 538 } 539 540 /* Iterator Helpers proposal 2.1.6.10 */ 541 async function AsyncIteratorForEach(fn) { 542 // Step 1. 543 var iterated = GetAsyncIteratorDirectWrapper(this); 544 545 // Step 2. 546 if (!IsCallable(fn)) { 547 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn)); 548 } 549 550 // Step 3. 551 for await (var value of allowContentIter(iterated)) { 552 // Steps d-g. 553 await callContentFunction(fn, undefined, value); 554 } 555 } 556 557 /* Iterator Helpers proposal 2.1.6.11 */ 558 async function AsyncIteratorSome(fn) { 559 // Step 1. 560 var iterated = GetAsyncIteratorDirectWrapper(this); 561 562 // Step 2. 563 if (!IsCallable(fn)) { 564 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn)); 565 } 566 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; 576 } 577 578 /* Iterator Helpers proposal 2.1.6.12 */ 579 async function AsyncIteratorEvery(fn) { 580 // Step 1. 581 var iterated = GetAsyncIteratorDirectWrapper(this); 582 583 // Step 2. 584 if (!IsCallable(fn)) { 585 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn)); 586 } 587 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; 597 } 598 599 /* Iterator Helpers proposal 2.1.6.13 */ 600 async function AsyncIteratorFind(fn) { 601 // Step 1. 602 var iterated = GetAsyncIteratorDirectWrapper(this); 603 604 // Step 2. 605 if (!IsCallable(fn)) { 606 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn)); 607 } 608 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 } 616 }