1 package goja
2
3 import (
4 "os"
5 "sync"
6 "testing"
7 )
8
9 const TESTLIB = `
10 function $ERROR(message) {
11 throw new Error(message);
12 }
13
14 function Test262Error() {
15 }
16
17 function assert(mustBeTrue, message) {
18 if (mustBeTrue === true) {
19 return;
20 }
21
22 if (message === undefined) {
23 message = 'Expected true but got ' + String(mustBeTrue);
24 }
25 $ERROR(message);
26 }
27
28 assert._isSameValue = function (a, b) {
29 if (a === b) {
30 // Handle +/-0 vs. -/+0
31 return a !== 0 || 1 / a === 1 / b;
32 }
33
34 // Handle NaN vs. NaN
35 return a !== a && b !== b;
36 };
37
38 assert.sameValue = function (actual, expected, message) {
39 if (assert._isSameValue(actual, expected)) {
40 return;
41 }
42
43 if (message === undefined) {
44 message = '';
45 } else {
46 message += ' ';
47 }
48
49 message += 'Expected SameValue(«' + String(actual) + '», «' + String(expected) + '») to be true';
50
51 $ERROR(message);
52 };
53
54 assert.throws = function (expectedErrorConstructor, func, message) {
55 if (typeof func !== "function") {
56 $ERROR('assert.throws requires two arguments: the error constructor ' +
57 'and a function to run');
58 return;
59 }
60 if (message === undefined) {
61 message = '';
62 } else {
63 message += ' ';
64 }
65
66 try {
67 func();
68 } catch (thrown) {
69 if (typeof thrown !== 'object' || thrown === null) {
70 message += 'Thrown value was not an object!';
71 $ERROR(message);
72 } else if (thrown.constructor !== expectedErrorConstructor) {
73 message += 'Expected a ' + expectedErrorConstructor.name + ' but got a ' + thrown.constructor.name;
74 $ERROR(message);
75 }
76 return;
77 }
78
79 message += 'Expected a ' + expectedErrorConstructor.name + ' to be thrown but no exception was thrown at all';
80 $ERROR(message);
81 };
82
83 function compareArray(a, b) {
84 if (b.length !== a.length) {
85 return false;
86 }
87
88 for (var i = 0; i < a.length; i++) {
89 if (b[i] !== a[i]) {
90 return false;
91 }
92 }
93 return true;
94 }
95 `
96
97 const TESTLIBX = `
98 function looksNative(fn) {
99 return /native code/.test(Function.prototype.toString.call(fn));
100 }
101
102 function deepEqual(a, b) {
103 if (typeof a === "object") {
104 if (typeof b === "object") {
105 if (a === b) {
106 return true;
107 }
108 if (Reflect.getPrototypeOf(a) !== Reflect.getPrototypeOf(b)) {
109 return false;
110 }
111 var keysA = Object.keys(a);
112 var keysB = Object.keys(b);
113 if (keysA.length !== keysB.length) {
114 return false;
115 }
116 if (!compareArray(keysA.sort(), keysB.sort())) {
117 return false;
118 }
119 for (var i = 0; i < keysA.length; i++) {
120 var key = keysA[i];
121 if (!deepEqual(a[key], b[key])) {
122 return false;
123 }
124 }
125 return true;
126 } else {
127 return false;
128 }
129 }
130 return assert._isSameValue(a, b);
131 }
132
133 function assertStack(e, expected) {
134 const lines = e.stack.split('\n');
135 assert.sameValue(lines.length, expected.length + 2, "Stack lengths mismatch");
136 let lnum = 1;
137 for (const [file, func, line, col] of expected) {
138 const expLine = func === "" ?
139 "\tat " + file + ":" + line + ":" + col + "(" :
140 "\tat " + func + " (" + file + ":" + line + ":" + col + "(";
141 assert.sameValue(lines[lnum].substring(0, expLine.length), expLine, "line " + lnum);
142 lnum++;
143 }
144 }
145 `
146
147 var (
148
149
150
151 _testLib, _testLibX *Program
152 testLibOnce, testLibXOnce sync.Once
153 )
154
155 func testLib() *Program {
156 testLibOnce.Do(func() {
157 _testLib = MustCompile("testlib.js", TESTLIB, false)
158 })
159 return _testLib
160 }
161
162 func testLibX() *Program {
163 testLibXOnce.Do(func() {
164 _testLibX = MustCompile("testlibx.js", TESTLIBX, false)
165 })
166 return _testLibX
167 }
168
169 func (r *Runtime) testPrg(p *Program, expectedResult Value, t *testing.T) {
170 p.dumpCode(t.Logf)
171 v, err := r.RunProgram(p)
172 if err != nil {
173 if ex, ok := err.(*Exception); ok {
174 t.Fatalf("Exception: %v", ex.String())
175 }
176 }
177 vm := r.vm
178 t.Logf("stack size: %d", len(vm.stack))
179 t.Logf("stashAllocs: %d", vm.stashAllocs)
180
181 if v == nil && expectedResult != nil || !v.SameAs(expectedResult) {
182 t.Fatalf("Result: %+v, expected: %+v", v, expectedResult)
183 }
184
185 if vm.sp != 0 {
186 t.Fatalf("sp: %d", vm.sp)
187 }
188
189 if l := len(vm.iterStack); l > 0 {
190 t.Fatalf("iter stack is not empty: %d", l)
191 }
192 }
193
194 func (r *Runtime) testScriptWithTestLib(script string, expectedResult Value, t *testing.T) {
195 _, err := r.RunProgram(testLib())
196 if err != nil {
197 t.Fatal(err)
198 }
199
200 r.testScript(script, expectedResult, t)
201 }
202
203 func (r *Runtime) testScriptWithTestLibX(script string, expectedResult Value, t *testing.T) {
204 _, err := r.RunProgram(testLib())
205 if err != nil {
206 t.Fatal(err)
207 }
208
209 _, err = r.RunProgram(testLibX())
210 if err != nil {
211 t.Fatal(err)
212 }
213
214 r.testScript(script, expectedResult, t)
215 }
216
217 func (r *Runtime) testScript(script string, expectedResult Value, t *testing.T) {
218 r.testPrg(MustCompile("test.js", script, false), expectedResult, t)
219 }
220
221 func testScript(script string, expectedResult Value, t *testing.T) {
222 New().testScript(script, expectedResult, t)
223 }
224
225 func testScriptWithTestLib(script string, expectedResult Value, t *testing.T) {
226 New().testScriptWithTestLib(script, expectedResult, t)
227 }
228
229 func testScriptWithTestLibX(script string, expectedResult Value, t *testing.T) {
230 New().testScriptWithTestLibX(script, expectedResult, t)
231 }
232
233 func (r *Runtime) testAsyncFunc(src string, expectedResult Value, t *testing.T) {
234 v, err := r.RunScript("test.js", "(async function test() {"+src+"\n})()")
235 if err != nil {
236 t.Fatal(err)
237 }
238 promise := v.Export().(*Promise)
239 switch s := promise.State(); s {
240 case PromiseStateFulfilled:
241 if res := promise.Result(); res == nil && expectedResult != nil || !res.SameAs(expectedResult) {
242 t.Fatalf("Result: %+v, expected: %+v", res, expectedResult)
243 }
244 case PromiseStateRejected:
245 res := promise.Result()
246 if resObj, ok := res.(*Object); ok {
247 if stack := resObj.Get("stack"); stack != nil {
248 t.Fatal(stack.String())
249 }
250 }
251 t.Fatal(res.String())
252 default:
253 t.Fatalf("Unexpected promise state: %v", s)
254 }
255 }
256
257 func (r *Runtime) testAsyncFuncWithTestLib(src string, expectedResult Value, t *testing.T) {
258 _, err := r.RunProgram(testLib())
259 if err != nil {
260 t.Fatal(err)
261 }
262
263 r.testAsyncFunc(src, expectedResult, t)
264 }
265
266 func (r *Runtime) testAsyncFuncWithTestLibX(src string, expectedResult Value, t *testing.T) {
267 _, err := r.RunProgram(testLib())
268 if err != nil {
269 t.Fatal(err)
270 }
271
272 _, err = r.RunProgram(testLibX())
273 if err != nil {
274 t.Fatal(err)
275 }
276
277 r.testAsyncFunc(src, expectedResult, t)
278 }
279
280 func testAsyncFunc(src string, expectedResult Value, t *testing.T) {
281 New().testAsyncFunc(src, expectedResult, t)
282 }
283
284 func testAsyncFuncWithTestLib(src string, expectedResult Value, t *testing.T) {
285 New().testAsyncFuncWithTestLib(src, expectedResult, t)
286 }
287
288 func testAsyncFuncWithTestLibX(src string, expectedResult Value, t *testing.T) {
289 New().testAsyncFuncWithTestLibX(src, expectedResult, t)
290 }
291
292 func TestEmptyProgram(t *testing.T) {
293 const SCRIPT = `
294 `
295
296 testScript(SCRIPT, _undefined, t)
297 }
298
299 func TestResultEmptyBlock(t *testing.T) {
300 const SCRIPT = `
301 undefined;
302 {}
303 `
304 testScript(SCRIPT, _undefined, t)
305 }
306
307 func TestResultVarDecl(t *testing.T) {
308 const SCRIPT = `
309 7; var x = 1;
310 `
311 testScript(SCRIPT, valueInt(7), t)
312 }
313
314 func TestResultLexDecl(t *testing.T) {
315 const SCRIPT = `
316 7; {let x = 1};
317 `
318 testScript(SCRIPT, valueInt(7), t)
319 }
320
321 func TestResultLexDeclBreak(t *testing.T) {
322 const SCRIPT = `
323 L:{ 7; {let x = 1; break L;}};
324 `
325 testScript(SCRIPT, valueInt(7), t)
326 }
327
328 func TestResultLexDeclNested(t *testing.T) {
329 const SCRIPT = `
330 7; {let x = (function() { return eval("8; {let y = 9}")})()};
331 `
332 testScript(SCRIPT, valueInt(7), t)
333 }
334
335 func TestErrorProto(t *testing.T) {
336 const SCRIPT = `
337 var e = new TypeError();
338 e.name;
339 `
340
341 testScript(SCRIPT, asciiString("TypeError"), t)
342 }
343
344 func TestThis1(t *testing.T) {
345 const SCRIPT = `
346 function independent() {
347 return this.prop;
348 }
349 var o = {};
350 o.b = {g: independent, prop: 42};
351
352 o.b.g();
353 `
354 testScript(SCRIPT, intToValue(42), t)
355 }
356
357 func TestThis2(t *testing.T) {
358 const SCRIPT = `
359 var o = {
360 prop: 37,
361 f: function() {
362 return this.prop;
363 }
364 };
365
366 o.f();
367 `
368
369 testScript(SCRIPT, intToValue(37), t)
370 }
371
372 func TestThisStrict(t *testing.T) {
373 const SCRIPT = `
374 "use strict";
375
376 Object.defineProperty(Object.prototype, "x", { get: function () { return this; } });
377
378 (5).x === 5;
379 `
380
381 testScript(SCRIPT, valueTrue, t)
382 }
383
384 func TestThisNoStrict(t *testing.T) {
385 const SCRIPT = `
386 Object.defineProperty(Object.prototype, "x", { get: function () { return this; } });
387
388 (5).x == 5;
389 `
390
391 testScript(SCRIPT, valueTrue, t)
392 }
393
394 func TestNestedFuncVarResolution(t *testing.T) {
395 const SCRIPT = `
396 (function outer() {
397 var v = 42;
398 function inner() {
399 return v;
400 }
401 return inner();
402 })();
403 `
404 testScript(SCRIPT, valueInt(42), t)
405 }
406
407 func TestNestedFuncVarResolution1(t *testing.T) {
408 const SCRIPT = `
409 function outer(argOuter) {
410 var called = 0;
411 var inner = function(argInner) {
412 if (arguments.length !== 1) {
413 throw new Error();
414 }
415 called++;
416 if (argOuter !== 1) {
417 throw new Error("argOuter");
418 }
419 if (argInner !== 2) {
420 throw new Error("argInner");
421 }
422 };
423 inner(2);
424 }
425 outer(1);
426 `
427 testScript(SCRIPT, _undefined, t)
428 }
429
430 func TestCallFewerArgs(t *testing.T) {
431 const SCRIPT = `
432 function A(a, b, c) {
433 return String(a) + " " + String(b) + " " + String(c);
434 }
435
436 A(1, 2);
437 `
438 testScript(SCRIPT, asciiString("1 2 undefined"), t)
439 }
440
441 func TestCallFewerArgsClosureNoArgs(t *testing.T) {
442 const SCRIPT = `
443 var x;
444 function A(a, b, c) {
445 var y = a;
446 x = function() { return " " + y };
447 return String(a) + " " + String(b) + " " + String(c);
448 }
449
450 A(1, 2) + x();
451 `
452 testScript(SCRIPT, asciiString("1 2 undefined 1"), t)
453 }
454
455 func TestCallFewerArgsClosureArgs(t *testing.T) {
456 const SCRIPT = `
457 var x;
458 function A(a, b, c) {
459 var y = b;
460 x = function() { return " " + a + " " + y };
461 return String(a) + " " + String(b) + " " + String(c);
462 }
463
464 A(1, 2) + x();
465 `
466 testScript(SCRIPT, asciiString("1 2 undefined 1 2"), t)
467 }
468
469 func TestCallMoreArgs(t *testing.T) {
470 const SCRIPT = `
471 function A(a, b) {
472 var c = 4;
473 return a - b + c;
474 }
475
476 A(1, 2, 3);
477 `
478 testScript(SCRIPT, intToValue(3), t)
479 }
480
481 func TestCallMoreArgsDynamic(t *testing.T) {
482 const SCRIPT = `
483 function A(a, b) {
484 var c = 4;
485 if (false) {
486 eval("");
487 }
488 return a - b + c;
489 }
490
491 A(1, 2, 3);
492 `
493 testScript(SCRIPT, intToValue(3), t)
494 }
495
496 func TestCallLessArgsDynamic(t *testing.T) {
497 const SCRIPT = `
498 function A(a, b, c) {
499 // Make it stashful
500 function B() {
501 return a;
502 }
503 return String(a) + " " + String(b) + " " + String(c);
504 }
505
506 A(1, 2);
507 `
508 testScript(SCRIPT, asciiString("1 2 undefined"), t)
509 }
510
511 func TestCallLessArgsDynamicLocalVar(t *testing.T) {
512 const SCRIPT = `
513 function f(param) {
514 var a = 42;
515 if (false) {
516 eval("");
517 }
518 return a;
519 }
520 f();
521 `
522
523 testScript(SCRIPT, intToValue(42), t)
524 }
525
526
531
532 func TestNativeCall(t *testing.T) {
533 const SCRIPT = `
534 var o = Object(1);
535 Object.defineProperty(o, "test", {value: 42});
536 o.test;
537 `
538 testScript(SCRIPT, intToValue(42), t)
539 }
540
541 func TestJSCall(t *testing.T) {
542 const SCRIPT = `
543 function getter() {
544 return this.x;
545 }
546 var o = Object(1);
547 o.x = 42;
548 Object.defineProperty(o, "test", {get: getter});
549 o.test;
550 `
551 testScript(SCRIPT, intToValue(42), t)
552
553 }
554
555 func TestLoop1(t *testing.T) {
556 const SCRIPT = `
557 function A() {
558 var x = 1;
559 for (var i = 0; i < 1; i++) {
560 var x = 2;
561 }
562 return x;
563 }
564
565 A();
566 `
567 testScript(SCRIPT, intToValue(2), t)
568 }
569
570 func TestLoopBreak(t *testing.T) {
571 const SCRIPT = `
572 function A() {
573 var x = 1;
574 for (var i = 0; i < 1; i++) {
575 break;
576 var x = 2;
577 }
578 return x;
579 }
580
581 A();
582 `
583 testScript(SCRIPT, intToValue(1), t)
584 }
585
586 func TestForLoopOptionalExpr(t *testing.T) {
587 const SCRIPT = `
588 function A() {
589 var x = 1;
590 for (;;) {
591 break;
592 var x = 2;
593 }
594 return x;
595 }
596
597 A();
598 `
599 testScript(SCRIPT, intToValue(1), t)
600 }
601
602 func TestBlockBreak(t *testing.T) {
603 const SCRIPT = `
604 var rv = 0;
605 B1: {
606 rv = 1;
607 B2: {
608 rv = 2;
609 break B1;
610 }
611 rv = 3;
612 }
613 rv;
614 `
615 testScript(SCRIPT, intToValue(2), t)
616
617 }
618
619 func TestTry(t *testing.T) {
620 const SCRIPT = `
621 function A() {
622 var x = 1;
623 try {
624 x = 2;
625 } catch(e) {
626 x = 3;
627 } finally {
628 x = 4;
629 }
630 return x;
631 }
632
633 A();
634 `
635 testScript(SCRIPT, intToValue(4), t)
636 }
637
638 func TestTryOptionalCatchBinding(t *testing.T) {
639 const SCRIPT = `
640 try {
641 throw null;
642 } catch {
643 }
644 `
645 testScript(SCRIPT, _undefined, t)
646 }
647
648 func TestTryCatch(t *testing.T) {
649 const SCRIPT = `
650 function A() {
651 var x;
652 try {
653 throw 4;
654 } catch(e) {
655 x = e;
656 }
657 return x;
658 }
659
660 A();
661 `
662 testScript(SCRIPT, intToValue(4), t)
663 }
664
665 func TestTryCatchDirectEval(t *testing.T) {
666 const SCRIPT = `
667 function A() {
668 var x;
669 try {
670 throw 4;
671 } catch(e) {
672 eval("x = e");
673 }
674 return x;
675 }
676
677 A();
678 `
679 testScript(SCRIPT, intToValue(4), t)
680 }
681
682 func TestTryExceptionInCatch(t *testing.T) {
683 const SCRIPT = `
684 function A() {
685 var x;
686 try {
687 throw 4;
688 } catch(e) {
689 throw 5;
690 }
691 return x;
692 }
693
694 var rv;
695 try {
696 A();
697 } catch (e) {
698 rv = e;
699 }
700 rv;
701 `
702 testScript(SCRIPT, intToValue(5), t)
703 }
704
705 func TestTryContinueInCatch(t *testing.T) {
706 const SCRIPT = `
707 var c3 = 0, fin3 = 0;
708 while (c3 < 2) {
709 try {
710 throw "ex1";
711 } catch(er1) {
712 c3 += 1;
713 continue;
714 } finally {
715 fin3 = 1;
716 }
717 fin3 = 0;
718 }
719
720 fin3;
721 `
722 testScript(SCRIPT, intToValue(1), t)
723 }
724
725 func TestContinueInWith(t *testing.T) {
726 const SCRIPT = `
727 var x;
728 var o = {x: 0};
729 for (var i = 0; i < 2; i++) {
730 with(o) {
731 x = i;
732 if (i === 0) {
733 continue;
734 }
735 }
736 break;
737 }
738 x;
739 `
740 testScript(SCRIPT, _undefined, t)
741 }
742
743 func TestTryContinueInFinally(t *testing.T) {
744 const SCRIPT = `
745 var c3 = 0, fin3 = 0;
746 while (c3 < 2) {
747 try {
748 throw "ex1";
749 } catch(er1) {
750 c3 += 1;
751 } finally {
752 fin3 = 1;
753 continue;
754 }
755 fin3 = 0;
756 }
757
758 fin3;
759 `
760 testScript(SCRIPT, intToValue(1), t)
761 }
762
763 func TestTryBreakFinallyContinue(t *testing.T) {
764 const SCRIPT = `
765 for (var i = 0; i < 3; i++) {
766 try {
767 break;
768 } finally {
769 continue;
770 }
771 }
772 `
773 testScript(SCRIPT, _undefined, t)
774 }
775
776 func TestTryBreakFinallyContinueWithResult(t *testing.T) {
777 const SCRIPT = `
778 for (var i = 0; i < 3; i++) {
779 try {
780 true;
781 break;
782 } finally {
783 continue;
784 }
785 }
786 `
787 testScript(SCRIPT, _undefined, t)
788 }
789
790 func TestTryBreakFinallyContinueWithResult1(t *testing.T) {
791 const SCRIPT = `
792 for (var i = 0; i < 3; i++) {
793 try {
794 true;
795 break;
796 } finally {
797 var x = 1;
798 continue;
799 }
800 }
801 `
802 testScript(SCRIPT, _undefined, t)
803 }
804
805 func TestTryBreakFinallyContinueWithResultNested(t *testing.T) {
806 const SCRIPT = `
807 LOOP:
808 for (var i = 0; i < 3; i++) {
809 try {
810 if (true) {
811 false; break;
812 }
813 } finally {
814 if (true) {
815 true; continue;
816 }
817 }
818 }
819 `
820 testScript(SCRIPT, valueTrue, t)
821 }
822
823 func TestTryBreakOuterFinallyContinue(t *testing.T) {
824 const SCRIPT = `
825 let iCount = 0, jCount = 0;
826 OUTER: for (let i = 0; i < 1; i++) {
827 iCount++;
828 for (let j = 0; j < 2; j++) {
829 jCount++;
830 try {
831 break OUTER;
832 } finally {
833 continue;
834 }
835 }
836 }
837 ""+iCount+jCount;
838 `
839 testScript(SCRIPT, asciiString("12"), t)
840 }
841
842 func TestTryIllegalContinueWithFinallyOverride(t *testing.T) {
843 const SCRIPT = `
844 L: {
845 while (Math.random() > 0.5) {
846 try {
847 continue L;
848 } finally {
849 break;
850 }
851 }
852 }
853 `
854 _, err := Compile("", SCRIPT, false)
855 if err == nil {
856 t.Fatal("expected error")
857 }
858 }
859
860 func TestTryIllegalContinueWithFinallyOverrideNoLabel(t *testing.T) {
861 const SCRIPT = `
862 L: {
863 try {
864 continue;
865 } finally {
866 break L;
867 }
868 }
869 `
870 _, err := Compile("", SCRIPT, false)
871 if err == nil {
872 t.Fatal("expected error")
873 }
874 }
875
876 func TestTryIllegalContinueWithFinallyOverrideDummy(t *testing.T) {
877 const SCRIPT = `
878 L: {
879 while (false) {
880 try {
881 continue L;
882 } finally {
883 break;
884 }
885 }
886 }
887 `
888 _, err := Compile("", SCRIPT, false)
889 if err == nil {
890 t.Fatal("expected error")
891 }
892 }
893
894 func TestTryNoResult(t *testing.T) {
895 const SCRIPT = `
896 true;
897 L:
898 try {
899 break L;
900 } finally {
901 }
902 `
903 testScript(SCRIPT, _undefined, t)
904 }
905
906 func TestCatchLexicalEnv(t *testing.T) {
907 const SCRIPT = `
908 function F() {
909 try {
910 throw 1;
911 } catch (e) {
912 var x = e;
913 }
914 return x;
915 }
916
917 F();
918 `
919 testScript(SCRIPT, intToValue(1), t)
920 }
921
922 func TestThrowType(t *testing.T) {
923 const SCRIPT = `
924 function Exception(message) {
925 this.message = message;
926 }
927
928
929 function A() {
930 try {
931 throw new Exception("boo!");
932 } catch(e) {
933 return e;
934 }
935 }
936 var thrown = A();
937 thrown !== null && typeof thrown === "object" && thrown.constructor === Exception;
938 `
939 testScript(SCRIPT, valueTrue, t)
940 }
941
942 func TestThrowConstructorName(t *testing.T) {
943 const SCRIPT = `
944 function Exception(message) {
945 this.message = message;
946 }
947
948
949 function A() {
950 try {
951 throw new Exception("boo!");
952 } catch(e) {
953 return e;
954 }
955 }
956 A().constructor.name;
957 `
958
959 testScript(SCRIPT, asciiString("Exception"), t)
960 }
961
962 func TestThrowNativeConstructorName(t *testing.T) {
963 const SCRIPT = `
964
965
966 function A() {
967 try {
968 throw new TypeError();
969 } catch(e) {
970 return e;
971 }
972 }
973 A().constructor.name;
974 `
975
976 testScript(SCRIPT, asciiString("TypeError"), t)
977 }
978
979 func TestEmptyTryNoCatch(t *testing.T) {
980 const SCRIPT = `
981 var called = false;
982 try {
983 } finally {
984 called = true;
985 }
986 called;
987 `
988
989 testScript(SCRIPT, valueTrue, t)
990 }
991
992 func TestTryReturnFromCatch(t *testing.T) {
993 const SCRIPT = `
994 function f(o) {
995 var x = 42;
996
997 function innerf(o) {
998 try {
999 throw o;
1000 } catch (e) {
1001 return x;
1002 }
1003 }
1004
1005 return innerf(o);
1006 }
1007 f({});
1008 `
1009
1010 testScript(SCRIPT, valueInt(42), t)
1011 }
1012
1013 func TestTryCompletionResult(t *testing.T) {
1014 const SCRIPT = `
1015 99; do { -99; try { 39 } catch (e) { -1 } finally { break; -2 }; } while (false);
1016 `
1017
1018 testScript(SCRIPT, _undefined, t)
1019 }
1020
1021 func TestIfElse(t *testing.T) {
1022 const SCRIPT = `
1023 var rv;
1024 if (rv === undefined) {
1025 rv = "passed";
1026 } else {
1027 rv = "failed";
1028 }
1029 rv;
1030 `
1031
1032 testScript(SCRIPT, asciiString("passed"), t)
1033 }
1034
1035 func TestIfElseRetVal(t *testing.T) {
1036 const SCRIPT = `
1037 var x;
1038 if (x === undefined) {
1039 "passed";
1040 } else {
1041 "failed";
1042 }
1043 `
1044
1045 testScript(SCRIPT, asciiString("passed"), t)
1046 }
1047
1048 func TestWhileReturnValue(t *testing.T) {
1049 const SCRIPT = `
1050 var x = 0;
1051 while(true) {
1052 x = 1;
1053 break;
1054 }
1055 `
1056 testScript(SCRIPT, intToValue(1), t)
1057 }
1058
1059 func TestIfElseLabel(t *testing.T) {
1060 const SCRIPT = `
1061 var x = 0;
1062 abc: if (true) {
1063 x = 1;
1064 break abc;
1065 }
1066 `
1067 testScript(SCRIPT, intToValue(1), t)
1068 }
1069
1070 func TestIfMultipleLabels(t *testing.T) {
1071 const SCRIPT = `
1072 var x = 0;
1073 xyz:abc: if (true) {
1074 break xyz;
1075 }
1076 `
1077 testScript(SCRIPT, _undefined, t)
1078 }
1079
1080 func TestBreakOutOfTry(t *testing.T) {
1081 const SCRIPT = `
1082 function A() {
1083 var x = 1;
1084 B: {
1085 try {
1086 x = 2;
1087 } catch(e) {
1088 x = 3;
1089 } finally {
1090 break B;
1091 x = 4;
1092 }
1093 }
1094 return x;
1095 }
1096
1097 A();
1098 `
1099 testScript(SCRIPT, intToValue(2), t)
1100 }
1101
1102 func TestReturnOutOfTryNested(t *testing.T) {
1103 const SCRIPT = `
1104 function A() {
1105 function nested() {
1106 try {
1107 return 1;
1108 } catch(e) {
1109 return 2;
1110 }
1111 }
1112 return nested();
1113 }
1114
1115 A();
1116 `
1117 testScript(SCRIPT, intToValue(1), t)
1118 }
1119
1120 func TestContinueLoop(t *testing.T) {
1121 const SCRIPT = `
1122 function A() {
1123 var r = 0;
1124 for (var i = 0; i < 5; i++) {
1125 if (i > 1) {
1126 continue;
1127 }
1128 r++;
1129 }
1130 return r;
1131 }
1132
1133 A();
1134 `
1135 testScript(SCRIPT, intToValue(2), t)
1136 }
1137
1138 func TestContinueOutOfTry(t *testing.T) {
1139 const SCRIPT = `
1140 function A() {
1141 var r = 0;
1142 for (var i = 0; i < 5; i++) {
1143 try {
1144 if (i > 1) {
1145 continue;
1146 }
1147 } catch(e) {
1148 return 99;
1149 }
1150 r++;
1151 }
1152 return r;
1153 }
1154
1155 A();
1156 `
1157 testScript(SCRIPT, intToValue(2), t)
1158 }
1159
1160 func TestThisInCatch(t *testing.T) {
1161 const SCRIPT = `
1162 function O() {
1163 try {
1164 f();
1165 } catch (e) {
1166 this.value = e.toString();
1167 }
1168 }
1169
1170 function f() {
1171 throw "ex";
1172 }
1173
1174 var o = new O();
1175 o.value;
1176 `
1177 testScript(SCRIPT, asciiString("ex"), t)
1178 }
1179
1180 func TestNestedTry(t *testing.T) {
1181 const SCRIPT = `
1182 var ex;
1183 try {
1184 throw "ex1";
1185 } catch (er1) {
1186 try {
1187 throw "ex2";
1188 } catch (er1) {
1189 ex = er1;
1190 }
1191 }
1192 ex;
1193 `
1194 testScript(SCRIPT, asciiString("ex2"), t)
1195 }
1196
1197 func TestNestedTryInStashlessFunc(t *testing.T) {
1198 const SCRIPT = `
1199 function f() {
1200 var ex1, ex2;
1201 try {
1202 throw "ex1";
1203 } catch (er1) {
1204 try {
1205 throw "ex2";
1206 } catch (er1) {
1207 ex2 = er1;
1208 }
1209 ex1 = er1;
1210 }
1211 return ex1 == "ex1" && ex2 == "ex2";
1212 }
1213 f();
1214 `
1215 testScript(SCRIPT, valueTrue, t)
1216 }
1217
1218 func TestEvalLexicalDecl(t *testing.T) {
1219 const SCRIPT = `
1220 eval("let x = true; x;");
1221 `
1222 testScript(SCRIPT, valueTrue, t)
1223 }
1224
1225 func TestEvalInCatchInStashlessFunc(t *testing.T) {
1226 const SCRIPT = `
1227 function f() {
1228 var ex;
1229 try {
1230 throw "ex1";
1231 } catch (er1) {
1232 eval("ex = er1");
1233 }
1234 return ex;
1235 }
1236 f();
1237 `
1238 testScript(SCRIPT, asciiString("ex1"), t)
1239 }
1240
1241 func TestCatchClosureInStashlessFunc(t *testing.T) {
1242 const SCRIPT = `
1243 function f() {
1244 var ex;
1245 try {
1246 throw "ex1";
1247 } catch (er1) {
1248 return function() {
1249 return er1;
1250 }
1251 }
1252 }
1253 f()();
1254 `
1255 testScript(SCRIPT, asciiString("ex1"), t)
1256 }
1257
1258 func TestCatchVarNotUsedInStashlessFunc(t *testing.T) {
1259 const SCRIPT = `
1260 function f() {
1261 var ex;
1262 try {
1263 throw "ex1";
1264 } catch (er1) {
1265 ex = "ok";
1266 }
1267 return ex;
1268 }
1269 f();
1270 `
1271 testScript(SCRIPT, asciiString("ok"), t)
1272 }
1273
1274 func TestNew(t *testing.T) {
1275 const SCRIPT = `
1276 function O() {
1277 this.x = 42;
1278 }
1279
1280 new O().x;
1281 `
1282
1283 testScript(SCRIPT, intToValue(42), t)
1284 }
1285
1286 func TestStringConstructor(t *testing.T) {
1287 const SCRIPT = `
1288 function F() {
1289 return String(33) + " " + String("cows");
1290 }
1291
1292 F();
1293 `
1294 testScript(SCRIPT, asciiString("33 cows"), t)
1295 }
1296
1297 func TestError(t *testing.T) {
1298 const SCRIPT = `
1299 function F() {
1300 return new Error("test");
1301 }
1302
1303 var e = F();
1304 e.message == "test" && e.name == "Error";
1305 `
1306 testScript(SCRIPT, valueTrue, t)
1307 }
1308
1309 func TestTypeError(t *testing.T) {
1310 const SCRIPT = `
1311 function F() {
1312 return new TypeError("test");
1313 }
1314
1315 var e = F();
1316 e.message == "test" && e.name == "TypeError";
1317 `
1318
1319 testScript(SCRIPT, valueTrue, t)
1320 }
1321
1322 func TestToString(t *testing.T) {
1323 const SCRIPT = `
1324 var o = {x: 42};
1325 o.toString = function() {
1326 return String(this.x);
1327 }
1328
1329 var o1 = {};
1330 o.toString() + " ### " + o1.toString();
1331 `
1332 testScript(SCRIPT, asciiString("42 ### [object Object]"), t)
1333 }
1334
1335 func TestEvalOrder(t *testing.T) {
1336 const SCRIPT = `
1337 var o = {f: function() {return 42}, x: 0};
1338 var trace = "";
1339
1340 function F1() {
1341 trace += "First!";
1342 return o;
1343 }
1344
1345 function F2() {
1346 trace += "Second!";
1347 return "f";
1348 }
1349
1350 function F3() {
1351 trace += "Third!";
1352 }
1353
1354 var rv = F1()[F2()](F3());
1355 rv += trace;
1356 rv;
1357 `
1358
1359 testScript(SCRIPT, asciiString("42First!Second!Third!"), t)
1360 }
1361
1362 func TestPostfixIncBracket(t *testing.T) {
1363 const SCRIPT = `
1364 var o = {x: 42};
1365 var trace = "";
1366
1367 function F1() {
1368 trace += "First!";
1369 return o;
1370 }
1371
1372 function F2() {
1373 trace += "Second!";
1374 return "x";
1375 }
1376
1377
1378 var rv = F1()[F2()]++;
1379 rv + trace + o.x;
1380 `
1381 testScript(SCRIPT, asciiString("42First!Second!43"), t)
1382 }
1383
1384 func TestPostfixIncDot(t *testing.T) {
1385 const SCRIPT = `
1386 var o = {x: 42};
1387 var trace = "";
1388
1389 function F1() {
1390 trace += "First!";
1391 return o;
1392 }
1393
1394 var rv = F1().x++;
1395 rv + trace + o.x;
1396 `
1397 testScript(SCRIPT, asciiString("42First!43"), t)
1398 }
1399
1400 func TestPrefixIncBracket(t *testing.T) {
1401 const SCRIPT = `
1402 var o = {x: 42};
1403 var trace = "";
1404
1405 function F1() {
1406 trace += "First!";
1407 return o;
1408 }
1409
1410 function F2() {
1411 trace += "Second!";
1412 return "x";
1413 }
1414
1415
1416 var rv = ++F1()[F2()];
1417 rv + trace + o.x;
1418 `
1419 testScript(SCRIPT, asciiString("43First!Second!43"), t)
1420 }
1421
1422 func TestPrefixIncDot(t *testing.T) {
1423 const SCRIPT = `
1424 var o = {x: 42};
1425 var trace = "";
1426
1427 function F1() {
1428 trace += "First!";
1429 return o;
1430 }
1431
1432 var rv = ++F1().x;
1433 rv + trace + o.x;
1434 `
1435 testScript(SCRIPT, asciiString("43First!43"), t)
1436 }
1437
1438 func TestPostDecObj(t *testing.T) {
1439 const SCRIPT = `
1440 var object = {valueOf: function() {return 1}};
1441 var y = object--;
1442 var ok = false;
1443 if (y === 1) {
1444 ok = true;
1445 }
1446 ok;
1447 `
1448
1449 testScript(SCRIPT, valueTrue, t)
1450 }
1451
1452 func TestPropAcc1(t *testing.T) {
1453 const SCRIPT = `
1454 1..toString()
1455 `
1456
1457 testScript(SCRIPT, asciiString("1"), t)
1458 }
1459
1460 func TestEvalDirect(t *testing.T) {
1461 const SCRIPT = `
1462 var rv = false;
1463 function foo(){ rv = true; }
1464
1465 var o = { };
1466 function f() {
1467 try {
1468 eval("o.bar( foo() );");
1469 } catch (e) {
1470 }
1471 }
1472 f();
1473 rv;
1474 `
1475 testScript(SCRIPT, valueTrue, t)
1476 }
1477
1478 func TestEvalRet(t *testing.T) {
1479 const SCRIPT = `
1480 eval("for (var i = 0; i < 3; i++) {i}")
1481 `
1482
1483 testScript(SCRIPT, valueInt(2), t)
1484 }
1485
1486 func TestEvalFunctionDecl(t *testing.T) {
1487 const SCRIPT = `
1488 eval("function F() {}")
1489 `
1490
1491 testScript(SCRIPT, _undefined, t)
1492 }
1493
1494 func TestEvalFunctionExpr(t *testing.T) {
1495 const SCRIPT = `
1496 eval("(function F() {return 42;})")()
1497 `
1498
1499 testScript(SCRIPT, intToValue(42), t)
1500 }
1501
1502 func TestEvalDirectScope(t *testing.T) {
1503 const SCRIPT = `
1504 var __10_4_2_1_3 = "str";
1505 function testcase() {
1506 var __10_4_2_1_3 = "str1";
1507 try {
1508 throw "error";
1509 } catch (e) {
1510 var __10_4_2_1_3 = "str2";
1511 return eval("__10_4_2_1_3");
1512 }
1513 }
1514 testcase();
1515 `
1516
1517 testScript(SCRIPT, asciiString("str2"), t)
1518 }
1519
1520 func TestEvalDirectScope1(t *testing.T) {
1521 const SCRIPT = `
1522 'use strict';
1523 var __10_4_2_1_5 = "str";
1524 function testcase() {
1525 var __10_4_2_1_5 = "str1";
1526 var r = eval("\
1527 var __10_4_2_1_5 = \'str2\'; \
1528 eval(\"\'str2\' === __10_4_2_1_5\")\
1529 ");
1530 return r;
1531 }
1532 testcase();
1533 `
1534
1535 testScript(SCRIPT, valueTrue, t)
1536 }
1537
1538 func TestEvalDirectCreateBinding(t *testing.T) {
1539 const SCRIPT = `
1540 function f() {
1541 eval("var x = true");
1542 return x;
1543 }
1544 var res = f();
1545 var thrown = false;
1546 try {
1547 x;
1548 } catch(e) {
1549 if (e instanceof ReferenceError) {
1550 thrown = true;
1551 } else {
1552 throw e;
1553 }
1554 }
1555 res && thrown;
1556 `
1557
1558 testScript(SCRIPT, valueTrue, t)
1559 }
1560
1561 func TestEvalDirectCreateBinding1(t *testing.T) {
1562 const SCRIPT = `
1563 function f() {
1564 eval("let x = 1; var y = 2; function f1() {return x};");
1565 assert.throws(ReferenceError, function() { x });
1566 return ""+y+f1();
1567 }
1568 f();
1569 `
1570
1571 testScriptWithTestLib(SCRIPT, asciiString("21"), t)
1572 }
1573
1574 func TestEvalDirectCreateBinding3(t *testing.T) {
1575 const SCRIPT = `
1576 function f() {
1577 let x;
1578 try {
1579 eval("var y=1, x=2");
1580 } catch(e) {}
1581 return y;
1582 }
1583 assert.throws(ReferenceError, f);
1584 `
1585
1586 testScriptWithTestLib(SCRIPT, _undefined, t)
1587 }
1588
1589 func TestEvalGlobalStrict(t *testing.T) {
1590 const SCRIPT = `
1591 'use strict';
1592 var evalStr =
1593 'for (var x in this) {\n'+
1594 ' if ( x === \'Math\' ) {\n'+
1595 ' }\n'+
1596 '}\n';
1597
1598 eval(evalStr);
1599 `
1600
1601 testScript(SCRIPT, _undefined, t)
1602 }
1603
1604 func TestEvalEmptyStrict(t *testing.T) {
1605 const SCRIPT = `
1606 'use strict';
1607 eval("");
1608 `
1609
1610 testScript(SCRIPT, _undefined, t)
1611 }
1612
1613 func TestEvalFuncDecl(t *testing.T) {
1614 const SCRIPT = `
1615 'use strict';
1616 var funcA = eval("function __funcA(__arg){return __arg;}; __funcA");
1617 typeof funcA;
1618 `
1619
1620 testScript(SCRIPT, asciiString("function"), t)
1621 }
1622
1623 func TestGetAfterSet(t *testing.T) {
1624 const SCRIPT = `
1625 function f() {
1626 var x = 1;
1627 return x;
1628 }
1629 `
1630
1631 testScript(SCRIPT, _undefined, t)
1632 }
1633
1634 func TestForLoopRet(t *testing.T) {
1635 const SCRIPT = `
1636 for (var i = 0; i < 20; i++) { if (i > 2) {break;} else { i }}
1637 `
1638
1639 testScript(SCRIPT, _undefined, t)
1640 }
1641
1642 func TestForLoopRet1(t *testing.T) {
1643 const SCRIPT = `
1644 for (var i = 0; i < 20; i++) { if (i > 2) {42;; {L:{break;}}} else { i }}
1645 `
1646
1647 testScript(SCRIPT, intToValue(42), t)
1648 }
1649
1650 func TestForInLoopRet(t *testing.T) {
1651 const SCRIPT = `
1652 var o = [1, 2, 3, 4];
1653 for (var i in o) { if (i > 2) {break;} else { i }}
1654 `
1655
1656 testScript(SCRIPT, _undefined, t)
1657 }
1658
1659 func TestForInLoopRet1(t *testing.T) {
1660 const SCRIPT = `
1661 var o = {};
1662 o.x = 1;
1663 o.y = 2;
1664 for (var i in o) {
1665 true;
1666 }
1667
1668 `
1669
1670 testScript(SCRIPT, valueTrue, t)
1671 }
1672
1673 func TestDoWhileLoopRet(t *testing.T) {
1674 const SCRIPT = `
1675 var i = 0;
1676 do {
1677 if (i > 2) {
1678 break;
1679 } else {
1680 i;
1681 }
1682 } while (i++ < 20);
1683 `
1684
1685 testScript(SCRIPT, _undefined, t)
1686 }
1687
1688 func TestDoWhileContinueRet(t *testing.T) {
1689 const SCRIPT = `
1690 var i = 0;
1691 do {
1692 if (i > 2) {
1693 true;
1694 continue;
1695 } else {
1696 i;
1697 }
1698 } while (i++ < 20);
1699 `
1700
1701 testScript(SCRIPT, valueTrue, t)
1702 }
1703
1704 func TestWhileLoopRet(t *testing.T) {
1705 const SCRIPT = `
1706 var i; while (i < 20) { if (i > 2) {break;} else { i++ }}
1707 `
1708
1709 testScript(SCRIPT, _undefined, t)
1710 }
1711
1712 func TestLoopRet1(t *testing.T) {
1713 const SCRIPT = `
1714 for (var i = 0; i < 20; i++) { }
1715 `
1716
1717 testScript(SCRIPT, _undefined, t)
1718 }
1719
1720 func TestInstanceof(t *testing.T) {
1721 const SCRIPT = `
1722 var rv;
1723 try {
1724 true();
1725 } catch (e) {
1726 rv = e instanceof TypeError;
1727 }
1728 rv;
1729 `
1730
1731 testScript(SCRIPT, valueTrue, t)
1732 }
1733
1734 func TestStrictAssign(t *testing.T) {
1735 const SCRIPT = `
1736 'use strict';
1737 var rv;
1738 var called = false;
1739 function F() {
1740 called = true;
1741 return 1;
1742 }
1743 try {
1744 x = F();
1745 } catch (e) {
1746 rv = e instanceof ReferenceError;
1747 }
1748 rv + " " + called;
1749 `
1750
1751 testScript(SCRIPT, asciiString("true true"), t)
1752 }
1753
1754 func TestStrictScope(t *testing.T) {
1755 const SCRIPT = `
1756 var rv;
1757 var called = false;
1758 function F() {
1759 'use strict';
1760 x = 1;
1761 }
1762 try {
1763 F();
1764 } catch (e) {
1765 rv = e instanceof ReferenceError;
1766 }
1767 x = 1;
1768 rv + " " + x;
1769 `
1770
1771 testScript(SCRIPT, asciiString("true 1"), t)
1772 }
1773
1774 func TestStringObj(t *testing.T) {
1775 const SCRIPT = `
1776 var s = new String("test");
1777 s[0] + s[2] + s[1];
1778 `
1779
1780 testScript(SCRIPT, asciiString("tse"), t)
1781 }
1782
1783 func TestStringPrimitive(t *testing.T) {
1784 const SCRIPT = `
1785 var s = "test";
1786 s[0] + s[2] + s[1];
1787 `
1788
1789 testScript(SCRIPT, asciiString("tse"), t)
1790 }
1791
1792 func TestCallGlobalObject(t *testing.T) {
1793 const SCRIPT = `
1794 var rv;
1795 try {
1796 this();
1797 } catch (e) {
1798 rv = e instanceof TypeError
1799 }
1800 rv;
1801 `
1802
1803 testScript(SCRIPT, valueTrue, t)
1804 }
1805
1806 func TestFuncLength(t *testing.T) {
1807 const SCRIPT = `
1808 function F(x, y) {
1809
1810 }
1811 F.length
1812 `
1813
1814 testScript(SCRIPT, intToValue(2), t)
1815 }
1816
1817 func TestNativeFuncLength(t *testing.T) {
1818 const SCRIPT = `
1819 eval.length + Object.defineProperty.length + String.length
1820 `
1821
1822 testScript(SCRIPT, intToValue(5), t)
1823 }
1824
1825 func TestArguments(t *testing.T) {
1826 const SCRIPT = `
1827 function F() {
1828 return arguments.length + " " + arguments[1];
1829 }
1830
1831 F(1,2,3)
1832 `
1833
1834 testScript(SCRIPT, asciiString("3 2"), t)
1835 }
1836
1837 func TestArgumentsPut(t *testing.T) {
1838 const SCRIPT = `
1839 function F(x, y) {
1840 arguments[0] -= arguments[1];
1841 return x;
1842 }
1843
1844 F(5, 2)
1845 `
1846
1847 testScript(SCRIPT, intToValue(3), t)
1848 }
1849
1850 func TestArgumentsPutStrict(t *testing.T) {
1851 const SCRIPT = `
1852 function F(x, y) {
1853 'use strict';
1854 arguments[0] -= arguments[1];
1855 return x;
1856 }
1857
1858 F(5, 2)
1859 `
1860
1861 testScript(SCRIPT, intToValue(5), t)
1862 }
1863
1864 func TestArgumentsExtra(t *testing.T) {
1865 const SCRIPT = `
1866 function F(x, y) {
1867 return arguments[2];
1868 }
1869
1870 F(1, 2, 42)
1871 `
1872
1873 testScript(SCRIPT, intToValue(42), t)
1874 }
1875
1876 func TestArgumentsExist(t *testing.T) {
1877 const SCRIPT = `
1878 function F(x, arguments) {
1879 return arguments;
1880 }
1881
1882 F(1, 42)
1883 `
1884
1885 testScript(SCRIPT, intToValue(42), t)
1886 }
1887
1888 func TestArgumentsDelete(t *testing.T) {
1889 const SCRIPT = `
1890 function f(x) {
1891 delete arguments[0];
1892 arguments[0] = 42;
1893 return x;
1894 }
1895 f(1)
1896 `
1897
1898 testScript(SCRIPT, intToValue(1), t)
1899 }
1900
1901 func TestArgumentsInEval(t *testing.T) {
1902 const SCRIPT = `
1903 function f() {
1904 return eval("arguments");
1905 }
1906 f(1)[0];
1907 `
1908
1909 testScript(SCRIPT, intToValue(1), t)
1910 }
1911
1912 func TestArgumentsRedeclareInEval(t *testing.T) {
1913 const SCRIPT = `
1914 assert.sameValue("arguments" in this, false, "No global 'arguments' binding");
1915
1916 function f(p = eval("var arguments = 'param'"), arguments) {}
1917 assert.throws(SyntaxError, f);
1918
1919 assert.sameValue("arguments" in this, false, "No global 'arguments' binding");
1920 `
1921
1922 testScriptWithTestLib(SCRIPT, _undefined, t)
1923 }
1924
1925 func TestArgumentsRedeclareArrow(t *testing.T) {
1926 const SCRIPT = `
1927 const oldArguments = globalThis.arguments;
1928 let count = 0;
1929 const f = (p = eval("var arguments = 'param'"), q = () => arguments) => {
1930 var arguments = "local";
1931 assert.sameValue(arguments, "local", "arguments");
1932 assert.sameValue(q(), "param", "q");
1933 count++;
1934 }
1935 f();
1936 assert.sameValue(count, 1);
1937 assert.sameValue(globalThis.arguments, oldArguments, "globalThis.arguments unchanged");
1938 `
1939 testScriptWithTestLib(SCRIPT, _undefined, t)
1940 }
1941
1942 func TestEvalParamWithDef(t *testing.T) {
1943 const SCRIPT = `
1944 function f(param = 0) {
1945 eval("var param = 1");
1946 return param;
1947 }
1948 f();
1949 `
1950
1951 testScript(SCRIPT, valueInt(1), t)
1952 }
1953
1954 func TestArgumentsRedefinedAsLetDyn(t *testing.T) {
1955 const SCRIPT = `
1956 function f() {
1957 let arguments;
1958 eval(""); // force dynamic scope
1959 return arguments;
1960 }
1961
1962 f(1,2);
1963 `
1964
1965 testScript(SCRIPT, _undefined, t)
1966 }
1967
1968 func TestWith(t *testing.T) {
1969 const SCRIPT = `
1970 var b = 1;
1971 var o = {a: 41};
1972 with(o) {
1973 a += b;
1974 }
1975 o.a;
1976
1977 `
1978
1979 testScript(SCRIPT, intToValue(42), t)
1980 }
1981
1982 func TestWithInFunc(t *testing.T) {
1983 const SCRIPT = `
1984 function F() {
1985 var b = 1;
1986 var c = 0;
1987 var o = {a: 40, c: 1};
1988 with(o) {
1989 a += b + c;
1990 }
1991 return o.a;
1992 }
1993
1994 F();
1995 `
1996
1997 testScript(SCRIPT, intToValue(42), t)
1998 }
1999
2000 func TestAssignNonExtendable(t *testing.T) {
2001 const SCRIPT = `
2002 'use strict';
2003
2004 function F() {
2005 this.x = 1;
2006 }
2007
2008 var o = new F();
2009 Object.preventExtensions(o);
2010 o.x = 42;
2011 o.x;
2012 `
2013
2014 testScript(SCRIPT, intToValue(42), t)
2015 }
2016
2017 func TestAssignNonExtendable1(t *testing.T) {
2018 const SCRIPT = `
2019 'use strict';
2020
2021 function F() {
2022 }
2023
2024 var o = new F();
2025 var rv;
2026
2027 Object.preventExtensions(o);
2028 try {
2029 o.x = 42;
2030 } catch (e) {
2031 rv = e.constructor === TypeError;
2032 }
2033
2034 rv += " " + o.x;
2035 rv;
2036 `
2037
2038 testScript(SCRIPT, asciiString("true undefined"), t)
2039 }
2040
2041 func TestAssignStrict(t *testing.T) {
2042 const SCRIPT = `
2043 'use strict';
2044
2045 try {
2046 eval("eval = 42");
2047 } catch(e) {
2048 var rv = e instanceof SyntaxError
2049 }
2050 rv;
2051 `
2052
2053 testScript(SCRIPT, valueTrue, t)
2054 }
2055
2056 func TestIllegalArgmentName(t *testing.T) {
2057 const SCRIPT = `
2058 'use strict';
2059
2060 try {
2061 eval("function F(eval) {}");
2062 } catch (e) {
2063 var rv = e instanceof SyntaxError
2064 }
2065 rv;
2066 `
2067
2068 testScript(SCRIPT, valueTrue, t)
2069 }
2070
2071 func TestFunction(t *testing.T) {
2072 const SCRIPT = `
2073
2074 var f0 = Function("");
2075 var f1 = Function("return ' one'");
2076 var f2 = Function("arg", "return ' ' + arg");
2077 f0() + f1() + f2("two");
2078 `
2079
2080 testScript(SCRIPT, asciiString("undefined one two"), t)
2081 }
2082
2083 func TestFunction1(t *testing.T) {
2084 const SCRIPT = `
2085
2086 var f = function f1(count) {
2087 if (count == 0) {
2088 return true;
2089 }
2090 return f1(count-1);
2091 }
2092
2093 f(1);
2094 `
2095
2096 testScript(SCRIPT, valueTrue, t)
2097 }
2098
2099 func TestFunction2(t *testing.T) {
2100 const SCRIPT = `
2101 var trace = "";
2102 function f(count) {
2103 trace += "f("+count+")";
2104 if (count == 0) {
2105 return;
2106 }
2107 return f(count-1);
2108 }
2109
2110 function f1() {
2111 trace += "f1";
2112 }
2113
2114 var f2 = f;
2115 f = f1;
2116 f2(1);
2117 trace;
2118
2119 `
2120
2121 testScript(SCRIPT, asciiString("f(1)f1"), t)
2122 }
2123
2124 func TestFunctionToString(t *testing.T) {
2125 const SCRIPT = `
2126
2127 Function("arg1", "arg2", "return 42").toString();
2128 `
2129
2130 testScript(SCRIPT, asciiString("function anonymous(arg1,arg2\n) {\nreturn 42\n}"), t)
2131 }
2132
2133 func TestObjectLiteral(t *testing.T) {
2134 const SCRIPT = `
2135 var getterCalled = false;
2136 var setterCalled = false;
2137
2138 var o = {get x() {getterCalled = true}, set x(_) {setterCalled = true}};
2139
2140 o.x;
2141 o.x = 42;
2142
2143 getterCalled && setterCalled;
2144 `
2145
2146 testScript(SCRIPT, valueTrue, t)
2147 }
2148
2149 func TestConst(t *testing.T) {
2150 const SCRIPT = `
2151
2152 var v1 = true && true;
2153 var v2 = 1/(-1 * 0);
2154 var v3 = 1 == 2 || v1;
2155 var v4 = true && false
2156 v1 === true && v2 === -Infinity && v3 === v1 && v4 === false;
2157 `
2158
2159 testScript(SCRIPT, valueTrue, t)
2160 }
2161
2162 func TestConstWhile(t *testing.T) {
2163 const SCRIPT = `
2164 var c = 0;
2165 while (2 + 2 === 4) {
2166 if (++c > 9) {
2167 break;
2168 }
2169 }
2170 c === 10;
2171 `
2172
2173 testScript(SCRIPT, valueTrue, t)
2174 }
2175
2176 func TestConstWhileThrow(t *testing.T) {
2177 const SCRIPT = `
2178 var thrown = false;
2179 try {
2180 while ('s' in true) {
2181 break;
2182 }
2183 } catch (e) {
2184 thrown = e instanceof TypeError
2185 }
2186 thrown;
2187 `
2188
2189 testScript(SCRIPT, valueTrue, t)
2190 }
2191
2192 func TestDupParams(t *testing.T) {
2193 const SCRIPT = `
2194 function F(x, y, x) {
2195 return x;
2196 }
2197
2198 F(1, 2);
2199 `
2200
2201 testScript(SCRIPT, _undefined, t)
2202 }
2203
2204 func TestUseUnsuppliedParam(t *testing.T) {
2205 const SCRIPT = `
2206 function getMessage(message) {
2207 if (message === undefined) {
2208 message = '';
2209 }
2210 message += " 123 456";
2211 return message;
2212 }
2213
2214 getMessage();
2215 `
2216
2217 testScript(SCRIPT, asciiString(" 123 456"), t)
2218 }
2219
2220 func TestForInLetWithInitializer(t *testing.T) {
2221 const SCRIPT = `for (let x = 3 in {}) { }`
2222 _, err := Compile("", SCRIPT, false)
2223 if err == nil {
2224 t.Fatal("Expected error")
2225 }
2226 }
2227
2228 func TestForInLoop(t *testing.T) {
2229 const SCRIPT = `
2230 function Proto() {}
2231 Proto.prototype.x = 42;
2232 var o = new Proto();
2233 o.y = 44;
2234 o.x = 45;
2235 var hasX = false;
2236 var hasY = false;
2237
2238 for (var i in o) {
2239 switch(i) {
2240 case "x":
2241 if (hasX) {
2242 throw new Error("Already has X");
2243 }
2244 hasX = true;
2245 break;
2246 case "y":
2247 if (hasY) {
2248 throw new Error("Already has Y");
2249 }
2250 hasY = true;
2251 break;
2252 }
2253 }
2254
2255 hasX && hasY;
2256 `
2257
2258 testScript(SCRIPT, valueTrue, t)
2259 }
2260
2261 func TestWhileLoopResult(t *testing.T) {
2262 const SCRIPT = `
2263 while(false);
2264
2265 `
2266
2267 testScript(SCRIPT, _undefined, t)
2268 }
2269
2270 func TestEmptySwitch(t *testing.T) {
2271 const SCRIPT = `
2272 switch(1){}
2273 `
2274
2275 testScript(SCRIPT, _undefined, t)
2276 }
2277
2278 func TestEmptyDoWhile(t *testing.T) {
2279 const SCRIPT = `
2280 do {} while(false)
2281 `
2282
2283 testScript(SCRIPT, _undefined, t)
2284 }
2285
2286 func TestSwitch(t *testing.T) {
2287 const SCRIPT = `
2288 function F(x) {
2289 var i = 0;
2290 switch (x) {
2291 case 0:
2292 i++;
2293 case 1:
2294 i++;
2295 default:
2296 i++;
2297 case 2:
2298 i++;
2299 break;
2300 case 3:
2301 i++;
2302 }
2303 return i;
2304 }
2305
2306 F(0) + F(1) + F(2) + F(4);
2307
2308 `
2309
2310 testScript(SCRIPT, intToValue(10), t)
2311 }
2312
2313 func TestSwitchDefFirst(t *testing.T) {
2314 const SCRIPT = `
2315 function F(x) {
2316 var i = 0;
2317 switch (x) {
2318 default:
2319 i++;
2320 case 0:
2321 i++;
2322 case 1:
2323 i++;
2324 case 2:
2325 i++;
2326 break;
2327 case 3:
2328 i++;
2329 }
2330 return i;
2331 }
2332
2333 F(0) + F(1) + F(2) + F(4);
2334
2335 `
2336
2337 testScript(SCRIPT, intToValue(10), t)
2338 }
2339
2340 func TestSwitchResult(t *testing.T) {
2341 const SCRIPT = `
2342 var x = 2;
2343
2344 switch (x) {
2345 case 0:
2346 "zero";
2347 case 1:
2348 "one";
2349 case 2:
2350 "two";
2351 break;
2352 case 3:
2353 "three";
2354 default:
2355 "default";
2356 }
2357 `
2358
2359 testScript(SCRIPT, asciiString("two"), t)
2360 }
2361
2362 func TestSwitchResult1(t *testing.T) {
2363 const SCRIPT = `
2364 var x = 0;
2365 switch (x) { case 0: "two"; case 1: break}
2366 `
2367
2368 testScript(SCRIPT, asciiString("two"), t)
2369 }
2370
2371 func TestSwitchResult2(t *testing.T) {
2372 const SCRIPT = `
2373 6; switch ("a") { case "a": 7; case "b": }
2374 `
2375
2376 testScript(SCRIPT, valueInt(7), t)
2377 }
2378
2379 func TestSwitchResultJumpIntoEmptyEval(t *testing.T) {
2380 const SCRIPT = `
2381 function t(x) {
2382 return eval("switch(x) { case 1: 2; break; case 2: let x = 1; case 3: x+2; break; case 4: default: 9}");
2383 }
2384 ""+t(2)+t();
2385 `
2386
2387 testScript(SCRIPT, asciiString("39"), t)
2388 }
2389
2390 func TestSwitchResultJumpIntoEmpty(t *testing.T) {
2391 const SCRIPT = `
2392 switch(2) { case 1: 2; break; case 2: let x = 1; case 3: x+2; case 4: {let y = 2}; break; default: 9};
2393 `
2394
2395 testScript(SCRIPT, valueInt(3), t)
2396 }
2397
2398 func TestSwitchLexical(t *testing.T) {
2399 const SCRIPT = `
2400 switch (true) { case true: let x = 1; }
2401 `
2402
2403 testScript(SCRIPT, _undefined, t)
2404 }
2405
2406 func TestSwitchBreakOuter(t *testing.T) {
2407 const SCRIPT = `
2408 LOOP:
2409 for (let i = 0; i < 10; i++) {
2410 switch (i) {
2411 case 0:
2412 continue;
2413 case 1:
2414 let x = 1;
2415 continue;
2416 case 2:
2417 try {
2418 x++;
2419 } catch (e) {
2420 if (e instanceof ReferenceError) {
2421 break LOOP;
2422 }
2423 }
2424 throw new Error("Exception was not thrown");
2425 }
2426 }
2427 `
2428
2429 testScript(SCRIPT, _undefined, t)
2430 }
2431
2432 func TestIfBreakResult(t *testing.T) {
2433 const SCRIPT = `
2434 L: {if (true) {42;} break L;}
2435 `
2436
2437 testScript(SCRIPT, intToValue(42), t)
2438 }
2439
2440 func TestSwitchNoMatch(t *testing.T) {
2441 const SCRIPT = `
2442 var result;
2443 var x;
2444 switch (x) {
2445 case 0:
2446 result = "2";
2447 break;
2448 }
2449
2450 result;
2451
2452 `
2453
2454 testScript(SCRIPT, _undefined, t)
2455 }
2456
2457 func TestSwitchNoMatchNoDefault(t *testing.T) {
2458 const SCRIPT = `
2459 switch (1) {
2460 case 0:
2461 }
2462 `
2463
2464 testScript(SCRIPT, _undefined, t)
2465 }
2466
2467 func TestSwitchNoMatchNoDefaultNoResult(t *testing.T) {
2468 const SCRIPT = `
2469 switch (1) {
2470 case 0:
2471 }
2472 42;
2473 `
2474
2475 testScript(SCRIPT, intToValue(42), t)
2476 }
2477
2478 func TestSwitchNoMatchNoDefaultNoResultMatch(t *testing.T) {
2479 const SCRIPT = `
2480 switch (1) {
2481 case 1:
2482 }
2483 42;
2484 `
2485
2486 testScript(SCRIPT, intToValue(42), t)
2487 }
2488
2489 func TestEmptySwitchNoResult(t *testing.T) {
2490 const SCRIPT = `
2491 switch (1) {}
2492 42;
2493 `
2494
2495 testScript(SCRIPT, intToValue(42), t)
2496 }
2497
2498 func TestGetOwnPropertyNames(t *testing.T) {
2499 const SCRIPT = `
2500 var o = {
2501 prop1: 42,
2502 prop2: "test"
2503 }
2504
2505 var hasProp1 = false;
2506 var hasProp2 = false;
2507
2508 var names = Object.getOwnPropertyNames(o);
2509 for (var i in names) {
2510 var p = names[i];
2511 switch(p) {
2512 case "prop1":
2513 hasProp1 = true;
2514 break;
2515 case "prop2":
2516 hasProp2 = true;
2517 break;
2518 }
2519 }
2520
2521 hasProp1 && hasProp2;
2522 `
2523
2524 testScript(SCRIPT, valueTrue, t)
2525 }
2526
2527 func TestArrayLiteral(t *testing.T) {
2528 const SCRIPT = `
2529
2530 var f1Called = false;
2531 var f2Called = false;
2532 var f3Called = false;
2533 var errorThrown = false;
2534
2535 function F1() {
2536 f1Called = true;
2537 }
2538
2539 function F2() {
2540 f2Called = true;
2541 }
2542
2543 function F3() {
2544 f3Called = true;
2545 }
2546
2547
2548 try {
2549 var a = [F1(), x(F3()), F2()];
2550 } catch(e) {
2551 if (e instanceof ReferenceError) {
2552 errorThrown = true;
2553 } else {
2554 throw e;
2555 }
2556 }
2557
2558 f1Called && !f2Called && f3Called && errorThrown && a === undefined;
2559 `
2560
2561 testScript(SCRIPT, valueTrue, t)
2562 }
2563
2564 func TestJumpOutOfReturn(t *testing.T) {
2565 const SCRIPT = `
2566 function f() {
2567 var a;
2568 if (a == 0) {
2569 return true;
2570 }
2571 }
2572
2573 f();
2574 `
2575
2576 testScript(SCRIPT, _undefined, t)
2577 }
2578
2579 func TestSwitchJumpOutOfReturn(t *testing.T) {
2580 const SCRIPT = `
2581 function f(x) {
2582 switch(x) {
2583 case 0:
2584 break;
2585 default:
2586 return x;
2587 }
2588 }
2589
2590 f(0);
2591 `
2592
2593 testScript(SCRIPT, _undefined, t)
2594 }
2595
2596 func TestSetToReadOnlyPropertyStrictBracket(t *testing.T) {
2597 const SCRIPT = `
2598 'use strict';
2599
2600 var o = {};
2601 var thrown = false;
2602 Object.defineProperty(o, "test", {value: 42, configurable: true});
2603 try {
2604 o["test"] = 43;
2605 } catch (e) {
2606 thrown = e instanceof TypeError;
2607 }
2608
2609 thrown;
2610 `
2611
2612 testScript(SCRIPT, valueTrue, t)
2613 }
2614
2615 func TestSetToReadOnlyPropertyStrictDot(t *testing.T) {
2616 const SCRIPT = `
2617 'use strict';
2618
2619 var o = {};
2620 var thrown = false;
2621 Object.defineProperty(o, "test", {value: 42, configurable: true});
2622 try {
2623 o.test = 43;
2624 } catch (e) {
2625 thrown = e instanceof TypeError;
2626 }
2627
2628 thrown;
2629 `
2630
2631 testScript(SCRIPT, valueTrue, t)
2632 }
2633
2634 func TestDeleteNonConfigurablePropertyStrictBracket(t *testing.T) {
2635 const SCRIPT = `
2636 'use strict';
2637
2638 var o = {};
2639 var thrown = false;
2640 Object.defineProperty(o, "test", {value: 42});
2641 try {
2642 delete o["test"];
2643 } catch (e) {
2644 thrown = e instanceof TypeError;
2645 }
2646
2647 thrown;
2648 `
2649
2650 testScript(SCRIPT, valueTrue, t)
2651 }
2652
2653 func TestDeleteNonConfigurablePropertyStrictDot(t *testing.T) {
2654 const SCRIPT = `
2655 'use strict';
2656
2657 var o = {};
2658 var thrown = false;
2659 Object.defineProperty(o, "test", {value: 42});
2660 try {
2661 delete o.test;
2662 } catch (e) {
2663 thrown = e instanceof TypeError;
2664 }
2665
2666 thrown;
2667 `
2668
2669 testScript(SCRIPT, valueTrue, t)
2670 }
2671
2672 func TestCompound1(t *testing.T) {
2673 const SCRIPT = `
2674 var x = 0;
2675 var scope = {x: 1};
2676 var f;
2677 with (scope) {
2678 f = function() {
2679 x *= (delete scope.x, 2);
2680 }
2681 }
2682 f();
2683
2684 scope.x === 2 && x === 0;
2685
2686 `
2687
2688 testScript(SCRIPT, valueTrue, t)
2689 }
2690
2691 func TestCompound2(t *testing.T) {
2692 const SCRIPT = `
2693
2694 var x;
2695 x = "x";
2696 x ^= "1";
2697
2698 `
2699 testScript(SCRIPT, intToValue(1), t)
2700 }
2701
2702 func TestDeleteArguments(t *testing.T) {
2703 defer func() {
2704 if _, ok := recover().(*CompilerSyntaxError); !ok {
2705 t.Fatal("Expected syntax error")
2706 }
2707 }()
2708 const SCRIPT = `
2709 'use strict';
2710
2711 function f() {
2712 delete arguments;
2713 }
2714
2715 `
2716 testScript(SCRIPT, _undefined, t)
2717 }
2718
2719 func TestReturnUndefined(t *testing.T) {
2720 const SCRIPT = `
2721 function f() {
2722 return x;
2723 }
2724
2725 var thrown = false;
2726 try {
2727 f();
2728 } catch (e) {
2729 thrown = e instanceof ReferenceError;
2730 }
2731
2732 thrown;
2733 `
2734 testScript(SCRIPT, valueTrue, t)
2735 }
2736
2737 func TestForBreak(t *testing.T) {
2738 const SCRIPT = `
2739 var supreme, count;
2740 supreme = 5;
2741 var __evaluated = eval("for(count=0;;) {if (count===supreme)break;else count++; }");
2742 if (__evaluated !== void 0) {
2743 throw new Error('#1: __evaluated === 4. Actual: __evaluated ==='+ __evaluated );
2744 }
2745
2746 `
2747 testScript(SCRIPT, _undefined, t)
2748 }
2749
2750 func TestLargeNumberLiteral(t *testing.T) {
2751 const SCRIPT = `
2752 var x = 0x800000000000000000000;
2753 x.toString();
2754 `
2755 testScript(SCRIPT, asciiString("9.671406556917033e+24"), t)
2756 }
2757
2758 func TestIncDelete(t *testing.T) {
2759 const SCRIPT = `
2760 var o = {x: 1};
2761 o.x += (delete o.x, 1);
2762 o.x;
2763 `
2764 testScript(SCRIPT, intToValue(2), t)
2765 }
2766
2767 func TestCompoundAssignRefError(t *testing.T) {
2768 const SCRIPT = `
2769 var thrown = false;
2770 try {
2771 a *= 1;
2772 } catch (e) {
2773 if (e instanceof ReferenceError) {
2774 thrown = true;
2775 } else {
2776 throw e;
2777 }
2778 }
2779 thrown;
2780 `
2781 testScript(SCRIPT, valueTrue, t)
2782 }
2783
2784 func TestObjectLiteral__Proto__(t *testing.T) {
2785 const SCRIPT = `
2786 var o = {
2787 __proto__: null,
2788 test: 42
2789 }
2790
2791 Object.getPrototypeOf(o);
2792 `
2793
2794 testScript(SCRIPT, _null, t)
2795 }
2796
2797 func TestEmptyCodeError(t *testing.T) {
2798 if _, err := New().RunString(`i`); err == nil {
2799 t.Fatal("Expected an error")
2800 } else {
2801 if e := err.Error(); e != "ReferenceError: i is not defined at <eval>:1:1(0)" {
2802 t.Fatalf("Unexpected error: '%s'", e)
2803 }
2804 }
2805 }
2806
2807 func TestForOfArray(t *testing.T) {
2808 const SCRIPT = `
2809 var array = [0, 'a', true, false, null, /* hole */, undefined, NaN];
2810 var i = 0;
2811
2812 for (var value of array) {
2813 assert.sameValue(value, array[i], 'element at index ' + i);
2814 i++;
2815 }
2816
2817 assert.sameValue(i, 8, 'Visits all elements');
2818 `
2819 testScriptWithTestLib(SCRIPT, _undefined, t)
2820 }
2821
2822 func TestForOfReturn(t *testing.T) {
2823 const SCRIPT = `
2824 var callCount = 0;
2825 var iterationCount = 0;
2826 var iterable = {};
2827 var x = {
2828 set attr(_) {
2829 throw new Test262Error();
2830 }
2831 };
2832
2833 iterable[Symbol.iterator] = function() {
2834 return {
2835 next: function() {
2836 return { done: false, value: 0 };
2837 },
2838 return: function() {
2839 callCount += 1;
2840 }
2841 }
2842 };
2843
2844 assert.throws(Test262Error, function() {
2845 for (x.attr of iterable) {
2846 iterationCount += 1;
2847 }
2848 });
2849
2850 assert.sameValue(iterationCount, 0, 'The loop body is not evaluated');
2851 assert.sameValue(callCount, 1, 'Iterator is closed');
2852 `
2853 testScriptWithTestLib(SCRIPT, _undefined, t)
2854 }
2855
2856 func TestForOfReturn1(t *testing.T) {
2857 const SCRIPT = `
2858 var iterable = {};
2859 var iterationCount = 0;
2860
2861 iterable[Symbol.iterator] = function() {
2862 return {
2863 next: function() {
2864 return { done: false, value: null };
2865 },
2866 get return() {
2867 throw new Test262Error();
2868 }
2869 };
2870 };
2871
2872 assert.throws(Test262Error, function() {
2873 for (var x of iterable) {
2874 iterationCount += 1;
2875 break;
2876 }
2877 });
2878
2879 assert.sameValue(iterationCount, 1, 'The loop body is evaluated');
2880 `
2881 testScriptWithTestLib(SCRIPT, _undefined, t)
2882 }
2883
2884 func TestForOfLet(t *testing.T) {
2885 const SCRIPT = `
2886 var iterCount = 0;
2887 function f() {}
2888 for (var let of [23]) {
2889 f(let);
2890 if (let != 23) {
2891 throw new Error("");
2892 }
2893 iterCount += 1;
2894 }
2895
2896 iterCount;
2897 `
2898 testScript(SCRIPT, valueInt(1), t)
2899 }
2900
2901 func TestForOfLetLet(t *testing.T) {
2902 const SCRIPT = `
2903 for (let let of [23]) {
2904 }
2905 `
2906 _, err := Compile("", SCRIPT, false)
2907 if err == nil {
2908 t.Fatal("Expected error")
2909 }
2910 }
2911
2912 func TestForHeadLet(t *testing.T) {
2913 const SCRIPT = `
2914 for (let = 0; let < 2; let++);
2915 `
2916 testScript(SCRIPT, _undefined, t)
2917 }
2918
2919 func TestLhsLet(t *testing.T) {
2920 const SCRIPT = `
2921 let = 1;
2922 let;
2923 `
2924 testScript(SCRIPT, valueInt(1), t)
2925 }
2926
2927 func TestLetPostfixASI(t *testing.T) {
2928 const SCRIPT = `
2929 let
2930 ++
2931 `
2932 _, err := Compile("", SCRIPT, false)
2933 if err == nil {
2934 t.Fatal("Expected error")
2935 }
2936 }
2937
2938 func TestIteratorReturnNormal(t *testing.T) {
2939 const SCRIPT = `
2940 var iterable = {};
2941 var iterationCount = 0;
2942
2943 iterable[Symbol.iterator] = function() {
2944 return {
2945 next: function() {
2946 return { done: ++iterationCount > 2, value: null };
2947 },
2948 get return() {
2949 throw new Test262Error();
2950 }
2951 };
2952 };
2953
2954 for (var x of iterable) {
2955 }
2956 `
2957 testScriptWithTestLib(SCRIPT, _undefined, t)
2958 }
2959
2960 func TestIteratorReturnErrorNested(t *testing.T) {
2961 const SCRIPT = `
2962 var returnCalled = {};
2963 function iter(id) {
2964 return function() {
2965 var count = 0;
2966 return {
2967 next: function () {
2968 return {
2969 value: null,
2970 done: ++count > 2
2971 };
2972 },
2973 return: function () {
2974 returnCalled[id] = true;
2975 throw new Error(id);
2976 }
2977 };
2978 }
2979 }
2980 var iterable1 = {};
2981 iterable1[Symbol.iterator] = iter("1");
2982 var iterable2 = {};
2983 iterable2[Symbol.iterator] = iter("2");
2984
2985 try {
2986 for (var i of iterable1) {
2987 for (var j of iterable2) {
2988 break;
2989 }
2990 }
2991 throw new Error("no exception was thrown");
2992 } catch (e) {
2993 if (e.message !== "2") {
2994 throw e;
2995 }
2996 }
2997 if (!returnCalled["1"]) {
2998 throw new Error("no return 1");
2999 }
3000 if (!returnCalled["2"]) {
3001 throw new Error("no return 2");
3002 }
3003 `
3004 testScript(SCRIPT, _undefined, t)
3005 }
3006
3007 func TestReturnFromForInLoop(t *testing.T) {
3008 const SCRIPT = `
3009 (function f() {
3010 for (var i in {a: 1}) {
3011 return true;
3012 }
3013 })();
3014 `
3015 testScript(SCRIPT, valueTrue, t)
3016 }
3017
3018 func TestReturnFromForOfLoop(t *testing.T) {
3019 const SCRIPT = `
3020 (function f() {
3021 for (var i of [1]) {
3022 return true;
3023 }
3024 })();
3025 `
3026 testScript(SCRIPT, valueTrue, t)
3027 }
3028
3029 func TestIfStackLeaks(t *testing.T) {
3030 const SCRIPT = `
3031 var t = 0;
3032 if (t === 0) {
3033 t;
3034 }
3035 `
3036 testScript(SCRIPT, _positiveZero, t)
3037 }
3038
3039 func TestWithCallee(t *testing.T) {
3040 const SCRIPT = `
3041 function O() {
3042 var that = this;
3043 this.m = function() {
3044 return this === that;
3045 }
3046 }
3047 with(new O()) {
3048 m();
3049 }
3050 `
3051 testScript(SCRIPT, valueTrue, t)
3052 }
3053
3054 func TestWithScope(t *testing.T) {
3055 const SCRIPT = `
3056 function f(o) {
3057 var x = 42;
3058
3059 function innerf(o) {
3060 with (o) {
3061 return x;
3062 }
3063 }
3064
3065 return innerf(o);
3066 }
3067 f({});
3068 `
3069 testScript(SCRIPT, valueInt(42), t)
3070 }
3071
3072 func TestEvalCallee(t *testing.T) {
3073 const SCRIPT = `
3074 (function () {
3075 'use strict';
3076 var v = function() {
3077 return this === undefined;
3078 };
3079 return eval('v()');
3080 })();
3081 `
3082 testScript(SCRIPT, valueTrue, t)
3083 }
3084
3085 func TestEvalBindingDeleteVar(t *testing.T) {
3086 const SCRIPT = `
3087 (function () {
3088 eval("var x = 1");
3089 return x === 1 && delete x;
3090 })();
3091 `
3092 testScript(SCRIPT, valueTrue, t)
3093 }
3094
3095 func TestEvalBindingDeleteFunc(t *testing.T) {
3096 const SCRIPT = `
3097 (function () {
3098 eval("function x(){}");
3099 return typeof x === "function" && delete x;
3100 })();
3101 `
3102 testScript(SCRIPT, valueTrue, t)
3103 }
3104
3105 func TestDeleteGlobalLexical(t *testing.T) {
3106 const SCRIPT = `
3107 let x;
3108 delete x;
3109 `
3110 testScript(SCRIPT, valueFalse, t)
3111 }
3112
3113 func TestDeleteGlobalEval(t *testing.T) {
3114 const SCRIPT = `
3115 eval("var x");
3116 delete x;
3117 `
3118 testScript(SCRIPT, valueTrue, t)
3119 }
3120
3121 func TestGlobalVarNames(t *testing.T) {
3122 vm := New()
3123 _, err := vm.RunString("(0,eval)('var x')")
3124 if err != nil {
3125 t.Fatal(err)
3126 }
3127 _, err = vm.RunString("let x")
3128 if err == nil {
3129 t.Fatal("Expected error")
3130 }
3131 }
3132
3133 func TestTryResultEmpty(t *testing.T) {
3134 const SCRIPT = `
3135 1; try { } finally { }
3136 `
3137 testScript(SCRIPT, _undefined, t)
3138 }
3139
3140 func TestTryResultEmptyCatch(t *testing.T) {
3141 const SCRIPT = `
3142 1; try { throw null } catch(e) { }
3143 `
3144 testScript(SCRIPT, _undefined, t)
3145 }
3146
3147 func TestTryResultEmptyContinueLoop(t *testing.T) {
3148 const SCRIPT = `
3149 for (var i = 0; i < 2; i++) { try {throw null;} catch(e) {continue;} 'bad'}
3150 `
3151 testScript(SCRIPT, _undefined, t)
3152 }
3153
3154 func TestTryEmptyCatchStackLeak(t *testing.T) {
3155 const SCRIPT = `
3156 (function() {
3157 var f;
3158 // Make sure the outer function is not stashless.
3159 (function() {
3160 f++;
3161 })();
3162 try {
3163 throw new Error();
3164 } catch(e) {}
3165 })();
3166 `
3167 testScript(SCRIPT, _undefined, t)
3168 }
3169
3170 func TestTryThrowEmptyCatch(t *testing.T) {
3171 const SCRIPT = `
3172 try {
3173 throw new Error();
3174 }
3175 catch (e) {}
3176 `
3177 testScript(SCRIPT, _undefined, t)
3178 }
3179
3180 func TestFalsyLoopBreak(t *testing.T) {
3181 const SCRIPT = `
3182 while(false) {
3183 break;
3184 }
3185 for(;false;) {
3186 break;
3187 }
3188 undefined;
3189 `
3190 MustCompile("", SCRIPT, false)
3191 }
3192
3193 func TestFalsyLoopBreakWithResult(t *testing.T) {
3194 const SCRIPT = `
3195 while(false) {
3196 break;
3197 }
3198 `
3199 testScript(SCRIPT, _undefined, t)
3200 }
3201
3202 func TestDummyCompile(t *testing.T) {
3203 const SCRIPT = `
3204 'use strict';
3205
3206 for (;false;) {
3207 eval = 1;
3208 }
3209 `
3210
3211 _, err := Compile("", SCRIPT, false)
3212 if err == nil {
3213 t.Fatal("expected error")
3214 }
3215 }
3216
3217 func TestDummyCompileForUpdate(t *testing.T) {
3218 const SCRIPT = `
3219 'use strict';
3220
3221 for (;false;eval=1) {
3222 }
3223 `
3224
3225 _, err := Compile("", SCRIPT, false)
3226 if err == nil {
3227 t.Fatal("expected error")
3228 }
3229 }
3230
3231 func TestObjectLiteralWithNumericKeys(t *testing.T) {
3232 const SCRIPT = `
3233 var o = {1e3: true};
3234 var keys = Object.keys(o);
3235 var o1 = {get 1e3() {return true;}};
3236 var keys1 = Object.keys(o1);
3237 var o2 = {1e21: true};
3238 var keys2 = Object.keys(o2);
3239 let o3 = {0(){return true}};
3240 keys.length === 1 && keys[0] === "1000" &&
3241 keys1.length === 1 && keys1[0] === "1000" && o1[1e3] === true &&
3242 keys2.length === 1 && keys2[0] === "1e+21" && o3[0]();
3243 `
3244 testScript(SCRIPT, valueTrue, t)
3245 }
3246
3247 func TestEscapedObjectPropertyKeys(t *testing.T) {
3248 const SCRIPT = `
3249 var obj = {
3250 w\u0069th: 42
3251 };
3252 var obj = {
3253 with() {42}
3254 };
3255 `
3256
3257 _, err := Compile("", SCRIPT, false)
3258 if err != nil {
3259 t.Fatal(err)
3260 }
3261 }
3262
3263 func TestEscapedKeywords(t *testing.T) {
3264 const SCRIPT = `r\u0065turn;`
3265 _, err := Compile("", SCRIPT, false)
3266 if err == nil {
3267 t.Fatal("Expected error")
3268 }
3269 }
3270
3271 func TestEscapedLet(t *testing.T) {
3272 const SCRIPT = `
3273 this.let = 0;
3274
3275 l\u0065t // ASI
3276 a;
3277
3278 // If the parser treated the previous escaped "let" as a lexical declaration,
3279 // this variable declaration will result an early syntax error.
3280 var a;
3281 `
3282 _, err := Compile("", SCRIPT, false)
3283 if err != nil {
3284 t.Fatal(err)
3285 }
3286 }
3287
3288 func TestObjectLiteralFuncProps(t *testing.T) {
3289 const SCRIPT = `
3290 (function() {
3291 'use strict';
3292 var o = {
3293 eval: function() {return 1;},
3294 arguments() {return 2;},
3295 test: function test1() {}
3296 }
3297 assert.sameValue(o.eval.name, "eval");
3298 assert.sameValue(o.arguments.name, "arguments");
3299 assert.sameValue(o.eval(), 1);
3300 assert.sameValue(o.arguments(), 2);
3301 assert.sameValue(o.test.name, "test1");
3302 })();
3303 `
3304
3305 testScriptWithTestLib(SCRIPT, _undefined, t)
3306 }
3307
3308 func TestFuncName(t *testing.T) {
3309 const SCRIPT = `
3310 var method = 1;
3311 var o = {
3312 method: function() {
3313 return method;
3314 },
3315 method1: function method() {
3316 return method;
3317 }
3318 }
3319 o.method() === 1 && o.method1() === o.method1;
3320 `
3321
3322 testScript(SCRIPT, valueTrue, t)
3323 }
3324
3325 func TestFuncNameAssign(t *testing.T) {
3326 const SCRIPT = `
3327 var f = function() {};
3328 var f1;
3329 f1 = function() {};
3330 let f2 = function() {};
3331
3332 f.name === "f" && f1.name === "f1" && f2.name === "f2";
3333 `
3334
3335 testScript(SCRIPT, valueTrue, t)
3336 }
3337
3338 func TestLexicalDeclGlobal(t *testing.T) {
3339 const SCRIPT = `
3340 if (true) {
3341 let it = "be";
3342 if (it !== "be") {
3343 throw new Error(it);
3344 }
3345 }
3346 let thrown = false;
3347 try {
3348 it;
3349 } catch(e) {
3350 if (e instanceof ReferenceError) {
3351 thrown = true;
3352 }
3353 }
3354 thrown;
3355 `
3356 testScript(SCRIPT, valueTrue, t)
3357 }
3358
3359 func TestLexicalDeclFunction(t *testing.T) {
3360 const SCRIPT = `
3361 function f() {
3362 if (true) {
3363 let it = "be";
3364 if (it !== "be") {
3365 throw new Error(it);
3366 }
3367 }
3368 let thrown = false;
3369 try {
3370 it;
3371 } catch(e) {
3372 if (e instanceof ReferenceError) {
3373 thrown = true;
3374 }
3375 }
3376 return thrown;
3377 }
3378 f();
3379 `
3380 testScript(SCRIPT, valueTrue, t)
3381 }
3382
3383 func TestLexicalDynamicScope(t *testing.T) {
3384 const SCRIPT = `
3385 const global = 1;
3386 function f() {
3387 const func = global + 1;
3388 function inner() {
3389 function assertThrows(fn) {
3390 let thrown = false;
3391 try {
3392 fn();
3393 } catch (e) {
3394 if (e instanceof TypeError) {
3395 thrown = true;
3396 } else {
3397 throw e;
3398 }
3399 }
3400 if (!thrown) {
3401 throw new Error("Did not throw");
3402 }
3403 }
3404
3405 assertThrows(function() {
3406 func++;
3407 });
3408 assertThrows(function() {
3409 global++;
3410 });
3411
3412 assertThrows(function() {
3413 eval("func++");
3414 });
3415 assertThrows(function() {
3416 eval("global++");
3417 });
3418
3419 return eval("func + 1");
3420 }
3421 return inner();
3422 }
3423 f();
3424 `
3425 testScript(SCRIPT, valueInt(3), t)
3426 }
3427
3428 func TestLexicalDynamicScope1(t *testing.T) {
3429 const SCRIPT = `
3430 (function() {
3431 const x = 1 * 4;
3432 return (function() {
3433 eval("");
3434 return x;
3435 })();
3436 })();
3437 `
3438 testScript(SCRIPT, intToValue(4), t)
3439 }
3440
3441 func TestLexicalDynamicScope2(t *testing.T) {
3442 const SCRIPT = `
3443 (function() {
3444 const x = 1 + 3;
3445 var y = 2 * 2;
3446 eval("");
3447 return x;
3448 })();
3449 `
3450 testScript(SCRIPT, intToValue(4), t)
3451 }
3452
3453 func TestNonStrictLet(t *testing.T) {
3454 const SCRIPT = `
3455 var let = 1;
3456 `
3457
3458 testScript(SCRIPT, _undefined, t)
3459 }
3460
3461 func TestStrictLet(t *testing.T) {
3462 const SCRIPT = `
3463 var let = 1;
3464 `
3465
3466 _, err := Compile("", SCRIPT, true)
3467 if err == nil {
3468 t.Fatal("Expected an error")
3469 }
3470 }
3471
3472 func TestLetLet(t *testing.T) {
3473 const SCRIPT = `
3474 let let = 1;
3475 `
3476
3477 _, err := Compile("", SCRIPT, false)
3478 if err == nil {
3479 t.Fatal("Expected an error")
3480 }
3481 }
3482
3483 func TestLetASI(t *testing.T) {
3484 const SCRIPT = `
3485 while (false) let // ASI
3486 x = 1;
3487 `
3488
3489 _, err := Compile("", SCRIPT, false)
3490 if err != nil {
3491 t.Fatal(err)
3492 }
3493 }
3494
3495 func TestLetASI1(t *testing.T) {
3496 const SCRIPT = `
3497 let
3498 x = 1;
3499 `
3500
3501 _, err := Compile("", SCRIPT, true)
3502 if err != nil {
3503 t.Fatal(err)
3504 }
3505 }
3506
3507 func TestLetNoASI(t *testing.T) {
3508 const SCRIPT = `
3509 function f() {}let
3510 x = 1;
3511 `
3512
3513 _, err := Compile("", SCRIPT, true)
3514 if err != nil {
3515 t.Fatal(err)
3516 }
3517 }
3518
3519 func TestLetNoASI1(t *testing.T) {
3520 const SCRIPT = `
3521 let
3522 let = 1;
3523 `
3524
3525 _, err := Compile("", SCRIPT, false)
3526 if err == nil {
3527 t.Fatal("Expected error")
3528 }
3529 }
3530
3531 func TestLetArrayWithNewline(t *testing.T) {
3532 const SCRIPT = `
3533 with ({}) let
3534 [a] = 0;
3535 `
3536
3537 _, err := Compile("", SCRIPT, false)
3538 if err == nil {
3539 t.Fatal("Expected error")
3540 }
3541 }
3542
3543 func TestDynamicUninitedVarAccess(t *testing.T) {
3544 const SCRIPT = `
3545 function f() {
3546 var x;
3547 return eval("x");
3548 }
3549 f();
3550 `
3551 testScript(SCRIPT, _undefined, t)
3552 }
3553
3554 func TestLexicalForLoopNoClosure(t *testing.T) {
3555 const SCRIPT = `
3556 let sum = 0;
3557 for (let i = 0; i < 3; i++) {
3558 sum += i;
3559 }
3560 sum;
3561 `
3562 testScript(SCRIPT, valueInt(3), t)
3563 }
3564
3565 func TestLexicalForLoopClosure(t *testing.T) {
3566 const SCRIPT = `
3567 var f = [];
3568 for (let i = 0; i < 3; i++) {
3569 f.push(function() {
3570 return i;
3571 });
3572 }
3573 f.length === 3 && f[0]() === 0 && f[1]() === 1 && f[2]() === 2;
3574 `
3575 testScript(SCRIPT, valueTrue, t)
3576 }
3577
3578 func TestLexicalForLoopClosureInNext(t *testing.T) {
3579 const SCRIPT = `
3580 const a = [];
3581 for (let i = 0; i < 5; a.push(function () { return i; }), ++i) { }
3582 let res = "";
3583 for (let k = 0; k < 5; ++k) {
3584 res += ""+a[k]();
3585 }
3586 res;
3587 `
3588 testScript(SCRIPT, asciiString("12345"), t)
3589 }
3590
3591 func TestVarForLoop(t *testing.T) {
3592 const SCRIPT = `
3593 var f = [];
3594 for (var i = 0, j = 0; i < 3; i++) {
3595 f.push(function() {
3596 return i;
3597 });
3598 }
3599 f.length === 3 && f[0]() === 3 && f[1]() === 3 && f[2]() === 3;
3600 `
3601 testScript(SCRIPT, valueTrue, t)
3602 }
3603
3604 func TestLexicalForOfLoop(t *testing.T) {
3605 const SCRIPT = `
3606 var f = [];
3607 for (let i of [0, 1, 2]) {
3608 f.push(function() {
3609 return i;
3610 });
3611 }
3612 f.length === 3 && f[0]() === 0 && f[1]() === 1 && f[2]() === 2;
3613 `
3614 testScript(SCRIPT, valueTrue, t)
3615 }
3616
3617 func TestLexicalForOfLoopContBreak(t *testing.T) {
3618 const SCRIPT = `
3619 const f = [];
3620 for (let i of [0, 1, 2, 3, 4, 5]) {
3621 if (i % 2) continue;
3622 f.push(function() {
3623 return i;
3624 });
3625 if (i > 2) break;
3626 }
3627 let res = "";
3628 f.forEach(function(item) {res += item()});
3629 f.length === 3 && res === "024";
3630 `
3631 testScript(SCRIPT, valueTrue, t)
3632 }
3633
3634 func TestVarBlockConflict(t *testing.T) {
3635 const SCRIPT = `
3636 let x;
3637 {
3638 if (false) {
3639 var x;
3640 }
3641 }
3642 `
3643 _, err := Compile("", SCRIPT, false)
3644 if err == nil {
3645 t.Fatal("Expected an error")
3646 }
3647 }
3648
3649 func TestVarBlockConflictEval(t *testing.T) {
3650 const SCRIPT = `
3651 assert.throws(SyntaxError, function() {
3652 let x;
3653 {
3654 if (true) {
3655 eval("var x");
3656 }
3657 }
3658 });
3659 `
3660 testScriptWithTestLib(SCRIPT, _undefined, t)
3661 }
3662
3663 func TestVarBlockNoConflict(t *testing.T) {
3664 const SCRIPT = `
3665 function f() {
3666 let x;
3667 function ff() {
3668 {
3669 var x = 3;
3670 }
3671 }
3672 ff();
3673 }
3674 f();
3675 `
3676 testScript(SCRIPT, _undefined, t)
3677 }
3678
3679 func TestVarBlockNoConflictEval(t *testing.T) {
3680 const SCRIPT = `
3681 function f() {
3682 let x;
3683 function ff() {
3684 {
3685 eval("var x = 3");
3686 }
3687 }
3688 ff();
3689 }
3690 f();
3691 `
3692 testScript(SCRIPT, _undefined, t)
3693 }
3694
3695 func TestVarDeclCorrectScope(t *testing.T) {
3696 const SCRIPT = `
3697 function f() {
3698 {
3699 let z;
3700 eval("var x = 3");
3701 }
3702 return x;
3703 }
3704 f();
3705 `
3706 testScript(SCRIPT, valueInt(3), t)
3707 }
3708
3709 func TestLexicalCatch(t *testing.T) {
3710 const SCRIPT = `
3711 try {
3712 throw null;
3713 } catch (e) {
3714 let x = 1;
3715 function f() {}
3716 e;
3717 }
3718 `
3719 testScript(SCRIPT, _null, t)
3720 }
3721
3722 func TestArgumentsLexicalDecl(t *testing.T) {
3723 const SCRIPT = `
3724 function f1() {
3725 let arguments;
3726 return arguments;
3727 }
3728 f1(42);
3729 `
3730 testScript(SCRIPT, _undefined, t)
3731 }
3732
3733 func TestArgumentsLexicalDeclAssign(t *testing.T) {
3734 const SCRIPT = `
3735 function f1() {
3736 let arguments = arguments;
3737 return a;
3738 }
3739 assert.throws(ReferenceError, function() {
3740 f1(42);
3741 });
3742 `
3743 testScriptWithTestLib(SCRIPT, _undefined, t)
3744 }
3745
3746 func TestLexicalConstModifyFromEval(t *testing.T) {
3747 const SCRIPT = `
3748 const x = 1;
3749 function f() {
3750 eval("x = 2");
3751 }
3752 assert.throws(TypeError, function() {
3753 f();
3754 });
3755 `
3756 testScriptWithTestLib(SCRIPT, _undefined, t)
3757 }
3758
3759 func TestLexicalStrictNames(t *testing.T) {
3760 const SCRIPT = `let eval = 1;`
3761
3762 _, err := Compile("", SCRIPT, true)
3763 if err == nil {
3764 t.Fatal("Expected an error")
3765 }
3766 }
3767
3768 func TestAssignAfterStackExpand(t *testing.T) {
3769
3770 const SCRIPT = `
3771 function f() {
3772 let sum = 0;
3773 for (let i = 0; i < arguments.length; i++) {
3774 sum += arguments[i];
3775 }
3776 return sum;
3777 }
3778 function testAssignment() {
3779 var x = 0;
3780 var scope = {};
3781
3782 with (scope) {
3783 x = (scope.x = f(0, 0, 0, 0, 0, 0, 1, 1), 1);
3784 }
3785
3786 if (scope.x !== 2) {
3787 throw new Error('#1: scope.x === 2. Actual: ' + (scope.x));
3788 }
3789 if (x !== 1) {
3790 throw new Error('#2: x === 1. Actual: ' + (x));
3791 }
3792 }
3793 testAssignment();
3794 `
3795 testScript(SCRIPT, _undefined, t)
3796 }
3797
3798 func TestArgAccessFromDynamicStash(t *testing.T) {
3799 const SCRIPT = `
3800 function f(arg) {
3801 function test() {
3802 eval("");
3803 return a;
3804 }
3805 return arg;
3806 }
3807 f(true);
3808 `
3809 testScript(SCRIPT, valueTrue, t)
3810 }
3811
3812 func TestLoadMixedLex(t *testing.T) {
3813 const SCRIPT = `
3814 function f() {
3815 let a = 1;
3816 {
3817 function inner() {
3818 eval("var a = true");
3819 return a;
3820 }
3821 return inner();
3822 }
3823 }
3824 f();
3825 `
3826 testScript(SCRIPT, valueTrue, t)
3827 }
3828
3829 func TestObjectLiteralSpread(t *testing.T) {
3830 const SCRIPT = `
3831 let src = {prop1: 1};
3832 Object.defineProperty(src, "prop2", {value: 2, configurable: true});
3833 Object.defineProperty(src, "prop3", {value: 3, enumerable: true, configurable: true});
3834 let target = {prop4: 4, ...src};
3835 assert(deepEqual(target, {prop1: 1, prop3: 3, prop4: 4}));
3836 `
3837 testScriptWithTestLibX(SCRIPT, _undefined, t)
3838 }
3839
3840 func TestArrayLiteralSpread(t *testing.T) {
3841 const SCRIPT = `
3842 let a1 = [1, 2];
3843 let a2 = [3, 4];
3844 let a = [...a1, 0, ...a2, 1];
3845 assert(compareArray(a, [1, 2, 0, 3, 4, 1]));
3846 `
3847 testScriptWithTestLib(SCRIPT, _undefined, t)
3848 }
3849
3850 func TestObjectAssignmentPattern(t *testing.T) {
3851 const SCRIPT = `
3852 let a, b, c;
3853 ({a, b, c=3} = {a: 1, b: 2});
3854 assert.sameValue(a, 1, "a");
3855 assert.sameValue(b, 2, "b");
3856 assert.sameValue(c, 3, "c");
3857 `
3858 testScriptWithTestLib(SCRIPT, _undefined, t)
3859 }
3860
3861 func TestObjectAssignmentPatternNoDyn(t *testing.T) {
3862 const SCRIPT = `
3863 (function() {
3864 let a, b, c;
3865 ({a, b, c=3} = {a: 1, b: 2});
3866 assert.sameValue(a, 1, "a");
3867 assert.sameValue(b, 2, "b");
3868 assert.sameValue(c, 3, "c");
3869 })();
3870 `
3871 testScriptWithTestLib(SCRIPT, _undefined, t)
3872 }
3873
3874 func TestObjectAssignmentPatternNested(t *testing.T) {
3875 const SCRIPT = `
3876 let a, b, c, d;
3877 ({a, b, c: {d} = 3} = {a: 1, b: 2, c: {d: 4}});
3878 assert.sameValue(a, 1, "a");
3879 assert.sameValue(b, 2, "b");
3880 assert.sameValue(c, undefined, "c");
3881 assert.sameValue(d, 4, "d");
3882 `
3883 testScriptWithTestLib(SCRIPT, _undefined, t)
3884 }
3885
3886 func TestObjectAssignmentPatternEvalOrder(t *testing.T) {
3887 const SCRIPT = `
3888 let trace = "";
3889 let target_obj = {};
3890
3891 function src() {
3892 trace += "src(),";
3893 return {
3894 get a() {
3895 trace += "get a,";
3896 return "a";
3897 }
3898 }
3899 }
3900
3901 function prop1() {
3902 trace += "prop1(),"
3903 return {
3904 toString: function() {
3905 trace += "prop1-to-string(),";
3906 return "a";
3907 }
3908 }
3909 }
3910
3911 function prop2() {
3912 trace += "prop2(),";
3913 return {
3914 toString: function() {
3915 trace += "prop2-to-string(),";
3916 return "b";
3917 }
3918 }
3919 }
3920
3921 function target() {
3922 trace += "target(),"
3923 return target_obj;
3924 }
3925
3926 let a, b;
3927
3928 ({[prop1()]: target().a, [prop2()]: b} = src());
3929 if (target_obj.a !== "a") {
3930 throw new Error("target_obj.a="+target_obj.a);
3931 }
3932 trace;
3933 `
3934 testScript(SCRIPT, asciiString("src(),prop1(),prop1-to-string(),target(),get a,prop2(),prop2-to-string(),"), t)
3935 }
3936
3937 func TestArrayAssignmentPatternEvalOrder(t *testing.T) {
3938 const SCRIPT = `
3939 let trace = "";
3940
3941 let src_arr = {
3942 [Symbol.iterator]: function() {
3943 let done = false;
3944 return {
3945 next: function() {
3946 trace += "next,";
3947 if (!done) {
3948 done = true;
3949 return {value: 0};
3950 }
3951 return {done: true};
3952 },
3953 return: function() {
3954 trace += "return,";
3955 }
3956 }
3957 }
3958 }
3959
3960 function src() {
3961 trace += "src(),";
3962 return src_arr;
3963 }
3964
3965 let tgt = {
3966 get a() {
3967 trace += "get a,";
3968 return "a";
3969 },
3970 get b() {
3971 trace += "get b,";
3972 return "b";
3973 }
3974 }
3975
3976 function target() {
3977 trace += "target(),";
3978 return tgt;
3979 }
3980
3981 function default_a() {
3982 trace += "default a,";
3983 return "def_a";
3984 }
3985
3986 function default_b() {
3987 trace += "default b,";
3988 return "def_b";
3989 }
3990
3991 ([target().a = default_a(), target().b = default_b()] = src());
3992 trace;
3993 `
3994 testScript(SCRIPT, asciiString("src(),target(),next,target(),next,default b,"), t)
3995 }
3996
3997 func TestObjectAssignPatternRest(t *testing.T) {
3998 const SCRIPT = `
3999 let a, b, c, d;
4000 ({a, b, c, ...d} = {a: 1, b: 2, d: 4});
4001 assert.sameValue(a, 1, "a");
4002 assert.sameValue(b, 2, "b");
4003 assert.sameValue(c, undefined, "c");
4004 assert(deepEqual(d, {d: 4}), "d");
4005 `
4006 testScriptWithTestLibX(SCRIPT, _undefined, t)
4007 }
4008
4009 func TestObjectBindPattern(t *testing.T) {
4010 const SCRIPT = `
4011 let {a, b, c, ...d} = {a: 1, b: 2, d: 4};
4012 assert.sameValue(a, 1, "a");
4013 assert.sameValue(b, 2, "b");
4014 assert.sameValue(c, undefined, "c");
4015 assert(deepEqual(d, {d: 4}), "d");
4016
4017 var { x: y, } = { x: 23 };
4018
4019 assert.sameValue(y, 23);
4020
4021 assert.throws(ReferenceError, function() {
4022 x;
4023 });
4024 `
4025 testScriptWithTestLibX(SCRIPT, _undefined, t)
4026 }
4027
4028 func TestObjLiteralShorthandWithInitializer(t *testing.T) {
4029 const SCRIPT = `
4030 o = {a=1};
4031 `
4032 _, err := Compile("", SCRIPT, false)
4033 if err == nil {
4034 t.Fatal("Expected an error")
4035 }
4036 }
4037
4038 func TestObjLiteralShorthandLetStringLit(t *testing.T) {
4039 const SCRIPT = `
4040 o = {"let"};
4041 `
4042 _, err := Compile("", SCRIPT, false)
4043 if err == nil {
4044 t.Fatal("Expected an error")
4045 }
4046 }
4047
4048 func TestObjLiteralComputedKeys(t *testing.T) {
4049 const SCRIPT = `
4050 let o = {
4051 get [Symbol.toString]() {
4052 }
4053 }
4054 `
4055 testScript(SCRIPT, _undefined, t)
4056 }
4057
4058 func TestObjLiteralComputedKeysEvalOrder(t *testing.T) {
4059 const SCRIPT = `
4060 let trace = [];
4061 function key() {
4062 trace.push("key");
4063 return {
4064 toString: function() {
4065 trace.push("key-toString");
4066 return "key";
4067 }
4068 }
4069 }
4070 function val() {
4071 trace.push("val");
4072 return "val";
4073 }
4074
4075 const _ = {
4076 [key()]: val(),
4077 }
4078
4079 trace.join(",");
4080 `
4081 testScript(SCRIPT, asciiString("key,key-toString,val"), t)
4082 }
4083
4084 func TestArrayAssignPattern(t *testing.T) {
4085 const SCRIPT = `
4086 let a, b;
4087 ([a, b] = [1, 2]);
4088 a === 1 && b === 2;
4089 `
4090 testScript(SCRIPT, valueTrue, t)
4091 }
4092
4093 func TestArrayAssignPattern1(t *testing.T) {
4094 const SCRIPT = `
4095 let a, b;
4096 ([a = 3, b = 2] = [1]);
4097 a === 1 && b === 2;
4098 `
4099 testScript(SCRIPT, valueTrue, t)
4100 }
4101
4102 func TestArrayAssignPatternLHS(t *testing.T) {
4103 const SCRIPT = `
4104 let a = {};
4105 [ a.b, a['c'] = 2 ] = [1];
4106 a.b === 1 && a.c === 2;
4107 `
4108 testScript(SCRIPT, valueTrue, t)
4109 }
4110
4111 func TestArrayAssignPatternElision(t *testing.T) {
4112 const SCRIPT = `
4113 let a, b;
4114 ([a,, b] = [1, 4, 2]);
4115 a === 1 && b === 2;
4116 `
4117 testScript(SCRIPT, valueTrue, t)
4118 }
4119
4120 func TestArrayAssignPatternRestPattern(t *testing.T) {
4121 const SCRIPT = `
4122 let a, b, z;
4123 [ z, ...[a, b] ] = [0, 1, 2];
4124 z === 0 && a === 1 && b === 2;
4125 `
4126 testScript(SCRIPT, valueTrue, t)
4127 }
4128
4129 func TestArrayBindingPattern(t *testing.T) {
4130 const SCRIPT = `
4131 let [a, b] = [1, 2];
4132 a === 1 && b === 2;
4133 `
4134 testScript(SCRIPT, valueTrue, t)
4135 }
4136
4137 func TestObjectPatternShorthandInit(t *testing.T) {
4138 const SCRIPT = `
4139 [...{ x = 1 }] = [];
4140 x;
4141 `
4142 testScript(SCRIPT, valueInt(1), t)
4143 }
4144
4145 func TestArrayBindingPatternRestPattern(t *testing.T) {
4146 const SCRIPT = `
4147 const [a, b, ...[c, d]] = [1, 2, 3, 4];
4148 a === 1 && b === 2 && c === 3 && d === 4;
4149 `
4150 testScript(SCRIPT, valueTrue, t)
4151 }
4152
4153 func TestForVarPattern(t *testing.T) {
4154 const SCRIPT = `
4155 var o = {a: 1};
4156 var trace = "";
4157 for (var [key, value] of Object.entries(o)) {
4158 trace += key+":"+value;
4159 }
4160 trace;
4161 `
4162 testScript(SCRIPT, asciiString("a:1"), t)
4163 }
4164
4165 func TestForLexPattern(t *testing.T) {
4166 const SCRIPT = `
4167 var o = {a: 1};
4168 var trace = "";
4169 for (const [key, value] of Object.entries(o)) {
4170 trace += key+":"+value;
4171 }
4172 trace;
4173 `
4174 testScript(SCRIPT, asciiString("a:1"), t)
4175 }
4176
4177 func TestBindingPatternRestTrailingComma(t *testing.T) {
4178 const SCRIPT = `
4179 const [a, b, ...rest,] = [];
4180 `
4181 _, err := Compile("", SCRIPT, false)
4182 if err == nil {
4183 t.Fatal("Expected an error")
4184 }
4185 }
4186
4187 func TestAssignPatternRestTrailingComma(t *testing.T) {
4188 const SCRIPT = `
4189 ([a, b, ...rest,] = []);
4190 `
4191 _, err := Compile("", SCRIPT, false)
4192 if err == nil {
4193 t.Fatal("Expected an error")
4194 }
4195 }
4196
4197 func TestFuncParamInitializerSimple(t *testing.T) {
4198 const SCRIPT = `
4199 function f(a = 1) {
4200 return a;
4201 }
4202 ""+f()+f(2);
4203 `
4204 testScript(SCRIPT, asciiString("12"), t)
4205 }
4206
4207 func TestFuncParamObjectPatternSimple(t *testing.T) {
4208 const SCRIPT = `
4209 function f({a, b} = {a: 1, b: 2}) {
4210 return "" + a + b;
4211 }
4212 ""+f()+" "+f({a: 3, b: 4});
4213 `
4214 testScript(SCRIPT, asciiString("12 34"), t)
4215 }
4216
4217 func TestFuncParamRestStackSimple(t *testing.T) {
4218 const SCRIPT = `
4219 function f(arg1, ...rest) {
4220 return rest;
4221 }
4222 let ar = f(1, 2, 3);
4223 ar.join(",");
4224 `
4225 testScript(SCRIPT, asciiString("2,3"), t)
4226 }
4227
4228 func TestFuncParamRestStashSimple(t *testing.T) {
4229 const SCRIPT = `
4230 function f(arg1, ...rest) {
4231 eval("true");
4232 return rest;
4233 }
4234 let ar = f(1, 2, 3);
4235 ar.join(",");
4236 `
4237 testScript(SCRIPT, asciiString("2,3"), t)
4238 }
4239
4240 func TestRestArgsNotInStash(t *testing.T) {
4241 const SCRIPT = `
4242 function f(...rest) {
4243 () => rest;
4244 return rest.length;
4245 }
4246 f(1,2);
4247 `
4248 testScript(SCRIPT, valueInt(2), t)
4249 }
4250
4251 func TestRestArgsInStash(t *testing.T) {
4252 const SCRIPT = `
4253 function f(first, ...rest) {
4254 () => first;
4255 () => rest;
4256 return rest.length;
4257 }
4258 f(1,2);
4259 `
4260 testScript(SCRIPT, valueInt(1), t)
4261 }
4262
4263 func TestRestArgsInStashFwdRef(t *testing.T) {
4264 const SCRIPT = `
4265 function f(first = eval(), ...rest) {
4266 () => first;
4267 () => rest;
4268 return rest.length === 1 && rest[0] === 2;
4269 }
4270 f(1,2);
4271 `
4272 testScript(SCRIPT, valueTrue, t)
4273 }
4274
4275 func TestFuncParamRestPattern(t *testing.T) {
4276 const SCRIPT = `
4277 function f(arg1, ...{0: rest1, 1: rest2}) {
4278 return ""+arg1+" "+rest1+" "+rest2;
4279 }
4280 f(1, 2, 3);
4281 `
4282 testScript(SCRIPT, asciiString("1 2 3"), t)
4283 }
4284
4285 func TestFuncParamForwardRef(t *testing.T) {
4286 const SCRIPT = `
4287 function f(a = b + 1, b) {
4288 return ""+a+" "+b;
4289 }
4290 f(1, 2);
4291 `
4292 testScript(SCRIPT, asciiString("1 2"), t)
4293 }
4294
4295 func TestFuncParamForwardRefMissing(t *testing.T) {
4296 const SCRIPT = `
4297 function f(a = b + 1, b) {
4298 return ""+a+" "+b;
4299 }
4300 assert.throws(ReferenceError, function() {
4301 f();
4302 });
4303 `
4304 testScriptWithTestLib(SCRIPT, _undefined, t)
4305 }
4306
4307 func TestFuncParamInnerRef(t *testing.T) {
4308 const SCRIPT = `
4309 function f(a = inner) {
4310 var inner = 42;
4311 return a;
4312 }
4313 assert.throws(ReferenceError, function() {
4314 f();
4315 });
4316 `
4317 testScriptWithTestLib(SCRIPT, _undefined, t)
4318 }
4319
4320 func TestFuncParamInnerRefEval(t *testing.T) {
4321 const SCRIPT = `
4322 function f(a = eval("inner")) {
4323 var inner = 42;
4324 return a;
4325 }
4326 assert.throws(ReferenceError, function() {
4327 f();
4328 });
4329 `
4330 testScriptWithTestLib(SCRIPT, _undefined, t)
4331 }
4332
4333 func TestFuncParamCalleeName(t *testing.T) {
4334 const SCRIPT = `
4335 function f(a = f) {
4336 var f;
4337 return f;
4338 }
4339 typeof f();
4340 `
4341 testScript(SCRIPT, asciiString("undefined"), t)
4342 }
4343
4344 func TestFuncParamVarCopy(t *testing.T) {
4345 const SCRIPT = `
4346 function f(a = f) {
4347 var a;
4348 return a;
4349 }
4350 typeof f();
4351 `
4352 testScript(SCRIPT, asciiString("function"), t)
4353 }
4354
4355 func TestFuncParamScope(t *testing.T) {
4356 const SCRIPT = `
4357 var x = 'outside';
4358 var probe1, probe2;
4359
4360 function f(
4361 _ = probe1 = function() { return x; },
4362 __ = (eval('var x = "inside";'), probe2 = function() { return x; })
4363 ) {
4364 }
4365 f();
4366 probe1()+" "+probe2();
4367 `
4368 testScript(SCRIPT, asciiString("inside inside"), t)
4369 }
4370
4371 func TestDefParamsStackPtr(t *testing.T) {
4372 const SCRIPT = `
4373 function A() {};
4374 A.B = function () {};
4375 function D(message = '') {
4376 var C = A.B;
4377 C([1,2,3]);
4378 };
4379
4380 D();
4381 `
4382 testScript(SCRIPT, _undefined, t)
4383 }
4384
4385 func TestNestedVariadicCalls(t *testing.T) {
4386 const SCRIPT = `
4387 function f() {
4388 return Array.prototype.join.call(arguments, ",");
4389 }
4390 f(...[1], "a", f(...[2]));
4391 `
4392 testScript(SCRIPT, asciiString("1,a,2"), t)
4393 }
4394
4395 func TestVariadicNew(t *testing.T) {
4396 const SCRIPT = `
4397 function C() {
4398 this.res = Array.prototype.join.call(arguments, ",");
4399 }
4400 var c = new C(...[1], "a", new C(...[2]).res);
4401 c.res;
4402 `
4403 testScript(SCRIPT, asciiString("1,a,2"), t)
4404 }
4405
4406 func TestVariadicUseStackVars(t *testing.T) {
4407 const SCRIPT = `
4408 function A(message) { return message; }
4409 function B(...args){
4410 return A(...args);
4411 }
4412 B("C");
4413 `
4414 testScript(SCRIPT, asciiString("C"), t)
4415 }
4416
4417 func TestCatchParamPattern(t *testing.T) {
4418 const SCRIPT = `
4419 function f() {
4420 let x = 3;
4421 try {
4422 throw {a: 1, b: 2};
4423 } catch ({a, b, c = x}) {
4424 let x = 99;
4425 return ""+a+" "+b+" "+c;
4426 }
4427 }
4428 f();
4429 `
4430 testScript(SCRIPT, asciiString("1 2 3"), t)
4431 }
4432
4433 func TestArrowUseStrict(t *testing.T) {
4434
4435 _, err := Compile("", "(a) => {'use strict';}", false)
4436 if err != nil {
4437 t.Fatal(err)
4438 }
4439
4440 _, err = Compile("", "(a=0) => {'use strict';}", false)
4441 if err == nil {
4442 t.Fatal("expected error")
4443 }
4444 }
4445
4446 func TestArrowBoxedThis(t *testing.T) {
4447 const SCRIPT = `
4448 var context;
4449 fn = function() {
4450 return (arg) => { var local; context = this; };
4451 };
4452
4453 fn()();
4454 context === this;
4455 `
4456
4457 testScript(SCRIPT, valueTrue, t)
4458 }
4459
4460 func TestParameterOverride(t *testing.T) {
4461 const SCRIPT = `
4462 function f(arg) {
4463 var arg = arg || "default"
4464 return arg
4465 }
4466 f()
4467 `
4468 testScript(SCRIPT, asciiString("default"), t)
4469 }
4470
4471 func TestEvalInIterScope(t *testing.T) {
4472 const SCRIPT = `
4473 for (let a = 0; a < 1; a++) {
4474 eval("a");
4475 }
4476 `
4477
4478 testScript(SCRIPT, valueInt(0), t)
4479 }
4480
4481 func TestTemplateLiterals(t *testing.T) {
4482 vm := New()
4483 _, err := vm.RunString("const a = 1, b = 'b';")
4484 if err != nil {
4485 t.Fatal(err)
4486 }
4487 f := func(t *testing.T, template, expected string) {
4488 res, err := vm.RunString(template)
4489 if err != nil {
4490 t.Fatal(err)
4491 }
4492 if actual := res.Export(); actual != expected {
4493 t.Fatalf("Expected: %q, actual: %q", expected, actual)
4494 }
4495 }
4496 t.Run("empty", func(t *testing.T) {
4497 f(t, "``", "")
4498 })
4499 t.Run("noSub", func(t *testing.T) {
4500 f(t, "`test`", "test")
4501 })
4502 t.Run("emptyTail", func(t *testing.T) {
4503 f(t, "`a=${a},b=${b}`", "a=1,b=b")
4504 })
4505 t.Run("emptyHead", func(t *testing.T) {
4506 f(t, "`${a},b=${b}$`", "1,b=b$")
4507 })
4508 t.Run("headAndTail", func(t *testing.T) {
4509 f(t, "`a=${a},b=${b}$`", "a=1,b=b$")
4510 })
4511 }
4512
4513 func TestTaggedTemplate(t *testing.T) {
4514 const SCRIPT = `
4515 let res;
4516 const o = {
4517 tmpl() {
4518 res = this;
4519 return () => {};
4520 }
4521 }
4522 ` +
4523 "o.tmpl()`test`;" + `
4524 res === o;
4525 `
4526
4527 testScript(SCRIPT, valueTrue, t)
4528 }
4529
4530 func TestDuplicateGlobalFunc(t *testing.T) {
4531 const SCRIPT = `
4532 function a(){}
4533 function b(){ return "b" }
4534 function c(){ return "c" }
4535 function a(){}
4536 b();
4537 `
4538
4539 testScript(SCRIPT, asciiString("b"), t)
4540 }
4541
4542 func TestDuplicateFunc(t *testing.T) {
4543 const SCRIPT = `
4544 function f() {
4545 function a(){}
4546 function b(){ return "b" }
4547 function c(){ return "c" }
4548 function a(){}
4549 return b();
4550 }
4551 f();
4552 `
4553
4554 testScript(SCRIPT, asciiString("b"), t)
4555 }
4556
4557 func TestSrcLocations(t *testing.T) {
4558
4559 const SCRIPT = `
4560 let i = {
4561 valueOf() {
4562 throw new Error();
4563 }
4564 };
4565 try {
4566 i++;
4567 } catch(e) {
4568 assertStack(e, [["test.js", "valueOf", 4, 10],
4569 ["test.js", "", 8, 3]
4570 ]);
4571 }
4572
4573 Object.defineProperty(globalThis, "x", {
4574 get() {
4575 throw new Error();
4576 },
4577 set() {
4578 throw new Error();
4579 }
4580 });
4581
4582 try {
4583 x;
4584 } catch(e) {
4585 assertStack(e, [["test.js", "get", 17, 10],
4586 ["test.js", "", 25, 3]
4587 ]);
4588 }
4589
4590 try {
4591 x++;
4592 } catch(e) {
4593 assertStack(e, [["test.js", "get", 17, 10],
4594 ["test.js", "", 33, 3]
4595 ]);
4596 }
4597
4598 try {
4599 x = 2;
4600 } catch(e) {
4601 assertStack(e, [["test.js", "set", 20, 10],
4602 ["test.js", "", 41, 3]
4603 ]);
4604 }
4605
4606 try {
4607 +i;
4608 } catch(e) {
4609 assertStack(e, [["test.js", "valueOf", 4, 10],
4610 ["test.js", "", 49, 4]
4611 ]);
4612 }
4613
4614 try {
4615 let n;
4616 n.field = {
4617 "key1": "test",
4618 "key2": {},
4619 }
4620 } catch(e) {
4621 assertStack(e, [["test.js", "", 58, 5]
4622 ]);
4623 }
4624 `
4625 testScriptWithTestLibX(SCRIPT, _undefined, t)
4626 }
4627
4628 func TestSrcLocationThrowLiteral(t *testing.T) {
4629 vm := New()
4630 _, err := vm.RunString(`
4631 const z = 1;
4632 throw "";
4633 `)
4634 if ex, ok := err.(*Exception); ok {
4635 pos := ex.stack[0].Position()
4636 if pos.Line != 3 {
4637 t.Fatal(pos)
4638 }
4639 } else {
4640 t.Fatal(err)
4641 }
4642 }
4643
4644 func TestSrcLocation(t *testing.T) {
4645 prg := MustCompile("test.js", `
4646 f();
4647 var x = 1;
4648 let y = 1;
4649 let [z1, z2] = [0, 0];
4650
4651 var [z3, z4] = [0, 0];
4652 `, false)
4653 const (
4654 varLine = 3
4655 letLine = 4
4656 dstrLetLine = 5
4657 dstrVarLine = 7
4658 )
4659 linesOfInterest := map[int]string{
4660 varLine: "var",
4661 letLine: "let",
4662 dstrLetLine: "destruct let",
4663 dstrVarLine: "destruct var",
4664 }
4665 for i := range prg.code {
4666 loc := prg.src.Position(prg.sourceOffset(i))
4667 delete(linesOfInterest, loc.Line)
4668 if len(linesOfInterest) == 0 {
4669 break
4670 }
4671 }
4672 for _, v := range linesOfInterest {
4673 t.Fatalf("no %s line", v)
4674 }
4675 }
4676
4677 func TestBadObjectKey(t *testing.T) {
4678 _, err := Compile("", "({!:0})", false)
4679 if err == nil {
4680 t.Fatal("expected error")
4681 }
4682 }
4683
4684 func TestConstantFolding(t *testing.T) {
4685 testValues := func(prg *Program, result Value, t *testing.T) {
4686 if len(prg.values) != 1 || !prg.values[0].SameAs(result) {
4687 prg.dumpCode(t.Logf)
4688 t.Fatalf("values: %v", prg.values)
4689 }
4690 }
4691 f := func(src string, result Value, t *testing.T) {
4692 prg := MustCompile("test.js", src, false)
4693 testValues(prg, result, t)
4694 New().testPrg(prg, result, t)
4695 }
4696 ff := func(src string, result Value, t *testing.T) {
4697 prg := MustCompile("test.js", src, false)
4698 fl := prg.code[0].(*newFunc)
4699 testValues(fl.prg, result, t)
4700 New().testPrg(prg, result, t)
4701 }
4702
4703 t.Run("lexical binding", func(t *testing.T) {
4704 f("const x = 1 + 2; x", valueInt(3), t)
4705 })
4706 t.Run("var binding", func(t *testing.T) {
4707 f("var x = 1 + 2; x", valueInt(3), t)
4708 })
4709 t.Run("assignment", func(t *testing.T) {
4710 f("x = 1 + 2; x", valueInt(3), t)
4711 })
4712 t.Run("object pattern", func(t *testing.T) {
4713 f("const {x = 1 + 2} = {}; x", valueInt(3), t)
4714 })
4715 t.Run("array pattern", func(t *testing.T) {
4716 f("const [x = 1 + 2] = []; x", valueInt(3), t)
4717 })
4718 t.Run("object literal", func(t *testing.T) {
4719 f("var o = {x: 1 + 2}; o.x", valueInt(3), t)
4720 })
4721 t.Run("array literal", func(t *testing.T) {
4722 f("var a = [3, 3, 3, 1 + 2]; a[3]", valueInt(3), t)
4723 })
4724 t.Run("default function parameter", func(t *testing.T) {
4725 ff("function f(arg = 1 + 2) {return arg}; f()", valueInt(3), t)
4726 })
4727 t.Run("return", func(t *testing.T) {
4728 ff("function f() {return 1 + 2}; f()", valueInt(3), t)
4729 })
4730 }
4731
4732 func TestAssignBeforeInit(t *testing.T) {
4733 const SCRIPT = `
4734 assert.throws(ReferenceError, () => {
4735 a = 1;
4736 let a;
4737 });
4738
4739 assert.throws(ReferenceError, () => {
4740 ({a, b} = {a: 1, b: 2});
4741 let a, b;
4742 });
4743
4744 assert.throws(ReferenceError, () => {
4745 (function() {
4746 eval("");
4747 ({a} = {a: 1});
4748 })();
4749 let a;
4750 });
4751
4752 assert.throws(ReferenceError, () => {
4753 const ctx = {x: 1};
4754 function t() {
4755 delete ctx.x;
4756 return 42;
4757 }
4758 with(ctx) {
4759 (function() {
4760 'use strict';
4761 ({x} = {x: t()});
4762 })();
4763 }
4764 return ctx.x;
4765 });
4766
4767 assert.throws(ReferenceError, () => {
4768 const ctx = {x: 1};
4769 function t() {
4770 delete ctx.x;
4771 return 42;
4772 }
4773 with(ctx) {
4774 (function() {
4775 'use strict';
4776 const src = {};
4777 Object.defineProperty(src, "x", {
4778 get() {
4779 return t();
4780 }
4781 });
4782 ({x} = src);
4783 })();
4784 }
4785 return ctx.x;
4786 });
4787 `
4788 testScriptWithTestLib(SCRIPT, _undefined, t)
4789 }
4790
4791 func TestOptChainCallee(t *testing.T) {
4792 const SCRIPT = `
4793 var a;
4794 assert.sameValue(a?.(true), undefined);
4795 a = null;
4796 assert.sameValue(a?.(), undefined);
4797 var o = {n: null};
4798 assert.sameValue(o.m?.(true), undefined);
4799 assert.sameValue(o.n?.(true), undefined);
4800 `
4801 testScriptWithTestLib(SCRIPT, _undefined, t)
4802 }
4803
4804 func TestObjectLiteralSuper(t *testing.T) {
4805 const SCRIPT = `
4806 const proto = {
4807 m() {
4808 return 40;
4809 }
4810 }
4811 const o = {
4812 m() {
4813 return super.m() + 2;
4814 }
4815 }
4816 o.__proto__ = proto;
4817 o.m();
4818 `
4819 testScript(SCRIPT, intToValue(42), t)
4820 }
4821
4822 func TestClassCaptureThisInFieldInit(t *testing.T) {
4823 const SCRIPT = `
4824 let capture;
4825
4826 class C {
4827 a = () => this
4828 }
4829
4830 let c = new C();
4831 c.a() === c;
4832 `
4833 testScript(SCRIPT, valueTrue, t)
4834 }
4835
4836 func TestClassUseThisInFieldInit(t *testing.T) {
4837 const SCRIPT = `
4838 let capture;
4839
4840 class C {
4841 a = this
4842 }
4843
4844 let c = new C();
4845 c.a === c;
4846 `
4847 testScript(SCRIPT, valueTrue, t)
4848 }
4849
4850 func TestClassCaptureThisInStaticFieldInit(t *testing.T) {
4851 const SCRIPT = `
4852 let capture;
4853
4854 class C {
4855 static a = (capture = () => this, 0)
4856 }
4857
4858 let c = new C();
4859 capture() === C;
4860 `
4861 testScript(SCRIPT, valueTrue, t)
4862 }
4863
4864 func TestClassDynCaptureThisInStaticFieldInit(t *testing.T) {
4865 const SCRIPT = `
4866 class C {
4867 static a = eval("this")
4868 }
4869
4870 C.a === C;
4871 `
4872 testScript(SCRIPT, valueTrue, t)
4873 }
4874
4875 func TestCompileClass(t *testing.T) {
4876 const SCRIPT = `
4877 class C extends Error {
4878 a = true;
4879 b = 1;
4880 ["b".toUpperCase()] = 2
4881 static A = Math.random() < 1
4882 constructor(message = "My Error") {
4883 super(message);
4884 }
4885 static M() {
4886 }
4887 static M1() {
4888 }
4889 m() {
4890 //return C.a;
4891 }
4892 m1() {
4893 return true;
4894 }
4895 static {
4896 this.supername = super.name;
4897 }
4898 }
4899 let c = new C();
4900 c.a === true && c.b === 1 && c.B === 2 && c.m1() && C.A && C.supername === "Error";
4901 `
4902 testScript(SCRIPT, valueTrue, t)
4903 }
4904
4905 func TestSuperInEval(t *testing.T) {
4906 const SCRIPT = `
4907 class C extends Error {
4908 constructor() {
4909 eval("super()");
4910 }
4911 m() {
4912 return eval("super.name");
4913 }
4914 }
4915 let c = new C();
4916 c.m() === "Error";
4917 `
4918 testScript(SCRIPT, valueTrue, t)
4919 }
4920
4921 func TestSuperRefDot(t *testing.T) {
4922 const SCRIPT = `
4923 let thisGet, thisSet;
4924 class P {
4925 _p = 0
4926 get p() {
4927 thisGet = this;
4928 return this._p;
4929 }
4930 set p(v) {
4931 thisSet = this;
4932 this._p = v;
4933 }
4934 }
4935
4936 class C extends P {
4937 g() {
4938 return super.p;
4939 }
4940 s(v) {
4941 super.p = v;
4942 }
4943
4944 inc() {
4945 super.p++;
4946 }
4947 incR() {
4948 return super.p++;
4949 }
4950
4951 inc1() {
4952 ++super.p;
4953 }
4954
4955 inc1R() {
4956 return ++super.p;
4957 }
4958 unary() {
4959 return +super.p;
4960 }
4961 pattern() {
4962 [super.p] = [9];
4963 }
4964 }
4965
4966 let o = new C();
4967 assert.sameValue(o.g(), 0, "get value");
4968 assert.sameValue(thisGet, o, "get this");
4969 o.s(1);
4970 assert.sameValue(o._p, 1, "set value");
4971 assert.sameValue(thisSet, o, "set this");
4972
4973 thisGet = undefined;
4974 thisSet = undefined;
4975 o.inc();
4976 assert.sameValue(o._p, 2, "inc value");
4977 assert.sameValue(thisGet, o, "inc thisGet");
4978 assert.sameValue(thisSet, o, "inc thisSet");
4979
4980 thisGet = undefined;
4981 thisSet = undefined;
4982 assert.sameValue(o.incR(), 2, "incR result");
4983 assert.sameValue(o._p, 3, "incR value");
4984 assert.sameValue(thisGet, o, "incR thisGet");
4985 assert.sameValue(thisSet, o, "incR thisSet");
4986
4987 thisGet = undefined;
4988 thisSet = undefined;
4989 o.inc1();
4990 assert.sameValue(o._p, 4, "inc1 value");
4991 assert.sameValue(thisGet, o, "inc1 thisGet");
4992 assert.sameValue(thisSet, o, "inc1 thisSet");
4993
4994 thisGet = undefined;
4995 thisSet = undefined;
4996 assert.sameValue(o.inc1R(), 5, "inc1R result");
4997 assert.sameValue(o._p, 5, "inc1R value");
4998 assert.sameValue(thisGet, o, "inc1R thisGet");
4999 assert.sameValue(thisSet, o, "inc1R thisSet");
5000
5001 assert.sameValue(o.unary(), 5, "unary");
5002
5003 o.pattern();
5004 assert.sameValue(o._p, 9, "pattern");
5005 `
5006 testScriptWithTestLib(SCRIPT, _undefined, t)
5007 }
5008
5009 func TestPrivateRefDot(t *testing.T) {
5010 const SCRIPT = `
5011 class C {
5012 #p = 0;
5013 g() {
5014 return this.#p;
5015 }
5016 s(v) {
5017 this.#p = v;
5018 }
5019
5020 inc() {
5021 this.#p++;
5022 }
5023 incR() {
5024 return this.#p++;
5025 }
5026
5027 inc1() {
5028 ++this.#p;
5029 }
5030
5031 inc1R() {
5032 return ++this.#p;
5033 }
5034 pattern() {
5035 [this.#p] = [9];
5036 }
5037 }
5038
5039 let o = new C();
5040 assert.sameValue(o.g(), 0, "get value");
5041 o.s(1);
5042 assert.sameValue(o.g(), 1, "set value");
5043
5044 o.inc();
5045 assert.sameValue(o.g(), 2, "inc value");
5046
5047 assert.sameValue(o.incR(), 2, "incR result");
5048 assert.sameValue(o.g(), 3, "incR value");
5049
5050 o.inc1();
5051 assert.sameValue(o.g(), 4, "inc1 value");
5052
5053 assert.sameValue(o.inc1R(), 5, "inc1R result");
5054 assert.sameValue(o.g(), 5, "inc1R value");
5055
5056 o.pattern();
5057 assert.sameValue(o.g(), 9, "pattern");
5058 `
5059 testScriptWithTestLib(SCRIPT, _undefined, t)
5060 }
5061
5062 func TestPrivateRefDotEval(t *testing.T) {
5063 const SCRIPT = `
5064 class C {
5065 #p = 0;
5066 g() {
5067 return eval("this.#p");
5068 }
5069 s(v) {
5070 eval("this.#p = v");
5071 }
5072
5073 incR() {
5074 return eval("this.#p++");
5075 }
5076
5077 inc1R() {
5078 return eval("++this.#p");
5079 }
5080
5081 pattern() {
5082 eval("[this.#p] = [9]");
5083 }
5084 }
5085
5086 let o = new C();
5087 assert.sameValue(o.g(), 0, "get value");
5088 o.s(1);
5089 assert.sameValue(o.g(), 1, "set value");
5090
5091 assert.sameValue(o.incR(), 1, "incR result");
5092 assert.sameValue(o.g(), 2, "incR value");
5093
5094 assert.sameValue(o.inc1R(), 3, "inc1R result");
5095 assert.sameValue(o.g(), 3, "inc1R value");
5096
5097 o.pattern();
5098 assert.sameValue(o.g(), 9, "pattern");
5099 `
5100 testScriptWithTestLib(SCRIPT, _undefined, t)
5101 }
5102
5103 func TestSuperRefDotCallee(t *testing.T) {
5104 const SCRIPT = `
5105 class P {
5106 get p() {
5107 return function() {
5108 return this;
5109 };
5110 }
5111 }
5112
5113 class C extends P {
5114 m() {
5115 return super.p();
5116 }
5117 }
5118
5119 let o = new C();
5120 o.m() === o;
5121 `
5122 testScript(SCRIPT, valueTrue, t)
5123 }
5124
5125 func TestSuperRefBracket(t *testing.T) {
5126 const SCRIPT = `
5127 let PROP = "p";
5128 let thisGet, thisSet;
5129 class P {
5130 _p = 0
5131 get p() {
5132 thisGet = this;
5133 return this._p;
5134 }
5135 set p(v) {
5136 thisSet = this;
5137 this._p = v;
5138 }
5139 }
5140
5141 class C extends P {
5142 g() {
5143 return super[PROP];
5144 }
5145 s(v) {
5146 super[PROP] = v;
5147 }
5148
5149 inc() {
5150 super[PROP]++;
5151 }
5152 incR() {
5153 return super[PROP]++;
5154 }
5155
5156 inc1() {
5157 ++super[PROP];
5158 }
5159
5160 inc1R() {
5161 return ++super[PROP];
5162 }
5163 pattern() {
5164 [super[PROP]] = [9];
5165 }
5166 }
5167
5168 let o = new C();
5169 assert.sameValue(o.g(), 0, "get value");
5170 assert.sameValue(thisGet, o, "get this");
5171 o.s(1);
5172 assert.sameValue(o._p, 1, "set value");
5173 assert.sameValue(thisSet, o, "set this");
5174
5175 thisGet = undefined;
5176 thisSet = undefined;
5177 o.inc();
5178 assert.sameValue(o._p, 2, "inc value");
5179 assert.sameValue(thisGet, o, "inc thisGet");
5180 assert.sameValue(thisSet, o, "inc thisSet");
5181
5182 thisGet = undefined;
5183 thisSet = undefined;
5184 assert.sameValue(o.incR(), 2, "incR result");
5185 assert.sameValue(o._p, 3, "incR value");
5186 assert.sameValue(thisGet, o, "incR thisGet");
5187 assert.sameValue(thisSet, o, "incR thisSet");
5188
5189 thisGet = undefined;
5190 thisSet = undefined;
5191 o.inc1();
5192 assert.sameValue(o._p, 4, "inc1 value");
5193 assert.sameValue(thisGet, o, "inc1 thisGet");
5194 assert.sameValue(thisSet, o, "inc1 thisSet");
5195
5196 thisGet = undefined;
5197 thisSet = undefined;
5198 assert.sameValue(o.inc1R(), 5, "inc1R result");
5199 assert.sameValue(o._p, 5, "inc1R value");
5200 assert.sameValue(thisGet, o, "inc1R thisGet");
5201 assert.sameValue(thisSet, o, "inc1R thisSet");
5202
5203 o.pattern();
5204 assert.sameValue(o._p, 9, "pattern");
5205 `
5206 testScriptWithTestLib(SCRIPT, _undefined, t)
5207 }
5208
5209 func TestSuperRefBracketEvalOrder(t *testing.T) {
5210 const SCRIPT = `
5211 let keyCallCount = 0;
5212
5213 function key() {
5214 keyCallCount++;
5215 C.prototype.__proto__ = null;
5216 return "k";
5217 }
5218
5219 class C {
5220 constructor() {
5221 super[key()]++;
5222 }
5223 }
5224
5225 assert.throws(TypeError, () => new C());
5226 assert.sameValue(keyCallCount, 1);
5227 `
5228 testScriptWithTestLib(SCRIPT, _undefined, t)
5229 }
5230
5231 func TestSuperRefBracketCallee(t *testing.T) {
5232 const SCRIPT = `
5233 let PROP = "p";
5234 class P {
5235 get p() {
5236 return function() {
5237 return this;
5238 };
5239 }
5240 }
5241
5242 class C extends P {
5243 m() {
5244 return super[PROP]();
5245 }
5246 }
5247
5248 let o = new C();
5249 o.m() === o;
5250 `
5251 testScript(SCRIPT, valueTrue, t)
5252 }
5253
5254 func TestSuperBaseInCtor(t *testing.T) {
5255 const SCRIPT = `
5256 let result;
5257 class Derived extends Object {
5258 constructor() {
5259 super();
5260 result = super.constructor === Object;
5261 }
5262 }
5263 new Derived();
5264 result;
5265 `
5266 testScript(SCRIPT, valueTrue, t)
5267 }
5268
5269 func TestClassNamedEval(t *testing.T) {
5270 const SCRIPT = `
5271 const C = class {
5272 }
5273
5274 C.name === "C";
5275 `
5276 testScript(SCRIPT, valueTrue, t)
5277 }
5278
5279 func TestClassNonDerived(t *testing.T) {
5280 const SCRIPT = `
5281 function initF() {
5282 }
5283 class C {
5284 f = initF()
5285 }
5286 let c = new C();
5287 `
5288
5289 testScript(SCRIPT, _undefined, t)
5290 }
5291
5292 func TestClassExpr(t *testing.T) {
5293 const SCRIPT = `
5294 typeof Object.getOwnPropertyDescriptor(class {get f() {}}.prototype, "f").get === "function";
5295 `
5296
5297 testScript(SCRIPT, valueTrue, t)
5298 }
5299
5300 func TestClassSuperInHeritage(t *testing.T) {
5301 const SCRIPT = `
5302 class P {
5303 a() {
5304 return Error;
5305 }
5306 }
5307
5308 class C extends P {
5309 m() {
5310 class Inner extends super.a() {
5311 }
5312 return new Inner();
5313 }
5314 }
5315
5316 new C().m() instanceof Error;
5317 `
5318
5319 testScript(SCRIPT, valueTrue, t)
5320 }
5321
5322 func TestClassSuperInHeritageExpr(t *testing.T) {
5323 const SCRIPT = `
5324 class P {
5325 a() {
5326 return Error;
5327 }
5328 }
5329
5330 class C extends P {
5331 m() {
5332 function f(cls) {
5333 return new cls();
5334 }
5335 return f(class Inner extends super.a() {
5336 })
5337 }
5338 }
5339
5340 new C().m() instanceof Error;
5341 `
5342
5343 testScript(SCRIPT, valueTrue, t)
5344 }
5345
5346 func TestClassReferToBinding(t *testing.T) {
5347 const SCRIPT = `
5348 const CC = class C {
5349 static T = 40
5350 f = C.T + 2
5351 }
5352 let c = new CC();
5353 c.f;
5354 `
5355
5356 testScript(SCRIPT, intToValue(42), t)
5357 }
5358
5359 func TestClassReferToBindingInStaticDecl(t *testing.T) {
5360 const SCRIPT = `
5361 class C {
5362 static T = C.name
5363 }
5364 C.T;
5365 `
5366
5367 testScript(SCRIPT, asciiString("C"), t)
5368 }
5369
5370 func TestClassReferToBindingInStaticEval(t *testing.T) {
5371 const SCRIPT = `
5372 const CC = class C {
5373 static T = eval("C.name")
5374 }
5375 CC.T;
5376 `
5377
5378 testScript(SCRIPT, asciiString("C"), t)
5379 }
5380
5381 func TestClassReferToBindingFromHeritage(t *testing.T) {
5382 const SCRIPT = `
5383 assert.throws(ReferenceError, () => {
5384 class C extends C {
5385 }
5386 });
5387 `
5388
5389 testScriptWithTestLib(SCRIPT, _undefined, t)
5390 }
5391
5392 func TestClassCaptureSuperCallInArrowFunc(t *testing.T) {
5393 const SCRIPT = `
5394 let f;
5395 class C extends class {} {
5396 constructor() {
5397 f = () => super();
5398 f();
5399 }
5400 }
5401 let c = new C();
5402 `
5403
5404 testScript(SCRIPT, _undefined, t)
5405 }
5406
5407 func TestClassCaptureSuperCallInNestedArrowFunc(t *testing.T) {
5408 const SCRIPT = `
5409 let f;
5410 class P {
5411 }
5412 class C extends P {
5413 constructor() {
5414 f = () => () => super();
5415 f()();
5416 }
5417 }
5418 new C() instanceof P;
5419 `
5420
5421 testScript(SCRIPT, valueTrue, t)
5422 }
5423
5424 func TestThisInEval(t *testing.T) {
5425 const SCRIPT = `
5426 assert.sameValue(eval("this"), this, "global");
5427
5428 let o = {
5429 f() {
5430 return eval("this");
5431 }
5432 }
5433 assert.sameValue(o.f(), o, "obj literal");
5434 `
5435
5436 testScriptWithTestLib(SCRIPT, _undefined, t)
5437 }
5438
5439 func TestStaticAsBindingTarget(t *testing.T) {
5440 const SCRIPT = `
5441 let [static] = [];
5442 `
5443 testScript(SCRIPT, _undefined, t)
5444 }
5445
5446 func TestEvalInStaticFieldInit(t *testing.T) {
5447 const SCRIPT = `
5448 var C = class {
5449 static f = 'test';
5450 static g = this.f + '262';
5451 static h = eval('this.g') + 'test';
5452 }
5453 C.f === "test" && C.g === "test262" && C.h === "test262test";
5454 `
5455 testScript(SCRIPT, valueTrue, t)
5456 }
5457
5458 func TestClassPrivateElemInEval(t *testing.T) {
5459 const SCRIPT = `
5460 let f1, f2;
5461
5462 class C extends (f1 = o => eval("o.#a"), Object) {
5463 static #a = 42;
5464 static {
5465 f2 = o => eval("o.#a");
5466 assert.sameValue(C.#a, 42);
5467 assert.sameValue((() => C.#a)(), 42);
5468 }
5469 }
5470
5471 assert.throws(SyntaxError, () => f1(C));
5472 assert.sameValue(f2(C), 42);
5473 `
5474 testScriptWithTestLib(SCRIPT, _undefined, t)
5475 }
5476
5477 func TestClassPrivateElemInIndirectEval(t *testing.T) {
5478 const SCRIPT = `
5479 let f1, f2;
5480
5481 class C extends (f1 = o => (0, eval)("o.#a"), Object) {
5482 static #a = 42;
5483 static {
5484 f2 = o => (0, eval)("o.#a");
5485 assert.throws(SyntaxError, () => (0, eval)("C.#a"));
5486 }
5487 }
5488
5489 assert.throws(SyntaxError, () => f1(C));
5490 assert.throws(SyntaxError, () => f2(C));
5491 `
5492 testScriptWithTestLib(SCRIPT, _undefined, t)
5493 }
5494
5495 func TestClassPrivateElemInFunction(t *testing.T) {
5496 const SCRIPT = `
5497 assert.throws(SyntaxError, () => {
5498 class C {
5499 static #a = 42;
5500 static {
5501 Function("o", "return o.#a");
5502 }
5503 }
5504 });
5505 `
5506 testScriptWithTestLib(SCRIPT, _undefined, t)
5507 }
5508
5509 func TestClassPrivateElementsDecl(t *testing.T) {
5510 const SCRIPT = `
5511 class C {
5512 #a = 42;
5513 get #b() {}
5514 set #b(_) {}
5515 get c() {
5516 return this.#a;
5517 }
5518 #m() {
5519 return this.#a;
5520 }
5521 static getter(inst) {
5522 return inst.#m();
5523 }
5524 }
5525 let c = new C();
5526 c.c + C.getter(c);
5527 `
5528 testScript(SCRIPT, intToValue(84), t)
5529 }
5530
5531 func TestPrivateIn(t *testing.T) {
5532 const SCRIPT = `
5533 class C {
5534 #a = 42;
5535 static check(inst) {
5536 return #a in inst;
5537 }
5538 }
5539 let c = new C();
5540 C.check(c);
5541 `
5542 testScript(SCRIPT, valueTrue, t)
5543 }
5544
5545 func TestDeletePropOfNonObject(t *testing.T) {
5546 const SCRIPT = `
5547 delete 'Test262'[100] && delete 'Test262'.a && delete 'Test262'['@'];
5548 `
5549 testScript(SCRIPT, valueTrue, t)
5550 }
5551
5552 func TestKeywordsAsLabels(t *testing.T) {
5553 const SCRIPT = `
5554 let: for (let i = 0; i < 2; i++) {
5555 if (i === 0) continue let;
5556 break let;
5557 }
5558
5559 \u006Cet: for (let i = 0; i < 2; i++) {
5560 if (i === 0) continue \u006Cet;
5561 break \u006Cet;
5562 }
5563
5564 yield: for (let i = 0; i < 2; i++) {
5565 if (i === 0) continue yield;
5566 break yield;
5567 }
5568
5569 yi\u0065ld: for (let i = 0; i < 2; i++) {
5570 if (i === 0) continue yi\u0065ld;
5571 break yi\u0065ld;
5572 }
5573 `
5574 testScript(SCRIPT, _undefined, t)
5575 }
5576
5577 func TestThisResolutionWithArg(t *testing.T) {
5578 const SCRIPT = `
5579 let capture;
5580 function f(arg) {
5581 capture = () => this; // move 'this' to stash
5582 return [this, arg];
5583 }
5584 const _this = {};
5585 const arg = {};
5586 const [_this1, arg1] = f.call(_this, arg);
5587 _this1 === _this && arg1 === arg;
5588 `
5589 testScript(SCRIPT, valueTrue, t)
5590 }
5591
5592 func TestThisResolutionArgInStash(t *testing.T) {
5593 const SCRIPT = `
5594 let capture;
5595 function f(arg) {
5596 capture = () => this + arg; // move 'this' and arguments to stash
5597 return [this, arg];
5598 }
5599 const _this = {};
5600 const arg = {};
5601 const [_this1, arg1] = f.call(_this, arg);
5602 _this1 === _this && arg1 === arg;
5603 `
5604 testScript(SCRIPT, valueTrue, t)
5605 }
5606
5607 func TestThisResolutionWithStackVar(t *testing.T) {
5608 const SCRIPT = `
5609 let capture;
5610 function f(arg) {
5611 const _ = 1; // a stack variable
5612 capture = () => this + arg; // move 'this' and arguments to stash
5613 return [this, arg];
5614 }
5615 const _this = {};
5616 const arg = {};
5617 const [_this1, arg1] = f.call(_this, arg);
5618 _this1 === _this && arg1 === arg;
5619 `
5620 testScript(SCRIPT, valueTrue, t)
5621 }
5622
5623 func TestForInLoopContinue(t *testing.T) {
5624 const SCRIPT = `
5625 var globalSink;
5626 (function() {
5627 const data = [{disabled: true}, {}];
5628 function dummy() {}
5629 function f1() {}
5630
5631 function f() {
5632 dummy(); // move dummy to stash (so that f1 is at index 1)
5633 for (const d of data) {
5634 if (d.disabled) continue;
5635 globalSink = () => d; // move d to stash
5636 f1();
5637 }
5638 }
5639
5640 f();
5641 })();
5642 `
5643 testScript(SCRIPT, _undefined, t)
5644 }
5645
5646 func TestForInLoopContinueOuter(t *testing.T) {
5647 const SCRIPT = `
5648 var globalSink;
5649 (function() {
5650 const data = [{disabled: true}, {}];
5651 function dummy1() {}
5652 function f1() {}
5653
5654 function f() {
5655 dummy1();
5656 let counter = 0;
5657 OUTER: for (let i = 0; i < 1; i++) {
5658 for (const d of data) {
5659 if (d.disabled) continue OUTER;
5660 globalSink = () => d;
5661 }
5662 counter++;
5663 }
5664 f1();
5665 if (counter !== 0) {
5666 throw new Error(counter);
5667 }
5668 }
5669
5670 f();
5671 })();
5672 `
5673 testScript(SCRIPT, _undefined, t)
5674 }
5675
5676 func TestLexicalDeclInSwitch(t *testing.T) {
5677 const SCRIPT = `
5678 switch(0) {
5679 case 1:
5680 if (false) b = 3;
5681 case 2:
5682 const c = 1;
5683 }
5684 `
5685 testScript(SCRIPT, _undefined, t)
5686 }
5687
5688 func TestClassFieldSpecial(t *testing.T) {
5689 const SCRIPT = `
5690 class C {
5691 get;
5692 set;
5693 async;
5694 static;
5695 }
5696 `
5697 testScript(SCRIPT, _undefined, t)
5698 }
5699
5700 func TestClassMethodSpecial(t *testing.T) {
5701 const SCRIPT = `
5702 class C {
5703 get() {}
5704 set() {}
5705 async() {}
5706 static() {}
5707 }
5708 `
5709 testScript(SCRIPT, _undefined, t)
5710 }
5711
5712 func TestClassMethodNumLiteral(t *testing.T) {
5713 const SCRIPT = `
5714 class C {
5715 0() {
5716 return true;
5717 }
5718 }
5719 new C()[0]();
5720 `
5721 testScript(SCRIPT, valueTrue, t)
5722 }
5723
5724 func TestAsyncFunc(t *testing.T) {
5725 const SCRIPT = `
5726 async (x = true, y) => {};
5727 async x => {};
5728 let passed = false;
5729 async function f() {
5730 return true;
5731 }
5732 async function f1(arg = true) {
5733 passed = await f();
5734 }
5735 await f1();
5736 return passed;
5737 `
5738 testAsyncFunc(SCRIPT, valueTrue, t)
5739 }
5740
5741 func TestObjectLiteralComputedMethodKeys(t *testing.T) {
5742 _, err := Compile("", `
5743 ({
5744 ["__proto__"]() {},
5745 ["__proto__"]() {}
5746 })
5747 `, false)
5748 if err != nil {
5749 t.Fatal(err)
5750 }
5751
5752 _, err = Compile("", `
5753 ({
5754 get ["__proto__"]() {},
5755 get ["__proto__"]() {}
5756 })
5757 `, false)
5758 if err != nil {
5759 t.Fatal(err)
5760 }
5761 }
5762
5763 func TestGeneratorFunc(t *testing.T) {
5764 const SCRIPT = `
5765 let trace = "";
5766 function defParam() {
5767 trace += "1";
5768 return "def";
5769 }
5770 function* g(param = defParam()) {
5771 const THREE = 3;
5772 trace += "2";
5773 assert.sameValue(Math.floor(yield 1), THREE);
5774 return 42;
5775 }
5776 let iter = g();
5777 assert.sameValue(trace, "1");
5778
5779 let next = iter.next();
5780 assert.sameValue(next.value, 1);
5781 assert.sameValue(next.done, false);
5782
5783 next = iter.next(Math.PI);
5784 assert.sameValue(next.value, 42);
5785 assert.sameValue(next.done, true);
5786
5787 assert.sameValue(trace, "12");
5788 `
5789 testScriptWithTestLib(SCRIPT, _undefined, t)
5790 }
5791
5792 func TestGeneratorMethods(t *testing.T) {
5793 const SCRIPT = `
5794 class C {
5795 *g(param) {
5796 yield 1;
5797 yield 2;
5798 }
5799 }
5800 let c = new C();
5801 let iter = c.g();
5802 let res = iter.next();
5803 assert.sameValue(res.value, 1);
5804 assert.sameValue(res.done, false);
5805
5806 res = iter.next();
5807 assert.sameValue(res.value, 2);
5808 assert.sameValue(res.done, false);
5809
5810 res = iter.next();
5811 assert.sameValue(res.value, undefined);
5812 assert.sameValue(res.done, true);
5813 `
5814 testScriptWithTestLib(SCRIPT, _undefined, t)
5815 }
5816
5817 func TestFunctionBodyClassDecl(t *testing.T) {
5818 const SCRIPT = `
5819 function as(requiredArgument = {}) {
5820 class something { }
5821 };
5822 `
5823 _, err := Compile("", SCRIPT, false)
5824 if err != nil {
5825 t.Fatal(err)
5826 }
5827 }
5828
5829
5845
5846 func BenchmarkCompile(b *testing.B) {
5847 data, err := os.ReadFile("testdata/S15.10.2.12_A1_T1.js")
5848 if err != nil {
5849 b.Fatal(err)
5850 }
5851
5852 src := string(data)
5853
5854 for i := 0; i < b.N; i++ {
5855 _, err := Compile("test.js", src, false)
5856 if err != nil {
5857 b.Fatal(err)
5858 }
5859 }
5860 }
5861
View as plain text