go.ketch.com/lib/goja@v0.0.1/compiler_test.go (about)

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