Home | History | Annotate | Download | only in harmony
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // Flags: --harmony-generators --expose-gc
     29 
     30 // Test generator iteration.
     31 
     32 var GeneratorFunction = (function*(){yield 1;}).__proto__.constructor;
     33 
     34 function assertIteratorResult(value, done, result) {
     35   assertEquals({ value: value, done: done}, result);
     36 }
     37 
     38 function TestGeneratorResultPrototype() {
     39   function* g() { yield 1; }
     40   var iter = g();
     41   var result = iter.next();
     42 
     43   assertSame(Object.prototype, Object.getPrototypeOf(result));
     44   property_names = Object.getOwnPropertyNames(result);
     45   property_names.sort();
     46   assertEquals(["done", "value"], property_names);
     47   assertIteratorResult(1, false, result);
     48 }
     49 TestGeneratorResultPrototype()
     50 
     51 function TestGenerator(g, expected_values_for_next,
     52                        send_val, expected_values_for_send) {
     53   function testNext(thunk) {
     54     var iter = thunk();
     55     for (var i = 0; i < expected_values_for_next.length; i++) {
     56       assertIteratorResult(expected_values_for_next[i],
     57                            i == expected_values_for_next.length - 1,
     58                            iter.next());
     59     }
     60     assertThrows(function() { iter.next(); }, Error);
     61   }
     62   function testSend(thunk) {
     63     var iter = thunk();
     64     for (var i = 0; i < expected_values_for_send.length; i++) {
     65       assertIteratorResult(expected_values_for_send[i],
     66                            i == expected_values_for_send.length - 1,
     67                            iter.next(send_val));
     68     }
     69     assertThrows(function() { iter.next(send_val); }, Error);
     70   }
     71   function testThrow(thunk) {
     72     for (var i = 0; i < expected_values_for_next.length; i++) {
     73       var iter = thunk();
     74       for (var j = 0; j < i; j++) {
     75         assertIteratorResult(expected_values_for_next[j],
     76                              j == expected_values_for_next.length - 1,
     77                              iter.next());
     78       }
     79       function Sentinel() {}
     80       assertThrows(function () { iter.throw(new Sentinel); }, Sentinel);
     81       assertThrows(function () { iter.next(); }, Error);
     82     }
     83   }
     84 
     85   testNext(g);
     86   testSend(g);
     87   testThrow(g);
     88 
     89   testNext(function*() { return yield* g(); });
     90   testSend(function*() { return yield* g(); });
     91   testThrow(function*() { return yield* g(); });
     92 
     93   if (g instanceof GeneratorFunction) {
     94     testNext(function() { return new g(); });
     95     testSend(function() { return new g(); });
     96     testThrow(function() { return new g(); });
     97   }
     98 }
     99 
    100 TestGenerator(function* g1() { },
    101               [undefined],
    102               "foo",
    103               [undefined]);
    104 
    105 TestGenerator(function* g2() { yield 1; },
    106               [1, undefined],
    107               "foo",
    108               [1, undefined]);
    109 
    110 TestGenerator(function* g3() { yield 1; yield 2; },
    111               [1, 2, undefined],
    112               "foo",
    113               [1, 2, undefined]);
    114 
    115 TestGenerator(function* g4() { yield 1; yield 2; return 3; },
    116               [1, 2, 3],
    117               "foo",
    118               [1, 2, 3]);
    119 
    120 TestGenerator(function* g5() { return 1; },
    121               [1],
    122              "foo",
    123               [1]);
    124 
    125 TestGenerator(function* g6() { var x = yield 1; return x; },
    126               [1, undefined],
    127               "foo",
    128               [1, "foo"]);
    129 
    130 TestGenerator(function* g7() { var x = yield 1; yield 2; return x; },
    131               [1, 2, undefined],
    132               "foo",
    133               [1, 2, "foo"]);
    134 
    135 TestGenerator(function* g8() { for (var x = 0; x < 4; x++) { yield x; } },
    136               [0, 1, 2, 3, undefined],
    137               "foo",
    138               [0, 1, 2, 3, undefined]);
    139 
    140 // Generator with arguments.
    141 TestGenerator(
    142     function g9() {
    143       return (function*(a, b, c, d) {
    144         yield a; yield b; yield c; yield d;
    145       })("fee", "fi", "fo", "fum");
    146     },
    147     ["fee", "fi", "fo", "fum", undefined],
    148     "foo",
    149     ["fee", "fi", "fo", "fum", undefined]);
    150 
    151 // Too few arguments.
    152 TestGenerator(
    153     function g10() {
    154       return (function*(a, b, c, d) {
    155         yield a; yield b; yield c; yield d;
    156       })("fee", "fi");
    157     },
    158     ["fee", "fi", undefined, undefined, undefined],
    159     "foo",
    160     ["fee", "fi", undefined, undefined, undefined]);
    161 
    162 // Too many arguments.
    163 TestGenerator(
    164     function g11() {
    165       return (function*(a, b, c, d) {
    166         yield a; yield b; yield c; yield d;
    167       })("fee", "fi", "fo", "fum", "I smell the blood of an Englishman");
    168     },
    169     ["fee", "fi", "fo", "fum", undefined],
    170     "foo",
    171     ["fee", "fi", "fo", "fum", undefined]);
    172 
    173 // The arguments object.
    174 TestGenerator(
    175     function g12() {
    176       return (function*(a, b, c, d) {
    177         for (var i = 0; i < arguments.length; i++) {
    178           yield arguments[i];
    179         }
    180       })("fee", "fi", "fo", "fum", "I smell the blood of an Englishman");
    181     },
    182     ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
    183      undefined],
    184     "foo",
    185     ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
    186      undefined]);
    187 
    188 // Access to captured free variables.
    189 TestGenerator(
    190     function g13() {
    191       return (function(a, b, c, d) {
    192         return (function*() {
    193           yield a; yield b; yield c; yield d;
    194         })();
    195       })("fee", "fi", "fo", "fum");
    196     },
    197     ["fee", "fi", "fo", "fum", undefined],
    198     "foo",
    199     ["fee", "fi", "fo", "fum", undefined]);
    200 
    201 // Abusing the arguments object.
    202 TestGenerator(
    203     function g14() {
    204       return (function*(a, b, c, d) {
    205         arguments[0] = "Be he live";
    206         arguments[1] = "or be he dead";
    207         arguments[2] = "I'll grind his bones";
    208         arguments[3] = "to make my bread";
    209         yield a; yield b; yield c; yield d;
    210       })("fee", "fi", "fo", "fum");
    211     },
    212     ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
    213      undefined],
    214     "foo",
    215     ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
    216      undefined]);
    217 
    218 // Abusing the arguments object: strict mode.
    219 TestGenerator(
    220     function g15() {
    221       return (function*(a, b, c, d) {
    222         "use strict";
    223         arguments[0] = "Be he live";
    224         arguments[1] = "or be he dead";
    225         arguments[2] = "I'll grind his bones";
    226         arguments[3] = "to make my bread";
    227         yield a; yield b; yield c; yield d;
    228       })("fee", "fi", "fo", "fum");
    229     },
    230     ["fee", "fi", "fo", "fum", undefined],
    231     "foo",
    232     ["fee", "fi", "fo", "fum", undefined]);
    233 
    234 // GC.
    235 TestGenerator(function* g16() { yield "baz"; gc(); yield "qux"; },
    236               ["baz", "qux", undefined],
    237               "foo",
    238               ["baz", "qux", undefined]);
    239 
    240 // Receivers.
    241 TestGenerator(
    242     function g17() {
    243       function* g() { yield this.x; yield this.y; }
    244       var o = { start: g, x: 1, y: 2 };
    245       return o.start();
    246     },
    247     [1, 2, undefined],
    248     "foo",
    249     [1, 2, undefined]);
    250 
    251 TestGenerator(
    252     function g18() {
    253       function* g() { yield this.x; yield this.y; }
    254       var iter = new g;
    255       iter.x = 1;
    256       iter.y = 2;
    257       return iter;
    258     },
    259     [1, 2, undefined],
    260     "foo",
    261     [1, 2, undefined]);
    262 
    263 TestGenerator(
    264     function* g19() {
    265       var x = 1;
    266       yield x;
    267       with({x:2}) { yield x; }
    268       yield x;
    269     },
    270     [1, 2, 1, undefined],
    271     "foo",
    272     [1, 2, 1, undefined]);
    273 
    274 TestGenerator(
    275     function* g20() { yield (1 + (yield 2) + 3); },
    276     [2, NaN, undefined],
    277     "foo",
    278     [2, "1foo3", undefined]);
    279 
    280 TestGenerator(
    281     function* g21() { return (1 + (yield 2) + 3); },
    282     [2, NaN],
    283     "foo",
    284     [2, "1foo3"]);
    285 
    286 TestGenerator(
    287     function* g22() { yield (1 + (yield 2) + 3); yield (4 + (yield 5) + 6); },
    288     [2, NaN, 5, NaN, undefined],
    289     "foo",
    290     [2, "1foo3", 5, "4foo6", undefined]);
    291 
    292 TestGenerator(
    293     function* g23() {
    294       return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
    295     },
    296     [2, NaN, 5, NaN, NaN],
    297     "foo",
    298     [2, "1foo3", 5, "4foo6", "foofoo"]);
    299 
    300 // Rewind a try context with and without operands on the stack.
    301 TestGenerator(
    302     function* g24() {
    303       try {
    304         return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
    305       } catch (e) {
    306         throw e;
    307       }
    308     },
    309     [2, NaN, 5, NaN, NaN],
    310     "foo",
    311     [2, "1foo3", 5, "4foo6", "foofoo"]);
    312 
    313 // Yielding in a catch context, with and without operands on the stack.
    314 TestGenerator(
    315     function* g25() {
    316       try {
    317         throw (yield (1 + (yield 2) + 3))
    318       } catch (e) {
    319         if (typeof e == 'object') throw e;
    320         return e + (yield (4 + (yield 5) + 6));
    321       }
    322     },
    323     [2, NaN, 5, NaN, NaN],
    324     "foo",
    325     [2, "1foo3", 5, "4foo6", "foofoo"]);
    326 
    327 // Generator function instances.
    328 TestGenerator(GeneratorFunction(),
    329               [undefined],
    330               "foo",
    331               [undefined]);
    332 
    333 TestGenerator(new GeneratorFunction(),
    334               [undefined],
    335               "foo",
    336               [undefined]);
    337 
    338 TestGenerator(GeneratorFunction('yield 1;'),
    339               [1, undefined],
    340               "foo",
    341               [1, undefined]);
    342 
    343 TestGenerator(
    344     function() { return GeneratorFunction('x', 'y', 'yield x + y;')(1, 2) },
    345     [3, undefined],
    346     "foo",
    347     [3, undefined]);
    348 
    349 // Access to this with formal arguments.
    350 TestGenerator(
    351     function () {
    352       return ({ x: 42, g: function* (a) { yield this.x } }).g(0);
    353     },
    354     [42, undefined],
    355     "foo",
    356     [42, undefined]);
    357 
    358 // Test that yield* re-yields received results without re-boxing.
    359 function TestDelegatingYield() {
    360   function results(results) {
    361     var i = 0;
    362     function next() {
    363       return results[i++];
    364     }
    365     return { next: next }
    366   }
    367   function* yield_results(expected) {
    368     return yield* results(expected);
    369   }
    370   function collect_results(iter) {
    371     var ret = [];
    372     var result;
    373     do {
    374       result = iter.next();
    375       ret.push(result);
    376     } while (!result.done);
    377     return ret;
    378   }
    379   // We have to put a full result for the end, because the return will re-box.
    380   var expected = [{value: 1}, 13, "foo", {value: 34, done: true}];
    381 
    382   // Sanity check.
    383   assertEquals(expected, collect_results(results(expected)));
    384   assertEquals(expected, collect_results(yield_results(expected)));
    385 }
    386 TestDelegatingYield();
    387 
    388 function TestTryCatch(instantiate) {
    389   function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; }
    390   function Sentinel() {}
    391 
    392   function Test1(iter) {
    393     assertIteratorResult(1, false, iter.next());
    394     assertIteratorResult(2, false, iter.next());
    395     assertIteratorResult(3, false, iter.next());
    396     assertIteratorResult(undefined, true, iter.next());
    397     assertThrows(function() { iter.next(); }, Error);
    398   }
    399   Test1(instantiate(g));
    400 
    401   function Test2(iter) {
    402     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    403     assertThrows(function() { iter.next(); }, Error);
    404   }
    405   Test2(instantiate(g));
    406 
    407   function Test3(iter) {
    408     assertIteratorResult(1, false, iter.next());
    409     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    410     assertThrows(function() { iter.next(); }, Error);
    411   }
    412   Test3(instantiate(g));
    413 
    414   function Test4(iter) {
    415     assertIteratorResult(1, false, iter.next());
    416     assertIteratorResult(2, false, iter.next());
    417     var exn = new Sentinel;
    418     assertIteratorResult(exn, false, iter.throw(exn));
    419     assertIteratorResult(3, false, iter.next());
    420     assertIteratorResult(undefined, true, iter.next());
    421     assertThrows(function() { iter.next(); }, Error);
    422   }
    423   Test4(instantiate(g));
    424 
    425   function Test5(iter) {
    426     assertIteratorResult(1, false, iter.next());
    427     assertIteratorResult(2, false, iter.next());
    428     var exn = new Sentinel;
    429     assertIteratorResult(exn, false, iter.throw(exn));
    430     assertIteratorResult(3, false, iter.next());
    431     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    432     assertThrows(function() { iter.next(); }, Error);
    433 
    434   }
    435   Test5(instantiate(g));
    436 
    437   function Test6(iter) {
    438     assertIteratorResult(1, false, iter.next());
    439     assertIteratorResult(2, false, iter.next());
    440     var exn = new Sentinel;
    441     assertIteratorResult(exn, false, iter.throw(exn));
    442     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    443     assertThrows(function() { iter.next(); }, Error);
    444   }
    445   Test6(instantiate(g));
    446 
    447   function Test7(iter) {
    448     assertIteratorResult(1, false, iter.next());
    449     assertIteratorResult(2, false, iter.next());
    450     assertIteratorResult(3, false, iter.next());
    451     assertIteratorResult(undefined, true, iter.next());
    452     assertThrows(function() { iter.next(); }, Error);
    453   }
    454   Test7(instantiate(g));
    455 }
    456 TestTryCatch(function (g) { return g(); });
    457 TestTryCatch(function* (g) { return yield* g(); });
    458 
    459 function TestTryFinally(instantiate) {
    460   function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; }
    461   function Sentinel() {}
    462   function Sentinel2() {}
    463 
    464   function Test1(iter) {
    465     assertIteratorResult(1, false, iter.next());
    466     assertIteratorResult(2, false, iter.next());
    467     assertIteratorResult(3, false, iter.next());
    468     assertIteratorResult(4, false, iter.next());
    469     assertIteratorResult(undefined, true, iter.next());
    470     assertThrows(function() { iter.next(); }, Error);
    471   }
    472   Test1(instantiate(g));
    473 
    474   function Test2(iter) {
    475     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    476     assertThrows(function() { iter.next(); }, Error);
    477   }
    478   Test2(instantiate(g));
    479 
    480   function Test3(iter) {
    481     assertIteratorResult(1, false, iter.next());
    482     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    483     assertThrows(function() { iter.next(); }, Error);
    484   }
    485   Test3(instantiate(g));
    486 
    487   function Test4(iter) {
    488     assertIteratorResult(1, false, iter.next());
    489     assertIteratorResult(2, false, iter.next());
    490     assertIteratorResult(3, false, iter.throw(new Sentinel));
    491     assertThrows(function() { iter.next(); }, Sentinel);
    492     assertThrows(function() { iter.next(); }, Error);
    493 
    494   }
    495   Test4(instantiate(g));
    496 
    497   function Test5(iter) {
    498     assertIteratorResult(1, false, iter.next());
    499     assertIteratorResult(2, false, iter.next());
    500     assertIteratorResult(3, false, iter.throw(new Sentinel));
    501     assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
    502     assertThrows(function() { iter.next(); }, Error);
    503   }
    504   Test5(instantiate(g));
    505 
    506   function Test6(iter) {
    507     assertIteratorResult(1, false, iter.next());
    508     assertIteratorResult(2, false, iter.next());
    509     assertIteratorResult(3, false, iter.next());
    510     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    511     assertThrows(function() { iter.next(); }, Error);
    512   }
    513   Test6(instantiate(g));
    514 
    515   function Test7(iter) {
    516     assertIteratorResult(1, false, iter.next());
    517     assertIteratorResult(2, false, iter.next());
    518     assertIteratorResult(3, false, iter.next());
    519     assertIteratorResult(4, false, iter.next());
    520     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    521     assertThrows(function() { iter.next(); }, Error);
    522   }
    523   Test7(instantiate(g));
    524 
    525   function Test8(iter) {
    526     assertIteratorResult(1, false, iter.next());
    527     assertIteratorResult(2, false, iter.next());
    528     assertIteratorResult(3, false, iter.next());
    529     assertIteratorResult(4, false, iter.next());
    530     assertIteratorResult(undefined, true, iter.next());
    531     assertThrows(function() { iter.next(); }, Error);
    532 
    533   }
    534   Test8(instantiate(g));
    535 }
    536 TestTryFinally(function (g) { return g(); });
    537 TestTryFinally(function* (g) { return yield* g(); });
    538 
    539 function TestNestedTry(instantiate) {
    540   function* g() {
    541     try {
    542       yield 1;
    543       try { yield 2; } catch (e) { yield e; }
    544       yield 3;
    545     } finally {
    546       yield 4;
    547     }
    548     yield 5;
    549   }
    550   function Sentinel() {}
    551   function Sentinel2() {}
    552 
    553   function Test1(iter) {
    554     assertIteratorResult(1, false, iter.next());
    555     assertIteratorResult(2, false, iter.next());
    556     assertIteratorResult(3, false, iter.next());
    557     assertIteratorResult(4, false, iter.next());
    558     assertIteratorResult(5, false, iter.next());
    559     assertIteratorResult(undefined, true, iter.next());
    560     assertThrows(function() { iter.next(); }, Error);
    561   }
    562   Test1(instantiate(g));
    563 
    564   function Test2(iter) {
    565     assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
    566     assertThrows(function() { iter.next(); }, Error);
    567   }
    568   Test2(instantiate(g));
    569 
    570   function Test3(iter) {
    571     assertIteratorResult(1, false, iter.next());
    572     assertIteratorResult(4, false, iter.throw(new Sentinel));
    573     assertThrows(function() { iter.next(); }, Sentinel);
    574     assertThrows(function() { iter.next(); }, Error);
    575   }
    576   Test3(instantiate(g));
    577 
    578   function Test4(iter) {
    579     assertIteratorResult(1, false, iter.next());
    580     assertIteratorResult(4, false, iter.throw(new Sentinel));
    581     assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
    582     assertThrows(function() { iter.next(); }, Error);
    583   }
    584   Test4(instantiate(g));
    585 
    586   function Test5(iter) {
    587     assertIteratorResult(1, false, iter.next());
    588     assertIteratorResult(2, false, iter.next());
    589     var exn = new Sentinel;
    590     assertIteratorResult(exn, false, iter.throw(exn));
    591     assertIteratorResult(3, false, iter.next());
    592     assertIteratorResult(4, false, iter.next());
    593     assertIteratorResult(5, false, iter.next());
    594     assertIteratorResult(undefined, true, iter.next());
    595     assertThrows(function() { iter.next(); }, Error);
    596 
    597   }
    598   Test5(instantiate(g));
    599 
    600   function Test6(iter) {
    601     assertIteratorResult(1, false, iter.next());
    602     assertIteratorResult(2, false, iter.next());
    603     var exn = new Sentinel;
    604     assertIteratorResult(exn, false, iter.throw(exn));
    605     assertIteratorResult(4, false, iter.throw(new Sentinel2));
    606     assertThrows(function() { iter.next(); }, Sentinel2);
    607     assertThrows(function() { iter.next(); }, Error);
    608   }
    609   Test6(instantiate(g));
    610 
    611   function Test7(iter) {
    612     assertIteratorResult(1, false, iter.next());
    613     assertIteratorResult(2, false, iter.next());
    614     var exn = new Sentinel;
    615     assertIteratorResult(exn, false, iter.throw(exn));
    616     assertIteratorResult(3, false, iter.next());
    617     assertIteratorResult(4, false, iter.throw(new Sentinel2));
    618     assertThrows(function() { iter.next(); }, Sentinel2);
    619     assertThrows(function() { iter.next(); }, Error);
    620 
    621   }
    622   Test7(instantiate(g));
    623 
    624   // That's probably enough.
    625 }
    626 TestNestedTry(function (g) { return g(); });
    627 TestNestedTry(function* (g) { return yield* g(); });
    628 
    629 function TestRecursion() {
    630   function TestNextRecursion() {
    631     function* g() { yield iter.next(); }
    632     var iter = g();
    633     return iter.next();
    634   }
    635   function TestSendRecursion() {
    636     function* g() { yield iter.next(42); }
    637     var iter = g();
    638     return iter.next();
    639   }
    640   function TestThrowRecursion() {
    641     function* g() { yield iter.throw(1); }
    642     var iter = g();
    643     return iter.next();
    644   }
    645   assertThrows(TestNextRecursion, Error);
    646   assertThrows(TestSendRecursion, Error);
    647   assertThrows(TestThrowRecursion, Error);
    648 }
    649 TestRecursion();
    650