1616
1717#include " ecma-builtin-helpers.h"
1818
19+ #include " ecma-alloc.h"
1920#include " ecma-array-object.h"
2021#include " ecma-builtins.h"
2122#include " ecma-conversion.h"
@@ -474,22 +475,33 @@ ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */
474475 * This function clamps the given index to the [0, length] range.
475476 * If the index is negative, 0 value is used.
476477 * If the index is greater than the length of the string, the normalized index will be the length of the string.
478+ * NaN is mapped to zero or length depending on the nan_to_zero parameter.
477479 *
478480 * See also:
479481 * ECMA-262 v5, 15.5.4.15
480482 *
481483 * Used by:
482484 * - The String.prototype.substring routine.
485+ * - The String.prototype.indexOf routine.
486+ * - The ecma_builtin_helper_string_prototype_object_index_of helper routine.
483487 *
484488 * @return uint32_t - the normalized value of the index
485489 */
486490uint32_t
487491ecma_builtin_helper_string_index_normalize (ecma_number_t index, /* *< index */
488- uint32_t length) /* *< string's length */
492+ uint32_t length, /* *< string's length */
493+ bool nan_to_zero) /* *< whether NaN is mapped to zero (t) or length (f) */
489494{
490495 uint32_t norm_index = 0 ;
491496
492- if (!ecma_number_is_nan (index) && !ecma_number_is_negative (index))
497+ if (ecma_number_is_nan (index))
498+ {
499+ if (!nan_to_zero)
500+ {
501+ norm_index = length;
502+ }
503+ }
504+ else if (!ecma_number_is_negative (index))
493505 {
494506 if (ecma_number_is_infinity (index))
495507 {
@@ -509,6 +521,162 @@ ecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */
509521 return norm_index;
510522} /* ecma_builtin_helper_string_index_normalize */
511523
524+ /*
525+ * Helper function for string indexOf and lastIndexOf functions
526+ *
527+ * This function implements string indexOf and lastIndexOf with required checks and conversions.
528+ *
529+ * See also:
530+ * ECMA-262 v5, 15.5.4.7
531+ * ECMA-262 v5, 15.5.4.8
532+ *
533+ * Used by:
534+ * - The String.prototype.indexOf routine.
535+ * - The String.prototype.lastIndexOf routine.
536+ *
537+ * @return uint32_t - (last)index of search string
538+ */
539+ ecma_completion_value_t
540+ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /* *< this argument */
541+ ecma_value_t arg1, /* *< routine's first argument */
542+ ecma_value_t arg2, /* *< routine's second argument */
543+ bool firstIndex) /* *< routine's third argument */
544+ {
545+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
546+
547+ /* 1 */
548+ ECMA_TRY_CATCH (check_coercible_val,
549+ ecma_op_check_object_coercible (this_arg),
550+ ret_value);
551+
552+ /* 2 */
553+ ECMA_TRY_CATCH (to_str_val,
554+ ecma_op_to_string (this_arg),
555+ ret_value);
556+
557+ /* 3 */
558+ ECMA_TRY_CATCH (search_str_val,
559+ ecma_op_to_string (arg1),
560+ ret_value);
561+
562+ /* 4 */
563+ ECMA_OP_TO_NUMBER_TRY_CATCH (pos_num,
564+ arg2,
565+ ret_value);
566+
567+ /* 6 */
568+ ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val);
569+ const ecma_length_t original_len = ecma_string_get_length (original_str_p);
570+ const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p);
571+
572+ /* 4b, 5, 7 */
573+ ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, firstIndex);
574+
575+ /* 8 */
576+ ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val);
577+ const ecma_length_t search_len = ecma_string_get_length (search_str_p);
578+ const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p);
579+
580+ ecma_number_t *ret_num_p = ecma_alloc_number ();
581+ *ret_num_p = ecma_int32_to_number (-1 );
582+
583+ /* 9 */
584+ if (search_len <= original_len)
585+ {
586+ if (!search_len)
587+ {
588+ *ret_num_p = ecma_uint32_to_number (firstIndex ? 0 : original_len);
589+ }
590+ else
591+ {
592+ /* create utf8 string from original string and advance to position */
593+ MEM_DEFINE_LOCAL_ARRAY (original_str_utf8_p,
594+ original_size,
595+ lit_utf8_byte_t );
596+
597+ ecma_string_to_utf8_string (original_str_p,
598+ original_str_utf8_p,
599+ (ssize_t ) (original_size));
600+
601+ lit_utf8_iterator_t original_it = lit_utf8_iterator_create (original_str_utf8_p, original_size);
602+
603+ ecma_length_t index = start;
604+ lit_utf8_iterator_advance (&original_it, index);
605+
606+ /* create utf8 string from search string */
607+ MEM_DEFINE_LOCAL_ARRAY (search_str_utf8_p,
608+ search_size,
609+ lit_utf8_byte_t );
610+
611+ ecma_string_to_utf8_string (search_str_p,
612+ search_str_utf8_p,
613+ (ssize_t ) (search_size));
614+
615+ lit_utf8_iterator_t search_it = lit_utf8_iterator_create (search_str_utf8_p, search_size);
616+
617+ /* iterate original string and try to match at each position */
618+ bool searching = true ;
619+
620+ while (searching)
621+ {
622+ /* match as long as possible */
623+ ecma_length_t match_len = 0 ;
624+ lit_utf8_iterator_t stored_original_it = original_it;
625+
626+ while (match_len < search_len &&
627+ index + match_len < original_len &&
628+ lit_utf8_iterator_read_next (&original_it) == lit_utf8_iterator_read_next (&search_it))
629+ {
630+ match_len++;
631+ }
632+
633+ /* check for match */
634+ if (match_len == search_len)
635+ {
636+ *ret_num_p = ecma_uint32_to_number (index);
637+ break ;
638+ }
639+ else
640+ {
641+ /* inc/dec index and update iterators and search condition */
642+ lit_utf8_iterator_seek_bos (&search_it);
643+ original_it = stored_original_it;
644+
645+ if (firstIndex)
646+ {
647+ if ((searching = (index <= original_len - search_len)))
648+ {
649+ lit_utf8_iterator_incr (&original_it);
650+ index++;
651+ }
652+ }
653+ else
654+ {
655+ if ((searching = (index > 0 )))
656+ {
657+ lit_utf8_iterator_decr (&original_it);
658+ index--;
659+ }
660+ }
661+ }
662+ }
663+
664+ MEM_FINALIZE_LOCAL_ARRAY (search_str_utf8_p);
665+ MEM_FINALIZE_LOCAL_ARRAY (original_str_utf8_p);
666+ }
667+ }
668+
669+ ecma_value_t new_value = ecma_make_number_value (ret_num_p);
670+ ret_value = ecma_make_normal_completion_value (new_value);
671+
672+ ECMA_OP_TO_NUMBER_FINALIZE (pos_num);
673+ ECMA_FINALIZE (search_str_val);
674+ ECMA_FINALIZE (to_str_val);
675+ ECMA_FINALIZE (check_coercible_val);
676+
677+ return ret_value;
678+ } /* ecma_builtin_helper_string_index_normalize */
679+
512680/* *
513681 * Helper function for using [[DefineOwnProperty]].
514682 *
0 commit comments