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
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.
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.
28 // Flags: --harmony-generators --expose-gc
30 // Test generator iteration.
32 var GeneratorFunction = (function*(){yield 1;}).__proto__.constructor;
34 function assertIteratorResult(value, done, result) {
35 assertEquals({ value: value, done: done}, result);
38 function assertIteratorIsClosed(iter) {
39 assertIteratorResult(undefined, true, iter.next());
40 assertDoesNotThrow(function() { iter.next(); });
43 function 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);
50 function TestGeneratorResultPrototype() {
51 function* g() { yield 1; }
53 var result = iter.next();
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);
61 TestGeneratorResultPrototype()
63 function TestGenerator(g, expected_values_for_next,
64 send_val, expected_values_for_send) {
65 function testNext(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());
73 assertIteratorIsClosed(iter);
75 function testSend(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,
82 assertIteratorIsClosed(iter);
84 function testThrow(thunk) {
85 for (var i = 0; i < expected_values_for_next.length; i++) {
87 for (var j = 0; j < i; j++) {
88 assertIteratorResult(expected_values_for_next[j],
89 j == expected_values_for_next.length - 1,
92 function Sentinel() {}
93 assertThrows(function () { iter.throw(new Sentinel); }, Sentinel);
94 assertThrownIteratorIsClosed(iter);
102 testNext(function*() { return yield* g(); });
103 testSend(function*() { return yield* g(); });
104 testThrow(function*() { return yield* g(); });
106 if (g instanceof GeneratorFunction) {
107 testNext(function() { return new g(); });
108 testSend(function() { return new g(); });
109 testThrow(function() { return new g(); });
113 TestGenerator(function* g1() { },
118 TestGenerator(function* g2() { yield 1; },
123 TestGenerator(function* g3() { yield 1; yield 2; },
128 TestGenerator(function* g4() { yield 1; yield 2; return 3; },
133 TestGenerator(function* g5() { return 1; },
138 TestGenerator(function* g6() { var x = yield 1; return x; },
143 TestGenerator(function* g7() { var x = yield 1; yield 2; return x; },
148 TestGenerator(function* g8() { for (var x = 0; x < 4; x++) { yield x; } },
149 [0, 1, 2, 3, undefined],
151 [0, 1, 2, 3, undefined]);
153 // Generator with arguments.
156 return (function*(a, b, c, d) {
157 yield a; yield b; yield c; yield d;
158 })("fee", "fi", "fo", "fum");
160 ["fee", "fi", "fo", "fum", undefined],
162 ["fee", "fi", "fo", "fum", undefined]);
164 // Too few arguments.
167 return (function*(a, b, c, d) {
168 yield a; yield b; yield c; yield d;
171 ["fee", "fi", undefined, undefined, undefined],
173 ["fee", "fi", undefined, undefined, undefined]);
175 // Too many arguments.
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");
182 ["fee", "fi", "fo", "fum", undefined],
184 ["fee", "fi", "fo", "fum", undefined]);
186 // The arguments object.
189 return (function*(a, b, c, d) {
190 for (var i = 0; i < arguments.length; i++) {
193 })("fee", "fi", "fo", "fum", "I smell the blood of an Englishman");
195 ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
198 ["fee", "fi", "fo", "fum", "I smell the blood of an Englishman",
201 // Access to captured free variables.
204 return (function(a, b, c, d) {
205 return (function*() {
206 yield a; yield b; yield c; yield d;
208 })("fee", "fi", "fo", "fum");
210 ["fee", "fi", "fo", "fum", undefined],
212 ["fee", "fi", "fo", "fum", undefined]);
214 // Abusing the arguments object.
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");
225 ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
228 ["Be he live", "or be he dead", "I'll grind his bones", "to make my bread",
231 // Abusing the arguments object: strict mode.
234 return (function*(a, b, c, d) {
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");
243 ["fee", "fi", "fo", "fum", undefined],
245 ["fee", "fi", "fo", "fum", undefined]);
248 TestGenerator(function* g16() { yield "baz"; gc(); yield "qux"; },
249 ["baz", "qux", undefined],
251 ["baz", "qux", undefined]);
256 function* g() { yield this.x; yield this.y; }
257 var o = { start: g, x: 1, y: 2 };
266 function* g() { yield this.x; yield this.y; }
280 with({x:2}) { yield x; }
283 [1, 2, 1, undefined],
285 [1, 2, 1, undefined]);
288 function* g20() { yield (1 + (yield 2) + 3); },
291 [2, "1foo3", undefined]);
294 function* g21() { return (1 + (yield 2) + 3); },
300 function* g22() { yield (1 + (yield 2) + 3); yield (4 + (yield 5) + 6); },
301 [2, NaN, 5, NaN, undefined],
303 [2, "1foo3", 5, "4foo6", undefined]);
307 return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
309 [2, NaN, 5, NaN, NaN],
311 [2, "1foo3", 5, "4foo6", "foofoo"]);
313 // Rewind a try context with and without operands on the stack.
317 return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6));
322 [2, NaN, 5, NaN, NaN],
324 [2, "1foo3", 5, "4foo6", "foofoo"]);
326 // Yielding in a catch context, with and without operands on the stack.
330 throw (yield (1 + (yield 2) + 3))
332 if (typeof e == 'object') throw e;
333 return e + (yield (4 + (yield 5) + 6));
336 [2, NaN, 5, NaN, NaN],
338 [2, "1foo3", 5, "4foo6", "foofoo"]);
340 // Yield with no arguments yields undefined.
342 function* g26() { return yield yield },
343 [undefined, undefined, undefined],
345 [undefined, "foo", "foo"]);
347 // A newline causes the parser to stop looking for an argument to yield.
354 [undefined, undefined],
356 [undefined, undefined]);
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.
367 assertIteratorResult(1, false, iter.next());
368 assertIteratorResult(2, false, iter.next());
369 assertIteratorResult(3, false, iter.next());
370 assertIteratorResult(undefined, true, iter.next());
378 assertIteratorResult("a", false, iter.next());
379 assertIteratorResult("b", false, iter.next());
380 assertIteratorResult("c", false, iter.next());
381 assertIteratorResult(undefined, true, iter.next());
384 // Generator function instances.
385 TestGenerator(GeneratorFunction(),
390 TestGenerator(new GeneratorFunction(),
395 TestGenerator(GeneratorFunction('yield 1;'),
401 function() { return GeneratorFunction('x', 'y', 'yield x + y;')(1, 2) },
406 // Access to this with formal arguments.
409 return ({ x: 42, g: function* (a) { yield this.x } }).g(0);
415 // Test that yield* re-yields received results without re-boxing.
416 function TestDelegatingYield() {
417 function results(results) {
422 var iter = { next: next };
424 ret[Symbol.iterator] = function() { return iter; };
427 function* yield_results(expected) {
428 return yield* results(expected);
430 function collect_results(iterable) {
431 var iter = iterable[Symbol.iterator]();
435 result = iter.next();
437 } while (!result.done);
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}];
444 assertEquals(expected, collect_results(results(expected)));
445 assertEquals(expected, collect_results(yield_results(expected)));
447 TestDelegatingYield();
449 function TestTryCatch(instantiate) {
450 function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; }
451 function Sentinel() {}
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);
459 Test1(instantiate(g));
461 function Test2(iter) {
462 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
463 assertThrownIteratorIsClosed(iter);
465 Test2(instantiate(g));
467 function Test3(iter) {
468 assertIteratorResult(1, false, iter.next());
469 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
470 assertThrownIteratorIsClosed(iter);
472 Test3(instantiate(g));
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);
482 Test4(instantiate(g));
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);
493 Test5(instantiate(g));
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);
503 Test6(instantiate(g));
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);
511 Test7(instantiate(g));
513 TestTryCatch(function (g) { return g(); });
514 TestTryCatch(function* (g) { return yield* g(); });
516 function TestTryFinally(instantiate) {
517 function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; }
518 function Sentinel() {}
519 function Sentinel2() {}
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);
528 Test1(instantiate(g));
530 function Test2(iter) {
531 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
532 assertThrownIteratorIsClosed(iter);
534 Test2(instantiate(g));
536 function Test3(iter) {
537 assertIteratorResult(1, false, iter.next());
538 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
539 assertThrownIteratorIsClosed(iter);
541 Test3(instantiate(g));
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);
550 Test4(instantiate(g));
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);
559 Test5(instantiate(g));
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);
568 Test6(instantiate(g));
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);
578 Test7(instantiate(g));
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);
587 Test8(instantiate(g));
589 TestTryFinally(function (g) { return g(); });
590 TestTryFinally(function* (g) { return yield* g(); });
592 function TestNestedTry(instantiate) {
596 try { yield 2; } catch (e) { yield e; }
603 function Sentinel() {}
604 function Sentinel2() {}
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);
614 Test1(instantiate(g));
616 function Test2(iter) {
617 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
618 assertThrownIteratorIsClosed(iter);
620 Test2(instantiate(g));
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);
628 Test3(instantiate(g));
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);
636 Test4(instantiate(g));
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);
648 Test5(instantiate(g));
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);
659 Test6(instantiate(g));
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);
671 Test7(instantiate(g));
673 // That's probably enough.
675 TestNestedTry(function (g) { return g(); });
676 TestNestedTry(function* (g) { return yield* g(); });
678 function TestRecursion() {
679 function TestNextRecursion() {
680 function* g() { yield iter.next(); }
684 function TestSendRecursion() {
685 function* g() { yield iter.next(42); }
689 function TestThrowRecursion() {
690 function* g() { yield iter.throw(1); }
694 assertThrows(TestNextRecursion, Error);
695 assertThrows(TestSendRecursion, Error);
696 assertThrows(TestThrowRecursion, Error);