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 ({