1package goja 2 3import ( 4 "github.com/dop251/goja/parser" 5 "io/ioutil" 6 "testing" 7) 8 9func testScript(script string, expectedResult Value, t *testing.T) { 10 prg, err := parser.ParseFile(nil, "test.js", script, 0) 11 if err != nil { 12 t.Fatal(err) 13 } 14 15 c := newCompiler() 16 c.compile(prg, false, false, true) 17 18 r := &Runtime{} 19 r.init() 20 21 vm := r.vm 22 vm.prg = c.p 23 vm.prg.dumpCode(t.Logf) 24 vm.run() 25 t.Logf("stack size: %d", len(vm.stack)) 26 t.Logf("stashAllocs: %d", vm.stashAllocs) 27 28 v := vm.r.globalObject.self.getStr("rv", nil) 29 if v == nil { 30 v = _undefined 31 } 32 if !v.SameAs(expectedResult) { 33 t.Fatalf("Result: %+v, expected: %+v", v, expectedResult) 34 } 35 36 if vm.sp != 0 { 37 t.Fatalf("sp: %d", vm.sp) 38 } 39} 40 41func testScript1(script string, expectedResult Value, t *testing.T) { 42 prg, err := parser.ParseFile(nil, "test.js", script, 0) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 c := newCompiler() 48 c.compile(prg, false, false, true) 49 50 r := &Runtime{} 51 r.init() 52 53 vm := r.vm 54 vm.prg = c.p 55 vm.prg.dumpCode(t.Logf) 56 vm.result = _undefined 57 vm.run() 58 v := vm.result 59 t.Logf("stack size: %d", len(vm.stack)) 60 t.Logf("stashAllocs: %d", vm.stashAllocs) 61 62 if v == nil && expectedResult != nil || !v.SameAs(expectedResult) { 63 t.Fatalf("Result: %+v, expected: %+v", v, expectedResult) 64 } 65 66 if vm.sp != 0 { 67 t.Fatalf("sp: %d", vm.sp) 68 } 69 70 if l := len(vm.iterStack); l > 0 { 71 t.Fatalf("iter stack is not empty: %d", l) 72 } 73} 74 75func TestEmptyProgram(t *testing.T) { 76 const SCRIPT = ` 77 ` 78 79 testScript1(SCRIPT, _undefined, t) 80} 81 82func TestResultEmptyBlock(t *testing.T) { 83 const SCRIPT = ` 84 undefined; 85 {} 86 ` 87 testScript1(SCRIPT, _undefined, t) 88} 89 90func TestResultVarDecl(t *testing.T) { 91 const SCRIPT = ` 92 7; var x = 1; 93 ` 94 testScript1(SCRIPT, valueInt(7), t) 95} 96 97func TestResultLexDecl(t *testing.T) { 98 const SCRIPT = ` 99 7; {let x = 1}; 100 ` 101 testScript1(SCRIPT, valueInt(7), t) 102} 103 104func TestResultLexDeclBreak(t *testing.T) { 105 const SCRIPT = ` 106 L:{ 7; {let x = 1; break L;}}; 107 ` 108 testScript1(SCRIPT, valueInt(7), t) 109} 110 111func TestResultLexDeclNested(t *testing.T) { 112 const SCRIPT = ` 113 7; {let x = (function() { return eval("8; {let y = 9}")})()}; 114 ` 115 testScript1(SCRIPT, valueInt(7), t) 116} 117 118func TestErrorProto(t *testing.T) { 119 const SCRIPT = ` 120 var e = new TypeError(); 121 e.name; 122 ` 123 124 testScript1(SCRIPT, asciiString("TypeError"), t) 125} 126 127func TestThis1(t *testing.T) { 128 const SCRIPT = ` 129 function independent() { 130 return this.prop; 131 } 132 var o = {}; 133 o.b = {g: independent, prop: 42}; 134 135 var rv = o.b.g(); 136 ` 137 testScript(SCRIPT, intToValue(42), t) 138} 139 140func TestThis2(t *testing.T) { 141 const SCRIPT = ` 142var o = { 143 prop: 37, 144 f: function() { 145 return this.prop; 146 } 147}; 148 149var rv = o.f(); 150` 151 152 testScript(SCRIPT, intToValue(37), t) 153} 154 155func TestThisStrict(t *testing.T) { 156 const SCRIPT = ` 157 "use strict"; 158 159 Object.defineProperty(Object.prototype, "x", { get: function () { return this; } }); 160 161 (5).x === 5; 162 ` 163 164 testScript1(SCRIPT, valueTrue, t) 165} 166 167func TestThisNoStrict(t *testing.T) { 168 const SCRIPT = ` 169 Object.defineProperty(Object.prototype, "x", { get: function () { return this; } }); 170 171 (5).x == 5; 172 ` 173 174 testScript1(SCRIPT, valueTrue, t) 175} 176 177func TestNestedFuncVarResolution(t *testing.T) { 178 const SCRIPT = ` 179 (function outer() { 180 var v = 42; 181 function inner() { 182 return v; 183 } 184 return inner(); 185 })(); 186` 187 testScript1(SCRIPT, valueInt(42), t) 188} 189 190func TestNestedFuncVarResolution1(t *testing.T) { 191 const SCRIPT = ` 192 function outer(argOuter) { 193 var called = 0; 194 var inner = function(argInner) { 195 if (arguments.length !== 1) { 196 throw new Error(); 197 } 198 called++; 199 if (argOuter !== 1) { 200 throw new Error("argOuter"); 201 } 202 if (argInner !== 2) { 203 throw new Error("argInner"); 204 } 205 }; 206 inner(2); 207 } 208 outer(1); 209 ` 210 testScript1(SCRIPT, _undefined, t) 211} 212 213func TestCallFewerArgs(t *testing.T) { 214 const SCRIPT = ` 215function A(a, b, c) { 216 return String(a) + " " + String(b) + " " + String(c); 217} 218 219var rv = A(1, 2); 220` 221 testScript(SCRIPT, asciiString("1 2 undefined"), t) 222} 223 224func TestCallFewerArgsClosureNoArgs(t *testing.T) { 225 const SCRIPT = ` 226 var x; 227 function A(a, b, c) { 228 var y = a; 229 x = function() { return " " + y }; 230 return String(a) + " " + String(b) + " " + String(c); 231 } 232 233 var rv = A(1, 2) + x(); 234` 235 testScript(SCRIPT, asciiString("1 2 undefined 1"), t) 236} 237 238func TestCallFewerArgsClosureArgs(t *testing.T) { 239 const SCRIPT = ` 240 var x; 241 function A(a, b, c) { 242 var y = b; 243 x = function() { return " " + a + " " + y }; 244 return String(a) + " " + String(b) + " " + String(c); 245 } 246 247 var rv = A(1, 2) + x(); 248` 249 testScript(SCRIPT, asciiString("1 2 undefined 1 2"), t) 250} 251 252func TestCallMoreArgs(t *testing.T) { 253 const SCRIPT = ` 254function A(a, b) { 255 var c = 4; 256 return a - b + c; 257} 258 259var rv = A(1, 2, 3); 260` 261 testScript(SCRIPT, intToValue(3), t) 262} 263 264func TestCallMoreArgsDynamic(t *testing.T) { 265 const SCRIPT = ` 266function A(a, b) { 267 var c = 4; 268 if (false) { 269 eval(""); 270 } 271 return a - b + c; 272} 273 274var rv = A(1, 2, 3); 275` 276 testScript(SCRIPT, intToValue(3), t) 277} 278 279func TestCallLessArgsDynamic(t *testing.T) { 280 const SCRIPT = ` 281function A(a, b, c) { 282 // Make it stashful 283 function B() { 284 return a; 285 } 286 return String(a) + " " + String(b) + " " + String(c); 287} 288 289var rv = A(1, 2); 290` 291 testScript(SCRIPT, asciiString("1 2 undefined"), t) 292} 293 294func TestCallLessArgsDynamicLocalVar(t *testing.T) { 295 const SCRIPT = ` 296 function f(param) { 297 var a = 42; 298 if (false) { 299 eval(""); 300 } 301 return a; 302 } 303 f(); 304` 305 306 testScript1(SCRIPT, intToValue(42), t) 307} 308 309/* 310func TestFib(t *testing.T) { 311 testScript(TEST_FIB, valueInt(9227465), t) 312} 313*/ 314 315func TestNativeCall(t *testing.T) { 316 const SCRIPT = ` 317 var o = Object(1); 318 Object.defineProperty(o, "test", {value: 42}); 319 var rv = o.test; 320 ` 321 testScript(SCRIPT, intToValue(42), t) 322} 323 324func TestJSCall(t *testing.T) { 325 const SCRIPT = ` 326 function getter() { 327 return this.x; 328 } 329 var o = Object(1); 330 o.x = 42; 331 Object.defineProperty(o, "test", {get: getter}); 332 var rv = o.test; 333 ` 334 testScript(SCRIPT, intToValue(42), t) 335 336} 337 338func TestLoop1(t *testing.T) { 339 const SCRIPT = ` 340 function A() { 341 var x = 1; 342 for (var i = 0; i < 1; i++) { 343 var x = 2; 344 } 345 return x; 346 } 347 348 var rv = A(); 349 ` 350 testScript(SCRIPT, intToValue(2), t) 351} 352 353func TestLoopBreak(t *testing.T) { 354 const SCRIPT = ` 355 function A() { 356 var x = 1; 357 for (var i = 0; i < 1; i++) { 358 break; 359 var x = 2; 360 } 361 return x; 362 } 363 364 var rv = A(); 365 ` 366 testScript(SCRIPT, intToValue(1), t) 367} 368 369func TestForLoopOptionalExpr(t *testing.T) { 370 const SCRIPT = ` 371 function A() { 372 var x = 1; 373 for (;;) { 374 break; 375 var x = 2; 376 } 377 return x; 378 } 379 380 var rv = A(); 381 ` 382 testScript(SCRIPT, intToValue(1), t) 383} 384 385func TestBlockBreak(t *testing.T) { 386 const SCRIPT = ` 387 var rv = 0; 388 B1: { 389 rv = 1; 390 B2: { 391 rv = 2; 392 break B1; 393 } 394 rv = 3; 395 } 396 397 ` 398 testScript(SCRIPT, intToValue(2), t) 399 400} 401 402func TestTry(t *testing.T) { 403 const SCRIPT = ` 404 function A() { 405 var x = 1; 406 try { 407 x = 2; 408 } catch(e) { 409 x = 3; 410 } finally { 411 x = 4; 412 } 413 return x; 414 } 415 416 var rv = A(); 417 ` 418 testScript(SCRIPT, intToValue(4), t) 419} 420 421func TestTryOptionalCatchBinding(t *testing.T) { 422 const SCRIPT = ` 423 try { 424 throw null; 425 } catch { 426 } 427 ` 428 testScript1(SCRIPT, _undefined, t) 429} 430 431func TestTryCatch(t *testing.T) { 432 const SCRIPT = ` 433 function A() { 434 var x; 435 try { 436 throw 4; 437 } catch(e) { 438 x = e; 439 } 440 return x; 441 } 442 443 var rv = A(); 444 ` 445 testScript(SCRIPT, intToValue(4), t) 446} 447 448func TestTryCatchDirectEval(t *testing.T) { 449 const SCRIPT = ` 450 function A() { 451 var x; 452 try { 453 throw 4; 454 } catch(e) { 455 eval("x = e"); 456 } 457 return x; 458 } 459 460 var rv = A(); 461 ` 462 testScript(SCRIPT, intToValue(4), t) 463} 464 465func TestTryExceptionInCatch(t *testing.T) { 466 const SCRIPT = ` 467 function A() { 468 var x; 469 try { 470 throw 4; 471 } catch(e) { 472 throw 5; 473 } 474 return x; 475 } 476 477 var rv; 478 try { 479 A(); 480 } catch (e) { 481 rv = e; 482 } 483 ` 484 testScript(SCRIPT, intToValue(5), t) 485} 486 487func TestTryContinueInCatch(t *testing.T) { 488 const SCRIPT = ` 489 var c3 = 0, fin3 = 0; 490 while (c3 < 2) { 491 try { 492 throw "ex1"; 493 } catch(er1) { 494 c3 += 1; 495 continue; 496 } finally { 497 fin3 = 1; 498 } 499 fin3 = 0; 500 } 501 502 fin3; 503 ` 504 testScript1(SCRIPT, intToValue(1), t) 505} 506 507func TestContinueInWith(t *testing.T) { 508 const SCRIPT = ` 509 var x; 510 var o = {x: 0}; 511 for (var i = 0; i < 2; i++) { 512 with(o) { 513 x = i; 514 if (i === 0) { 515 continue; 516 } 517 } 518 break; 519 } 520 x; 521 ` 522 testScript1(SCRIPT, _undefined, t) 523} 524 525func TestTryContinueInFinally(t *testing.T) { 526 const SCRIPT = ` 527 var c3 = 0, fin3 = 0; 528 while (c3 < 2) { 529 try { 530 throw "ex1"; 531 } catch(er1) { 532 c3 += 1; 533 } finally { 534 fin3 = 1; 535 continue; 536 } 537 fin3 = 0; 538 } 539 540 fin3; 541 ` 542 testScript1(SCRIPT, intToValue(1), t) 543} 544 545func TestTryBreakFinallyContinue(t *testing.T) { 546 const SCRIPT = ` 547 for (var i = 0; i < 3; i++) { 548 try { 549 break; 550 } finally { 551 continue; 552 } 553 } 554 ` 555 testScript1(SCRIPT, _undefined, t) 556} 557 558func TestTryBreakFinallyContinueWithResult(t *testing.T) { 559 const SCRIPT = ` 560 for (var i = 0; i < 3; i++) { 561 try { 562 true; 563 break; 564 } finally { 565 continue; 566 } 567 } 568 ` 569 testScript1(SCRIPT, valueTrue, t) 570} 571 572func TestTryBreakFinallyContinueWithResult1(t *testing.T) { 573 const SCRIPT = ` 574 for (var i = 0; i < 3; i++) { 575 try { 576 true; 577 break; 578 } finally { 579 var x = 1; 580 continue; 581 } 582 } 583 ` 584 testScript1(SCRIPT, valueTrue, t) 585} 586 587func TestTryBreakFinallyContinueWithResultNested(t *testing.T) { 588 const SCRIPT = ` 589LOOP: 590 for (var i = 0; i < 3; i++) { 591 try { 592 if (true) { 593 false; break; 594 } 595 } finally { 596 if (true) { 597 true; continue; 598 } 599 } 600 } 601 ` 602 testScript1(SCRIPT, valueTrue, t) 603} 604 605func TestTryBreakOuterFinallyContinue(t *testing.T) { 606 const SCRIPT = ` 607 let iCount = 0, jCount = 0; 608 OUTER: for (let i = 0; i < 1; i++) { 609 iCount++; 610 for (let j = 0; j < 2; j++) { 611 jCount++; 612 try { 613 break OUTER; 614 } finally { 615 continue; 616 } 617 } 618 } 619 ""+iCount+jCount; 620 ` 621 testScript1(SCRIPT, asciiString("12"), t) 622} 623 624func TestTryIllegalContinueWithFinallyOverride(t *testing.T) { 625 const SCRIPT = ` 626 L: { 627 while (Math.random() > 0.5) { 628 try { 629 continue L; 630 } finally { 631 break; 632 } 633 } 634 } 635 ` 636 _, err := Compile("", SCRIPT, false) 637 if err == nil { 638 t.Fatal("expected error") 639 } 640} 641 642func TestTryIllegalContinueWithFinallyOverrideNoLabel(t *testing.T) { 643 const SCRIPT = ` 644 L: { 645 try { 646 continue; 647 } finally { 648 break L; 649 } 650 } 651 ` 652 _, err := Compile("", SCRIPT, false) 653 if err == nil { 654 t.Fatal("expected error") 655 } 656} 657 658func TestTryIllegalContinueWithFinallyOverrideDummy(t *testing.T) { 659 const SCRIPT = ` 660 L: { 661 while (false) { 662 try { 663 continue L; 664 } finally { 665 break; 666 } 667 } 668 } 669 ` 670 _, err := Compile("", SCRIPT, false) 671 if err == nil { 672 t.Fatal("expected error") 673 } 674} 675 676func TestTryNoResult(t *testing.T) { 677 const SCRIPT = ` 678 true; 679 L: 680 try { 681 break L; 682 } finally { 683 } 684 ` 685 testScript1(SCRIPT, _undefined, t) 686} 687 688func TestCatchLexicalEnv(t *testing.T) { 689 const SCRIPT = ` 690 function F() { 691 try { 692 throw 1; 693 } catch (e) { 694 var x = e; 695 } 696 return x; 697 } 698 699 F(); 700 ` 701 testScript1(SCRIPT, intToValue(1), t) 702} 703 704func TestThrowType(t *testing.T) { 705 const SCRIPT = ` 706 function Exception(message) { 707 this.message = message; 708 } 709 710 711 function A() { 712 try { 713 throw new Exception("boo!"); 714 } catch(e) { 715 return e; 716 } 717 } 718 var thrown = A(); 719 var rv = thrown !== null && typeof thrown === "object" && thrown.constructor === Exception; 720 ` 721 testScript(SCRIPT, valueTrue, t) 722} 723 724func TestThrowConstructorName(t *testing.T) { 725 const SCRIPT = ` 726 function Exception(message) { 727 this.message = message; 728 } 729 730 731 function A() { 732 try { 733 throw new Exception("boo!"); 734 } catch(e) { 735 return e; 736 } 737 } 738 A().constructor.name; 739 ` 740 741 testScript1(SCRIPT, asciiString("Exception"), t) 742} 743 744func TestThrowNativeConstructorName(t *testing.T) { 745 const SCRIPT = ` 746 747 748 function A() { 749 try { 750 throw new TypeError(); 751 } catch(e) { 752 return e; 753 } 754 } 755 A().constructor.name; 756 ` 757 758 testScript1(SCRIPT, asciiString("TypeError"), t) 759} 760 761func TestEmptyTryNoCatch(t *testing.T) { 762 const SCRIPT = ` 763 var called = false; 764 try { 765 } finally { 766 called = true; 767 } 768 called; 769 ` 770 771 testScript1(SCRIPT, valueTrue, t) 772} 773 774func TestTryReturnFromCatch(t *testing.T) { 775 const SCRIPT = ` 776 function f(o) { 777 var x = 42; 778 779 function innerf(o) { 780 try { 781 throw o; 782 } catch (e) { 783 return x; 784 } 785 } 786 787 return innerf(o); 788 } 789 f({}); 790 ` 791 792 testScript1(SCRIPT, valueInt(42), t) 793} 794 795func TestIfElse(t *testing.T) { 796 const SCRIPT = ` 797 var rv; 798 if (rv === undefined) { 799 rv = "passed"; 800 } else { 801 rv = "failed"; 802 } 803 ` 804 805 testScript(SCRIPT, asciiString("passed"), t) 806} 807 808func TestIfElseRetVal(t *testing.T) { 809 const SCRIPT = ` 810 var x; 811 if (x === undefined) { 812 "passed"; 813 } else { 814 "failed"; 815 } 816 ` 817 818 testScript1(SCRIPT, asciiString("passed"), t) 819} 820 821func TestWhileReturnValue(t *testing.T) { 822 const SCRIPT = ` 823 var x = 0; 824 while(true) { 825 x = 1; 826 break; 827 } 828 ` 829 testScript1(SCRIPT, intToValue(1), t) 830} 831 832func TestIfElseLabel(t *testing.T) { 833 const SCRIPT = ` 834 var x = 0; 835 abc: if (true) { 836 x = 1; 837 break abc; 838 } 839 ` 840 testScript1(SCRIPT, intToValue(1), t) 841} 842 843func TestIfMultipleLabels(t *testing.T) { 844 const SCRIPT = ` 845 var x = 0; 846 xyz:abc: if (true) { 847 break xyz; 848 } 849 ` 850 testScript1(SCRIPT, _undefined, t) 851} 852 853func TestBreakOutOfTry(t *testing.T) { 854 const SCRIPT = ` 855 function A() { 856 var x = 1; 857 B: { 858 try { 859 x = 2; 860 } catch(e) { 861 x = 3; 862 } finally { 863 break B; 864 x = 4; 865 } 866 } 867 return x; 868 } 869 870 A(); 871 ` 872 testScript1(SCRIPT, intToValue(2), t) 873} 874 875func TestReturnOutOfTryNested(t *testing.T) { 876 const SCRIPT = ` 877 function A() { 878 function nested() { 879 try { 880 return 1; 881 } catch(e) { 882 return 2; 883 } 884 } 885 return nested(); 886 } 887 888 A(); 889 ` 890 testScript1(SCRIPT, intToValue(1), t) 891} 892 893func TestContinueLoop(t *testing.T) { 894 const SCRIPT = ` 895 function A() { 896 var r = 0; 897 for (var i = 0; i < 5; i++) { 898 if (i > 1) { 899 continue; 900 } 901 r++; 902 } 903 return r; 904 } 905 906 A(); 907 ` 908 testScript1(SCRIPT, intToValue(2), t) 909} 910 911func TestContinueOutOfTry(t *testing.T) { 912 const SCRIPT = ` 913 function A() { 914 var r = 0; 915 for (var i = 0; i < 5; i++) { 916 try { 917 if (i > 1) { 918 continue; 919 } 920 } catch(e) { 921 return 99; 922 } 923 r++; 924 } 925 return r; 926 } 927 928 A(); 929 ` 930 testScript1(SCRIPT, intToValue(2), t) 931} 932 933func TestThisInCatch(t *testing.T) { 934 const SCRIPT = ` 935 function O() { 936 try { 937 f(); 938 } catch (e) { 939 this.value = e.toString(); 940 } 941 } 942 943 function f() { 944 throw "ex"; 945 } 946 947 var o = new O(); 948 o.value; 949 ` 950 testScript1(SCRIPT, asciiString("ex"), t) 951} 952 953func TestNestedTry(t *testing.T) { 954 const SCRIPT = ` 955 var ex; 956 try { 957 throw "ex1"; 958 } catch (er1) { 959 try { 960 throw "ex2"; 961 } catch (er1) { 962 ex = er1; 963 } 964 } 965 ex; 966 ` 967 testScript1(SCRIPT, asciiString("ex2"), t) 968} 969 970func TestNestedTryInStashlessFunc(t *testing.T) { 971 const SCRIPT = ` 972 function f() { 973 var ex1, ex2; 974 try { 975 throw "ex1"; 976 } catch (er1) { 977 try { 978 throw "ex2"; 979 } catch (er1) { 980 ex2 = er1; 981 } 982 ex1 = er1; 983 } 984 return ex1 == "ex1" && ex2 == "ex2"; 985 } 986 f(); 987 ` 988 testScript1(SCRIPT, valueTrue, t) 989} 990 991func TestEvalLexicalDecl(t *testing.T) { 992 const SCRIPT = ` 993 eval("let x = true; x;"); 994 ` 995 testScript1(SCRIPT, valueTrue, t) 996} 997 998func TestEvalInCatchInStashlessFunc(t *testing.T) { 999 const SCRIPT = ` 1000 function f() { 1001 var ex; 1002 try { 1003 throw "ex1"; 1004 } catch (er1) { 1005 eval("ex = er1"); 1006 } 1007 return ex; 1008 } 1009 f(); 1010 ` 1011 testScript1(SCRIPT, asciiString("ex1"), t) 1012} 1013 1014func TestCatchClosureInStashlessFunc(t *testing.T) { 1015 const SCRIPT = ` 1016 function f() { 1017 var ex; 1018 try { 1019 throw "ex1"; 1020 } catch (er1) { 1021 return function() { 1022 return er1; 1023 } 1024 } 1025 } 1026 f()(); 1027 ` 1028 testScript1(SCRIPT, asciiString("ex1"), t) 1029} 1030 1031func TestCatchVarNotUsedInStashlessFunc(t *testing.T) { 1032 const SCRIPT = ` 1033 function f() { 1034 var ex; 1035 try { 1036 throw "ex1"; 1037 } catch (er1) { 1038 ex = "ok"; 1039 } 1040 return ex; 1041 } 1042 f(); 1043 ` 1044 testScript1(SCRIPT, asciiString("ok"), t) 1045} 1046 1047func TestNew(t *testing.T) { 1048 const SCRIPT = ` 1049 function O() { 1050 this.x = 42; 1051 } 1052 1053 new O().x; 1054 ` 1055 1056 testScript1(SCRIPT, intToValue(42), t) 1057} 1058 1059func TestStringConstructor(t *testing.T) { 1060 const SCRIPT = ` 1061 function F() { 1062 return String(33) + " " + String("cows"); 1063 } 1064 1065 F(); 1066 ` 1067 testScript1(SCRIPT, asciiString("33 cows"), t) 1068} 1069 1070func TestError(t *testing.T) { 1071 const SCRIPT = ` 1072 function F() { 1073 return new Error("test"); 1074 } 1075 1076 var e = F(); 1077 var rv = e.message == "test" && e.name == "Error"; 1078 ` 1079 testScript(SCRIPT, valueTrue, t) 1080} 1081 1082func TestTypeError(t *testing.T) { 1083 const SCRIPT = ` 1084 function F() { 1085 return new TypeError("test"); 1086 } 1087 1088 var e = F(); 1089 e.message == "test" && e.name == "TypeError"; 1090 ` 1091 1092 testScript1(SCRIPT, valueTrue, t) 1093} 1094 1095func TestToString(t *testing.T) { 1096 const SCRIPT = ` 1097 var o = {x: 42}; 1098 o.toString = function() { 1099 return String(this.x); 1100 } 1101 1102 var o1 = {}; 1103 o.toString() + " ### " + o1.toString(); 1104 ` 1105 testScript1(SCRIPT, asciiString("42 ### [object Object]"), t) 1106} 1107 1108func TestEvalOrder(t *testing.T) { 1109 const SCRIPT = ` 1110 var o = {f: function() {return 42}, x: 0}; 1111 var trace = ""; 1112 1113 function F1() { 1114 trace += "First!"; 1115 return o; 1116 } 1117 1118 function F2() { 1119 trace += "Second!"; 1120 return "f"; 1121 } 1122 1123 function F3() { 1124 trace += "Third!"; 1125 } 1126 1127 var rv = F1()[F2()](F3()); 1128 rv += trace; 1129 ` 1130 1131 testScript(SCRIPT, asciiString("42First!Second!Third!"), t) 1132} 1133 1134func TestPostfixIncBracket(t *testing.T) { 1135 const SCRIPT = ` 1136 var o = {x: 42}; 1137 var trace = ""; 1138 1139 function F1() { 1140 trace += "First!"; 1141 return o; 1142 } 1143 1144 function F2() { 1145 trace += "Second!"; 1146 return "x"; 1147 } 1148 1149 1150 var rv = F1()[F2()]++; 1151 rv += trace + o.x; 1152 ` 1153 testScript(SCRIPT, asciiString("42First!Second!43"), t) 1154} 1155 1156func TestPostfixIncDot(t *testing.T) { 1157 const SCRIPT = ` 1158 var o = {x: 42}; 1159 var trace = ""; 1160 1161 function F1() { 1162 trace += "First!"; 1163 return o; 1164 } 1165 1166 var rv = F1().x++; 1167 rv += trace + o.x; 1168 ` 1169 testScript(SCRIPT, asciiString("42First!43"), t) 1170} 1171 1172func TestPrefixIncBracket(t *testing.T) { 1173 const SCRIPT = ` 1174 var o = {x: 42}; 1175 var trace = ""; 1176 1177 function F1() { 1178 trace += "First!"; 1179 return o; 1180 } 1181 1182 function F2() { 1183 trace += "Second!"; 1184 return "x"; 1185 } 1186 1187 1188 var rv = ++F1()[F2()]; 1189 rv += trace + o.x; 1190 ` 1191 testScript(SCRIPT, asciiString("43First!Second!43"), t) 1192} 1193 1194func TestPrefixIncDot(t *testing.T) { 1195 const SCRIPT = ` 1196 var o = {x: 42}; 1197 var trace = ""; 1198 1199 function F1() { 1200 trace += "First!"; 1201 return o; 1202 } 1203 1204 var rv = ++F1().x; 1205 rv += trace + o.x; 1206 ` 1207 testScript(SCRIPT, asciiString("43First!43"), t) 1208} 1209 1210func TestPostDecObj(t *testing.T) { 1211 const SCRIPT = ` 1212 var object = {valueOf: function() {return 1}}; 1213 var y = object--; 1214 var ok = false; 1215 if (y === 1) { 1216 ok = true; 1217 } 1218 ok; 1219 ` 1220 1221 testScript1(SCRIPT, valueTrue, t) 1222} 1223 1224func TestPropAcc1(t *testing.T) { 1225 const SCRIPT = ` 1226 1..toString() 1227 ` 1228 1229 testScript1(SCRIPT, asciiString("1"), t) 1230} 1231 1232func TestEvalDirect(t *testing.T) { 1233 const SCRIPT = ` 1234 var rv = false; 1235 function foo(){ rv = true; } 1236 1237 var o = { }; 1238 function f() { 1239 try { 1240 eval("o.bar( foo() );"); 1241 } catch (e) { 1242 1243 } 1244 } 1245 f(); 1246 ` 1247 testScript(SCRIPT, valueTrue, t) 1248} 1249 1250func TestEvalRet(t *testing.T) { 1251 const SCRIPT = ` 1252 eval("for (var i = 0; i < 3; i++) {i}") 1253 ` 1254 1255 testScript1(SCRIPT, valueInt(2), t) 1256} 1257 1258func TestEvalFunctionDecl(t *testing.T) { 1259 const SCRIPT = ` 1260 eval("function F() {}") 1261 ` 1262 1263 testScript1(SCRIPT, _undefined, t) 1264} 1265 1266func TestEvalFunctionExpr(t *testing.T) { 1267 const SCRIPT = ` 1268 eval("(function F() {return 42;})")() 1269 ` 1270 1271 testScript1(SCRIPT, intToValue(42), t) 1272} 1273 1274func TestEvalDirectScope(t *testing.T) { 1275 const SCRIPT = ` 1276 var __10_4_2_1_3 = "str"; 1277 function testcase() { 1278 var __10_4_2_1_3 = "str1"; 1279 try { 1280 throw "error"; 1281 } catch (e) { 1282 var __10_4_2_1_3 = "str2"; 1283 return eval("__10_4_2_1_3"); 1284 } 1285 } 1286 testcase(); 1287 ` 1288 1289 testScript1(SCRIPT, asciiString("str2"), t) 1290} 1291 1292func TestEvalDirectScope1(t *testing.T) { 1293 const SCRIPT = ` 1294 'use strict'; 1295 var __10_4_2_1_5 = "str"; 1296 function testcase() { 1297 var __10_4_2_1_5 = "str1"; 1298 var r = eval("\ 1299 var __10_4_2_1_5 = \'str2\'; \ 1300 eval(\"\'str2\' === __10_4_2_1_5\")\ 1301 "); 1302 return r; 1303 } 1304 testcase(); 1305 ` 1306 1307 testScript1(SCRIPT, valueTrue, t) 1308} 1309 1310func TestEvalDirectCreateBinding(t *testing.T) { 1311 const SCRIPT = ` 1312 function f() { 1313 eval("var x = true"); 1314 return x; 1315 } 1316 var res = f(); 1317 var thrown = false; 1318 try { 1319 x; 1320 } catch(e) { 1321 if (e instanceof ReferenceError) { 1322 thrown = true; 1323 } else { 1324 throw e; 1325 } 1326 } 1327 res && thrown; 1328 ` 1329 1330 testScript1(SCRIPT, valueTrue, t) 1331} 1332 1333func TestEvalDirectCreateBinding1(t *testing.T) { 1334 const SCRIPT = ` 1335 function f() { 1336 eval("let x = 1; var y = 2; function f1() {return x};"); 1337 assert.throws(ReferenceError, function() { x }); 1338 return ""+y+f1(); 1339 } 1340 f(); 1341 ` 1342 1343 testScript1(TESTLIB+SCRIPT, asciiString("21"), t) 1344} 1345 1346func TestEvalDirectCreateBinding3(t *testing.T) { 1347 const SCRIPT = ` 1348 function f() { 1349 let x; 1350 try { 1351 eval("var y=1, x=2"); 1352 } catch(e) {} 1353 return y; 1354 } 1355 assert.throws(ReferenceError, f); 1356 ` 1357 1358 testScript1(TESTLIB+SCRIPT, _undefined, t) 1359} 1360 1361func TestEvalGlobalStrict(t *testing.T) { 1362 const SCRIPT = ` 1363 'use strict'; 1364 var evalStr = 1365 'for (var x in this) {\n'+ 1366 ' if ( x === \'Math\' ) {\n'+ 1367 ' }\n'+ 1368 '}\n'; 1369 1370 eval(evalStr); 1371 ` 1372 1373 testScript1(SCRIPT, _undefined, t) 1374} 1375 1376func TestEvalEmptyStrict(t *testing.T) { 1377 const SCRIPT = ` 1378 'use strict'; 1379 eval(""); 1380 ` 1381 1382 testScript1(SCRIPT, _undefined, t) 1383} 1384 1385func TestEvalFuncDecl(t *testing.T) { 1386 const SCRIPT = ` 1387 'use strict'; 1388 var funcA = eval("function __funcA(__arg){return __arg;}; __funcA"); 1389 typeof funcA; 1390 ` 1391 1392 testScript1(SCRIPT, asciiString("function"), t) 1393} 1394 1395func TestGetAfterSet(t *testing.T) { 1396 const SCRIPT = ` 1397 function f() { 1398 var x = 1; 1399 return x; 1400 } 1401 ` 1402 1403 testScript1(SCRIPT, _undefined, t) 1404} 1405 1406func TestForLoopRet(t *testing.T) { 1407 const SCRIPT = ` 1408 for (var i = 0; i < 20; i++) { if (i > 2) {break;} else { i }} 1409 ` 1410 1411 testScript1(SCRIPT, _undefined, t) 1412} 1413 1414func TestForLoopRet1(t *testing.T) { 1415 const SCRIPT = ` 1416 for (var i = 0; i < 20; i++) { if (i > 2) {42;; {L:{break;}}} else { i }} 1417 ` 1418 1419 testScript1(SCRIPT, intToValue(42), t) 1420} 1421 1422func TestForInLoopRet(t *testing.T) { 1423 const SCRIPT = ` 1424 var o = [1, 2, 3, 4]; 1425 for (var i in o) { if (i > 2) {break;} else { i }} 1426 ` 1427 1428 testScript1(SCRIPT, _undefined, t) 1429} 1430 1431func TestForInLoopRet1(t *testing.T) { 1432 const SCRIPT = ` 1433 var o = {}; 1434 o.x = 1; 1435 o.y = 2; 1436 for (var i in o) { 1437 true; 1438 } 1439 1440 ` 1441 1442 testScript1(SCRIPT, valueTrue, t) 1443} 1444 1445func TestDoWhileLoopRet(t *testing.T) { 1446 const SCRIPT = ` 1447 var i = 0; 1448 do { 1449 if (i > 2) { 1450 break; 1451 } else { 1452 i; 1453 } 1454 } while (i++ < 20); 1455 ` 1456 1457 testScript1(SCRIPT, _undefined, t) 1458} 1459 1460func TestDoWhileContinueRet(t *testing.T) { 1461 const SCRIPT = ` 1462 var i = 0; 1463 do { 1464 if (i > 2) { 1465 true; 1466 continue; 1467 } else { 1468 i; 1469 } 1470 } while (i++ < 20); 1471 ` 1472 1473 testScript1(SCRIPT, valueTrue, t) 1474} 1475 1476func TestWhileLoopRet(t *testing.T) { 1477 const SCRIPT = ` 1478 var i; while (i < 20) { if (i > 2) {break;} else { i++ }} 1479 ` 1480 1481 testScript1(SCRIPT, _undefined, t) 1482} 1483 1484func TestLoopRet1(t *testing.T) { 1485 const SCRIPT = ` 1486 for (var i = 0; i < 20; i++) { } 1487 ` 1488 1489 testScript1(SCRIPT, _undefined, t) 1490} 1491 1492func TestInstanceof(t *testing.T) { 1493 const SCRIPT = ` 1494 var rv; 1495 try { 1496 true(); 1497 } catch (e) { 1498 rv = e instanceof TypeError; 1499 } 1500 ` 1501 1502 testScript(SCRIPT, valueTrue, t) 1503} 1504 1505func TestStrictAssign(t *testing.T) { 1506 const SCRIPT = ` 1507 'use strict'; 1508 var rv; 1509 var called = false; 1510 function F() { 1511 called = true; 1512 return 1; 1513 } 1514 try { 1515 x = F(); 1516 } catch (e) { 1517 rv = e instanceof ReferenceError; 1518 } 1519 rv += " " + called; 1520 ` 1521 1522 testScript(SCRIPT, asciiString("true true"), t) 1523} 1524 1525func TestStrictScope(t *testing.T) { 1526 const SCRIPT = ` 1527 var rv; 1528 var called = false; 1529 function F() { 1530 'use strict'; 1531 x = 1; 1532 } 1533 try { 1534 F(); 1535 } catch (e) { 1536 rv = e instanceof ReferenceError; 1537 } 1538 x = 1; 1539 rv += " " + x; 1540 ` 1541 1542 testScript(SCRIPT, asciiString("true 1"), t) 1543} 1544 1545func TestStringObj(t *testing.T) { 1546 const SCRIPT = ` 1547 var s = new String("test"); 1548 s[0] + s[2] + s[1]; 1549 ` 1550 1551 testScript1(SCRIPT, asciiString("tse"), t) 1552} 1553 1554func TestStringPrimitive(t *testing.T) { 1555 const SCRIPT = ` 1556 var s = "test"; 1557 s[0] + s[2] + s[1]; 1558 ` 1559 1560 testScript1(SCRIPT, asciiString("tse"), t) 1561} 1562 1563func TestCallGlobalObject(t *testing.T) { 1564 const SCRIPT = ` 1565 var rv; 1566 try { 1567 this(); 1568 } catch (e) { 1569 rv = e instanceof TypeError 1570 } 1571 ` 1572 1573 testScript(SCRIPT, valueTrue, t) 1574} 1575 1576func TestFuncLength(t *testing.T) { 1577 const SCRIPT = ` 1578 function F(x, y) { 1579 1580 } 1581 F.length 1582 ` 1583 1584 testScript1(SCRIPT, intToValue(2), t) 1585} 1586 1587func TestNativeFuncLength(t *testing.T) { 1588 const SCRIPT = ` 1589 eval.length + Object.defineProperty.length + String.length 1590 ` 1591 1592 testScript1(SCRIPT, intToValue(5), t) 1593} 1594 1595func TestArguments(t *testing.T) { 1596 const SCRIPT = ` 1597 function F() { 1598 return arguments.length + " " + arguments[1]; 1599 } 1600 1601 F(1,2,3) 1602 ` 1603 1604 testScript1(SCRIPT, asciiString("3 2"), t) 1605} 1606 1607func TestArgumentsPut(t *testing.T) { 1608 const SCRIPT = ` 1609 function F(x, y) { 1610 arguments[0] -= arguments[1]; 1611 return x; 1612 } 1613 1614 F(5, 2) 1615 ` 1616 1617 testScript1(SCRIPT, intToValue(3), t) 1618} 1619 1620func TestArgumentsPutStrict(t *testing.T) { 1621 const SCRIPT = ` 1622 function F(x, y) { 1623 'use strict'; 1624 arguments[0] -= arguments[1]; 1625 return x; 1626 } 1627 1628 F(5, 2) 1629 ` 1630 1631 testScript1(SCRIPT, intToValue(5), t) 1632} 1633 1634func TestArgumentsExtra(t *testing.T) { 1635 const SCRIPT = ` 1636 function F(x, y) { 1637 return arguments[2]; 1638 } 1639 1640 F(1, 2, 42) 1641 ` 1642 1643 testScript1(SCRIPT, intToValue(42), t) 1644} 1645 1646func TestArgumentsExist(t *testing.T) { 1647 const SCRIPT = ` 1648 function F(x, arguments) { 1649 return arguments; 1650 } 1651 1652 F(1, 42) 1653 ` 1654 1655 testScript1(SCRIPT, intToValue(42), t) 1656} 1657 1658func TestArgumentsDelete(t *testing.T) { 1659 const SCRIPT = ` 1660 function f(x) { 1661 delete arguments[0]; 1662 arguments[0] = 42; 1663 return x; 1664 } 1665 f(1) 1666 ` 1667 1668 testScript1(SCRIPT, intToValue(1), t) 1669} 1670 1671func TestArgumentsInEval(t *testing.T) { 1672 const SCRIPT = ` 1673 function f() { 1674 return eval("arguments"); 1675 } 1676 f(1)[0]; 1677 ` 1678 1679 testScript1(SCRIPT, intToValue(1), t) 1680} 1681 1682func TestArgumentsRedeclareInEval(t *testing.T) { 1683 const SCRIPT = ` 1684 assert.sameValue("arguments" in this, false, "No global 'arguments' binding"); 1685 1686 function f(p = eval("var arguments = 'param'"), arguments) {} 1687 assert.throws(SyntaxError, f); 1688 1689 assert.sameValue("arguments" in this, false, "No global 'arguments' binding"); 1690 ` 1691 1692 testScript1(TESTLIB+SCRIPT, _undefined, t) 1693} 1694 1695func TestArgumentsRedeclareArrow(t *testing.T) { 1696 const SCRIPT = ` 1697 const oldArguments = globalThis.arguments; 1698 let count = 0; 1699 const f = (p = eval("var arguments = 'param'"), q = () => arguments) => { 1700 var arguments = "local"; 1701 assert.sameValue(arguments, "local", "arguments"); 1702 assert.sameValue(q(), "param", "q"); 1703 count++; 1704 } 1705 f(); 1706 assert.sameValue(count, 1); 1707 assert.sameValue(globalThis.arguments, oldArguments, "globalThis.arguments unchanged"); 1708 ` 1709 testScript1(TESTLIB+SCRIPT, _undefined, t) 1710} 1711 1712func TestEvalParamWithDef(t *testing.T) { 1713 const SCRIPT = ` 1714 function f(param = 0) { 1715 eval("var param = 1"); 1716 return param; 1717 } 1718 f(); 1719 ` 1720 1721 testScript1(SCRIPT, valueInt(1), t) 1722} 1723 1724func TestArgumentsRedefinedAsLetDyn(t *testing.T) { 1725 const SCRIPT = ` 1726 function f() { 1727 let arguments; 1728 eval(""); // force dynamic scope 1729 return arguments; 1730 } 1731 1732 f(1,2); 1733 ` 1734 1735 testScript1(SCRIPT, _undefined, t) 1736} 1737 1738func TestWith(t *testing.T) { 1739 const SCRIPT = ` 1740 var b = 1; 1741 var o = {a: 41}; 1742 with(o) { 1743 a += b; 1744 } 1745 o.a; 1746 1747 ` 1748 1749 testScript1(SCRIPT, intToValue(42), t) 1750} 1751 1752func TestWithInFunc(t *testing.T) { 1753 const SCRIPT = ` 1754 function F() { 1755 var b = 1; 1756 var c = 0; 1757 var o = {a: 40, c: 1}; 1758 with(o) { 1759 a += b + c; 1760 } 1761 return o.a; 1762 } 1763 1764 F(); 1765 ` 1766 1767 testScript1(SCRIPT, intToValue(42), t) 1768} 1769 1770func TestAssignNonExtendable(t *testing.T) { 1771 const SCRIPT = ` 1772 'use strict'; 1773 1774 function F() { 1775 this.x = 1; 1776 } 1777 1778 var o = new F(); 1779 Object.preventExtensions(o); 1780 o.x = 42; 1781 o.x; 1782 ` 1783 1784 testScript1(SCRIPT, intToValue(42), t) 1785} 1786 1787func TestAssignNonExtendable1(t *testing.T) { 1788 const SCRIPT = ` 1789 'use strict'; 1790 1791 function F() { 1792 } 1793 1794 var o = new F(); 1795 var rv; 1796 1797 Object.preventExtensions(o); 1798 try { 1799 o.x = 42; 1800 } catch (e) { 1801 rv = e.constructor === TypeError; 1802 } 1803 1804 rv += " " + o.x; 1805 1806 ` 1807 1808 testScript(SCRIPT, asciiString("true undefined"), t) 1809} 1810 1811func TestAssignStrict(t *testing.T) { 1812 const SCRIPT = ` 1813 'use strict'; 1814 1815 try { 1816 eval("eval = 42"); 1817 } catch(e) { 1818 var rv = e instanceof SyntaxError 1819 } 1820 ` 1821 1822 testScript(SCRIPT, valueTrue, t) 1823} 1824 1825func TestIllegalArgmentName(t *testing.T) { 1826 const SCRIPT = ` 1827 'use strict'; 1828 1829 try { 1830 eval("function F(eval) {}"); 1831 } catch (e) { 1832 var rv = e instanceof SyntaxError 1833 } 1834 1835 ` 1836 1837 testScript(SCRIPT, valueTrue, t) 1838} 1839 1840func TestFunction(t *testing.T) { 1841 const SCRIPT = ` 1842 1843 var f0 = Function(""); 1844 var f1 = Function("return ' one'"); 1845 var f2 = Function("arg", "return ' ' + arg"); 1846 f0() + f1() + f2("two"); 1847 ` 1848 1849 testScript1(SCRIPT, asciiString("undefined one two"), t) 1850} 1851 1852func TestFunction1(t *testing.T) { 1853 const SCRIPT = ` 1854 1855 var f = function f1(count) { 1856 if (count == 0) { 1857 return true; 1858 } 1859 return f1(count-1); 1860 } 1861 1862 f(1); 1863 ` 1864 1865 testScript1(SCRIPT, valueTrue, t) 1866} 1867 1868func TestFunction2(t *testing.T) { 1869 const SCRIPT = ` 1870 var trace = ""; 1871 function f(count) { 1872 trace += "f("+count+")"; 1873 if (count == 0) { 1874 return; 1875 } 1876 return f(count-1); 1877 } 1878 1879 function f1() { 1880 trace += "f1"; 1881 } 1882 1883 var f2 = f; 1884 f = f1; 1885 f2(1); 1886 trace; 1887 1888 ` 1889 1890 testScript1(SCRIPT, asciiString("f(1)f1"), t) 1891} 1892 1893func TestFunctionToString(t *testing.T) { 1894 const SCRIPT = ` 1895 1896 Function("arg1", "arg2", "return 42").toString(); 1897 ` 1898 1899 testScript1(SCRIPT, asciiString("function anonymous(arg1,arg2){return 42}"), t) 1900} 1901 1902func TestObjectLiteral(t *testing.T) { 1903 const SCRIPT = ` 1904 var getterCalled = false; 1905 var setterCalled = false; 1906 1907 var o = {get x() {getterCalled = true}, set x() {setterCalled = true}}; 1908 1909 o.x; 1910 o.x = 42; 1911 1912 getterCalled && setterCalled; 1913 ` 1914 1915 testScript1(SCRIPT, valueTrue, t) 1916} 1917 1918func TestConst(t *testing.T) { 1919 const SCRIPT = ` 1920 1921 var v1 = true && true; 1922 var v2 = 1/(-1 * 0); 1923 var v3 = 1 == 2 || v1; 1924 var v4 = true && false 1925 v1 === true && v2 === -Infinity && v3 === v1 && v4 === false; 1926 ` 1927 1928 testScript1(SCRIPT, valueTrue, t) 1929} 1930 1931func TestConstWhile(t *testing.T) { 1932 const SCRIPT = ` 1933 var c = 0; 1934 while (2 + 2 === 4) { 1935 if (++c > 9) { 1936 break; 1937 } 1938 } 1939 c === 10; 1940 ` 1941 1942 testScript1(SCRIPT, valueTrue, t) 1943} 1944 1945func TestConstWhileThrow(t *testing.T) { 1946 const SCRIPT = ` 1947 var thrown = false; 1948 try { 1949 while ('s' in true) { 1950 break; 1951 } 1952 } catch (e) { 1953 thrown = e instanceof TypeError 1954 } 1955 thrown; 1956 ` 1957 1958 testScript1(SCRIPT, valueTrue, t) 1959} 1960 1961func TestDupParams(t *testing.T) { 1962 const SCRIPT = ` 1963 function F(x, y, x) { 1964 return x; 1965 } 1966 1967 F(1, 2); 1968 ` 1969 1970 testScript1(SCRIPT, _undefined, t) 1971} 1972 1973func TestUseUnsuppliedParam(t *testing.T) { 1974 const SCRIPT = ` 1975 function getMessage(message) { 1976 if (message === undefined) { 1977 message = ''; 1978 } 1979 message += " 123 456"; 1980 return message; 1981 } 1982 1983 getMessage(); 1984 ` 1985 1986 testScript1(SCRIPT, asciiString(" 123 456"), t) 1987} 1988 1989func TestForInLetWithInitializer(t *testing.T) { 1990 const SCRIPT = `for (let x = 3 in {}) { }` 1991 _, err := Compile("", SCRIPT, false) 1992 if err == nil { 1993 t.Fatal("Expected error") 1994 } 1995} 1996 1997func TestForInLoop(t *testing.T) { 1998 const SCRIPT = ` 1999 function Proto() {} 2000 Proto.prototype.x = 42; 2001 var o = new Proto(); 2002 o.y = 44; 2003 o.x = 45; 2004 var hasX = false; 2005 var hasY = false; 2006 2007 for (var i in o) { 2008 switch(i) { 2009 case "x": 2010 if (hasX) { 2011 throw new Error("Already has X"); 2012 } 2013 hasX = true; 2014 break; 2015 case "y": 2016 if (hasY) { 2017 throw new Error("Already has Y"); 2018 } 2019 hasY = true; 2020 break; 2021 } 2022 } 2023 2024 hasX && hasY; 2025 ` 2026 2027 testScript1(SCRIPT, valueTrue, t) 2028} 2029 2030func TestWhileLoopResult(t *testing.T) { 2031 const SCRIPT = ` 2032 while(false); 2033 2034 ` 2035 2036 testScript1(SCRIPT, _undefined, t) 2037} 2038 2039func TestEmptySwitch(t *testing.T) { 2040 const SCRIPT = ` 2041 switch(1){} 2042 ` 2043 2044 testScript1(SCRIPT, _undefined, t) 2045} 2046 2047func TestEmptyDoWhile(t *testing.T) { 2048 const SCRIPT = ` 2049 do {} while(false) 2050 ` 2051 2052 testScript1(SCRIPT, _undefined, t) 2053} 2054 2055func TestSwitch(t *testing.T) { 2056 const SCRIPT = ` 2057 function F(x) { 2058 var i = 0; 2059 switch (x) { 2060 case 0: 2061 i++; 2062 case 1: 2063 i++; 2064 default: 2065 i++; 2066 case 2: 2067 i++; 2068 break; 2069 case 3: 2070 i++; 2071 } 2072 return i; 2073 } 2074 2075 F(0) + F(1) + F(2) + F(4); 2076 2077 ` 2078 2079 testScript1(SCRIPT, intToValue(10), t) 2080} 2081 2082func TestSwitchDefFirst(t *testing.T) { 2083 const SCRIPT = ` 2084 function F(x) { 2085 var i = 0; 2086 switch (x) { 2087 default: 2088 i++; 2089 case 0: 2090 i++; 2091 case 1: 2092 i++; 2093 case 2: 2094 i++; 2095 break; 2096 case 3: 2097 i++; 2098 } 2099 return i; 2100 } 2101 2102 F(0) + F(1) + F(2) + F(4); 2103 2104 ` 2105 2106 testScript1(SCRIPT, intToValue(10), t) 2107} 2108 2109func TestSwitchResult(t *testing.T) { 2110 const SCRIPT = ` 2111 var x = 2; 2112 2113 switch (x) { 2114 case 0: 2115 "zero"; 2116 case 1: 2117 "one"; 2118 case 2: 2119 "two"; 2120 break; 2121 case 3: 2122 "three"; 2123 default: 2124 "default"; 2125 } 2126 ` 2127 2128 testScript1(SCRIPT, asciiString("two"), t) 2129} 2130 2131func TestSwitchResult1(t *testing.T) { 2132 const SCRIPT = ` 2133 var x = 0; 2134 switch (x) { case 0: "two"; case 1: break} 2135 ` 2136 2137 testScript1(SCRIPT, asciiString("two"), t) 2138} 2139 2140func TestSwitchResult2(t *testing.T) { 2141 const SCRIPT = ` 2142 6; switch ("a") { case "a": 7; case "b": } 2143 ` 2144 2145 testScript1(SCRIPT, valueInt(7), t) 2146} 2147 2148func TestSwitchResultJumpIntoEmptyEval(t *testing.T) { 2149 const SCRIPT = ` 2150 function t(x) { 2151 return eval("switch(x) { case 1: 2; break; case 2: let x = 1; case 3: x+2; break; case 4: default: 9}"); 2152 } 2153 ""+t(2)+t(); 2154 ` 2155 2156 testScript1(SCRIPT, asciiString("39"), t) 2157} 2158 2159func TestSwitchResultJumpIntoEmpty(t *testing.T) { 2160 const SCRIPT = ` 2161 switch(2) { case 1: 2; break; case 2: let x = 1; case 3: x+2; case 4: {let y = 2}; break; default: 9}; 2162 ` 2163 2164 testScript1(SCRIPT, valueInt(3), t) 2165} 2166 2167func TestSwitchLexical(t *testing.T) { 2168 const SCRIPT = ` 2169 switch (true) { case true: let x = 1; } 2170 ` 2171 2172 testScript1(SCRIPT, _undefined, t) 2173} 2174 2175func TestSwitchBreakOuter(t *testing.T) { 2176 const SCRIPT = ` 2177 LOOP: 2178 for (let i = 0; i < 10; i++) { 2179 switch (i) { 2180 case 0: 2181 continue; 2182 case 1: 2183 let x = 1; 2184 continue; 2185 case 2: 2186 try { 2187 x++; 2188 } catch (e) { 2189 if (e instanceof ReferenceError) { 2190 break LOOP; 2191 } 2192 } 2193 throw new Error("Exception was not thrown"); 2194 } 2195 } 2196 ` 2197 2198 testScript1(SCRIPT, _undefined, t) 2199} 2200 2201func TestIfBreakResult(t *testing.T) { 2202 const SCRIPT = ` 2203 L: {if (true) {42;} break L;} 2204 ` 2205 2206 testScript1(SCRIPT, intToValue(42), t) 2207} 2208 2209func TestSwitchNoMatch(t *testing.T) { 2210 const SCRIPT = ` 2211 var result; 2212 var x; 2213 switch (x) { 2214 case 0: 2215 result = "2"; 2216 break; 2217 } 2218 2219 result; 2220 2221 ` 2222 2223 testScript1(SCRIPT, _undefined, t) 2224} 2225 2226func TestSwitchNoMatchNoDefault(t *testing.T) { 2227 const SCRIPT = ` 2228 switch (1) { 2229 case 0: 2230 } 2231 ` 2232 2233 testScript1(SCRIPT, _undefined, t) 2234} 2235 2236func TestSwitchNoMatchNoDefaultNoResult(t *testing.T) { 2237 const SCRIPT = ` 2238 switch (1) { 2239 case 0: 2240 } 2241 42; 2242 ` 2243 2244 testScript1(SCRIPT, intToValue(42), t) 2245} 2246 2247func TestSwitchNoMatchNoDefaultNoResultMatch(t *testing.T) { 2248 const SCRIPT = ` 2249 switch (1) { 2250 case 1: 2251 } 2252 42; 2253 ` 2254 2255 testScript1(SCRIPT, intToValue(42), t) 2256} 2257 2258func TestEmptySwitchNoResult(t *testing.T) { 2259 const SCRIPT = ` 2260 switch (1) {} 2261 42; 2262 ` 2263 2264 testScript1(SCRIPT, intToValue(42), t) 2265} 2266 2267func TestGetOwnPropertyNames(t *testing.T) { 2268 const SCRIPT = ` 2269 var o = { 2270 prop1: 42, 2271 prop2: "test" 2272 } 2273 2274 var hasProp1 = false; 2275 var hasProp2 = false; 2276 2277 var names = Object.getOwnPropertyNames(o); 2278 for (var i in names) { 2279 var p = names[i]; 2280 switch(p) { 2281 case "prop1": 2282 hasProp1 = true; 2283 break; 2284 case "prop2": 2285 hasProp2 = true; 2286 break; 2287 } 2288 } 2289 2290 hasProp1 && hasProp2; 2291 ` 2292 2293 testScript1(SCRIPT, valueTrue, t) 2294} 2295 2296func TestArrayLiteral(t *testing.T) { 2297 const SCRIPT = ` 2298 2299 var f1Called = false; 2300 var f2Called = false; 2301 var f3Called = false; 2302 var errorThrown = false; 2303 2304 function F1() { 2305 f1Called = true; 2306 } 2307 2308 function F2() { 2309 f2Called = true; 2310 } 2311 2312 function F3() { 2313 f3Called = true; 2314 } 2315 2316 2317 try { 2318 var a = [F1(), x(F3()), F2()]; 2319 } catch(e) { 2320 if (e instanceof ReferenceError) { 2321 errorThrown = true; 2322 } else { 2323 throw e; 2324 } 2325 } 2326 2327 f1Called && !f2Called && f3Called && errorThrown && a === undefined; 2328 ` 2329 2330 testScript1(SCRIPT, valueTrue, t) 2331} 2332 2333func TestJumpOutOfReturn(t *testing.T) { 2334 const SCRIPT = ` 2335 function f() { 2336 var a; 2337 if (a == 0) { 2338 return true; 2339 } 2340 } 2341 2342 f(); 2343 ` 2344 2345 testScript1(SCRIPT, _undefined, t) 2346} 2347 2348func TestSwitchJumpOutOfReturn(t *testing.T) { 2349 const SCRIPT = ` 2350 function f(x) { 2351 switch(x) { 2352 case 0: 2353 break; 2354 default: 2355 return x; 2356 } 2357 } 2358 2359 f(0); 2360 ` 2361 2362 testScript1(SCRIPT, _undefined, t) 2363} 2364 2365func TestSetToReadOnlyPropertyStrictBracket(t *testing.T) { 2366 const SCRIPT = ` 2367 'use strict'; 2368 2369 var o = {}; 2370 var thrown = false; 2371 Object.defineProperty(o, "test", {value: 42, configurable: true}); 2372 try { 2373 o["test"] = 43; 2374 } catch (e) { 2375 thrown = e instanceof TypeError; 2376 } 2377 2378 thrown; 2379 ` 2380 2381 testScript1(SCRIPT, valueTrue, t) 2382} 2383 2384func TestSetToReadOnlyPropertyStrictDot(t *testing.T) { 2385 const SCRIPT = ` 2386 'use strict'; 2387 2388 var o = {}; 2389 var thrown = false; 2390 Object.defineProperty(o, "test", {value: 42, configurable: true}); 2391 try { 2392 o.test = 43; 2393 } catch (e) { 2394 thrown = e instanceof TypeError; 2395 } 2396 2397 thrown; 2398 ` 2399 2400 testScript1(SCRIPT, valueTrue, t) 2401} 2402 2403func TestDeleteNonConfigurablePropertyStrictBracket(t *testing.T) { 2404 const SCRIPT = ` 2405 'use strict'; 2406 2407 var o = {}; 2408 var thrown = false; 2409 Object.defineProperty(o, "test", {value: 42}); 2410 try { 2411 delete o["test"]; 2412 } catch (e) { 2413 thrown = e instanceof TypeError; 2414 } 2415 2416 thrown; 2417 ` 2418 2419 testScript1(SCRIPT, valueTrue, t) 2420} 2421 2422func TestDeleteNonConfigurablePropertyStrictDot(t *testing.T) { 2423 const SCRIPT = ` 2424 'use strict'; 2425 2426 var o = {}; 2427 var thrown = false; 2428 Object.defineProperty(o, "test", {value: 42}); 2429 try { 2430 delete o.test; 2431 } catch (e) { 2432 thrown = e instanceof TypeError; 2433 } 2434 2435 thrown; 2436 ` 2437 2438 testScript1(SCRIPT, valueTrue, t) 2439} 2440 2441func TestCompound1(t *testing.T) { 2442 const SCRIPT = ` 2443 var x = 0; 2444 var scope = {x: 1}; 2445 var f; 2446 with (scope) { 2447 f = function() { 2448 x *= (delete scope.x, 2); 2449 } 2450 } 2451 f(); 2452 2453 scope.x === 2 && x === 0; 2454 2455 ` 2456 2457 testScript1(SCRIPT, valueTrue, t) 2458} 2459 2460func TestCompound2(t *testing.T) { 2461 const SCRIPT = ` 2462 2463var x; 2464x = "x"; 2465x ^= "1"; 2466 2467 ` 2468 testScript1(SCRIPT, intToValue(1), t) 2469} 2470 2471func TestDeleteArguments(t *testing.T) { 2472 defer func() { 2473 if _, ok := recover().(*CompilerSyntaxError); !ok { 2474 t.Fatal("Expected syntax error") 2475 } 2476 }() 2477 const SCRIPT = ` 2478 'use strict'; 2479 2480 function f() { 2481 delete arguments; 2482 } 2483 2484 ` 2485 testScript1(SCRIPT, _undefined, t) 2486} 2487 2488func TestReturnUndefined(t *testing.T) { 2489 const SCRIPT = ` 2490 function f() { 2491 return x; 2492 } 2493 2494 var thrown = false; 2495 try { 2496 f(); 2497 } catch (e) { 2498 thrown = e instanceof ReferenceError; 2499 } 2500 2501 thrown; 2502 ` 2503 testScript1(SCRIPT, valueTrue, t) 2504} 2505 2506func TestForBreak(t *testing.T) { 2507 const SCRIPT = ` 2508 var supreme, count; 2509 supreme = 5; 2510 var __evaluated = eval("for(count=0;;) {if (count===supreme)break;else count++; }"); 2511 if (__evaluated !== void 0) { 2512 throw new Error('#1: __evaluated === 4. Actual: __evaluated ==='+ __evaluated ); 2513 } 2514 2515 ` 2516 testScript1(SCRIPT, _undefined, t) 2517} 2518 2519func TestLargeNumberLiteral(t *testing.T) { 2520 const SCRIPT = ` 2521 var x = 0x800000000000000000000; 2522 x.toString(); 2523 ` 2524 testScript1(SCRIPT, asciiString("9.671406556917033e+24"), t) 2525} 2526 2527func TestIncDelete(t *testing.T) { 2528 const SCRIPT = ` 2529 var o = {x: 1}; 2530 o.x += (delete o.x, 1); 2531 o.x; 2532 ` 2533 testScript1(SCRIPT, intToValue(2), t) 2534} 2535 2536func TestCompoundAssignRefError(t *testing.T) { 2537 const SCRIPT = ` 2538 var thrown = false; 2539 try { 2540 a *= 1; 2541 } catch (e) { 2542 if (e instanceof ReferenceError) { 2543 thrown = true; 2544 } else { 2545 throw e; 2546 } 2547 } 2548 thrown; 2549 ` 2550 testScript1(SCRIPT, valueTrue, t) 2551} 2552 2553func TestObjectLiteral__Proto__(t *testing.T) { 2554 const SCRIPT = ` 2555 var o = { 2556 __proto__: null, 2557 test: 42 2558 } 2559 2560 Object.getPrototypeOf(o); 2561 ` 2562 2563 testScript1(SCRIPT, _null, t) 2564} 2565 2566func TestEmptyCodeError(t *testing.T) { 2567 if _, err := New().RunString(`i`); err == nil { 2568 t.Fatal("Expected an error") 2569 } else { 2570 if e := err.Error(); e != "ReferenceError: i is not defined at <eval>:1:1(0)" { 2571 t.Fatalf("Unexpected error: '%s'", e) 2572 } 2573 } 2574} 2575 2576func TestForOfArray(t *testing.T) { 2577 const SCRIPT = ` 2578 var array = [0, 'a', true, false, null, /* hole */, undefined, NaN]; 2579 var i = 0; 2580 2581 for (var value of array) { 2582 assert.sameValue(value, array[i], 'element at index ' + i); 2583 i++; 2584 } 2585 2586 assert.sameValue(i, 8, 'Visits all elements'); 2587 ` 2588 testScript1(TESTLIB+SCRIPT, _undefined, t) 2589} 2590 2591func TestForOfReturn(t *testing.T) { 2592 const SCRIPT = ` 2593 var callCount = 0; 2594 var iterationCount = 0; 2595 var iterable = {}; 2596 var x = { 2597 set attr(_) { 2598 throw new Test262Error(); 2599 } 2600 }; 2601 2602 iterable[Symbol.iterator] = function() { 2603 return { 2604 next: function() { 2605 return { done: false, value: 0 }; 2606 }, 2607 return: function() { 2608 callCount += 1; 2609 } 2610 } 2611 }; 2612 2613 assert.throws(Test262Error, function() { 2614 for (x.attr of iterable) { 2615 iterationCount += 1; 2616 } 2617 }); 2618 2619 assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); 2620 assert.sameValue(callCount, 1, 'Iterator is closed'); 2621 ` 2622 testScript1(TESTLIB+SCRIPT, _undefined, t) 2623} 2624 2625func TestForOfReturn1(t *testing.T) { 2626 const SCRIPT = ` 2627 var iterable = {}; 2628 var iterationCount = 0; 2629 2630 iterable[Symbol.iterator] = function() { 2631 return { 2632 next: function() { 2633 return { done: false, value: null }; 2634 }, 2635 get return() { 2636 throw new Test262Error(); 2637 } 2638 }; 2639 }; 2640 2641 assert.throws(Test262Error, function() { 2642 for (var x of iterable) { 2643 iterationCount += 1; 2644 break; 2645 } 2646 }); 2647 2648 assert.sameValue(iterationCount, 1, 'The loop body is evaluated'); 2649 ` 2650 testScript1(TESTLIB+SCRIPT, _undefined, t) 2651} 2652 2653func TestForOfLet(t *testing.T) { 2654 const SCRIPT = ` 2655 var iterCount = 0; 2656 function f() {} 2657 for (var let of [23]) { 2658 f(let); 2659 if (let != 23) { 2660 throw new Error(""); 2661 } 2662 iterCount += 1; 2663 } 2664 2665 iterCount; 2666` 2667 testScript1(SCRIPT, valueInt(1), t) 2668} 2669 2670func TestForOfLetLet(t *testing.T) { 2671 const SCRIPT = ` 2672 for (let let of [23]) { 2673 } 2674` 2675 _, err := Compile("", SCRIPT, false) 2676 if err == nil { 2677 t.Fatal("Expected error") 2678 } 2679} 2680 2681func TestForHeadLet(t *testing.T) { 2682 const SCRIPT = ` 2683 for (let = 0; let < 2; let++); 2684` 2685 testScript1(SCRIPT, _undefined, t) 2686} 2687 2688func TestLhsLet(t *testing.T) { 2689 const SCRIPT = ` 2690 let = 1; 2691 let; 2692 ` 2693 testScript1(SCRIPT, valueInt(1), t) 2694} 2695 2696func TestLetPostfixASI(t *testing.T) { 2697 const SCRIPT = ` 2698 let 2699 ++ 2700 ` 2701 _, err := Compile("", SCRIPT, false) 2702 if err == nil { 2703 t.Fatal("Expected error") 2704 } 2705} 2706 2707func TestIteratorReturnNormal(t *testing.T) { 2708 const SCRIPT = ` 2709 var iterable = {}; 2710 var iterationCount = 0; 2711 2712 iterable[Symbol.iterator] = function() { 2713 return { 2714 next: function() { 2715 return { done: ++iterationCount > 2, value: null }; 2716 }, 2717 get return() { 2718 throw new Test262Error(); 2719 } 2720 }; 2721 }; 2722 2723 for (var x of iterable) { 2724 } 2725 ` 2726 testScript1(TESTLIB+SCRIPT, _undefined, t) 2727} 2728 2729func TestIteratorReturnErrorNested(t *testing.T) { 2730 const SCRIPT = ` 2731 var returnCalled = {}; 2732 function iter(id) { 2733 return function() { 2734 var count = 0; 2735 return { 2736 next: function () { 2737 return { 2738 value: null, 2739 done: ++count > 2 2740 }; 2741 }, 2742 return: function () { 2743 returnCalled[id] = true; 2744 throw new Error(id); 2745 } 2746 }; 2747 } 2748 } 2749 var iterable1 = {}; 2750 iterable1[Symbol.iterator] = iter("1"); 2751 var iterable2 = {}; 2752 iterable2[Symbol.iterator] = iter("2"); 2753 2754 try { 2755 for (var i of iterable1) { 2756 for (var j of iterable2) { 2757 break; 2758 } 2759 } 2760 throw new Error("no exception was thrown"); 2761 } catch (e) { 2762 if (e.message !== "2") { 2763 throw e; 2764 } 2765 } 2766 if (!returnCalled["1"]) { 2767 throw new Error("no return 1"); 2768 } 2769 if (!returnCalled["2"]) { 2770 throw new Error("no return 2"); 2771 } 2772 ` 2773 testScript1(SCRIPT, _undefined, t) 2774} 2775 2776func TestReturnFromForInLoop(t *testing.T) { 2777 const SCRIPT = ` 2778 (function f() { 2779 for (var i in {a: 1}) { 2780 return true; 2781 } 2782 })(); 2783 ` 2784 testScript1(SCRIPT, valueTrue, t) 2785} 2786 2787func TestReturnFromForOfLoop(t *testing.T) { 2788 const SCRIPT = ` 2789 (function f() { 2790 for (var i of [1]) { 2791 return true; 2792 } 2793 })(); 2794 ` 2795 testScript1(SCRIPT, valueTrue, t) 2796} 2797 2798func TestIfStackLeaks(t *testing.T) { 2799 const SCRIPT = ` 2800 var t = 0; 2801 if (t === 0) { 2802 t; 2803 } 2804 ` 2805 testScript1(SCRIPT, _positiveZero, t) 2806} 2807 2808func TestWithCallee(t *testing.T) { 2809 const SCRIPT = ` 2810 function O() { 2811 var that = this; 2812 this.m = function() { 2813 return this === that; 2814 } 2815 } 2816 with(new O()) { 2817 m(); 2818 } 2819 ` 2820 testScript1(SCRIPT, valueTrue, t) 2821} 2822 2823func TestWithScope(t *testing.T) { 2824 const SCRIPT = ` 2825 function f(o) { 2826 var x = 42; 2827 2828 function innerf(o) { 2829 with (o) { 2830 return x; 2831 } 2832 } 2833 2834 return innerf(o); 2835 } 2836 f({}); 2837 ` 2838 testScript1(SCRIPT, valueInt(42), t) 2839} 2840 2841func TestEvalCallee(t *testing.T) { 2842 const SCRIPT = ` 2843 (function () { 2844 'use strict'; 2845 var v = function() { 2846 return this === undefined; 2847 }; 2848 return eval('v()'); 2849 })(); 2850 ` 2851 testScript1(SCRIPT, valueTrue, t) 2852} 2853 2854func TestEvalBindingDeleteVar(t *testing.T) { 2855 const SCRIPT = ` 2856 (function () { 2857 eval("var x = 1"); 2858 return x === 1 && delete x; 2859 })(); 2860 ` 2861 testScript1(SCRIPT, valueTrue, t) 2862} 2863 2864func TestEvalBindingDeleteFunc(t *testing.T) { 2865 const SCRIPT = ` 2866 (function () { 2867 eval("function x(){}"); 2868 return typeof x === "function" && delete x; 2869 })(); 2870 ` 2871 testScript1(SCRIPT, valueTrue, t) 2872} 2873 2874func TestDeleteGlobalLexical(t *testing.T) { 2875 const SCRIPT = ` 2876 let x; 2877 delete x; 2878 ` 2879 testScript1(SCRIPT, valueFalse, t) 2880} 2881 2882func TestDeleteGlobalEval(t *testing.T) { 2883 const SCRIPT = ` 2884 eval("var x"); 2885 delete x; 2886 ` 2887 testScript1(SCRIPT, valueTrue, t) 2888} 2889 2890func TestGlobalVarNames(t *testing.T) { 2891 vm := New() 2892 _, err := vm.RunString("(0,eval)('var x')") 2893 if err != nil { 2894 t.Fatal(err) 2895 } 2896 _, err = vm.RunString("let x") 2897 if err == nil { 2898 t.Fatal("Expected error") 2899 } 2900} 2901 2902func TestTryResultEmpty(t *testing.T) { 2903 const SCRIPT = ` 2904 1; try { } finally { } 2905 ` 2906 testScript1(SCRIPT, _undefined, t) 2907} 2908 2909func TestTryResultEmptyCatch(t *testing.T) { 2910 const SCRIPT = ` 2911 1; try { throw null } catch(e) { } 2912 ` 2913 testScript1(SCRIPT, _undefined, t) 2914} 2915 2916func TestTryResultEmptyContinueLoop(t *testing.T) { 2917 const SCRIPT = ` 2918 for (var i = 0; i < 2; i++) { try {throw null;} catch(e) {continue;} 'bad'} 2919 ` 2920 testScript1(SCRIPT, _undefined, t) 2921} 2922 2923func TestTryEmptyCatchStackLeak(t *testing.T) { 2924 const SCRIPT = ` 2925 (function() { 2926 var f; 2927 // Make sure the outer function is not stashless. 2928 (function() { 2929 f++; 2930 })(); 2931 try { 2932 throw new Error(); 2933 } catch(e) {} 2934 })(); 2935 ` 2936 testScript1(SCRIPT, _undefined, t) 2937} 2938 2939func TestTryThrowEmptyCatch(t *testing.T) { 2940 const SCRIPT = ` 2941 try { 2942 throw new Error(); 2943 } 2944 catch (e) {} 2945 ` 2946 testScript1(SCRIPT, _undefined, t) 2947} 2948 2949func TestFalsyLoopBreak(t *testing.T) { 2950 const SCRIPT = ` 2951 while(false) { 2952 break; 2953 } 2954 for(;false;) { 2955 break; 2956 } 2957 undefined; 2958 ` 2959 MustCompile("", SCRIPT, false) 2960} 2961 2962func TestFalsyLoopBreakWithResult(t *testing.T) { 2963 const SCRIPT = ` 2964 while(false) { 2965 break; 2966 } 2967 ` 2968 testScript1(SCRIPT, _undefined, t) 2969} 2970 2971func TestDummyCompile(t *testing.T) { 2972 const SCRIPT = ` 2973 'use strict'; 2974 2975 for (;false;) { 2976 eval = 1; 2977 } 2978 ` 2979 2980 _, err := Compile("", SCRIPT, false) 2981 if err == nil { 2982 t.Fatal("expected error") 2983 } 2984} 2985 2986func TestDummyCompileForUpdate(t *testing.T) { 2987 const SCRIPT = ` 2988 'use strict'; 2989 2990 for (;false;eval=1) { 2991 } 2992 ` 2993 2994 _, err := Compile("", SCRIPT, false) 2995 if err == nil { 2996 t.Fatal("expected error") 2997 } 2998} 2999 3000func TestObjectLiteralWithNumericKeys(t *testing.T) { 3001 const SCRIPT = ` 3002 var o = {1e3: true}; 3003 var keys = Object.keys(o); 3004 var o1 = {get 1e3() {return true;}}; 3005 var keys1 = Object.keys(o1); 3006 var o2 = {1e21: true}; 3007 var keys2 = Object.keys(o2); 3008 keys.length === 1 && keys[0] === "1000" && 3009 keys1.length === 1 && keys1[0] === "1000" && o1[1e3] === true && 3010 keys2.length === 1 && keys2[0] === "1e+21"; 3011 ` 3012 testScript1(SCRIPT, valueTrue, t) 3013} 3014 3015func TestEscapedObjectPropertyKeys(t *testing.T) { 3016 const SCRIPT = ` 3017 var obj = { 3018 w\u0069th: 42 3019 }; 3020 var obj = { 3021 with() {42} 3022 }; 3023 ` 3024 3025 _, err := Compile("", SCRIPT, false) 3026 if err != nil { 3027 t.Fatal(err) 3028 } 3029} 3030 3031func TestObjectLiteralFuncProps(t *testing.T) { 3032 const SCRIPT = ` 3033 (function() { 3034 'use strict'; 3035 var o = { 3036 eval: function() {return 1;}, 3037 arguments() {return 2;}, 3038 test: function test1() {} 3039 } 3040 assert.sameValue(o.eval.name, "eval"); 3041 assert.sameValue(o.arguments.name, "arguments"); 3042 assert.sameValue(o.eval(), 1); 3043 assert.sameValue(o.arguments(), 2); 3044 assert.sameValue(o.test.name, "test1"); 3045 })(); 3046 ` 3047 3048 testScript1(TESTLIB+SCRIPT, _undefined, t) 3049} 3050 3051func TestFuncName(t *testing.T) { 3052 const SCRIPT = ` 3053 var method = 1; 3054 var o = { 3055 method: function() { 3056 return method; 3057 }, 3058 method1: function method() { 3059 return method; 3060 } 3061 } 3062 o.method() === 1 && o.method1() === o.method1; 3063 ` 3064 3065 testScript1(SCRIPT, valueTrue, t) 3066} 3067 3068func TestFuncNameAssign(t *testing.T) { 3069 const SCRIPT = ` 3070 var f = function() {}; 3071 var f1; 3072 f1 = function() {}; 3073 let f2 = function() {}; 3074 3075 f.name === "f" && f1.name === "f1" && f2.name === "f2"; 3076 ` 3077 3078 testScript1(SCRIPT, valueTrue, t) 3079} 3080 3081func TestLexicalDeclGlobal(t *testing.T) { 3082 const SCRIPT = ` 3083 if (true) { 3084 let it = "be"; 3085 if (it !== "be") { 3086 throw new Error(it); 3087 } 3088 } 3089 let thrown = false; 3090 try { 3091 it; 3092 } catch(e) { 3093 if (e instanceof ReferenceError) { 3094 thrown = true; 3095 } 3096 } 3097 thrown; 3098 ` 3099 testScript1(SCRIPT, valueTrue, t) 3100} 3101 3102func TestLexicalDeclFunction(t *testing.T) { 3103 const SCRIPT = ` 3104 function f() { 3105 if (true) { 3106 let it = "be"; 3107 if (it !== "be") { 3108 throw new Error(it); 3109 } 3110 } 3111 let thrown = false; 3112 try { 3113 it; 3114 } catch(e) { 3115 if (e instanceof ReferenceError) { 3116 thrown = true; 3117 } 3118 } 3119 return thrown; 3120 } 3121 f(); 3122 ` 3123 testScript1(SCRIPT, valueTrue, t) 3124} 3125 3126func TestLexicalDynamicScope(t *testing.T) { 3127 const SCRIPT = ` 3128 const global = 1; 3129 function f() { 3130 const func = global + 1; 3131 function inner() { 3132 function assertThrows(fn) { 3133 let thrown = false; 3134 try { 3135 fn(); 3136 } catch (e) { 3137 if (e instanceof TypeError) { 3138 thrown = true; 3139 } else { 3140 throw e; 3141 } 3142 } 3143 if (!thrown) { 3144 throw new Error("Did not throw"); 3145 } 3146 } 3147 3148 assertThrows(function() { 3149 func++; 3150 }); 3151 assertThrows(function() { 3152 global++; 3153 }); 3154 3155 assertThrows(function() { 3156 eval("func++"); 3157 }); 3158 assertThrows(function() { 3159 eval("global++"); 3160 }); 3161 3162 return eval("func + 1"); 3163 } 3164 return inner(); 3165 } 3166 f(); 3167 ` 3168 testScript1(SCRIPT, valueInt(3), t) 3169} 3170 3171func TestNonStrictLet(t *testing.T) { 3172 const SCRIPT = ` 3173 var let = 1; 3174 ` 3175 3176 testScript1(SCRIPT, _undefined, t) 3177} 3178 3179func TestStrictLet(t *testing.T) { 3180 const SCRIPT = ` 3181 var let = 1; 3182 ` 3183 3184 _, err := Compile("", SCRIPT, true) 3185 if err == nil { 3186 t.Fatal("Expected an error") 3187 } 3188} 3189 3190func TestLetLet(t *testing.T) { 3191 const SCRIPT = ` 3192 let let = 1; 3193 ` 3194 3195 _, err := Compile("", SCRIPT, false) 3196 if err == nil { 3197 t.Fatal("Expected an error") 3198 } 3199} 3200 3201func TestLetASI(t *testing.T) { 3202 const SCRIPT = ` 3203 while (false) let // ASI 3204 x = 1; 3205 ` 3206 3207 _, err := Compile("", SCRIPT, false) 3208 if err != nil { 3209 t.Fatal(err) 3210 } 3211} 3212 3213func TestLetASI1(t *testing.T) { 3214 const SCRIPT = ` 3215 let 3216 x = 1; 3217 ` 3218 3219 _, err := Compile("", SCRIPT, true) 3220 if err != nil { 3221 t.Fatal(err) 3222 } 3223} 3224 3225func TestLetNoASI(t *testing.T) { 3226 const SCRIPT = ` 3227 function f() {}let 3228x = 1; 3229 ` 3230 3231 _, err := Compile("", SCRIPT, true) 3232 if err != nil { 3233 t.Fatal(err) 3234 } 3235} 3236 3237func TestLetNoASI1(t *testing.T) { 3238 const SCRIPT = ` 3239let 3240let = 1; 3241 ` 3242 3243 _, err := Compile("", SCRIPT, false) 3244 if err == nil { 3245 t.Fatal("Expected error") 3246 } 3247} 3248 3249func TestLetArrayWithNewline(t *testing.T) { 3250 const SCRIPT = ` 3251 with ({}) let 3252 [a] = 0; 3253 ` 3254 3255 _, err := Compile("", SCRIPT, false) 3256 if err == nil { 3257 t.Fatal("Expected error") 3258 } 3259} 3260 3261func TestDynamicUninitedVarAccess(t *testing.T) { 3262 const SCRIPT = ` 3263 function f() { 3264 var x; 3265 return eval("x"); 3266 } 3267 f(); 3268 ` 3269 testScript1(SCRIPT, _undefined, t) 3270} 3271 3272func TestLexicalForLoopNoClosure(t *testing.T) { 3273 const SCRIPT = ` 3274 let sum = 0; 3275 for (let i = 0; i < 3; i++) { 3276 sum += i; 3277 } 3278 sum; 3279 ` 3280 testScript1(SCRIPT, valueInt(3), t) 3281} 3282 3283func TestLexicalForLoopClosure(t *testing.T) { 3284 const SCRIPT = ` 3285 var f = []; 3286 for (let i = 0; i < 3; i++) { 3287 f.push(function() { 3288 return i; 3289 }); 3290 } 3291 f.length === 3 && f[0]() === 0 && f[1]() === 1 && f[2]() === 2; 3292 ` 3293 testScript1(SCRIPT, valueTrue, t) 3294} 3295 3296func TestLexicalForLoopClosureInNext(t *testing.T) { 3297 const SCRIPT = ` 3298 const a = []; 3299 for (let i = 0; i < 5; a.push(function () { return i; }), ++i) { } 3300 let res = ""; 3301 for (let k = 0; k < 5; ++k) { 3302 res += ""+a[k](); 3303 } 3304 res; 3305 ` 3306 testScript1(SCRIPT, asciiString("12345"), t) 3307} 3308 3309func TestVarForLoop(t *testing.T) { 3310 const SCRIPT = ` 3311 var f = []; 3312 for (var i = 0, j = 0; i < 3; i++) { 3313 f.push(function() { 3314 return i; 3315 }); 3316 } 3317 f.length === 3 && f[0]() === 3 && f[1]() === 3 && f[2]() === 3; 3318 ` 3319 testScript1(SCRIPT, valueTrue, t) 3320} 3321 3322func TestLexicalForOfLoop(t *testing.T) { 3323 const SCRIPT = ` 3324 var f = []; 3325 for (let i of [0, 1, 2]) { 3326 f.push(function() { 3327 return i; 3328 }); 3329 } 3330 f.length === 3 && f[0]() === 0 && f[1]() === 1 && f[2]() === 2; 3331 ` 3332 testScript1(SCRIPT, valueTrue, t) 3333} 3334 3335func TestLexicalForOfLoopContBreak(t *testing.T) { 3336 const SCRIPT = ` 3337 const f = []; 3338 for (let i of [0, 1, 2, 3, 4, 5]) { 3339 if (i % 2) continue; 3340 f.push(function() { 3341 return i; 3342 }); 3343 if (i > 2) break; 3344 } 3345 let res = ""; 3346 f.forEach(function(item) {res += item()}); 3347 f.length === 3 && res === "024"; 3348 ` 3349 testScript1(SCRIPT, valueTrue, t) 3350} 3351 3352func TestVarBlockConflict(t *testing.T) { 3353 const SCRIPT = ` 3354 let x; 3355 { 3356 if (false) { 3357 var x; 3358 } 3359 } 3360 ` 3361 _, err := Compile("", SCRIPT, false) 3362 if err == nil { 3363 t.Fatal("Expected an error") 3364 } 3365} 3366 3367func TestVarBlockConflictEval(t *testing.T) { 3368 const SCRIPT = ` 3369 assert.throws(SyntaxError, function() { 3370 let x; 3371 { 3372 if (true) { 3373 eval("var x"); 3374 } 3375 } 3376 }); 3377 ` 3378 testScript1(TESTLIB+SCRIPT, _undefined, t) 3379} 3380 3381func TestVarBlockNoConflict(t *testing.T) { 3382 const SCRIPT = ` 3383 function f() { 3384 let x; 3385 function ff() { 3386 { 3387 var x = 3; 3388 } 3389 } 3390 ff(); 3391 } 3392 f(); 3393 ` 3394 testScript1(SCRIPT, _undefined, t) 3395} 3396 3397func TestVarBlockNoConflictEval(t *testing.T) { 3398 const SCRIPT = ` 3399 function f() { 3400 let x; 3401 function ff() { 3402 { 3403 eval("var x = 3"); 3404 } 3405 } 3406 ff(); 3407 } 3408 f(); 3409 ` 3410 testScript1(SCRIPT, _undefined, t) 3411} 3412 3413func TestVarDeclCorrectScope(t *testing.T) { 3414 const SCRIPT = ` 3415 function f() { 3416 { 3417 let z; 3418 eval("var x = 3"); 3419 } 3420 return x; 3421 } 3422 f(); 3423 ` 3424 testScript1(SCRIPT, valueInt(3), t) 3425} 3426 3427func TestLexicalCatch(t *testing.T) { 3428 const SCRIPT = ` 3429 try { 3430 throw null; 3431 } catch (e) { 3432 let x = 1; 3433 function f() {} 3434 e; 3435 } 3436 ` 3437 testScript1(SCRIPT, _null, t) 3438} 3439 3440func TestArgumentsLexicalDecl(t *testing.T) { 3441 const SCRIPT = ` 3442 function f1() { 3443 let arguments; 3444 return arguments; 3445 } 3446 f1(42); 3447 ` 3448 testScript1(SCRIPT, _undefined, t) 3449} 3450 3451func TestArgumentsLexicalDeclAssign(t *testing.T) { 3452 const SCRIPT = ` 3453 function f1() { 3454 let arguments = arguments; 3455 return a; 3456 } 3457 assert.throws(ReferenceError, function() { 3458 f1(42); 3459 }); 3460 ` 3461 testScript1(TESTLIB+SCRIPT, _undefined, t) 3462} 3463 3464func TestLexicalConstModifyFromEval(t *testing.T) { 3465 const SCRIPT = ` 3466 const x = 1; 3467 function f() { 3468 eval("x = 2"); 3469 } 3470 assert.throws(TypeError, function() { 3471 f(); 3472 }); 3473 ` 3474 testScript1(TESTLIB+SCRIPT, _undefined, t) 3475} 3476 3477func TestLexicalStrictNames(t *testing.T) { 3478 const SCRIPT = `let eval = 1;` 3479 3480 _, err := Compile("", SCRIPT, true) 3481 if err == nil { 3482 t.Fatal("Expected an error") 3483 } 3484} 3485 3486func TestAssignAfterStackExpand(t *testing.T) { 3487 // make sure the reference to the variable x does not remain stale after the stack is copied 3488 const SCRIPT = ` 3489 function f() { 3490 let sum = 0; 3491 for (let i = 0; i < arguments.length; i++) { 3492 sum += arguments[i]; 3493 } 3494 return sum; 3495 } 3496 function testAssignment() { 3497 var x = 0; 3498 var scope = {}; 3499 3500 with (scope) { 3501 x = (scope.x = f(0, 0, 0, 0, 0, 0, 1, 1), 1); 3502 } 3503 3504 if (scope.x !== 2) { 3505 throw new Error('#1: scope.x === 2. Actual: ' + (scope.x)); 3506 } 3507 if (x !== 1) { 3508 throw new Error('#2: x === 1. Actual: ' + (x)); 3509 } 3510 } 3511 testAssignment(); 3512 ` 3513 testScript1(SCRIPT, _undefined, t) 3514} 3515 3516func TestArgAccessFromDynamicStash(t *testing.T) { 3517 const SCRIPT = ` 3518 function f(arg) { 3519 function test() { 3520 eval(""); 3521 return a; 3522 } 3523 return arg; 3524 } 3525 f(true); 3526 ` 3527 testScript1(SCRIPT, valueTrue, t) 3528} 3529 3530func TestLoadMixedLex(t *testing.T) { 3531 const SCRIPT = ` 3532 function f() { 3533 let a = 1; 3534 { 3535 function inner() { 3536 eval("var a = true"); 3537 return a; 3538 } 3539 return inner(); 3540 } 3541 } 3542 f(); 3543 ` 3544 testScript1(SCRIPT, valueTrue, t) 3545} 3546 3547func TestObjectLiteralSpread(t *testing.T) { 3548 const SCRIPT = ` 3549 let src = {prop1: 1}; 3550 Object.defineProperty(src, "prop2", {value: 2, configurable: true}); 3551 Object.defineProperty(src, "prop3", {value: 3, enumerable: true, configurable: true}); 3552 let target = {prop4: 4, ...src}; 3553 assert(deepEqual(target, {prop1: 1, prop3: 3, prop4: 4})); 3554 ` 3555 testScript1(TESTLIBX+SCRIPT, _undefined, t) 3556} 3557 3558func TestArrayLiteralSpread(t *testing.T) { 3559 const SCRIPT = ` 3560 let a1 = [1, 2]; 3561 let a2 = [3, 4]; 3562 let a = [...a1, 0, ...a2, 1]; 3563 assert(compareArray(a, [1, 2, 0, 3, 4, 1])); 3564 ` 3565 testScript1(TESTLIB+SCRIPT, _undefined, t) 3566} 3567 3568func TestObjectAssignmentPattern(t *testing.T) { 3569 const SCRIPT = ` 3570 let a, b, c; 3571 ({a, b, c=3} = {a: 1, b: 2}); 3572 assert.sameValue(a, 1, "a"); 3573 assert.sameValue(b, 2, "b"); 3574 assert.sameValue(c, 3, "c"); 3575 ` 3576 testScript1(TESTLIB+SCRIPT, _undefined, t) 3577} 3578 3579func TestObjectAssignmentPatternNested(t *testing.T) { 3580 const SCRIPT = ` 3581 let a, b, c, d; 3582 ({a, b, c: {d} = 3} = {a: 1, b: 2, c: {d: 4}}); 3583 assert.sameValue(a, 1, "a"); 3584 assert.sameValue(b, 2, "b"); 3585 assert.sameValue(c, undefined, "c"); 3586 assert.sameValue(d, 4, "d"); 3587 ` 3588 testScript1(TESTLIB+SCRIPT, _undefined, t) 3589} 3590 3591func TestObjectAssignmentPatternEvalOrder(t *testing.T) { 3592 const SCRIPT = ` 3593 let trace = ""; 3594 let target_obj = {}; 3595 3596 function src() { 3597 trace += "src(),"; 3598 return { 3599 get a() { 3600 trace += "get a,"; 3601 return "a"; 3602 } 3603 } 3604 } 3605 3606 function prop1() { 3607 trace += "prop1()," 3608 return { 3609 toString: function() { 3610 trace += "prop1-to-string(),"; 3611 return "a"; 3612 } 3613 } 3614 } 3615 3616 function prop2() { 3617 trace += "prop2(),"; 3618 return { 3619 toString: function() { 3620 trace += "prop2-to-string(),"; 3621 return "b"; 3622 } 3623 } 3624 } 3625 3626 function target() { 3627 trace += "target()," 3628 return target_obj; 3629 } 3630 3631 let a, b; 3632 3633 ({[prop1()]: target().a, [prop2()]: b} = src()); 3634 if (target_obj.a !== "a") { 3635 throw new Error("target_obj.a="+target_obj.a); 3636 } 3637 trace; 3638 ` 3639 testScript1(SCRIPT, asciiString("src(),prop1(),prop1-to-string(),target(),get a,prop2(),prop2-to-string(),"), t) 3640} 3641 3642func TestArrayAssignmentPatternEvalOrder(t *testing.T) { 3643 const SCRIPT = ` 3644 let trace = ""; 3645 3646 let src_arr = { 3647 [Symbol.iterator]: function() { 3648 let done = false; 3649 return { 3650 next: function() { 3651 trace += "next,"; 3652 if (!done) { 3653 done = true; 3654 return {value: 0}; 3655 } 3656 return {done: true}; 3657 }, 3658 return: function() { 3659 trace += "return,"; 3660 } 3661 } 3662 } 3663 } 3664 3665 function src() { 3666 trace += "src(),"; 3667 return src_arr; 3668 } 3669 3670 let tgt = { 3671 get a() { 3672 trace += "get a,"; 3673 return "a"; 3674 }, 3675 get b() { 3676 trace += "get b,"; 3677 return "b"; 3678 } 3679 } 3680 3681 function target() { 3682 trace += "target(),"; 3683 return tgt; 3684 } 3685 3686 function default_a() { 3687 trace += "default a,"; 3688 return "def_a"; 3689 } 3690 3691 function default_b() { 3692 trace += "default b,"; 3693 return "def_b"; 3694 } 3695 3696 ([target().a = default_a(), target().b = default_b()] = src()); 3697 trace; 3698 ` 3699 testScript1(SCRIPT, asciiString("src(),target(),next,target(),next,default b,"), t) 3700} 3701 3702func TestObjectAssignPatternRest(t *testing.T) { 3703 const SCRIPT = ` 3704 let a, b, c, d; 3705 ({a, b, c, ...d} = {a: 1, b: 2, d: 4}); 3706 assert.sameValue(a, 1, "a"); 3707 assert.sameValue(b, 2, "b"); 3708 assert.sameValue(c, undefined, "c"); 3709 assert(deepEqual(d, {d: 4}), "d"); 3710 ` 3711 testScript1(TESTLIBX+SCRIPT, _undefined, t) 3712} 3713 3714func TestObjectBindPattern(t *testing.T) { 3715 const SCRIPT = ` 3716 let {a, b, c, ...d} = {a: 1, b: 2, d: 4}; 3717 assert.sameValue(a, 1, "a"); 3718 assert.sameValue(b, 2, "b"); 3719 assert.sameValue(c, undefined, "c"); 3720 assert(deepEqual(d, {d: 4}), "d"); 3721 3722 var { x: y, } = { x: 23 }; 3723 3724 assert.sameValue(y, 23); 3725 3726 assert.throws(ReferenceError, function() { 3727 x; 3728 }); 3729 ` 3730 testScript1(TESTLIBX+SCRIPT, _undefined, t) 3731} 3732 3733func TestObjLiteralShorthandWithInitializer(t *testing.T) { 3734 const SCRIPT = ` 3735 o = {a=1}; 3736 ` 3737 _, err := Compile("", SCRIPT, false) 3738 if err == nil { 3739 t.Fatal("Expected an error") 3740 } 3741} 3742 3743func TestObjLiteralShorthandLetStringLit(t *testing.T) { 3744 const SCRIPT = ` 3745 o = {"let"}; 3746 ` 3747 _, err := Compile("", SCRIPT, false) 3748 if err == nil { 3749 t.Fatal("Expected an error") 3750 } 3751} 3752 3753func TestObjLiteralComputedKeys(t *testing.T) { 3754 const SCRIPT = ` 3755 let o = { 3756 get [Symbol.toString]() { 3757 } 3758 } 3759 ` 3760 testScript1(SCRIPT, _undefined, t) 3761} 3762 3763func TestObjLiteralComputedKeysEvalOrder(t *testing.T) { 3764 const SCRIPT = ` 3765 let trace = []; 3766 function key() { 3767 trace.push("key"); 3768 return { 3769 toString: function() { 3770 trace.push("key-toString"); 3771 return "key"; 3772 } 3773 } 3774 } 3775 function val() { 3776 trace.push("val"); 3777 return "val"; 3778 } 3779 3780 const _ = { 3781 [key()]: val(), 3782 } 3783 3784 trace.join(","); 3785 ` 3786 testScript1(SCRIPT, asciiString("key,key-toString,val"), t) 3787} 3788 3789func TestArrayAssignPattern(t *testing.T) { 3790 const SCRIPT = ` 3791 let a, b; 3792 ([a, b] = [1, 2]); 3793 a === 1 && b === 2; 3794 ` 3795 testScript1(SCRIPT, valueTrue, t) 3796} 3797 3798func TestArrayAssignPattern1(t *testing.T) { 3799 const SCRIPT = ` 3800 let a, b; 3801 ([a = 3, b = 2] = [1]); 3802 a === 1 && b === 2; 3803 ` 3804 testScript1(SCRIPT, valueTrue, t) 3805} 3806 3807func TestArrayAssignPatternLHS(t *testing.T) { 3808 const SCRIPT = ` 3809 let a = {}; 3810 [ a.b, a['c'] = 2 ] = [1]; 3811 a.b === 1 && a.c === 2; 3812 ` 3813 testScript1(SCRIPT, valueTrue, t) 3814} 3815 3816func TestArrayAssignPatternElision(t *testing.T) { 3817 const SCRIPT = ` 3818 let a, b; 3819 ([a,, b] = [1, 4, 2]); 3820 a === 1 && b === 2; 3821 ` 3822 testScript1(SCRIPT, valueTrue, t) 3823} 3824 3825func TestArrayAssignPatternRestPattern(t *testing.T) { 3826 const SCRIPT = ` 3827 let a, b, z; 3828 [ z, ...[a, b] ] = [0, 1, 2]; 3829 z === 0 && a === 1 && b === 2; 3830 ` 3831 testScript1(SCRIPT, valueTrue, t) 3832} 3833 3834func TestArrayBindingPattern(t *testing.T) { 3835 const SCRIPT = ` 3836 let [a, b] = [1, 2]; 3837 a === 1 && b === 2; 3838 ` 3839 testScript1(SCRIPT, valueTrue, t) 3840} 3841 3842func TestObjectPatternShorthandInit(t *testing.T) { 3843 const SCRIPT = ` 3844 [...{ x = 1 }] = []; 3845 x; 3846 ` 3847 testScript1(SCRIPT, valueInt(1), t) 3848} 3849 3850func TestArrayBindingPatternRestPattern(t *testing.T) { 3851 const SCRIPT = ` 3852 const [a, b, ...[c, d]] = [1, 2, 3, 4]; 3853 a === 1 && b === 2 && c === 3 && d === 4; 3854 ` 3855 testScript1(SCRIPT, valueTrue, t) 3856} 3857 3858func TestForVarPattern(t *testing.T) { 3859 const SCRIPT = ` 3860 var o = {a: 1}; 3861 var trace = ""; 3862 for (var [key, value] of Object.entries(o)) { 3863 trace += key+":"+value; 3864 } 3865 trace; 3866 ` 3867 testScript1(SCRIPT, asciiString("a:1"), t) 3868} 3869 3870func TestForLexPattern(t *testing.T) { 3871 const SCRIPT = ` 3872 var o = {a: 1}; 3873 var trace = ""; 3874 for (const [key, value] of Object.entries(o)) { 3875 trace += key+":"+value; 3876 } 3877 trace; 3878 ` 3879 testScript1(SCRIPT, asciiString("a:1"), t) 3880} 3881 3882func TestBindingPatternRestTrailingComma(t *testing.T) { 3883 const SCRIPT = ` 3884 const [a, b, ...rest,] = []; 3885 ` 3886 _, err := Compile("", SCRIPT, false) 3887 if err == nil { 3888 t.Fatal("Expected an error") 3889 } 3890} 3891 3892func TestAssignPatternRestTrailingComma(t *testing.T) { 3893 const SCRIPT = ` 3894 ([a, b, ...rest,] = []); 3895 ` 3896 _, err := Compile("", SCRIPT, false) 3897 if err == nil { 3898 t.Fatal("Expected an error") 3899 } 3900} 3901 3902func TestFuncParamInitializerSimple(t *testing.T) { 3903 const SCRIPT = ` 3904 function f(a = 1) { 3905 return a; 3906 } 3907 ""+f()+f(2); 3908 ` 3909 testScript1(SCRIPT, asciiString("12"), t) 3910} 3911 3912func TestFuncParamObjectPatternSimple(t *testing.T) { 3913 const SCRIPT = ` 3914 function f({a, b} = {a: 1, b: 2}) { 3915 return "" + a + b; 3916 } 3917 ""+f()+" "+f({a: 3, b: 4}); 3918 ` 3919 testScript1(SCRIPT, asciiString("12 34"), t) 3920} 3921 3922func TestFuncParamRestStackSimple(t *testing.T) { 3923 const SCRIPT = ` 3924 function f(arg1, ...rest) { 3925 return rest; 3926 } 3927 let ar = f(1, 2, 3); 3928 ar.join(","); 3929 ` 3930 testScript1(SCRIPT, asciiString("2,3"), t) 3931} 3932 3933func TestFuncParamRestStashSimple(t *testing.T) { 3934 const SCRIPT = ` 3935 function f(arg1, ...rest) { 3936 eval("true"); 3937 return rest; 3938 } 3939 let ar = f(1, 2, 3); 3940 ar.join(","); 3941 ` 3942 testScript1(SCRIPT, asciiString("2,3"), t) 3943} 3944 3945func TestRestArgsNotInStash(t *testing.T) { 3946 const SCRIPT = ` 3947 function f(...rest) { 3948 () => rest; 3949 return rest.length; 3950 } 3951 f(1,2); 3952 ` 3953 testScript1(SCRIPT, valueInt(2), t) 3954} 3955 3956func TestRestArgsInStash(t *testing.T) { 3957 const SCRIPT = ` 3958 function f(first, ...rest) { 3959 () => first; 3960 () => rest; 3961 return rest.length; 3962 } 3963 f(1,2); 3964 ` 3965 testScript1(SCRIPT, valueInt(1), t) 3966} 3967 3968func TestRestArgsInStashFwdRef(t *testing.T) { 3969 const SCRIPT = ` 3970 function f(first = eval(), ...rest) { 3971 () => first; 3972 () => rest; 3973 return rest.length === 1 && rest[0] === 2; 3974 } 3975 f(1,2); 3976 ` 3977 testScript1(SCRIPT, valueTrue, t) 3978} 3979 3980func TestFuncParamRestPattern(t *testing.T) { 3981 const SCRIPT = ` 3982 function f(arg1, ...{0: rest1, 1: rest2}) { 3983 return ""+arg1+" "+rest1+" "+rest2; 3984 } 3985 f(1, 2, 3); 3986 ` 3987 testScript1(SCRIPT, asciiString("1 2 3"), t) 3988} 3989 3990func TestFuncParamForwardRef(t *testing.T) { 3991 const SCRIPT = ` 3992 function f(a = b + 1, b) { 3993 return ""+a+" "+b; 3994 } 3995 f(1, 2); 3996 ` 3997 testScript1(SCRIPT, asciiString("1 2"), t) 3998} 3999 4000func TestFuncParamForwardRefMissing(t *testing.T) { 4001 const SCRIPT = ` 4002 function f(a = b + 1, b) { 4003 return ""+a+" "+b; 4004 } 4005 assert.throws(ReferenceError, function() { 4006 f(); 4007 }); 4008 ` 4009 testScript1(TESTLIB+SCRIPT, _undefined, t) 4010} 4011 4012func TestFuncParamInnerRef(t *testing.T) { 4013 const SCRIPT = ` 4014 function f(a = inner) { 4015 var inner = 42; 4016 return a; 4017 } 4018 assert.throws(ReferenceError, function() { 4019 f(); 4020 }); 4021 ` 4022 testScript1(TESTLIB+SCRIPT, _undefined, t) 4023} 4024 4025func TestFuncParamInnerRefEval(t *testing.T) { 4026 const SCRIPT = ` 4027 function f(a = eval("inner")) { 4028 var inner = 42; 4029 return a; 4030 } 4031 assert.throws(ReferenceError, function() { 4032 f(); 4033 }); 4034 ` 4035 testScript1(TESTLIB+SCRIPT, _undefined, t) 4036} 4037 4038func TestFuncParamCalleeName(t *testing.T) { 4039 const SCRIPT = ` 4040 function f(a = f) { 4041 var f; 4042 return f; 4043 } 4044 typeof f(); 4045 ` 4046 testScript1(SCRIPT, asciiString("undefined"), t) 4047} 4048 4049func TestFuncParamVarCopy(t *testing.T) { 4050 const SCRIPT = ` 4051 function f(a = f) { 4052 var a; 4053 return a; 4054 } 4055 typeof f(); 4056 ` 4057 testScript1(SCRIPT, asciiString("function"), t) 4058} 4059 4060func TestFuncParamScope(t *testing.T) { 4061 const SCRIPT = ` 4062 var x = 'outside'; 4063 var probe1, probe2; 4064 4065 function f( 4066 _ = probe1 = function() { return x; }, 4067 __ = (eval('var x = "inside";'), probe2 = function() { return x; }) 4068 ) { 4069 } 4070 f(); 4071 probe1()+" "+probe2(); 4072 ` 4073 testScript1(SCRIPT, asciiString("inside inside"), t) 4074} 4075 4076func TestDefParamsStackPtr(t *testing.T) { 4077 const SCRIPT = ` 4078 function A() {}; 4079 A.B = function () {}; 4080 function D(message = '') { 4081 var C = A.B; 4082 C([1,2,3]); 4083 }; 4084 4085 D(); 4086 ` 4087 testScript1(SCRIPT, _undefined, t) 4088} 4089 4090func TestNestedVariadicCalls(t *testing.T) { 4091 const SCRIPT = ` 4092 function f() { 4093 return Array.prototype.join.call(arguments, ","); 4094 } 4095 f(...[1], "a", f(...[2])); 4096 ` 4097 testScript1(SCRIPT, asciiString("1,a,2"), t) 4098} 4099 4100func TestVariadicNew(t *testing.T) { 4101 const SCRIPT = ` 4102 function C() { 4103 this.res = Array.prototype.join.call(arguments, ","); 4104 } 4105 var c = new C(...[1], "a", new C(...[2]).res); 4106 c.res; 4107 ` 4108 testScript1(SCRIPT, asciiString("1,a,2"), t) 4109} 4110 4111func TestVariadicUseStackVars(t *testing.T) { 4112 const SCRIPT = ` 4113 function A(message) { return message; } 4114 function B(...args){ 4115 return A(...args); 4116 } 4117 B("C"); 4118 ` 4119 testScript1(SCRIPT, asciiString("C"), t) 4120} 4121 4122func TestCatchParamPattern(t *testing.T) { 4123 const SCRIPT = ` 4124 function f() { 4125 let x = 3; 4126 try { 4127 throw {a: 1, b: 2}; 4128 } catch ({a, b, c = x}) { 4129 let x = 99; 4130 return ""+a+" "+b+" "+c; 4131 } 4132 } 4133 f(); 4134 ` 4135 testScript1(SCRIPT, asciiString("1 2 3"), t) 4136} 4137 4138func TestArrowUseStrict(t *testing.T) { 4139 // simple parameter list -- ok 4140 _, err := Compile("", "(a) => {'use strict';}", false) 4141 if err != nil { 4142 t.Fatal(err) 4143 } 4144 // non-simple parameter list -- syntax error 4145 _, err = Compile("", "(a=0) => {'use strict';}", false) 4146 if err == nil { 4147 t.Fatal("expected error") 4148 } 4149} 4150 4151func TestArrowBoxedThis(t *testing.T) { 4152 const SCRIPT = ` 4153 var context; 4154 fn = function() { 4155 return (arg) => { var local; context = this; }; 4156 }; 4157 4158 fn()(); 4159 context === this; 4160 ` 4161 4162 testScript1(SCRIPT, valueTrue, t) 4163} 4164func TestParameterOverride(t *testing.T) { 4165 const SCRIPT = ` 4166 function f(arg) { 4167 var arg = arg || "default" 4168 return arg 4169 } 4170 f() 4171 ` 4172 testScript1(SCRIPT, asciiString("default"), t) 4173} 4174 4175func TestEvalInIterScope(t *testing.T) { 4176 const SCRIPT = ` 4177 for (let a = 0; a < 1; a++) { 4178 eval("a"); 4179 } 4180 ` 4181 4182 testScript1(SCRIPT, valueInt(0), t) 4183} 4184 4185func TestTemplateLiterals(t *testing.T) { 4186 vm := New() 4187 _, err := vm.RunString("const a = 1, b = 'b';") 4188 if err != nil { 4189 t.Fatal(err) 4190 } 4191 f := func(t *testing.T, template, expected string) { 4192 res, err := vm.RunString(template) 4193 if err != nil { 4194 t.Fatal(err) 4195 } 4196 if actual := res.Export(); actual != expected { 4197 t.Fatalf("Expected: %q, actual: %q", expected, actual) 4198 } 4199 } 4200 t.Run("empty", func(t *testing.T) { 4201 f(t, "``", "") 4202 }) 4203 t.Run("noSub", func(t *testing.T) { 4204 f(t, "`test`", "test") 4205 }) 4206 t.Run("emptyTail", func(t *testing.T) { 4207 f(t, "`a=${a},b=${b}`", "a=1,b=b") 4208 }) 4209 t.Run("emptyHead", func(t *testing.T) { 4210 f(t, "`${a},b=${b}$`", "1,b=b$") 4211 }) 4212 t.Run("headAndTail", func(t *testing.T) { 4213 f(t, "`a=${a},b=${b}$`", "a=1,b=b$") 4214 }) 4215} 4216 4217func TestTaggedTemplate(t *testing.T) { 4218 const SCRIPT = ` 4219 let res; 4220 const o = { 4221 tmpl() { 4222 res = this; 4223 return () => {}; 4224 } 4225 } 4226 ` + 4227 "o.tmpl()`test`;" + ` 4228 res === o; 4229 ` 4230 4231 testScript1(SCRIPT, valueTrue, t) 4232} 4233 4234/* 4235func TestBabel(t *testing.T) { 4236 src, err := ioutil.ReadFile("babel7.js") 4237 if err != nil { 4238 t.Fatal(err) 4239 } 4240 vm := New() 4241 _, err = vm.RunString(string(src)) 4242 if err != nil { 4243 t.Fatal(err) 4244 } 4245 _, err = vm.RunString(`var result = Babel.transform("", {presets: ["es2015"]});`) 4246 if err != nil { 4247 t.Fatal(err) 4248 } 4249}*/ 4250 4251func BenchmarkCompile(b *testing.B) { 4252 data, err := ioutil.ReadFile("testdata/S15.10.2.12_A1_T1.js") 4253 if err != nil { 4254 b.Fatal(err) 4255 } 4256 4257 src := string(data) 4258 4259 for i := 0; i < b.N; i++ { 4260 _, err := Compile("test.js", src, false) 4261 if err != nil { 4262 b.Fatal(err) 4263 } 4264 } 4265} 4266