From c1bddc74d7c07f3f8546891a68d4166315382ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Lang=C3=B3?= Date: Mon, 21 Jan 2019 11:44:52 +0100 Subject: [PATCH] Added new 'jerry_value_instanceof' API function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com --- docs/02.API-REFERENCE.md | 78 ++++++++++++ jerry-core/api/jerry.c | 35 ++++++ .../ecma/operations/ecma-function-object.c | 3 +- jerry-core/include/jerryscript-core.h | 1 + tests/unit-core/test-api-instaceof.c | 118 ++++++++++++++++++ 5 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 tests/unit-core/test-api-instaceof.c diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 77af7c6afb..75267061a2 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -1084,6 +1084,84 @@ jerry_get_global_object (void); Functions to check the type of an API value ([jerry_value_t](#jerry_value_t)). + +## jerry_instanceof + +**Summary** + +Returns whether the given `jerry_value_t` is an instance of the given prototype. + +**Prototype** + +```c +jerry_value_t +jerry_instanceof (const jerry_value_t value, const jerry_value_t prototype); +``` + +- `value` - api value of instance object +- `prototype` - api value of prototype +- return value + - error, if value argument is not an object or prototype argument is not a function + - true, if the specified value is an instance of the given prototype + - false, otherwise + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +static jerry_value_t +my_constructor (const jerry_value_t func_val, + const jerry_value_t this_val, + const jerry_value_t argv[], + const jerry_length_t argc) +{ + return jerry_create_undefined (); +} + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t base_obj = jerry_create_object (); + jerry_value_t constructor = jerry_create_external_function (my_constructor); + + /* External functions does not have a prototype by default, so we need to create one */ + jerry_value_t prototype_str = jerry_create_string ((const jerry_char_t *) ("prototype")); + jerry_release_value (jerry_set_property (constructor, prototype_str, base_obj)); + jerry_release_value (prototype_str); + + /* Construct the instance. */ + jerry_value_t instance_val = jerry_construct_object (constructor, NULL, 0); + + /* Call the API function of 'instanceof'. */ + jerry_value_t is_instance = jerry_instanceof (instance_val, constructor); + if (!jerry_value_is_error (is_instance) + && jerry_get_boolean_value (is_instance) == true) + { + /* ... */ + } + + /* Free all of the jerry values and cleanup the engine. */ + jerry_release_value (base_obj); + jerry_release_value (constructor); + jerry_release_value (instance_val); + jerry_release_value (is_instance); + + jerry_cleanup (); + return 0; +} +``` + +**See also** + +- [jerry_construct_object](#jerry_construct_object) +- [jerry_create_external_function](#jerry_create_external_function) + + ## jerry_value_is_abort **Summary** diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 7b7c7228de..78cbd07d44 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -601,6 +601,41 @@ jerry_get_global_object (void) return ecma_make_object_value (global_obj_p); } /* jerry_get_global_object */ +/** + * Check if the specified value is an instance of the given prototype. + * + * See also ECMA-262 v5.1, 11.8.6 + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return true - if the specified value is an instance of the given prototype + * false - otherwise + * error - if value argument is not an object or prototype argument is not a function. + * + */ +jerry_value_t +jerry_instanceof (const jerry_value_t value, /**< object value */ + const jerry_value_t prototype) /**< prototpye function */ +{ + jerry_assert_api_available (); + + if (ecma_is_value_error_reference (value) + || ecma_is_value_error_reference (prototype)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + + if (!ecma_is_value_object (value) + || !ecma_op_is_callable (prototype)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + + ecma_object_t *proto_obj_p = ecma_get_object_from_value (prototype); + return jerry_return (ecma_op_object_has_instance (proto_obj_p, value)); +} /* jerry_instanceof */ + /** * Check if the specified value is an abort value. * diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 71119971d8..e3dadf5d9c 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -327,7 +327,8 @@ ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_ /** * 15.3.5.3 implementation of [[HasInstance]] for Function objects * - * @return ecma value + * @return true/false - if arguments are valid + * error - otherwise * Returned value must be freed with ecma_free_value */ ecma_value_t diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 1386abaf70..dcc3ddbaca 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -343,6 +343,7 @@ jerry_value_t jerry_get_global_object (void); /** * Checker functions of 'jerry_value_t'. */ +jerry_value_t jerry_instanceof (const jerry_value_t value, const jerry_value_t prototype); bool jerry_value_is_abort (const jerry_value_t value); bool jerry_value_is_array (const jerry_value_t value); bool jerry_value_is_boolean (const jerry_value_t value); diff --git a/tests/unit-core/test-api-instaceof.c b/tests/unit-core/test-api-instaceof.c new file mode 100644 index 0000000000..5b51abaef6 --- /dev/null +++ b/tests/unit-core/test-api-instaceof.c @@ -0,0 +1,118 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" + +#include "test-common.h" + +#define T(lhs, rhs, res) \ + { lhs, rhs, res } + +typedef struct +{ + jerry_value_t lhs; + jerry_value_t rhs; + bool expected; +} test_entry_t; + +static jerry_value_t +my_constructor (const jerry_value_t func_val, /**< function */ + const jerry_value_t this_val, /**< this */ + const jerry_value_t argv[], /**< arguments */ + const jerry_length_t argc) /**< number of arguments */ +{ + (void) func_val; + (void) this_val; + (void) argv; + (void) argc; + return jerry_create_undefined (); +} /* my_constructor */ + +int +main (void) +{ + TEST_INIT (); + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t base_obj = jerry_create_object (); + jerry_value_t constructor = jerry_create_external_function (my_constructor); + + jerry_value_t no_proto_instance_val = jerry_construct_object (constructor, NULL, 0); + + jerry_value_t prototype_str = jerry_create_string ((const jerry_char_t *) "prototype"); + jerry_value_t res = jerry_set_property (constructor, prototype_str, base_obj); + jerry_release_value (prototype_str); + TEST_ASSERT (!jerry_value_is_error (res)); + jerry_release_value (res); + + jerry_value_t instance_val = jerry_construct_object (constructor, NULL, 0); + + jerry_value_t error = jerry_create_error_from_value (base_obj, false); + + test_entry_t bool_tests[] = + { + T (jerry_acquire_value (instance_val), jerry_acquire_value (constructor), true), + T (jerry_acquire_value (no_proto_instance_val), jerry_acquire_value (constructor), false), + T (jerry_acquire_value (base_obj), jerry_acquire_value (constructor), false) + }; + + for (uint32_t idx = 0; idx < sizeof (bool_tests) / sizeof (test_entry_t); idx++) + { + jerry_value_t result = jerry_instanceof (bool_tests[idx].lhs, bool_tests[idx].rhs); + TEST_ASSERT (!jerry_value_is_error (result)); + TEST_ASSERT (jerry_get_boolean_value (result) == bool_tests[idx].expected); + jerry_release_value (bool_tests[idx].lhs); + jerry_release_value (bool_tests[idx].rhs); + jerry_release_value (result); + } + + test_entry_t error_tests[] = + { + T (jerry_acquire_value (constructor), jerry_acquire_value (instance_val), true), + T (jerry_create_undefined (), jerry_acquire_value (constructor), true), + T (jerry_acquire_value (instance_val), jerry_create_undefined (), true), + T (jerry_acquire_value (instance_val), jerry_acquire_value (base_obj), true), + T (jerry_acquire_value (error), jerry_acquire_value (constructor), true), + T (jerry_acquire_value (instance_val), jerry_acquire_value (error), true), + T (jerry_create_string ((const jerry_char_t *) ""), jerry_create_string ((const jerry_char_t *) ""), true), + T (jerry_create_string ((const jerry_char_t *) ""), jerry_create_number (5.0), true), + T (jerry_create_number (5.0), jerry_create_string ((const jerry_char_t *) ""), true), + T (jerry_create_array (1), jerry_create_array (1), true), + T (jerry_create_array (1), jerry_create_object (), true), + T (jerry_create_object (), jerry_create_array (1), true), + T (jerry_create_null (), jerry_create_object (), true), + T (jerry_create_object (), jerry_create_string ((const jerry_char_t *) ""), true) + }; + + for (uint32_t idx = 0; idx < sizeof (error_tests) / sizeof (test_entry_t); idx++) + { + jerry_value_t result = jerry_instanceof (error_tests[idx].lhs, error_tests[idx].rhs); + TEST_ASSERT (jerry_value_is_error (result) == error_tests[idx].expected); + jerry_release_value (error_tests[idx].lhs); + jerry_release_value (error_tests[idx].rhs); + jerry_release_value (result); + } + + jerry_release_value (base_obj); + jerry_release_value (constructor); + jerry_release_value (error); + jerry_release_value (instance_val); + jerry_release_value (no_proto_instance_val); + + jerry_cleanup (); + + return 0; +} /* main */