mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
7 years ago
committed by
GitHub
17 changed files with 384 additions and 58 deletions
@ -0,0 +1,36 @@ |
|||
/*
|
|||
* duk_instanceof() with rhs having @@hasInstance |
|||
*/ |
|||
|
|||
/*===
|
|||
*** test_1 (duk_safe_call) |
|||
hasinst called |
|||
instanceof: 1 |
|||
final top: 2 |
|||
==> rc=0, result='undefined' |
|||
===*/ |
|||
|
|||
static duk_ret_t test_1(duk_context *ctx, void *udata) { |
|||
(void) udata; |
|||
|
|||
/* Function.prototype[@@hasInstance] is not writable or configurable.
|
|||
* To set it, use duk_def_prop() or Object.defineProperty() to avoid |
|||
* the ancestor blocking the write. |
|||
*/ |
|||
duk_eval_string(ctx, "123"); |
|||
duk_eval_string(ctx, "(function foo() {})"); |
|||
duk_push_string(ctx, DUK_WELLKNOWN_SYMBOL("Symbol.hasInstance")); |
|||
duk_eval_string(ctx, "(function hasinst() { print('hasinst called'); return true; })"); |
|||
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE); |
|||
|
|||
/* [ lhs rhs ] */ |
|||
|
|||
printf("instanceof: %d\n", (int) duk_instanceof(ctx, 0, 1)); |
|||
|
|||
printf("final top: %ld\n", (long) duk_get_top(ctx)); |
|||
return 0; |
|||
} |
|||
|
|||
void test(duk_context *ctx) { |
|||
TEST_SAFE_CALL(test_1); |
|||
} |
@ -0,0 +1,181 @@ |
|||
/* |
|||
* instanceof and @@hasInstance |
|||
*/ |
|||
|
|||
/*=== |
|||
- No @@hasInstance case; inherited from Function.prototype |
|||
false |
|||
true |
|||
- Function overrides @@hasInstance |
|||
false |
|||
true |
|||
- Function inherits a non-standard @@hasInstance |
|||
inherited hasInstance true 123 |
|||
true |
|||
inherited hasInstance true [object Object] |
|||
true |
|||
- Function inherits a non-standard @@hasInstance, but function itself also provides an undefined @@hasInstance |
|||
false |
|||
true |
|||
true |
|||
- Same but overriding value is null |
|||
false |
|||
true |
|||
true |
|||
- Same but overriding value is not undefined/null, but also not a callable object |
|||
TypeError |
|||
- Same, plain non-callable object |
|||
TypeError |
|||
- @@hasInstance is a getter with side effects |
|||
@@hasInstance getter |
|||
hasInstance true 123 |
|||
true |
|||
@@hasInstance getter |
|||
hasInstance true [object Object] |
|||
true |
|||
- Function.prototype[@@hasInstance] exists |
|||
true |
|||
true |
|||
false |
|||
function false false false |
|||
- Function.prototype[@@hasInstance] access to OrdinaryHasInstance() |
|||
false |
|||
true |
|||
false |
|||
true |
|||
===*/ |
|||
|
|||
function basicTest() { |
|||
print('- No @@hasInstance case; inherited from Function.prototype'); |
|||
var rhs = function () {}; |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
|
|||
print('- Function overrides @@hasInstance'); |
|||
var rhs = function () {}; |
|||
rhs[Symbol.hasInstance] = function (v) { |
|||
print('hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
|
|||
print('- Function inherits a non-standard @@hasInstance'); |
|||
var rhs = function () {}; |
|||
var o = {}; |
|||
Object.setPrototypeOf(rhs, o); |
|||
o[Symbol.hasInstance] = function (v) { |
|||
print('inherited hasInstance', this === rhs, v); |
|||
return true; |
|||
} |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
|
|||
// In this case we fall back to OrdinaryHasInstance().
|
|||
print('- Function inherits a non-standard @@hasInstance, but function itself also provides an undefined @@hasInstance'); |
|||
var rhs = function () {}; |
|||
var o = {}; |
|||
Object.setPrototypeOf(rhs, o); |
|||
o[Symbol.hasInstance] = function (v) { |
|||
print('undefined hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
rhs[Symbol.hasInstance] = void 0; |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
var inst = new rhs(); |
|||
print(inst instanceof rhs); |
|||
|
|||
// For null value, GetMethod (https://www.ecma-international.org/ecma-262/6.0/#sec-getmethod)
|
|||
// returns 'undefined' for both undefined AND null, so that InstanceofOperator(O, C)
|
|||
// handles them the same in Step 4 of https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator.
|
|||
// In other words, for both undefined and null we must fall back to the
|
|||
// OrdinaryHasInstance() algorithm. V8 treats null and undefined differently
|
|||
// (TypeError for null), Firefox treats them the same.
|
|||
|
|||
// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator
|
|||
// A non-undefined/null value, causes a "not callable" TypeError
|
|||
print('- Same but overriding value is null'); |
|||
var rhs = function () {}; |
|||
var o = {}; |
|||
Object.setPrototypeOf(rhs, o); |
|||
o[Symbol.hasInstance] = function (v) { |
|||
print('null hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
rhs[Symbol.hasInstance] = null; |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
var inst = new rhs(); |
|||
print(inst instanceof rhs); |
|||
|
|||
print('- Same but overriding value is not undefined/null, but also not a callable object'); |
|||
var rhs = function () {}; |
|||
var o = {}; |
|||
Object.setPrototypeOf(rhs, o); |
|||
o[Symbol.hasInstance] = function (v) { |
|||
print('fail hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
try { |
|||
rhs[Symbol.hasInstance] = true; |
|||
print(123 instanceof rhs); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
print('- Same, plain non-callable object'); |
|||
var rhs = function () {}; |
|||
var o = {}; |
|||
Object.setPrototypeOf(rhs, o); |
|||
o[Symbol.hasInstance] = function (v) { |
|||
print('fail hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
try { |
|||
rhs[Symbol.hasInstance] = { plain: true }; |
|||
print(123 instanceof rhs); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
print('- @@hasInstance is a getter with side effects'); |
|||
var rhs = function () {}; |
|||
Object.defineProperty(rhs, Symbol.hasInstance, { |
|||
get: function () { |
|||
print('@@hasInstance getter'); |
|||
return function (v) { |
|||
print('hasInstance', this === rhs, v); |
|||
return 1; |
|||
} |
|||
} |
|||
}); |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
|
|||
print('- Function.prototype[@@hasInstance] exists'); |
|||
print(Symbol.hasInstance in Function.prototype); |
|||
print(Function.prototype[Symbol.hasInstance].call(Error, new RangeError())); |
|||
print(Function.prototype[Symbol.hasInstance].call(Error, new Date())); |
|||
var pd = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance); |
|||
print(typeof pd.value, pd.writable, pd.enumerable, pd.configurable); |
|||
|
|||
// Function.prototype[@@hasInstance] allows direct access to the
|
|||
// ES2015 OrdinaryHasInstance() specification method.
|
|||
print('- Function.prototype[@@hasInstance] access to OrdinaryHasInstance()'); |
|||
var rhs = function () {}; |
|||
rhs[Symbol.hasInstance] = function (v) { |
|||
print('hasInstance', this === rhs, v); |
|||
return 0; |
|||
} |
|||
print(123 instanceof rhs); |
|||
print(Object.create(rhs.prototype) instanceof rhs); |
|||
print(Function.prototype[Symbol.hasInstance].call(rhs, {})); |
|||
print(Function.prototype[Symbol.hasInstance].call(rhs, Object.create(rhs.prototype))); |
|||
} |
|||
|
|||
try { |
|||
basicTest(); |
|||
} catch (e) { |
|||
print(e.stack || e); |
|||
} |
Loading…
Reference in new issue