blob: b6fcdaa48792d2d7b2d6fc7b486d746e9da8e99b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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();