From cf5e158510eac24cd003b072a52133f616144d99 Mon Sep 17 00:00:00 2001 From: Ilyong Cho Date: Mon, 30 Mar 2015 16:04:49 +0900 Subject: [PATCH 1/2] Implement some Jerry API / jerry_api_call_function() and jerry_api_get_object_field_value() --- .../builtin-objects/ecma-builtin-jerry.cpp | 18 ++ jerry-core/jerry-api.h | 15 +- jerry-core/jerry.cpp | 161 +++++++++++++++++- 3 files changed, 182 insertions(+), 12 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp index d4deb010b..3bff4dcfe 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp @@ -440,6 +440,24 @@ ecma_op_extension_object_get_own_property (ecma_object_t *obj_p, /**< the extens switch (field_p->type) { + case JERRY_API_DATA_TYPE_EMPTY: + { + value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + + break; + } + case JERRY_API_DATA_TYPE_UNDEFINED: + { + value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + + break; + } + case JERRY_API_DATA_TYPE_NULL: + { + value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); + + break; + } case JERRY_API_DATA_TYPE_BOOLEAN: { value = ecma_make_simple_value (field_p->v_bool ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index b546505ec..bb36cd4ab 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -36,6 +36,9 @@ */ typedef enum { + JERRY_API_DATA_TYPE_EMPTY, + JERRY_API_DATA_TYPE_UNDEFINED, + JERRY_API_DATA_TYPE_NULL, JERRY_API_DATA_TYPE_BOOLEAN, /**< bool */ JERRY_API_DATA_TYPE_FLOAT32, /**< 32-bit float */ JERRY_API_DATA_TYPE_FLOAT64, /**< 64-bit float */ @@ -59,7 +62,7 @@ typedef struct ecma_object_t jerry_api_object_t; */ typedef struct { - const jerry_api_data_type_t type; /**< argument data type */ + jerry_api_data_type_t type; /**< argument data type */ union { @@ -70,11 +73,8 @@ typedef struct uint32_t v_uint32; /**< number converted 32-bit unsigned integer */ - union - { - jerry_api_string_t *v_string; /**< pointer to a JS string */ - jerry_api_object_t *v_object; /**< pointer to a JS object */ - }; + jerry_api_string_t *v_string; /**< pointer to a JS string */ + jerry_api_object_t *v_object; /**< pointer to a JS object */ }; } jerry_api_value_t; @@ -98,6 +98,9 @@ bool jerry_api_call_function (jerry_api_object_t *function_object_p, const jerry_api_value_t args_p [], uint32_t args_count); +extern EXTERN_C +jerry_api_object_t* jerry_api_get_global (void); + extern EXTERN_C jerry_api_object_t* jerry_api_create_object (void); diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 7462ffd54..d721b7237 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -14,11 +14,17 @@ */ #include "deserializer.h" +#include "ecma-alloc.h" +#include "ecma-builtins.h" #include "ecma-extension.h" #include "ecma-gc.h" +#include "ecma-function-object.h" +#include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-init-finalize.h" +#include "ecma-objects.h" #include "ecma-objects-general.h" +#include "mem-heap.h" #include "jerry.h" #include "jrt.h" #include "parser.h" @@ -54,6 +60,113 @@ static jerry_flag_t jerry_flags; */ char jerry_extension_characters_buffer [CONFIG_EXTENSION_CHAR_BUFFER_SIZE]; + +static jerry_api_value_t +convert_ecma_value_to_api_value (const ecma_value_t& value) +{ + jerry_api_value_t ret; + if (ecma_is_value_empty (value)) + { + ret.type = JERRY_API_DATA_TYPE_EMPTY; + } + else if (ecma_is_value_undefined (value)) + { + ret.type = JERRY_API_DATA_TYPE_UNDEFINED; + } + else if (ecma_is_value_boolean (value)) + { + ret.type = JERRY_API_DATA_TYPE_BOOLEAN; + ret.v_bool = ecma_is_value_true (value); + } + else if (ecma_is_value_number (value)) + { + ecma_number_t *num = ecma_get_number_from_value(value); + + #if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + + ret.type = JERRY_API_DATA_TYPE_FLOAT32; + ret.v_float32 = *num; + + #elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + + ret.type = JERRY_API_DATA_TYPE_FLOAT64; + ret.v_float64 = *num; + + #endif + } + else if (ecma_is_value_string (value)) + { + ecma_string_t *str = ecma_get_string_from_value(value); + + ret.type = JERRY_API_DATA_TYPE_STRING; + ret.v_string = ecma_copy_or_ref_ecma_string(str); + } + else if (ecma_is_value_object (value)) + { + ecma_object_t *obj = ecma_get_object_from_value(value); + ecma_ref_object(obj); + + ret.type = JERRY_API_DATA_TYPE_OBJECT; + ret.v_object = obj; + } else { + JERRY_UNIMPLEMENTED ("Unsupported type of conversion from ecma_value to api_value"); + } + return ret; +} + + +static ecma_value_t +convert_api_value_to_ecma_value (const jerry_api_value_t& value) +{ + switch (value.type) + { + case JERRY_API_DATA_TYPE_EMPTY: + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + } + case JERRY_API_DATA_TYPE_UNDEFINED: + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + case JERRY_API_DATA_TYPE_NULL: + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); + } + case JERRY_API_DATA_TYPE_BOOLEAN: + { + return ecma_make_simple_value (value.v_bool ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + } + case JERRY_API_DATA_TYPE_FLOAT32: + { + ecma_number_t *num = ecma_alloc_number (); + *num = static_cast (value.v_float32); + return ecma_make_number_value (num); + } + case JERRY_API_DATA_TYPE_FLOAT64: + { + ecma_number_t *num = ecma_alloc_number (); + *num = static_cast (value.v_float64); + return ecma_make_number_value (num); + } + case JERRY_API_DATA_TYPE_UINT32: + { + ecma_number_t *num = ecma_alloc_number (); + *num = static_cast (value.v_uint32); + return ecma_make_number_value (num); + } + case JERRY_API_DATA_TYPE_STRING: + { + return ecma_make_string_value (value.v_string); + } + case JERRY_API_DATA_TYPE_OBJECT: + { + return ecma_make_object_value (value.v_object); + } + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); +} + + /** * Extend Global scope with specified extension object * @@ -160,6 +273,8 @@ jerry_api_release_object (jerry_api_object_t *object_p) /**< pointer acquired th * or is 'undefined' (if retval_p is NULL); * false - otherwise. */ +#include +#include "ecma-helpers.h" bool jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */ jerry_api_value_t *retval_p, /**< place for function's return value (if it is required) @@ -168,13 +283,42 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob * (NULL if arguments number is zero) */ uint32_t args_count) /**< number of the arguments */ { - JERRY_ASSERT (args_count == 0 - || args_p != NULL); + JERRY_ASSERT (args_count == 0 || args_p != NULL); - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS ("API routine is not implemented", - function_object_p, retval_p, args_p, args_count); + MEM_DEFINE_LOCAL_ARRAY(arg_values, args_count, ecma_value_t); + + for (uint32_t i = 0; i < args_count; ++i) { + arg_values[i] = convert_api_value_to_ecma_value (args_p[i]); + } + + ecma_completion_value_t call_result = ecma_op_function_call ( + function_object_p, + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + arg_values, + static_cast (args_count)); + + ecma_value_t val = ecma_get_completion_value_value (call_result); + *retval_p = convert_ecma_value_to_api_value (val); + + MEM_FINALIZE_LOCAL_ARRAY (arg_values); + + return true; } /* jerry_api_call_function */ +/** +* Get global object +* +* Note: +* caller should release the object with jerry_api_release_objc, just when the value becomes unnecessary. +* +* @return pointer to the global object +*/ +jerry_api_object_t* +jerry_api_get_global (void) +{ + return jerry_api_acquire_object (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); +} + /** * Create an object * @@ -240,8 +384,12 @@ jerry_api_get_object_field_value (jerry_api_object_t *object_p, /**< object */ const char *field_name_p, /**< name of the field */ jerry_api_value_t *field_value_p) /**< out: field value, if retrieved successfully */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS ("API routine is not implemented", - object_p, field_name_p, field_value_p); + JERRY_ASSERT(object_p != NULL); + + ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*)field_name_p); + ecma_value_t val = ecma_get_completion_value_value (ecma_op_object_get (object_p, field_name_str_p)); + *field_value_p = convert_ecma_value_to_api_value (val); + return true; } /* jerry_api_get_object_field_value */ /** @@ -261,6 +409,7 @@ jerry_api_set_object_field_value (jerry_api_object_t *object_p, /**< object */ object_p, field_name_p, field_value_p); } /* jerry_api_set_object_field_value */ + /** * Jerry engine initialization */ From 33cfaa73b32d426bff68aea7198665d15dfc768d Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 30 Mar 2015 20:35:58 +0300 Subject: [PATCH 2/2] Implementation of unimplemented Jerry API parts; adding Jerry API unit test based on test prepared by Ilyong. --- CMakeLists.txt | 2 +- .../builtin-objects/ecma-builtin-jerry.cpp | 6 - jerry-core/jerry-api.h | 31 +- jerry-core/jerry.cpp | 427 ++++++++++++------ tests/unit/test_api.cpp | 111 +++++ 5 files changed, 430 insertions(+), 147 deletions(-) create mode 100644 tests/unit/test_api.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 52ab6eccc..2b1981e4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,7 @@ project (Jerry CXX C ASM) set(FLAGS_COMMON_RELEASE "-Os -nostdlib") # Unit tests - set(FLAGS_COMMON_UNITTESTS "-O3 -nodefaultlibs") + set(FLAGS_COMMON_UNITTESTS "-O0 -nodefaultlibs") # Include directories # Core interface diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp index 3bff4dcfe..f023886b5 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-jerry.cpp @@ -440,12 +440,6 @@ ecma_op_extension_object_get_own_property (ecma_object_t *obj_p, /**< the extens switch (field_p->type) { - case JERRY_API_DATA_TYPE_EMPTY: - { - value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - - break; - } case JERRY_API_DATA_TYPE_UNDEFINED: { value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index bb36cd4ab..cbdc9ba13 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -36,9 +36,8 @@ */ typedef enum { - JERRY_API_DATA_TYPE_EMPTY, - JERRY_API_DATA_TYPE_UNDEFINED, - JERRY_API_DATA_TYPE_NULL, + JERRY_API_DATA_TYPE_UNDEFINED, /**< undefined */ + JERRY_API_DATA_TYPE_NULL, /**< null */ JERRY_API_DATA_TYPE_BOOLEAN, /**< bool */ JERRY_API_DATA_TYPE_FLOAT32, /**< 32-bit float */ JERRY_API_DATA_TYPE_FLOAT64, /**< 64-bit float */ @@ -60,7 +59,7 @@ typedef struct ecma_object_t jerry_api_object_t; /** * Description of an extension function's argument */ -typedef struct +typedef struct jerry_api_value_t { jerry_api_data_type_t type; /**< argument data type */ @@ -73,8 +72,11 @@ typedef struct uint32_t v_uint32; /**< number converted 32-bit unsigned integer */ - jerry_api_string_t *v_string; /**< pointer to a JS string */ - jerry_api_object_t *v_object; /**< pointer to a JS object */ + union + { + jerry_api_string_t *v_string; /**< pointer to a JS string */ + jerry_api_object_t *v_object; /**< pointer to a JS object */ + }; }; } jerry_api_value_t; @@ -93,14 +95,10 @@ extern EXTERN_C void jerry_api_release_object (jerry_api_object_t *object_p); extern EXTERN_C -bool jerry_api_call_function (jerry_api_object_t *function_object_p, - jerry_api_value_t *retval_p, - const jerry_api_value_t args_p [], - uint32_t args_count); +void jerry_api_release_value (jerry_api_value_t *value_p); extern EXTERN_C -jerry_api_object_t* jerry_api_get_global (void); - +jerry_api_string_t* jerry_api_create_string (const char *v); extern EXTERN_C jerry_api_object_t* jerry_api_create_object (void); @@ -121,6 +119,15 @@ bool jerry_api_set_object_field_value (jerry_api_object_t *object_p, const char *field_name_p, const jerry_api_value_t *field_value_p); +extern EXTERN_C +bool jerry_api_call_function (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 d721b7237..446f6d1f0 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -17,14 +17,12 @@ #include "ecma-alloc.h" #include "ecma-builtins.h" #include "ecma-extension.h" -#include "ecma-gc.h" #include "ecma-function-object.h" -#include "ecma-globals.h" +#include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-init-finalize.h" #include "ecma-objects.h" #include "ecma-objects-general.h" -#include "mem-heap.h" #include "jerry.h" #include "jrt.h" #include "parser.h" @@ -60,111 +58,150 @@ static jerry_flag_t jerry_flags; */ char jerry_extension_characters_buffer [CONFIG_EXTENSION_CHAR_BUFFER_SIZE]; - -static jerry_api_value_t -convert_ecma_value_to_api_value (const ecma_value_t& value) +/** + * Convert ecma-value to Jerry API value representation + * + * Note: + * if the output value contains string / object, it should be freed + * with jerry_api_release_string / jerry_api_release_object, + * just when it becomes unnecessary. + */ +static void +jerry_api_convert_ecma_value_to_api_value (jerry_api_value_t *out_value_p, /**< out: api value */ + const ecma_value_t& value) /**< ecma-value (undefined, + * null, boolean, number, + * string or object */ { - jerry_api_value_t ret; - if (ecma_is_value_empty (value)) + JERRY_ASSERT (out_value_p != NULL); + + if (ecma_is_value_undefined (value)) { - ret.type = JERRY_API_DATA_TYPE_EMPTY; + out_value_p->type = JERRY_API_DATA_TYPE_UNDEFINED; } - else if (ecma_is_value_undefined (value)) + if (ecma_is_value_null (value)) { - ret.type = JERRY_API_DATA_TYPE_UNDEFINED; + out_value_p->type = JERRY_API_DATA_TYPE_NULL; } else if (ecma_is_value_boolean (value)) { - ret.type = JERRY_API_DATA_TYPE_BOOLEAN; - ret.v_bool = ecma_is_value_true (value); + out_value_p->type = JERRY_API_DATA_TYPE_BOOLEAN; + out_value_p->v_bool = ecma_is_value_true (value); } else if (ecma_is_value_number (value)) { - ecma_number_t *num = ecma_get_number_from_value(value); + ecma_number_t *num = ecma_get_number_from_value (value); - #if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 - - ret.type = JERRY_API_DATA_TYPE_FLOAT32; - ret.v_float32 = *num; - - #elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 - - ret.type = JERRY_API_DATA_TYPE_FLOAT64; - ret.v_float64 = *num; - - #endif +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + out_value_p->type = JERRY_API_DATA_TYPE_FLOAT32; + out_value_p->v_float32 = *num; +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + out_value_p->type = JERRY_API_DATA_TYPE_FLOAT64; + out_value_p->v_float64 = *num; +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ } else if (ecma_is_value_string (value)) { - ecma_string_t *str = ecma_get_string_from_value(value); + ecma_string_t *str = ecma_get_string_from_value (value); - ret.type = JERRY_API_DATA_TYPE_STRING; - ret.v_string = ecma_copy_or_ref_ecma_string(str); + out_value_p->type = JERRY_API_DATA_TYPE_STRING; + out_value_p->v_string = ecma_copy_or_ref_ecma_string (str); } else if (ecma_is_value_object (value)) { - ecma_object_t *obj = ecma_get_object_from_value(value); - ecma_ref_object(obj); + ecma_object_t *obj = ecma_get_object_from_value (value); + ecma_ref_object (obj); - ret.type = JERRY_API_DATA_TYPE_OBJECT; - ret.v_object = obj; - } else { - JERRY_UNIMPLEMENTED ("Unsupported type of conversion from ecma_value to api_value"); + out_value_p->type = JERRY_API_DATA_TYPE_OBJECT; + out_value_p->v_object = obj; } - return ret; -} - - -static ecma_value_t -convert_api_value_to_ecma_value (const jerry_api_value_t& value) -{ - switch (value.type) + else + { + /* Impossible type of conversion from ecma_value to api_value */ + JERRY_UNREACHABLE (); + } +} /* jerry_api_convert_ecma_value_to_api_value */ + +/** + * Convert value, represented in Jerry API format, to ecma-value. + * + * Note: + * the output ecma-value should be freed with ecma_free_value when it becomes unnecessary. + */ +static void +jerry_api_convert_api_value_to_ecma_value (ecma_value_t *out_value_p, /**< out: ecma-value */ + const jerry_api_value_t* api_value_p) /**< value in Jerry API format */ +{ + switch (api_value_p->type) { - case JERRY_API_DATA_TYPE_EMPTY: - { - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - } case JERRY_API_DATA_TYPE_UNDEFINED: { - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + *out_value_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + + break; } case JERRY_API_DATA_TYPE_NULL: { - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); + *out_value_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); + + break; } case JERRY_API_DATA_TYPE_BOOLEAN: { - return ecma_make_simple_value (value.v_bool ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + *out_value_p = ecma_make_simple_value (api_value_p->v_bool ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + + break; } case JERRY_API_DATA_TYPE_FLOAT32: { ecma_number_t *num = ecma_alloc_number (); - *num = static_cast (value.v_float32); - return ecma_make_number_value (num); + *num = static_cast (api_value_p->v_float32); + + *out_value_p = ecma_make_number_value (num); + + break; } case JERRY_API_DATA_TYPE_FLOAT64: { ecma_number_t *num = ecma_alloc_number (); - *num = static_cast (value.v_float64); - return ecma_make_number_value (num); + *num = static_cast (api_value_p->v_float64); + + *out_value_p = ecma_make_number_value (num); + + break; } case JERRY_API_DATA_TYPE_UINT32: { ecma_number_t *num = ecma_alloc_number (); - *num = static_cast (value.v_uint32); - return ecma_make_number_value (num); + *num = static_cast (api_value_p->v_uint32); + + *out_value_p = ecma_make_number_value (num); + + break; } case JERRY_API_DATA_TYPE_STRING: { - return ecma_make_string_value (value.v_string); + ecma_string_t *str_p = ecma_copy_or_ref_ecma_string (api_value_p->v_string); + + *out_value_p = ecma_make_string_value (str_p); + + break; } case JERRY_API_DATA_TYPE_OBJECT: { - return ecma_make_object_value (value.v_object); + ecma_object_t *obj_p = api_value_p->v_object; + + ecma_ref_object (obj_p); + + *out_value_p = ecma_make_object_value (obj_p); + + break; + } + default: + { + JERRY_UNREACHABLE (); } } - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); -} +} /* jerry_api_convert_api_value_to_ecma_value */ /** @@ -259,65 +296,34 @@ jerry_api_release_object (jerry_api_object_t *object_p) /**< pointer acquired th } /* jerry_api_release_object */ /** - * Call function specified by a function object - * - * Note: - * if call was performed successfully and returned value of type string or object, then caller - * should release the string / object with corresponding jerry_api_release_string / jerry_api_release_object, - * just when the value becomes unnecessary. - * - * @return true, if call was performed successfully, i.e.: - * - arguments number equals to the function's length property; - * - no unhandled exceptions were thrown; - * - returned value type is corresponding to one of jerry_api_data_type_t (if retval_p is not NULL) - * or is 'undefined' (if retval_p is NULL); - * false - otherwise. + * Release specified Jerry API value */ -#include -#include "ecma-helpers.h" -bool -jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */ - jerry_api_value_t *retval_p, /**< place for function's return value (if it is required) - * or NULL (if it should be 'undefined') */ - const jerry_api_value_t args_p [], /**< function's call arguments - * (NULL if arguments number is zero) */ - uint32_t args_count) /**< number of the arguments */ +void +jerry_api_release_value (jerry_api_value_t *value_p) /**< API value */ { - JERRY_ASSERT (args_count == 0 || args_p != NULL); - - MEM_DEFINE_LOCAL_ARRAY(arg_values, args_count, ecma_value_t); - - for (uint32_t i = 0; i < args_count; ++i) { - arg_values[i] = convert_api_value_to_ecma_value (args_p[i]); - } - - ecma_completion_value_t call_result = ecma_op_function_call ( - function_object_p, - ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), - arg_values, - static_cast (args_count)); - - ecma_value_t val = ecma_get_completion_value_value (call_result); - *retval_p = convert_ecma_value_to_api_value (val); - - MEM_FINALIZE_LOCAL_ARRAY (arg_values); - - return true; -} /* jerry_api_call_function */ + if (value_p->type == JERRY_API_DATA_TYPE_STRING) + { + jerry_api_release_string (value_p->v_string); + } + else if (value_p->type == JERRY_API_DATA_TYPE_OBJECT) + { + jerry_api_release_object (value_p->v_object); + } +} /* jerry_api_release_value */ /** -* Get global object -* -* Note: -* caller should release the object with jerry_api_release_objc, just when the value becomes unnecessary. -* -* @return pointer to the global object -*/ -jerry_api_object_t* -jerry_api_get_global (void) + * Create a string + * + * Note: + * caller should release the string with jerry_api_release_string, just when the value becomes unnecessary. + * + * @return pointer to created string + */ +jerry_api_string_t* +jerry_api_create_string (const char *v) /**< string value */ { - return jerry_api_acquire_object (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); -} + return ecma_new_ecma_string ((const ecma_char_t*) v); +} /* jerry_api_create_string */ /** * Create an object @@ -347,8 +353,35 @@ jerry_api_add_object_field (jerry_api_object_t *object_p, /**< object to add fie const jerry_api_value_t *field_value_p, /**< value of the field */ bool is_writable) /**< flag indicating whether the created field should be writable */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS ("API routine is not implemented", - object_p, field_name_p, field_value_p, is_writable); + bool is_successful = false; + + if (ecma_get_object_extensible (object_p)) + { + ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*) field_name_p); + + ecma_property_t *prop_p = ecma_op_object_get_own_property (object_p, field_name_str_p); + + if (prop_p == NULL) + { + is_successful = true; + + ecma_value_t value_to_put; + jerry_api_convert_api_value_to_ecma_value (&value_to_put, field_value_p); + + prop_p = ecma_create_named_data_property (object_p, + field_name_str_p, + is_writable, + true, + true); + ecma_named_data_property_assign_value (object_p, prop_p, value_to_put); + + ecma_free_value (value_to_put, true); + } + + ecma_deref_ecma_string (field_name_str_p); + } + + return is_successful; } /* jerry_api_add_object_field */ /** @@ -362,21 +395,37 @@ bool jerry_api_delete_object_field (jerry_api_object_t *object_p, /**< object to delete field at */ const char *field_name_p) /**< name of the field */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS ("API routine is not implemented", - object_p, field_name_p); + bool is_successful = true; + + ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*) field_name_p); + + ecma_completion_value_t delete_completion = ecma_op_object_delete (object_p, + field_name_str_p, + true); + + if (!ecma_is_completion_value_normal (delete_completion)) + { + JERRY_ASSERT (ecma_is_completion_value_throw (delete_completion)); + + is_successful = false; + } + + ecma_free_completion_value (delete_completion); + + ecma_deref_ecma_string (field_name_str_p); + + return is_successful; } /* jerry_api_delete_object_field */ /** * Get value of field in the specified object * * Note: - * if value was retrieved successfully and it is of type string or object, then caller - * should release the string / object with corresponding jerry_api_release_string / jerry_api_release_object, - * just when the value becomes unnecessary. + * if value was retrieved successfully, it should be freed + * with jerry_api_release_value just when it becomes unnecessary. * * @return true, if field value was retrieved successfully, i.e. upon the call: * - there is field with specified name in the object; - * - field value is not undefined nor null; * false - otherwise. */ bool @@ -384,12 +433,31 @@ jerry_api_get_object_field_value (jerry_api_object_t *object_p, /**< object */ const char *field_name_p, /**< name of the field */ jerry_api_value_t *field_value_p) /**< out: field value, if retrieved successfully */ { - JERRY_ASSERT(object_p != NULL); + bool is_successful = true; - ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*)field_name_p); - ecma_value_t val = ecma_get_completion_value_value (ecma_op_object_get (object_p, field_name_str_p)); - *field_value_p = convert_ecma_value_to_api_value (val); - return true; + ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*) field_name_p); + + ecma_completion_value_t get_completion = ecma_op_object_get (object_p, + field_name_str_p); + + if (ecma_is_completion_value_normal (get_completion)) + { + ecma_value_t val = ecma_get_completion_value_value (get_completion); + + jerry_api_convert_ecma_value_to_api_value (field_value_p, val); + } + else + { + JERRY_ASSERT (ecma_is_completion_value_throw (get_completion)); + + is_successful = false; + } + + ecma_free_completion_value (get_completion); + + ecma_deref_ecma_string (field_name_str_p); + + return is_successful; } /* jerry_api_get_object_field_value */ /** @@ -405,10 +473,113 @@ jerry_api_set_object_field_value (jerry_api_object_t *object_p, /**< object */ const char *field_name_p, /**< name of the field */ const jerry_api_value_t *field_value_p) /**< field value to set */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS ("API routine is not implemented", - object_p, field_name_p, field_value_p); + bool is_successful = true; + + ecma_string_t* field_name_str_p = ecma_new_ecma_string ((const ecma_char_t*) field_name_p); + + ecma_value_t value_to_put; + jerry_api_convert_api_value_to_ecma_value (&value_to_put, field_value_p); + + ecma_completion_value_t set_completion = ecma_op_object_put (object_p, + field_name_str_p, + value_to_put, + true); + + if (!ecma_is_completion_value_normal (set_completion)) + { + JERRY_ASSERT (ecma_is_completion_value_throw (set_completion)); + + is_successful = false; + } + + ecma_free_completion_value (set_completion); + + ecma_free_value (value_to_put, true); + ecma_deref_ecma_string (field_name_str_p); + + return is_successful; } /* jerry_api_set_object_field_value */ +/** + * 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.: + * - 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_value_t *retval_p, /**< place for function's return value (if it is required) + * or NULL (if it should be 'undefined') */ + 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)); + + bool is_successful = true; + + MEM_DEFINE_LOCAL_ARRAY (arg_values, args_count, ecma_value_t); + + for (uint32_t i = 0; i < args_count; ++i) + { + jerry_api_convert_api_value_to_ecma_value (&arg_values [i], &args_p [i]); + } + + ecma_completion_value_t call_completion; + + call_completion = ecma_op_function_call (function_object_p, + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + arg_values, + 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 + { + /* unhandled exception during the function call */ + + JERRY_ASSERT (ecma_is_completion_value_throw (call_completion)); + + is_successful = false; + } + + ecma_free_completion_value (call_completion); + + for (uint32_t i = 0; i < args_count; i++) + { + ecma_free_value (arg_values [i], true); + } + + MEM_FINALIZE_LOCAL_ARRAY (arg_values); + + return is_successful; +} /* jerry_api_call_function */ + +/** + * Get global object + * + * Note: + * caller should release the object with jerry_api_release_object, just when the value becomes unnecessary. + * + * @return pointer to the global object + */ +jerry_api_object_t* +jerry_api_get_global (void) +{ + return ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); +} /* jerry_api_get_global */ /** * Jerry engine initialization diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp new file mode 100644 index 000000000..6eb0ce36a --- /dev/null +++ b/tests/unit/test_api.cpp @@ -0,0 +1,111 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include + +#include "jerry.h" +#include "jerry-api.h" + +const char *test_source = "var t = 1;\nfunction f () {\n return t;\n}\nthis.foo = f;\n"; + +/** + * Initialize Jerry API value with specified float64 number + */ +static void +test_api_init_api_value_float64 (jerry_api_value_t *out_value_p, /**< out: API value */ + double v) /**< float64 value to initialize with */ +{ + out_value_p->type = JERRY_API_DATA_TYPE_FLOAT64; + out_value_p->v_float64 = v; +} /* test_api_init_api_value_float64 */ + +/** + * Initialize Jerry API value with specified float64 number + */ +static void +test_api_init_api_value_string (jerry_api_value_t *out_value_p, /**< out: API value */ + const char* v) /**< string value to initialize with */ +{ + out_value_p->type = JERRY_API_DATA_TYPE_STRING; + out_value_p->v_string = jerry_api_create_string (v); +} /* test_api_init_api_value_string */ + +int +main (void) +{ + jerry_init (JERRY_FLAG_EMPTY); + + bool is_ok; + ssize_t sz; + jerry_api_value_t val_t, val_foo; + jerry_api_object_t* global_obj_p; + jerry_api_value_t res, args [2]; + char buffer [16]; + + is_ok = jerry_parse (NULL, test_source, strlen (test_source)); + assert (is_ok); + + is_ok = (jerry_run (NULL) == JERRY_COMPLETION_CODE_OK); + assert (is_ok); + + global_obj_p = jerry_api_get_global (); + + is_ok = jerry_api_get_object_field_value (global_obj_p, "t", &val_t); + assert (is_ok + && val_t.type == JERRY_API_DATA_TYPE_FLOAT64 + && val_t.v_float64 == 1.0); + jerry_api_release_value (&val_t); + + is_ok = jerry_api_get_object_field_value (global_obj_p, "foo", &val_foo); + assert (is_ok + && val_foo.type == JERRY_API_DATA_TYPE_OBJECT); + + test_api_init_api_value_float64 (&args[0], 4); + test_api_init_api_value_float64 (&args[1], 2); + + is_ok = jerry_api_call_function (val_foo.v_object, &res, args, 2); + assert (is_ok + && res.type == JERRY_API_DATA_TYPE_FLOAT64 + && res.v_float64 == 1.0); + jerry_api_release_value (&res); + + test_api_init_api_value_string (&args[0], "abcd"); + is_ok = jerry_api_set_object_field_value (global_obj_p, + "t", + &args[0]); + assert (is_ok); + jerry_api_release_value (&args[0]); + + is_ok = jerry_api_call_function (val_foo.v_object, &res, args, 2); + assert (is_ok + && res.type == JERRY_API_DATA_TYPE_STRING); + sz = jerry_api_string_to_char_buffer (res.v_string, NULL, 0); + assert (sz == -5); + sz = jerry_api_string_to_char_buffer (res.v_string, buffer, -sz); + assert (sz == 5); + jerry_api_release_value (&res); + assert (!strcmp (buffer, "abcd")); + + jerry_api_release_value (&val_foo); + + jerry_api_release_object (global_obj_p); + + jerry_cleanup (); + + return 0; +}