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 assertIteratorIsClosed(iter); 45} 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) { 104 testNext(function() { return new g(); }); 105 testSend(function() { return new g(); }); 106 testThrow(function() { return new g(); }); 107 } 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( 262 function g18() { 263 function* g() { yield this.x; yield this.y; } 264 var iter = new g; 265 iter.x = 1; 266 iter.y = 2; 267 return iter; 268 }, 269 [1, 2, undefined], 270 "foo", 271 [1, 2, undefined]); 272 273TestGenerator( 274 function* g19() { 275 var x = 1; 276 yield x; 277 with({x:2}) { yield x; } 278 yield x; 279 }, 280 [1, 2, 1, undefined], 281 "foo", 282 [1, 2, 1, undefined]); 283 284TestGenerator( 285 function* g20() { yield (1 + (yield 2) + 3); }, 286 [2, NaN, undefined], 287 "foo", 288 [2, "1foo3", undefined]); 289 290TestGenerator( 291 function* g21() { return (1 + (yield 2) + 3); }, 292 [2, NaN], 293 "foo", 294 [2, "1foo3"]); 295 296TestGenerator( 297 function* g22() { yield (1 + (yield 2) + 3); yield (4 + (yield 5) + 6); }, 298 [2, NaN, 5, NaN, undefined], 299 "foo", 300 [2, "1foo3", 5, "4foo6", undefined]); 301 302TestGenerator( 303 function* g23() { 304 return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6)); 305 }, 306 [2, NaN, 5, NaN, NaN], 307 "foo", 308 [2, "1foo3", 5, "4foo6", "foofoo"]); 309 310// Rewind a try context with and without operands on the stack. 311TestGenerator( 312 function* g24() { 313 try { 314 return (yield (1 + (yield 2) + 3)) + (yield (4 + (yield 5) + 6)); 315 } catch (e) { 316 throw e; 317 } 318 }, 319 [2, NaN, 5, NaN, NaN], 320 "foo", 321 [2, "1foo3", 5, "4foo6", "foofoo"]); 322 323// Yielding in a catch context, with and without operands on the stack. 324TestGenerator( 325 function* g25() { 326 try { 327 throw (yield (1 + (yield 2) + 3)) 328 } catch (e) { 329 if (typeof e == 'object') throw e; 330 return e + (yield (4 + (yield 5) + 6)); 331 } 332 }, 333 [2, NaN, 5, NaN, NaN], 334 "foo", 335 [2, "1foo3", 5, "4foo6", "foofoo"]); 336 337// Yield with no arguments yields undefined. 338TestGenerator( 339 function* g26() { return yield yield }, 340 [undefined, undefined, undefined], 341 "foo", 342 [undefined, "foo", "foo"]); 343 344// A newline causes the parser to stop looking for an argument to yield. 345TestGenerator( 346 function* g27() { 347 yield 348 3 349 return 350 }, 351 [undefined, undefined], 352 "foo", 353 [undefined, undefined]); 354 355// TODO(wingo): We should use TestGenerator for these, except that 356// currently yield* will unconditionally propagate a throw() to the 357// delegate iterator, which fails for these iterators that don't have 358// throw(). See http://code.google.com/p/v8/issues/detail?id=3484. 359(function() { 360 function* g28() { 361 yield* [1, 2, 3]; 362 } 363 var iter = g28(); 364 assertIteratorResult(1, false, iter.next()); 365 assertIteratorResult(2, false, iter.next()); 366 assertIteratorResult(3, false, iter.next()); 367 assertIteratorResult(undefined, true, iter.next()); 368})(); 369 370(function() { 371 function* g29() { 372 yield* "abc"; 373 } 374 var iter = g29(); 375 assertIteratorResult("a", false, iter.next()); 376 assertIteratorResult("b", false, iter.next()); 377 assertIteratorResult("c", false, iter.next()); 378 assertIteratorResult(undefined, true, iter.next()); 379})(); 380 381// Generator function instances. 382TestGenerator(GeneratorFunction(), 383 [undefined], 384 "foo", 385 [undefined]); 386 387TestGenerator(new GeneratorFunction(), 388 [undefined], 389 "foo", 390 [undefined]); 391 392TestGenerator(GeneratorFunction('yield 1;'), 393 [1, undefined], 394 "foo", 395 [1, undefined]); 396 397TestGenerator( 398 function() { return GeneratorFunction('x', 'y', 'yield x + y;')(1, 2) }, 399 [3, undefined], 400 "foo", 401 [3, undefined]); 402 403// Access to this with formal arguments. 404TestGenerator( 405 function () { 406 return ({ x: 42, g: function* (a) { yield this.x } }).g(0); 407 }, 408 [42, undefined], 409 "foo", 410 [42, undefined]); 411 412// Test that yield* re-yields received results without re-boxing. 413function TestDelegatingYield() { 414 function results(results) { 415 var i = 0; 416 function next() { 417 return results[i++]; 418 } 419 var iter = { next: next }; 420 var ret = {}; 421 ret[Symbol.iterator] = function() { return iter; }; 422 return ret; 423 } 424 function* yield_results(expected) { 425 return yield* results(expected); 426 } 427 function collect_results(iterable) { 428 var iter = iterable[Symbol.iterator](); 429 var ret = []; 430 var result; 431 do { 432 result = iter.next(); 433 ret.push(result); 434 } while (!result.done); 435 return ret; 436 } 437 // We have to put a full result for the end, because the return will re-box. 438 var expected = [{value: 1}, 13, "foo", {value: 34, done: true}]; 439 440 // Sanity check. 441 assertEquals(expected, collect_results(results(expected))); 442 assertEquals(expected, collect_results(yield_results(expected))); 443} 444TestDelegatingYield(); 445 446function TestTryCatch(instantiate) { 447 function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; } 448 function Sentinel() {} 449 450 function Test1(iter) { 451 assertIteratorResult(1, false, iter.next()); 452 assertIteratorResult(2, false, iter.next()); 453 assertIteratorResult(3, false, iter.next()); 454 assertIteratorIsClosed(iter); 455 } 456 Test1(instantiate(g)); 457 458 function Test2(iter) { 459 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 460 assertThrownIteratorIsClosed(iter); 461 } 462 Test2(instantiate(g)); 463 464 function Test3(iter) { 465 assertIteratorResult(1, false, iter.next()); 466 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 467 assertThrownIteratorIsClosed(iter); 468 } 469 Test3(instantiate(g)); 470 471 function Test4(iter) { 472 assertIteratorResult(1, false, iter.next()); 473 assertIteratorResult(2, false, iter.next()); 474 var exn = new Sentinel; 475 assertIteratorResult(exn, false, iter.throw(exn)); 476 assertIteratorResult(3, false, iter.next()); 477 assertIteratorIsClosed(iter); 478 } 479 Test4(instantiate(g)); 480 481 function Test5(iter) { 482 assertIteratorResult(1, false, iter.next()); 483 assertIteratorResult(2, false, iter.next()); 484 var exn = new Sentinel; 485 assertIteratorResult(exn, false, iter.throw(exn)); 486 assertIteratorResult(3, false, iter.next()); 487 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 488 assertThrownIteratorIsClosed(iter); 489 } 490 Test5(instantiate(g)); 491 492 function Test6(iter) { 493 assertIteratorResult(1, false, iter.next()); 494 assertIteratorResult(2, false, iter.next()); 495 var exn = new Sentinel; 496 assertIteratorResult(exn, false, iter.throw(exn)); 497 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 498 assertThrownIteratorIsClosed(iter); 499 } 500 Test6(instantiate(g)); 501 502 function Test7(iter) { 503 assertIteratorResult(1, false, iter.next()); 504 assertIteratorResult(2, false, iter.next()); 505 assertIteratorResult(3, false, iter.next()); 506 assertIteratorIsClosed(iter); 507 } 508 Test7(instantiate(g)); 509} 510TestTryCatch(function (g) { return g(); }); 511TestTryCatch(function* (g) { return yield* g(); }); 512 513function TestTryFinally(instantiate) { 514 function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; } 515 function Sentinel() {} 516 function Sentinel2() {} 517 518 function Test1(iter) { 519 assertIteratorResult(1, false, iter.next()); 520 assertIteratorResult(2, false, iter.next()); 521 assertIteratorResult(3, false, iter.next()); 522 assertIteratorResult(4, false, iter.next()); 523 assertIteratorIsClosed(iter); 524 } 525 Test1(instantiate(g)); 526 527 function Test2(iter) { 528 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 529 assertThrownIteratorIsClosed(iter); 530 } 531 Test2(instantiate(g)); 532 533 function Test3(iter) { 534 assertIteratorResult(1, false, iter.next()); 535 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 536 assertThrownIteratorIsClosed(iter); 537 } 538 Test3(instantiate(g)); 539 540 function Test4(iter) { 541 assertIteratorResult(1, false, iter.next()); 542 assertIteratorResult(2, false, iter.next()); 543 assertIteratorResult(3, false, iter.throw(new Sentinel)); 544 assertThrows(function() { iter.next(); }, Sentinel); 545 assertThrownIteratorIsClosed(iter); 546 } 547 Test4(instantiate(g)); 548 549 function Test5(iter) { 550 assertIteratorResult(1, false, iter.next()); 551 assertIteratorResult(2, false, iter.next()); 552 assertIteratorResult(3, false, iter.throw(new Sentinel)); 553 assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); 554 assertThrownIteratorIsClosed(iter); 555 } 556 Test5(instantiate(g)); 557 558 function Test6(iter) { 559 assertIteratorResult(1, false, iter.next()); 560 assertIteratorResult(2, false, iter.next()); 561 assertIteratorResult(3, false, iter.next()); 562 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 563 assertThrownIteratorIsClosed(iter); 564 } 565 Test6(instantiate(g)); 566 567 function Test7(iter) { 568 assertIteratorResult(1, false, iter.next()); 569 assertIteratorResult(2, false, iter.next()); 570 assertIteratorResult(3, false, iter.next()); 571 assertIteratorResult(4, false, iter.next()); 572 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 573 assertThrownIteratorIsClosed(iter); 574 } 575 Test7(instantiate(g)); 576 577 function Test8(iter) { 578 assertIteratorResult(1, false, iter.next()); 579 assertIteratorResult(2, false, iter.next()); 580 assertIteratorResult(3, false, iter.next()); 581 assertIteratorResult(4, false, iter.next()); 582 assertIteratorIsClosed(iter); 583 } 584 Test8(instantiate(g)); 585} 586TestTryFinally(function (g) { return g(); }); 587TestTryFinally(function* (g) { return yield* g(); }); 588 589function TestNestedTry(instantiate) { 590 function* g() { 591 try { 592 yield 1; 593 try { yield 2; } catch (e) { yield e; } 594 yield 3; 595 } finally { 596 yield 4; 597 } 598 yield 5; 599 } 600 function Sentinel() {} 601 function Sentinel2() {} 602 603 function Test1(iter) { 604 assertIteratorResult(1, false, iter.next()); 605 assertIteratorResult(2, false, iter.next()); 606 assertIteratorResult(3, false, iter.next()); 607 assertIteratorResult(4, false, iter.next()); 608 assertIteratorResult(5, false, iter.next()); 609 assertIteratorIsClosed(iter); 610 } 611 Test1(instantiate(g)); 612 613 function Test2(iter) { 614 assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); 615 assertThrownIteratorIsClosed(iter); 616 } 617 Test2(instantiate(g)); 618 619 function Test3(iter) { 620 assertIteratorResult(1, false, iter.next()); 621 assertIteratorResult(4, false, iter.throw(new Sentinel)); 622 assertThrows(function() { iter.next(); }, Sentinel); 623 assertThrownIteratorIsClosed(iter); 624 } 625 Test3(instantiate(g)); 626 627 function Test4(iter) { 628 assertIteratorResult(1, false, iter.next()); 629 assertIteratorResult(4, false, iter.throw(new Sentinel)); 630 assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); 631 assertThrownIteratorIsClosed(iter); 632 } 633 Test4(instantiate(g)); 634 635 function Test5(iter) { 636 assertIteratorResult(1, false, iter.next()); 637 assertIteratorResult(2, false, iter.next()); 638 var exn = new Sentinel; 639 assertIteratorResult(exn, false, iter.throw(exn)); 640 assertIteratorResult(3, false, iter.next()); 641 assertIteratorResult(4, false, iter.next()); 642 assertIteratorResult(5, false, iter.next()); 643 assertIteratorIsClosed(iter); 644 } 645 Test5(instantiate(g)); 646 647 function Test6(iter) { 648 assertIteratorResult(1, false, iter.next()); 649 assertIteratorResult(2, false, iter.next()); 650 var exn = new Sentinel; 651 assertIteratorResult(exn, false, iter.throw(exn)); 652 assertIteratorResult(4, false, iter.throw(new Sentinel2)); 653 assertThrows(function() { iter.next(); }, Sentinel2); 654 assertThrownIteratorIsClosed(iter); 655 } 656 Test6(instantiate(g)); 657 658 function Test7(iter) { 659 assertIteratorResult(1, false, iter.next()); 660 assertIteratorResult(2, false, iter.next()); 661 var exn = new Sentinel; 662 assertIteratorResult(exn, false, iter.throw(exn)); 663 assertIteratorResult(3, false, iter.next()); 664 assertIteratorResult(4, false, iter.throw(new Sentinel2)); 665 assertThrows(function() { iter.next(); }, Sentinel2); 666 assertThrownIteratorIsClosed(iter); 667 } 668 Test7(instantiate(g)); 669 670 // That's probably enough. 671} 672TestNestedTry(function (g) { return g(); }); 673TestNestedTry(function* (g) { return yield* g(); }); 674 675function TestRecursion() { 676 function TestNextRecursion() { 677 function* g() { yield iter.next(); } 678 var iter = g(); 679 return iter.next(); 680 } 681 function TestSendRecursion() { 682 function* g() { yield iter.next(42); } 683 var iter = g(); 684 return iter.next(); 685 } 686 function TestThrowRecursion() { 687 function* g() { yield iter.throw(1); } 688 var iter = g(); 689 return iter.next(); 690 } 691 assertThrows(TestNextRecursion, Error); 692 assertThrows(TestSendRecursion, Error); 693 assertThrows(TestThrowRecursion, Error); 694} 695TestRecursion(); 696