From c55617c7b9bc9e22272463be5fc74e4428f70d0c 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 'instanceof' binary operation to the API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added 'JERRY_BIN_OP_INSTANCEOF' to 'jerry_binary_operation_t' and 'jerry_binary_operation'. Added unit tests for this new operation and updated the documentations. JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com --- docs/02.API-REFERENCE.md | 57 +++++++- jerry-core/api/jerry.c | 11 ++ .../ecma/operations/ecma-function-object.c | 3 +- jerry-core/include/jerryscript-core.h | 13 +- ... test-api-binary-operations-comparisons.c} | 0 .../test-api-binary-operations-instanceof.c | 122 ++++++++++++++++++ 6 files changed, 198 insertions(+), 8 deletions(-) rename tests/unit-core/{test-api-binary-operations.c => test-api-binary-operations-comparisons.c} (100%) create mode 100644 tests/unit-core/test-api-binary-operations-instanceof.c diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index d3d80c0e14..28b9bda6fe 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -286,6 +286,7 @@ Enum that contains the supported binary operation types - JERRY_BIN_OP_LESS_EQUAL - less or equal relation (<=) - JERRY_BIN_OP_GREATER - greater relation (>) - JERRY_BIN_OP_GREATER_EQUAL - greater or equal relation (>=) + - JERRY_BIN_OP_INSTANCEOF - instanceof operation ## jerry_property_descriptor_t @@ -1092,6 +1093,7 @@ jerry_get_global_object (void); - [jerry_release_value](#jerry_release_value) - [jerry_define_own_property](#jerry_define_own_property) + # Checker functions Functions to check the type of an API value ([jerry_value_t](#jerry_value_t)). @@ -1741,7 +1743,7 @@ jerry_binary_operation (jerry_binary_operation_t op, - error, if argument has an error flag or operation is unsuccessful or unsupported - true/false, the result of the binary operation on the given operands otherwise -**Example** +**Example - JERRY_BIN_OP_EQUAL** ```c { @@ -1772,6 +1774,59 @@ jerry_binary_operation (jerry_binary_operation_t op, } ``` +**Example - JERRY_BIN_OP_INSTANCEOF** + +[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_binary_operation (JERRY_BIN_OP_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_binary_operation_t](#jerry_binary_operation_t) diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 736daf710c..2e3f21f6ca 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -947,6 +947,17 @@ jerry_binary_operation (jerry_binary_operation_t op, /**< operation */ { return jerry_return (opfunc_relation (lhs, rhs, true, true)); } + case JERRY_BIN_OP_INSTANCEOF: + { + if (!ecma_is_value_object (lhs) + || !ecma_op_is_callable (rhs)) + { + 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 (rhs); + return jerry_return (ecma_op_object_has_instance (proto_obj_p, lhs)); + } default: { return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Unsupported binary operation"))); diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 13f944fdcb..301b50753a 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -391,7 +391,8 @@ ecma_op_implicit_class_constructor_has_instance (ecma_object_t *func_obj_p, /**< /** * 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 c74ae5ee45..91b910b3fb 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -313,12 +313,13 @@ typedef struct jerry_context_t jerry_context_t; */ typedef enum { - JERRY_BIN_OP_EQUAL = 0u, /**< equal comparison (==) */ - JERRY_BIN_OP_STRICT_EQUAL, /**< strict equal comparison (===) */ - JERRY_BIN_OP_LESS, /**< less relation (<) */ - JERRY_BIN_OP_LESS_EQUAL, /**< less or equal relation (<=) */ - JERRY_BIN_OP_GREATER, /**< greater relation (>) */ - JERRY_BIN_OP_GREATER_EQUAL /**< greater or equal relation (>=)*/ + JERRY_BIN_OP_EQUAL = 0u, /**< equal comparison (==) */ + JERRY_BIN_OP_STRICT_EQUAL, /**< strict equal comparison (===) */ + JERRY_BIN_OP_LESS, /**< less relation (<) */ + JERRY_BIN_OP_LESS_EQUAL, /**< less or equal relation (<=) */ + JERRY_BIN_OP_GREATER, /**< greater relation (>) */ + JERRY_BIN_OP_GREATER_EQUAL, /**< greater or equal relation (>=)*/ + JERRY_BIN_OP_INSTANCEOF, /**< instanceof operation */ } jerry_binary_operation_t; /** diff --git a/tests/unit-core/test-api-binary-operations.c b/tests/unit-core/test-api-binary-operations-comparisons.c similarity index 100% rename from tests/unit-core/test-api-binary-operations.c rename to tests/unit-core/test-api-binary-operations-comparisons.c diff --git a/tests/unit-core/test-api-binary-operations-instanceof.c b/tests/unit-core/test-api-binary-operations-instanceof.c new file mode 100644 index 0000000000..00a099ee19 --- /dev/null +++ b/tests/unit-core/test-api-binary-operations-instanceof.c @@ -0,0 +1,122 @@ +/* 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_binary_operation (JERRY_BIN_OP_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_binary_operation (JERRY_BIN_OP_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 */