tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

iterables-iteration.js (4483B)


      1 // Copyright (C) 2025 André Bargull. All rights reserved.
      2 // This code is governed by the BSD license found in the LICENSE file.
      3 
      4 /*---
      5 esid: sec-iterator.zip
      6 description: >
      7  Perform iteration of the "iterables" argument.
      8 info: |
      9  Iterator.zip ( iterables [ , options ] )
     10    ...
     11    10. Let inputIter be ? GetIterator(iterables, sync).
     12    11. Let next be not-started.
     13    12. Repeat, while next is not done,
     14      a. Set next to Completion(IteratorStepValue(inputIter)).
     15      b. IfAbruptCloseIterators(next, iters).
     16      c. If next is not done, then
     17        i. Let iter be Completion(GetIteratorFlattenable(next, reject-strings)).
     18        ii. IfAbruptCloseIterators(iter, the list-concatenation of « inputIter » and iters).
     19        iii. Append iter to iters.
     20    ...
     21 
     22  GetIterator ( obj, kind )
     23    ...
     24    2. Else,
     25      a. Let method be ? GetMethod(obj, %Symbol.iterator%).
     26    3. If method is undefined, throw a TypeError exception.
     27    4. Return ? GetIteratorFromMethod(obj, method).
     28 
     29  GetIteratorFromMethod ( obj, method )
     30    1. Let iterator be ? Call(method, obj).
     31    2. If iterator is not an Object, throw a TypeError exception.
     32    3. Return ? GetIteratorDirect(iterator).
     33 
     34  GetIteratorDirect ( obj )
     35    1. Let nextMethod be ? Get(obj, "next").
     36    2. Let iteratorRecord be the Iterator Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
     37    3. Return iteratorRecord.
     38 
     39  GetIteratorFlattenable ( obj, primitiveHandling )
     40    1. If obj is not an Object, then
     41      a. If primitiveHandling is reject-primitives, throw a TypeError exception.
     42      b. Assert: primitiveHandling is iterate-string-primitives.
     43      c. If obj is not a String, throw a TypeError exception.
     44    2. Let method be ? GetMethod(obj, %Symbol.iterator%).
     45    3. If method is undefined, then
     46      a. Let iterator be obj.
     47    4. Else,
     48      a. Let iterator be ? Call(method, obj).
     49    5. If iterator is not an Object, throw a TypeError exception.
     50    6. Return ? GetIteratorDirect(iterator).
     51 includes: [proxyTrapsHelper.js, compareArray.js]
     52 features: [joint-iteration]
     53 ---*/
     54 
     55 // Object implementing Iterator protocol, but throws when calling any Iterator methods.
     56 var throwingIterator = {
     57  next() {
     58    throw new Test262Error();
     59  },
     60  return() {
     61    throw new Test262Error();
     62  }
     63 };
     64 
     65 var iterableReturningThrowingIterator = {
     66  [Symbol.iterator]() {
     67    return throwingIterator;
     68  }
     69 };
     70 
     71 // "iterables" argument must be an iterable.
     72 assert.throws(TypeError, function() {
     73  Iterator.zip(Object.create(null));
     74 });
     75 
     76 // GetIteratorFlattenable accepts both iterables and iterators.
     77 Iterator.zip([
     78  throwingIterator,
     79  iterableReturningThrowingIterator,
     80 ]);
     81 
     82 // GetIteratorFlattenable rejects non-objects.
     83 var badIterators = [
     84  undefined,
     85  null,
     86  true,
     87  "",
     88  Symbol(),
     89  0,
     90  0n,
     91 ];
     92 
     93 for (var iterator of badIterators) {
     94  assert.throws(TypeError, function() {
     95    Iterator.zip([iterator]);
     96  });
     97 }
     98 
     99 // GetIterator and GetIteratorFlattenable read properties in the correct order.
    100 var log = [];
    101 
    102 function makeProxyWithGetHandler(name, obj) {
    103  return new Proxy(obj, allowProxyTraps({
    104    get(target, propertyKey, receiver) {
    105      log.push(`${name}::${String(propertyKey)}`);
    106      return Reflect.get(target, propertyKey, receiver);
    107    }
    108  }));
    109 }
    110 
    111 var elements = [
    112  // An iterator.
    113  makeProxyWithGetHandler("first", throwingIterator),
    114 
    115  // An iterable.
    116  makeProxyWithGetHandler("second", iterableReturningThrowingIterator),
    117 
    118  // An object without any iteration methods.
    119  makeProxyWithGetHandler("third", Object.create(null)),
    120 ];
    121 
    122 var elementsIter = elements.values();
    123 
    124 var iterables = makeProxyWithGetHandler("iterables", {
    125  [Symbol.iterator]() {
    126    // Called with the correct receiver and no arguments.
    127    assert.sameValue(this, iterables);
    128    assert.sameValue(arguments.length, 0);
    129 
    130    return this;
    131  },
    132  next() {
    133    log.push("call next");
    134 
    135    // Called with the correct receiver and no arguments.
    136    assert.sameValue(this, iterables);
    137    assert.sameValue(arguments.length, 0);
    138 
    139    return elementsIter.next();
    140  },
    141  return() {
    142    throw new Test262Error("unexpected call to return method");
    143  }
    144 });
    145 
    146 Iterator.zip(iterables);
    147 
    148 assert.compareArray(log, [
    149  "iterables::Symbol(Symbol.iterator)",
    150  "iterables::next",
    151 
    152  "call next",
    153  "first::Symbol(Symbol.iterator)",
    154  "first::next",
    155 
    156  "call next",
    157  "second::Symbol(Symbol.iterator)",
    158 
    159  "call next",
    160  "third::Symbol(Symbol.iterator)",
    161  "third::next",
    162 
    163  "call next",
    164 ]);
    165 
    166 reportCompare(0, 0);