diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index ed285257c..2c013c62d 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -149,6 +149,12 @@ bool jerry_api_call_function (jerry_api_object_t *function_object_p, const jerry_api_value_t args_p [], uint16_t args_count); +extern EXTERN_C +bool jerry_api_construct_object (jerry_api_object_t *function_object_p, + jerry_api_value_t *retval_p, + const jerry_api_value_t args_p [], + uint16_t args_count); + extern EXTERN_C jerry_api_object_t* jerry_api_get_global (void); diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index da65ea91a..a004403c1 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -652,25 +652,35 @@ jerry_api_set_object_native_handle (jerry_api_object_t *object_p, /**< object to } /* jerry_api_set_object_native_handle */ /** - * Call function specified by a function object + * Invoke function specified by a function object * * Note: - * if call was performed successfully, returned value should be freed + * if invocation was performed successfully, returned value should be freed * with jerry_api_release_value just when the value becomes unnecessary. * - * @return true, if call was performed successfully, i.e.: + * Note: + * If function is invoked as constructor, it should support [[Construct]] method, + * otherwise, if function is simply called - it should support [[Call]] method. + * + * @return true, if invocation was performed successfully, i.e.: * - no unhandled exceptions were thrown in connection with the call; * false - otherwise. */ -bool -jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */ - jerry_api_object_t *this_arg_p, /**< this arg for this binding - * or NULL (set this binding to the global object) */ - jerry_api_value_t *retval_p, /**< pointer to place for function's return value - * or NULL (to ignore the return value) */ - const jerry_api_value_t args_p [], /**< function's call arguments - * (NULL if arguments number is zero) */ - uint16_t args_count) /**< number of the arguments */ +static bool +jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke function as constructor + * (this_arg_p should be NULL, as it is ignored), + * false - perform function call */ + jerry_api_object_t *function_object_p, /**< function object to call */ + jerry_api_object_t *this_arg_p, /**< object for 'this' binding + * or NULL (set 'this' binding to newly constructed object, + * if function is invoked as constructor; + * in case of simple function call set 'this' + * binding to the global object) */ + jerry_api_value_t *retval_p, /**< pointer to place for function's return value + * or NULL (to ignore the return value) */ + const jerry_api_value_t args_p [], /**< function's call arguments + * (NULL if arguments number is zero) */ + uint16_t args_count) /**< number of the arguments */ { JERRY_ASSERT (args_count == 0 || args_p != NULL); JERRY_STATIC_ASSERT (sizeof (args_count) == sizeof (ecma_length_t)); @@ -686,21 +696,35 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob ecma_completion_value_t call_completion; - ecma_value_t this_arg_val; - - if (this_arg_p == NULL) + if (is_invoke_as_constructor) { - this_arg_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + JERRY_ASSERT (this_arg_p == NULL); + JERRY_ASSERT (jerry_api_is_constructor (function_object_p)); + + call_completion = ecma_op_function_construct (function_object_p, + arg_values, + args_count); } else { - this_arg_val = ecma_make_object_value (this_arg_p); - } + JERRY_ASSERT (jerry_api_is_function (function_object_p)); - call_completion = ecma_op_function_call (function_object_p, - this_arg_val, - arg_values, - args_count); + ecma_value_t this_arg_val; + + if (this_arg_p == NULL) + { + this_arg_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + this_arg_val = ecma_make_object_value (this_arg_p); + } + + call_completion = ecma_op_function_call (function_object_p, + this_arg_val, + arg_values, + args_count); + } if (ecma_is_completion_value_normal (call_completion)) { @@ -716,6 +740,11 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob JERRY_ASSERT (ecma_is_completion_value_throw (call_completion)); + if (retval_p != NULL) + { + jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); + } + is_successful = false; } @@ -729,8 +758,69 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob MEM_FINALIZE_LOCAL_ARRAY (arg_values); return is_successful; +} /* jerry_api_invoke_function */ + +/** + * Call function specified by a function object + * + * Note: + * if call was performed successfully, returned value should be freed + * with jerry_api_release_value just when the value becomes unnecessary. + * + * @return true, if call was performed successfully, i.e.: + * - specified object is a function object (see also jerry_api_is_function); + * - no unhandled exceptions were thrown in connection with the call; + * false - otherwise. + */ +bool +jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */ + jerry_api_object_t *this_arg_p, /**< object for 'this' binding + * or NULL (set 'this' binding to the global object) */ + jerry_api_value_t *retval_p, /**< pointer to place for function's return value + * or NULL (to ignore the return value) */ + const jerry_api_value_t args_p [], /**< function's call arguments + * (NULL if arguments number is zero) */ + uint16_t args_count) /**< number of the arguments */ +{ + if (jerry_api_is_function (function_object_p)) + { + return jerry_api_invoke_function (false, function_object_p, this_arg_p, retval_p, args_p, args_count); + } + { + return false; + } } /* jerry_api_call_function */ +/** + * Construct object invoking specified function object as a constructor + * + * Note: + * if construction was performed successfully, returned value should be freed + * with jerry_api_release_value just when the value becomes unnecessary. + * + * @return true, if construction was performed successfully, i.e.: + * - specified object is a constructor function object (see also jerry_api_is_constructor); + * - no unhandled exceptions were thrown in connection with the invocation; + * false - otherwise. + */ +bool +jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function object to call */ + jerry_api_value_t *retval_p, /**< pointer to place for function's return value + * or NULL (to ignore the return value) */ + const jerry_api_value_t args_p [], /**< function's call arguments + * (NULL if arguments number is zero) */ + uint16_t args_count) /**< number of the arguments */ +{ + if (jerry_api_is_constructor (function_object_p)) + { + return jerry_api_invoke_function (true, function_object_p, NULL, retval_p, args_p, args_count); + } + else + { + return false; + } +} /* jerry_api_construct_object */ + /** * Get global object * diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index fc0000ce2..869edc9f8 100644 --- a/tests/unit/test_api.cpp +++ b/tests/unit/test_api.cpp @@ -38,11 +38,19 @@ const char *test_source = ( "function call_external () {" " return this.external ('1', true);" "}" - "function call_external_construct () {" - " return new external_construct (true);" - "}" ); +/** + * Initialize Jerry API value with specified boolean value + */ +static void +test_api_init_api_value_bool (jerry_api_value_t *out_value_p, /**< out: API value */ + bool v) /**< boolean value to initialize with */ +{ + out_value_p->type = JERRY_API_DATA_TYPE_BOOLEAN; + out_value_p->v_bool = v; +} /* test_api_init_api_value_bool */ + /** * Initialize Jerry API value with specified float64 number */ @@ -138,7 +146,7 @@ main (void) bool is_ok; ssize_t sz; jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo, val_value_field; - jerry_api_value_t val_external, val_external_construct, val_call_external, val_call_external_construct; + jerry_api_value_t val_external, val_external_construct, val_call_external; jerry_api_object_t* global_obj_p; jerry_api_object_t* external_func_p, *external_construct_p; jerry_api_value_t res, args [2]; @@ -303,15 +311,9 @@ main (void) jerry_api_release_value (&val_external_construct); jerry_api_release_object (external_construct_p); - // Call 'call_external_construct' function that should call external function created above, as constructor - is_ok = jerry_api_get_object_field_value (global_obj_p, "call_external_construct", &val_call_external_construct); - assert (is_ok - && val_call_external_construct.type == JERRY_API_DATA_TYPE_OBJECT); - is_ok = jerry_api_call_function (val_call_external_construct.v_object, - global_obj_p, - &res, - NULL, 0); - jerry_api_release_value (&val_call_external_construct); + // Call external function created above, as constructor + test_api_init_api_value_bool (&args[0], true); + is_ok = jerry_api_construct_object (external_construct_p, &res, args, 1); assert (is_ok && res.type == JERRY_API_DATA_TYPE_OBJECT); is_ok = jerry_api_get_object_field_value (res.v_object,