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: --expose-gc
29
30// Test generator iteration.
31
32var GeneratorFunction = (function*(){yield 1;}).__proto__.constructor;
33
34function assertIteratorResult(value, done, result) {
35  assertEquals({ value: value, done: done}, result);
36}
37
38function assertIteratorIsClosed(iter) {
39  assertIteratorResult(undefined, true, iter.next());
40  assertDoesNotThrow(function() { iter.next(); });
41}
42
43function assertThrownIteratorIsClosed(iter) {
44  // TODO(yusukesuzuki): Since status of a thrown generator is "executing",
45  // following tests are failed.
46  // https://code.google.com/p/v8/issues/detail?id=3096
47  // assertIteratorIsClosed(iter);
48}
49
50function TestGeneratorResultPrototype() {
51  function* g() { yield 1; }
52  var iter = g();
53  var result = iter.next();
54
55  assertSame(Object.prototype, Object.getPrototypeOf(result));
56  property_names = Object.getOwnPropertyNames(result);
57  property_names.sort();
58  assertEquals(["done", "value"], property_names);
59  assertIteratorResult(1, false, result);
60}
61TestGeneratorResultPrototype()
62
63function TestGenerator(g, expected_values_for_next,
64                       send_val, expected_values_for_send) {
65  function testNext(thunk) {
66    var iter = thunk();
67    for (var i = 0; i < expected_values_for_next.length; i++) {
68      var v1 = expected_values_for_next[i];
69      var v2 = i == expected_values_for_next.length - 1;
70      // var v3 = iter.next();
71      assertIteratorResult(v1, v2, iter.next());
72    }
73    assertIteratorIsClosed(iter);
74  }
75  function testSend(thunk) {
76    var iter = thunk();
77    for (var i = 0; i < expected_values_for_send.length; i++) {
78      assertIteratorResult(expected_values_for_send[i],
79                           i == expected_values_for_send.length - 1,
80                           iter.next(send_val));
81    }
82    assertIteratorIsClosed(iter);
83  }
84  function testThrow(thunk) {
85    for (var i = 0; i < expected_values_for_next.length; i++) {
86      var iter = thunk();
87      for (var j = 0; j < i; j++) {
88        assertIteratorResult(expected_values_for_next[j],
89                             j == expected_values_for_next.length - 1,
90                             iter.next());
91      }
92      function Sentinel() {}
93      assertThrows(function () { iter.throw(new Sentinel); }, Sentinel);
94      assertThrownIteratorIsClosed(iter);
95    }
96  }
97
98  testNext(g);
99  testSend(g);
100  testThrow(g);
101
102  testNext(function*() { return yield* g(); });
103  testSend(function*() { return yield* g(); });
104  testThrow(function*() { return yield* g(); });
105
106  if (g instanceof GeneratorFunction) {
107    testNext(function() { return new g(); });
108    testSend(function() { return new g(); });
109    testThrow(function() { return new g(); });
110  }
111}
112
113TestGenerator(function* g1() { },
114              [undefined],
115              "foo",
116              [undefined]);
117
118TestGenerator(function* g2() { yield 1; },
119              [1, undefined],
120              "foo",
121              [1, undefined]);
122
123TestGenerator(function* g3() { yield 1; yield 2; },
124              [1, 2, undefined],
125              "foo",
126              [1, 2, undefined]);
127
128TestGenerator(function* g4() { yield 1; yield 2; return 3; },
129              [1, 2, 3],
130              "foo",
131              [1, 2, 3]);
132
133TestGenerator(function* g5() { return 1; },
134              [1],
135             "foo",
136              [1]);
137
138TestGenerator(function* g6() { var x = yield 1; return x; },
139              [1, undefined],
140              "foo",
141              [1, "foo"]);
142
143TestGenerator(function* g7() { var x = yield 1; yield 2; return x; },
144              [1, 2, undefined],
145              "foo",
146              [1, 2, "foo"]);
147
148TestGenerator(function* g8() { for (var x = 0; x < 4; x++) { yield x; } },
149              [0, 1, 2, 3, undefined],
150              "foo",
151              [0, 1, 2, 3, undefined]);
152
153// Generator with arguments.
154TestGenerator(
155    function g9() {
156      return (function*(a, b, c, d) {
157        yield a; yield b; yield c; yield d;
158      })("fee", "fi", "fo", "fum");
159    },
160    ["fee", "fi", "fo", "fum", undefined],
161    "foo",
162    ["fee", "fi", "fo", "fum", undefined]);
163
164// Too few arguments.
165TestGenerator(
166    function g10() {
167      return (function*(a, b, c, d) {
168        yield a; yield b; yield c; yield d;
169      })("fee", "fi");
170    },
171    ["fee", "fi", undefined, undefined, undefined],
172    "foo",
173    ["fee", "fi", undefined, undefined, undefined]);
174
175// Too many arguments.
176TestGenerator(
177    function g11() {
178      return (function*(a, b, c, d) {
179        yield a; yield b; yield c; yield d;
180      })("fee", "fi", "fo", "fum", "I smell the blood of an Englishman");
181    },
182    ["fee", "fi", "fo", "fum", undefined],
183    "foo",
184    ["fee", "fi", "fo", "fum", undefined]);
185
186// The arguments object.
187TestGenerator(
188    function g12() {
189      return (function*(a, b, c, d) {
190        for (var i = 0; i < arguments.length; i++) {
191          yield arguments[i];
192        }
193      })("fee", "fi", "fo", "fum", "I smell the blood of an Englishman");
194    },
195    ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
196     undefined],
197    "foo",
198    ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
199     undefined]);
200
201// Access to captured free variables.
202TestGenerator(
203    function g13() {
204      return (function(a, b, c, d) {
205        return (function*() {
206          yield a; yield b; yield c; yield d;
207        })();
208      })("fee", "fi", "fo", "fum");
209    },
210    ["fee", "fi", "fo", "fum", undefined],
211    "foo",
212    ["fee", "fi", "fo", "fum", undefined]);
213
214// Abusing the arguments object.
215TestGenerator(
216    function g14() {
217      return (function*(a, b, c, d) {
218        arguments[0] = "Be he live";
219        arguments[1] = "or be he dead";
220        arguments[2] = "I'll grind his bones";
221        arguments[3] = "to make my bread";
222        yield a; yield b; yield c; yield d;
223      })("fee", "fi", "fo", "fum");
224    },
225    ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
226     undefined],
227    "foo",
228    ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
229     undefined]);
230
231// Abusing the arguments object: strict mode.
232TestGenerator(
233    function g15() {
234      return (function*(a, b, c, d) {
235        "use strict";
236        arguments[0] = "Be he live";
237        arguments[1] = "or be he dead";
238        arguments[2] = "I'll grind his bones";
239        arguments[3] = "to make my bread";
240        yield a; yield b; yield c; yield d;
241      })("fee", "fi", "fo", "fum");
242    },
243    ["fee", "fi", "fo", "fum", undefined],
244    "foo",
245    ["fee", "fi", "fo", "fum", undefined]);
246
247// GC.
248TestGenerator(function* g16() { yield "baz"; gc(); yield "qux"; },
249              ["baz", "qux", undefined],
250              "foo",
251              ["baz", "qux", undefined]);
252
253// Receivers.
254TestGenerator(
255    function g17() {
256      function* g() { yield this.x; yield this.y; }
257      var o = { start: g, x: 1, y: 2 };
258      return o.start();
259    },
260    [1, 2, undefined],
261    "foo",
262    [1, 2, undefined]);
263
264TestGenerator(
265    function g18() {
266      function* g() { yield this.x; yield this.y; }
267      var iter = new g;
268      iter.x = 1;
269      iter.y = 2;
270      return iter;
271    },
272    [1, 2, undefined],
273    "foo",
274    [1, 2, undefined]);
275
276TestGenerator(
277    function* g19() {
278      var x = 1;
279      yield x;
280      with({x:2}) { yield x; }
281      yield x;
282    },
283    [1, 2, 1, undefined],
284    "foo",
285    [1, 2, 1, undefined]);
286
287TestGenerator(
288    function* g20() { yield (1 + (yield 2) + 3); },
289    [2, NaN, undefined],
290    "foo",
291    [2, "1foo3", undefined]);
292
293TestGenerator(
294    function* g21() { return (1 + (yield 2) + 3); },
295    [2, NaN],
296    "foo",
297    [2, "1foo3"]);
298
299TestGenerator(
300    function* g22() { yield (1 + (yield 2) + 3); yield (4 + (yield 5) + 6); },
301    [2, NaN, 5, NaN, undefined],
302    "foo",
303    [2, "1foo3", 5, "4foo6", undefined]);
304
305TestGenerator(
306    function* g23() {
307      return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
308    },
309    [2, NaN, 5, NaN, NaN],
310    "foo",
311    [2, "1foo3", 5, "4foo6", "foofoo"]);
312
313// Rewind a try context with and without operands on the stack.
314TestGenerator(
315    function* g24() {
316      try {
317        return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
318      } catch (e) {
319        throw e;
320      }
321    },
322    [2, NaN, 5, NaN, NaN],
323    "foo",
324    [2, "1foo3", 5, "4foo6", "foofoo"]);
325
326// Yielding in a catch context, with and without operands on the stack.
327TestGenerator(
328    function* g25() {
329      try {
330        throw (yield (1 + (yield 2) + 3))
331      } catch (e) {
332        if (typeof e == 'object') throw e;
333        return e + (yield (4 + (yield 5) + 6));
334      }
335    },
336    [2, NaN, 5, NaN, NaN],
337    "foo",
338    [2, "1foo3", 5, "4foo6", "foofoo"]);
339
340// Yield with no arguments yields undefined.
341TestGenerator(
342    function* g26() { return yield yield },
343    [undefined, undefined, undefined],
344    "foo",
345    [undefined, "foo", "foo"]);
346
347// A newline causes the parser to stop looking for an argument to yield.
348TestGenerator(
349    function* g27() {
350      yield
351      3
352      return
353    },
354    [undefined, undefined],
355    "foo",
356    [undefined, undefined]);
357
358// TODO(wingo): We should use TestGenerator for these, except that
359// currently yield* will unconditionally propagate a throw() to the
360// delegate iterator, which fails for these iterators that don't have
361// throw().  See http://code.google.com/p/v8/issues/detail?id=3484.
362(function() {
363    function* g28() {
364      yield* [1, 2, 3];
365    }
366    var iter = g28();
367    assertIteratorResult(1, false, iter.next());
368    assertIteratorResult(2, false, iter.next());
369    assertIteratorResult(3, false, iter.next());
370    assertIteratorResult(undefined, true, iter.next());
371})();
372
373(function() {
374    function* g29() {
375      yield* "abc";
376    }
377    var iter = g29();
378    assertIteratorResult("a", false, iter.next());
379    assertIteratorResult("b", false, iter.next());
380    assertIteratorResult("c", false, iter.next());
381    assertIteratorResult(undefined, true, iter.next());
382})();
383
384// Generator function instances.
385TestGenerator(GeneratorFunction(),
386              [undefined],
387              "foo",
388              [undefined]);
389
390TestGenerator(new GeneratorFunction(),
391              [undefined],
392              "foo",
393              [undefined]);
394
395TestGenerator(GeneratorFunction('yield 1;'),
396              [1, undefined],
397              "foo",
398              [1, undefined]);
399
400TestGenerator(
401    function() { return GeneratorFunction('x', 'y', 'yield x + y;')(1, 2) },
402    [3, undefined],
403    "foo",
404    [3, undefined]);
405
406// Access to this with formal arguments.
407TestGenerator(
408    function () {
409      return ({ x: 42, g: function* (a) { yield this.x } }).g(0);
410    },
411    [42, undefined],
412    "foo",
413    [42, undefined]);
414
415// Test that yield* re-yields received results without re-boxing.
416function TestDelegatingYield() {
417  function results(results) {
418    var i = 0;
419    function next() {
420      return results[i++];
421    }
422    var iter = { next: next };
423    var ret = {};
424    ret[Symbol.iterator] = function() { return iter; };
425    return ret;
426  }
427  function* yield_results(expected) {
428    return yield* results(expected);
429  }
430  function collect_results(iterable) {
431    var iter = iterable[Symbol.iterator]();
432    var ret = [];
433    var result;
434    do {
435      result = iter.next();
436      ret.push(result);
437    } while (!result.done);
438    return ret;
439  }
440  // We have to put a full result for the end, because the return will re-box.
441  var expected = [{value: 1}, 13, "foo", {value: 34, done: true}];
442
443  // Sanity check.
444  assertEquals(expected, collect_results(results(expected)));
445  assertEquals(expected, collect_results(yield_results(expected)));
446}
447TestDelegatingYield();
448
449function TestTryCatch(instantiate) {
450  function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; }
451  function Sentinel() {}
452
453  function Test1(iter) {
454    assertIteratorResult(1, false, iter.next());
455    assertIteratorResult(2, false, iter.next());
456    assertIteratorResult(3, false, iter.next());
457    assertIteratorIsClosed(iter);
458  }
459  Test1(instantiate(g));
460
461  function Test2(iter) {
462    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
463    assertThrownIteratorIsClosed(iter);
464  }
465  Test2(instantiate(g));
466
467  function Test3(iter) {
468    assertIteratorResult(1, false, iter.next());
469    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
470    assertThrownIteratorIsClosed(iter);
471  }
472  Test3(instantiate(g));
473
474  function Test4(iter) {
475    assertIteratorResult(1, false, iter.next());
476    assertIteratorResult(2, false, iter.next());
477    var exn = new Sentinel;
478    assertIteratorResult(exn, false, iter.throw(exn));
479    assertIteratorResult(3, false, iter.next());
480    assertIteratorIsClosed(iter);
481  }
482  Test4(instantiate(g));
483
484  function Test5(iter) {
485    assertIteratorResult(1, false, iter.next());
486    assertIteratorResult(2, false, iter.next());
487    var exn = new Sentinel;
488    assertIteratorResult(exn, false, iter.throw(exn));
489    assertIteratorResult(3, false, iter.next());
490    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
491    assertThrownIteratorIsClosed(iter);
492  }
493  Test5(instantiate(g));
494
495  function Test6(iter) {
496    assertIteratorResult(1, false, iter.next());
497    assertIteratorResult(2, false, iter.next());
498    var exn = new Sentinel;
499    assertIteratorResult(exn, false, iter.throw(exn));
500    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
501    assertThrownIteratorIsClosed(iter);
502  }
503  Test6(instantiate(g));
504
505  function Test7(iter) {
506    assertIteratorResult(1, false, iter.next());
507    assertIteratorResult(2, false, iter.next());
508    assertIteratorResult(3, false, iter.next());
509    assertIteratorIsClosed(iter);
510  }
511  Test7(instantiate(g));
512}
513TestTryCatch(function (g) { return g(); });
514TestTryCatch(function* (g) { return yield* g(); });
515
516function TestTryFinally(instantiate) {
517  function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; }
518  function Sentinel() {}
519  function Sentinel2() {}
520
521  function Test1(iter) {
522    assertIteratorResult(1, false, iter.next());
523    assertIteratorResult(2, false, iter.next());
524    assertIteratorResult(3, false, iter.next());
525    assertIteratorResult(4, false, iter.next());
526    assertIteratorIsClosed(iter);
527  }
528  Test1(instantiate(g));
529
530  function Test2(iter) {
531    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
532    assertThrownIteratorIsClosed(iter);
533  }
534  Test2(instantiate(g));
535
536  function Test3(iter) {
537    assertIteratorResult(1, false, iter.next());
538    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
539    assertThrownIteratorIsClosed(iter);
540  }
541  Test3(instantiate(g));
542
543  function Test4(iter) {
544    assertIteratorResult(1, false, iter.next());
545    assertIteratorResult(2, false, iter.next());
546    assertIteratorResult(3, false, iter.throw(new Sentinel));
547    assertThrows(function() { iter.next(); }, Sentinel);
548    assertThrownIteratorIsClosed(iter);
549  }
550  Test4(instantiate(g));
551
552  function Test5(iter) {
553    assertIteratorResult(1, false, iter.next());
554    assertIteratorResult(2, false, iter.next());
555    assertIteratorResult(3, false, iter.throw(new Sentinel));
556    assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
557    assertThrownIteratorIsClosed(iter);
558  }
559  Test5(instantiate(g));
560
561  function Test6(iter) {
562    assertIteratorResult(1, false, iter.next());
563    assertIteratorResult(2, false, iter.next());
564    assertIteratorResult(3, false, iter.next());
565    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
566    assertThrownIteratorIsClosed(iter);
567  }
568  Test6(instantiate(g));
569
570  function Test7(iter) {
571    assertIteratorResult(1, false, iter.next());
572    assertIteratorResult(2, false, iter.next());
573    assertIteratorResult(3, false, iter.next());
574    assertIteratorResult(4, false, iter.next());
575    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
576    assertThrownIteratorIsClosed(iter);
577  }
578  Test7(instantiate(g));
579
580  function Test8(iter) {
581    assertIteratorResult(1, false, iter.next());
582    assertIteratorResult(2, false, iter.next());
583    assertIteratorResult(3, false, iter.next());
584    assertIteratorResult(4, false, iter.next());
585    assertIteratorIsClosed(iter);
586  }
587  Test8(instantiate(g));
588}
589TestTryFinally(function (g) { return g(); });
590TestTryFinally(function* (g) { return yield* g(); });
591
592function TestNestedTry(instantiate) {
593  function* g() {
594    try {
595      yield 1;
596      try { yield 2; } catch (e) { yield e; }
597      yield 3;
598    } finally {
599      yield 4;
600    }
601    yield 5;
602  }
603  function Sentinel() {}
604  function Sentinel2() {}
605
606  function Test1(iter) {
607    assertIteratorResult(1, false, iter.next());
608    assertIteratorResult(2, false, iter.next());
609    assertIteratorResult(3, false, iter.next());
610    assertIteratorResult(4, false, iter.next());
611    assertIteratorResult(5, false, iter.next());
612    assertIteratorIsClosed(iter);
613  }
614  Test1(instantiate(g));
615
616  function Test2(iter) {
617    assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
618    assertThrownIteratorIsClosed(iter);
619  }
620  Test2(instantiate(g));
621
622  function Test3(iter) {
623    assertIteratorResult(1, false, iter.next());
624    assertIteratorResult(4, false, iter.throw(new Sentinel));
625    assertThrows(function() { iter.next(); }, Sentinel);
626    assertThrownIteratorIsClosed(iter);
627  }
628  Test3(instantiate(g));
629
630  function Test4(iter) {
631    assertIteratorResult(1, false, iter.next());
632    assertIteratorResult(4, false, iter.throw(new Sentinel));
633    assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
634    assertThrownIteratorIsClosed(iter);
635  }
636  Test4(instantiate(g));
637
638  function Test5(iter) {
639    assertIteratorResult(1, false, iter.next());
640    assertIteratorResult(2, false, iter.next());
641    var exn = new Sentinel;
642    assertIteratorResult(exn, false, iter.throw(exn));
643    assertIteratorResult(3, false, iter.next());
644    assertIteratorResult(4, false, iter.next());
645    assertIteratorResult(5, false, iter.next());
646    assertIteratorIsClosed(iter);
647  }
648  Test5(instantiate(g));
649
650  function Test6(iter) {
651    assertIteratorResult(1, false, iter.next());
652    assertIteratorResult(2, false, iter.next());
653    var exn = new Sentinel;
654    assertIteratorResult(exn, false, iter.throw(exn));
655    assertIteratorResult(4, false, iter.throw(new Sentinel2));
656    assertThrows(function() { iter.next(); }, Sentinel2);
657    assertThrownIteratorIsClosed(iter);
658  }
659  Test6(instantiate(g));
660
661  function Test7(iter) {
662    assertIteratorResult(1, false, iter.next());
663    assertIteratorResult(2, false, iter.next());
664    var exn = new Sentinel;
665    assertIteratorResult(exn, false, iter.throw(exn));
666    assertIteratorResult(3, false, iter.next());
667    assertIteratorResult(4, false, iter.throw(new Sentinel2));
668    assertThrows(function() { iter.next(); }, Sentinel2);
669    assertThrownIteratorIsClosed(iter);
670  }
671  Test7(instantiate(g));
672
673  // That's probably enough.
674}
675TestNestedTry(function (g) { return g(); });
676TestNestedTry(function* (g) { return yield* g(); });
677
678function TestRecursion() {
679  function TestNextRecursion() {
680    function* g() { yield iter.next(); }
681    var iter = g();
682    return iter.next();
683  }
684  function TestSendRecursion() {
685    function* g() { yield iter.next(42); }
686    var iter = g();
687    return iter.next();
688  }
689  function TestThrowRecursion() {
690    function* g() { yield iter.throw(1); }
691    var iter = g();
692    return iter.next();
693  }
694  assertThrows(TestNextRecursion, Error);
695  assertThrows(TestSendRecursion, Error);
696  assertThrows(TestThrowRecursion, Error);
697}
698TestRecursion();
699