Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update API for invocation of functions and constructors #188

Merged
merged 1 commit into from
Jun 17, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 54 additions & 29 deletions jerry-core/jerry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -879,8 +879,8 @@ jerry_api_set_object_native_handle (jerry_api_object_t *object_p, /**< object to
* Invoke function specified by a function object
*
* Note:
* if invocation was performed successfully, returned value should be freed
* with jerry_api_release_value just when the value becomes unnecessary.
* returned value should be freed with jerry_api_release_value
* just when the value becomes unnecessary.
*
* Note:
* If function is invoked as constructor, it should support [[Construct]] method,
Expand All @@ -900,8 +900,9 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
* 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) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
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 */
Expand Down Expand Up @@ -950,28 +951,20 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
args_count);
}

if (ecma_is_completion_value_normal (call_completion))
{
if (retval_p != NULL)
{
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (call_completion));
}
}
else
if (!ecma_is_completion_value_normal (call_completion))
{
/* unhandled exception during the function call */

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;
}

if (retval_p != NULL)
{
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (call_completion));
}

ecma_free_completion_value (call_completion);

for (uint32_t i = 0; i < args_count; i++)
Expand All @@ -984,24 +977,42 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
return is_successful;
} /* jerry_api_invoke_function */

/**
* Construct new TypeError object
*/
static void
jerry_api_construct_type_error (jerry_api_value_t *retval_p) /**< out: value with constructed
* TypeError object */
{
ecma_object_t *type_error_obj_p = ecma_new_standard_error (ECMA_ERROR_TYPE);
ecma_value_t type_error_value = ecma_make_object_value (type_error_obj_p);

jerry_api_convert_ecma_value_to_api_value (retval_p, type_error_value);

ecma_deref_object (type_error_obj_p);
} /* jerry_api_construct_type_error */

/**
* 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.
* 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.
* false - otherwise, 'retval_p' contains thrown exception:
* if called object is not function object - a TypeError instance;
* else - exception, thrown during the function call.
*/
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) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
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 */
Expand All @@ -1012,7 +1023,13 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob
{
return jerry_api_invoke_function (false, function_object_p, this_arg_p, retval_p, args_p, args_count);
}
else
{
if (retval_p != NULL)
{
jerry_api_construct_type_error (retval_p);
}

return false;
}
} /* jerry_api_call_function */
Expand All @@ -1021,18 +1038,21 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob
* 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.
* 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.
* false - otherwise, 'retval_p' contains thrown exception:
* if specified object is not a constructor function object - a TypeError instance;
* else - exception, thrown during the invocation.
*/
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) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
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 */
Expand All @@ -1045,6 +1065,11 @@ jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function
}
else
{
if (retval_p != NULL)
{
jerry_api_construct_type_error (retval_p);
}

return false;
}
} /* jerry_api_construct_object */
Expand Down
72 changes: 70 additions & 2 deletions tests/unit/test-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const char *test_source = (
" } "
" assert(catched); "
"} "
"function throw_reference_error() { "
" throw new ReferenceError ();"
"} "
);

bool test_api_is_free_callback_was_called = false;
Expand Down Expand Up @@ -222,11 +225,11 @@ main (void)

jerry_init (JERRY_FLAG_EMPTY);

bool is_ok;
bool is_ok, is_exception;
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;
jerry_api_object_t* global_obj_p;
jerry_api_object_t* global_obj_p, *obj_p;
jerry_api_object_t* external_func_p, *external_construct_p;
jerry_api_object_t* throw_test_handler_p;
jerry_api_value_t res, args[2];
Expand Down Expand Up @@ -437,6 +440,71 @@ main (void)
jerry_api_release_value (&val_t);
jerry_api_release_value (&res);

// Test: Unhandled exception in called function
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
JERRY_ASSERT (is_ok
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);

is_ok = jerry_api_call_function (val_t.v_object,
global_obj_p,
&res,
NULL, 0);
is_exception = !is_ok;

JERRY_ASSERT (is_exception);
jerry_api_release_value (&val_t);

// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);

// Test: Call of non-function
obj_p = jerry_api_create_object ();
is_ok = jerry_api_call_function (obj_p,
global_obj_p,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);

// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);

jerry_api_release_object (obj_p);

// Test: Unhandled exception in function called, as constructor
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
JERRY_ASSERT (is_ok
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);

is_ok = jerry_api_construct_object (val_t.v_object,
&res,
NULL, 0);
is_exception = !is_ok;

JERRY_ASSERT (is_exception);
jerry_api_release_value (&val_t);

// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);

// Test: Call of non-function as constructor
obj_p = jerry_api_create_object ();
is_ok = jerry_api_construct_object (obj_p,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);

// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);

jerry_api_release_object (obj_p);

// Test: eval
const char *eval_code_src_p = "(function () { return 123; })";
jerry_completion_code_t status = jerry_api_eval (eval_code_src_p,
strlen (eval_code_src_p),
Expand Down