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