From ece246ef9e003f6365fa4828e945bba4d04d4168 Mon Sep 17 00:00:00 2001 From: "pius.lee" Date: Fri, 2 Oct 2015 10:06:36 +0900 Subject: [PATCH] Add foreach function for inquiry properties into obj JerryScript-DCO-1.0-Signed-off-by: pius.lee pius.lee@samsung.com --- jerry-core/jerry-api.h | 10 +++++ jerry-core/jerry.cpp | 58 ++++++++++++++++++++++++ tests/unit/test-api.cpp | 97 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 164 insertions(+), 1 deletion(-) diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index 249b2a810..a026e4e65 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -140,6 +140,13 @@ typedef bool (*jerry_external_handler_t) (const jerry_api_object_t *function_obj */ typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p); +/** + * function type applied for each fields in objects + */ +typedef bool (*jerry_object_field_foreach_t) (const jerry_api_string_t *field_name_p, + const jerry_api_value_t *field_value_p, + void *user_data_p); + extern EXTERN_C ssize_t jerry_api_string_to_char_buffer (const jerry_api_string_t *, jerry_api_char_t *, ssize_t); extern EXTERN_C @@ -200,6 +207,9 @@ extern EXTERN_C bool jerry_api_set_object_field_value_sz (jerry_api_object_t *, const jerry_api_char_t *, jerry_api_size_t, const jerry_api_value_t *); +extern EXTERN_C +bool jerry_api_foreach_object_field (jerry_api_object_t *, jerry_object_field_foreach_t, void *); + extern EXTERN_C bool jerry_api_get_object_native_handle (jerry_api_object_t *, uintptr_t *); diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 11a482ae4..acd977230 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -26,6 +26,7 @@ #include "ecma-init-finalize.h" #include "ecma-objects.h" #include "ecma-objects-general.h" +#include "ecma-try-catch-macro.h" #include "lit-magic-strings.h" #include "parser.h" #include "serializer.h" @@ -898,6 +899,63 @@ bool jerry_api_get_object_field_value (jerry_api_object_t *object_p, field_value_p); } +/** + * Applies the given function to the every fields in the objects + * + * @return true, if object fields traversal was performed successfully, i.e.: + * - no unhandled exceptions were thrown in object fields traversal; + * - object fields traversal was stopped on callback that returned false; + * false - otherwise, + * if getter of field threw a exception or unhandled exceptions were thrown during traversal; + */ +bool +jerry_api_foreach_object_field (jerry_api_object_t *object_p, /**< object */ + jerry_object_field_foreach_t foreach_p, /**< foreach function */ + void *user_data_p) /**< user data for foreach function */ +{ + jerry_assert_api_available (); + + ecma_collection_iterator_t names_iter; + ecma_collection_header_t *names_p = ecma_op_object_get_property_names (object_p, false, true, true); + ecma_collection_iterator_init (&names_iter, names_p); + + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + bool continuous = true; + + while (ecma_is_completion_value_empty (ret_value) + && continuous + && ecma_collection_iterator_next (&names_iter)) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (*names_iter.current_value_p); + + ECMA_TRY_CATCH (property_value, ecma_op_object_get (object_p, property_name_p), ret_value); + + jerry_api_value_t field_value; + jerry_api_convert_ecma_value_to_api_value (&field_value, property_value); + + continuous = foreach_p (property_name_p, &field_value, user_data_p); + + jerry_api_release_value (&field_value); + + ECMA_FINALIZE (property_value); + } + + ecma_free_values_collection (names_p, true); + if (ecma_is_completion_value_empty (ret_value)) + { + return true; + } + else + { + JERRY_ASSERT (ecma_is_completion_value_throw (ret_value)); + + ecma_free_completion_value (ret_value); + + return false; + } +} /* jerry_api_foreach_object_field */ + /** * Get value of field in the specified object * diff --git a/tests/unit/test-api.cpp b/tests/unit/test-api.cpp index 9f29de8d9..343ba4664 100644 --- a/tests/unit/test-api.cpp +++ b/tests/unit/test-api.cpp @@ -15,6 +15,7 @@ #include "jerry.h" #include "jerry-api.h" +#include "config.h" #include "test-common.h" @@ -54,6 +55,9 @@ const char *test_source = ( "function throw_reference_error() { " " throw new ReferenceError ();" "} " + "p = {'alpha':32, 'bravo':false, 'charlie':{}, 'delta':123.45, 'echo':'foobar'};" + "np = {}; Object.defineProperty (np, 'foxtrot', { " + "get: function() { throw 'error'; }, enumerable: true }) " ); bool test_api_is_free_callback_was_called = false; @@ -231,8 +235,81 @@ const jerry_api_char_ptr_t magic_string_items[] = #undef JERRY_MAGIC_STRING_DEF }; +static bool foreach (const jerry_api_string_t *name, + const jerry_api_value_t *value, void *user_data) +{ + char str_buf_p[128]; + ssize_t sz = jerry_api_string_to_char_buffer (name, (jerry_api_char_t *)str_buf_p, 128); + str_buf_p[sz] = '\0'; + if (!strncmp (str_buf_p, "alpha", (size_t)sz)) + { +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_FLOAT32); + JERRY_ASSERT (value->v_float32 == 32.0f); +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_FLOAT64); + JERRY_ASSERT (value->v_float64 == 32.0); +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ + } + else if (!strncmp (str_buf_p, "bravo", (size_t)sz)) + { + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_BOOLEAN); + JERRY_ASSERT (value->v_bool == false); + } + else if (!strncmp (str_buf_p, "charlie", (size_t)sz)) + { + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_OBJECT); + } + else if (!strncmp (str_buf_p, "delta", (size_t)sz)) + { +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_FLOAT32); + JERRY_ASSERT (value->v_float32 == 123.45f); +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_FLOAT64); + JERRY_ASSERT (value->v_float64 == 123.45); +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ + } + else if (!strncmp (str_buf_p, "echo", (size_t)sz)) + { + JERRY_ASSERT (value->type == JERRY_API_DATA_TYPE_STRING); + ssize_t echo_sz = jerry_api_string_to_char_buffer (value->v_string, (jerry_api_char_t *)str_buf_p, 128); + str_buf_p[echo_sz] = '\0'; + JERRY_ASSERT (!strncmp (str_buf_p, "foobar", (size_t)echo_sz)); + } + else + { + JERRY_ASSERT (false); + } + JERRY_ASSERT (!strncmp ((const char*)user_data, "user_data", 9)); + return true; +} + +static bool foreach_exception (const jerry_api_string_t *name, const jerry_api_value_t *, void *) +{ + char str_buf_p[128]; + ssize_t sz = jerry_api_string_to_char_buffer (name, (jerry_api_char_t *)str_buf_p, 128); + str_buf_p[sz] = '\0'; + + if (!strncmp (str_buf_p, "foxtrot", (size_t)sz)) + { + JERRY_ASSERT (false); + } + return true; +} + +static bool foreach_subset (const jerry_api_string_t *, const jerry_api_value_t *, void *user_data) +{ + int *count_p = reinterpret_cast(user_data); + if (*count_p == 3) + { + return false; + } + (*count_p)++; + return true; +} int main (void) { @@ -242,7 +319,7 @@ main (void) 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_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo, val_value_field, val_p, val_np; jerry_api_value_t val_external, val_external_construct, val_call_external; jerry_api_object_t* global_obj_p, *obj_p; jerry_api_object_t* external_func_p, *external_construct_p; @@ -352,6 +429,24 @@ main (void) && res.v_float64 == 12.0); jerry_api_release_value (&res); + // foreach properties + jerry_api_get_object_field_value (global_obj_p, (jerry_api_char_t *) "p", &val_p); + is_ok = jerry_api_foreach_object_field (val_p.v_object, foreach, (void*)"user_data"); + JERRY_ASSERT (is_ok); + + // break foreach at third element + int count = 0; + is_ok = jerry_api_foreach_object_field (val_p.v_object, foreach_subset, &count); + JERRY_ASSERT (is_ok); + JERRY_ASSERT (count == 3); + jerry_api_release_value (&val_p); + + // foreach with throw test + jerry_api_get_object_field_value (global_obj_p, (jerry_api_char_t *) "np", &val_np); + is_ok = !jerry_api_foreach_object_field (val_np.v_object, foreach_exception, NULL); + JERRY_ASSERT (is_ok); + jerry_api_release_value (&val_np); + // Get a.foo is_ok = jerry_api_get_object_field_value (val_a.v_object, (jerry_api_char_t *) "foo", &val_a_foo); JERRY_ASSERT (is_ok