Although the standard does not specify the effect of $nn in String.replace when nn is bigger than the max, the test-262 test suite expects a certain behaviour. This behaviour is mimiced by this patch.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg@inf.u-szeged.hu
This commit is contained in:
Zoltan Herczeg 2015-08-10 23:09:38 -07:00
parent d31eb3c4cb
commit a751478a19
2 changed files with 88 additions and 37 deletions

View File

@ -994,26 +994,25 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
ecma_value_t match_value) /**< returned match value */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ecma_string_t *length_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
ecma_object_t *match_object_p = ecma_get_object_from_value (match_value);
ECMA_TRY_CATCH (match_length_value,
ecma_op_object_get (match_object_p, length_string_p),
ret_value);
JERRY_ASSERT (ecma_is_value_number (match_length_value));
ecma_number_t *match_length_number_p = ecma_get_number_from_value (match_length_value);
ecma_length_t match_length = (ecma_length_t) (*match_length_number_p);
JERRY_ASSERT ((ecma_length_t) ecma_number_to_uint32 (*match_length_number_p) == match_length);
JERRY_ASSERT (match_length >= 1);
if (context_p->is_replace_callable)
{
ecma_object_t *match_object_p = ecma_get_object_from_value (match_value);
ecma_string_t *length_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
ECMA_TRY_CATCH (length_value,
ecma_op_object_get (match_object_p, length_string_p),
ret_value);
JERRY_ASSERT (ecma_is_value_number (length_value));
ecma_number_t *length_number_p = ecma_get_number_from_value (length_value);
ecma_length_t length = (ecma_length_t) (*length_number_p);
JERRY_ASSERT ((ecma_length_t) ecma_number_to_uint32 (*length_number_p) == length);
JERRY_ASSERT (length >= 1);
MEM_DEFINE_LOCAL_ARRAY (arguments_list,
length + 2,
match_length + 2,
ecma_value_t);
/* An error might occure during the array copy and
@ -1021,7 +1020,7 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
ecma_length_t values_copied = 0;
for (ecma_length_t i = 0;
(i < length) && ecma_is_completion_value_empty (ret_value);
(i < match_length) && ecma_is_completion_value_empty (ret_value);
i++)
{
ecma_string_t *index_p = ecma_new_ecma_string_from_uint32 (i);
@ -1041,14 +1040,14 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
ecma_number_t *index_number_p = ecma_alloc_number ();
*index_number_p = context_p->match_start;
arguments_list[length] = ecma_make_number_value (index_number_p);
arguments_list[length + 1] = ecma_copy_value (context_p->input_string, true);
arguments_list[match_length] = ecma_make_number_value (index_number_p);
arguments_list[match_length + 1] = ecma_copy_value (context_p->input_string, true);
ECMA_TRY_CATCH (result_value,
ecma_op_function_call_array_args (context_p->replace_function_p,
context_p->regexp_or_search_string,
arguments_list,
length + 2),
match_length + 2),
ret_value);
ECMA_TRY_CATCH (to_string_value,
@ -1060,7 +1059,7 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
ECMA_FINALIZE (to_string_value);
ECMA_FINALIZE (result_value);
ecma_free_value (arguments_list[length + 1], true);
ecma_free_value (arguments_list[match_length + 1], true);
ecma_dealloc_number (index_number_p);
}
@ -1070,11 +1069,23 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
}
MEM_FINALIZE_LOCAL_ARRAY (arguments_list);
ECMA_FINALIZE (length_value);
ecma_deref_ecma_string (length_string_p);
}
else
{
/* Although the ECMA standard does not specify how $nn (n is a decimal
* number) captures should be replaced if nn is greater than the maximum
* capture index, we follow the test-262 expected behaviour:
*
* if maximum capture index is < 10
* we replace only those $n and $0n captures, where n < maximum capture index
* otherwise
* we replace only those $nn captures, where nn < maximum capture index
*
* other $n $nn sequences left unchanged
*
* example: "<xy>".replace(/(x)y/, "$1,$2,$01,$12") === "<x,$2,x,x2>"
*/
ecma_string_t *result_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
ecma_length_t previous_start = 0;
@ -1098,20 +1109,42 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
{
current_position++;
}
else if (action == LIT_CHAR_0)
else if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9)
{
lit_utf8_iterator_incr (&replace_iterator);
ecma_char_t next_character = lit_utf8_iterator_peek_next (&replace_iterator);
if (!(next_character >= LIT_CHAR_1 && next_character <= LIT_CHAR_9))
uint32_t index = 0;
index = (uint32_t) (action - LIT_CHAR_0);
if (index >= match_length)
{
action = LIT_CHAR_NULL;
}
lit_utf8_iterator_decr (&replace_iterator);
else if (index == 0 || match_length > 10)
{
lit_utf8_iterator_incr (&replace_iterator);
ecma_char_t next_character = lit_utf8_iterator_peek_next (&replace_iterator);
if (next_character >= LIT_CHAR_0 && next_character <= LIT_CHAR_9)
{
uint32_t full_index = index * 10 + (uint32_t) (next_character - LIT_CHAR_0);
if (full_index > 0 && full_index < match_length)
{
index = match_length;
}
}
lit_utf8_iterator_decr (&replace_iterator);
if (index == 0)
{
action = LIT_CHAR_NULL;
}
}
}
else if (action != LIT_CHAR_AMPERSAND
&& action != LIT_CHAR_GRAVE_ACCENT
&& action != LIT_CHAR_SINGLE_QUOTE
&& !(action >= LIT_CHAR_1 && action <= LIT_CHAR_9))
&& action != LIT_CHAR_SINGLE_QUOTE)
{
action = LIT_CHAR_NULL;
}
@ -1159,14 +1192,23 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9)
{
index = (uint32_t) (action - LIT_CHAR_0);
action = lit_utf8_iterator_peek_next (&replace_iterator);
if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9)
if ((match_length > 10 || index == 0)
&& !lit_utf8_iterator_is_eos (&replace_iterator))
{
index = index * 10 + (uint32_t) (action - LIT_CHAR_0);
lit_utf8_iterator_incr (&replace_iterator);
current_position++;
action = lit_utf8_iterator_peek_next (&replace_iterator);
if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9)
{
uint32_t full_index = index * 10 + (uint32_t) (action - LIT_CHAR_0);
if (full_index < match_length)
{
index = full_index;
lit_utf8_iterator_incr (&replace_iterator);
current_position++;
}
}
}
JERRY_ASSERT (index != 0);
JERRY_ASSERT (index > 0 && index < match_length);
}
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
@ -1215,6 +1257,9 @@ ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_se
}
}
ECMA_FINALIZE (match_length_value);
ecma_deref_ecma_string (length_string_p);
return ret_value;
} /* ecma_builtin_string_prototype_object_replace_get_string */

