mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
12 years ago
257 changed files with 30503 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,63 @@ |
|||
/* |
|||
* E5 Section 10.6, main algorithm step 14 requires that a strict |
|||
* arguments object 'callee' and 'caller' throwers must be the specific |
|||
* thrower defined in E5 Section 13.2.3. |
|||
*/ |
|||
|
|||
/*=== |
|||
test get and set |
|||
object |
|||
object |
|||
object |
|||
object |
|||
true |
|||
true |
|||
true |
|||
true |
|||
true |
|||
true |
|||
true |
|||
TypeError |
|||
TypeError |
|||
===*/ |
|||
|
|||
function f(x,y) { 'use strict'; return arguments; }; |
|||
function g(x,y) { 'use strict'; return arguments; }; |
|||
|
|||
var a = f(1,2,3); |
|||
var b = g(3,2,1); |
|||
|
|||
pd1 = Object.getOwnPropertyDescriptor(a, "caller"); |
|||
pd2 = Object.getOwnPropertyDescriptor(a, "callee"); |
|||
pd3 = Object.getOwnPropertyDescriptor(b, "caller"); |
|||
pd4 = Object.getOwnPropertyDescriptor(b, "callee"); |
|||
|
|||
print('test get and set') |
|||
print(typeof pd1); |
|||
print(typeof pd2); |
|||
print(typeof pd3); |
|||
print(typeof pd4); |
|||
|
|||
// all of these should print true
|
|||
|
|||
print(pd1.get === pd1.set); |
|||
print(pd2.get === pd2.set); |
|||
print(pd3.get === pd3.set); |
|||
print(pd4.get === pd4.set); |
|||
|
|||
print(pd1.get === pd2.get); |
|||
print(pd2.get === pd3.get); |
|||
print(pd3.get === pd4.get); |
|||
|
|||
try { |
|||
pd1.get(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
pd2.get(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Array objects (E5 Section 15.4). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME: */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Boolean objects (E5 Section 15.6). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Date objects (E5 Sections 15.9, B.2.4, B.2.5, B.2.6). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* __duk__ builtin. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Error objects (E5 Section 15.11). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Function objects (E5 Section 15.3). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,42 @@ |
|||
/* |
|||
* Builtin global (E5 Sections 15.1, B.2.1, B.2.2) |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
var indirectEval = eval; |
|||
var global = indirectEval('this'); |
|||
|
|||
/*=== |
|||
[object global] |
|||
===*/ |
|||
|
|||
/* [[Class]] implementation defined, but we expect 'global' */ |
|||
|
|||
print(global); |
|||
|
|||
/*=== |
|||
TypeError |
|||
TypeError |
|||
===*/ |
|||
|
|||
/* Not callable or constructable */ |
|||
|
|||
try { |
|||
global(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
new global(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,15 @@ |
|||
/* |
|||
* JSON object (E5 Section 15.12). |
|||
* |
|||
* There are detailed JSON tests elsewhere. Here we test the basic |
|||
* functionality. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,795 @@ |
|||
/* |
|||
* Math object (E5 Section 15.8). |
|||
* |
|||
* Difficulties arise from: |
|||
* |
|||
* - Trigonometric functions are not required to be bit exact |
|||
* - Random number testing |
|||
* - Some calls distinguish between +0 and -0 (e.g. asin) |
|||
* |
|||
* To distinguish zero signs, the idiom '1 / x' is used. If x is +0, |
|||
* this will result in Infinity, and if x is -0, it will result in |
|||
* -Infinity. |
|||
*/ |
|||
|
|||
function printRounded6(x) { |
|||
print(Math.round(x * 1000000)); |
|||
} |
|||
|
|||
function printExact(x) { |
|||
print(x.toString()); |
|||
} |
|||
|
|||
function zeroSign(x) { |
|||
if (x !== 0) { |
|||
return 'zero expected'; |
|||
} |
|||
if (1 / x >= 0) { |
|||
return 1; |
|||
} else { |
|||
return -1; |
|||
} |
|||
} |
|||
|
|||
var pr6 = printRounded6; |
|||
var prE = printExact; |
|||
|
|||
/*=== |
|||
rounded constant test |
|||
2718282 |
|||
2302585 |
|||
693147 |
|||
1442695 |
|||
434294 |
|||
3141593 |
|||
707107 |
|||
1414214 |
|||
===*/ |
|||
|
|||
/* Rounded constant test. */ |
|||
|
|||
print('rounded constant test'); |
|||
pr6(Math.E); |
|||
pr6(Math.LN10); |
|||
pr6(Math.LN2); |
|||
pr6(Math.LOG2E); |
|||
pr6(Math.LOG10E); |
|||
pr6(Math.PI); |
|||
pr6(Math.SQRT1_2); |
|||
pr6(Math.SQRT2); |
|||
|
|||
/*=== |
|||
exact constant test |
|||
2.718281828459045 |
|||
2.302585092994046 |
|||
0.6931471805599453 |
|||
1.4426950408889634 |
|||
0.4342944819032518 |
|||
3.141592653589793 |
|||
0.7071067811865476 |
|||
1.4142135623730951 |
|||
===*/ |
|||
|
|||
/* Exact constant test. The results were taken from V8 and compared |
|||
* against Rhino. |
|||
*/ |
|||
|
|||
print('exact constant test'); |
|||
prE(Math.E); |
|||
prE(Math.LN10); |
|||
prE(Math.LN2); |
|||
prE(Math.LOG2E); |
|||
prE(Math.LOG10E); |
|||
prE(Math.PI); |
|||
prE(Math.SQRT1_2); |
|||
prE(Math.SQRT2); |
|||
|
|||
/*=== |
|||
abs |
|||
123 |
|||
123 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
NaN |
|||
Infinity |
|||
Infinity |
|||
===*/ |
|||
|
|||
print('abs'); |
|||
prE(Math.abs(+123)); |
|||
prE(Math.abs(-123)); |
|||
prE(Math.abs(+0)); |
|||
print(zeroSign(Math.abs(+0))); |
|||
prE(Math.abs(-0)); |
|||
print(zeroSign(Math.abs(-0))); |
|||
prE(Math.abs(Number.NaN)); |
|||
prE(Math.abs(Number.POSITIVE_INFINITY)); |
|||
prE(Math.abs(Number.NEGATIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
acos |
|||
1570796 |
|||
0 |
|||
1 |
|||
3141593 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
===*/ |
|||
|
|||
print('acos'); |
|||
pr6(Math.acos(0)); |
|||
prE(Math.acos(1)); |
|||
print(zeroSign(Math.acos(1))); |
|||
pr6(Math.acos(-1)) |
|||
pr6(Math.acos(Number.NaN)); |
|||
pr6(Math.acos(1.0000001)); |
|||
pr6(Math.acos(-1.0000001)); |
|||
|
|||
/*=== |
|||
asin |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
1570796 |
|||
-1570796 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
===*/ |
|||
|
|||
print('asin'); |
|||
prE(Math.asin(+0)); |
|||
print(zeroSign(Math.asin(+0))); |
|||
prE(Math.asin(-0)); |
|||
print(zeroSign(Math.asin(-0))); |
|||
pr6(Math.asin(1)); |
|||
pr6(Math.asin(-1)) |
|||
pr6(Math.asin(Number.NaN)); |
|||
pr6(Math.asin(1.0000001)); |
|||
pr6(Math.asin(-1.0000001)); |
|||
|
|||
/*=== |
|||
atan |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
1570796 |
|||
-1570796 |
|||
===*/ |
|||
|
|||
print('atan'); |
|||
prE(Math.atan(Number.NaN)); |
|||
prE(Math.atan(+0)); |
|||
print(zeroSign(Math.atan(+0))); |
|||
prE(Math.atan(-0)); |
|||
print(zeroSign(Math.atan(-0))); |
|||
pr6(Math.atan(Number.POSITIVE_INFINITY)); |
|||
pr6(Math.atan(Number.NEGATIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
atan2 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
1570796 |
|||
1570796 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
3141593 |
|||
3141593 |
|||
0 |
|||
-1 |
|||
0 |
|||
-1 |
|||
-3141593 |
|||
-3141593 |
|||
-1570796 |
|||
-1570796 |
|||
0 |
|||
1 |
|||
3141593 |
|||
0 |
|||
-1 |
|||
-3141593 |
|||
1570796 |
|||
1570796 |
|||
-1570796 |
|||
-1570796 |
|||
785398 |
|||
2356194 |
|||
-785398 |
|||
-2356194 |
|||
===*/ |
|||
|
|||
print('atan2'); |
|||
prE(Math.atan2(NaN, NaN)); |
|||
prE(Math.atan2(1, NaN)); |
|||
prE(Math.atan2(NaN, 1)); |
|||
pr6(Math.atan2(1, +0)); |
|||
pr6(Math.atan2(1, -0)); |
|||
|
|||
prE(Math.atan2(+0, 1)); print(zeroSign(Math.atan2(+0, 1))); |
|||
prE(Math.atan2(+0, +0)); print(zeroSign(Math.atan2(+0, +0))); |
|||
pr6(Math.atan2(+0, -0)); |
|||
pr6(Math.atan2(+0, -1)); |
|||
|
|||
prE(Math.atan2(-0, 1)); print(zeroSign(Math.atan2(-0, 1))); |
|||
prE(Math.atan2(-0, +0)); print(zeroSign(Math.atan2(-0, +0))); |
|||
pr6(Math.atan2(-0, -0)); |
|||
pr6(Math.atan2(-0, -1)); |
|||
|
|||
pr6(Math.atan2(-1, +0)); |
|||
pr6(Math.atan2(-1, -0)); |
|||
|
|||
prE(Math.atan2(1, Number.POSITIVE_INFINITY)); print(zeroSign(Math.atan2(1, Number.POSITIVE_INFINITY))); |
|||
pr6(Math.atan2(1, Number.NEGATIVE_INFINITY)); |
|||
prE(Math.atan2(-1, Number.POSITIVE_INFINITY)); print(zeroSign(Math.atan2(-1, Number.POSITIVE_INFINITY))); |
|||
pr6(Math.atan2(-1, Number.NEGATIVE_INFINITY)); |
|||
|
|||
pr6(Math.atan2(Number.POSITIVE_INFINITY, 1)); |
|||
pr6(Math.atan2(Number.POSITIVE_INFINITY, -1)); |
|||
pr6(Math.atan2(Number.NEGATIVE_INFINITY, 1)); |
|||
pr6(Math.atan2(Number.NEGATIVE_INFINITY, -1)); |
|||
|
|||
pr6(Math.atan2(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY)); |
|||
pr6(Math.atan2(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY)); |
|||
pr6(Math.atan2(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY)); |
|||
pr6(Math.atan2(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
ceil |
|||
123 |
|||
124 |
|||
-123 |
|||
-122 |
|||
4294967307 |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
Infinity |
|||
-Infinity |
|||
0 |
|||
-1 |
|||
-1 |
|||
===*/ |
|||
|
|||
print('ceil'); |
|||
|
|||
prE(Math.ceil(123)); |
|||
prE(Math.ceil(123.000001)); |
|||
prE(Math.ceil(-123)); |
|||
prE(Math.ceil(-122.999999)); |
|||
|
|||
prE(Math.ceil(4294967306.5)); // value higher than 32 bits
|
|||
|
|||
prE(Math.ceil(NaN)); |
|||
prE(Math.ceil(+0)); print(zeroSign(Math.ceil(+0))); |
|||
prE(Math.ceil(-0)); print(zeroSign(Math.ceil(-0))); |
|||
prE(Number.POSITIVE_INFINITY); |
|||
prE(Number.NEGATIVE_INFINITY); |
|||
prE(Math.ceil(-0.5)); print(zeroSign(Math.ceil(-0.5))); |
|||
prE(Math.ceil(-1.0)); |
|||
|
|||
/*=== |
|||
cos |
|||
NaN |
|||
1 |
|||
1 |
|||
NaN |
|||
NaN |
|||
540302 |
|||
===*/ |
|||
|
|||
print('cos'); |
|||
|
|||
prE(Math.cos(NaN)); |
|||
prE(Math.cos(+0)); |
|||
prE(Math.cos(-0)); |
|||
prE(Math.cos(Number.POSITIVE_INFINITY)); |
|||
prE(Math.cos(Number.NEGATIVE_INFINITY)); |
|||
pr6(Math.cos(1)); |
|||
|
|||
/*=== |
|||
exp |
|||
NaN |
|||
1 |
|||
1 |
|||
Infinity |
|||
0 |
|||
1 |
|||
===*/ |
|||
|
|||
print('exp'); |
|||
|
|||
prE(Math.exp(NaN)); |
|||
prE(Math.exp(+0)); |
|||
prE(Math.exp(-0)); |
|||
prE(Math.exp(Number.POSITIVE_INFINITY)); |
|||
prE(Math.exp(Number.NEGATIVE_INFINITY)); print(zeroSign(Math.exp(Number.NEGATIVE_INFINITY))); |
|||
|
|||
/*=== |
|||
floor |
|||
123 |
|||
122 |
|||
-123 |
|||
-124 |
|||
4294967306 |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
Infinity |
|||
-Infinity |
|||
0 |
|||
1 |
|||
1 |
|||
===*/ |
|||
|
|||
print('floor'); |
|||
|
|||
prE(Math.floor(123)); |
|||
prE(Math.floor(122.999999)); |
|||
prE(Math.floor(-123)); |
|||
prE(Math.floor(-124)); |
|||
|
|||
prE(Math.floor(4294967306.5)); // value higher than 32 bits
|
|||
|
|||
prE(Math.floor(NaN)); |
|||
prE(Math.floor(+0)); print(zeroSign(Math.floor(+0))); |
|||
prE(Math.floor(-0)); print(zeroSign(Math.floor(-0))); |
|||
prE(Math.floor(Number.POSITIVE_INFINITY)); |
|||
prE(Math.floor(Number.NEGATIVE_INFINITY)); |
|||
prE(Math.floor(0.5)); print(zeroSign(Math.floor(0.5))); |
|||
prE(Math.floor(1)); |
|||
|
|||
/*=== |
|||
log |
|||
4812184 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
-Infinity |
|||
-Infinity |
|||
0 |
|||
1 |
|||
Infinity |
|||
===*/ |
|||
|
|||
print('log'); |
|||
|
|||
pr6(Math.log(123)); |
|||
|
|||
prE(Math.log(NaN)); |
|||
|
|||
prE(Math.log(-0.000001)); |
|||
prE(Math.log(Number.NEGATIVE_INFINITY)); |
|||
|
|||
prE(Math.log(+0)); |
|||
prE(Math.log(-0)); |
|||
|
|||
prE(Math.log(1)); print(zeroSign(Math.log(1))); |
|||
|
|||
prE(Math.log(Number.POSITIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
max |
|||
456 |
|||
Infinity |
|||
123 |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
-Infinity |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
===*/ |
|||
|
|||
print('max'); |
|||
|
|||
prE(Math.max(123, -123, 456, 234)); |
|||
prE(Math.max(123, -123, Number.POSITIVE_INFINITY, 234)); |
|||
prE(Math.max(123)); |
|||
|
|||
prE(Math.max(+0)); |
|||
print(zeroSign(Math.max(+0))); |
|||
prE(Math.max(-0)); |
|||
print(zeroSign(Math.max(-0))); |
|||
|
|||
prE(Math.max()); // -> -Infinity (!)
|
|||
prE(Math.max(1,2,NaN,4)); |
|||
|
|||
prE(Math.max(+0, -0)); // -> +0
|
|||
print(zeroSign(Math.max(+0, -0))); |
|||
|
|||
prE(Math.max(-0, +0)); // -> +0
|
|||
print(zeroSign(Math.max(-0, +0))); |
|||
|
|||
/*=== |
|||
min |
|||
-123 |
|||
-Infinity |
|||
123 |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
Infinity |
|||
NaN |
|||
0 |
|||
-1 |
|||
0 |
|||
-1 |
|||
===*/ |
|||
|
|||
print('min'); |
|||
|
|||
prE(Math.min(123, -123, 456, 234)); |
|||
prE(Math.min(123, -123, Number.NEGATIVE_INFINITY, 234)); |
|||
prE(Math.min(123)); |
|||
|
|||
prE(Math.min(+0)); |
|||
print(zeroSign(Math.min(+0))); |
|||
prE(Math.min(-0)); |
|||
print(zeroSign(Math.min(-0))); |
|||
|
|||
prE(Math.min()); // -> Infinity (!)
|
|||
prE(Math.min(1,2,NaN,4)); |
|||
|
|||
prE(Math.min(+0, -0)); // -> -0
|
|||
print(zeroSign(Math.min(+0, -0))); |
|||
|
|||
prE(Math.min(-0, +0)); // -> -0
|
|||
print(zeroSign(Math.min(-0, +0))); |
|||
|
|||
/*=== |
|||
pow 1 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
NaN |
|||
NaN |
|||
NaN |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
1 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
NaN |
|||
===*/ |
|||
|
|||
print('pow 1'); |
|||
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, NaN)); |
|||
prE(Math.pow(-1, NaN)); |
|||
prE(Math.pow(-0, NaN)); |
|||
prE(Math.pow(+0, NaN)); |
|||
prE(Math.pow(1, NaN)); |
|||
prE(Math.pow(Number.POSITIVE_INFINITY, NaN)); |
|||
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, +0)); |
|||
prE(Math.pow(-1, +0)); |
|||
prE(Math.pow(-0, +0)); |
|||
prE(Math.pow(+0, +0)); |
|||
prE(Math.pow(1, +0)); |
|||
prE(Math.pow(Number.POSITIVE_INFINITY, +0)); |
|||
prE(Math.pow(NaN, +0)); |
|||
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, -0)); |
|||
prE(Math.pow(-1, -0)); |
|||
prE(Math.pow(-0, -0)); |
|||
prE(Math.pow(+0, -0)); |
|||
prE(Math.pow(1, -0)); |
|||
prE(Math.pow(Number.POSITIVE_INFINITY, -0)); |
|||
prE(Math.pow(NaN, -0)); |
|||
|
|||
prE(Math.pow(NaN, Number.NEGATIVE_INFINITY)); |
|||
prE(Math.pow(NaN, -1)); |
|||
prE(Math.pow(NaN, +1)); |
|||
prE(Math.pow(NaN, Number.POSITIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
pow 2 |
|||
Infinity |
|||
Infinity |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
Infinity |
|||
Infinity |
|||
Infinity |
|||
0 |
|||
1 |
|||
-Infinity |
|||
Infinity |
|||
Infinity |
|||
Infinity |
|||
0 |
|||
-1 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
===*/ |
|||
|
|||
print('pow 2'); |
|||
|
|||
prE(Math.pow(1.0000001, Number.POSITIVE_INFINITY)); |
|||
prE(Math.pow(-1.0000001, Number.POSITIVE_INFINITY)); |
|||
|
|||
prE(Math.pow(1.0000001, Number.NEGATIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(1.0000001, Number.NEGATIVE_INFINITY))); |
|||
prE(Math.pow(-1.0000001, Number.NEGATIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(-1.0000001, Number.NEGATIVE_INFINITY))); |
|||
|
|||
prE(Math.pow(1, Number.POSITIVE_INFINITY)); |
|||
prE(Math.pow(-1, Number.POSITIVE_INFINITY)); |
|||
prE(Math.pow(1, Number.NEGATIVE_INFINITY)); |
|||
prE(Math.pow(-1, Number.NEGATIVE_INFINITY)); |
|||
|
|||
prE(Math.pow(0.999999, Number.POSITIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(0.999999, Number.POSITIVE_INFINITY))); |
|||
prE(Math.pow(-0.999999, Number.POSITIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(-0.999999, Number.POSITIVE_INFINITY))); |
|||
prE(Math.pow(0.999999, Number.NEGATIVE_INFINITY)); |
|||
prE(Math.pow(-0.999999, Number.NEGATIVE_INFINITY)); |
|||
|
|||
prE(Math.pow(Number.POSITIVE_INFINITY, 0.000001)); |
|||
prE(Math.pow(Number.POSITIVE_INFINITY, -0.000001)); |
|||
print(zeroSign(Math.pow(Number.POSITIVE_INFINITY, -0.000001))); |
|||
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, 3)); // odd integer
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, 4)); |
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, 4.5)); |
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY)); |
|||
|
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, -3)); |
|||
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -3))); |
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, -4)); |
|||
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -4))); |
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, -4.5)); |
|||
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -4.5))); |
|||
prE(Math.pow(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY))); |
|||
|
|||
/*=== |
|||
pow 3 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
Infinity |
|||
Infinity |
|||
0 |
|||
-1 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
0 |
|||
1 |
|||
-Infinity |
|||
Infinity |
|||
Infinity |
|||
Infinity |
|||
NaN |
|||
NaN |
|||
15213989025 |
|||
-123345000 |
|||
1000000 |
|||
-8107 |
|||
66 |
|||
===*/ |
|||
|
|||
print('pow 3'); |
|||
|
|||
prE(Math.pow(+0, 0.0000001)); |
|||
print(zeroSign(Math.pow(+0, 0.0000001))); |
|||
prE(Math.pow(+0, Number.POSITIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(+0, Number.POSITIVE_INFINITY))); |
|||
|
|||
prE(Math.pow(+0, -0.000001)); |
|||
prE(Math.pow(+0, Number.NEGATIVE_INFINITY)); |
|||
|
|||
prE(Math.pow(-0, 3)); |
|||
print(zeroSign(Math.pow(-0, 3))); |
|||
prE(Math.pow(-0, 4)); |
|||
print(zeroSign(Math.pow(-0, 4))); |
|||
prE(Math.pow(-0, 4.5)); |
|||
print(zeroSign(Math.pow(-0, 4.5))); |
|||
prE(Math.pow(-0, Number.POSITIVE_INFINITY)); |
|||
print(zeroSign(Math.pow(-0, Number.POSITIVE_INFINITY))); |
|||
|
|||
prE(Math.pow(-0, -3)); |
|||
prE(Math.pow(-0, -4)); |
|||
prE(Math.pow(-0, -4.5)); |
|||
prE(Math.pow(-0, Number.NEGATIVE_INFINITY)); |
|||
|
|||
// x < 0 and x is finite; y is finite and not an integer
|
|||
prE(Math.pow(-123.345, -123.1)); |
|||
prE(Math.pow(-123.345, 123.1)); |
|||
|
|||
// x < 0 and x is finite, y is finite and an integer
|
|||
pr6(Math.pow(-123.345, 2)); |
|||
pr6(Math.pow(-123.345, 1)); |
|||
pr6(Math.pow(-123.345, 0)); |
|||
pr6(Math.pow(-123.345, -1)); |
|||
pr6(Math.pow(-123.345, -2)); |
|||
|
|||
/*=== |
|||
random |
|||
true true |
|||
true true |
|||
===*/ |
|||
|
|||
/* This is a statistical test, but should pass almost always. */ |
|||
|
|||
print('random'); |
|||
|
|||
var rnd_val; |
|||
var rnd_sum = 0; |
|||
var rnd_ge0 = true; |
|||
var rnd_lt0 = true; |
|||
for (i = 0; i < 100000; i++) { |
|||
rnd_val = Math.random(); |
|||
if (!(rnd_val >= 0)) { rnd_ge0 = false; } |
|||
if (!(rnd_val < 1)) { rnd_lt0 = false; } |
|||
rnd_sum += rnd_val; |
|||
} |
|||
|
|||
print(rnd_ge0, rnd_lt0); |
|||
print(rnd_sum >= 49700.0, rnd_sum <= 50300.0); |
|||
|
|||
/*=== |
|||
round |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
Infinity |
|||
-Infinity |
|||
0 |
|||
1 |
|||
1 |
|||
0 |
|||
-1 |
|||
-1 |
|||
4 |
|||
-3 |
|||
===*/ |
|||
|
|||
print('round'); |
|||
|
|||
prE(Math.round(NaN)); |
|||
prE(Math.round(+0)); |
|||
print(zeroSign(Math.round(+0))); |
|||
prE(Math.round(-0)); |
|||
print(zeroSign(Math.round(-0))); |
|||
prE(Math.round(Number.POSITIVE_INFINITY)); |
|||
prE(Math.round(Number.NEGATIVE_INFINITY)); |
|||
prE(Math.round(0.400009)); |
|||
print(zeroSign(Math.round(0.400009))); |
|||
prE(Math.round(0.5)); |
|||
prE(Math.round(-0.5)); |
|||
print(zeroSign(Math.round(-0.5))); |
|||
print(Math.round(-0.500001)); |
|||
prE(Math.round(3.5)); |
|||
prE(Math.round(-3.5)); // tie break towards +Infinity
|
|||
|
|||
/*=== |
|||
sin |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
NaN |
|||
NaN |
|||
841471 |
|||
===*/ |
|||
|
|||
print('sin'); |
|||
|
|||
prE(Math.sin(NaN)); |
|||
prE(Math.sin(+0)); |
|||
print(zeroSign(Math.sin(+0))); |
|||
prE(Math.sin(-0)); |
|||
print(zeroSign(Math.sin(-0))); |
|||
prE(Math.sin(Number.POSITIVE_INFINITY)); |
|||
prE(Math.sin(Number.NEGATIVE_INFINITY)); |
|||
pr6(Math.sin(1)); |
|||
|
|||
/*=== |
|||
sqrt |
|||
2000000 |
|||
1414214 |
|||
NaN |
|||
NaN |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
Infinity |
|||
===*/ |
|||
|
|||
print('sqrt'); |
|||
|
|||
pr6(Math.sqrt(4)); |
|||
pr6(Math.sqrt(2)); |
|||
|
|||
prE(Math.sqrt(NaN)); |
|||
prE(Math.sqrt(-0.000001)); |
|||
prE(Math.sqrt(Number.NEGATIVE_INFINITY)); |
|||
prE(Math.sqrt(+0)); |
|||
print(zeroSign(Math.sqrt(+0))); |
|||
prE(Math.sqrt(-0)); |
|||
print(zeroSign(Math.sqrt(-0))); |
|||
prE(Math.sqrt(Number.POSITIVE_INFINITY)); |
|||
|
|||
/*=== |
|||
tan |
|||
1557408 |
|||
-2185040 |
|||
648361 |
|||
NaN |
|||
0 |
|||
1 |
|||
0 |
|||
-1 |
|||
NaN |
|||
NaN |
|||
===*/ |
|||
|
|||
print('tan'); |
|||
|
|||
pr6(Math.tan(1)); |
|||
pr6(Math.tan(2)); |
|||
pr6(Math.tan(10)); |
|||
|
|||
prE(Math.tan(NaN)); |
|||
prE(Math.tan(+0)); |
|||
print(zeroSign(Math.tan(+0))); |
|||
prE(Math.tan(-0)); |
|||
print(zeroSign(Math.tan(-0))); |
|||
prE(Math.tan(Number.POSITIVE_INFINITY)); |
|||
prE(Math.tan(Number.NEGATIVE_INFINITY)); |
|||
|
@ -0,0 +1,38 @@ |
|||
/* |
|||
* Number objects (E5 Section 15.7). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
|||
/*=== |
|||
undefined |
|||
true |
|||
true |
|||
false |
|||
===*/ |
|||
|
|||
/* When called as a constructor, a Number instance will always have the |
|||
* original Number.prototype regardless of what Number.prototype is now |
|||
* set to. E5 Section 15.7.2.1. |
|||
* |
|||
* However, Number.prototype is not writable or configurable, so this |
|||
* behavior doesn't need to be implemented explicitly; just ensure that |
|||
* Number.prototype is not writable. |
|||
*/ |
|||
|
|||
var orig_prototype = Number.prototype; |
|||
var repl_prototype = { "foo": "bar" }; |
|||
Number.prototype = repl_prototype; /* this write will fail silently */ |
|||
|
|||
var num = new Number(123); |
|||
print(num.foo); |
|||
print(Object.getPrototypeOf(num) === Number.prototype); |
|||
print(Object.getPrototypeOf(num) === orig_prototype); |
|||
print(Object.getPrototypeOf(num) === repl_prototype); |
|||
|
@ -0,0 +1,20 @@ |
|||
/* |
|||
* Object objects (E5 Section 15.2). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/*=== |
|||
function |
|||
object |
|||
===*/ |
|||
|
|||
print(typeof Object); |
|||
print(typeof Object.prototype); |
|||
|
|||
/* FIXME */ |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,12 @@ |
|||
/* |
|||
* RegExp objects (E5 Section 15.10). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,16 @@ |
|||
/* |
|||
* Case conversion tests for cases not covered by |
|||
* |
|||
* test-builtin-string-caseconversion-single.js |
|||
* |
|||
* Specifically, context and locale specific conversion rules. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,18 @@ |
|||
/* |
|||
* String objects (E5 Sections 15.5, B.2.3). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
|||
/* |
|||
* toUpperCase() behavior. |
|||
* |
|||
* This behavior is also related to RegExp Canonicalization behavior. |
|||
*/ |
|||
|
@ -0,0 +1,38 @@ |
|||
/* |
|||
* CheckObjectCoercible() (E5 Section 9.10). |
|||
* |
|||
* This primitive cannot be directly tested. It is referenced in the |
|||
* specification almost exclusively for String.prototype functions, like |
|||
* charAt(). |
|||
* |
|||
* We use String.prototype.charAt() for indirect testing. |
|||
*/ |
|||
|
|||
function indirectCheckObjectCoercible(x) { |
|||
String.prototype.charAt.call(x, 0); |
|||
} |
|||
|
|||
/*=== |
|||
TypeError |
|||
TypeError |
|||
no error |
|||
no error |
|||
no error |
|||
no error |
|||
no error |
|||
no error |
|||
no error |
|||
===*/ |
|||
|
|||
var values = [ undefined, null, true, false, 123.0, "foo", {}, [], function () {} ]; |
|||
var i; |
|||
|
|||
for (i = 0; i < values.length; i++) { |
|||
try { |
|||
indirectCheckObjectCoercible(values[i]); |
|||
print('no error'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,40 @@ |
|||
/* |
|||
* IsCallable() (E5 Section 9.11). |
|||
* |
|||
* IsCallable() cannot be directly tested, but Function.prototype.bind() |
|||
* provides a very easy primitive for testing it. E5 Section 15.3.4.5, step |
|||
* 2 will throw a TypeError if IsCallable(func) is false. |
|||
*/ |
|||
|
|||
function indirectIsCallable(x) { |
|||
Function.prototype.bind.call(x); |
|||
} |
|||
|
|||
/*=== |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
no error |
|||
no error |
|||
no error |
|||
===*/ |
|||
|
|||
var values = [ undefined, null, true, false, 123.0, "foo", |
|||
{}, [], function () {}, Object.prototype.toLocaleString, |
|||
Object.prototype.toLocaleString.bind('foo') ]; |
|||
var i; |
|||
|
|||
for (i = 0; i < values.length; i++) { |
|||
try { |
|||
indirectIsCallable(values[i]); |
|||
print('no error'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,271 @@ |
|||
/* |
|||
* SameValue() (E5 Section 9.12). |
|||
* |
|||
* SameValue() is difficult to test indirectly. It appears in E5 Section |
|||
* 8.12.9, [[DefineOwnProperty]] several times. |
|||
* |
|||
* One relatively simple approach is to create a non-configurable, non-writable |
|||
* property, and attempt to use Object.defineProperty() to set a new value for |
|||
* the property. If SameValue(oldValue,newValue), no exception is thrown. |
|||
* Otherwise, reject (TypeError); see E5 Section 8.12.9, step 10.a.ii.1. |
|||
*/ |
|||
|
|||
function sameValue(x,y) { |
|||
var obj = {}; |
|||
|
|||
try { |
|||
Object.defineProperty(obj, 'test', { |
|||
writable: false, |
|||
enumerable: false, |
|||
configurable: false, |
|||
value: x |
|||
}); |
|||
|
|||
Object.defineProperty(obj, 'test', { |
|||
value: y |
|||
}); |
|||
} catch (e) { |
|||
if (e.name === 'TypeError') { |
|||
return false; |
|||
} else { |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
function test(x,y) { |
|||
print(sameValue(x,y)); |
|||
} |
|||
|
|||
/*=== |
|||
test: different types, first undefined |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is undefined */ |
|||
|
|||
print('test: different types, first undefined') |
|||
test(undefined, null); |
|||
test(undefined, true); |
|||
test(undefined, false); |
|||
test(undefined, 123.0); |
|||
test(undefined, 'foo'); |
|||
test(undefined, {}); |
|||
|
|||
/*=== |
|||
test: different types, first null |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is null */ |
|||
|
|||
print('test: different types, first null') |
|||
test(null, undefined); |
|||
test(null, true); |
|||
test(null, false); |
|||
test(null, 123.0); |
|||
test(null, 'foo'); |
|||
test(null, {}); |
|||
|
|||
/*=== |
|||
test: different types, first boolean |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is boolean */ |
|||
|
|||
print('test: different types, first boolean') |
|||
test(true, undefined); |
|||
test(true, null); |
|||
test(true, 123.0); |
|||
test(true, 'foo'); |
|||
test(true, {}); |
|||
|
|||
test(false, undefined); |
|||
test(false, null); |
|||
test(false, 123.0); |
|||
test(false, 'foo'); |
|||
test(false, {}); |
|||
|
|||
/*=== |
|||
test: different types, first number |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is number */ |
|||
|
|||
print('test: different types, first number') |
|||
test(123.0, undefined); |
|||
test(123.0, null); |
|||
test(123.0, true); |
|||
test(123.0, false); |
|||
test(123.0, 'foo'); |
|||
test(123.0, {}); |
|||
|
|||
/*=== |
|||
test: different types, first string |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is string */ |
|||
|
|||
print('test: different types, first string') |
|||
test('foo', undefined); |
|||
test('foo', null); |
|||
test('foo', true); |
|||
test('foo', false); |
|||
test('foo', 123.0); |
|||
test('foo', {}); |
|||
|
|||
/*=== |
|||
test: different types, first object |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
false |
|||
===*/ |
|||
|
|||
/* Different types, first is object */ |
|||
|
|||
print('test: different types, first object') |
|||
test({}, undefined); |
|||
test({}, null); |
|||
test({}, true); |
|||
test({}, false); |
|||
test({}, 123.0); |
|||
test({}, 'foo'); |
|||
|
|||
/*=== |
|||
test: same types, undefined |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: undefined */ |
|||
|
|||
print('test: same types, undefined') |
|||
test(undefined, undefined); |
|||
|
|||
/*=== |
|||
test: same types, null |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: null */ |
|||
|
|||
print('test: same types, null') |
|||
test(null, null); |
|||
|
|||
/*=== |
|||
test: same types, boolean |
|||
true |
|||
false |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: boolean */ |
|||
|
|||
print('test: same types, boolean') |
|||
test(true, true); |
|||
test(true, false); |
|||
test(false, true); |
|||
test(false, false); |
|||
|
|||
/*=== |
|||
test: same types, number |
|||
true |
|||
true |
|||
false |
|||
false |
|||
true |
|||
true |
|||
false |
|||
false |
|||
true |
|||
true |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: number */ |
|||
|
|||
print('test: same types, number') |
|||
test(NaN, NaN); |
|||
test(-0, -0); |
|||
test(-0, +0); |
|||
test(+0, -0); |
|||
test(+0, +0); |
|||
test(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY); |
|||
test(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY); |
|||
test(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY); |
|||
test(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); |
|||
test(-123.0, -123.0); |
|||
test(123.0, 123.0); |
|||
|
|||
/*=== |
|||
test: same types, string |
|||
true |
|||
false |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: string */ |
|||
|
|||
print('test: same types, string') |
|||
test('', ''); |
|||
test('foo', '') |
|||
test('', 'foo'); |
|||
test('foo', 'foo'); |
|||
|
|||
/*=== |
|||
test: same types, object |
|||
true |
|||
false |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
/* Same types: object */ |
|||
|
|||
var obj1 = {}; |
|||
var obj2 = {}; |
|||
|
|||
print('test: same types, object') |
|||
test(obj1, obj1); |
|||
test(obj1, obj2); |
|||
test(obj2, obj1); |
|||
test(obj2, obj2); |
|||
|
@ -0,0 +1,51 @@ |
|||
/* |
|||
* ToBoolean() (E5 Section 9.2). |
|||
*/ |
|||
|
|||
function test(values) { |
|||
for (var i = 0; i < values.length; i++) { |
|||
/* Two logical NOTs is basically ToBoolean() */ |
|||
print(!!values[i]); |
|||
} |
|||
} |
|||
|
|||
/*=== |
|||
false |
|||
false |
|||
true |
|||
false |
|||
===*/ |
|||
|
|||
test([ undefined, null, true, false ]); |
|||
|
|||
/*=== |
|||
false |
|||
false |
|||
false |
|||
true |
|||
true |
|||
true |
|||
true |
|||
===*/ |
|||
|
|||
test([ +0, -0, Number.NaN ]); |
|||
test([ 123.0, -123.0, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]); |
|||
|
|||
/*=== |
|||
false |
|||
true |
|||
true |
|||
===*/ |
|||
|
|||
test([ "", "nonempty", "0" ]); |
|||
|
|||
/*=== |
|||
true |
|||
true |
|||
true |
|||
true |
|||
true |
|||
===*/ |
|||
|
|||
test([ {}, [], function() {}, Number.prototype.toString, Number.prototype.toString.bind('foo') ]) |
|||
|
@ -0,0 +1,140 @@ |
|||
/* |
|||
* ToInt32() (E5 Section 9.5). |
|||
* |
|||
* Indirect testing using '<<' (E5 Section 11.7.1): "x << 0" is equivalent |
|||
* to ToInt32(). ToInt32() first coerces with ToNumber(), so that is noted |
|||
* in the cases. |
|||
*/ |
|||
|
|||
function toint32(x) { |
|||
return x << 0; |
|||
} |
|||
|
|||
function zeroSign(x) { |
|||
if (x !== 0) { |
|||
return 'nz'; |
|||
} |
|||
if (1 / x > 0) { |
|||
return 'pos'; |
|||
} else { |
|||
return 'neg'; |
|||
} |
|||
} |
|||
|
|||
function test(x) { |
|||
var t = toint32(x); |
|||
print(t, zeroSign(t)); |
|||
} |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(undefined) -> NaN -> +0
|
|||
test(undefined); |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(null) -> +0 -> +0
|
|||
test(null); |
|||
|
|||
/*=== |
|||
1 nz |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(true) -> 1 -> 1
|
|||
test(true); |
|||
|
|||
// Tonumber(false) -> +0 -> +0
|
|||
test(false); |
|||
|
|||
/*=== |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(NaN) -> NaN -> +0
|
|||
test(NaN); |
|||
|
|||
// ToNumber(+0) -> +0 -> +0
|
|||
test(+0); |
|||
|
|||
// ToNumber(-0) -> -0 -> +0
|
|||
test(-0); |
|||
|
|||
// ToNumber(+Infinity) -> +Infinity -> +0
|
|||
test(Number.POSITIVE_INFINITY); |
|||
|
|||
// ToNumber(-Infinity) -> -Infinity -> +0
|
|||
test(Number.NEGATIVE_INFINITY); |
|||
|
|||
/*=== |
|||
123 nz |
|||
-123 nz |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
1410065408 nz |
|||
===*/ |
|||
|
|||
/* ToNumber() string coercion, E5 Section 9.3.1 */ |
|||
|
|||
test("123"); |
|||
test("-123"); |
|||
test("+0"); |
|||
test("-0"); |
|||
test("Infinity"); |
|||
test("+Infinity"); |
|||
test("-Infinity"); |
|||
|
|||
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
|
|||
test("NaY"); // same case
|
|||
|
|||
test("1e10"); // larger than 32-bit, fits in 53 bits of double
|
|||
|
|||
/* FIXME: object coercion */ |
|||
|
|||
/*=== |
|||
0 pos |
|||
1 nz |
|||
-1 nz |
|||
2 nz |
|||
-1 nz |
|||
0 pos |
|||
2 nz |
|||
===*/ |
|||
|
|||
/* A couple of modulo tests */ |
|||
|
|||
test(4294967296); |
|||
test(4294967297); |
|||
test(-1); |
|||
test(-4294967294); // +2
|
|||
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295 --> -1
|
|||
test(9007199254740992); // (2^53) % (2^32) --> 0
|
|||
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
|
|||
|
|||
/*=== |
|||
3 nz |
|||
-3 nz |
|||
===*/ |
|||
|
|||
/* Rounding |
|||
* |
|||
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3 |
|||
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4) |
|||
*/ |
|||
|
|||
test(3.4); // -> 3 -> 3
|
|||
test(-3.4); // -> -3 -> -3
|
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* ToInteger() (E5 Section 9.4). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,84 @@ |
|||
/* |
|||
* ToNumber() (E5 Section 9.3). |
|||
* |
|||
* Postfix increment changes its LHS, put returns ToNumber(oldValue) as the |
|||
* expression value. Use this get ToNumber() indirectly. |
|||
*/ |
|||
|
|||
function tonumber(x) { |
|||
var tmp = x; |
|||
return tmp++; |
|||
} |
|||
|
|||
function zeroSign(x) { |
|||
if (x !== 0) { |
|||
return 'nz'; |
|||
} |
|||
if (1 / x > 0) { |
|||
return 'pos'; |
|||
} else { |
|||
return 'neg'; |
|||
} |
|||
} |
|||
|
|||
function test(x) { |
|||
var num = tonumber(x); |
|||
print(num, zeroSign(num)); |
|||
} |
|||
|
|||
/*=== |
|||
NaN nz |
|||
0 pos |
|||
1 nz |
|||
0 pos |
|||
-1 nz |
|||
0 neg |
|||
0 pos |
|||
1 nz |
|||
NaN nz |
|||
Infinity nz |
|||
-Infinity nz |
|||
===*/ |
|||
|
|||
test(undefined); |
|||
test(null); |
|||
test(true); |
|||
test(false); |
|||
test(-1); |
|||
test(-0); |
|||
test(+0); |
|||
test(1); |
|||
test(NaN); |
|||
test(Number.POSITIVE_INFINITY); |
|||
test(Number.NEGATIVE_INFINITY); |
|||
|
|||
/*=== |
|||
-1 nz |
|||
0 neg |
|||
0 pos |
|||
0 pos |
|||
1 nz |
|||
-Infinity nz |
|||
Infinity nz |
|||
Infinity nz |
|||
3735928559 nz |
|||
===*/ |
|||
|
|||
/* String to number */ |
|||
|
|||
test("-1"); |
|||
test("-0"); |
|||
test("+0"); |
|||
test("0"); |
|||
test("1"); |
|||
|
|||
test("-Infinity"); |
|||
test("+Infinity"); |
|||
test("Infinity"); |
|||
|
|||
test("0xdeadbeef"); |
|||
|
|||
/* FIXME: octal */ |
|||
|
|||
/* FIXME: object coercion */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* ToObject() (E5 Section 9.9). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* ToPrimitive() (E5 Section 9.1). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* ToString() (E5 Section 9.8). |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -0,0 +1,141 @@ |
|||
/* |
|||
* ToUint16() (E5 Section 9.7). |
|||
* |
|||
* Indirect testing using String.fromCharCode() (which seems to be the |
|||
* only caller for this internal coercion!). ToUint16() first coerces |
|||
* with ToNumber(), so that is noted in the cases. |
|||
*/ |
|||
|
|||
function touint16(x) { |
|||
var str = String.fromCharCode(x); // Coerce with ToUint16 (E5 Section 15.5.3.2)
|
|||
return str.charCodeAt(0); // Read back
|
|||
} |
|||
|
|||
function zeroSign(x) { |
|||
if (x !== 0) { |
|||
return 'nz'; |
|||
} |
|||
if (1 / x > 0) { |
|||
return 'pos'; |
|||
} else { |
|||
return 'neg'; |
|||
} |
|||
} |
|||
|
|||
function test(x) { |
|||
var t = touint16(x); |
|||
print(t, zeroSign(t)); |
|||
} |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(undefined) -> NaN -> +0
|
|||
test(undefined); |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(null) -> +0 -> +0
|
|||
test(null); |
|||
|
|||
/*=== |
|||
1 nz |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(true) -> 1 -> 1
|
|||
test(true); |
|||
|
|||
// Tonumber(false) -> +0 -> +0
|
|||
test(false); |
|||
|
|||
/*=== |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(NaN) -> NaN -> +0
|
|||
test(NaN); |
|||
|
|||
// ToNumber(+0) -> +0 -> +0
|
|||
test(+0); |
|||
|
|||
// ToNumber(-0) -> -0 -> +0
|
|||
test(-0); |
|||
|
|||
// ToNumber(+Infinity) -> +Infinity -> +0
|
|||
test(Number.POSITIVE_INFINITY); |
|||
|
|||
// ToNumber(-Infinity) -> -Infinity -> +0
|
|||
test(Number.NEGATIVE_INFINITY); |
|||
|
|||
/*=== |
|||
123 nz |
|||
65413 nz |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
58368 nz |
|||
===*/ |
|||
|
|||
/* ToNumber() string coercion, E5 Section 9.3.1 */ |
|||
|
|||
test("123"); |
|||
test("-123"); |
|||
test("+0"); |
|||
test("-0"); |
|||
test("Infinity"); |
|||
test("+Infinity"); |
|||
test("-Infinity"); |
|||
|
|||
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
|
|||
test("NaY"); // same case
|
|||
|
|||
test("1e10"); // larger than 32-bit, fits in 53 bits of double
|
|||
|
|||
/* FIXME: object coercion */ |
|||
|
|||
/*=== |
|||
0 pos |
|||
1 nz |
|||
65535 nz |
|||
2 nz |
|||
65535 nz |
|||
0 pos |
|||
2 nz |
|||
===*/ |
|||
|
|||
/* A couple of modulo tests */ |
|||
|
|||
test(4294967296); |
|||
test(4294967297); |
|||
test(-1); // --> 0xffffU
|
|||
test(-4294967294); // +2
|
|||
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295 --> 65535
|
|||
test(9007199254740992); // (2^53) % (2^32) --> 0
|
|||
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
|
|||
|
|||
/*=== |
|||
3 nz |
|||
65533 nz |
|||
===*/ |
|||
|
|||
/* Rounding |
|||
* |
|||
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3 |
|||
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4) |
|||
*/ |
|||
|
|||
test(3.4); // -> 3 -> 3
|
|||
test(-3.4); // -> -3 -> (2^32) - 3
|
|||
|
@ -0,0 +1,140 @@ |
|||
/* |
|||
* ToUint32() (E5 Section 9.6). |
|||
* |
|||
* Indirect testing using '>>>' (E5 Section 11.7.3): "x >>> 0" is equivalent |
|||
* to ToUint32(x). ToUint32() first coerces with ToNumber(), so that is noted |
|||
* in the cases. |
|||
*/ |
|||
|
|||
function touint32(x) { |
|||
return x >>> 0; |
|||
} |
|||
|
|||
function zeroSign(x) { |
|||
if (x !== 0) { |
|||
return 'nz'; |
|||
} |
|||
if (1 / x > 0) { |
|||
return 'pos'; |
|||
} else { |
|||
return 'neg'; |
|||
} |
|||
} |
|||
|
|||
function test(x) { |
|||
var t = touint32(x); |
|||
print(t, zeroSign(t)); |
|||
} |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(undefined) -> NaN -> +0
|
|||
test(undefined); |
|||
|
|||
/*=== |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(null) -> +0 -> +0
|
|||
test(null); |
|||
|
|||
/*=== |
|||
1 nz |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(true) -> 1 -> 1
|
|||
test(true); |
|||
|
|||
// Tonumber(false) -> +0 -> +0
|
|||
test(false); |
|||
|
|||
/*=== |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
===*/ |
|||
|
|||
// ToNumber(NaN) -> NaN -> +0
|
|||
test(NaN); |
|||
|
|||
// ToNumber(+0) -> +0 -> +0
|
|||
test(+0); |
|||
|
|||
// ToNumber(-0) -> -0 -> +0
|
|||
test(-0); |
|||
|
|||
// ToNumber(+Infinity) -> +Infinity -> +0
|
|||
test(Number.POSITIVE_INFINITY); |
|||
|
|||
// ToNumber(-Infinity) -> -Infinity -> +0
|
|||
test(Number.NEGATIVE_INFINITY); |
|||
|
|||
/*=== |
|||
123 nz |
|||
4294967173 nz |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
0 pos |
|||
1410065408 nz |
|||
===*/ |
|||
|
|||
/* ToNumber() string coercion, E5 Section 9.3.1 */ |
|||
|
|||
test("123"); |
|||
test("-123"); |
|||
test("+0"); |
|||
test("-0"); |
|||
test("Infinity"); |
|||
test("+Infinity"); |
|||
test("-Infinity"); |
|||
|
|||
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
|
|||
test("NaY"); // same case
|
|||
|
|||
test("1e10"); // larger than 32-bit, fits in 53 bits of double
|
|||
|
|||
/* FIXME: object coercion */ |
|||
|
|||
/*=== |
|||
0 pos |
|||
1 nz |
|||
4294967295 nz |
|||
2 nz |
|||
4294967295 nz |
|||
0 pos |
|||
2 nz |
|||
===*/ |
|||
|
|||
/* A couple of modulo tests */ |
|||
|
|||
test(4294967296); |
|||
test(4294967297); |
|||
test(-1); // --> 0xffffffffU
|
|||
test(-4294967294); // +2
|
|||
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295
|
|||
test(9007199254740992); // (2^53) % (2^32) --> 0
|
|||
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
|
|||
|
|||
/*=== |
|||
3 nz |
|||
4294967293 nz |
|||
===*/ |
|||
|
|||
/* Rounding |
|||
* |
|||
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3 |
|||
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4) |
|||
*/ |
|||
|
|||
test(3.4); // -> 3 -> 3
|
|||
test(-3.4); // -> -3 -> (2^32) - 3
|
|||
|
@ -0,0 +1,11 @@ |
|||
/* |
|||
* Addition precedence test. |
|||
*/ |
|||
|
|||
/*=== |
|||
3foo34 |
|||
===*/ |
|||
|
|||
/* This is equivalent to: (((1 + 2) + 'foo') + 3) + 4 === "3foo34" */ |
|||
|
|||
print(1 + 2 + 'foo' + 3 + 4); |
@ -0,0 +1,63 @@ |
|||
/* |
|||
* Some 'arguments' binding tests |
|||
*/ |
|||
|
|||
/*=== |
|||
object |
|||
number |
|||
object |
|||
false |
|||
object |
|||
===*/ |
|||
|
|||
/* A non-strict 'arguments' binding is writable but not deletable. */ |
|||
|
|||
function arguments_write() { |
|||
print(typeof arguments); |
|||
arguments = 1; |
|||
print(typeof arguments); |
|||
} |
|||
|
|||
function arguments_delete() { |
|||
print(typeof arguments); |
|||
print(delete arguments); |
|||
print(typeof arguments); |
|||
} |
|||
|
|||
try { |
|||
arguments_write(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
arguments_delete(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* A strict 'arguments' binding is immutable. It cannot be deleted nor can |
|||
* it be assigned to; doing so would be a SyntaxError. |
|||
* |
|||
* XXX: how to test that the binding is actually immutable, as it is a |
|||
* SyntaxError trying to delete it or assign to it? Even an eval() call |
|||
* does not work: the eval will be parsed in strict mode too. |
|||
*/ |
|||
|
|||
try { |
|||
eval("function arguments_strict_delete() { 'use strict'; delete arguments; }"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function arguments_strict_delete() { 'use strict'; arguments = 1; }"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,65 @@ |
|||
|
|||
/*=== |
|||
0 |
|||
undefined |
|||
1 |
|||
1 |
|||
undefined |
|||
2 |
|||
1 |
|||
2 |
|||
undefined |
|||
===*/ |
|||
|
|||
print([].length); |
|||
print([][0]); |
|||
|
|||
print([1].length); |
|||
print([1][0]); |
|||
print([1][1]); |
|||
|
|||
print([1,2].length); |
|||
print([1,2][0]); |
|||
print([1,2][1]); |
|||
print([1,2][2]); |
|||
|
|||
/*=== |
|||
11 |
|||
20 |
|||
===*/ |
|||
|
|||
/* two sets of MPUTARR */ |
|||
|
|||
print([1,2,3,4,5,6,7,8,9,10,11].length); /* 10 + 1 */ |
|||
print([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20].length); /* 10 + 10 */ |
|||
|
|||
/*=== |
|||
0 |
|||
1 |
|||
1 |
|||
1 |
|||
2 |
|||
2 |
|||
2 |
|||
3 |
|||
===*/ |
|||
|
|||
/* elisions */ |
|||
|
|||
print([].length); |
|||
print([,].length); /* here, even one comma has an effect */ |
|||
print([1].length); |
|||
print([1,].length); /* here, one additional comma has no effect */ |
|||
print([1,,].length); /* but two do */ |
|||
print([1,2].length); |
|||
print([1,2,].length); /* quite confusingly, one additional comma has no effect */ |
|||
print([1,2,,].length); /* but two do */ |
|||
|
|||
/*=== |
|||
2 |
|||
===*/ |
|||
|
|||
/* regexp values */ |
|||
|
|||
print([/foo/,/bar/].length); |
|||
|
@ -0,0 +1,34 @@ |
|||
/* |
|||
* Property attributes of array entries. Also tests the properties with |
|||
* and without an internal "array part". |
|||
*/ |
|||
|
|||
function printDesc(desc) { |
|||
print(desc.writable, desc.enumerable, desc.configurable); |
|||
} |
|||
|
|||
/*=== |
|||
true true true |
|||
true true true |
|||
true true true |
|||
true true true |
|||
true true true |
|||
true true true |
|||
true true true |
|||
===*/ |
|||
|
|||
/* array is initially dense (array part exists) */ |
|||
a = [1,2,3]; |
|||
|
|||
printDesc(Object.getOwnPropertyDescriptor(a, '0')); |
|||
printDesc(Object.getOwnPropertyDescriptor(a, '1')); |
|||
printDesc(Object.getOwnPropertyDescriptor(a, '2')); |
|||
|
|||
/* force array to be sparse (array part is abandoned) */ |
|||
a[10000] = 4; |
|||
|
|||
printDesc(Object.getOwnPropertyDescriptor(a, '0')); |
|||
printDesc(Object.getOwnPropertyDescriptor(a, '1')); |
|||
printDesc(Object.getOwnPropertyDescriptor(a, '2')); |
|||
printDesc(Object.getOwnPropertyDescriptor(a, '10000')); |
|||
|
@ -0,0 +1,17 @@ |
|||
|
|||
/*=== |
|||
ReferenceError |
|||
===*/ |
|||
|
|||
/* Valid LeftHandSideExpression which is invalid for assignment |
|||
* is a run-time ReferenceError, not a SyntaxError. E5 allows |
|||
* a LHS Reference to be returned from a function, although it |
|||
* provides no standard way of doing so. |
|||
*/ |
|||
|
|||
try { |
|||
eval("f() = 1"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,33 @@ |
|||
/*=== |
|||
10 |
|||
9 |
|||
8 |
|||
7 |
|||
6 |
|||
5 |
|||
4 |
|||
3 |
|||
2 |
|||
1 |
|||
10 |
|||
9 |
|||
8 |
|||
7 |
|||
6 |
|||
5 |
|||
4 |
|||
3 |
|||
2 |
|||
1 |
|||
===*/ |
|||
|
|||
/* Simple tests for assignment */ |
|||
|
|||
for (i = 10; i; i -= 1) { |
|||
print(i); |
|||
} |
|||
|
|||
for (i = 10; i; i = i - 1) { |
|||
print(i); |
|||
} |
|||
|
@ -0,0 +1,26 @@ |
|||
/* |
|||
* Bit op tests. |
|||
*/ |
|||
|
|||
/* FIXME: incomplete */ |
|||
/* FIXME: precedence tests, associativity tests */ |
|||
/* FIXME: ranges, coercion, etc */ |
|||
|
|||
/*=== |
|||
64 |
|||
===*/ |
|||
|
|||
print(255 & 64); |
|||
|
|||
/*=== |
|||
192 |
|||
===*/ |
|||
|
|||
print(128 | 64); |
|||
|
|||
/*=== |
|||
191 |
|||
===*/ |
|||
|
|||
print(255 ^ 64); |
|||
|
@ -0,0 +1,34 @@ |
|||
/* FIXME: missing a lot of coercion cases */ |
|||
|
|||
/*=== |
|||
-124 |
|||
123 |
|||
-1410065409 |
|||
1410065408 |
|||
===*/ |
|||
|
|||
print(~123); |
|||
print(~~123); |
|||
print(~1e10); |
|||
print(~~1e10); |
|||
|
|||
/*=== |
|||
-124 |
|||
123 |
|||
-2 |
|||
1 |
|||
===*/ |
|||
|
|||
/* Ensure that target is not modified (this would happen if expression is |
|||
* not allocated a real temporary register but operates directly on a register |
|||
* bound value). |
|||
*/ |
|||
|
|||
var x = 123; |
|||
print(~x); |
|||
print(x); |
|||
|
|||
var obj = {x:1}; |
|||
print(~obj.x); |
|||
print(obj.x); |
|||
|
@ -0,0 +1,34 @@ |
|||
|
|||
/*=== |
|||
10 20 |
|||
-> 10 21 |
|||
-> 11 21 |
|||
===*/ |
|||
|
|||
/* Broken at some point. */ |
|||
|
|||
var x = 10; |
|||
var y = 20; |
|||
|
|||
function f_postinc() { |
|||
print(x, y); |
|||
|
|||
// interpreted as "x; ++y;"
|
|||
x |
|||
++y |
|||
|
|||
print('->', x, y); |
|||
|
|||
// interpreted as "x++; y;"
|
|||
x++ |
|||
y |
|||
|
|||
print('->', x, y); |
|||
} |
|||
|
|||
try { |
|||
f_postinc(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,48 @@ |
|||
/*=== |
|||
throw |
|||
throw |
|||
throw |
|||
===*/ |
|||
|
|||
/* This was broken at an early point: the compiler would use a function-wide |
|||
* register binding for 'e' and look up the argument / variable declaration |
|||
* instead of the (dynamic) catch binding. |
|||
* |
|||
* h() would actually work because 'with' turns off fast path identifier |
|||
* lookups for its duration. |
|||
*/ |
|||
|
|||
function f(e) { |
|||
try { |
|||
throw 'throw'; |
|||
} catch (e) { |
|||
print(e); |
|||
} |
|||
} |
|||
|
|||
function g() { |
|||
var e = 'var'; |
|||
|
|||
try { |
|||
throw 'throw'; |
|||
} catch (e) { |
|||
print(e); |
|||
} |
|||
} |
|||
|
|||
function h() { |
|||
var e = 'var'; |
|||
|
|||
with ({}) { |
|||
try { |
|||
throw 'throw'; |
|||
} catch (e) { |
|||
print(e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
f('arg'); |
|||
g(); |
|||
h(); |
|||
|
@ -0,0 +1,22 @@ |
|||
|
|||
/*=== |
|||
3 |
|||
===*/ |
|||
|
|||
var tmp = String.fromCharCode(3.4); |
|||
print(tmp.charCodeAt(0)); |
|||
|
|||
/*=== |
|||
3 |
|||
===*/ |
|||
|
|||
print(String.fromCharCode(3.4).charCodeAt(0)); |
|||
|
|||
/*=== |
|||
3 |
|||
===*/ |
|||
|
|||
/* This was broken at some point, and printed "3.4" */ |
|||
function f(x) { return String.fromCharCode(x).charCodeAt(0); } |
|||
print(f(3.4)); |
|||
|
@ -0,0 +1,17 @@ |
|||
|
|||
/*=== |
|||
y 2 |
|||
x 1 |
|||
===*/ |
|||
|
|||
/* This had a bug at some point. */ |
|||
|
|||
function f(x) { |
|||
return function(y) { |
|||
print('y', y); |
|||
print('x', x); |
|||
} |
|||
} |
|||
|
|||
f(1)(2); |
|||
|
@ -0,0 +1,18 @@ |
|||
|
|||
/*=== |
|||
finalizer |
|||
object |
|||
finalizer |
|||
object |
|||
===*/ |
|||
|
|||
a={}; |
|||
|
|||
// The finalizer rescues the reference (= makes it reachable again)
|
|||
__duk__.setFinalizer(a, function(x) { print('finalizer'); a=x }); |
|||
|
|||
a = null; |
|||
print(typeof a); |
|||
a = null; |
|||
print(typeof a); |
|||
|
@ -0,0 +1,41 @@ |
|||
|
|||
/*=== |
|||
0 foo |
|||
1 bar |
|||
0 foo |
|||
1 bar |
|||
0 foo |
|||
1 bar |
|||
===*/ |
|||
|
|||
/* g() used to be broken: local_iter would not get assigned to as a |
|||
* left-hand side if it was a register-bound variable. |
|||
*/ |
|||
|
|||
var arr = ['foo', 'bar']; |
|||
|
|||
function f() { |
|||
for (global_iter in arr) { |
|||
print(global_iter, arr[global_iter]); |
|||
} |
|||
} |
|||
|
|||
function g() { |
|||
var local_iter; |
|||
|
|||
for (local_iter in arr) { |
|||
print(local_iter, arr[local_iter]); |
|||
} |
|||
} |
|||
|
|||
function h() { |
|||
for (var local_iter in arr) { |
|||
print(local_iter, arr[local_iter]); |
|||
} |
|||
} |
|||
|
|||
|
|||
f(); |
|||
g(); |
|||
h(); |
|||
|
@ -0,0 +1,21 @@ |
|||
/*=== |
|||
0 |
|||
1 |
|||
2 |
|||
0 |
|||
1 |
|||
2 |
|||
===*/ |
|||
|
|||
/* Latter variant was broken at some point */ |
|||
|
|||
var test = 'Foo'; |
|||
|
|||
for (i in test) { |
|||
print(i) |
|||
} |
|||
|
|||
for (var i in test) { |
|||
print(i) |
|||
} |
|||
|
@ -0,0 +1,26 @@ |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* This was broken at some point: formal argument list is parsed in |
|||
* non-strict mode so 'implements' is allowed. When function is |
|||
* detected to be strict, the argument list needs to be rechecked |
|||
* to ensure that there are no reserved words which are recognized |
|||
* only in strict mode. |
|||
* |
|||
* This is not actually clear cut in the specification, but this |
|||
* behavior follows e.g. V8. |
|||
*/ |
|||
|
|||
try { |
|||
// FutureReservedWord only recognized in strict mode,
|
|||
// function declared in non-strict mode but function
|
|||
// itself is strict
|
|||
eval("function foo(implements) { 'use strict'; };"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,25 @@ |
|||
/*=== |
|||
foo,foo |
|||
===*/ |
|||
|
|||
/* This used to have a bug: closure numbers would get incorrectly used. */ |
|||
|
|||
function F() { |
|||
this.values = []; |
|||
} |
|||
F.prototype.f = function() { |
|||
this.values[this.values.length] = 'foo'; |
|||
} |
|||
F.prototype.g = function() { |
|||
this.values[this.values.length] = 'bar'; |
|||
} |
|||
|
|||
function test() { |
|||
var obj = new F(); |
|||
obj.f(); |
|||
obj.f(); |
|||
print(obj.values); |
|||
} |
|||
|
|||
test(); |
|||
|
@ -0,0 +1,33 @@ |
|||
/* |
|||
* Broken at some point; regression test. |
|||
*/ |
|||
|
|||
/*=== |
|||
redecl |
|||
===*/ |
|||
|
|||
function foo(x,y) { |
|||
print(x,y); |
|||
} |
|||
|
|||
function foo(x,y) { |
|||
print('redecl'); |
|||
} |
|||
|
|||
foo(1,2); |
|||
|
|||
/*=== |
|||
second 1 2 |
|||
===*/ |
|||
|
|||
/* Shadowing declarations inside a function (register bound) */ |
|||
|
|||
function functest() { |
|||
function foo(x,y) { print('first',x,y); } |
|||
function foo(x,y) { print('second',x,y); } |
|||
|
|||
foo(1,2); |
|||
} |
|||
|
|||
functest(); |
|||
|
@ -0,0 +1,44 @@ |
|||
/*=== |
|||
62 |
|||
===*/ |
|||
|
|||
/* This parsed incorrectly at one point, the slash was parsed as |
|||
* part of a RegExp leading to SyntaxError. |
|||
*/ |
|||
|
|||
var obj, val; |
|||
|
|||
try { |
|||
eval("obj = { foo: 124 };"); |
|||
eval("val = obj['foo']/2;"); |
|||
eval("print(val)"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
50 |
|||
===*/ |
|||
|
|||
/* Similar test for parens */ |
|||
|
|||
try { |
|||
print(eval("(50+50)/2")); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
NaN |
|||
===*/ |
|||
|
|||
/* Similar test for braces (this doesn't evaluate to anything useful |
|||
* but is not a SyntaxError. |
|||
*/ |
|||
|
|||
try { |
|||
print(eval("({foo:1}/2)")); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,17 @@ |
|||
/*=== |
|||
A |
|||
===*/ |
|||
|
|||
/* This was broken at some point, returning 65 (argument) instead of |
|||
* desired value, string "A". |
|||
*/ |
|||
|
|||
function f(x) { |
|||
return String.fromCharCode(x); |
|||
} |
|||
|
|||
try { |
|||
print(f(65)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
@ -0,0 +1,12 @@ |
|||
/*=== |
|||
|
|||
undefined |
|||
|
|||
undefined |
|||
===*/ |
|||
|
|||
print(String()); // required to result in empty string: ""
|
|||
print(String(undefined)); // required to result in "undefined"
|
|||
|
|||
print(new String().toString()); // required to result in empty string: ""
|
|||
print(new String(undefined).toString()); // required to result in "undefined"
|
@ -0,0 +1,16 @@ |
|||
/*=== |
|||
undefined |
|||
===*/ |
|||
|
|||
/* 'x' does not resolve, should not cause a ReferenceError but |
|||
* an "undefined" typeof. E5 Section 11.4.3, step 2.a. |
|||
* |
|||
* This was broken at some point. |
|||
*/ |
|||
|
|||
try { |
|||
print(typeof x); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,42 @@ |
|||
|
|||
var thread; |
|||
var res; |
|||
|
|||
/*=== |
|||
123 |
|||
===*/ |
|||
|
|||
/* Calling via Function.prototype.call() or Function.prototype.apply() would |
|||
* prevent a yield(). |
|||
*/ |
|||
|
|||
function innerfunc() { |
|||
__duk__.yield(123); |
|||
} |
|||
|
|||
function coroutine1() { |
|||
// This is a native call so naive handling would prevent a later yield
|
|||
innerfunc.call(); |
|||
} |
|||
|
|||
function coroutine2() { |
|||
// Same here
|
|||
innerfunc.apply(); |
|||
} |
|||
|
|||
try { |
|||
thread = __duk__.spawn(coroutine1); |
|||
res = __duk__.resume(thread, 0); |
|||
print(res); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
thread = __duk__.spawn(coroutine2); |
|||
res = __duk__.resume(thread, 0); |
|||
print(res); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,64 @@ |
|||
/* |
|||
* Production for: |
|||
* |
|||
* f(1).g(2); |
|||
* |
|||
* comes from: |
|||
* |
|||
* LeftHandSideExpression -> CallExpression |
|||
* -> CallExpression Arguments |
|||
* -> (CallExpression . IdentifierName) Arguments |
|||
* -> ((MemberExpression Arguments) . IdentifierName) Arguments |
|||
* -> ((PrimaryExpression Arguments) . IdentifierName) Arguments |
|||
* -> ((Identifer Arguments) . IdentifierName) Arguments |
|||
* |
|||
* So, the original expression is equivalent to: |
|||
* |
|||
* (f(1)).g(2); |
|||
* |
|||
* Note that the first name is an Identifier, i.e. does not allow reserved words. |
|||
* However, the latter is not, so this is valid: |
|||
* |
|||
* foo(1).if(2) |
|||
*/ |
|||
|
|||
/*=== |
|||
f 1 |
|||
g 2 |
|||
f 1 |
|||
g 2 |
|||
f 3 |
|||
g 4 |
|||
===*/ |
|||
|
|||
function f(x) { |
|||
print('f', x); |
|||
return { |
|||
"g": function(y) { |
|||
print('g', y); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function z(x, y) { |
|||
f(x).g(y); |
|||
} |
|||
|
|||
try { |
|||
f(1).g(2); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
(f(1)).g(2); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
z(3, 4); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* CallExpression tests |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME: expressions like: foo()() and foo().bar() etc */ |
|||
|
@ -0,0 +1,24 @@ |
|||
|
|||
/*=== |
|||
g this.name: myThis |
|||
f this.name: myThis |
|||
===*/ |
|||
|
|||
/* Ensure that calling through 'this' preserves this binding. */ |
|||
|
|||
function f() { |
|||
print('f this.name:', this.name); |
|||
} |
|||
|
|||
function g() { |
|||
print('g this.name:', this.name); |
|||
this.f(); |
|||
} |
|||
|
|||
var myThis = { |
|||
name: 'myThis', |
|||
f: f |
|||
}; |
|||
|
|||
g.call(myThis); |
|||
|
@ -0,0 +1,21 @@ |
|||
/*=== |
|||
123 |
|||
foo |
|||
123 |
|||
===*/ |
|||
|
|||
function foo(e) { |
|||
print(e); |
|||
|
|||
try { |
|||
throw 'foo' |
|||
} catch (e) { |
|||
print(e); |
|||
} |
|||
|
|||
print(e); |
|||
} |
|||
|
|||
foo(123); |
|||
|
|||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,35 @@ |
|||
|
|||
var t; |
|||
|
|||
/*=== |
|||
1 2 3 |
|||
3 |
|||
===*/ |
|||
|
|||
print(1,2,3) |
|||
print((1,2,3)) |
|||
|
|||
/*=== |
|||
foo |
|||
bar |
|||
undefined |
|||
foo |
|||
bar |
|||
3 |
|||
===*/ |
|||
|
|||
/* This parses as: (t = print('foo')), (print('bar')), (1+2); |
|||
* So 't' gets return value of print('foo') = undefined. |
|||
*/ |
|||
t = print('foo'), print('bar'), 1 + 2; |
|||
print(t); |
|||
|
|||
t = (print('foo'), print('bar'), 1 + 2); |
|||
print(t); |
|||
|
|||
/*=== |
|||
3 |
|||
===*/ |
|||
|
|||
t = eval("1, 2, 3"); |
|||
print(t); |
@ -0,0 +1,107 @@ |
|||
/* |
|||
* Tests on compiler recursion limits. |
|||
*/ |
|||
|
|||
/* FIXME: any other recursion points? |
|||
* |
|||
* Object and array literals? |
|||
*/ |
|||
|
|||
var t; |
|||
|
|||
/*=== |
|||
1 |
|||
Error |
|||
===*/ |
|||
|
|||
/* Parenthesis; expression recursion */ |
|||
|
|||
function buildParenExpr(count) { |
|||
var t = '1'; |
|||
var i; |
|||
|
|||
for (i = 0; i < count; i++) { |
|||
t = '(' + t + ')'; |
|||
} |
|||
|
|||
return t; |
|||
} |
|||
|
|||
try { |
|||
/* a reasonable nest count should of course compile */ |
|||
print(eval(buildParenExpr(50))); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* an internal error without other trouble should happen */ |
|||
print(eval(buildParenExpr(1000))); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
innermost block |
|||
Error |
|||
===*/ |
|||
|
|||
/* Statement recursion */ |
|||
|
|||
function buildBlockExpr(count) { |
|||
var t = "'innermost block';"; // implicit return value
|
|||
var i; |
|||
|
|||
for (i = 0; i < count; i++) { |
|||
t = "if (true) { " + t + "}"; |
|||
} |
|||
|
|||
return t; |
|||
} |
|||
|
|||
try { |
|||
// reasonable count
|
|||
print(eval(buildBlockExpr(50))); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(eval(buildBlockExpr(1000))); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
innermost func |
|||
Error |
|||
===*/ |
|||
|
|||
/* Function recursion */ |
|||
|
|||
function buildFuncExpr(count) { |
|||
var t = "(function(){ print('innermost func'); })"; |
|||
var i; |
|||
|
|||
for (i = 0; i < count; i++) { |
|||
// t: function expression (not called)
|
|||
t = "(function(){" + t + "()" + "})"; |
|||
} |
|||
|
|||
t = t + "()"; // call the outermost
|
|||
return t; |
|||
} |
|||
|
|||
try { |
|||
// reasonable
|
|||
eval(buildFuncExpr(50)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval(buildFuncExpr(1000)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,100 @@ |
|||
|
|||
/*=== |
|||
1 |
|||
2 |
|||
===*/ |
|||
|
|||
try { |
|||
eval("print(true ? 1 : 2);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("print(false ? 1 : 2);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
|||
/*=== |
|||
SyntaxError |
|||
1 3 |
|||
===*/ |
|||
|
|||
/* In "A ? B : C" both B and C are AssignmentExpressions, and |
|||
* do not allow the comma operator. |
|||
* |
|||
* In the case of "true ? 1,2 : 3" there is no way to match |
|||
* "1,2" against an AssignmentExpression, so a SyntaxError. |
|||
* |
|||
* In the case of "true ? 1 : 2,3" the ConditionalExpression |
|||
* will match "true ? 1 : 2" and there will be a surrounding |
|||
* comma expression, i.e.: "(true ? 1 : 2), 3". |
|||
*/ |
|||
|
|||
try { |
|||
eval("print(true ? 1,2 : 3);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("print(true ? 1 : 2,3);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
1 4 |
|||
===*/ |
|||
|
|||
/* Here comma works as a normal argument separator. */ |
|||
|
|||
try { |
|||
eval("print(true ? 1 : 2, false ? 3 : 4);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
C |
|||
D |
|||
F |
|||
G |
|||
===*/ |
|||
|
|||
/* |
|||
* The following: |
|||
* |
|||
* A ? B ? C : D : E ? F : G |
|||
* |
|||
* parses as: |
|||
* |
|||
* A ? (B ? C : D) : (E ? F : G) |
|||
*/ |
|||
|
|||
try { |
|||
eval("print(true ? true ? 'C' : 'D' : true ? 'F' : 'G');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("print(true ? false ? 'C' : 'D' : true ? 'F' : 'G');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("print(false ? true ? 'C' : 'D' : true ? 'F' : 'G');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("print(false ? true ? 'C' : 'D' : false ? 'F' : 'G');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Test that we can continue after a callstack limit error. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/*FIXME*/ |
|||
|
@ -0,0 +1,60 @@ |
|||
/* |
|||
* Test that we can continue after a catchstack limit error. |
|||
*/ |
|||
|
|||
/*=== |
|||
Error |
|||
true |
|||
===*/ |
|||
|
|||
/* The current limits for callstack and catchstack are the same |
|||
* (10000), so a recursive call with more than one catcher should |
|||
* ensure that the catchstack is exhausted first. |
|||
* |
|||
* This only works (= hits catchstack limit) if valstack limit is |
|||
* significantly higher (currently 100000). |
|||
*/ |
|||
|
|||
function f1() { |
|||
try { |
|||
try { |
|||
try { |
|||
try { |
|||
f1(); |
|||
} finally { |
|||
} |
|||
} finally { |
|||
} |
|||
} finally { |
|||
} |
|||
} finally { |
|||
} |
|||
} |
|||
|
|||
try { |
|||
f1(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
|
|||
// ensure that it is indeed the catchstack which failed; Rhino and V8
|
|||
// will fail this test of course
|
|||
print(/catch/i.test(e.message)); |
|||
} |
|||
|
|||
/*=== |
|||
6765 |
|||
===* |
|||
|
|||
/* Test that we can continue normally. Just a simple recursive call test here. */ |
|||
|
|||
function fib(x) { |
|||
if (x == 0) { return 0; } |
|||
if (x == 1) { return 1; } |
|||
return fib(x - 1) + fib(x - 2); |
|||
} |
|||
|
|||
try { |
|||
print(fib(20)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
@ -0,0 +1,12 @@ |
|||
/* |
|||
* Test that we can continue after a valstack limit error. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/*FIXME*/ |
|||
|
@ -0,0 +1,40 @@ |
|||
|
|||
/*=== |
|||
resume tests |
|||
yielder starting |
|||
yielder arg: foo |
|||
yielded with 1 |
|||
resumed with bar |
|||
yielded with 2 |
|||
resumed with quux |
|||
yielded with 3 |
|||
resumed with baz |
|||
yielder ending |
|||
yielded with 123 |
|||
finished |
|||
===*/ |
|||
|
|||
function yielder(x) { |
|||
var yield = __duk__.yield; |
|||
|
|||
print('yielder starting'); |
|||
print('yielder arg:', x); |
|||
|
|||
print('resumed with', yield(1)); |
|||
print('resumed with', yield(2)); |
|||
print('resumed with', yield(3)); |
|||
|
|||
print('yielder ending'); |
|||
return 123; |
|||
} |
|||
|
|||
var t = __duk__.spawn(yielder); |
|||
|
|||
print('resume tests'); |
|||
print('yielded with', __duk__.resume(t, 'foo')); |
|||
print('yielded with', __duk__.resume(t, 'bar')); |
|||
print('yielded with', __duk__.resume(t, 'quux')); |
|||
print('yielded with', __duk__.resume(t, 'baz')); |
|||
|
|||
print('finished'); |
|||
|
@ -0,0 +1,123 @@ |
|||
/* |
|||
* Some test cases for label matching cases. |
|||
* |
|||
* Especially, test 'continue' through a switch. |
|||
*/ |
|||
|
|||
/*=== |
|||
before break |
|||
after do |
|||
before continue |
|||
after do |
|||
===*/ |
|||
|
|||
/* fast break (handled with a JUMP) */ |
|||
|
|||
try { |
|||
do { |
|||
print("before break"); |
|||
break; |
|||
print("after break"); |
|||
} while(0); |
|||
print("after do"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
done = 0; |
|||
do { |
|||
if (done) { |
|||
break; |
|||
} |
|||
print("before continue"); |
|||
done = 1; |
|||
continue; |
|||
print("after continue"); |
|||
} while(0); |
|||
print("after do"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
break caught by finally |
|||
broke out |
|||
continue caught by finally |
|||
broke out |
|||
===*/ |
|||
|
|||
/* slow break across a try-catch boundary, handled with BREAK */ |
|||
|
|||
try { |
|||
do { |
|||
try { |
|||
break; |
|||
} finally { |
|||
print("break caught by finally"); // caught, but rethrown
|
|||
} |
|||
} while(true); |
|||
print("broke out"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/* slow continue across a try-catch boundary, handled with CONTINUE */ |
|||
|
|||
try { |
|||
done = 0; |
|||
do { |
|||
if (done) { |
|||
break; |
|||
} |
|||
try { |
|||
done = 1; |
|||
continue; |
|||
} finally { |
|||
print("continue caught by finally"); // caught, but rethrown
|
|||
} |
|||
} while(true); |
|||
print("broke out"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
===*/ |
|||
|
|||
/* FIXME: same tests for 'with' */ |
|||
|
|||
/*=== |
|||
3 |
|||
2 |
|||
1 |
|||
loop done |
|||
===*/ |
|||
|
|||
/* A continue with an empty label from inside a switch should bypass the |
|||
* switch statement (which registers no empty label for 'continue') and |
|||
* may match an empty label outside the switch. |
|||
*/ |
|||
|
|||
try { |
|||
count = 3; |
|||
do { |
|||
print(count); |
|||
count -= 1; |
|||
if (count == 0) { |
|||
break; |
|||
} |
|||
|
|||
switch(1) { |
|||
case 1: |
|||
// this continue should go to top of the do-loop
|
|||
continue; |
|||
} |
|||
|
|||
print("never here"); |
|||
} while(true); |
|||
print("loop done"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,22 @@ |
|||
/*=== |
|||
foo |
|||
bar |
|||
foo |
|||
===*/ |
|||
|
|||
try { |
|||
throw 'foo'; |
|||
} catch (e) { |
|||
print(e); |
|||
|
|||
try { |
|||
throw 'bar'; |
|||
} catch (e) { |
|||
/* new, shadowing lex env here */ |
|||
print(e); |
|||
/* old lex env restored before inner try completes */ |
|||
} |
|||
|
|||
print(e); |
|||
} |
|||
|
@ -0,0 +1,11 @@ |
|||
/*=== |
|||
Infinity |
|||
===*/ |
|||
|
|||
with (Number) { |
|||
/* binds to Number.POSITIVE_INFINITY */ |
|||
print(POSITIVE_INFINITY); |
|||
} |
|||
|
|||
/* FIXME: more tests */ |
|||
|
@ -0,0 +1,25 @@ |
|||
|
|||
/*=== |
|||
d |
|||
c |
|||
b |
|||
a |
|||
===*/ |
|||
|
|||
function f(a,b,c) { |
|||
if (a) { |
|||
print('a'); |
|||
} else if (b) { |
|||
print('b'); |
|||
} else if (c) { |
|||
print('c'); |
|||
} else { |
|||
print('d'); |
|||
} |
|||
} |
|||
|
|||
f(false, false, false); |
|||
f(false, false, true); |
|||
f(false, true, false); |
|||
f(true, false, false); |
|||
|
@ -0,0 +1,186 @@ |
|||
/* |
|||
* Tests for declaration binding instantiation (E5 Section 10.5). |
|||
*/ |
|||
|
|||
/*=== |
|||
1 |
|||
false |
|||
1 |
|||
SyntaxError |
|||
1 |
|||
false |
|||
1 |
|||
SyntaxError |
|||
function |
|||
false |
|||
function |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Argument, function declaration, and variable bindings are |
|||
* non-configurable (non-deletable) in function code. |
|||
*/ |
|||
|
|||
try { |
|||
// binding not deletable, 'delete a' returns false (E5 Section 10.2.1.1.5,
|
|||
// step 3).
|
|||
eval("function func_arg1(a) { print(a); print(delete a); print(a); }"); |
|||
func_arg1(1); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// in strict mode, SyntaxError
|
|||
eval("function func_arg2(a) { 'use strict'; print(a); print(delete a); print(a); }"); |
|||
func_arg2(1); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_var1() { var a = 1; print(a); print(delete a); print(a); }"); |
|||
func_var1(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_var2() { 'use strict'; var a = 1; print(a); print(delete a); print(a); }"); |
|||
func_var2(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_fun1() { function a() {}; print(typeof a); print(delete a); print(typeof a); }"); |
|||
func_fun1(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_fun2() { 'use strict'; function a() {}; print(typeof a); print(delete a); print(typeof a); }"); |
|||
func_fun2(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
10 |
|||
true |
|||
ReferenceError |
|||
function |
|||
true |
|||
undefined |
|||
===*/ |
|||
|
|||
/* Variable and function declarations established using a direct eval ARE deletable, |
|||
* even in function code. |
|||
*/ |
|||
|
|||
try { |
|||
eval("function func_var_eval1() { eval('var a = 10'); print(a); print(delete(a)); print(a); };"); |
|||
func_var_eval1(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_fun_eval1() { eval('function a() {}'); print(typeof a); print(delete(a)); print(typeof a); };"); |
|||
func_fun_eval1(); |
|||
} catch (e) { |
|||
print(e.name, e.message); |
|||
} |
|||
|
|||
/*=== |
|||
true |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Attempt to delete an unresolvable identifier reference returns true (!) in |
|||
* non-strict mode, and is a SyntaxError in strict mode. |
|||
*/ |
|||
|
|||
try { |
|||
eval("function func_unres1(a) { print(delete unresolvable); }"); |
|||
func_unres1(1); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function func_unres2(a) { 'use strict'; print(delete unresolvable); }"); |
|||
func_unres2(1); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
ReferenceError |
|||
ReferenceError |
|||
object |
|||
===*/ |
|||
|
|||
/* Arguments binding should exist for functions, not for global/eval code. |
|||
* |
|||
* Note: 'node' has arguments bound in global code. Rhino also does. |
|||
*/ |
|||
|
|||
try { |
|||
// global
|
|||
print(typeof arguments); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// eval embedded in global
|
|||
print(eval("typeof arguments")); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// function
|
|||
eval("function foo() { print(typeof arguments); }; foo();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
object |
|||
number |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* An arguments binding is mutable for non-strict code, immutable for strict code. |
|||
* |
|||
* Attempt to assign to arguments is a SyntaxError in strict code, so this is |
|||
* actually pretty difficult to test :-). Even direct eval in strict code |
|||
* creates a separate variable environment. |
|||
*/ |
|||
|
|||
function arguments_mutability1() { |
|||
print(typeof arguments); |
|||
arguments = 1; |
|||
print(typeof arguments); |
|||
} |
|||
|
|||
try { |
|||
arguments_mutability1(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function arguments_mutability2() {\n" + |
|||
" 'use strict';\n" + |
|||
" print(typeof arguments);\n" + |
|||
" arguments = 1;\n" + |
|||
" print(typeof arguments);\n" + |
|||
"}"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,149 @@ |
|||
|
|||
/* FIXME: deletion tests for unconfigurable bindings etc */ |
|||
|
|||
/*=== |
|||
1 2 |
|||
undefined 2 |
|||
undefined undefined |
|||
===*/ |
|||
|
|||
var obj = {foo:1, bar:2}; |
|||
|
|||
print(obj.foo, obj.bar); |
|||
delete obj.foo; |
|||
print(obj.foo, obj.bar); |
|||
delete obj['bar']; |
|||
print(obj.foo, obj.bar); |
|||
|
|||
/*=== |
|||
true |
|||
false |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
/* Attempting to delete an unresolvable reference is 'true' in non-strict mode. |
|||
* Deleting a resolvable reference returns 'true' or 'false', depending on |
|||
* whether the target is deletable. |
|||
*/ |
|||
|
|||
this.deletable_ref = 1; /* configurable property in global object -> deletable */ |
|||
|
|||
try { |
|||
/* unresolvable (at run time) */ |
|||
|
|||
/* Note: Rhino will throw a TypeError: |
|||
* "js: uncaught JavaScript runtime exception: TypeError: Cannot delete property "foo" of null" |
|||
* |
|||
* V8 works correctly. |
|||
*/ |
|||
|
|||
print(delete foo); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* resolvable, maps to global object, cannot be deleted */ |
|||
print(delete NaN); /* this.NaN is a non-configurable property */ |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* resolvable, a non-deletable variable binding, cannot be deleted */ |
|||
eval("function f_vardel() { var x; print(delete x); }; f_vardel();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* resolvable, maps to global object, can be deleted */ |
|||
print(delete deletable_ref); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
SyntaxError |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Attempting to delete an unresolvable reference or any identifier |
|||
* in strict mode is a compile-time SyntaxError. |
|||
*/ |
|||
|
|||
try { |
|||
eval("function f1(x) { 'use strict'; delete x; }; f1();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function f2() { 'use strict'; var x = 1; delete x; }; f2();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function f3() { 'use strict'; function x() {}; delete x; }; f3();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// parseInt resides in the global object, which is bound to the global
|
|||
// environment record
|
|||
eval("function f4() { 'use strict'; delete parseInt; }; f4();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
true |
|||
test |
|||
true |
|||
===*/ |
|||
|
|||
/* Deleting a non-reference is always 'true', even in strict mode. */ |
|||
|
|||
try { |
|||
print(delete 1); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(delete print('test')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
1 |
|||
true |
|||
true |
|||
undefined |
|||
===*/ |
|||
|
|||
/* Parenthesis must not affect behavior */ |
|||
|
|||
obj = {foo:1}; |
|||
|
|||
try { |
|||
print(obj.foo); |
|||
print(delete ((obj['foo']))); |
|||
print(delete ((obj['bar']))); // undefined property -> 'true'
|
|||
print(obj.foo); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,250 @@ |
|||
/* |
|||
* A bit messy direct eval tests. |
|||
*/ |
|||
|
|||
var global = this; |
|||
var orig_eval = eval; |
|||
|
|||
/*=== |
|||
false |
|||
"this" value |
|||
10 |
|||
20 |
|||
false |
|||
"this" value |
|||
20 |
|||
20 |
|||
5 |
|||
===*/ |
|||
|
|||
/* Direct eval call needs to (1) be referenced with the name 'eval', |
|||
* and (2) bind to the original eval() function. |
|||
* |
|||
* It does NOT need to be bound through the original environment |
|||
* record, i.e. the global object. A local variable with the name |
|||
* 'eval' and which points to the built-in eval function is OK. |
|||
*/ |
|||
|
|||
var x = 5; |
|||
|
|||
function f1() { |
|||
var x = 10; |
|||
|
|||
// direct eval, non-strict eval code ->
|
|||
// * this binding maintained
|
|||
// * lexical/variable environment maintained
|
|||
|
|||
print(eval("this === global")); |
|||
print("" + eval("this")); |
|||
print(eval("x")); // binds to f1()'s var 'x'
|
|||
eval("var x = 20"); // modifies f1()'s var 'x'
|
|||
print(x); |
|||
|
|||
// direct eval, strict eval code ->
|
|||
// * this binding maintained
|
|||
// * lexical/variable environment is a fresh one
|
|||
|
|||
print(eval("'use strict'; this === global")); |
|||
print("" + eval("'use strict'; this")); |
|||
print(eval("'use strict'; x")); // "bleeds out", matches f1()'x var 'x'
|
|||
eval("'use strict'; var x = 30;"); // own env, no change to our 'x'
|
|||
print(x); |
|||
} |
|||
|
|||
try { |
|||
f1.call('"this" value'); |
|||
print(x); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
/*=== |
|||
true |
|||
Infinity |
|||
5 |
|||
50 |
|||
20 |
|||
true |
|||
Infinity |
|||
15 |
|||
50 |
|||
20 |
|||
15 |
|||
20 |
|||
===*/ |
|||
|
|||
function f2() { |
|||
var x = 50; |
|||
var indirect_eval = eval; |
|||
|
|||
// indirect_eval("x") and indirect_eval("var x = 15") fails
|
|||
// in V8 for some reason
|
|||
|
|||
// indirect eval call, non-strict eval code ->
|
|||
// * this binding is global object
|
|||
// * lexical/variable environment is the global object
|
|||
|
|||
print(indirect_eval("this === global")); |
|||
print(indirect_eval("this.Number.POSITIVE_INFINITY")); |
|||
print(indirect_eval("x")); // binds to global 'x'
|
|||
indirect_eval("var x = 15"); // to global object
|
|||
indirect_eval("var y = 20"); // to global object
|
|||
print(x); // our 'x'
|
|||
print(y); // still prints, bleeds to global object
|
|||
|
|||
// indirect eval call, strict eval code
|
|||
// * this binding is global object
|
|||
// * lexical/variable environment is a fresh one
|
|||
|
|||
print(indirect_eval("'use strict'; this === global")); |
|||
print(indirect_eval("'use strict'; this.Number.POSITIVE_INFINITY")); |
|||
print(indirect_eval("'use strict'; x")); // bleeds out, binds to global 'x'
|
|||
indirect_eval("'use strict'; var x = 100"); // own copy
|
|||
indirect_eval("'use strict'; var y = 200"); // own copy
|
|||
print(x); // our 'x'
|
|||
print(y); // still prints, bleeds to global object
|
|||
} |
|||
|
|||
try { |
|||
f2.call('"this" value'); |
|||
print(x); |
|||
print(y); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
"this" value |
|||
===*/ |
|||
|
|||
/* Direct eval call through a local variable of name 'eval'. |
|||
* Note that we can't simply say 'var eval = eval' because |
|||
* that would ALWAYS assign undefined to 'eval' (variable |
|||
* declarations happen before any right-hand-sides are |
|||
* evaluated). |
|||
*/ |
|||
|
|||
function f3() { |
|||
var eval = orig_eval; |
|||
|
|||
// this is a direct eval -> this binding should remain
|
|||
print("" + eval('this')); |
|||
} |
|||
|
|||
try { |
|||
f3.call('"this" value'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
false |
|||
fake eval |
|||
true |
|||
false |
|||
===*/ |
|||
|
|||
|
|||
/* An illustration that a certain eval() call may change from a direct eval |
|||
* to an indirect one dynamically. There are other ways to get the same |
|||
* effect. |
|||
* |
|||
* The impact is that whenever a variable named 'eval' is encountered by |
|||
* the compiler, it must always generate slow path code for it. In |
|||
* particular, CSVAR must be used for call setup (not CSREG). |
|||
*/ |
|||
|
|||
var binding_obj = {}; |
|||
|
|||
function wrapper() { |
|||
var ret; |
|||
with (binding_obj) { |
|||
ret = function() { |
|||
// direct eval --> prints false
|
|||
// indirect eval --> prints true
|
|||
print(eval('this === global')); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
try { |
|||
var func = wrapper(); |
|||
|
|||
// initially, binding_obj has no 'eval' binding, hence direct eval
|
|||
func(); |
|||
|
|||
// add 'intercepting' eval binding, hence indirect eval
|
|||
binding_obj.eval = function(x) { print('fake eval'); return orig_eval(x); }; |
|||
func(); |
|||
|
|||
// remove intercepting binding, again a direct eval
|
|||
delete binding_obj.eval; |
|||
func(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
forced this |
|||
Infinity |
|||
Infinity |
|||
===*/ |
|||
|
|||
/* Is it a direct eval call if an "eval()" target is a bound function |
|||
* whose target function is the built-in eval? |
|||
* |
|||
* The answer in the spec is no: the result of GetValue() for "eval" |
|||
* must be the built-in eval function for the call to be considered |
|||
* direct. |
|||
* |
|||
* Check that we follow these semantics. |
|||
*/ |
|||
|
|||
var bound_eval = eval.bind('bound this'); // bind 'this' to 'bound this'
|
|||
var indirect_eval = eval; |
|||
|
|||
function bound1() { |
|||
// direct eval, this should bound to 'forced this'
|
|||
print("" + eval("this")); |
|||
} |
|||
|
|||
function bound2() { |
|||
// indirect eval through a bound function, this should be
|
|||
// bound to the global object
|
|||
print(bound_eval("this.Number.POSITIVE_INFINITY")); |
|||
} |
|||
|
|||
function bound3() { |
|||
// indirect eval through a bound function, but eval code is
|
|||
// strict; this should still be bound to the global object
|
|||
print(bound_eval("'use strict'; this.Number.POSITIVE_INFINITY")); |
|||
} |
|||
|
|||
try { |
|||
/* The 'this' binding for eval() itself (here, the string "bound this") |
|||
* should not really matter; the 'this' binding for the evaluated code |
|||
* should still be as specified in E5 Section 10.4.2. |
|||
* |
|||
* The initial [[Call]] would happen using semantics from E5 Section |
|||
* 15.3.4.5.1. That algorithm would [[Call]] the built-in eval |
|||
* function (E5 Section 10.4.2) which would ignore any 'this' binding. |
|||
*/ |
|||
|
|||
bound1.call('forced this'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
bound2.call('forced this'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
bound3.call('forced this'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,110 @@ |
|||
/* |
|||
* Various directive prologue tests. |
|||
* |
|||
* How to detect whether strict mode is enabled? This can be done |
|||
* through any strict mode feature. One very simple one is this: |
|||
* strict functions don't get a 'this' binding when invoked, whereas |
|||
* 'this' binding for non-strict functions is the global object. |
|||
* |
|||
* Thus, the following prints true when executed inside a strict mode |
|||
* function: |
|||
* |
|||
* print(!this); |
|||
* |
|||
*/ |
|||
|
|||
/*=== |
|||
false |
|||
true |
|||
false |
|||
true |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
/* Basic test for strict mode directive. */ |
|||
|
|||
function f_nostrict() { |
|||
print(!this); |
|||
} |
|||
|
|||
function f_strict() { |
|||
'use strict'; |
|||
print(!this); |
|||
} |
|||
|
|||
function f_nostrict_escape() { |
|||
/* escaped characters are significant for directives: the expression |
|||
* below is a directive, but not a valid 'use strict' directive. |
|||
*/ |
|||
'use\u0020strict'; |
|||
print(!this); |
|||
} |
|||
|
|||
function f_strict_escape() { |
|||
/* the first directive is ignored, the second is still processed (we're |
|||
* still in the directive prologue). |
|||
*/ |
|||
'use\u0020strict'; // not a 'use strict' directive, but still a valid directive
|
|||
'use strict'; // but this is
|
|||
print(!this); |
|||
} |
|||
|
|||
function f_nostrict_plain_string_only() { |
|||
/* to be part of the directive prologue, the expression must be a plain |
|||
* string with no parens etc. |
|||
*/ |
|||
('use strict'); // not a valid 'use strict' directive, terminates prologue
|
|||
'use strict'; // no longer a 'use strict' directive, not inside prologue
|
|||
print(!this); |
|||
} |
|||
|
|||
function f_strict_comments_ok() { |
|||
/* comments and whitespace don't affect directive prologue parsing */ |
|||
'use strict' /* comment */; |
|||
print(!this); |
|||
} |
|||
|
|||
f_nostrict(); |
|||
f_strict(); |
|||
f_nostrict_escape(); |
|||
f_strict_escape(); |
|||
f_nostrict_plain_string_only(); |
|||
f_strict_comments_ok(); |
|||
|
|||
/*=== |
|||
false |
|||
===*/ |
|||
|
|||
/* This was broken at some point: unless the first statement parsing had |
|||
* finished, the "in directive prologue" flag would be incorrectly set |
|||
* for a nested statement. |
|||
*/ |
|||
|
|||
function f_nostrict_nested() { |
|||
try { |
|||
'use strict'; // should have no effect
|
|||
} catch (e) { |
|||
} |
|||
|
|||
print(!this); |
|||
} |
|||
|
|||
f_nostrict_nested(); |
|||
|
|||
/*=== |
|||
use strict |
|||
use strict |
|||
===*/ |
|||
|
|||
/* Although directives are special, they are still valid expression statements |
|||
* and must generate an implicit return value for e.g. eval(). |
|||
*/ |
|||
|
|||
try { |
|||
print(eval("'use strict'")); |
|||
print(eval("'use strict'; var x = 10")); // var statement is empty, no effect
|
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,29 @@ |
|||
/* |
|||
* Property deleted from enumeration target is still found from |
|||
* ancestor after deletion. Should it be enumerated or not? |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/*=== |
|||
bar skip |
|||
foo inherited |
|||
===*/ |
|||
|
|||
function F() {}; |
|||
F.prototype = { "foo": "inherited" }; |
|||
|
|||
var a = new F(); |
|||
a.bar = "skip"; |
|||
a.foo = "own"; |
|||
|
|||
// enumeration order: "bar", "foo"
|
|||
for (var i in a) { |
|||
delete a.foo; // only affects 'a', not F.prototype
|
|||
print(i, a[i]); |
|||
} |
|||
|
@ -0,0 +1,30 @@ |
|||
/* |
|||
* Basic equality operator tests |
|||
*/ |
|||
|
|||
/* FIXME: fine grained coercion checks */ |
|||
|
|||
/*=== |
|||
false true false |
|||
true false true |
|||
false true false |
|||
true false true |
|||
===*/ |
|||
|
|||
print(1 == 2, 2 == 2, 3 == 2); |
|||
print(1 != 2, 2 != 2, 3 != 2); |
|||
print(1 === 2, 2 === 2, 3 === 2); |
|||
print(1 !== 2, 2 !== 2, 3 !== 2); |
|||
|
|||
/*=== |
|||
true |
|||
false |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
print(123 == '123'); |
|||
print(123 === '123'); |
|||
|
|||
print(123 != '123'); |
|||
print(123 !== '123'); |
@ -0,0 +1,54 @@ |
|||
/* |
|||
* Simple cases for Error constructor |
|||
*/ |
|||
|
|||
var e; |
|||
|
|||
/*=== |
|||
string |
|||
|
|||
string |
|||
|
|||
===*/ |
|||
|
|||
e = new Error(undefined); |
|||
print(typeof e.message); /* should be inherited from prototype, empty string */ |
|||
print(e.message); |
|||
|
|||
// same behavior if called as function
|
|||
e = Error(undefined); |
|||
print(typeof e.message); |
|||
print(e.message); |
|||
|
|||
/*=== |
|||
foo |
|||
foo |
|||
===*/ |
|||
|
|||
e = new Error('foo'); |
|||
print(e.message); |
|||
|
|||
e = Error('foo'); |
|||
print(e.message); |
|||
|
|||
/*=== |
|||
string null |
|||
string null |
|||
string 123 |
|||
string 123 |
|||
===*/ |
|||
|
|||
/* ToString() coercion */ |
|||
|
|||
e = new Error(null); |
|||
print(typeof e.message, e.message); |
|||
|
|||
e = Error(null); |
|||
print(typeof e.message, e.message); |
|||
|
|||
e = new Error(123); |
|||
print(typeof e.message, e.message); |
|||
|
|||
e = Error(123); |
|||
print(typeof e.message, e.message); |
|||
|
@ -0,0 +1,20 @@ |
|||
/*=== |
|||
number 1 |
|||
object |
|||
===*/ |
|||
|
|||
/* This parses as a block statement with a labeled statement |
|||
* ("foo:") and an expression statement ("1"). |
|||
*/ |
|||
|
|||
var t; |
|||
|
|||
t = eval("{foo:1}"); |
|||
print(typeof t, t); |
|||
|
|||
/* Probable intended object literal. */ |
|||
|
|||
t = eval("({foo:1})"); |
|||
print(typeof t); |
|||
|
|||
|
@ -0,0 +1,20 @@ |
|||
/* |
|||
* Just random tests for ensuring valstack does not grow during |
|||
* execution. |
|||
*/ |
|||
|
|||
/*=== |
|||
try finished |
|||
===*/ |
|||
|
|||
/* This was broken at one point: executor left temp values on valstack |
|||
* which eventually ran out of spare. |
|||
*/ |
|||
|
|||
try { |
|||
eval("for (var i = 0; i < 100000; i++) { 'foo' + i + 'bar' }"); |
|||
print("try finished"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,12 @@ |
|||
|
|||
/*=== |
|||
foo -> 1 |
|||
bar -> 2 |
|||
===*/ |
|||
|
|||
obj = {foo:1,bar:2}; |
|||
|
|||
for (i in obj) { |
|||
print(i,'->',obj[i]); |
|||
} |
|||
|
@ -0,0 +1,87 @@ |
|||
|
|||
function lhs() { |
|||
print('lhs'); |
|||
} |
|||
|
|||
function getenum1() { |
|||
print('getenum1'); |
|||
return {}; |
|||
} |
|||
|
|||
function getenum2() { |
|||
print('getenum2'); |
|||
return { 'foo': 'bar' }; |
|||
} |
|||
|
|||
function getint() { |
|||
print('getint'); |
|||
return 10; |
|||
} |
|||
|
|||
/*=== |
|||
getenum1 |
|||
done |
|||
getenum2 |
|||
lhs |
|||
ReferenceError |
|||
===*/ |
|||
|
|||
/* The left-hand-side of a for-in may be a function call (and some other |
|||
* expressions allowed by LeftHandSideExpression). This is NOT a SyntaxError |
|||
* and will only produce a ReferenceError when the actual assignment is |
|||
* attempted. |
|||
* |
|||
* Note that at least Rhino and V8 won't call the lhs() function before |
|||
* throwing a ReferenceError. This seems technically incorrect: E5 Section |
|||
* 12.6.4 steps 6.b and 6.c seem to indicate that the LHS should be evaluated |
|||
* first, and only the actual attempt to PutValue() to an invalid reference |
|||
* should throw a ReferenceError. The specification does allow leeway in |
|||
* whether or not the LHS is evaluated repeatedly though. |
|||
* |
|||
* In any case, the current implementation will evaluate the lhs() before |
|||
* throwing a ReferenceError, so the test case now tests for that behavior. |
|||
*/ |
|||
|
|||
try { |
|||
/* Here the enumerator will be empty, so no ReferenceError should happen. |
|||
* The lhs() expression is not evaluated at all. |
|||
*/ |
|||
|
|||
for (lhs() in getenum1()) { |
|||
print('loop'); |
|||
} |
|||
print('done'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Here empty() is called, but ReferenceError occurs on first assignment. */ |
|||
|
|||
for (lhs() in getenum2()) { |
|||
print('loop'); |
|||
} |
|||
print('done'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
getint |
|||
getenum2 |
|||
foo |
|||
===*/ |
|||
|
|||
/* The variable initializer of a for-in statement may have a value. |
|||
* That value is computed before the enumeration target is evaluated. |
|||
*/ |
|||
|
|||
try { |
|||
for (var i = getint() in getenum2()) { |
|||
print(i); |
|||
} |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,32 @@ |
|||
|
|||
/*=== |
|||
foo bar |
|||
foo bar undefined |
|||
foo |
|||
|
|||
foo |
|||
foo |
|||
foo |
|||
===*/ |
|||
|
|||
/* The apply 'argArray' does NOT have to be an array; its "length" |
|||
* property is coerced with ToUint32() and properties are then |
|||
* looped. |
|||
*/ |
|||
|
|||
/* Note: Rhino will complain the following: |
|||
* |
|||
* js: uncaught JavaScript runtime exception: TypeError: second argument to Function.prototype.apply must be an array |
|||
* |
|||
* This seems incorrect (for E5), Section 15.3.4.3 step 3 only checks |
|||
* whether the argument is an object. |
|||
*/ |
|||
|
|||
print.apply(null, { "0": "foo", "1": "bar", "length": 2 }); |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": 3 }); |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": 1 }); |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": 4294967296 }); /* ToUint32(len) -> 0 */ |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": 4294967297 }); /* ToUint32(len) -> 1 */ |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": "1" }); /* ToUint32("1") -> 1 */ |
|||
print.apply(null, { "0": "foo", "1": "bar", "length": true }); /* ToUint32(true) -> 1 */ |
|||
|
@ -0,0 +1,39 @@ |
|||
|
|||
var func; |
|||
|
|||
/*=== |
|||
|
|||
1 2 |
|||
1 2 3 4 |
|||
1 2 3 |
|||
===*/ |
|||
|
|||
/* Basic cases */ |
|||
print.bind(null)(); |
|||
print.bind(null,1,2)(); |
|||
print.bind(null,1,2)(3,4); |
|||
print.bind(null,1).bind(null,2).bind(null,3)(); |
|||
|
|||
/*=== |
|||
2 |
|||
2 |
|||
1 |
|||
0 |
|||
0 |
|||
===*/ |
|||
|
|||
/* FIXME: length handling of bound function, improve */ |
|||
|
|||
function f1(x,y) { |
|||
} |
|||
|
|||
print(f1.length); |
|||
func = f1.bind(null); |
|||
print(func.length); |
|||
func = f1.bind(null, 1); |
|||
print(func.length); |
|||
func = f1.bind(null, 1, 2); |
|||
print(func.length); |
|||
func = f1.bind(null, 1, 2, 3); |
|||
print(func.length); |
|||
|
@ -0,0 +1,23 @@ |
|||
|
|||
/*=== |
|||
|
|||
1 2 |
|||
===*/ |
|||
|
|||
/* Basic cases */ |
|||
print.call(null); |
|||
print.call(null,1,2); |
|||
|
|||
/*=== |
|||
TypeError |
|||
===*/ |
|||
|
|||
/* Contrived case where E5 Section 15.3.4.4 step 1 should cause TypeError */ |
|||
|
|||
try { |
|||
({ "call": Function.prototype.call }).call(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/* FIXME: thisArg handling */ |
@ -0,0 +1,17 @@ |
|||
|
|||
/*=== |
|||
inner 1 2 |
|||
===*/ |
|||
|
|||
function foo(x) { |
|||
return function(y) { |
|||
print('inner', x, y); |
|||
} |
|||
} |
|||
|
|||
try { |
|||
foo(1)(2); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,100 @@ |
|||
/* |
|||
* E5 Section 15.3.2: function constructor argument list is not |
|||
* necessarily just identifier names, a call argument may contain |
|||
* multiple argument declarations. |
|||
* |
|||
* The arguments joined with "," should parse as a FormalParameterList_opt. |
|||
* Apparently this means that the source can contain newlines and comments |
|||
* too! |
|||
*/ |
|||
|
|||
/*=== |
|||
6 |
|||
6 |
|||
6 |
|||
6 |
|||
6 |
|||
6 |
|||
===*/ |
|||
|
|||
var f1, f2, f3, f4, f5, f6; |
|||
|
|||
try { |
|||
print(eval('f1 = new Function("a", "b", "c", "return a+b+c"); f1(1,2,3);')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(eval('f2 = new Function("a, b, c", "return a+b+c"); f2(1,2,3);')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(eval('f3 = new Function("a, b", "c", "return a+b+c"); f3(1,2,3);')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(eval('f4 = new Function("a /*first*/", "b /*second*/, c /*third*/", "return a+b+c"); f4(1,2,3);')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* It's unclear in the specification whether this should be a SyntaxError or not. |
|||
* If one naively constructs a parse string as: |
|||
* |
|||
* function (a, b, c //last) { return a+b+c }
|
|||
* |
|||
* Then this would be a syntax error. On the other hand, the specification does not |
|||
* say that this should be done; rather, the argument list, joined by commas, should |
|||
* be parsed as a FormalParameterList_opt and the body should be parsed as a |
|||
* FunctionBody, separately. So we interpret this to mean that this should actually |
|||
* work correctly. The formal argument list to be parsed is: |
|||
* |
|||
* a,b, c // last
|
|||
* |
|||
* This fails in V8 and Rhino, though. For example, Rhino will complain: |
|||
* |
|||
* SyntaxError: missing ) after formal parameters |
|||
* |
|||
* which seems incorrect because FormalParameterList_opt does NOT include parentheses |
|||
* at all (just the identifiers and commas). |
|||
* |
|||
* V8 (Node) will complain: |
|||
* |
|||
* [SyntaxError: Unexpected token return] |
|||
* |
|||
*/ |
|||
|
|||
print(eval('f5 = new Function("a", "b, c // last", "return a+b+c"); f5(1,2,3);')); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Here the format argument list to be parsed would be: |
|||
* |
|||
* a |
|||
* ,b |
|||
* ,c // last [newline]
|
|||
* |
|||
* Again, this should parse as a FormalParameterList_opt but fails to do so in |
|||
* Rhino and V8. Rhino will complain: |
|||
* |
|||
* SyntaxError: unterminated string literal |
|||
* |
|||
* whereas V8 will complain: |
|||
* |
|||
* [SyntaxError: Unexpected token ILLEGAL] |
|||
*/ |
|||
|
|||
eval('f6 = new Function("a\n", "b\n,c // last\n", "return a+b+c"); f6(1,2,3);'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,198 @@ |
|||
/* Function formal arguments do not accept reserved words. |
|||
* |
|||
* We interpret this also to mean that a function declaration/expression |
|||
* in non-strict code will respect strict mode restricted reserved words |
|||
* if the function body is strict. This matches with V8. |
|||
*/ |
|||
|
|||
var orig_eval = eval; |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
try { |
|||
// Keyword
|
|||
eval("function foo(for) {};"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord
|
|||
eval("function foo(class) {};"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord only recognized in strict mode
|
|||
// -> should work
|
|||
eval("function foo(implements) { print(implements) }; foo('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord only recognized in strict mode,
|
|||
// function declared in non-strict mode but function
|
|||
// itself is strict
|
|||
eval("function foo(implements) { 'use strict'; };"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Function expressions */ |
|||
|
|||
try { |
|||
eval("(function foo(for) {})();"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(class) {})();"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(implements) { print(implements) })('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(implements) { 'use strict'; })();"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
success |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Eval and arguments */ |
|||
|
|||
try { |
|||
eval("function foo(eval) { print(eval); }; foo('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function foo(eval) { 'use strict'; print(eval); }; foo('success');"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function foo(arguments) { print(arguments); }; foo('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function foo(arguments) { 'use strict'; print(arguments); }; foo('success');"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
success |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Eval and arguments, function expressions */ |
|||
|
|||
try { |
|||
eval("(function foo(eval) { print(eval); })('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(eval) { 'use strict'; print(eval); })('success');"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(arguments) { print(arguments); })('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(arguments) { 'use strict'; print(arguments); })foo('success');"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
2 |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Duplicate argument names */ |
|||
|
|||
try { |
|||
// ok, binds to latter
|
|||
eval("function foo(a,a) { print(a); }; foo(1,2);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("function foo(a,a) { 'use strict'; print(a); }; foo(1,2);"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
2 |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Duplicate argument names, function expressions */ |
|||
|
|||
try { |
|||
// ok, binds to latter
|
|||
eval("(function foo(a,a) { print(a); })(1,2);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo(a,a) { 'use strict'; print(a); })(1,2);"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,11 @@ |
|||
/*=== |
|||
0 |
|||
2 |
|||
===*/ |
|||
|
|||
function f1() {} |
|||
function f2(x,y) {}; |
|||
|
|||
print(f1.length); |
|||
print(f2.length); |
|||
|
@ -0,0 +1,168 @@ |
|||
/* Function name is an identifier (in both function declaration and |
|||
* function expression) and cannot contain reserved words. Also, |
|||
* "eval" and "arguments" are prohibited for strict functions (although |
|||
* they are not reserved words). |
|||
* |
|||
* We interpret (like V8) that a strict function contained in non-strict |
|||
* code cannot be named with one of the additional strict mode reserved |
|||
* words. |
|||
*/ |
|||
|
|||
var orig_eval = eval; |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
try { |
|||
// Keyword
|
|||
eval("function for() {};"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord
|
|||
eval("function class() {};"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord only recognized in strict mode
|
|||
// -> should work
|
|||
eval("function implements() { print('success') }; implements();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// FutureReservedWord only recognized in strict mode,
|
|||
// function declared in non-strict mode but function
|
|||
// itself is strict
|
|||
eval("function implements() { 'use strict'; };"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
success |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
/* Same tests for function declarations */ |
|||
|
|||
try { |
|||
eval("(function for() {});"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function class() {});"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function implements() { print('success') })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function implements() { 'use strict'; });"); |
|||
print('never here'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
try { |
|||
eval("function eval() { 'use strict'; };"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
eval = orig_eval; // just in case
|
|||
|
|||
try { |
|||
eval("function arguments() { 'use strict'; };"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
===*/ |
|||
|
|||
try { |
|||
eval("(function eval() { 'use strict'; })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
eval = orig_eval; // just in case
|
|||
|
|||
try { |
|||
eval("(function arguments() { 'use strict'; })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
success |
|||
success |
|||
===*/ |
|||
|
|||
/* Non-strict mode allows eval() and arguments() named functions. */ |
|||
|
|||
try { |
|||
eval("function eval(a) { print(a); }; eval('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
eval = orig_eval; // just in case
|
|||
|
|||
try { |
|||
eval("function arguments(a) { print(a); }; arguments('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
success |
|||
success |
|||
===*/ |
|||
|
|||
try { |
|||
eval("(function eval(a) { print(a); })('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
eval = orig_eval; // just in case
|
|||
|
|||
try { |
|||
eval("(function arguments(a) { print(a); })('success');"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,29 @@ |
|||
/*=== |
|||
function |
|||
function |
|||
===*/ |
|||
|
|||
/* Simple test that function declaration name and function expression name |
|||
* can be accessed from inside the function. |
|||
*/ |
|||
function foo() { |
|||
print(typeof foo); |
|||
} |
|||
|
|||
try { |
|||
foo(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
var funcexpr = 'not visible'; |
|||
var temp = function funcexpr() { |
|||
print(typeof funcexpr); |
|||
}; |
|||
|
|||
try { |
|||
temp(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,98 @@ |
|||
/* |
|||
* Various identifier shadowing cases |
|||
*/ |
|||
|
|||
/*=== |
|||
function |
|||
undefined |
|||
function |
|||
inner foo |
|||
number |
|||
===*/ |
|||
|
|||
/* Function expression name is bound outside the function scope; |
|||
* a single-identifier scope is created between the surrounding |
|||
* scope and the function scope. |
|||
* |
|||
* Thus you can declare a variable or a function of the same name, |
|||
* and it will hide the function name binding. |
|||
*/ |
|||
|
|||
try { |
|||
/* Base case */ |
|||
eval("(function foo() { print(typeof foo); })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Var declaration shadows and is undefined, since variable |
|||
* declaration happens on entry but assignment only when |
|||
* statement is reached. |
|||
*/ |
|||
eval("(function foo() { print(typeof foo); var foo = 1; })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Function declaration shadows and is defined as the inner |
|||
* function: function declarations happen on entry. |
|||
*/ |
|||
eval("(function foo() { print(typeof foo); foo(); function foo() { print('inner foo'); }; })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Argument shadows the function name binding, again simply |
|||
* because the function name binding exists "outside" the |
|||
* function scope. |
|||
*/ |
|||
eval("(function foo(foo) { print(typeof foo); })(1);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
123 |
|||
function |
|||
inner func |
|||
1 |
|||
1 |
|||
10 |
|||
===*/ |
|||
|
|||
/* An argument name shadows automatic 'arguments' binding */ |
|||
|
|||
try { |
|||
eval("(function foo(arguments) { print(arguments); })(123);"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/* A function declaration inside the function shadows automatic 'arguments' |
|||
* binding. |
|||
*/ |
|||
|
|||
try { |
|||
eval("(function foo() { function arguments() { print('inner func'); }; print(typeof arguments); arguments(); })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/* A variable declaration does NOT shadow the automatic 'arguments' binding. */ |
|||
|
|||
try { |
|||
eval("(function foo() { var arguments; print(arguments[0]); })(1,2)"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
eval("(function foo() { print(arguments[0]); var arguments = 10; print(arguments); })(1,2)"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
|
@ -0,0 +1,14 @@ |
|||
/* |
|||
* Development time testcase for a function without arguments |
|||
*/ |
|||
|
|||
/*=== |
|||
hello world |
|||
===*/ |
|||
|
|||
try { |
|||
eval("(function() { print('hello world'); })();"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,14 @@ |
|||
/* FIXME: for eval/global code */ |
|||
/* FIXME: test for handling of 'valued' and 'non-valued' statements */ |
|||
|
|||
/*=== |
|||
3 |
|||
3 |
|||
===*/ |
|||
|
|||
/* basic case */ |
|||
print(eval('1+2;')); |
|||
|
|||
/* an empty statement (like debugger) must not alter non-empty previous result */ |
|||
print(eval('1+2; debugger;')); |
|||
|
@ -0,0 +1,32 @@ |
|||
/* |
|||
* Implicit return value of global code, eval code, and function code. |
|||
* |
|||
* The return value of a function unless it returns with an explicit |
|||
* value is always 'undefined', see E5 Sections 11.2.3 and 13.2.1. |
|||
* |
|||
* The return value of a program (global code or eval code) is the |
|||
* value of its last statement. A 'return' statement outside of a |
|||
* function body is, in fact, a SyntaxError (E5 Section 12.9). |
|||
* See E5 Sections 14, 15.1.2.1. |
|||
*/ |
|||
|
|||
/*=== |
|||
3 number |
|||
undefined undefined |
|||
3 number |
|||
===*/ |
|||
|
|||
var t; |
|||
|
|||
t = eval("1+2"); |
|||
print(t, typeof t); |
|||
|
|||
function f1(a,b) { a+b; } |
|||
function f2(a,b) { return a+b; } |
|||
|
|||
t = f1(1,2); |
|||
print(t, typeof t); |
|||
|
|||
t = f2(1,2); |
|||
print(t, typeof t); |
|||
|
@ -0,0 +1,24 @@ |
|||
/* |
|||
* LeftHandSideExpression allows a much wider syntactical set of |
|||
* lvalues than we actually support. Valid LHS values which we |
|||
* can't write to must not cause SyntaxError but a ReferenceError. |
|||
* |
|||
* The side effects of the LHS and the RHS (in that order) must |
|||
* happen before the ReferenceError. |
|||
*/ |
|||
|
|||
/* FIXME: is this correct? Both Rhino and V8 will just throw a |
|||
* ReferenceError. |
|||
*/ |
|||
|
|||
/*=== |
|||
lhs |
|||
rhs |
|||
ReferenceError |
|||
===*/ |
|||
|
|||
try { |
|||
eval("print('lhs') = print('rhs');"); |
|||
} catch(e) { |
|||
print(e.name); |
|||
} |
@ -0,0 +1,41 @@ |
|||
/*=== |
|||
TypeError |
|||
TypeError |
|||
TypeError |
|||
===*/ |
|||
|
|||
/* TypeError is required for cyclic structures. */ |
|||
|
|||
obj1 = { 'foo': 1 }; |
|||
obj1.cycle = obj1; |
|||
|
|||
obj2a = { 'foo': 1 }; |
|||
obj2b = { 'bar': 2 }; |
|||
obj2a.cycle = obj2b; |
|||
obj2b.cycle = obj2a; |
|||
|
|||
obj3a = { 'foo': 1 }; |
|||
obj3b = { 'bar': 2 }; |
|||
obj3c = { 'quux': 3 }; |
|||
obj3a.cycle = obj3b; |
|||
obj3b.cycle = obj3c; |
|||
obj3c.cycle = obj3a; |
|||
|
|||
try { |
|||
print(JSON.stringify(obj1)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(JSON.stringify(obj2a)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
print(JSON.stringify(obj3a)); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,267 @@ |
|||
|
|||
var t; |
|||
var i; |
|||
var x; |
|||
var numbers; |
|||
|
|||
/*=== |
|||
undefined undefined |
|||
{} |
|||
{"foo":1} |
|||
[1,2,null,4] |
|||
===*/ |
|||
|
|||
// result is undefined
|
|||
t = JSON.stringify(undefined); |
|||
print(typeof t, t); |
|||
|
|||
// undefined values are not serialized in objects
|
|||
print(JSON.stringify({bar:undefined})); // empty case perhaps worth extra test
|
|||
print(JSON.stringify({foo:1,bar:undefined})); |
|||
|
|||
// undefined values are serialized as 'null' in arrays
|
|||
print(JSON.stringify([1,2,undefined,4])); |
|||
|
|||
/*=== |
|||
string null |
|||
{"foo":1,"bar":null} |
|||
[1,2,null,4] |
|||
===*/ |
|||
|
|||
t = JSON.stringify(null); |
|||
print(typeof t, t); |
|||
|
|||
print(JSON.stringify({foo:1,bar:null})); |
|||
|
|||
print(JSON.stringify([1,2,null,4])); |
|||
|
|||
/*=== |
|||
string true |
|||
{"foo":1,"bar":true} |
|||
[1,2,true,4] |
|||
===*/ |
|||
|
|||
t = JSON.stringify(true); |
|||
print(typeof t, t); |
|||
|
|||
print(JSON.stringify({foo:1,bar:true})); |
|||
|
|||
print(JSON.stringify([1,2,true,4])); |
|||
|
|||
/*=== |
|||
string false |
|||
{"foo":1,"bar":false} |
|||
[1,2,false,4] |
|||
===*/ |
|||
|
|||
t = JSON.stringify(false); |
|||
print(typeof t, t); |
|||
|
|||
print(JSON.stringify({foo:1,bar:false})); |
|||
|
|||
print(JSON.stringify([1,2,false,4])); |
|||
|
|||
/*=== |
|||
string -123 |
|||
{"foo":1,"bar":-123} |
|||
[1,2,-123,4] |
|||
string 0 |
|||
{"foo":1,"bar":0} |
|||
[1,2,0,4] |
|||
string 0 |
|||
{"foo":1,"bar":0} |
|||
[1,2,0,4] |
|||
string 123 |
|||
{"foo":1,"bar":123} |
|||
[1,2,123,4] |
|||
string null |
|||
{"foo":1,"bar":null} |
|||
[1,2,null,4] |
|||
string null |
|||
{"foo":1,"bar":null} |
|||
[1,2,null,4] |
|||
string null |
|||
{"foo":1,"bar":null} |
|||
[1,2,null,4] |
|||
===*/ |
|||
|
|||
/* Basic cases for numbers. Special cases: |
|||
* |
|||
* +0/-0 serializes as 0 (the sign of zero is always omitted) |
|||
* -Infinity serializes a null |
|||
* Infinity - "" - |
|||
* NaN - "" - |
|||
*/ |
|||
|
|||
numbers = [ -123, -0, +0, 123, |
|||
Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN ]; |
|||
|
|||
for (i = 0; i < numbers.length; i++) { |
|||
x = numbers[i]; |
|||
|
|||
t = JSON.stringify(x); |
|||
print(typeof t, t); |
|||
|
|||
print(JSON.stringify({foo:1,bar:x})); |
|||
|
|||
print(JSON.stringify([1,2,x,4])); |
|||
} |
|||
|
|||
/*=== |
|||
===*/ |
|||
|
|||
/* Fraction handling for numbers. */ |
|||
|
|||
/* FIXME */ |
|||
|
|||
/*=== |
|||
string "foo" |
|||
{"foo":1,"bar":"foo"} |
|||
[1,2,"foo",4] |
|||
string "foo \n\"bar" |
|||
{"foo":1,"bar":"foo \n\"bar"} |
|||
[1,2,"foo \n\"bar",4] |
|||
===*/ |
|||
|
|||
/* Basic cases for strings. */ |
|||
|
|||
strings = [ "foo", "foo \n\"bar" ]; |
|||
|
|||
for (i = 0; i < strings.length; i++) { |
|||
x = strings[i]; |
|||
|
|||
t = JSON.stringify(x); |
|||
print(typeof t, t); |
|||
|
|||
print(JSON.stringify({foo:1,bar:x})); |
|||
|
|||
print(JSON.stringify([1,2,x,4])); |
|||
} |
|||
|
|||
/*=== |
|||
"\"" |
|||
"\\" |
|||
"/" |
|||
"\u0000" |
|||
"\u0001" |
|||
"\u0002" |
|||
"\u0003" |
|||
"\u0004" |
|||
"\u0005" |
|||
"\u0006" |
|||
"\u0007" |
|||
"\b" |
|||
"\t" |
|||
"\n" |
|||
"\u000b" |
|||
"\f" |
|||
"\r" |
|||
"\u000e" |
|||
"\u000f" |
|||
"\u0010" |
|||
"\u0011" |
|||
"\u0012" |
|||
"\u0013" |
|||
"\u0014" |
|||
"\u0015" |
|||
"\u0016" |
|||
"\u0017" |
|||
"\u0018" |
|||
"\u0019" |
|||
"\u001a" |
|||
"\u001b" |
|||
"\u001c" |
|||
"\u001d" |
|||
"\u001e" |
|||
"\u001f" |
|||
" " |
|||
34 128 34 |
|||
34 129 34 |
|||
34 130 34 |
|||
34 131 34 |
|||
34 132 34 |
|||
34 133 34 |
|||
34 134 34 |
|||
34 135 34 |
|||
34 136 34 |
|||
34 137 34 |
|||
34 138 34 |
|||
34 139 34 |
|||
34 140 34 |
|||
34 141 34 |
|||
34 142 34 |
|||
34 143 34 |
|||
34 144 34 |
|||
34 145 34 |
|||
34 146 34 |
|||
34 147 34 |
|||
34 148 34 |
|||
34 149 34 |
|||
34 150 34 |
|||
34 151 34 |
|||
34 152 34 |
|||
34 153 34 |
|||
34 154 34 |
|||
34 155 34 |
|||
34 156 34 |
|||
34 157 34 |
|||
34 158 34 |
|||
34 159 34 |
|||
===*/ |
|||
|
|||
/* Escape testing. |
|||
* |
|||
* Note that JSON.stringify() is required to NOT escape any control |
|||
* characters which are < U+0020. For instance, U+0080 is encoded |
|||
* as the three characters '"', '\u0080' (unescaped), '"'. We test |
|||
* for these by looking at the code points. |
|||
* |
|||
* Also note that although '/' can be escaped in JSON, it MUST NOT |
|||
* be escaped by JSON.stringify(). |
|||
*/ |
|||
|
|||
// special chars
|
|||
strings = [ '"', '\\', '/' ]; |
|||
for (i = 0; i < strings.length; i++) { |
|||
t = JSON.stringify(strings[i]); |
|||
print(t); |
|||
} |
|||
|
|||
for (i = 0; i <= 32; i++) { |
|||
t = JSON.stringify(String.fromCharCode(i)); |
|||
print(t); |
|||
} |
|||
|
|||
for (i = 0x80; i < 0xa0; i++) { |
|||
t = JSON.stringify(String.fromCharCode(i)); |
|||
print(t.charCodeAt(0), t.charCodeAt(1), t.charCodeAt(2)); |
|||
} |
|||
|
|||
/*=== |
|||
{"foo":1,"bar":"text","object":{"baz":2},"array":[1,2,3]} |
|||
===*/ |
|||
|
|||
/* Very basic object/array serialization test. */ |
|||
t = JSON.stringify({foo:1,bar:'text',object:{baz:2},array:[1,2,3]}); |
|||
print(t); |
|||
|
|||
/*=== |
|||
[1,2,null,4] |
|||
[1,2,null,4] |
|||
[1,2,null,4] |
|||
===*/ |
|||
|
|||
/* Functions (anything callable) serialize as 'null' */ |
|||
|
|||
// anonymous Ecmascript function
|
|||
t = JSON.stringify([1,2,function(){},4]); |
|||
print(t); |
|||
|
|||
// native function
|
|||
t = JSON.stringify([1,2,Object.prototype.toString,4]); |
|||
print(t); |
|||
|
|||
// bound function
|
|||
t = JSON.stringify([1,2,print.bind('foo'),4]); |
|||
print(t); |
|||
|
@ -0,0 +1,34 @@ |
|||
/* When encoding any value (val) using JSON.stringigy(), encoding begins |
|||
* with a dummy wrapper object: |
|||
* |
|||
* { "": val } |
|||
* |
|||
* This seems to be a purely internal matter but is not: the wrapper |
|||
* object is accessible to a replacement function. |
|||
*/ |
|||
|
|||
var val; |
|||
var t; |
|||
|
|||
/*=== |
|||
replacer |
|||
object |
|||
foo |
|||
|
|||
foo |
|||
===*/ |
|||
|
|||
// Here the wrapper object is: { "": "foo" }
|
|||
|
|||
val = "foo"; |
|||
t = JSON.stringify(val, function(k, v) { |
|||
// this binding: holder object, i.e. the wrapper
|
|||
// k: key
|
|||
// v: value
|
|||
|
|||
print("replacer"); |
|||
print(typeof this); |
|||
print(this['']); // access the empty string key of the wrapper!
|
|||
print(k); // empty string
|
|||
print(v); // 'foo'
|
|||
}); |
@ -0,0 +1,24 @@ |
|||
/* |
|||
* Simple label parsing test without actual label semantics tests. |
|||
*/ |
|||
|
|||
/*=== |
|||
foo |
|||
bar |
|||
quux |
|||
===*/ |
|||
|
|||
label1: |
|||
print("foo"); |
|||
|
|||
label1: |
|||
label2: |
|||
print("bar"); |
|||
|
|||
label1: |
|||
label2: |
|||
label3: |
|||
do { |
|||
print("quux"); |
|||
} while(0); |
|||
|
@ -0,0 +1,51 @@ |
|||
/* |
|||
* A labelled statement can only be followed by a statement, not a |
|||
* source element, even at the top level. Concretely, a function |
|||
* declaration cannot follow a label, nor can an expression statement |
|||
* begin with 'function'. |
|||
* |
|||
* This is the E5 standards compliant behavior, which this test now |
|||
* looks for. In practice, it makes sense to parse these as either |
|||
* function expressions, or as some form of 'function statements'. |
|||
* The test needs to be updated when decision on this is made. |
|||
*/ |
|||
|
|||
/*=== |
|||
SyntaxError |
|||
SyntaxError |
|||
try finished |
|||
===*/ |
|||
|
|||
try { |
|||
/* Function f2 declaration follows label which is not allowed. |
|||
* Also, an expression statement cannot begin with 'function', |
|||
* so this should result in SyntaxError. |
|||
* |
|||
* V8 allows this in non-strict mode (as function statement?). |
|||
*/ |
|||
|
|||
eval("function f1() { mylabel: function f2() {} }"); |
|||
print("try finished"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Strict mode should have no effect on this, but this test |
|||
* illustrates V8 behavior (i.e. V8 gives a SyntaxError here |
|||
* but only in strict mode). |
|||
*/ |
|||
eval("function f1() { 'use strict'; mylabel: function f2() {} }"); |
|||
print("try finished"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
/* Here function f2 is a function expression, so it is OK. */ |
|||
eval("function f1() { mylabel: (function f2() {}) }"); |
|||
print("try finished"); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue