diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c index bbc178413..e4b0c21ae 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.c +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -1224,8 +1224,61 @@ ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */ ecma_length_t argc) /**< number of arguments */ { JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); - JERRY_UNUSED_4 (obj_p, new_target_p, args_p, argc); - return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Construct]]")); + + ecma_proxy_object_t * proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_CONSTRUCT); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + JERRY_ASSERT (ecma_object_is_constructor (target_obj_p)); + + return ecma_op_function_construct (target_obj_p, new_target_p, args_p, argc); + } + + /* 8. */ + ecma_value_t arg_array = ecma_op_create_array_object (args_p, argc, false); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t new_target_value = ecma_make_object_value (new_target_p); + ecma_value_t function_call_args[] = {target, arg_array, new_target_value}; + + /* 9. */ + ecma_value_t new_obj = ecma_op_function_call (func_obj_p, handler, function_call_args, 3); + + ecma_free_value (arg_array); + ecma_deref_object (func_obj_p); + + /* 10 .*/ + if (ECMA_IS_VALUE_ERROR (new_obj)) + { + return new_obj; + } + + /* 11. */ + if (!ecma_is_value_object (new_obj)) + { + ecma_free_value (new_obj); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned non-object")); + } + + /* 12. */ + return new_obj; } /* ecma_proxy_object_construct */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index f01f173f2..d37f261f1 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -589,7 +589,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TYPE_ERROR_UL, "TypeError") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNDEFINED_UL, "Undefined") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__PROTO__, "__proto__") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARGUMENTS, "arguments") -#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONSTRUCT, "construct") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DECODE_URI, "decodeURI") diff --git a/tests/jerry/es2015/proxy_construct.js b/tests/jerry/es2015/proxy_construct.js index 1df33e352..46ff8e0b4 100644 --- a/tests/jerry/es2015/proxy_construct.js +++ b/tests/jerry/es2015/proxy_construct.js @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Update these tests when the internal routine has been implemented +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. var target = function () {}; var handler = { construct (target) { @@ -26,13 +28,138 @@ try { new proxy(5) assert(false); } catch (e) { - assert(e instanceof TypeError); + assert(e === 42); } try { // 22.1.2.3.4.a Array.of.call(proxy); assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic functionality +var proxy = new Proxy({},{}); + +try { + new proxy(); + assert(false); } catch (e) { assert(e instanceof TypeError); } + +var proxy2 = new Proxy(proxy, {}); + +try { + new proxy2(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var called = false; + +function Target() { + called = true; + this.property1 = 'value1'; +}; + +Target.prototype = {}; +var proxy = new Proxy(Target, {}); + +assert(called === false); + +var instance = new proxy(); + +assert(called === true); +assert('value1' === instance.property1); +assert(Target.prototype === Object.getPrototypeOf(instance)); + +var proxy2 = new Proxy(proxy, {}); +called = false; +var instance2 = new proxy2(); + +assert(called === true); +assert('value1' === instance2.property1); +assert(Target.prototype === Object.getPrototypeOf(instance)); + +function Target2(a, b) { + this.sum = a + b; +}; +var handler = { + construct(t, c, args) { + return { sum: 42 }; + } +}; +var proxy = new Proxy(Target2, handler); +assert((new proxy(1, 2)).sum === 42); + +function Target3(arg1, arg2) { + this.arg1 = arg1; + this.arg2 = arg2; +} +var seen_target, seen_arguments, seen_new_target; +var handler = { + construct(target, args, new_target) { + seen_target = target; + seen_arguments = args; + seen_new_target = new_target; + return Reflect.construct(target, args, new_target); + } +} +var proxy = new Proxy(Target3, handler); +var instance = new proxy('a', 'b'); + +assert(Target3 === seen_target); +assert(JSON.stringify(seen_arguments) === '["a","b"]'); +assert(proxy === seen_new_target); +assert('a' === instance.arg1); +assert('b' === instance.arg2); + +var instance2 = Reflect.construct(proxy, ['a1', 'b1'], Array); +assert(Target3 === seen_target); +assert(JSON.stringify(seen_arguments) === '["a1","b1"]'); +assert(Array === seen_new_target); +assert('a1'=== instance2.arg1); +assert('b1' === instance2.arg2); + +var p = new Proxy(function() {}, { + construct: function(target, argumentsList, newTarget) { + throw 42; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test when invariants gets violated +var p = new Proxy(function() {}, { + construct: function(target, argumentsList, newTarget) { + return 1; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var p = new Proxy({}, { + construct: function(target, argumentsList, newTarget) { + return {}; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_define_own_property.js b/tests/jerry/es2015/proxy_define_own_property.js index d4d8157d9..ebb34fbd5 100644 --- a/tests/jerry/es2015/proxy_define_own_property.js +++ b/tests/jerry/es2015/proxy_define_own_property.js @@ -23,10 +23,5 @@ var handler = { defineProperty (target) { var proxy = new Proxy(target, handler); -try { - // 22.1.2.3.8.c - Array.of.call(proxy, 5) - assert(false); -} catch (e) { - assert(e instanceof TypeError); -} +// 22.1.2.3.8.c +Array.of.call(proxy, 5)