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"
@@ -470,22 +471,33 @@ ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */
470471 * This function clamps the given index to the [0, length] range.
471472 * If the index is negative, 0 value is used.
472473 * If the index is greater than the length of the string, the normalized index will be the length of the string.
474+ * NaN is mapped to zero or length depending on the nan_to_zero parameter.
473475 *
474476 * See also:
475477 * ECMA-262 v5, 15.5.4.15
476478 *
477479 * Used by:
478480 * - The String.prototype.substring routine.
481+ * - The String.prototype.indexOf routine.
482+ * - The ecma_builtin_helper_string_prototype_object_index_of helper routine.
479483 *
480484 * @return uint32_t - the normalized value of the index
481485 */
482486uint32_t
483487ecma_builtin_helper_string_index_normalize (ecma_number_t index, /* *< index */
484- uint32_t length) /* *< string's length */
488+ uint32_t length, /* *< string's length */
489+ bool nan_to_zero) /* *< whether NaN is mapped to zero (t) or length (f) */
485490{
486491 uint32_t norm_index = 0 ;
487492
488- if (!ecma_number_is_nan (index) && !ecma_number_is_negative (index))
493+ if (ecma_number_is_nan (index))
494+ {
495+ if (!nan_to_zero)
496+ {
497+ norm_index = length;
498+ }
499+ }
500+ else if (!ecma_number_is_negative (index))
489501 {
490502 if (ecma_number_is_infinity (index))
491503 {
@@ -505,6 +517,162 @@ ecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */
505517 return norm_index;
506518} /* ecma_builtin_helper_string_index_normalize */
507519
520+ /*
521+ * Helper function for string indexOf and lastIndexOf functions
522+ *
523+ * This function implements string indexOf and lastIndexOf with required checks and conversions.
524+ *
525+ * See also:
526+ * ECMA-262 v5, 15.5.4.7
527+ * ECMA-262 v5, 15.5.4.8
528+ *
529+ * Used by:
530+ * - The String.prototype.indexOf routine.
531+ * - The String.prototype.lastIndexOf routine.
532+ *
533+ * @return uint32_t - (last)index of search string
534+ */
535+ ecma_completion_value_t
536+ ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /* *< this argument */
537+ ecma_value_t arg1, /* *< routine's first argument */
538+ ecma_value_t arg2, /* *< routine's second argument */
539+ bool firstIndex) /* *< routine's third argument */
540+ {
541+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
542+
543+ /* 1 */
544+ ECMA_TRY_CATCH (check_coercible_val,
545+ ecma_op_check_object_coercible (this_arg),
546+ ret_value);
547+
548+ /* 2 */
549+ ECMA_TRY_CATCH (to_str_val,
550+ ecma_op_to_string (this_arg),
551+ ret_value);
552+
553+ /* 3 */
554+ ECMA_TRY_CATCH (search_str_val,
555+ ecma_op_to_string (arg1),
556+ ret_value);
557+
558+ /* 4 */
559+ ECMA_OP_TO_NUMBER_TRY_CATCH (pos_num,
560+ arg2,
561+ ret_value);
562+
563+ /* 6 */
564+ ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val);
565+ const ecma_length_t original_len = ecma_string_get_length (original_str_p);
566+ const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p);
567+
568+ /* 4b, 5, 7 */
569+ ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, firstIndex);
570+
571+ /* 8 */
572+ ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val);
573+ const ecma_length_t search_len = ecma_string_get_length (search_str_p);
574+ const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p);
575+
576+ ecma_number_t *ret_num_p = ecma_alloc_number ();
577+ *ret_num_p = ecma_int32_to_number (-1 );
578+
579+ /* 9 */
580+ if (search_len <= original_len)
581+ {
582+ if (!search_len)
583+ {
584+ *ret_num_p = ecma_uint32_to_number (firstIndex ? 0 : original_len);
585+ }
586+ else
587+ {
588+ /* create utf8 string from original string and advance to position */
589+ MEM_DEFINE_LOCAL_ARRAY (original_str_utf8_p,
590+ original_size,
591+ lit_utf8_byte_t );
592+
593+ ecma_string_to_utf8_string (original_str_p,
594+ original_str_utf8_p,
595+ (ssize_t ) (original_size));
596+
597+ lit_utf8_iterator_t original_it = lit_utf8_iterator_create (original_str_utf8_p, original_size);
598+
599+ ecma_length_t index = start;
600+ lit_utf8_iterator_advance (&original_it, index);
601+
602+ /* create utf8 string from search string */
603+ MEM_DEFINE_LOCAL_ARRAY (search_str_utf8_p,
604+ search_size,
605+ lit_utf8_byte_t );
606+
607+ ecma_string_to_utf8_string (search_str_p,
608+ search_str_utf8_p,
609+ (ssize_t ) (search_size));
610+
611+ lit_utf8_iterator_t search_it = lit_utf8_iterator_create (search_str_utf8_p, search_size);
612+
613+ /* iterate original string and try to match at each position */
614+ bool searching = true ;
615+
616+ while (searching)
617+ {
618+ /* match as long as possible */
619+ ecma_length_t match_len = 0 ;
620+ lit_utf8_iterator_t stored_original_it = original_it;
621+
622+ while (match_len < search_len &&
623+ index + match_len < original_len &&
624+ lit_utf8_iterator_read_next (&original_it) == lit_utf8_iterator_read_next (&search_it))
625+ {
626+ match_len++;
627+ }
628+
629+ /* check for match */
630+ if (match_len == search_len)
631+ {
632+ *ret_num_p = ecma_uint32_to_number (index);
633+ break ;
634+ }
635+ else
636+ {
637+ /* inc/dec index and update iterators and search condition */
638+ lit_utf8_iterator_seek_bos (&search_it);
639+ original_it = stored_original_it;
640+
641+ if (firstIndex)
642+ {
643+ if ((searching = (index <= original_len - search_len)))
644+ {
645+ lit_utf8_iterator_incr (&original_it);
646+ index++;
647+ }
648+ }
649+ else
650+ {
651+ if ((searching = (index > 0 )))
652+ {
653+ lit_utf8_iterator_decr (&original_it);
654+ index--;
655+ }
656+ }
657+ }
658+ }
659+
660+ MEM_FINALIZE_LOCAL_ARRAY (search_str_utf8_p);
661+ MEM_FINALIZE_LOCAL_ARRAY (original_str_utf8_p);
662+ }
663+ }
664+
665+ ecma_value_t new_value = ecma_make_number_value (ret_num_p);
666+ ret_value = ecma_make_normal_completion_value (new_value);
667+
668+ ECMA_OP_TO_NUMBER_FINALIZE (pos_num);
669+ ECMA_FINALIZE (search_str_val);
670+ ECMA_FINALIZE (to_str_val);
671+ ECMA_FINALIZE (check_coercible_val);
672+
673+ return ret_value;
674+ } /* ecma_builtin_helper_string_index_normalize */
675+
508676/* *
509677 * Helper function for using [[DefineOwnProperty]].
510678 *
0 commit comments