1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci#include "ecma-builtin-helpers.h"
17425bb815Sopenharmony_ci
18425bb815Sopenharmony_ci#include "ecma-alloc.h"
19425bb815Sopenharmony_ci#include "ecma-array-object.h"
20425bb815Sopenharmony_ci#include "ecma-builtins.h"
21425bb815Sopenharmony_ci#include "ecma-builtin-object.h"
22425bb815Sopenharmony_ci#include "ecma-conversion.h"
23425bb815Sopenharmony_ci#include "ecma-function-object.h"
24425bb815Sopenharmony_ci#include "ecma-exceptions.h"
25425bb815Sopenharmony_ci#include "ecma-gc.h"
26425bb815Sopenharmony_ci#include "ecma-helpers.h"
27425bb815Sopenharmony_ci#include "jmem.h"
28425bb815Sopenharmony_ci#include "ecma-objects.h"
29425bb815Sopenharmony_ci#include "ecma-try-catch-macro.h"
30425bb815Sopenharmony_ci#include "lit-magic-strings.h"
31425bb815Sopenharmony_ci#include "lit-char-helpers.h"
32425bb815Sopenharmony_ci
33425bb815Sopenharmony_ci/** \addtogroup ecma ECMA
34425bb815Sopenharmony_ci * @{
35425bb815Sopenharmony_ci *
36425bb815Sopenharmony_ci * \addtogroup ecmabuiltinhelpers ECMA builtin helper operations
37425bb815Sopenharmony_ci * @{
38425bb815Sopenharmony_ci */
39425bb815Sopenharmony_ci
40425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
41425bb815Sopenharmony_ci/**
42425bb815Sopenharmony_ci * Helper function for Object.prototype.toString routine when
43425bb815Sopenharmony_ci * the @@toStringTag property is present
44425bb815Sopenharmony_ci *
45425bb815Sopenharmony_ci * See also:
46425bb815Sopenharmony_ci *          ECMA-262 v6, 19.1.3.6
47425bb815Sopenharmony_ci *
48425bb815Sopenharmony_ci * @return ecma value
49425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
50425bb815Sopenharmony_ci */
51425bb815Sopenharmony_cistatic ecma_value_t
52425bb815Sopenharmony_ciecma_builtin_helper_object_to_string_tag_helper (ecma_value_t tag_value) /**< string tag */
53425bb815Sopenharmony_ci{
54425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_string (tag_value));
55425bb815Sopenharmony_ci
56425bb815Sopenharmony_ci  ecma_string_t *tag_str_p = ecma_get_string_from_value (tag_value);
57425bb815Sopenharmony_ci  ecma_string_t *ret_string_p;
58425bb815Sopenharmony_ci
59425bb815Sopenharmony_ci  /* Building string "[object #@@toStringTag#]"
60425bb815Sopenharmony_ci     The string size will be size("[object ") + size(#@@toStringTag#) + size ("]"). */
61425bb815Sopenharmony_ci  const lit_utf8_size_t buffer_size = 9 + ecma_string_get_size (tag_str_p);
62425bb815Sopenharmony_ci  JMEM_DEFINE_LOCAL_ARRAY (str_buffer, buffer_size, lit_utf8_byte_t);
63425bb815Sopenharmony_ci
64425bb815Sopenharmony_ci  lit_utf8_byte_t *buffer_ptr = str_buffer;
65425bb815Sopenharmony_ci
66425bb815Sopenharmony_ci  const lit_magic_string_id_t magic_string_ids[] =
67425bb815Sopenharmony_ci  {
68425bb815Sopenharmony_ci    LIT_MAGIC_STRING_LEFT_SQUARE_CHAR,
69425bb815Sopenharmony_ci    LIT_MAGIC_STRING_OBJECT,
70425bb815Sopenharmony_ci    LIT_MAGIC_STRING_SPACE_CHAR,
71425bb815Sopenharmony_ci  };
72425bb815Sopenharmony_ci
73425bb815Sopenharmony_ci  /* Copy to buffer the "[object " string */
74425bb815Sopenharmony_ci  for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i)
75425bb815Sopenharmony_ci  {
76425bb815Sopenharmony_ci    buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr,
77425bb815Sopenharmony_ci                                                  (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
78425bb815Sopenharmony_ci
79425bb815Sopenharmony_ci    JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
80425bb815Sopenharmony_ci  }
81425bb815Sopenharmony_ci
82425bb815Sopenharmony_ci  /* Copy to buffer the #@@toStringTag# string */
83425bb815Sopenharmony_ci  buffer_ptr += ecma_string_copy_to_cesu8_buffer (tag_str_p, buffer_ptr,
84425bb815Sopenharmony_ci                                                  (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
85425bb815Sopenharmony_ci
86425bb815Sopenharmony_ci  JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
87425bb815Sopenharmony_ci
88425bb815Sopenharmony_ci  /* Copy to buffer the "]" string */
89425bb815Sopenharmony_ci  buffer_ptr = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR, buffer_ptr,
90425bb815Sopenharmony_ci                                                (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
91425bb815Sopenharmony_ci
92425bb815Sopenharmony_ci  JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
93425bb815Sopenharmony_ci
94425bb815Sopenharmony_ci  ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));
95425bb815Sopenharmony_ci
96425bb815Sopenharmony_ci  JMEM_FINALIZE_LOCAL_ARRAY (str_buffer);
97425bb815Sopenharmony_ci  ecma_deref_ecma_string (tag_str_p);
98425bb815Sopenharmony_ci
99425bb815Sopenharmony_ci  return ecma_make_string_value (ret_string_p);
100425bb815Sopenharmony_ci} /* ecma_builtin_helper_object_to_string_tag_helper */
101425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
102425bb815Sopenharmony_ci
103425bb815Sopenharmony_ci/**
104425bb815Sopenharmony_ci * Common implementation of the Object.prototype.toString routine
105425bb815Sopenharmony_ci *
106425bb815Sopenharmony_ci * See also:
107425bb815Sopenharmony_ci *          ECMA-262 v5, 15.2.4.2
108425bb815Sopenharmony_ci *
109425bb815Sopenharmony_ci * Used by:
110425bb815Sopenharmony_ci *         - The Object.prototype.toString routine.
111425bb815Sopenharmony_ci *         - The Array.prototype.toString routine as fallback.
112425bb815Sopenharmony_ci *
113425bb815Sopenharmony_ci * @return ecma value
114425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
115425bb815Sopenharmony_ci */
116425bb815Sopenharmony_ci
117425bb815Sopenharmony_ciecma_value_t
118425bb815Sopenharmony_ciecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this argument */
119425bb815Sopenharmony_ci{
120425bb815Sopenharmony_ci  lit_magic_string_id_t type_string;
121425bb815Sopenharmony_ci
122425bb815Sopenharmony_ci  if (ecma_is_value_undefined (this_arg))
123425bb815Sopenharmony_ci  {
124425bb815Sopenharmony_ci    type_string = LIT_MAGIC_STRING_UNDEFINED_UL;
125425bb815Sopenharmony_ci  }
126425bb815Sopenharmony_ci  else if (ecma_is_value_null (this_arg))
127425bb815Sopenharmony_ci  {
128425bb815Sopenharmony_ci    type_string = LIT_MAGIC_STRING_NULL_UL;
129425bb815Sopenharmony_ci  }
130425bb815Sopenharmony_ci  else
131425bb815Sopenharmony_ci  {
132425bb815Sopenharmony_ci    ecma_value_t obj_this = ecma_op_to_object (this_arg);
133425bb815Sopenharmony_ci
134425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (obj_this))
135425bb815Sopenharmony_ci    {
136425bb815Sopenharmony_ci      return obj_this;
137425bb815Sopenharmony_ci    }
138425bb815Sopenharmony_ci
139425bb815Sopenharmony_ci    JERRY_ASSERT (ecma_is_value_object (obj_this));
140425bb815Sopenharmony_ci
141425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
142425bb815Sopenharmony_ci
143425bb815Sopenharmony_ci    type_string = ecma_object_get_class_name (obj_p);
144425bb815Sopenharmony_ci
145425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
146425bb815Sopenharmony_ci    ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG);
147425bb815Sopenharmony_ci
148425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (tag_value))
149425bb815Sopenharmony_ci    {
150425bb815Sopenharmony_ci      ecma_deref_object (obj_p);
151425bb815Sopenharmony_ci      return tag_value;
152425bb815Sopenharmony_ci    }
153425bb815Sopenharmony_ci
154425bb815Sopenharmony_ci    if (ecma_is_value_string (tag_value))
155425bb815Sopenharmony_ci    {
156425bb815Sopenharmony_ci      ecma_deref_object (obj_p);
157425bb815Sopenharmony_ci      return ecma_builtin_helper_object_to_string_tag_helper (tag_value);
158425bb815Sopenharmony_ci    }
159425bb815Sopenharmony_ci
160425bb815Sopenharmony_ci    ecma_free_value (tag_value);
161425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_ci    ecma_deref_object (obj_p);
164425bb815Sopenharmony_ci  }
165425bb815Sopenharmony_ci
166425bb815Sopenharmony_ci  ecma_string_t *ret_string_p;
167425bb815Sopenharmony_ci
168425bb815Sopenharmony_ci  /* Building string "[object #type#]" where type is 'Undefined',
169425bb815Sopenharmony_ci     'Null' or one of possible object's classes.
170425bb815Sopenharmony_ci     The string with null character is maximum 27 characters long. */
171425bb815Sopenharmony_ci  const lit_utf8_size_t buffer_size = 27;
172425bb815Sopenharmony_ci  JERRY_VLA (lit_utf8_byte_t, str_buffer, buffer_size);
173425bb815Sopenharmony_ci
174425bb815Sopenharmony_ci  lit_utf8_byte_t *buffer_ptr = str_buffer;
175425bb815Sopenharmony_ci
176425bb815Sopenharmony_ci  const lit_magic_string_id_t magic_string_ids[] =
177425bb815Sopenharmony_ci  {
178425bb815Sopenharmony_ci    LIT_MAGIC_STRING_LEFT_SQUARE_CHAR,
179425bb815Sopenharmony_ci    LIT_MAGIC_STRING_OBJECT,
180425bb815Sopenharmony_ci    LIT_MAGIC_STRING_SPACE_CHAR,
181425bb815Sopenharmony_ci    type_string,
182425bb815Sopenharmony_ci    LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR
183425bb815Sopenharmony_ci  };
184425bb815Sopenharmony_ci
185425bb815Sopenharmony_ci  for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i)
186425bb815Sopenharmony_ci  {
187425bb815Sopenharmony_ci    buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr,
188425bb815Sopenharmony_ci                                                  (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
189425bb815Sopenharmony_ci    JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
190425bb815Sopenharmony_ci  }
191425bb815Sopenharmony_ci
192425bb815Sopenharmony_ci  ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));
193425bb815Sopenharmony_ci
194425bb815Sopenharmony_ci  return ecma_make_string_value (ret_string_p);
195425bb815Sopenharmony_ci} /* ecma_builtin_helper_object_to_string */
196425bb815Sopenharmony_ci
197425bb815Sopenharmony_ci/**
198425bb815Sopenharmony_ci * The Array.prototype's 'toLocaleString' single element operation routine
199425bb815Sopenharmony_ci *
200425bb815Sopenharmony_ci * See also:
201425bb815Sopenharmony_ci *          ECMA-262 v5, 15.4.4.3 steps 6-8 and 10.b-d
202425bb815Sopenharmony_ci *
203425bb815Sopenharmony_ci * @return ecma value
204425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
205425bb815Sopenharmony_ci */
206425bb815Sopenharmony_ciecma_string_t *
207425bb815Sopenharmony_ciecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /**< this object */
208425bb815Sopenharmony_ci                                                   uint32_t index) /**< array index */
209425bb815Sopenharmony_ci{
210425bb815Sopenharmony_ci  ecma_value_t index_value = ecma_op_object_get_by_uint32_index (obj_p, index);
211425bb815Sopenharmony_ci
212425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (index_value))
213425bb815Sopenharmony_ci  {
214425bb815Sopenharmony_ci    return NULL;
215425bb815Sopenharmony_ci  }
216425bb815Sopenharmony_ci
217425bb815Sopenharmony_ci  if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value))
218425bb815Sopenharmony_ci  {
219425bb815Sopenharmony_ci    return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
220425bb815Sopenharmony_ci  }
221425bb815Sopenharmony_ci
222425bb815Sopenharmony_ci  ecma_value_t index_obj_value = ecma_op_to_object (index_value);
223425bb815Sopenharmony_ci
224425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (index_obj_value))
225425bb815Sopenharmony_ci  {
226425bb815Sopenharmony_ci    ecma_free_value (index_value);
227425bb815Sopenharmony_ci    return NULL;
228425bb815Sopenharmony_ci  }
229425bb815Sopenharmony_ci
230425bb815Sopenharmony_ci  ecma_string_t *ret_string_p = NULL;
231425bb815Sopenharmony_ci  ecma_object_t *index_obj_p = ecma_get_object_from_value (index_obj_value);
232425bb815Sopenharmony_ci  ecma_value_t to_locale_value = ecma_op_object_get_by_magic_id (index_obj_p, LIT_MAGIC_STRING_TO_LOCALE_STRING_UL);
233425bb815Sopenharmony_ci
234425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (to_locale_value))
235425bb815Sopenharmony_ci  {
236425bb815Sopenharmony_ci    goto cleanup;
237425bb815Sopenharmony_ci  }
238425bb815Sopenharmony_ci
239425bb815Sopenharmony_ci  if (!ecma_op_is_callable (to_locale_value))
240425bb815Sopenharmony_ci  {
241425bb815Sopenharmony_ci    ecma_free_value (to_locale_value);
242425bb815Sopenharmony_ci    ecma_raise_type_error (ECMA_ERR_MSG ("'toLocaleString' is missing or not a function."));
243425bb815Sopenharmony_ci    goto cleanup;
244425bb815Sopenharmony_ci  }
245425bb815Sopenharmony_ci
246425bb815Sopenharmony_ci  ecma_object_t *locale_func_obj_p = ecma_get_object_from_value (to_locale_value);
247425bb815Sopenharmony_ci  ecma_value_t call_value = ecma_op_function_call (locale_func_obj_p,
248425bb815Sopenharmony_ci                                                   index_obj_value,
249425bb815Sopenharmony_ci                                                   NULL,
250425bb815Sopenharmony_ci                                                   0);
251425bb815Sopenharmony_ci  ecma_deref_object (locale_func_obj_p);
252425bb815Sopenharmony_ci
253425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (call_value))
254425bb815Sopenharmony_ci  {
255425bb815Sopenharmony_ci    goto cleanup;
256425bb815Sopenharmony_ci  }
257425bb815Sopenharmony_ci
258425bb815Sopenharmony_ci  ret_string_p = ecma_op_to_string (call_value);
259425bb815Sopenharmony_ci  ecma_free_value (call_value);
260425bb815Sopenharmony_ci
261425bb815Sopenharmony_cicleanup:
262425bb815Sopenharmony_ci  ecma_deref_object (index_obj_p);
263425bb815Sopenharmony_ci  ecma_free_value (index_value);
264425bb815Sopenharmony_ci
265425bb815Sopenharmony_ci  return ret_string_p;
266425bb815Sopenharmony_ci} /* ecma_builtin_helper_get_to_locale_string_at_index */
267425bb815Sopenharmony_ci
268425bb815Sopenharmony_ci/**
269425bb815Sopenharmony_ci * The Object.keys and Object.getOwnPropertyNames routine's common part.
270425bb815Sopenharmony_ci *
271425bb815Sopenharmony_ci * See also:
272425bb815Sopenharmony_ci *          ECMA-262 v5, 15.2.3.4 steps 2-5
273425bb815Sopenharmony_ci *          ECMA-262 v5, 15.2.3.14 steps 3-6
274425bb815Sopenharmony_ci *
275425bb815Sopenharmony_ci * @return ecma value - Array of property names.
276425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
277425bb815Sopenharmony_ci */
278425bb815Sopenharmony_ciecma_value_t
279425bb815Sopenharmony_ciecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */
280425bb815Sopenharmony_ci                                           uint32_t opts) /**< any combination of ecma_list_properties_options_t */
281425bb815Sopenharmony_ci{
282425bb815Sopenharmony_ci  JERRY_ASSERT (obj_p != NULL);
283425bb815Sopenharmony_ci
284425bb815Sopenharmony_ci  ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, opts);
285425bb815Sopenharmony_ci
286425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
287425bb815Sopenharmony_ci  if (props_p == NULL)
288425bb815Sopenharmony_ci  {
289425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
290425bb815Sopenharmony_ci  }
291425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
292425bb815Sopenharmony_ci
293425bb815Sopenharmony_ci  if (props_p->item_count == 0)
294425bb815Sopenharmony_ci  {
295425bb815Sopenharmony_ci    ecma_collection_destroy (props_p);
296425bb815Sopenharmony_ci    return ecma_op_create_array_object (NULL, 0, false);
297425bb815Sopenharmony_ci  }
298425bb815Sopenharmony_ci
299425bb815Sopenharmony_ci  ecma_value_t new_array = ecma_op_create_array_object (props_p->buffer_p, props_p->item_count, false);
300425bb815Sopenharmony_ci  ecma_collection_free (props_p);
301425bb815Sopenharmony_ci
302425bb815Sopenharmony_ci  return new_array;
303425bb815Sopenharmony_ci} /* ecma_builtin_helper_object_get_properties */
304425bb815Sopenharmony_ci
305425bb815Sopenharmony_ci/**
306425bb815Sopenharmony_ci * Helper function to normalizing an array index
307425bb815Sopenharmony_ci *
308425bb815Sopenharmony_ci * See also:
309425bb815Sopenharmony_ci *          ECMA-262 v5, 15.4.4.10 steps 5, 6, 7 part 2, 8
310425bb815Sopenharmony_ci *          ECMA-262 v5, 15.4.4.12 steps 5, 6
311425bb815Sopenharmony_ci *          ECMA-262 v5, 15.5.4.13 steps 4 - 7
312425bb815Sopenharmony_ci *          ECMA-262 v6, 22.1.3.6 steps 5 - 7, 8 part 2, 9, 10
313425bb815Sopenharmony_ci *          ECMA-262 v6, 22.1.3.3 steps 5 - 10, 11 part 2, 12, 13
314425bb815Sopenharmony_ci *          ECMA-262 v6, 22.2.3.5 steps 5 - 10, 11 part 2, 12, 13
315425bb815Sopenharmony_ci *          ECMA-262 v6, 22.2.3.23 steps 5 - 10
316425bb815Sopenharmony_ci *          ECMA-262 v6, 24.1.4.3 steps 6 - 8, 9 part 2, 10, 11
317425bb815Sopenharmony_ci *          ECMA-262 v6, 22.2.3.26 steps 7 - 9, 10 part 2, 11, 12
318425bb815Sopenharmony_ci *          ECMA-262 v6, 22.2.3.8 steps 5 - 7, 8 part 2, 9, 10
319425bb815Sopenharmony_ci *
320425bb815Sopenharmony_ci * Used by:
321425bb815Sopenharmony_ci *         - The Array.prototype.slice routine.
322425bb815Sopenharmony_ci *         - The Array.prototype.splice routine.
323425bb815Sopenharmony_ci *         - The String.prototype.slice routine.
324425bb815Sopenharmony_ci *         - The Array.prototype.fill routine.
325425bb815Sopenharmony_ci *         - The Array.prototype.copyWithin routine.
326425bb815Sopenharmony_ci *         - The TypedArray.prototype.copyWithin routine.
327425bb815Sopenharmony_ci *         - The TypedArray.prototype.slice routine.
328425bb815Sopenharmony_ci *         - The ArrayBuffer.prototype.slice routine.
329425bb815Sopenharmony_ci *         - The TypedArray.prototype.subarray routine.
330425bb815Sopenharmony_ci *         - The TypedArray.prototype.fill routine.
331425bb815Sopenharmony_ci *
332425bb815Sopenharmony_ci * @return ECMA_VALUE_EMPTY if successful
333425bb815Sopenharmony_ci *         conversion error otherwise
334425bb815Sopenharmony_ci */
335425bb815Sopenharmony_ciuint32_t
336425bb815Sopenharmony_ciecma_builtin_helper_array_index_normalize (ecma_value_t arg, /**< index */
337425bb815Sopenharmony_ci                                           uint32_t length, /**< array's length */
338425bb815Sopenharmony_ci                                           uint32_t *number_p) /**< [out] uint32_t */
339425bb815Sopenharmony_ci{
340425bb815Sopenharmony_ci  ecma_number_t to_int;
341425bb815Sopenharmony_ci
342425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg, &to_int)))
343425bb815Sopenharmony_ci  {
344425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
345425bb815Sopenharmony_ci  }
346425bb815Sopenharmony_ci
347425bb815Sopenharmony_ci  *number_p = ((to_int < 0) ? (uint32_t) JERRY_MAX ((length + to_int), 0)
348425bb815Sopenharmony_ci                            : (uint32_t) JERRY_MIN (to_int, length));
349425bb815Sopenharmony_ci
350425bb815Sopenharmony_ci  return ECMA_VALUE_EMPTY;
351425bb815Sopenharmony_ci} /* ecma_builtin_helper_array_index_normalize */
352425bb815Sopenharmony_ci
353425bb815Sopenharmony_ci/**
354425bb815Sopenharmony_ci * Helper function for concatenating an ecma_value_t to an Array.
355425bb815Sopenharmony_ci *
356425bb815Sopenharmony_ci * See also:
357425bb815Sopenharmony_ci *          ECMA-262 v5, 15.4.4.4 steps 5.b - 5.c
358425bb815Sopenharmony_ci *
359425bb815Sopenharmony_ci * Used by:
360425bb815Sopenharmony_ci *         - The Array.prototype.concat routine.
361425bb815Sopenharmony_ci *
362425bb815Sopenharmony_ci * @return ecma value
363425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
364425bb815Sopenharmony_ci */
365425bb815Sopenharmony_ciecma_value_t
366425bb815Sopenharmony_ciecma_builtin_helper_array_concat_value (ecma_object_t *array_obj_p, /**< array */
367425bb815Sopenharmony_ci                                        uint32_t *length_p, /**< [in,out] array's length */
368425bb815Sopenharmony_ci                                        ecma_value_t value) /**< value to concat */
369425bb815Sopenharmony_ci{
370425bb815Sopenharmony_ci  /* 5.b */
371425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
372425bb815Sopenharmony_ci  ecma_value_t is_spreadable = ecma_op_is_concat_spreadable (value);
373425bb815Sopenharmony_ci
374425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (is_spreadable))
375425bb815Sopenharmony_ci  {
376425bb815Sopenharmony_ci    return is_spreadable;
377425bb815Sopenharmony_ci  }
378425bb815Sopenharmony_ci
379425bb815Sopenharmony_ci  bool spread_object = is_spreadable == ECMA_VALUE_TRUE;
380425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_ES2015) */
381425bb815Sopenharmony_ci  bool spread_object = ecma_is_value_true (ecma_is_value_array (value));
382425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
383425bb815Sopenharmony_ci
384425bb815Sopenharmony_ci  if (spread_object)
385425bb815Sopenharmony_ci  {
386425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (value);
387425bb815Sopenharmony_ci
388425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
389425bb815Sopenharmony_ci    uint32_t arg_len;
390425bb815Sopenharmony_ci    ecma_value_t error = ecma_op_object_get_length (obj_p, &arg_len);
391425bb815Sopenharmony_ci
392425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (error))
393425bb815Sopenharmony_ci    {
394425bb815Sopenharmony_ci      return error;
395425bb815Sopenharmony_ci    }
396425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_ES2015) */
397425bb815Sopenharmony_ci    /* 5.b.ii */
398425bb815Sopenharmony_ci    uint32_t arg_len = ecma_array_get_length (obj_p);
399425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
400425bb815Sopenharmony_ci    /* 5.b.iii */
401425bb815Sopenharmony_ci    for (uint32_t array_index = 0; array_index < arg_len; array_index++)
402425bb815Sopenharmony_ci    {
403425bb815Sopenharmony_ci      /* 5.b.iii.2 */
404425bb815Sopenharmony_ci      ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, array_index);
405425bb815Sopenharmony_ci
406425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (get_value))
407425bb815Sopenharmony_ci      {
408425bb815Sopenharmony_ci        return get_value;
409425bb815Sopenharmony_ci      }
410425bb815Sopenharmony_ci
411425bb815Sopenharmony_ci      if (!ecma_is_value_found (get_value))
412425bb815Sopenharmony_ci      {
413425bb815Sopenharmony_ci        continue;
414425bb815Sopenharmony_ci      }
415425bb815Sopenharmony_ci
416425bb815Sopenharmony_ci      /* 5.b.iii.3.b */
417425bb815Sopenharmony_ci      /* This will always be a simple value since 'is_throw' is false, so no need to free. */
418425bb815Sopenharmony_ci      ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p,
419425bb815Sopenharmony_ci                                                                     *length_p + array_index,
420425bb815Sopenharmony_ci                                                                     get_value,
421425bb815Sopenharmony_ci                                                                     ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
422425bb815Sopenharmony_ci
423425bb815Sopenharmony_ci      JERRY_ASSERT (ecma_is_value_true (put_comp));
424425bb815Sopenharmony_ci      ecma_free_value (get_value);
425425bb815Sopenharmony_ci    }
426425bb815Sopenharmony_ci
427425bb815Sopenharmony_ci    *length_p += arg_len;
428425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
429425bb815Sopenharmony_ci  }
430425bb815Sopenharmony_ci
431425bb815Sopenharmony_ci  /* 5.c.i */
432425bb815Sopenharmony_ci  /* This will always be a simple value since 'is_throw' is false, so no need to free. */
433425bb815Sopenharmony_ci  ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p,
434425bb815Sopenharmony_ci                                                                 (*length_p)++,
435425bb815Sopenharmony_ci                                                                 value,
436425bb815Sopenharmony_ci                                                                 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
437425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_true (put_comp));
438425bb815Sopenharmony_ci
439425bb815Sopenharmony_ci  return ECMA_VALUE_EMPTY;
440425bb815Sopenharmony_ci} /* ecma_builtin_helper_array_concat_value */
441425bb815Sopenharmony_ci
442425bb815Sopenharmony_ci/**
443425bb815Sopenharmony_ci * Helper function to normalizing a string index
444425bb815Sopenharmony_ci *
445425bb815Sopenharmony_ci * This function clamps the given index to the [0, length] range.
446425bb815Sopenharmony_ci * If the index is negative, 0 value is used.
447425bb815Sopenharmony_ci * If the index is greater than the length of the string, the normalized index will be the length of the string.
448425bb815Sopenharmony_ci * NaN is mapped to zero or length depending on the nan_to_zero parameter.
449425bb815Sopenharmony_ci *
450425bb815Sopenharmony_ci * See also:
451425bb815Sopenharmony_ci *          ECMA-262 v5, 15.5.4.15
452425bb815Sopenharmony_ci *
453425bb815Sopenharmony_ci * Used by:
454425bb815Sopenharmony_ci *         - The String.prototype.substring routine.
455425bb815Sopenharmony_ci *         - The ecma_builtin_helper_string_prototype_object_index_of helper routine.
456425bb815Sopenharmony_ci *
457425bb815Sopenharmony_ci * @return uint32_t - the normalized value of the index
458425bb815Sopenharmony_ci */
459425bb815Sopenharmony_ciuint32_t
460425bb815Sopenharmony_ciecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */
461425bb815Sopenharmony_ci                                            uint32_t length, /**< string's length */
462425bb815Sopenharmony_ci                                            bool nan_to_zero) /**< whether NaN is mapped to zero (t) or length (f) */
463425bb815Sopenharmony_ci{
464425bb815Sopenharmony_ci  uint32_t norm_index = 0;
465425bb815Sopenharmony_ci
466425bb815Sopenharmony_ci  if (ecma_number_is_nan (index))
467425bb815Sopenharmony_ci  {
468425bb815Sopenharmony_ci    if (!nan_to_zero)
469425bb815Sopenharmony_ci    {
470425bb815Sopenharmony_ci      norm_index = length;
471425bb815Sopenharmony_ci    }
472425bb815Sopenharmony_ci  }
473425bb815Sopenharmony_ci  else if (!ecma_number_is_negative (index))
474425bb815Sopenharmony_ci  {
475425bb815Sopenharmony_ci    if (ecma_number_is_infinity (index))
476425bb815Sopenharmony_ci    {
477425bb815Sopenharmony_ci      norm_index = length;
478425bb815Sopenharmony_ci    }
479425bb815Sopenharmony_ci    else
480425bb815Sopenharmony_ci    {
481425bb815Sopenharmony_ci      norm_index = ecma_number_to_uint32 (index);
482425bb815Sopenharmony_ci
483425bb815Sopenharmony_ci      if (norm_index > length)
484425bb815Sopenharmony_ci      {
485425bb815Sopenharmony_ci        norm_index = length;
486425bb815Sopenharmony_ci      }
487425bb815Sopenharmony_ci    }
488425bb815Sopenharmony_ci  }
489425bb815Sopenharmony_ci
490425bb815Sopenharmony_ci  return norm_index;
491425bb815Sopenharmony_ci} /* ecma_builtin_helper_string_index_normalize */
492425bb815Sopenharmony_ci
493425bb815Sopenharmony_ci/**
494425bb815Sopenharmony_ci * Helper function for string indexOf, lastIndexOf, startsWith, includes, endsWith functions
495425bb815Sopenharmony_ci *
496425bb815Sopenharmony_ci * See also:
497425bb815Sopenharmony_ci *          ECMA-262 v5, 15.5.4.7
498425bb815Sopenharmony_ci *          ECMA-262 v5, 15.5.4.8
499425bb815Sopenharmony_ci *          ECMA-262 v6, 21.1.3.6
500425bb815Sopenharmony_ci *          ECMA-262 v6, 21.1.3.7
501425bb815Sopenharmony_ci *          ECMA-262 v6, 21.1.3.18
502425bb815Sopenharmony_ci *
503425bb815Sopenharmony_ci * Used by:
504425bb815Sopenharmony_ci *         - The String.prototype.indexOf routine.
505425bb815Sopenharmony_ci *         - The String.prototype.lastIndexOf routine.
506425bb815Sopenharmony_ci *         - The String.prototype.startsWith routine.
507425bb815Sopenharmony_ci *         - The String.prototype.includes routine.
508425bb815Sopenharmony_ci *         - The String.prototype.endsWith routine.
509425bb815Sopenharmony_ci *
510425bb815Sopenharmony_ci * @return ecma_value_t - Returns index (last index) or a
511425bb815Sopenharmony_ci *                        boolean value
512425bb815Sopenharmony_ci */
513425bb815Sopenharmony_ciecma_value_t
514425bb815Sopenharmony_ciecma_builtin_helper_string_prototype_object_index_of (ecma_string_t *original_str_p, /**< this argument */
515425bb815Sopenharmony_ci                                                      ecma_value_t arg1, /**< routine's first argument */
516425bb815Sopenharmony_ci                                                      ecma_value_t arg2, /**< routine's second argument */
517425bb815Sopenharmony_ci                                                      ecma_string_index_of_mode_t mode) /**< routine's mode */
518425bb815Sopenharmony_ci{
519425bb815Sopenharmony_ci  /* 5 (indexOf) -- 6 (lastIndexOf) */
520425bb815Sopenharmony_ci  const ecma_length_t original_len = ecma_string_get_length (original_str_p);
521425bb815Sopenharmony_ci
522425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
523425bb815Sopenharmony_ci  /* 4, 6 (startsWith, includes, endsWith) */
524425bb815Sopenharmony_ci  if (mode >= ECMA_STRING_STARTS_WITH)
525425bb815Sopenharmony_ci  {
526425bb815Sopenharmony_ci    ecma_value_t regexp = ecma_op_is_regexp (arg1);
527425bb815Sopenharmony_ci
528425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (regexp))
529425bb815Sopenharmony_ci    {
530425bb815Sopenharmony_ci      return regexp;
531425bb815Sopenharmony_ci    }
532425bb815Sopenharmony_ci
533425bb815Sopenharmony_ci    if (regexp == ECMA_VALUE_TRUE)
534425bb815Sopenharmony_ci    {
535425bb815Sopenharmony_ci      JERRY_ASSERT (ECMA_STRING_LAST_INDEX_OF < mode && mode <= ECMA_STRING_ENDS_WITH);
536425bb815Sopenharmony_ci      return ecma_raise_type_error (ECMA_ERR_MSG ("Search string can't be of type: RegExp"));
537425bb815Sopenharmony_ci    }
538425bb815Sopenharmony_ci  }
539425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
540425bb815Sopenharmony_ci
541425bb815Sopenharmony_ci  /* 7, 8 */
542425bb815Sopenharmony_ci  ecma_string_t *search_str_p = ecma_op_to_string (arg1);
543425bb815Sopenharmony_ci
544425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (search_str_p == NULL))
545425bb815Sopenharmony_ci  {
546425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
547425bb815Sopenharmony_ci  }
548425bb815Sopenharmony_ci
549425bb815Sopenharmony_ci  /* 4 (indexOf, lastIndexOf), 9 (startsWith, includes), 10 (endsWith) */
550425bb815Sopenharmony_ci  ecma_number_t pos_num;
551425bb815Sopenharmony_ci  ecma_value_t ret_value;
552425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
553425bb815Sopenharmony_ci  if (mode > ECMA_STRING_LAST_INDEX_OF)
554425bb815Sopenharmony_ci  {
555425bb815Sopenharmony_ci    ret_value = ecma_op_to_integer (arg2, &pos_num);
556425bb815Sopenharmony_ci  }
557425bb815Sopenharmony_ci  else
558425bb815Sopenharmony_ci  {
559425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
560425bb815Sopenharmony_ci    ret_value = ecma_get_number (arg2, &pos_num);
561425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
562425bb815Sopenharmony_ci  }
563425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
564425bb815Sopenharmony_ci
565425bb815Sopenharmony_ci  /* 10 (startsWith, includes), 11 (endsWith) */
566425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (ret_value))
567425bb815Sopenharmony_ci  {
568425bb815Sopenharmony_ci    ecma_deref_ecma_string (search_str_p);
569425bb815Sopenharmony_ci    return ret_value;
570425bb815Sopenharmony_ci  }
571425bb815Sopenharmony_ci
572425bb815Sopenharmony_ci  bool use_first_index = mode != ECMA_STRING_LAST_INDEX_OF;
573425bb815Sopenharmony_ci
574425bb815Sopenharmony_ci  /* 4b, 6 (indexOf) - 4b, 5, 7 (lastIndexOf) */
575425bb815Sopenharmony_ci  ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, use_first_index);
576425bb815Sopenharmony_ci
577425bb815Sopenharmony_ci  ecma_number_t ret_num = ECMA_NUMBER_MINUS_ONE;
578425bb815Sopenharmony_ci
579425bb815Sopenharmony_ci  ecma_length_t index_of = 0;
580425bb815Sopenharmony_ci
581425bb815Sopenharmony_ci  ret_value = ECMA_VALUE_FALSE;
582425bb815Sopenharmony_ci
583425bb815Sopenharmony_ci  switch (mode)
584425bb815Sopenharmony_ci  {
585425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
586425bb815Sopenharmony_ci    case ECMA_STRING_STARTS_WITH:
587425bb815Sopenharmony_ci    {
588425bb815Sopenharmony_ci      const ecma_length_t search_len = ecma_string_get_length (search_str_p);
589425bb815Sopenharmony_ci
590425bb815Sopenharmony_ci      if (search_len + start > original_len)
591425bb815Sopenharmony_ci      {
592425bb815Sopenharmony_ci        break;
593425bb815Sopenharmony_ci      }
594425bb815Sopenharmony_ci
595425bb815Sopenharmony_ci      if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true, start, &index_of))
596425bb815Sopenharmony_ci      {
597425bb815Sopenharmony_ci        /* 15, 16 (startsWith) */
598425bb815Sopenharmony_ci        ret_value = ecma_make_boolean_value (index_of == start);
599425bb815Sopenharmony_ci      }
600425bb815Sopenharmony_ci      break;
601425bb815Sopenharmony_ci    }
602425bb815Sopenharmony_ci    case ECMA_STRING_INCLUDES:
603425bb815Sopenharmony_ci    {
604425bb815Sopenharmony_ci      if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true, start, &index_of))
605425bb815Sopenharmony_ci      {
606425bb815Sopenharmony_ci        ret_value = ECMA_VALUE_TRUE;
607425bb815Sopenharmony_ci      }
608425bb815Sopenharmony_ci      break;
609425bb815Sopenharmony_ci    }
610425bb815Sopenharmony_ci    case ECMA_STRING_ENDS_WITH:
611425bb815Sopenharmony_ci    {
612425bb815Sopenharmony_ci      if (start == 0)
613425bb815Sopenharmony_ci      {
614425bb815Sopenharmony_ci        start = original_len;
615425bb815Sopenharmony_ci      }
616425bb815Sopenharmony_ci
617425bb815Sopenharmony_ci      ecma_length_t search_str_len = ecma_string_get_length (search_str_p);
618425bb815Sopenharmony_ci
619425bb815Sopenharmony_ci      if (search_str_len == 0)
620425bb815Sopenharmony_ci      {
621425bb815Sopenharmony_ci        ret_value = ECMA_VALUE_TRUE;
622425bb815Sopenharmony_ci        break;
623425bb815Sopenharmony_ci      }
624425bb815Sopenharmony_ci
625425bb815Sopenharmony_ci      int32_t start_ends_with = (int32_t) (start - search_str_len);
626425bb815Sopenharmony_ci
627425bb815Sopenharmony_ci      if (start_ends_with < 0)
628425bb815Sopenharmony_ci      {
629425bb815Sopenharmony_ci        break;
630425bb815Sopenharmony_ci      }
631425bb815Sopenharmony_ci      if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true,
632425bb815Sopenharmony_ci                                                 (ecma_length_t) start_ends_with, &index_of))
633425bb815Sopenharmony_ci      {
634425bb815Sopenharmony_ci        ret_value = ecma_make_boolean_value (index_of == (ecma_length_t) start_ends_with);
635425bb815Sopenharmony_ci      }
636425bb815Sopenharmony_ci      break;
637425bb815Sopenharmony_ci    }
638425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
639425bb815Sopenharmony_ci
640425bb815Sopenharmony_ci    case ECMA_STRING_INDEX_OF:
641425bb815Sopenharmony_ci    case ECMA_STRING_LAST_INDEX_OF:
642425bb815Sopenharmony_ci    default:
643425bb815Sopenharmony_ci    {
644425bb815Sopenharmony_ci      /* 8 (indexOf) -- 9 (lastIndexOf) */
645425bb815Sopenharmony_ci      if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, use_first_index, start, &index_of))
646425bb815Sopenharmony_ci      {
647425bb815Sopenharmony_ci        ret_num = ((ecma_number_t) index_of);
648425bb815Sopenharmony_ci      }
649425bb815Sopenharmony_ci      ret_value = ecma_make_number_value (ret_num);
650425bb815Sopenharmony_ci      break;
651425bb815Sopenharmony_ci    }
652425bb815Sopenharmony_ci  }
653425bb815Sopenharmony_ci
654425bb815Sopenharmony_ci  ecma_deref_ecma_string (search_str_p);
655425bb815Sopenharmony_ci
656425bb815Sopenharmony_ci  return ret_value;
657425bb815Sopenharmony_ci} /* ecma_builtin_helper_string_prototype_object_index_of */
658425bb815Sopenharmony_ci
659425bb815Sopenharmony_ci/**
660425bb815Sopenharmony_ci * Helper function for finding index of a search string
661425bb815Sopenharmony_ci *
662425bb815Sopenharmony_ci * This function clamps the given index to the [0, length] range.
663425bb815Sopenharmony_ci * If the index is negative, 0 value is used.
664425bb815Sopenharmony_ci * If the index is greater than the length of the string, the normalized index will be the length of the string.
665425bb815Sopenharmony_ci * NaN is mapped to zero or length depending on the nan_to_zero parameter.
666425bb815Sopenharmony_ci *
667425bb815Sopenharmony_ci * See also:
668425bb815Sopenharmony_ci *          ECMA-262 v5, 15.5.4.7,8,11
669425bb815Sopenharmony_ci *
670425bb815Sopenharmony_ci * Used by:
671425bb815Sopenharmony_ci *         - The ecma_builtin_helper_string_prototype_object_index_of helper routine.
672425bb815Sopenharmony_ci *         - The ecma_builtin_string_prototype_object_replace_match helper routine.
673425bb815Sopenharmony_ci *
674425bb815Sopenharmony_ci * @return bool - whether there is a match for the search string
675425bb815Sopenharmony_ci */
676425bb815Sopenharmony_cibool
677425bb815Sopenharmony_ciecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index */
678425bb815Sopenharmony_ci                                       ecma_string_t *search_str_p, /**< string's length */
679425bb815Sopenharmony_ci                                       bool first_index, /**< whether search for first (t) or last (f) index */
680425bb815Sopenharmony_ci                                       ecma_length_t start_pos, /**< start position */
681425bb815Sopenharmony_ci                                       ecma_length_t *ret_index_p) /**< [out] position found in original string */
682425bb815Sopenharmony_ci{
683425bb815Sopenharmony_ci  bool match_found = false;
684425bb815Sopenharmony_ci  const ecma_length_t original_len = ecma_string_get_length (original_str_p);
685425bb815Sopenharmony_ci  const ecma_length_t search_len = ecma_string_get_length (search_str_p);
686425bb815Sopenharmony_ci
687425bb815Sopenharmony_ci  if (search_len <= original_len)
688425bb815Sopenharmony_ci  {
689425bb815Sopenharmony_ci    if (!search_len)
690425bb815Sopenharmony_ci    {
691425bb815Sopenharmony_ci      match_found = true;
692425bb815Sopenharmony_ci      *ret_index_p = first_index ? start_pos : original_len;
693425bb815Sopenharmony_ci    }
694425bb815Sopenharmony_ci    else
695425bb815Sopenharmony_ci    {
696425bb815Sopenharmony_ci      /* create utf8 string from original string and advance to position */
697425bb815Sopenharmony_ci      ECMA_STRING_TO_UTF8_STRING (original_str_p, original_str_utf8_p, original_str_size);
698425bb815Sopenharmony_ci
699425bb815Sopenharmony_ci      ecma_length_t index = start_pos;
700425bb815Sopenharmony_ci
701425bb815Sopenharmony_ci      const lit_utf8_byte_t *original_str_curr_p = original_str_utf8_p;
702425bb815Sopenharmony_ci      for (ecma_length_t idx = 0; idx < index; idx++)
703425bb815Sopenharmony_ci      {
704425bb815Sopenharmony_ci        lit_utf8_incr (&original_str_curr_p);
705425bb815Sopenharmony_ci      }
706425bb815Sopenharmony_ci
707425bb815Sopenharmony_ci      /* create utf8 string from search string */
708425bb815Sopenharmony_ci      ECMA_STRING_TO_UTF8_STRING (search_str_p, search_str_utf8_p, search_str_size);
709425bb815Sopenharmony_ci
710425bb815Sopenharmony_ci      const lit_utf8_byte_t *search_str_curr_p = search_str_utf8_p;
711425bb815Sopenharmony_ci
712425bb815Sopenharmony_ci      /* iterate original string and try to match at each position */
713425bb815Sopenharmony_ci      bool searching = true;
714425bb815Sopenharmony_ci      ecma_char_t first_char = lit_cesu8_read_next (&search_str_curr_p);
715425bb815Sopenharmony_ci      while (searching)
716425bb815Sopenharmony_ci      {
717425bb815Sopenharmony_ci        /* match as long as possible */
718425bb815Sopenharmony_ci        ecma_length_t match_len = 0;
719425bb815Sopenharmony_ci        const lit_utf8_byte_t *stored_original_str_curr_p = original_str_curr_p;
720425bb815Sopenharmony_ci
721425bb815Sopenharmony_ci        if (match_len < search_len &&
722425bb815Sopenharmony_ci            index + match_len < original_len &&
723425bb815Sopenharmony_ci            lit_cesu8_read_next (&original_str_curr_p) == first_char)
724425bb815Sopenharmony_ci        {
725425bb815Sopenharmony_ci          const lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p;
726425bb815Sopenharmony_ci          match_len++;
727425bb815Sopenharmony_ci
728425bb815Sopenharmony_ci          while (match_len < search_len &&
729425bb815Sopenharmony_ci                 index + match_len < original_len &&
730425bb815Sopenharmony_ci                 lit_cesu8_read_next (&original_str_curr_p) == lit_cesu8_read_next (&nested_search_str_curr_p))
731425bb815Sopenharmony_ci          {
732425bb815Sopenharmony_ci            match_len++;
733425bb815Sopenharmony_ci          }
734425bb815Sopenharmony_ci        }
735425bb815Sopenharmony_ci
736425bb815Sopenharmony_ci        /* check for match */
737425bb815Sopenharmony_ci        if (match_len == search_len)
738425bb815Sopenharmony_ci        {
739425bb815Sopenharmony_ci          match_found = true;
740425bb815Sopenharmony_ci          *ret_index_p = index;
741425bb815Sopenharmony_ci
742425bb815Sopenharmony_ci          break;
743425bb815Sopenharmony_ci        }
744425bb815Sopenharmony_ci        else
745425bb815Sopenharmony_ci        {
746425bb815Sopenharmony_ci          /* inc/dec index and update iterators and search condition */
747425bb815Sopenharmony_ci          original_str_curr_p = stored_original_str_curr_p;
748425bb815Sopenharmony_ci
749425bb815Sopenharmony_ci          if (first_index)
750425bb815Sopenharmony_ci          {
751425bb815Sopenharmony_ci            if ((searching = (index <= original_len - search_len)))
752425bb815Sopenharmony_ci            {
753425bb815Sopenharmony_ci              lit_utf8_incr (&original_str_curr_p);
754425bb815Sopenharmony_ci              index++;
755425bb815Sopenharmony_ci            }
756425bb815Sopenharmony_ci          }
757425bb815Sopenharmony_ci          else
758425bb815Sopenharmony_ci          {
759425bb815Sopenharmony_ci            if ((searching = (index > 0)))
760425bb815Sopenharmony_ci            {
761425bb815Sopenharmony_ci              lit_utf8_decr (&original_str_curr_p);
762425bb815Sopenharmony_ci              index--;
763425bb815Sopenharmony_ci            }
764425bb815Sopenharmony_ci          }
765425bb815Sopenharmony_ci        }
766425bb815Sopenharmony_ci      }
767425bb815Sopenharmony_ci
768425bb815Sopenharmony_ci      ECMA_FINALIZE_UTF8_STRING (search_str_utf8_p, search_str_size);
769425bb815Sopenharmony_ci      ECMA_FINALIZE_UTF8_STRING (original_str_utf8_p, original_str_size);
770425bb815Sopenharmony_ci    }
771425bb815Sopenharmony_ci  }
772425bb815Sopenharmony_ci
773425bb815Sopenharmony_ci  return match_found;
774425bb815Sopenharmony_ci} /* ecma_builtin_helper_string_find_index */
775425bb815Sopenharmony_ci
776425bb815Sopenharmony_ci/**
777425bb815Sopenharmony_ci * Helper function for using [[DefineOwnProperty]] specialized for indexed property names
778425bb815Sopenharmony_ci *
779425bb815Sopenharmony_ci * Note: this method falls back to the general ecma_builtin_helper_def_prop
780425bb815Sopenharmony_ci *
781425bb815Sopenharmony_ci * @return ecma value
782425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
783425bb815Sopenharmony_ci */
784425bb815Sopenharmony_ciecma_value_t
785425bb815Sopenharmony_ciecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, /**< object */
786425bb815Sopenharmony_ci                                       uint32_t index, /**< property index */
787425bb815Sopenharmony_ci                                       ecma_value_t value, /**< value */
788425bb815Sopenharmony_ci                                       uint32_t opts) /**< any combination of ecma_property_flag_t bits */
789425bb815Sopenharmony_ci{
790425bb815Sopenharmony_ci  if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM))
791425bb815Sopenharmony_ci  {
792425bb815Sopenharmony_ci    return ecma_builtin_helper_def_prop (obj_p,
793425bb815Sopenharmony_ci                                         ECMA_CREATE_DIRECT_UINT32_STRING (index),
794425bb815Sopenharmony_ci                                         value,
795425bb815Sopenharmony_ci                                         opts);
796425bb815Sopenharmony_ci  }
797425bb815Sopenharmony_ci
798425bb815Sopenharmony_ci  ecma_string_t *index_str_p = ecma_new_non_direct_string_from_uint32 (index);
799425bb815Sopenharmony_ci  ecma_value_t ret_value = ecma_builtin_helper_def_prop (obj_p,
800425bb815Sopenharmony_ci                                                         index_str_p,
801425bb815Sopenharmony_ci                                                         value,
802425bb815Sopenharmony_ci                                                         opts);
803425bb815Sopenharmony_ci  ecma_deref_ecma_string (index_str_p);
804425bb815Sopenharmony_ci
805425bb815Sopenharmony_ci  return ret_value;
806425bb815Sopenharmony_ci} /* ecma_builtin_helper_def_prop_by_index */
807425bb815Sopenharmony_ci
808425bb815Sopenharmony_ci/**
809425bb815Sopenharmony_ci * Helper function for using [[DefineOwnProperty]].
810425bb815Sopenharmony_ci *
811425bb815Sopenharmony_ci * See also:
812425bb815Sopenharmony_ci *          ECMA-262 v5, 8.12.9
813425bb815Sopenharmony_ci *          ECMA-262 v5, 15.4.5.1
814425bb815Sopenharmony_ci *
815425bb815Sopenharmony_ci * @return ecma value
816425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
817425bb815Sopenharmony_ci */
818425bb815Sopenharmony_ciecma_value_t
819425bb815Sopenharmony_ciecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */
820425bb815Sopenharmony_ci                              ecma_string_t *name_p, /**< name string */
821425bb815Sopenharmony_ci                              ecma_value_t value, /**< value */
822425bb815Sopenharmony_ci                              uint32_t opts) /**< any combination of ecma_property_flag_t bits
823425bb815Sopenharmony_ci                                              *   with the optional ECMA_IS_THROW flag */
824425bb815Sopenharmony_ci{
825425bb815Sopenharmony_ci  ecma_property_descriptor_t prop_desc;
826425bb815Sopenharmony_ci
827425bb815Sopenharmony_ci  prop_desc.flags = (uint16_t) (ECMA_NAME_DATA_PROPERTY_DESCRIPTOR_BITS | opts);
828425bb815Sopenharmony_ci
829425bb815Sopenharmony_ci  prop_desc.value = value;
830425bb815Sopenharmony_ci
831425bb815Sopenharmony_ci  return ecma_op_object_define_own_property (obj_p,
832425bb815Sopenharmony_ci                                             name_p,
833425bb815Sopenharmony_ci                                             &prop_desc);
834425bb815Sopenharmony_ci} /* ecma_builtin_helper_def_prop */
835425bb815Sopenharmony_ci
836425bb815Sopenharmony_ci/**
837425bb815Sopenharmony_ci * GetSubstitution abstract operation
838425bb815Sopenharmony_ci *
839425bb815Sopenharmony_ci * See:
840425bb815Sopenharmony_ci *     ECMA-262 v6.0 21.1.3.14.1
841425bb815Sopenharmony_ci */
842425bb815Sopenharmony_civoid
843425bb815Sopenharmony_ciecma_builtin_replace_substitute (ecma_replace_context_t *ctx_p) /**< replace context */
844425bb815Sopenharmony_ci{
845425bb815Sopenharmony_ci  JERRY_ASSERT (ctx_p->string_p != NULL);
846425bb815Sopenharmony_ci  JERRY_ASSERT (ctx_p->matched_p == NULL
847425bb815Sopenharmony_ci                || (ctx_p->matched_p >= ctx_p->string_p
848425bb815Sopenharmony_ci                    && ctx_p->matched_p <= ctx_p->string_p + ctx_p->string_size));
849425bb815Sopenharmony_ci
850425bb815Sopenharmony_ci  lit_utf8_size_t replace_size;
851425bb815Sopenharmony_ci  uint8_t replace_flags = ECMA_STRING_FLAG_IS_ASCII;
852425bb815Sopenharmony_ci  const lit_utf8_byte_t *replace_buf_p = ecma_string_get_chars (ctx_p->replace_str_p,
853425bb815Sopenharmony_ci                                                                &replace_size,
854425bb815Sopenharmony_ci                                                                NULL,
855425bb815Sopenharmony_ci                                                                NULL,
856425bb815Sopenharmony_ci                                                                &replace_flags);
857425bb815Sopenharmony_ci
858425bb815Sopenharmony_ci  const lit_utf8_byte_t *const replace_end_p = replace_buf_p + replace_size;
859425bb815Sopenharmony_ci  const lit_utf8_byte_t *curr_p = replace_buf_p;
860425bb815Sopenharmony_ci  const lit_utf8_byte_t *last_inserted_end_p = replace_buf_p;
861425bb815Sopenharmony_ci
862425bb815Sopenharmony_ci  while (curr_p < replace_end_p)
863425bb815Sopenharmony_ci  {
864425bb815Sopenharmony_ci    if (*curr_p++ == LIT_CHAR_DOLLAR_SIGN)
865425bb815Sopenharmony_ci    {
866425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (&(ctx_p->builder),
867425bb815Sopenharmony_ci                                     last_inserted_end_p,
868425bb815Sopenharmony_ci                                     (lit_utf8_size_t) (curr_p - last_inserted_end_p - 1));
869425bb815Sopenharmony_ci      if (curr_p >= replace_end_p)
870425bb815Sopenharmony_ci      {
871425bb815Sopenharmony_ci        last_inserted_end_p = curr_p - 1;
872425bb815Sopenharmony_ci        break;
873425bb815Sopenharmony_ci      }
874425bb815Sopenharmony_ci
875425bb815Sopenharmony_ci      const lit_utf8_byte_t c = *curr_p++;
876425bb815Sopenharmony_ci
877425bb815Sopenharmony_ci      switch (c)
878425bb815Sopenharmony_ci      {
879425bb815Sopenharmony_ci        case LIT_CHAR_DOLLAR_SIGN:
880425bb815Sopenharmony_ci        {
881425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN);
882425bb815Sopenharmony_ci          break;
883425bb815Sopenharmony_ci        }
884425bb815Sopenharmony_ci        case LIT_CHAR_AMPERSAND:
885425bb815Sopenharmony_ci        {
886425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
887425bb815Sopenharmony_ci          if (JERRY_UNLIKELY (ctx_p->matched_p == NULL))
888425bb815Sopenharmony_ci          {
889425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->capture_count == 0);
890425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->u.collection_p != NULL);
891425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0);
892425bb815Sopenharmony_ci            const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0];
893425bb815Sopenharmony_ci
894425bb815Sopenharmony_ci            JERRY_ASSERT (ecma_is_value_string (match_value));
895425bb815Sopenharmony_ci            ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (match_value));
896425bb815Sopenharmony_ci            break;
897425bb815Sopenharmony_ci          }
898425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
899425bb815Sopenharmony_ci
900425bb815Sopenharmony_ci          JERRY_ASSERT (ctx_p->matched_p != NULL);
901425bb815Sopenharmony_ci          ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->matched_p, ctx_p->matched_size);
902425bb815Sopenharmony_ci          break;
903425bb815Sopenharmony_ci        }
904425bb815Sopenharmony_ci        case LIT_CHAR_GRAVE_ACCENT:
905425bb815Sopenharmony_ci        {
906425bb815Sopenharmony_ci          ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->string_p, ctx_p->match_byte_pos);
907425bb815Sopenharmony_ci          break;
908425bb815Sopenharmony_ci        }
909425bb815Sopenharmony_ci        case LIT_CHAR_SINGLE_QUOTE:
910425bb815Sopenharmony_ci        {
911425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
912425bb815Sopenharmony_ci          if (JERRY_UNLIKELY (ctx_p->matched_p == NULL))
913425bb815Sopenharmony_ci          {
914425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->capture_count == 0);
915425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->u.collection_p != NULL);
916425bb815Sopenharmony_ci            JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0);
917425bb815Sopenharmony_ci            const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0];
918425bb815Sopenharmony_ci
919425bb815Sopenharmony_ci            JERRY_ASSERT (ecma_is_value_string (match_value));
920425bb815Sopenharmony_ci            const ecma_string_t *const matched_p = ecma_get_string_from_value (match_value);
921425bb815Sopenharmony_ci            const lit_utf8_size_t match_size = ecma_string_get_size (matched_p);
922425bb815Sopenharmony_ci            const lit_utf8_byte_t *const begin_p = ctx_p->string_p + ctx_p->match_byte_pos + match_size;
923425bb815Sopenharmony_ci
924425bb815Sopenharmony_ci            ecma_stringbuilder_append_raw (&(ctx_p->builder),
925425bb815Sopenharmony_ci                                           begin_p,
926425bb815Sopenharmony_ci                                           (lit_utf8_size_t) (ctx_p->string_p + ctx_p->string_size - begin_p));
927425bb815Sopenharmony_ci            break;
928425bb815Sopenharmony_ci          }
929425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
930425bb815Sopenharmony_ci
931425bb815Sopenharmony_ci          JERRY_ASSERT (ctx_p->matched_p != NULL);
932425bb815Sopenharmony_ci          ecma_stringbuilder_append_raw (&(ctx_p->builder),
933425bb815Sopenharmony_ci                                         ctx_p->matched_p + ctx_p->matched_size,
934425bb815Sopenharmony_ci                                         ctx_p->string_size - ctx_p->match_byte_pos - ctx_p->matched_size);
935425bb815Sopenharmony_ci          break;
936425bb815Sopenharmony_ci        }
937425bb815Sopenharmony_ci        default:
938425bb815Sopenharmony_ci        {
939425bb815Sopenharmony_ci          const lit_utf8_byte_t *const number_begin_p = curr_p - 1;
940425bb815Sopenharmony_ci
941425bb815Sopenharmony_ci          if (lit_char_is_decimal_digit (c))
942425bb815Sopenharmony_ci          {
943425bb815Sopenharmony_ci            uint32_t capture_count = ctx_p->capture_count;
944425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
945425bb815Sopenharmony_ci            if (capture_count == 0 && ctx_p->u.collection_p != NULL)
946425bb815Sopenharmony_ci            {
947425bb815Sopenharmony_ci              capture_count = ctx_p->u.collection_p->item_count;
948425bb815Sopenharmony_ci            }
949425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
950425bb815Sopenharmony_ci
951425bb815Sopenharmony_ci            uint8_t idx = (uint8_t) (c - LIT_CHAR_0);
952425bb815Sopenharmony_ci            if (curr_p < replace_end_p && lit_char_is_decimal_digit (*(curr_p)))
953425bb815Sopenharmony_ci            {
954425bb815Sopenharmony_ci              uint8_t two_digit_index = (uint8_t) (idx * 10 + (uint8_t) (*(curr_p) - LIT_CHAR_0));
955425bb815Sopenharmony_ci              if (two_digit_index < capture_count)
956425bb815Sopenharmony_ci              {
957425bb815Sopenharmony_ci                idx = two_digit_index;
958425bb815Sopenharmony_ci                curr_p++;
959425bb815Sopenharmony_ci              }
960425bb815Sopenharmony_ci            }
961425bb815Sopenharmony_ci
962425bb815Sopenharmony_ci            if (idx > 0 && idx < capture_count)
963425bb815Sopenharmony_ci            {
964425bb815Sopenharmony_ci              if (ctx_p->capture_count > 0)
965425bb815Sopenharmony_ci              {
966425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_REGEXP)
967425bb815Sopenharmony_ci                JERRY_ASSERT (ctx_p->u.captures_p != NULL);
968425bb815Sopenharmony_ci                const ecma_regexp_capture_t *const capture_p = ctx_p->u.captures_p + idx;
969425bb815Sopenharmony_ci
970425bb815Sopenharmony_ci                if (ECMA_RE_IS_CAPTURE_DEFINED (capture_p))
971425bb815Sopenharmony_ci                {
972425bb815Sopenharmony_ci                  ecma_stringbuilder_append_raw (&(ctx_p->builder),
973425bb815Sopenharmony_ci                                                 capture_p->begin_p,
974425bb815Sopenharmony_ci                                                 (lit_utf8_size_t) (capture_p->end_p - capture_p->begin_p));
975425bb815Sopenharmony_ci                }
976425bb815Sopenharmony_ci
977425bb815Sopenharmony_ci                break;
978425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
979425bb815Sopenharmony_ci              }
980425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
981425bb815Sopenharmony_ci              else if (ctx_p->u.collection_p != NULL)
982425bb815Sopenharmony_ci              {
983425bb815Sopenharmony_ci                const ecma_value_t capture_value = ctx_p->u.collection_p->buffer_p[idx];
984425bb815Sopenharmony_ci                if (!ecma_is_value_undefined (capture_value))
985425bb815Sopenharmony_ci                {
986425bb815Sopenharmony_ci                  ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (capture_value));
987425bb815Sopenharmony_ci                }
988425bb815Sopenharmony_ci
989425bb815Sopenharmony_ci                break;
990425bb815Sopenharmony_ci              }
991425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
992425bb815Sopenharmony_ci            }
993425bb815Sopenharmony_ci          }
994425bb815Sopenharmony_ci
995425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN);
996425bb815Sopenharmony_ci          curr_p = number_begin_p;
997425bb815Sopenharmony_ci          break;
998425bb815Sopenharmony_ci        }
999425bb815Sopenharmony_ci      }
1000425bb815Sopenharmony_ci
1001425bb815Sopenharmony_ci      last_inserted_end_p = curr_p;
1002425bb815Sopenharmony_ci    }
1003425bb815Sopenharmony_ci  }
1004425bb815Sopenharmony_ci
1005425bb815Sopenharmony_ci  ecma_stringbuilder_append_raw (&(ctx_p->builder),
1006425bb815Sopenharmony_ci                                 last_inserted_end_p,
1007425bb815Sopenharmony_ci                                 (lit_utf8_size_t) (replace_end_p - last_inserted_end_p));
1008425bb815Sopenharmony_ci
1009425bb815Sopenharmony_ci  if (replace_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
1010425bb815Sopenharmony_ci  {
1011425bb815Sopenharmony_ci    jmem_heap_free_block ((void *) replace_buf_p, replace_size);
1012425bb815Sopenharmony_ci  }
1013425bb815Sopenharmony_ci} /* ecma_builtin_replace_substitute */
1014425bb815Sopenharmony_ci
1015425bb815Sopenharmony_ci/**
1016425bb815Sopenharmony_ci * @}
1017425bb815Sopenharmony_ci * @}
1018425bb815Sopenharmony_ci */
1019