View File

@ -17,9 +17,15 @@ assert ("abcabc".replace("bc", ":") === "a:abc");
assert ("hello".replace("", ":") === ":hello");
assert ("xabcxabcx".replace (/abc/g, "[$&][$`][$']") === "x[abc][x][xabcx]x[abc][xabcx][x]x");
assert ("abc".replace (/a(b)c|d()/, "[$1][$01][$2][$02][$99][$123][$012]") === "[b][b][][][][3][b2]");
assert ("abc".replace (/a(b)c|d()/, "[$1][$01][$2][$02][$99][$123][$012]") === "[b][b][][][$99][b23][b2]");
assert ("abc".replace("abc", "$x$$5$0$00$") === "$x$5$0$00$");
assert ("#x#".replace("x", "$1") === "#$1#");
assert ("#x#".replace(/(x)/, "$1$2") === "#x$2#");
assert ("#x#".replace(/(x)/, "$01$02$11$20") === "#x$02x1$20#");
assert ("#xy#".replace(/(x)((((((((((y))))))))))/, "$07|$20|$11|$12|$110|$99|$011") === "#y|y0|y|x2|y0|y9|x1#");
assert ("#xy#".replace(/(x)((((((((y))))))))/, "$00|$01|$011|$090|$10|$99") === "#$00|x|x1|y0|x0|y9#");
assert ("a true true story".replace(true) === "a undefined true story");
assert ("1234".replace(23, 32) === "1324");