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