From c8a16f2107f7b47b768a9da8e949a16c707f4e03 Mon Sep 17 00:00:00 2001 From: Peter Gal Date: Fri, 10 Jul 2015 15:29:43 +0200 Subject: [PATCH] Improve Function constructor argument handling. For the Function constructor it is possible to pass the name of the function arguments in one or more strings, and each argument name should be separated with a comma. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com --- .../builtin-objects/ecma-builtin-function.cpp | 146 ++++++++++++++++-- tests/jerry/function-construct.js | 9 ++ 2 files changed, 143 insertions(+), 12 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp index 3fba8e3f2..3da362c78 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp @@ -55,6 +55,86 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**< return ecma_builtin_function_dispatch_construct (arguments_list_p, arguments_list_len); } /* ecma_builtin_function_dispatch_call */ +/** + * Helper method to count and convert the arguments for the Function constructor call. + * + * Performs the operation described in ECMA 262 v5.1 15.3.2.1 steps 5.a-d + * + * + * @return completion value - concatenated arguments as a string. + * Returned value must be freed with ecma_free_completion_value. + */ +static ecma_completion_value_t +ecma_builtin_function_helper_get_arguments (const ecma_value_t *arguments_list_p, /** < arguments list */ + ecma_length_t arguments_list_len, /** < number of arguments */ + ecma_length_t *out_total_number_of_args_p) /** < out: number of + * arguments found */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + JERRY_ASSERT (out_total_number_of_args_p != NULL); + + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + /* We are only processing the function arguments skipping the function body */ + ecma_length_t number_of_function_args = (arguments_list_len == 0 ? 0 : arguments_list_len - 1); + ecma_string_t *arguments_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + + ecma_string_t *separator_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR); + + for (ecma_length_t idx = 0; + idx < number_of_function_args && ecma_is_completion_value_empty (ret_value); + idx++) + { + ECMA_TRY_CATCH (str_arg_value, + ecma_op_to_string (arguments_list_p[idx]), + ret_value); + + ecma_string_t *str_p = ecma_get_string_from_value (str_arg_value); + + lit_utf8_size_t str_size = ecma_string_get_size (str_p); + MEM_DEFINE_LOCAL_ARRAY (start_p, str_size, lit_utf8_byte_t); + + ecma_string_to_utf8_string (str_p, start_p, (ssize_t) str_size); + lit_utf8_iterator_t iter = lit_utf8_iterator_create (start_p, str_size); + + while (!lit_utf8_iterator_is_eos (&iter)) + { + ecma_char_t current_char = lit_utf8_iterator_read_next (&iter); + + if (current_char == ',') + { + (*out_total_number_of_args_p)++; + } + } + + MEM_FINALIZE_LOCAL_ARRAY (start_p); + + ecma_string_t *concated_str_p = ecma_concat_ecma_strings (arguments_str_p, str_p); + ecma_deref_ecma_string (arguments_str_p); + arguments_str_p = concated_str_p; + + if (idx < number_of_function_args - 1) + { + ecma_string_t *concated_str_p = ecma_concat_ecma_strings (arguments_str_p, separator_string_p); + ecma_deref_ecma_string (arguments_str_p); + arguments_str_p = concated_str_p; + } + + (*out_total_number_of_args_p)++; + + ECMA_FINALIZE (str_arg_value); + } + + ecma_deref_ecma_string (separator_string_p); + + if (ecma_is_completion_value_empty (ret_value)) + { + ret_value = ecma_make_normal_completion_value (ecma_make_string_value (arguments_str_p)); + } + + return ret_value; +} /* ecma_builtin_function_helper_get_arguments */ + /** * Handle calling [[Construct]] of built-in Function object * @@ -71,9 +151,19 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + ecma_length_t total_number_of_function_args = 0; + + ECMA_TRY_CATCH (arguments_value, + ecma_builtin_function_helper_get_arguments (arguments_list_p, + arguments_list_len, + &total_number_of_function_args), + ret_value); + + ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value); + /* Last string, if any, is the function's body, and the rest, if any - are the function's parameter names */ MEM_DEFINE_LOCAL_ARRAY (string_params_p, - arguments_list_len == 0 ? 1 : arguments_list_len, + arguments_list_len == 0 ? 1 : total_number_of_function_args + 1, ecma_string_t *); uint32_t params_count; @@ -89,22 +179,52 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, else { /* 4., 5., 6. */ - strings_buffer_size = 0; - params_count = 0; - while (params_count < arguments_list_len - && ecma_is_completion_value_empty (ret_value)) + + lit_utf8_size_t str_size = ecma_string_get_size (arguments_str_p); + strings_buffer_size = str_size; + + MEM_DEFINE_LOCAL_ARRAY (start_p, str_size, lit_utf8_byte_t); + + ecma_string_to_utf8_string (arguments_str_p, start_p, (ssize_t) str_size); + lit_utf8_iterator_t iter = lit_utf8_iterator_create (start_p, str_size); + ecma_length_t last_separator = lit_utf8_iterator_get_index (&iter); + ecma_length_t end_position; + + while (!lit_utf8_iterator_is_eos (&iter)) { - ECMA_TRY_CATCH (str_arg_value, - ecma_op_to_string (arguments_list_p[params_count]), - ret_value); + ecma_char_t current_char = lit_utf8_iterator_read_next (&iter); - string_params_p[params_count] = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (str_arg_value)); - strings_buffer_size += ecma_string_get_size (string_params_p[params_count]); - params_count++; + if (current_char == ',') + { + lit_utf8_iterator_decr (&iter); + end_position = lit_utf8_iterator_get_index (&iter); - ECMA_FINALIZE (str_arg_value); + string_params_p[params_count] = ecma_string_substr (arguments_str_p, last_separator, end_position); + + lit_utf8_iterator_incr (&iter); + last_separator = lit_utf8_iterator_get_index (&iter); + + params_count++; + } } + + end_position = lit_utf8_string_length (start_p, str_size); + string_params_p[params_count] = ecma_string_substr (arguments_str_p, last_separator, end_position); + params_count++; + + MEM_FINALIZE_LOCAL_ARRAY (start_p); + + ECMA_TRY_CATCH (str_arg_value, + ecma_op_to_string (arguments_list_p[arguments_list_len - 1]), + ret_value); + + ecma_string_t *str_p = ecma_get_string_from_value (str_arg_value); + string_params_p[params_count] = ecma_copy_or_ref_ecma_string (str_p); + strings_buffer_size += ecma_string_get_size (str_p); + params_count++; + + ECMA_FINALIZE (str_arg_value); } if (ecma_is_completion_value_empty (ret_value)) @@ -197,6 +317,8 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, MEM_FINALIZE_LOCAL_ARRAY (string_params_p); + ECMA_FINALIZE (arguments_value); + return ret_value; } /* ecma_builtin_function_dispatch_construct */ diff --git a/tests/jerry/function-construct.js b/tests/jerry/function-construct.js index 8f221c216..757fd13f4 100644 --- a/tests/jerry/function-construct.js +++ b/tests/jerry/function-construct.js @@ -62,6 +62,15 @@ for (i = 1; i < 10; i ++) } } +var f = new Function ("a,b", "c", "return a + b + c;"); +assert (f (1,2,3) === 6); + +f = new Function ("a,b", "c,d", "return a + b + c + d;"); +assert (f (1,2,3,4) === 10); + +f = new Function ("a" , "b", "c,d", "return a + b + c + d;"); +assert (f (1,2,3,4) === 10); + try { new Function ({