mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
7.9 KiB
295 lines
7.9 KiB
/*
|
|
* If the 'caller' property of a non-bound function (strict or not) or an
|
|
* Arguments object of a non-strict function with at least one formal parameter
|
|
* has a -value- which is a strict function, throw a TypeError in [[Get]].
|
|
* See E5.1 Sections 15.3.5.4 and 10.6.
|
|
*
|
|
* The situation is a bit ambiguous for bound functions: Section 15.3.4.5
|
|
* (which describes bind()) states that [[Get]] is as for ordinary functions,
|
|
* specified in Section 15.3.5.4. However, Section 15.3.5.4 states:
|
|
*
|
|
* NOTE: Function objects created using Function.prototype.bind
|
|
* use the default [[Get]] internal method.
|
|
*
|
|
* This seems to imply that bound functions do not have this special
|
|
* behavior.
|
|
*
|
|
* These special [[Get]] behaviors are quite complicated to understand
|
|
* because both the base value and the property value affect the final
|
|
* behavior. Also, the nature of the Arguments object depends on whether
|
|
* the function has formal arguments or not, which is quite nonintuitive.
|
|
*
|
|
* Rhino and V8 also don't seem to match the behavior mandated by the
|
|
* specification. For V8 there seem to be the following deviations:
|
|
*
|
|
* - V8 doesn't apply the special [[Get]] semantics to non-strict
|
|
* functions while E5.1 Section 15.3.5.4 doesn't limit the behavior
|
|
* to strict functions only (the behavior is limited to 'caller'
|
|
* having a strict function as a -value-, but the base can be a
|
|
* non-strict function too).
|
|
*
|
|
* - V8 promotes a string written to 'caller' into an object which
|
|
* seems non-compliant.
|
|
*
|
|
* - V8 doesn't apply the special [[Get]] semantics for non-strict
|
|
* Arguments object even when the callee has formal arguments
|
|
* (which is supposed to enable the special behaviors for the
|
|
* [[ParameterMap]] handling and "caller").
|
|
*/
|
|
|
|
/*===
|
|
functions
|
|
0 0 string
|
|
0 1 function
|
|
0 2 TypeError
|
|
0 3 function
|
|
0 4 TypeError
|
|
1 0 fail to set "caller": TypeError
|
|
1 0 TypeError
|
|
1 1 fail to set "caller": TypeError
|
|
1 1 TypeError
|
|
1 2 fail to set "caller": TypeError
|
|
1 2 TypeError
|
|
1 3 fail to set "caller": TypeError
|
|
1 3 TypeError
|
|
1 4 fail to set "caller": TypeError
|
|
1 4 TypeError
|
|
2 0 fail to set "caller": TypeError
|
|
2 0 TypeError
|
|
2 1 fail to set "caller": TypeError
|
|
2 1 TypeError
|
|
2 2 fail to set "caller": TypeError
|
|
2 2 TypeError
|
|
2 3 fail to set "caller": TypeError
|
|
2 3 TypeError
|
|
2 4 fail to set "caller": TypeError
|
|
2 4 TypeError
|
|
3 0 fail to set "caller": TypeError
|
|
3 0 TypeError
|
|
3 1 fail to set "caller": TypeError
|
|
3 1 TypeError
|
|
3 2 fail to set "caller": TypeError
|
|
3 2 TypeError
|
|
3 3 fail to set "caller": TypeError
|
|
3 3 TypeError
|
|
3 4 fail to set "caller": TypeError
|
|
3 4 TypeError
|
|
non-strict arguments, no formals
|
|
bar
|
|
undefined
|
|
0 string
|
|
1 function
|
|
2 function
|
|
3 function
|
|
4 function
|
|
non-strict arguments, with formals
|
|
bar
|
|
undefined
|
|
0 string
|
|
1 function
|
|
2 TypeError
|
|
3 function
|
|
4 TypeError
|
|
strict arguments, no formals
|
|
bar
|
|
TypeError
|
|
strict arguments, with formals
|
|
bar
|
|
TypeError
|
|
===*/
|
|
|
|
var baseFunctionCreators = [
|
|
function () {
|
|
return function nonStrictNonBoundBase () {}
|
|
},
|
|
function () {
|
|
return function strictNonBoundBase () { 'use strict'; }
|
|
},
|
|
function () {
|
|
var f = function nonStrictBoundBase() {};
|
|
return f.bind('dummy');
|
|
},
|
|
function () {
|
|
var f = function strictBoundBase() { 'use strict' };
|
|
return f.bind('dummy');
|
|
}
|
|
];
|
|
|
|
function nonStrictFunc() {
|
|
}
|
|
function strictFunc() {
|
|
'use strict';
|
|
}
|
|
var nonStrictBoundFunc = nonStrictFunc.bind('dummy');
|
|
var strictBoundFunc = strictFunc.bind('dummy');
|
|
|
|
var callerPropertyValues = [
|
|
'whatever',
|
|
nonStrictFunc,
|
|
strictFunc,
|
|
nonStrictBoundFunc,
|
|
strictBoundFunc
|
|
];
|
|
|
|
function testFunctions() {
|
|
var i, j;
|
|
var base, val;
|
|
|
|
for (i = 0; i < baseFunctionCreators.length; i++) {
|
|
for (j = 0; j < callerPropertyValues.length; j++) {
|
|
base = baseFunctionCreators[i]();
|
|
|
|
// Note: this step fails (as expected) for bound functions and
|
|
// strict functions because they have a non-writable 'caller'
|
|
// property.
|
|
try {
|
|
base.caller = callerPropertyValues[j];
|
|
} catch (e) {
|
|
print(i, j, 'fail to set "caller": ' + e.name);
|
|
}
|
|
|
|
try {
|
|
val = base.caller;
|
|
print(i, j, typeof val);
|
|
} catch (e) {
|
|
print(i, j, e.name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Quite counterintuitively, a non-strict function with *no formals* will get
|
|
// an arguments object no special [[Get]] behavior -- not even special behavior
|
|
// for 'caller'. This happens because the arguments object will not get a
|
|
// [[ParameterMap]] in E.5 Section 10.6 step 12 and then later in Section 10.6:
|
|
//
|
|
// The [[Get]] internal method of an arguments object for a non-strict mode
|
|
// function with formal parameters when called with a property name P performs
|
|
// the following steps: [...]
|
|
|
|
function testArgumentsNonStrictNoFormals() {
|
|
var val;
|
|
var i;
|
|
|
|
print(arguments[1]); // just a test to see 'arguments' is proper
|
|
|
|
// Non-strict arguments has no 'caller' property so we can vary its value.
|
|
try {
|
|
val = arguments.caller;
|
|
print(typeof val);
|
|
} catch (e) {
|
|
print(e.name);
|
|
}
|
|
|
|
// Because this function has no formal arguments, the 'arguments' object
|
|
// won't get a special behavior - including also getting no special
|
|
// behavior for "caller" (which is very unintuitive).
|
|
for (i = 0; i < callerPropertyValues.length; i++) {
|
|
arguments.caller = callerPropertyValues[i];
|
|
try {
|
|
val = arguments.caller;
|
|
print(i, typeof val);
|
|
} catch (e) {
|
|
print(i, e.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
function testArgumentsNonStrictWithFormals(whatever) {
|
|
var val;
|
|
var i;
|
|
|
|
print(arguments[1]); // just a test to see 'arguments' is proper
|
|
|
|
// Non-strict arguments has no 'caller' property so we can vary its value.
|
|
try {
|
|
val = arguments.caller;
|
|
print(typeof val);
|
|
} catch (e) {
|
|
print(e.name);
|
|
}
|
|
|
|
// Non-strict arguments has special [[Get]] behavior which throws an error
|
|
// if the value (!) of 'caller' is a strict mode function. However, this
|
|
// only applies if the function referring to 'arguments' has at least one
|
|
// formal parameter.
|
|
for (i = 0; i < callerPropertyValues.length; i++) {
|
|
arguments.caller = callerPropertyValues[i];
|
|
try {
|
|
val = arguments.caller;
|
|
print(i, typeof val);
|
|
} catch (e) {
|
|
print(i, e.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
function testArgumentsStrictNoFormals() {
|
|
'use strict';
|
|
|
|
var val;
|
|
|
|
print(arguments[1]); // just a test to see 'arguments' is proper
|
|
|
|
// This test fails with a TypeError because the 'caller' property of a
|
|
// strict arguments object is a non-writable Thrower, so we can't vary
|
|
// the 'caller' value. This is probably why a strict Arguments object
|
|
// does not have (or need) the special [[Get]] behavior.
|
|
try {
|
|
val = arguments.caller;
|
|
print(typeof val);
|
|
} catch (e) {
|
|
print(e.name);
|
|
}
|
|
}
|
|
|
|
function testArgumentsStrictWithFormals(whatever) {
|
|
'use strict';
|
|
|
|
var val;
|
|
|
|
print(arguments[1]); // just a test to see 'arguments' is proper
|
|
|
|
// Same results as above.
|
|
try {
|
|
val = arguments.caller;
|
|
print(typeof val);
|
|
} catch (e) {
|
|
print(e.name);
|
|
}
|
|
}
|
|
|
|
print('functions');
|
|
try {
|
|
testFunctions();
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|
|
print('non-strict arguments, no formals');
|
|
try {
|
|
testArgumentsNonStrictNoFormals('foo', 'bar', 'quux');
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|
|
print('non-strict arguments, with formals');
|
|
try {
|
|
testArgumentsNonStrictWithFormals('foo', 'bar', 'quux');
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|
|
print('strict arguments, no formals');
|
|
try {
|
|
testArgumentsStrictNoFormals('foo', 'bar', 'quux');
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|
|
print('strict arguments, with formals');
|
|
try {
|
|
testArgumentsStrictWithFormals('foo', 'bar', 'quux');
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|