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