tor-browser

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

destructuring-iterator.js (3542B)


      1 load(libdir + 'asserts.js');
      2 load(libdir + 'iteration.js');
      3 load(libdir + 'eqArrayHelper.js');
      4 
      5 // throw on non-iterables
      6 assertThrowsInstanceOf(() => { [a, b, c] = {0: 0, 1: 1, 2: 2} }, TypeError);
      7 
      8 var nextcalls = 0, donecalls = 0, valuecalls = 0;
      9 var doneafter = 0;
     10 var iterable = {};
     11 iterable[Symbol.iterator] = function () {
     12  return {
     13    next: function () {
     14      assertEq(arguments.length, 0, 'iterator.next() should be called with no arguments');
     15      nextcalls++;
     16      return {
     17        get done() {
     18          donecalls++;
     19          return --doneafter < 0;
     20        },
     21        get value() {
     22          valuecalls++;
     23          return valuecalls;
     24        }
     25      };
     26    }
     27  }
     28 };
     29 
     30 function assertIterable(expectCalls, fn, expectResult) {
     31  [nextcalls, donecalls, valuecalls, doneafter] = [0,0,0, expectCalls[3]];
     32  assertEqArray(fn(iterable), expectResult);
     33  assertEq(nextcalls,  expectCalls[0], 'calls to iterator.next()');
     34  assertEq(donecalls,  expectCalls[1], 'getting iterator.next().done');
     35  assertEq(valuecalls, expectCalls[2], 'getting iterator.next().value');
     36 }
     37 
     38 assertIterable([1,1,1,1],
     39  it => { var [a] = it; return [a]; },
     40  [1]);
     41 assertIterable([2,2,1,1],
     42  it => { var [a,b,c] = it; return [a,b,c]; },
     43  [1,undefined,undefined]);
     44 assertIterable([2,2,1,1],
     45  it => { var [a,b,...rest] = it; return [a,b,...rest]; },
     46  [1,undefined]);
     47 assertIterable([5,5,4,4],
     48  it => { var [,,...rest] = it; return rest; },
     49  [3,4]);
     50 
     51 // the iterator should be exhausted before any error is thrown
     52 assertIterable([5,5,4,4],
     53  it => {
     54    assertThrowsInstanceOf(function () {
     55      "use strict";
     56      [...{0: "".x}] = it;
     57    }, TypeError);
     58    return [];
     59  },
     60  []);
     61 
     62 var arraycalls = 0;
     63 var ArrayIterator = Array.prototype[Symbol.iterator];
     64 Array.prototype[Symbol.iterator] = function () {
     65  arraycalls++;
     66  return ArrayIterator.apply(this, arguments);
     67 };
     68 // [...rest] should not call Array#@@iterator for the LHS
     69 var [...rest] = iterable;
     70 assertEq(arraycalls, 0, 'calls to Array#@@iterator');
     71 // [...[...rest]] should do so, since it creates an implicit array for the
     72 // first rest pattern, then destructures that again using @@iterator() for the
     73 // second rest pattern.
     74 var [...[...rest]] = iterable;
     75 assertEq(arraycalls, 1, 'calls to Array#@@iterator');
     76 
     77 // loop `fn` a few times, to get it JIT-compiled
     78 function loop(fn) {
     79  var i = 1e4;
     80  while (i--) fn();
     81 }
     82 
     83 loop(() => { doneafter = 4; var [a] = iterable; return a; });
     84 loop(() => { doneafter = 4; var [a,b,...[...rest]] = iterable; return rest; });
     85 
     86 
     87 // destructuring assignment should always use iterators and not optimize
     88 // to a "group assignment"
     89 delete Array.prototype[Symbol.iterator];
     90 assertThrowsInstanceOf(() => { var [a,b] = [1,2]; }, TypeError);
     91 Array.prototype[Symbol.iterator] = ArrayIterator;
     92 
     93 // observe the binding order
     94 a = undefined, b = undefined, c = undefined;
     95 var obj = {};
     96 obj[Symbol.iterator] = function* () {
     97 // normal fields should be initialized right after |.next()|
     98 yield 1;
     99 assertEq(a, 1);
    100 yield 2;
    101 yield 3;
    102 assertEq(b, 3);
    103 yield 4;
    104 yield 5;
    105 // rest should be initialized after the iterator is exhausted
    106 assertEq(c, undefined);
    107 };
    108 [a, , b, ...c] = obj;
    109 assertEqArray(c, [4,5]);
    110 
    111 // a throw inside the destructuring of the "catch" value should not enter
    112 // the "catch" block
    113 
    114 assertThrowsValue(function () {
    115  try {
    116    Array.prototype[Symbol.iterator] = function () { throw 'from iterator'; };
    117    throw [1, 2];
    118  } catch ([x, y]) {
    119    throw 'not reached';
    120  }
    121 }, 'from iterator');
    122 Array.prototype[Symbol.iterator] = ArrayIterator;