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
This commit is contained in:
Peter Gal 2015-07-10 15:29:43 +02:00 committed by Evgeny Gavrin
parent 292d99ba4e
commit c8a16f2107
2 changed files with 143 additions and 12 deletions

View File

@ -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 */

View File

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