From cd7cf53ecb43f1072032bc1764433139258eeab8 Mon Sep 17 00:00:00 2001 From: Laszlo Vidacs Date: Mon, 23 Nov 2015 18:03:49 +0100 Subject: [PATCH] Rearrange String.prototype.indexOf, lastIndexOf and Replace helpers Fixes issue #515 JerryScript-DCO-1.0-Signed-off-by: Laszlo Vidacs lvidacs.u-szeged@partner.samsung.com --- .../builtin-objects/ecma-builtin-helpers.cpp | 106 ++++++--- .../builtin-objects/ecma-builtin-helpers.h | 2 + .../ecma-builtin-string-prototype.cpp | 206 +----------------- tests/jerry/string-prototype-indexof.js | 21 +- 4 files changed, 87 insertions(+), 248 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp index e7cad2280..19ea0c718 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp @@ -430,7 +430,6 @@ ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */ * * Used by: * - The String.prototype.substring routine. - * - The String.prototype.indexOf routine. * - The ecma_builtin_helper_string_prototype_object_index_of helper routine. * * @return uint32_t - the normalized value of the index @@ -469,7 +468,7 @@ ecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */ return norm_index; } /* ecma_builtin_helper_string_index_normalize */ -/* +/** * Helper function for string indexOf and lastIndexOf functions * * This function implements string indexOf and lastIndexOf with required checks and conversions. @@ -488,7 +487,7 @@ ecma_completion_value_t ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2, /**< routine's second argument */ - bool firstIndex) /**< routine's third argument */ + bool first_index) /**< routine's third argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); @@ -512,28 +511,74 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /** arg2, ret_value); - /* 6 */ + /* 5 (indexOf) -- 6 (lastIndexOf) */ ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val); const ecma_length_t original_len = ecma_string_get_length (original_str_p); - const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p); - /* 4b, 5, 7 */ - ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, firstIndex); + /* 4b, 6 (indexOf) - 4b, 5, 7 (lastIndexOf) */ + ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, first_index); - /* 8 */ + /* 7 (indexOf) -- 8 (lastIndexOf) */ ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val); - const ecma_length_t search_len = ecma_string_get_length (search_str_p); - const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p); ecma_number_t *ret_num_p = ecma_alloc_number (); *ret_num_p = ecma_int32_to_number (-1); - /* 9 */ + /* 8 (indexOf) -- 9 (lastIndexOf) */ + ecma_length_t index_of = 0; + if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, first_index, start, &index_of)) + { + *ret_num_p = ecma_uint32_to_number (index_of); + } + + ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p)); + + ECMA_OP_TO_NUMBER_FINALIZE (pos_num); + ECMA_FINALIZE (search_str_val); + ECMA_FINALIZE (to_str_val); + ECMA_FINALIZE (check_coercible_val); + + return ret_value; +} /* ecma_builtin_helper_string_prototype_object_index_of */ + +/** + * Helper function for finding index of a search string + * + * This function clamps the given index to the [0, length] range. + * If the index is negative, 0 value is used. + * If the index is greater than the length of the string, the normalized index will be the length of the string. + * NaN is mapped to zero or length depending on the nan_to_zero parameter. + * + * See also: + * ECMA-262 v5, 15.5.4.7,8,11 + * + * Used by: + * - The ecma_builtin_helper_string_prototype_object_index_of helper routine. + * - The ecma_builtin_string_prototype_object_replace_match helper routine. + * + * @return uint32_t - the normalized value of the index + */ +bool +ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index */ + ecma_string_t *search_str_p, /**< string's length */ + bool first_index, /**< whether search for first (t) or last (f) index */ + ecma_length_t start_pos, /**< start position */ + ecma_length_t *ret_index_p) /**> position found in original string */ +{ + bool match_found = false; + + const ecma_length_t original_len = ecma_string_get_length (original_str_p); + const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p); + + const ecma_length_t search_len = ecma_string_get_length (search_str_p); + const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p); + if (search_len <= original_len) { if (!search_len) { - *ret_num_p = ecma_uint32_to_number (firstIndex ? 0 : original_len); + match_found = true; + *ret_index_p = first_index ? 0 : original_len; } else { @@ -547,7 +592,7 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /** (ssize_t) (original_size)); JERRY_ASSERT (sz >= 0); - ecma_length_t index = start; + ecma_length_t index = start_pos; lit_utf8_byte_t *original_str_curr_p = original_str_utf8_p + index; @@ -565,33 +610,42 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /** /* iterate original string and try to match at each position */ bool searching = true; - + ecma_char_t first_char = lit_utf8_read_next (&search_str_curr_p); while (searching) { /* match as long as possible */ ecma_length_t match_len = 0; lit_utf8_byte_t *stored_original_str_curr_p = original_str_curr_p; - while (match_len < search_len && - index + match_len < original_len && - lit_utf8_read_next (&original_str_curr_p) == lit_utf8_read_next (&search_str_curr_p)) + if (match_len < search_len && + index + match_len < original_len && + lit_utf8_read_next (&original_str_curr_p) == first_char) { + lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p; match_len++; + + while (match_len < search_len && + index + match_len < original_len && + lit_utf8_read_next (&original_str_curr_p) == lit_utf8_read_next (&nested_search_str_curr_p)) + { + match_len++; + } } /* check for match */ if (match_len == search_len) { - *ret_num_p = ecma_uint32_to_number (index); + match_found = true; + *ret_index_p = index; + break; } else { /* inc/dec index and update iterators and search condition */ - search_str_curr_p = search_str_utf8_p; original_str_curr_p = stored_original_str_curr_p; - if (firstIndex) + if (first_index) { if ((searching = (index <= original_len - search_len))) { @@ -615,16 +669,8 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /** } } - ecma_value_t new_value = ecma_make_number_value (ret_num_p); - ret_value = ecma_make_normal_completion_value (new_value); - - ECMA_OP_TO_NUMBER_FINALIZE (pos_num); - ECMA_FINALIZE (search_str_val); - ECMA_FINALIZE (to_str_val); - ECMA_FINALIZE (check_coercible_val); - - return ret_value; -} /* ecma_builtin_helper_string_index_normalize */ + return match_found; +} /* ecma_builtin_helper_string_find_index */ /** * Helper function for using [[DefineOwnProperty]]. diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index abab96366..023d9b272 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -41,6 +41,8 @@ ecma_builtin_helper_string_index_normalize (ecma_number_t, uint32_t, bool); extern ecma_completion_value_t ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t, ecma_value_t, ecma_value_t, bool); +extern bool +ecma_builtin_helper_string_find_index (ecma_string_t *, ecma_string_t *, bool, ecma_length_t, ecma_length_t *); extern ecma_completion_value_t ecma_builtin_helper_def_prop (ecma_object_t *, ecma_string_t *, ecma_value_t, bool, bool, bool, bool); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.cpp index 4c9e42953..0fb00a3cd 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.cpp @@ -312,123 +312,7 @@ ecma_builtin_string_prototype_object_index_of (ecma_value_t this_arg, /**< this ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { - ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); - - /* 1 */ - ECMA_TRY_CATCH (check_coercible_val, - ecma_op_check_object_coercible (this_arg), - ret_value); - - /* 2 */ - ECMA_TRY_CATCH (to_str_val, - ecma_op_to_string (this_arg), - ret_value); - - /* 3 */ - ECMA_TRY_CATCH (search_str_val, - ecma_op_to_string (arg1), - ret_value); - - /* 4 */ - ECMA_OP_TO_NUMBER_TRY_CATCH (pos_num, - arg2, - ret_value); - - /* 5 */ - ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val); - const ecma_length_t original_len = ecma_string_get_length (original_str_p); - const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p); - - /* 4b, 6 */ - ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, true); - - /* 7 */ - ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val); - const ecma_length_t search_len = ecma_string_get_length (search_str_p); - const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p); - - ecma_number_t *ret_num_p = ecma_alloc_number (); - *ret_num_p = ecma_int32_to_number (-1); - - /* 8 */ - if (search_len <= original_len) - { - if (!search_len) - { - *ret_num_p = ecma_uint32_to_number (0); - } - else - { - /* create utf8 string from original string and advance to start position */ - MEM_DEFINE_LOCAL_ARRAY (original_str_utf8_p, - original_size, - lit_utf8_byte_t); - - ssize_t sz = ecma_string_to_utf8_string (original_str_p, - original_str_utf8_p, - (ssize_t) (original_size)); - JERRY_ASSERT (sz >= 0); - - ecma_length_t index = start; - - lit_utf8_byte_t *original_str_curr_p = original_str_utf8_p + index; - - /* create utf8 string from search string */ - MEM_DEFINE_LOCAL_ARRAY (search_str_utf8_p, - search_size, - lit_utf8_byte_t); - - ssize_t sz = ecma_string_to_utf8_string (search_str_p, - search_str_utf8_p, - (ssize_t) (search_size)); - JERRY_ASSERT (sz >= 0); - - lit_utf8_byte_t *search_str_curr_p = search_str_utf8_p; - - /* iterate original string and try to match at each position */ - bool found = false; - - while (!found && index <= original_len - search_len) - { - ecma_length_t match_len = 0; - lit_utf8_byte_t *stored_original_str_curr_p = original_str_curr_p; - - while (match_len < search_len && - lit_utf8_read_next (&original_str_curr_p) == lit_utf8_read_next (&search_str_curr_p)) - { - match_len++; - } - - /* Check for match */ - if (match_len == search_len) - { - *ret_num_p = ecma_uint32_to_number (index); - found = true; - } - else - { - /* reset iterators */ - search_str_curr_p = search_str_utf8_p; - original_str_curr_p = stored_original_str_curr_p; - lit_utf8_incr (&original_str_curr_p); - } - index++; - } - - MEM_FINALIZE_LOCAL_ARRAY (search_str_utf8_p); - MEM_FINALIZE_LOCAL_ARRAY (original_str_utf8_p); - } - } - - ecma_value_t new_value = ecma_make_number_value (ret_num_p); - ret_value = ecma_make_normal_completion_value (new_value); - - ECMA_OP_TO_NUMBER_FINALIZE (pos_num); - ECMA_FINALIZE (search_str_val); - ECMA_FINALIZE (to_str_val); - ECMA_FINALIZE (check_coercible_val); - - return ret_value; + return ecma_builtin_helper_string_prototype_object_index_of (this_arg, arg1, arg2, true); } /* ecma_builtin_string_prototype_object_index_of */ /** @@ -872,94 +756,18 @@ ecma_builtin_string_prototype_object_replace_match (ecma_builtin_replace_search_ JERRY_ASSERT (!context_p->is_global); ecma_string_t *search_string_p = ecma_get_string_from_value (context_p->regexp_or_search_string); - lit_utf8_size_t search_size = ecma_string_get_size (search_string_p); - - MEM_DEFINE_LOCAL_ARRAY (search_start_p, - search_size, - lit_utf8_byte_t); - - ssize_t sz = ecma_string_to_utf8_string (search_string_p, - search_start_p, - (ssize_t) (search_size)); - JERRY_ASSERT (sz >= 0); - ecma_string_t *input_string_p = ecma_get_string_from_value (context_p->input_string); - lit_utf8_size_t input_size = ecma_string_get_size (input_string_p); - MEM_DEFINE_LOCAL_ARRAY (input_start_p, - input_size, - lit_utf8_byte_t); - - ssize_t sz = ecma_string_to_utf8_string (input_string_p, - input_start_p, - (ssize_t) (input_size)); - JERRY_ASSERT (sz >= 0); - - lit_utf8_byte_t *search_str_curr_p = search_start_p; - lit_utf8_byte_t *input_str_curr_p = input_start_p; - - ecma_length_t match_start = 0; - ecma_length_t match_end = 0; - bool match_found = false; - - if (!search_size) - { - /* Empty string, always matches. */ - match_found = true; - } - else - { - const lit_utf8_byte_t *input_str_end_p = input_start_p + input_size; - const lit_utf8_byte_t *search_str_end_p = search_start_p + search_size; - ecma_char_t first_char = lit_utf8_read_next (&search_str_curr_p); - - while (input_str_curr_p < input_str_end_p) - { - if (lit_utf8_read_next (&input_str_curr_p) == first_char) - { - /* Local copy to preserve the original value. */ - lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p; - lit_utf8_byte_t *nested_input_str_curr_p = input_str_curr_p; - match_end = match_start + 1; - - match_found = true; - while (nested_search_str_curr_p < search_str_end_p) - { - if (nested_input_str_curr_p >= input_str_end_p) - { - match_found = false; - break; - } - - ecma_char_t search_character = lit_utf8_read_next (&nested_search_str_curr_p); - ecma_char_t input_character = lit_utf8_read_next (&nested_input_str_curr_p); - - if (search_character != input_character) - { - match_found = false; - break; - } - match_end++; - } - - if (match_found) - { - break; - } - } - match_start++; - } - } - - if (match_found) + ecma_length_t index_of; + if (ecma_builtin_helper_string_find_index (input_string_p, search_string_p, true, 0, &index_of)) { ecma_value_t arguments_list_p[1] = { context_p->regexp_or_search_string }; ECMA_TRY_CATCH (new_array_value, ecma_op_create_array_object (arguments_list_p, 1, false), ret_value); - context_p->match_start = match_start; - context_p->match_end = match_end; + context_p->match_start = index_of; + context_p->match_end = index_of + ecma_string_get_length (search_string_p); ret_value = ecma_make_normal_completion_value (ecma_copy_value (new_array_value, true)); @@ -969,10 +777,8 @@ ecma_builtin_string_prototype_object_replace_match (ecma_builtin_replace_search_ { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_NULL); } - - MEM_FINALIZE_LOCAL_ARRAY (input_start_p); - MEM_FINALIZE_LOCAL_ARRAY (search_start_p); } + return ret_value; } /* ecma_builtin_string_prototype_object_replace_match */ diff --git a/tests/jerry/string-prototype-indexof.js b/tests/jerry/string-prototype-indexof.js index 96f6a94cf..28a0eb8e2 100644 --- a/tests/jerry/string-prototype-indexof.js +++ b/tests/jerry/string-prototype-indexof.js @@ -85,7 +85,7 @@ assert("Hello world, welcome to the universe.".indexOf("welcome", undefined_var) // check booleans assert("true".indexOf(true, false) === 0); -// check this is undefined +// check coercible - undefined try { String.prototype.indexOf.call(undefined); assert(false); @@ -93,7 +93,7 @@ try { assert(e instanceof TypeError); } -// check this is null +// check coercible - null try { String.prototype.indexOf.call(null); assert(false); @@ -101,24 +101,9 @@ try { assert(e instanceof TypeError); } -// check coercible - undefined -try { - assert(true.indexOf()); - assert(false); -} catch (e) { - assert(e instanceof TypeError); -} - -// check coercible - null -try { - assert(isNaN(String.prototype.indexOf.call(null, 0))); - assert(false); -} catch (e) { - assert(e instanceof TypeError); -} - // check coercible - Boolean assert(String.prototype.indexOf.call(true, "e") === 3); +assert(String.prototype.indexOf.call(false, "e") === 4); // check coercible - Object var test_object = {firstName:"John", lastName:"Doe"};