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