Iterator.js (53191B)
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 IteratorIdentity() { 6 return this; 7 } 8 9 /* ECMA262 7.2.7 */ 10 function IteratorNext(iteratorRecord, value) { 11 // Steps 1-2. 12 var result = 13 ArgumentsLength() < 2 14 ? callContentFunction(iteratorRecord.nextMethod, iteratorRecord.iterator) 15 : callContentFunction( 16 iteratorRecord.nextMethod, 17 iteratorRecord.iterator, 18 value 19 ); 20 // Step 3. 21 if (!IsObject(result)) { 22 ThrowTypeError(JSMSG_OBJECT_REQUIRED, result); 23 } 24 // Step 4. 25 return result; 26 } 27 28 // https://tc39.es/ecma262/#sec-getiterator 29 function GetIterator(obj, isAsync, method) { 30 // Step 1. If hint is not present, set hint to sync. 31 // Step 2. If method is not present, then 32 if (!method) { 33 // Step 2.a. If hint is async, then 34 if (isAsync) { 35 // Step 2.a.i. Set method to ? GetMethod(obj, @@asyncIterator). 36 method = GetMethod(obj, GetBuiltinSymbol("asyncIterator")); 37 38 // Step 2.a.ii. If method is undefined, then 39 if (!method) { 40 // Step 2.a.ii.1. Let syncMethod be ? GetMethod(obj, @@iterator). 41 var syncMethod = GetMethod(obj, GetBuiltinSymbol("iterator")); 42 43 // Step 2.a.ii.2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod). 44 var syncIteratorRecord = GetIterator(obj, false, syncMethod); 45 46 // Step 2.a.ii.2. Return CreateAsyncFromSyncIterator(syncIteratorRecord). 47 return CreateAsyncFromSyncIterator(syncIteratorRecord.iterator, syncIteratorRecord.nextMethod); 48 } 49 } else { 50 // Step 2.b. Otherwise, set method to ? GetMethod(obj, @@iterator). 51 method = GetMethod(obj, GetBuiltinSymbol("iterator")); 52 } 53 } 54 55 // Step 3. Let iterator be ? Call(method, obj). 56 var iterator = callContentFunction(method, obj); 57 58 // Step 4. If Type(iterator) is not Object, throw a TypeError exception. 59 if (!IsObject(iterator)) { 60 ThrowTypeError(JSMSG_NOT_ITERABLE, obj === null ? "null" : typeof obj); 61 } 62 63 // Step 5. Let nextMethod be ? GetV(iterator, "next"). 64 var nextMethod = iterator.next; 65 66 // Step 6. Let iteratorRecord be the Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }. 67 var iteratorRecord = { 68 __proto__: null, 69 iterator, 70 nextMethod, 71 done: false, 72 }; 73 74 // Step 7. Return iteratorRecord. 75 return iteratorRecord; 76 } 77 78 /** 79 * GetIteratorFlattenable ( obj, stringHandling ) 80 * 81 * https://tc39.es/ecma262/#sec-getiteratorflattenable 82 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 83 */ 84 function GetIteratorFlattenable(obj, rejectStrings) { 85 assert(typeof rejectStrings === "boolean", "rejectStrings is a boolean"); 86 87 // Step 1. 88 if (!IsObject(obj)) { 89 // Steps 1.a-c. 90 if (rejectStrings || typeof obj !== "string") { 91 ThrowTypeError(JSMSG_OBJECT_REQUIRED, obj === null ? "null" : typeof obj); 92 } 93 } 94 95 // Step 2. 96 var method = obj[GetBuiltinSymbol("iterator")]; 97 98 // Steps 3-4. 99 var iterator; 100 if (IsNullOrUndefined(method)) { 101 iterator = obj; 102 } else { 103 iterator = callContentFunction(method, obj); 104 } 105 106 // Step 5. 107 if (!IsObject(iterator)) { 108 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 109 } 110 111 // Step 6. (Caller must call GetIteratorDirect.) 112 return iterator; 113 } 114 115 /** 116 * Iterator.from ( O ) 117 * 118 * https://tc39.es/ecma262/#sec-iterator.from 119 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 120 */ 121 function IteratorFrom(O) { 122 // Step 1. (Inlined call to GetIteratorDirect.) 123 var iterator = GetIteratorFlattenable(O, /* rejectStrings= */ false); 124 var nextMethod = iterator.next; 125 126 // Step 2. 127 // 128 // Calls |isPrototypeOf| instead of |instanceof| to avoid looking up the 129 // `@@hasInstance` property. 130 var hasInstance = callFunction( 131 std_Object_isPrototypeOf, 132 GetBuiltinPrototype("Iterator"), 133 iterator 134 ); 135 136 // Step 3. 137 if (hasInstance) { 138 return iterator; 139 } 140 141 // Step 4. 142 var wrapper = NewWrapForValidIterator(); 143 144 // Step 5. 145 UnsafeSetReservedSlot( 146 wrapper, 147 WRAP_FOR_VALID_ITERATOR_ITERATOR_SLOT, 148 iterator 149 ); 150 UnsafeSetReservedSlot( 151 wrapper, 152 WRAP_FOR_VALID_ITERATOR_NEXT_METHOD_SLOT, 153 nextMethod 154 ); 155 156 // Step 6. 157 return wrapper; 158 } 159 160 /** 161 * %WrapForValidIteratorPrototype%.next ( ) 162 * 163 * https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.next 164 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 165 */ 166 function WrapForValidIteratorNext() { 167 // Steps 1-2. 168 var O = this; 169 if (!IsObject(O) || (O = GuardToWrapForValidIterator(O)) === null) { 170 return callFunction( 171 CallWrapForValidIteratorMethodIfWrapped, 172 this, 173 "WrapForValidIteratorNext" 174 ); 175 } 176 177 // Step 3. 178 var iterator = UnsafeGetReservedSlot(O, WRAP_FOR_VALID_ITERATOR_ITERATOR_SLOT); 179 var nextMethod = UnsafeGetReservedSlot(O, WRAP_FOR_VALID_ITERATOR_NEXT_METHOD_SLOT); 180 181 // Step 4. 182 return callContentFunction(nextMethod, iterator); 183 } 184 185 /** 186 * %WrapForValidIteratorPrototype%.return ( ) 187 * 188 * https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.return 189 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 190 */ 191 function WrapForValidIteratorReturn() { 192 // Steps 1-2. 193 var O = this; 194 if (!IsObject(O) || (O = GuardToWrapForValidIterator(O)) === null) { 195 return callFunction( 196 CallWrapForValidIteratorMethodIfWrapped, 197 this, 198 "WrapForValidIteratorReturn" 199 ); 200 } 201 202 // Step 3. 203 var iterator = UnsafeGetReservedSlot(O, WRAP_FOR_VALID_ITERATOR_ITERATOR_SLOT); 204 205 // Step 4. 206 assert(IsObject(iterator), "iterator is an object"); 207 208 // Step 5. 209 var returnMethod = iterator.return; 210 211 // Step 6. 212 if (IsNullOrUndefined(returnMethod)) { 213 return { 214 value: undefined, 215 done: true, 216 }; 217 } 218 219 // Step 7. 220 return callContentFunction(returnMethod, iterator); 221 } 222 223 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 224 /** 225 * Explicit Resource Management Proposal 226 * 27.1.2.1 %IteratorPrototype% [ @@dispose ] ( ) 227 * https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-%25iteratorprototype%25-%40%40dispose 228 */ 229 function IteratorDispose() { 230 // Step 1. Let O be the this value. 231 var O = this; 232 233 // Step 2. Let return be ? GetMethod(O, "return"). 234 var returnMethod = GetMethod(O, "return"); 235 236 // Step 3. If return is not undefined, then 237 if (returnMethod !== undefined) { 238 // Step 3.a. Perform ? Call(return, O, « »). 239 callContentFunction(returnMethod, O); 240 } 241 242 // Step 4. Return NormalCompletion(empty). (implicit) 243 } 244 #endif 245 246 /** 247 * %IteratorHelperPrototype%.next ( ) 248 * 249 * https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.next 250 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 251 */ 252 function IteratorHelperNext() { 253 // Step 1. 254 var O = this; 255 if (!IsObject(O) || (O = GuardToIteratorHelper(O)) === null) { 256 return callFunction( 257 CallIteratorHelperMethodIfWrapped, 258 this, 259 "IteratorHelperNext" 260 ); 261 } 262 var generator = UnsafeGetReservedSlot(O, ITERATOR_HELPER_GENERATOR_SLOT); 263 return callFunction(GeneratorNext, generator, undefined); 264 } 265 266 /** 267 * %IteratorHelperPrototype%.return ( ) 268 * 269 * https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.return 270 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 271 */ 272 function IteratorHelperReturn() { 273 // Step 1. 274 var O = this; 275 276 // Step 2. 277 if (!IsObject(O) || (O = GuardToIteratorHelper(O)) === null) { 278 return callFunction( 279 CallIteratorHelperMethodIfWrapped, 280 this, 281 "IteratorHelperReturn" 282 ); 283 } 284 285 // Step 3. (Implicit) 286 287 // Step 4 (Partial). If O.[[GeneratorState]] is suspended-start, then 288 // 289 // Retrieve the current resume index before calling GeneratorReturn. 290 var generator = UnsafeGetReservedSlot(O, ITERATOR_HELPER_GENERATOR_SLOT); 291 var resumeIndex = UnsafeGetReservedSlot(generator, GENERATOR_RESUME_INDEX_SLOT); 292 assert( 293 resumeIndex === undefined || 294 resumeIndex === null || 295 typeof resumeIndex === "number", 296 "unexpected resumeIndex value" 297 ); 298 299 // If the generator was suspended at the initial yield, then the generator 300 // state is "suspended-start". 301 var isSuspendedStart = resumeIndex === GENERATOR_RESUME_INDEX_INITIAL_YIELD; 302 assert( 303 !isSuspendedStart || IsSuspendedGenerator(generator), 304 "unexpected 'suspended-start' state for non-suspended generator" 305 ); 306 307 // Step 4.a. Set O.[[GeneratorState]] to completed. 308 // Step 4.b. NOTE: (elided) 309 // Step 4.d. Return CreateIteratorResultObject(undefined, true). 310 // Step 5. Let C be ReturnCompletion(undefined). 311 // Step 6. Return ? GeneratorResumeAbrupt(O, C, "Iterator Helper"). 312 var result = callFunction(GeneratorReturn, generator, undefined); 313 314 // Step 4 (Cont'ed). If O.[[GeneratorState]] is suspended-start, then 315 // 316 // Performed after GeneratorReturn, so even if IteratorClose throws an error, 317 // it's not possible to re-enter the generator. 318 if (isSuspendedStart) { 319 var underlyingIterator = UnsafeGetReservedSlot(O, ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT); 320 assert( 321 underlyingIterator === undefined || IsObject(underlyingIterator), 322 "underlyingIterator is undefined or an object" 323 ); 324 325 // Step 4.c. Perform ? IteratorClose(O.[[UnderlyingIterator]], NormalCompletion(unused)). 326 // 327 // NB: |underlyingIterator| can be `undefined` for IteratorConcat. 328 if (IsObject(underlyingIterator)) { 329 IteratorClose(underlyingIterator); 330 } 331 } 332 333 return result; 334 } 335 336 // Lazy %Iterator.prototype% methods 337 // 338 // In order to match the semantics of the built-in generator objects, we use a 339 // reserved slot on the IteratorHelper objects to store a regular generator that 340 // is called from the %IteratorHelper.prototype% methods. 341 // 342 // Each of the lazy methods is divided into a prelude and a body, with the 343 // eager prelude steps being contained in the corresponding IteratorX method 344 // and the lazy body steps inside the IteratorXGenerator generator functions. 345 // 346 // Each prelude method initializes and returns a new IteratorHelper object. 347 // As part of this initialization process, the appropriate generator function 348 // is called and stored in the IteratorHelper object, alongside the underlying 349 // iterator object. 350 351 /** 352 * Iterator.prototype.map ( mapper ) 353 * 354 * https://tc39.es/ecma262/#sec-iterator.prototype.map 355 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 356 */ 357 function IteratorMap(mapper) { 358 // Step 1. 359 var iterator = this; 360 361 // Step 2. 362 if (!IsObject(iterator)) { 363 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 364 } 365 366 // Steps 3-4. 367 if (!IsCallable(mapper)) { 368 try { 369 IteratorClose(iterator); 370 } catch {} 371 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper)); 372 } 373 374 // Step 5. (Inlined call to GetIteratorDirect.) 375 var nextMethod = iterator.next; 376 377 // Steps 6-8. 378 var result = NewIteratorHelper(); 379 var generator = IteratorMapGenerator(iterator, nextMethod, mapper); 380 UnsafeSetReservedSlot( 381 result, 382 ITERATOR_HELPER_GENERATOR_SLOT, 383 generator 384 ); 385 UnsafeSetReservedSlot( 386 result, 387 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 388 iterator 389 ); 390 391 // Step 9. 392 return result; 393 } 394 395 /** 396 * Iterator.prototype.map ( mapper ) 397 * 398 * Abstract closure definition. 399 * 400 * https://tc39.es/ecma262/#sec-iterator.prototype.map 401 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 402 */ 403 function* IteratorMapGenerator(iterator, nextMethod, mapper) { 404 // Step 6.a. 405 var counter = 0; 406 407 // Step 6.b. 408 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 409 // Steps 6.b.i-ii. (Implicit through for-of loop) 410 411 // Step 6.b.iii. 412 var mapped = callContentFunction(mapper, undefined, value, counter); 413 414 // Step 6.b.iv. (Implicit through for-of loop) 415 416 // Step 6.b.v. 417 yield mapped; 418 419 // Step 6.b.vi. (Implicit through for-of loop) 420 421 // Step 6.b.vii. 422 counter += 1; 423 } 424 } 425 426 /** 427 * Iterator.prototype.filter ( predicate ) 428 * 429 * https://tc39.es/ecma262/#sec-iterator.prototype.filter 430 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 431 */ 432 function IteratorFilter(predicate) { 433 // Step 1. 434 var iterator = this; 435 436 // Step 2. 437 if (!IsObject(iterator)) { 438 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 439 } 440 441 // Steps 3-4. 442 if (!IsCallable(predicate)) { 443 try { 444 IteratorClose(iterator); 445 } catch {} 446 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 447 } 448 449 // Step 5. (Inlined call to GetIteratorDirect.) 450 var nextMethod = iterator.next; 451 452 // Steps 6-8. 453 var result = NewIteratorHelper(); 454 var generator = IteratorFilterGenerator(iterator, nextMethod, predicate); 455 UnsafeSetReservedSlot( 456 result, 457 ITERATOR_HELPER_GENERATOR_SLOT, 458 generator 459 ); 460 UnsafeSetReservedSlot( 461 result, 462 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 463 iterator 464 ); 465 466 // Step 9. 467 return result; 468 } 469 470 /** 471 * Iterator.prototype.filter ( predicate ) 472 * 473 * Abstract closure definition. 474 * 475 * https://tc39.es/ecma262/#sec-iterator.prototype.filter 476 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 477 */ 478 function* IteratorFilterGenerator(iterator, nextMethod, predicate) { 479 // Step 6.a. 480 var counter = 0; 481 482 // Step 6.b. 483 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 484 // Steps 6.b.i-ii. (Implicit through for-of loop) 485 486 // Step 6.b.iii. 487 var selected = callContentFunction(predicate, undefined, value, counter); 488 489 // Step 6.b.iv. (Implicit through for-of loop) 490 491 // Step 6.b.v. 492 if (selected) { 493 // Step 6.b.v.1. 494 yield value; 495 496 // Step 6.b.v.2. (Implicit through for-of loop) 497 } 498 499 // Step 6.b.vi. 500 counter += 1; 501 } 502 } 503 504 /** 505 * Iterator.prototype.take ( limit ) 506 * 507 * https://tc39.es/ecma262/#sec-iterator.prototype.take 508 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 509 */ 510 function IteratorTake(limit) { 511 // Step 1. 512 var iterator = this; 513 514 // Step 2. 515 if (!IsObject(iterator)) { 516 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 517 } 518 519 // Steps 3-5. 520 var numLimit; 521 try { 522 numLimit = +limit; 523 } catch (e) { 524 try { 525 IteratorClose(iterator); 526 } catch {} 527 throw e; 528 } 529 530 // Steps 6-8. 531 var integerLimit = std_Math_trunc(numLimit); 532 if (!(integerLimit >= 0)) { 533 try { 534 IteratorClose(iterator); 535 } catch {} 536 ThrowRangeError(JSMSG_NEGATIVE_LIMIT); 537 } 538 539 // Step 9. (Inlined call to GetIteratorDirect.) 540 var nextMethod = iterator.next; 541 542 // Steps 10-12. 543 var result = NewIteratorHelper(); 544 var generator = IteratorTakeGenerator(iterator, nextMethod, integerLimit); 545 UnsafeSetReservedSlot( 546 result, 547 ITERATOR_HELPER_GENERATOR_SLOT, 548 generator 549 ); 550 UnsafeSetReservedSlot( 551 result, 552 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 553 iterator 554 ); 555 556 // Step 13. 557 return result; 558 } 559 560 /** 561 * Iterator.prototype.take ( limit ) 562 * 563 * Abstract closure definition. 564 * 565 * https://tc39.es/ecma262/#sec-iterator.prototype.take 566 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 567 */ 568 function* IteratorTakeGenerator(iterator, nextMethod, remaining) { 569 // Step 8.a. (Implicit) 570 571 // Step 8.b.i. (Reordered before for-of loop entry) 572 if (remaining === 0) { 573 IteratorClose(iterator); 574 return; 575 } 576 577 // Step 8.b. 578 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 579 // Steps 8.b.iii-iv. (Implicit through for-of loop) 580 581 // Step 8.b.v. 582 yield value; 583 584 // Step 8.b.vi. (Implicit through for-of loop) 585 586 // Steps 8.b.i-ii. (Reordered) 587 if (--remaining === 0) { 588 // |break| implicitly calls IteratorClose. 589 break; 590 } 591 } 592 } 593 594 /** 595 * Iterator.prototype.drop ( limit ) 596 * 597 * https://tc39.es/ecma262/#sec-iterator.prototype.drop 598 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 599 */ 600 function IteratorDrop(limit) { 601 // Step 1. 602 var iterator = this; 603 604 // Step 2. 605 if (!IsObject(iterator)) { 606 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 607 } 608 609 // Steps 3-5. 610 var numLimit; 611 try { 612 numLimit = +limit; 613 } catch (e) { 614 try { 615 IteratorClose(iterator); 616 } catch {} 617 throw e; 618 } 619 620 // Steps 6-8. 621 var integerLimit = std_Math_trunc(numLimit); 622 if (!(integerLimit >= 0)) { 623 try { 624 IteratorClose(iterator); 625 } catch {} 626 ThrowRangeError(JSMSG_NEGATIVE_LIMIT); 627 } 628 629 // Step 9. (Inlined call to GetIteratorDirect.) 630 var nextMethod = iterator.next; 631 632 // Steps 10-12. 633 var result = NewIteratorHelper(); 634 var generator = IteratorDropGenerator(iterator, nextMethod, integerLimit); 635 UnsafeSetReservedSlot( 636 result, 637 ITERATOR_HELPER_GENERATOR_SLOT, 638 generator 639 ); 640 UnsafeSetReservedSlot( 641 result, 642 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 643 iterator 644 ); 645 646 // Step 13. 647 return result; 648 } 649 650 /** 651 * Iterator.prototype.drop ( limit ) 652 * 653 * Abstract closure definition. 654 * 655 * https://tc39.es/ecma262/#sec-iterator.prototype.drop 656 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 657 */ 658 function* IteratorDropGenerator(iterator, nextMethod, remaining) { 659 // Step 10.a. (Implicit) 660 661 // Steps 10.b-c. 662 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 663 // Step 10.b.i. 664 if (remaining-- <= 0) { 665 // Steps 10.b.ii-iii. (Implicit through for-of loop) 666 // Steps 10.c.i-ii. (Implicit through for-of loop) 667 668 // Step 10.c.iii. 669 yield value; 670 671 // Step 10.c.iv. (Implicit through for-of loop) 672 } 673 } 674 } 675 676 /** 677 * Iterator.prototype.flatMap ( mapper ) 678 * 679 * https://tc39.es/ecma262/#sec-iterator.prototype.flatmap 680 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 681 */ 682 function IteratorFlatMap(mapper) { 683 // Step 1. 684 var iterator = this; 685 686 // Step 2. 687 if (!IsObject(iterator)) { 688 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 689 } 690 691 // Steps 3-4. 692 if (!IsCallable(mapper)) { 693 try { 694 IteratorClose(iterator); 695 } catch {} 696 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapper)); 697 } 698 699 // Step 5. (Inlined call to GetIteratorDirect.) 700 var nextMethod = iterator.next; 701 702 // Steps 6-8. 703 var result = NewIteratorHelper(); 704 var generator = IteratorFlatMapGenerator(iterator, nextMethod, mapper); 705 UnsafeSetReservedSlot( 706 result, 707 ITERATOR_HELPER_GENERATOR_SLOT, 708 generator 709 ); 710 UnsafeSetReservedSlot( 711 result, 712 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 713 iterator 714 ); 715 716 // Step 9. 717 return result; 718 } 719 720 /** 721 * Iterator.prototype.flatMap ( mapper ) 722 * 723 * Abstract closure definition. 724 * 725 * https://tc39.es/ecma262/#sec-iterator.prototype.flatmap 726 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 727 */ 728 function* IteratorFlatMapGenerator(iterator, nextMethod, mapper) { 729 // Step 6.a. 730 var counter = 0; 731 732 // Step 6.b. 733 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 734 // Steps 6.b.i-ii. (Implicit through for-of loop) 735 736 // Step 6.b.iii. 737 var mapped = callContentFunction(mapper, undefined, value, counter); 738 739 // Step 6.b.iv. (Implicit through for-of loop) 740 741 // Steps 6.b.v. 742 var innerIterator = GetIteratorFlattenable(mapped, /* rejectStrings= */ true); 743 var innerIteratorNextMethod = innerIterator.next; 744 745 // Step 6.b.vi. (Implicit through for-of loop) 746 747 // Steps 6.b.vii-viii. 748 for (var innerValue of allowContentIterWithNext(innerIterator, innerIteratorNextMethod)) { 749 // Steps 6.b.viii.1-3. (Implicit through for-of loop) 750 751 // Step 6.b.viii.4.a. 752 yield innerValue; 753 754 // Step 6.b.viii.4.b. (Implicit through for-of loop) 755 } 756 757 // Step 6.b.ix. 758 counter += 1; 759 } 760 } 761 762 /** 763 * Iterator.prototype.reduce ( reducer [ , initialValue ] ) 764 * 765 * https://tc39.es/ecma262/#sec-iterator.prototype.reduce 766 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 767 */ 768 function IteratorReduce(reducer /*, initialValue*/) { 769 // Step 1. 770 var iterator = this; 771 772 // Step 2. 773 if (!IsObject(iterator)) { 774 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 775 } 776 777 // Steps 3-4. 778 if (!IsCallable(reducer)) { 779 try { 780 IteratorClose(iterator); 781 } catch {} 782 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, reducer)); 783 } 784 785 // Step 5. (Inlined call to GetIteratorDirect.) 786 var nextMethod = iterator.next; 787 788 // Steps 6-7. 789 var accumulator; 790 var counter; 791 if (ArgumentsLength() === 1) { 792 // Steps 6.a-d. (Moved below.) 793 counter = -1; 794 } else { 795 // Step 7.a. 796 accumulator = GetArgument(1); 797 798 // Step 7.b. 799 counter = 0; 800 } 801 802 // Step 8. 803 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 804 if (counter < 0) { 805 // Step 6. (Reordered steps to compute initial accumulator.) 806 807 // Step 6.c. 808 accumulator = value; 809 810 // Step 6.d. 811 counter = 1; 812 } else { 813 // Steps 8.a-b and 8.d. (Implicit through for-of loop) 814 815 // Steps 8.c and 8.e-f. 816 accumulator = callContentFunction(reducer, undefined, accumulator, value, counter++); 817 } 818 } 819 820 // Step 6.b. 821 if (counter < 0) { 822 ThrowTypeError(JSMSG_EMPTY_ITERATOR_REDUCE); 823 } 824 825 // Step 8.b. 826 return accumulator; 827 } 828 829 /** 830 * Iterator.prototype.toArray ( ) 831 * 832 * https://tc39.es/ecma262/#sec-iterator.prototype.toarray 833 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 834 */ 835 function IteratorToArray() { 836 // Step 1. 837 var iterator = this; 838 839 // Step 2. 840 if (!IsObject(iterator)) { 841 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 842 } 843 844 // Step 3. (Inlined call to GetIteratorDirect.) 845 var nextMethod = iterator.next; 846 847 // Steps 4-5. 848 return [...allowContentIterWithNext(iterator, nextMethod)]; 849 } 850 851 /** 852 * Iterator.prototype.forEach ( fn ) 853 * 854 * https://tc39.es/ecma262/#sec-iterator.prototype.foreach 855 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 856 */ 857 function IteratorForEach(fn) { 858 // Step 1. 859 var iterator = this; 860 861 // Step 2. 862 if (!IsObject(iterator)) { 863 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 864 } 865 866 // Steps 3-4. 867 if (!IsCallable(fn)) { 868 try { 869 IteratorClose(iterator); 870 } catch {} 871 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, fn)); 872 } 873 874 // Step 5. (Inlined call to GetIteratorDirect.) 875 var nextMethod = iterator.next; 876 877 // Step 6. 878 var counter = 0; 879 880 // Step 7. 881 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 882 // Steps 7.a-b. (Implicit through for-of loop) 883 884 // Steps 7.c and 7.e. 885 callContentFunction(fn, undefined, value, counter++); 886 887 // Step 7.d. (Implicit through for-of loop) 888 } 889 } 890 891 /** 892 * Iterator.prototype.some ( predicate ) 893 * 894 * https://tc39.es/ecma262/#sec-iterator.prototype.some 895 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 896 */ 897 function IteratorSome(predicate) { 898 // Step 1. 899 var iterator = this; 900 901 // Step 2. 902 if (!IsObject(iterator)) { 903 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 904 } 905 906 // Steps 3-4. 907 if (!IsCallable(predicate)) { 908 try { 909 IteratorClose(iterator); 910 } catch {} 911 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 912 } 913 914 // Step 5. (Inlined call to GetIteratorDirect.) 915 var nextMethod = iterator.next; 916 917 // Step 6. 918 var counter = 0; 919 920 // Step 7. 921 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 922 // Steps 7.a-b. (Implicit through for-of loop) 923 924 // Steps 7.c-f. 925 if (callContentFunction(predicate, undefined, value, counter++)) { 926 return true; 927 } 928 } 929 930 // Step 7.b. 931 return false; 932 } 933 934 /** 935 * Iterator.prototype.every ( predicate ) 936 * 937 * https://tc39.es/ecma262/#sec-iterator.prototype.every 938 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 939 */ 940 function IteratorEvery(predicate) { 941 // Step 1. 942 var iterator = this; 943 944 // Step 2. 945 if (!IsObject(iterator)) { 946 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 947 } 948 949 // Steps 3-4. 950 if (!IsCallable(predicate)) { 951 try { 952 IteratorClose(iterator); 953 } catch {} 954 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 955 } 956 957 // Step 5. (Inlined call to GetIteratorDirect.) 958 var nextMethod = iterator.next; 959 960 // Step 6. 961 var counter = 0; 962 963 // Step 7. 964 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 965 // Steps 7.a-b. (Implicit through for-of loop) 966 967 // Steps 7.c-f. 968 if (!callContentFunction(predicate, undefined, value, counter++)) { 969 return false; 970 } 971 } 972 973 // Step 7.b. 974 return true; 975 } 976 977 /** 978 * Iterator.prototype.find ( predicate ) 979 * 980 * https://tc39.es/ecma262/#sec-iterator.prototype.find 981 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16 982 */ 983 function IteratorFind(predicate) { 984 // Step 1. 985 var iterator = this; 986 987 // Step 2. 988 if (!IsObject(iterator)) { 989 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 990 } 991 992 // Steps 3-4. 993 if (!IsCallable(predicate)) { 994 try { 995 IteratorClose(iterator); 996 } catch {} 997 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 998 } 999 1000 // Step 5. (Inlined call to GetIteratorDirect.) 1001 var nextMethod = iterator.next; 1002 1003 // Step 6. 1004 var counter = 0; 1005 1006 // Step 7. 1007 for (var value of allowContentIterWithNext(iterator, nextMethod)) { 1008 // Steps 7.a-b. (Implicit through for-of loop) 1009 1010 // Steps 7.c-f. 1011 if (callContentFunction(predicate, undefined, value, counter++)) { 1012 return value; 1013 } 1014 } 1015 } 1016 1017 /** 1018 * Iterator.concat ( ...items ) 1019 * 1020 * https://tc39.es/proposal-iterator-sequencing/ 1021 */ 1022 function IteratorConcat() { 1023 // Step 1. 1024 // 1025 // Stored in reversed order to simplify removing processed items. 1026 var index = ArgumentsLength() * 2; 1027 var iterables = std_Array(index); 1028 1029 // Step 2. 1030 for (var i = 0; i < ArgumentsLength(); i++) { 1031 var item = GetArgument(i); 1032 1033 // Step 2.a. 1034 if (!IsObject(item)) { 1035 ThrowTypeError(JSMSG_OBJECT_REQUIRED, typeof item); 1036 } 1037 1038 // Step 2.b. (Inlined GetMethod) 1039 var method = item[GetBuiltinSymbol("iterator")]; 1040 1041 // Step 2.c. 1042 if (!IsCallable(method)) { 1043 ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(item)); 1044 } 1045 1046 // Step 2.d. 1047 DefineDataProperty(iterables, --index, item); 1048 DefineDataProperty(iterables, --index, method); 1049 } 1050 assert(index === 0, "all items stored"); 1051 1052 // Steps 3-5. 1053 var result = NewIteratorHelper(); 1054 var generator = IteratorConcatGenerator(iterables); 1055 UnsafeSetReservedSlot( 1056 result, 1057 ITERATOR_HELPER_GENERATOR_SLOT, 1058 generator 1059 ); 1060 // ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT is unused because IteratorConcat 1061 // doesn't have an underlying iterator. 1062 1063 // Step 6. 1064 return result; 1065 } 1066 1067 /** 1068 * Iterator.concat ( ...items ) 1069 * 1070 * https://tc39.es/proposal-iterator-sequencing/ 1071 */ 1072 function* IteratorConcatGenerator(iterables) { 1073 assert(IsArray(iterables), "iterables is an array"); 1074 assert(iterables.length % 2 === 0, "iterables contains pairs (item, method)"); 1075 1076 // Step 3.a. 1077 for (var i = iterables.length; i > 0;) { 1078 var item = iterables[--i]; 1079 var method = iterables[--i]; 1080 1081 // Remove processed items to avoid keeping them alive. 1082 iterables.length -= 2; 1083 1084 // Steps 3.a.i-v. 1085 for (var innerValue of allowContentIterWith(item, method)) { 1086 // Steps 3.a.v.1-3. (Implicit through for-of loop) 1087 1088 yield innerValue; 1089 } 1090 } 1091 } 1092 1093 /** 1094 * Iterator.zip (iterables [, options]) 1095 * 1096 * https://tc39.es/proposal-joint-iteration/#sec-iterator.zip 1097 */ 1098 function IteratorZip(iterables, options = undefined) { 1099 // Step 1. 1100 if (!IsObject(iterables)) { 1101 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterables === null ? "null" : typeof iterables); 1102 } 1103 1104 // Steps 2-7. 1105 if (options !== undefined) { 1106 // Step 2. (Inlined GetOptionsObject) 1107 if (!IsObject(options)) { 1108 ThrowTypeError( 1109 JSMSG_OBJECT_REQUIRED_ARG, "options", "Iterator.zip", ToSource(options) 1110 ); 1111 } 1112 1113 // Step 3. 1114 var mode = options.mode; 1115 1116 // Step 4. 1117 if (mode === undefined) { 1118 mode = "shortest"; 1119 } 1120 1121 // Step 5. 1122 if (mode !== "shortest" && mode !== "longest" && mode !== "strict") { 1123 if (typeof mode !== "string") { 1124 ThrowTypeError( 1125 JSMSG_ITERATOR_ZIP_INVALID_OPTION_TYPE, 1126 "mode", 1127 mode === null ? "null" : typeof mode 1128 ); 1129 } 1130 ThrowTypeError( 1131 JSMSG_ITERATOR_ZIP_INVALID_OPTION_VALUE, "mode", ToSource(mode) 1132 ); 1133 } 1134 1135 // Step 6. 1136 var paddingOption = undefined; 1137 1138 // Step 7. 1139 if (mode === "longest") { 1140 // Step 7.a. 1141 paddingOption = options.padding; 1142 1143 // Step 7.b. 1144 if (paddingOption !== undefined && !IsObject(paddingOption)) { 1145 ThrowTypeError( 1146 JSMSG_ITERATOR_ZIP_INVALID_OPTION_TYPE, 1147 "padding", 1148 padding === null ? "null" : typeof padding 1149 ); 1150 } 1151 } 1152 } else { 1153 // Step 4. 1154 var mode = "shortest"; 1155 } 1156 1157 // Step 8. 1158 var iters = []; 1159 var nextMethods = []; 1160 1161 // Steps 10-12. 1162 try { 1163 var closedIterators = false; 1164 for (var iter of allowContentIter(iterables)) { 1165 // Step 12.a. (Implicit) 1166 1167 // Step 12.c.i. 1168 try { 1169 iter = GetIteratorFlattenable(iter, /* rejectStrings= */ true); 1170 var nextMethod = iter.next; 1171 } catch (e) { 1172 // Step 12.c.ii. 1173 closedIterators = true; 1174 IteratorCloseAllForException(iters); 1175 throw e; 1176 } 1177 1178 // Step 12.c.iii. 1179 DefineDataProperty(iters, iters.length, iter); 1180 DefineDataProperty(nextMethods, nextMethods.length, nextMethod); 1181 } 1182 } catch (e) { 1183 // Step 12.b. 1184 if (!closedIterators) { 1185 IteratorCloseAllForException(iters); 1186 } 1187 throw e; 1188 } 1189 1190 // Step 14. 1191 if (mode === "longest") { 1192 // Step 9. (Reordered) 1193 var padding = []; 1194 1195 // Step 13. (Reordered) 1196 var iterCount = iters.length; 1197 1198 // Steps 14.b. 1199 if (paddingOption !== undefined) { 1200 // Steps 14.b.i-v. 1201 try { 1202 // Take care to not execute IteratorStepValue when |iterCount| is zero. 1203 if (iterCount > 0) { 1204 for (var paddingValue of allowContentIter(paddingOption)) { 1205 DefineDataProperty(padding, padding.length, paddingValue); 1206 1207 // |break| statement to perform IteratorClose. 1208 if (padding.length === iterCount) { 1209 break; 1210 } 1211 } 1212 } else { 1213 // Empty array destructuring performs GetIterator + IteratorClose. 1214 // eslint-disable-next-line no-empty-pattern 1215 var [] = allowContentIter(paddingOption); 1216 } 1217 } catch (e) { 1218 // Steps 14.b.ii, 14.b.iv.1.b, 14.b.v.2. 1219 IteratorCloseAllForException(iters); 1220 throw e; 1221 } 1222 } 1223 1224 // Steps 14.a.i and 14.b.iv.2. 1225 // 1226 // Fill with |undefined| up to |iterCount|. 1227 for (var i = padding.length; i < iterCount; i++) { 1228 DefineDataProperty(padding, i, undefined); 1229 } 1230 } 1231 1232 // Steps 15-16. 1233 var result = NewIteratorHelper(); 1234 var generator = IteratorZipGenerator(iters, nextMethods, mode, padding); 1235 var closeIterator = { 1236 return() { 1237 IteratorCloseAllForReturn(iters); 1238 return {}; 1239 } 1240 }; 1241 UnsafeSetReservedSlot( 1242 result, 1243 ITERATOR_HELPER_GENERATOR_SLOT, 1244 generator 1245 ); 1246 UnsafeSetReservedSlot( 1247 result, 1248 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 1249 closeIterator 1250 ); 1251 1252 return result; 1253 } 1254 1255 /** 1256 * Iterator.zipKeyed ( iterables [, options] ) 1257 * 1258 * https://tc39.es/proposal-joint-iteration/#sec-iterator.zipkeyed 1259 */ 1260 function IteratorZipKeyed(iterables, options = undefined) { 1261 // Step 1. 1262 if (!IsObject(iterables)) { 1263 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterables === null ? "null" : typeof iterables); 1264 } 1265 1266 // Steps 2-7. 1267 if (options !== undefined) { 1268 // Step 2. (Inlined GetOptionsObject) 1269 if (!IsObject(options)) { 1270 ThrowTypeError( 1271 JSMSG_OBJECT_REQUIRED_ARG, "options", "Iterator.zipKeyed", ToSource(options) 1272 ); 1273 } 1274 1275 // Step 3. 1276 var mode = options.mode; 1277 1278 // Step 4. 1279 if (mode === undefined) { 1280 mode = "shortest"; 1281 } 1282 1283 // Step 5. 1284 if (mode !== "shortest" && mode !== "longest" && mode !== "strict") { 1285 if (typeof mode !== "string") { 1286 ThrowTypeError( 1287 JSMSG_ITERATOR_ZIP_INVALID_OPTION_TYPE, 1288 "mode", 1289 mode === null ? "null" : typeof mode 1290 ); 1291 } 1292 ThrowTypeError( 1293 JSMSG_ITERATOR_ZIP_INVALID_OPTION_VALUE, "mode", ToSource(mode) 1294 ); 1295 } 1296 1297 // Step 6. 1298 var paddingOption = undefined; 1299 1300 // Step 7. 1301 if (mode === "longest") { 1302 // Step 7.a. 1303 paddingOption = options.padding; 1304 1305 // Step 7.b. 1306 if (paddingOption !== undefined && !IsObject(paddingOption)) { 1307 ThrowTypeError( 1308 JSMSG_ITERATOR_ZIP_INVALID_OPTION_TYPE, 1309 "padding", 1310 padding === null ? "null" : typeof padding 1311 ); 1312 } 1313 } 1314 } else { 1315 // Step 4. 1316 var mode = "shortest"; 1317 } 1318 1319 // Step 8. 1320 var iters = []; 1321 var nextMethods = []; 1322 1323 // Step 10. 1324 var allKeys = std_Reflect_ownKeys(iterables); 1325 1326 // Step 11. 1327 var keys = []; 1328 1329 // Step 12. 1330 try { 1331 for (var i = 0; i < allKeys.length; i++) { 1332 var key = allKeys[i]; 1333 1334 // Step 12.a. 1335 var desc = ObjectGetOwnPropertyDescriptor(iterables, key); 1336 1337 // Step 12.c. 1338 if (desc && desc.enumerable) { 1339 // Step 12.c.i. 1340 var value = iterables[key]; 1341 1342 // Step 12.c.iii. 1343 if (value !== undefined) { 1344 // Step 12.c.iii.1. 1345 DefineDataProperty(keys, keys.length, key); 1346 1347 // Step 12.c.iii.2. 1348 var iter = GetIteratorFlattenable(value, /* rejectStrings= */ true); 1349 var nextMethod = iter.next; 1350 1351 // Step 12.c.iii.4. 1352 DefineDataProperty(iters, iters.length, iter); 1353 DefineDataProperty(nextMethods, nextMethods.length, nextMethod); 1354 } 1355 } 1356 } 1357 } catch (e) { 1358 // Steps 12.b, 12.c.ii, and 12.c.iii.3. 1359 IteratorCloseAllForException(iters); 1360 throw e; 1361 } 1362 1363 // Step 14. 1364 if (mode === "longest") { 1365 // Step 9. (Reordered) 1366 var padding = []; 1367 1368 // Steps 14.a-b. 1369 if (paddingOption === undefined) { 1370 // Step 13. (Reordered) 1371 var iterCount = iters.length; 1372 1373 // Step 14.1.i. 1374 for (var i = 0; i < iterCount; i++) { 1375 DefineDataProperty(padding, i, undefined); 1376 } 1377 } else { 1378 try { 1379 // Step 14.b.i. 1380 for (var i = 0; i < keys.length; i++) { 1381 DefineDataProperty(padding, i, paddingOption[keys[i]]); 1382 } 1383 } catch (e) { 1384 // Step 14.b.i.2. 1385 IteratorCloseAllForException(iters); 1386 throw e; 1387 } 1388 } 1389 } 1390 1391 // Steps 15-16. 1392 var result = NewIteratorHelper(); 1393 var generator = IteratorZipGenerator(iters, nextMethods, mode, padding, keys); 1394 var closeIterator = { 1395 return() { 1396 IteratorCloseAllForReturn(iters); 1397 return {}; 1398 } 1399 }; 1400 UnsafeSetReservedSlot( 1401 result, 1402 ITERATOR_HELPER_GENERATOR_SLOT, 1403 generator 1404 ); 1405 UnsafeSetReservedSlot( 1406 result, 1407 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 1408 closeIterator 1409 ); 1410 1411 return result; 1412 } 1413 1414 /** 1415 * IteratorZip ( iters, mode, padding, finishResults ) 1416 * 1417 * https://tc39.es/proposal-joint-iteration/#sec-IteratorZip 1418 */ 1419 function* IteratorZipGenerator(iters, nextMethods, mode, padding, keys) { 1420 assert( 1421 iters.length === nextMethods.length, 1422 "iters and nextMethods have the same number of entries" 1423 ); 1424 assert( 1425 mode === "shortest" || mode === "longest" || mode === "strict", 1426 "invalid mode" 1427 ); 1428 assert( 1429 mode !== "longest" || (IsArray(padding) && padding.length === iters.length), 1430 "iters and padding have the same number of entries" 1431 ); 1432 assert( 1433 keys === undefined || (IsArray(keys) && keys.length === iters.length), 1434 "keys is undefined or an array with iters.length entries" 1435 ); 1436 1437 // Step 1. 1438 var iterCount = iters.length; 1439 1440 // Step 2. 1441 // 1442 // Our implementation reuses |iters| instead of using another list. This 1443 // counter is the number of non-null entries in |iters|. 1444 var openIterCount = iterCount; 1445 1446 // Step 3.a. 1447 if (iterCount === 0) { 1448 return; 1449 } 1450 1451 // Step 3.b. 1452 while (true) { 1453 // Step 3.b.i. 1454 var results = []; 1455 1456 // Step 3.b.ii. 1457 assert(openIterCount > 0, "at least one open iterator"); 1458 1459 // Step 3.b.iii. 1460 for (var i = 0; i < iterCount; i++) { 1461 // Step 3.b.iii.1. 1462 var iter = iters[i]; 1463 var nextMethod = nextMethods[i]; 1464 1465 // Steps 3.b.iii.2-3. 1466 var result; 1467 if (iter === null) { 1468 // Step 3.b.iii.2.a. 1469 assert(mode === "longest", "padding only applied when mode is longest"); 1470 1471 // Step 3.b.iii.2.b. 1472 result = padding[i]; 1473 } else { 1474 // Steps 3.b.iii.3.a-c. 1475 try { 1476 // Step 3.b.iii.3.a. 1477 var iterResult = callContentFunction(nextMethod, iter); 1478 if (!IsObject(iterResult)) { 1479 ThrowTypeError(JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next"); 1480 } 1481 var done = !!iterResult.done; 1482 if (!done) { 1483 result = iterResult.value; 1484 } 1485 } catch (e) { 1486 // Step 3.b.iii.3.b.i. 1487 iters[i] = null; 1488 1489 // Step 3.b.iii.3.b.ii. 1490 IteratorCloseAllForException(iters); 1491 throw e; 1492 } 1493 1494 // Step 3.b.iii.3.d. 1495 if (done) { 1496 // Step 3.b.iii.3.d.i. 1497 // 1498 // Set to null to mark the iterator as closed. 1499 iters[i] = null; 1500 1501 // Step 3.b.iii.3.d.ii. 1502 if (mode === "shortest") { 1503 // Step 3.b.iii.3.d.ii.i. 1504 IteratorCloseAllForReturn(iters); 1505 return; 1506 } 1507 1508 // Step 3.b.iii.3.d.iii. 1509 if (mode === "strict") { 1510 // Step 3.b.iii.3.d.iii.i. 1511 if (i !== 0) { 1512 IteratorCloseAllForException(iters); 1513 ThrowTypeError(JSMSG_ITERATOR_ZIP_STRICT_OPEN_ITERATOR); 1514 } 1515 1516 // Step 3.b.iii.3.d.iii.ii. 1517 for (var k = 1; k < iterCount; k++) { 1518 // Step 3.b.iii.3.d.iii.ii.i. 1519 assert(iters[k] !== null, "unexpected closed iterator"); 1520 1521 // Steps 3.b.iii.3.d.iii.ii.ii-iv. 1522 var done; 1523 try { 1524 // Step 3.b.iii.3.d.iii.ii.ii. 1525 var iterResult = callContentFunction(nextMethods[k], iters[k]); 1526 if (!IsObject(iterResult)) { 1527 ThrowTypeError(JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next"); 1528 } 1529 done = !!iterResult.done; 1530 } catch (e) { 1531 // // Step 3.b.iii.3.d.iii.ii.iii.i. 1532 iters[k] = null; 1533 1534 // Step 3.b.iii.3.d.iii.ii.iii.ii. 1535 IteratorCloseAllForException(iters); 1536 throw e; 1537 } 1538 1539 // Steps 3.b.iii.3.d.iii.ii.v-vi. 1540 if (done) { 1541 // Steps 3.b.iii.3.d.iii.ii.v.i. 1542 iters[k] = null; 1543 } else { 1544 // Steps 3.b.iii.3.d.iii.ii.vi.i. 1545 IteratorCloseAllForException(iters); 1546 ThrowTypeError(JSMSG_ITERATOR_ZIP_STRICT_OPEN_ITERATOR); 1547 } 1548 } 1549 1550 // Step 3.b.iii.3.d.iii.iii. 1551 return; 1552 } 1553 1554 // Step 3.b.iii.3.d.iii.iv.i. 1555 assert(mode === "longest", "unexpected mode"); 1556 1557 // Step 3.b.iii.3.d.iii.iv.ii. 1558 assert(openIterCount > 0, "at least one open iterator"); 1559 if (--openIterCount === 0) { 1560 return; 1561 } 1562 1563 // Step 3.b.iii.3.d.iii.iv.iii. 1564 iters[i] = null; 1565 1566 // Step 3.b.iii.3.d.iii.iv.iv. 1567 result = padding[i]; 1568 } 1569 } 1570 1571 // Step 3.b.iii.4. 1572 DefineDataProperty(results, results.length, result); 1573 } 1574 1575 // Step 3.b.iv. 1576 if (keys) { 1577 // Iterator.zipKeyed, step 15.a. 1578 var obj = std_Object_create(null); 1579 1580 // Iterator.zipKeyed, step 15.b. 1581 for (var i = 0; i < keys.length; i++) { 1582 DefineDataProperty(obj, keys[i], results[i]); 1583 } 1584 1585 // Iterator.zipKeyed, step 15.c. 1586 results = obj; 1587 } 1588 1589 // Steps 3.b.v-vi. 1590 var returnCompletion = true; 1591 try { 1592 // Step 3.b.v. 1593 yield results; 1594 1595 returnCompletion = false; 1596 } finally { 1597 // Step 3.b.vi. 1598 // 1599 // IteratorHelper iterators can't continue execution with a Throw 1600 // completion, so this must be a Return completion. 1601 if (returnCompletion) { 1602 IteratorCloseAllForReturn(iters); 1603 } 1604 } 1605 } 1606 } 1607 1608 /** 1609 * IteratorCloseAll ( iters, completion ) 1610 * 1611 * When |completion| is a Return completion. 1612 * 1613 * https://tc39.es/proposal-joint-iteration/#sec-closeall 1614 */ 1615 function IteratorCloseAllForReturn(iters) { 1616 assert(IsArray(iters), "iters is an array"); 1617 1618 var exception; 1619 var hasException = false; 1620 1621 // Step 1. 1622 for (var i = iters.length - 1; i >= 0; i--) { 1623 var iter = iters[i]; 1624 assert(IsObject(iter) || iter === null, "iter is an object or null"); 1625 1626 if (IsObject(iter)) { 1627 try { 1628 IteratorClose(iter); 1629 } catch (e) { 1630 // Store the first exception and then ignore any later exceptions. 1631 if (!hasException) { 1632 hasException = true; 1633 exception = e; 1634 } 1635 } 1636 } 1637 } 1638 1639 // Step 2. 1640 if (hasException) { 1641 throw exception; 1642 } 1643 } 1644 1645 /** 1646 * IteratorCloseAll ( iters, completion ) 1647 * 1648 * When |completion| is a Throw completion. 1649 * 1650 * https://tc39.es/proposal-joint-iteration/#sec-closeall 1651 */ 1652 function IteratorCloseAllForException(iters) { 1653 assert(IsArray(iters), "iters is an array"); 1654 1655 // Step 1. 1656 for (var i = iters.length - 1; i >= 0; i--) { 1657 var iter = iters[i]; 1658 assert(IsObject(iter) || iter === null, "iter is an object or null"); 1659 1660 if (IsObject(iter)) { 1661 try { 1662 IteratorClose(iter); 1663 } catch { 1664 // Ignore any inner exceptions. 1665 } 1666 } 1667 } 1668 1669 // Step 2. (Performed in caller) 1670 } 1671 1672 #ifdef NIGHTLY_BUILD 1673 /** 1674 * CreateNumericRangeIterator (start, end, optionOrStep, type) 1675 * Step 18 1676 * 1677 * https://tc39.es/proposal-iterator.range/#sec-create-numeric-range-iterator 1678 */ 1679 function IteratorRangeNext() { 1680 var obj = this; 1681 // Step 18. Let closure be a new Abstract Closure with no parameters 1682 // that captures start, end, step, inclusiveEnd, zero, one and performs the following steps when called: 1683 1684 if (!IsObject(obj) || (obj = GuardToIteratorRange(obj)) === null) { 1685 return callFunction( 1686 CallIteratorRangeMethodIfWrapped, 1687 this, 1688 "IteratorRangeNext" 1689 ); 1690 } 1691 1692 // Retrieve values from reserved slots 1693 var start = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_START); 1694 var end = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_END); 1695 var step = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_STEP); 1696 var inclusiveEnd = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_INCLUSIVE_END); 1697 var zero = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_ZERO); 1698 var one = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_ONE); 1699 var currentCount = UnsafeGetReservedSlot(obj, ITERATOR_RANGE_SLOT_CURRENT_COUNT); 1700 1701 // Step 18.a: If end > start, let ifIncrease be true 1702 // Step 18.b: Else let ifIncrease be false 1703 var ifIncrease = end > start; 1704 1705 // Step 18.c: If step > zero, let ifStepIncrease be true 1706 // Step 18.d: Else let ifStepIncrease be false 1707 var ifStepIncrease = step > zero; 1708 1709 // Step 18.e: If ifIncrease is not ifStepIncrease, return undefined. 1710 if (ifIncrease !== ifStepIncrease) { 1711 return { value: undefined, done: true }; 1712 } 1713 1714 // Step 18.f: Let hitsEnd be false 1715 var hitsEnd = false; 1716 1717 // Step 18.g: Let currentCount be zero (already handled via slots) 1718 1719 // Step 18.i.i: Let currentYieldingValue be start + (step × currentCount) 1720 var currentYieldingValue = start + (step * currentCount); 1721 1722 // Step 18.i.ii: If currentYieldingValue is equal to end, set hitsEnd to true 1723 hitsEnd = currentYieldingValue === end && !inclusiveEnd; 1724 1725 1726 // Step 18.i.iii: Set currentCount to currentCount + one 1727 currentCount = currentCount + one; 1728 1729 // Step 18.i.iv: If ifIncrease is true, then 1730 if (ifIncrease) { 1731 // Step 18.i.iv.1: If inclusiveEnd is true, then 1732 if (inclusiveEnd) { 1733 // Step 18.i.iv.1.a: If currentYieldingValue > end, return undefined. 1734 if (currentYieldingValue > end) { 1735 return { value: undefined, done: true }; 1736 } 1737 } else { 1738 // Step 18.i.iv.2: If currentYieldingValue >= end, return undefined 1739 if (currentYieldingValue >= end) { 1740 return { value: undefined, done: true }; 1741 } 1742 } 1743 } else { 1744 // Step 18.i.v: Else 1745 // Step 18.i.v.1: If inclusiveEnd is true, then 1746 if (inclusiveEnd) { 1747 //Step 18.i.v.1.a.a. If end > currentYieldingValue, return undefined. 1748 if (end > currentYieldingValue) { 1749 return { value: undefined, done: true }; 1750 } 1751 } else { 1752 // Step 18.i.v.2: Else 1753 if (end >= currentYieldingValue) { 1754 // Step 18i.v.2.a: If end >= currentYieldingValue, return undefined 1755 return { value: undefined, done: true }; 1756 } 1757 } 1758 } 1759 1760 // Step 18.i.vi: Yield currentYieldingValue 1761 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_CURRENT_COUNT, currentCount); 1762 1763 // Step 18.j: Return undefined if the loop completes 1764 if (hitsEnd) { 1765 return { value: undefined, done: true }; 1766 } 1767 1768 // Return the current value 1769 return { value: currentYieldingValue, done: false }; 1770 } 1771 1772 1773 1774 /** 1775 * CreateNumericRangeIterator (start, end, optionOrStep, type) 1776 * 1777 * https://tc39.es/proposal-iterator.range/#sec-create-numeric-range-iterator 1778 */ 1779 function CreateNumericRangeIterator(start, end, optionOrStep, isNumberRange) { 1780 1781 // Step 1: If start is NaN, throw a RangeError exception. 1782 if (isNumberRange && Number_isNaN(start)) { 1783 ThrowRangeError(JSMSG_ITERATOR_RANGE_INVALID_START_RANGEERR); 1784 } 1785 1786 // Step 2: If end is NaN, throw a RangeError exception. 1787 if (isNumberRange && Number_isNaN(end)) { 1788 ThrowRangeError(JSMSG_ITERATOR_RANGE_INVALID_END_RANGEERR); 1789 } 1790 1791 // Step 3: If type is NUMBER-RANGE, then 1792 if (isNumberRange) { 1793 // Step 3.a. Assert: start is a Number. 1794 assert(typeof start === 'number', "The 'start' argument must be a number"); 1795 1796 // Step 3.b. If end is not a Number, throw a TypeError exception. 1797 if (typeof end !== 'number') { 1798 ThrowTypeError(JSMSG_ITERATOR_RANGE_INVALID_END); 1799 } 1800 1801 // Step 3.c. Let zero be 0ℤ. 1802 var zero = 0; 1803 1804 // Step 3.d. Let one be 1ℤ. 1805 var one = 1; 1806 // 4: Else, 1807 } else { 1808 // 4.a. Assert: start is a BigInt. 1809 assert(typeof start === 'bigint', "The 'start' argument must be a bigint"); 1810 1811 // 4.b. If end is not +∞𝔽 or -∞𝔽 and end is not a BigInt, throw a TypeError exception. 1812 if (typeof end !== 'bigint' && !(Number_isFinite(end))) { 1813 ThrowTypeError(JSMSG_ITERATOR_RANGE_INVALID_END); 1814 } 1815 1816 // 4.c. Let zero be 0𝔽. 1817 var zero = 0n; 1818 1819 // 4.d. Let one be 1𝔽. 1820 var one = 1n; 1821 } 1822 // Step 5: If start is +∞ or -∞, throw a RangeError exception. 1823 if (typeof start === 'number' && !Number_isFinite(start)) { 1824 ThrowRangeError(JSMSG_ITERATOR_RANGE_START_INFINITY); 1825 } 1826 // Step 6: Let inclusiveEnd be false. 1827 var inclusiveEnd = false; 1828 1829 // Step 7: If optionOrStep is undefined or null, then 1830 // Step 7.a. Let step be undefined. 1831 var step; 1832 1833 // Step 8: Else if optionOrStep is an Object, then 1834 if (optionOrStep !== null && typeof optionOrStep === 'object') { 1835 // Step 8.a. Let step be ? Get(optionOrStep, "step"). 1836 step = optionOrStep.step; 1837 1838 // Step 8.b. Set inclusiveEnd to ToBoolean(? Get(optionOrStep, "inclusive")). 1839 inclusiveEnd = TO_BOOLEAN(optionOrStep.inclusiveEnd); 1840 } 1841 // Step 9: Else if type is NUMBER-RANGE and optionOrStep is a Number, then 1842 else if (isNumberRange && typeof optionOrStep === 'number') { 1843 // Step 9.a. Let step be optionOrStep. 1844 step = optionOrStep; 1845 } 1846 1847 // Step 10: Else if type is BIGINT-RANGE and optionOrStep is a BigInt, then 1848 // Step 10.a. Let step be optionOrStep. 1849 else if (!isNumberRange && typeof optionOrStep === 'bigint') { 1850 step = optionOrStep; 1851 } 1852 // Step 11: Else, throw a TypeError exception. 1853 else if (optionOrStep !== undefined && optionOrStep !== null) { 1854 ThrowTypeError(JSMSG_ITERATOR_RANGE_INVALID_STEP); 1855 } 1856 1857 // Step 12: If step is undefined or null, then 1858 if (step === undefined || step === null) { 1859 // Step 12.a. If end > start, let step be one. 1860 // Step 12.b. Else let step be -one. 1861 step = end > start ? one : -one; 1862 } 1863 1864 // Step 13: If step is NaN, throw a RangeError exception. 1865 if (typeof step === "number" && Number_isNaN(step)) { 1866 ThrowRangeError(JSMSG_ITERATOR_RANGE_STEP_NAN); 1867 } 1868 1869 // Step 14: If type is NUMBER-RANGE and step is not a Number, throw a TypeError exception. 1870 if (isNumberRange && typeof step !== 'number') { 1871 ThrowTypeError(JSMSG_ITERATOR_RANGE_STEP_NOT_NUMBER); 1872 } 1873 1874 // Step 15: Else if type is BIGINT-RANGE and step is not a BigInt, throw a TypeError exception 1875 else if (!isNumberRange && typeof step !== 'bigint') { 1876 ThrowTypeError(JSMSG_ITERATOR_RANGE_STEP_NOT_BIGINT); 1877 } 1878 1879 // Step 16: If step is +∞ or -∞, throw a RangeError exception. 1880 if (typeof step === 'number' && !Number_isFinite(step)) { 1881 ThrowRangeError(JSMSG_ITERATOR_RANGE_STEP_NOT_FINITE); 1882 } 1883 1884 // Step 17: If step is zero and start is not end, throw a RangeError exception. 1885 if (step === zero && start !== end) { 1886 ThrowRangeError(JSMSG_ITERATOR_RANGE_STEP_ZERO); 1887 } 1888 // Step 19: Return CreateIteratorFromClosure(closure, "%NumericRangeIteratorPrototype%", %NumericRangeIteratorPrototype%). 1889 1890 var obj = NewIteratorRange(); 1891 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_START, start); 1892 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_END, end); 1893 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_STEP, step); 1894 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_INCLUSIVE_END, inclusiveEnd); 1895 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_ZERO, zero); 1896 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_ONE, one); 1897 UnsafeSetReservedSlot(obj, ITERATOR_RANGE_SLOT_CURRENT_COUNT, zero); 1898 1899 return obj; 1900 } 1901 1902 1903 1904 /** 1905 * Iterator.range ( start, end, optionOrStep ) 1906 * 1907 * https://tc39.es/proposal-iterator.range/#sec-iterator.range 1908 */ 1909 function IteratorRange(start, end, optionOrStep) { 1910 1911 // Step 1. If start is a Number, return ? CreateNumericRangeIterator(start, end, optionOrStep, NUMBER-RANGE) 1912 if (typeof start === 'number') { 1913 return CreateNumericRangeIterator(start, end, optionOrStep, true); 1914 } 1915 1916 // Step 2. If start is a BigInt, return ? CreateNumericRangeIterator(start, end, optionOrStep, BIGINT-RANGE) 1917 if (typeof start === 'bigint') { 1918 return CreateNumericRangeIterator(start, end, optionOrStep, false); 1919 } 1920 1921 // Step 3. Throw a TypeError exception. 1922 ThrowTypeError(JSMSG_ITERATOR_RANGE_INVALID_START); 1923 1924 } 1925 1926 /** 1927 * Iterator.prototype.chunks ( chunkSize ) 1928 * 1929 * https://tc39.es/proposal-iterator-chunking/#sec-iterator.prototype.chunks 1930 */ 1931 function IteratorChunks(chunkSize) { 1932 // Step 1. Let O be the this value. 1933 var iterator = this; 1934 1935 // Step 2. If O is not an Object, throw a TypeError exception. 1936 if (!IsObject(iterator)) { 1937 ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); 1938 } 1939 1940 // Step 3. Let iterated be the Iterator Record 1941 // { [[Iterator]]: O, [[NextMethod]]: undefined, [[Done]]: false }. 1942 1943 // Step 4. If chunkSize is not an integral Number in the inclusive interval 1944 // from 1𝔽 to 𝔽(2**32 - 1), then 1945 if (!Number_isInteger(chunkSize) || (chunkSize < 1 || chunkSize > (2 ** 32) - 1)) { 1946 // Step 4.a. Let error be ThrowCompletion(a newly created RangeError object). 1947 // Step 4.b. Return ? IteratorClose(iterated, error). 1948 try { 1949 IteratorClose(iterator); 1950 } catch {} 1951 ThrowRangeError(JSMSG_INVALID_CHUNKSIZE); 1952 } 1953 1954 // Step 5. Set iterated to ? GetIteratorDirect(O). 1955 var nextMethod = iterator.next; 1956 1957 // Step 6. Let closure be a new Abstract Closure with ... 1958 // (Handled in IteratorChunksGenerator.) 1959 1960 // Step 7. Let result be CreateIteratorFromClosure( 1961 // closure, "Iterator Helper", %IteratorHelperPrototype%, 1962 // « [[UnderlyingIterators]] » 1963 // ). 1964 var result = NewIteratorHelper(); 1965 var generator = IteratorChunksGenerator(iterator, nextMethod, chunkSize); 1966 1967 // Step 8. Set result.[[UnderlyingIterators]] to « iterated ». 1968 UnsafeSetReservedSlot( 1969 result, 1970 ITERATOR_HELPER_GENERATOR_SLOT, 1971 generator 1972 ); 1973 UnsafeSetReservedSlot( 1974 result, 1975 ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, 1976 iterator 1977 ); 1978 1979 // Step 9. Return result. 1980 return result; 1981 } 1982 1983 /** 1984 * Iterator.prototype.chunks ( chunkSize ) 1985 * 1986 * Abstract closure definition. 1987 * 1988 * https://tc39.es/proposal-iterator-chunking/#sec-iterator.prototype.chunks 1989 */ 1990 /* eslint-disable-next-line require-yield */ 1991 function* IteratorChunksGenerator(iterator, nextMethod, chunkSize) { 1992 IteratorClose(iterator); 1993 } 1994 1995 /** 1996 * Iterator.prototype.windows ( windowSize, undersized ) 1997 * 1998 * https://tc39.es/proposal-iterator-chunking/#sec-iterator.prototype.windows 1999 */ 2000 function IteratorWindows(windowSize, undersized) { 2001 return false; 2002 } 2003 2004 /** 2005 * Iterator.prototype.join ( separator ) 2006 * 2007 * https://tc39.es/proposal-iterator-join/#sec-iterator.prototype.join 2008 */ 2009 function IteratorJoin(separator) { 2010 return false; 2011 } 2012 #endif