1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecma-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-builtin-helpers.h"
19 #include "ecma-builtins.h"
20 #include "ecma-builtin-regexp.inc.h"
21 #include "ecma-conversion.h"
22 #include "ecma-exceptions.h"
23 #include "ecma-function-object.h"
24 #include "ecma-gc.h"
25 #include "ecma-globals.h"
26 #include "ecma-helpers.h"
27 #include "ecma-iterator-object.h"
28 #include "ecma-objects.h"
29 #include "ecma-string-object.h"
30 #include "jcontext.h"
31 #include "jrt.h"
32 #include "jrt-libc-includes.h"
33 #include "lit-char-helpers.h"
34 #include "lit-strings.h"
35
36 #if ENABLED (JERRY_BUILTIN_REGEXP)
37 #include "ecma-regexp-object.h"
38 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
39
40 #if ENABLED (JERRY_BUILTIN_STRING)
41
42 #define ECMA_BUILTINS_INTERNAL
43 #include "ecma-builtins-internal.h"
44
45 /**
46 * This object has a custom dispatch function.
47 */
48 #define BUILTIN_CUSTOM_DISPATCH
49
50 /**
51 * List of built-in routine identifiers.
52 */
53 enum
54 {
55 ECMA_STRING_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
56 /* Note: These 4 routines MUST be in this order */
57 ECMA_STRING_PROTOTYPE_TO_STRING,
58 ECMA_STRING_PROTOTYPE_VALUE_OF,
59 ECMA_STRING_PROTOTYPE_CHAR_AT,
60 ECMA_STRING_PROTOTYPE_CHAR_CODE_AT,
61
62 ECMA_STRING_PROTOTYPE_CONCAT,
63 ECMA_STRING_PROTOTYPE_SLICE,
64
65 ECMA_STRING_PROTOTYPE_LOCALE_COMPARE,
66
67 ECMA_STRING_PROTOTYPE_MATCH,
68 ECMA_STRING_PROTOTYPE_REPLACE,
69 ECMA_STRING_PROTOTYPE_SEARCH,
70
71 ECMA_STRING_PROTOTYPE_SPLIT,
72 ECMA_STRING_PROTOTYPE_SUBSTRING,
73 ECMA_STRING_PROTOTYPE_TO_LOWER_CASE,
74 ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE,
75 ECMA_STRING_PROTOTYPE_TO_UPPER_CASE,
76 ECMA_STRING_PROTOTYPE_TO_LOCAL_UPPER_CASE,
77 ECMA_STRING_PROTOTYPE_TRIM,
78
79 ECMA_STRING_PROTOTYPE_SUBSTR,
80
81 ECMA_STRING_PROTOTYPE_REPEAT,
82 ECMA_STRING_PROTOTYPE_CODE_POINT_AT,
83 /* Note: These 5 routines MUST be in this order */
84 ECMA_STRING_PROTOTYPE_LAST_INDEX_OF,
85 ECMA_STRING_PROTOTYPE_INDEX_OF,
86 ECMA_STRING_PROTOTYPE_STARTS_WITH,
87 ECMA_STRING_PROTOTYPE_INCLUDES,
88 ECMA_STRING_PROTOTYPE_ENDS_WITH,
89
90 ECMA_STRING_PROTOTYPE_ITERATOR,
91 };
92
93 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-string-prototype.inc.h"
94 #define BUILTIN_UNDERSCORED_ID string_prototype
95 #include "ecma-builtin-internal-routines-template.inc.h"
96
97 /** \addtogroup ecma ECMA
98 * @{
99 *
100 * \addtogroup ecmabuiltins
101 * @{
102 *
103 * \addtogroup stringprototype ECMA String.prototype object built-in
104 * @{
105 */
106
107 /**
108 * The String.prototype object's 'toString' and 'valueOf' routines
109 *
110 * See also:
111 * ECMA-262 v5, 15.5.4.2
112 * ECMA-262 v5, 15.5.4.3
113 *
114 * @return ecma value
115 * Returned value must be freed with ecma_free_value.
116 */
117 static ecma_value_t
ecma_builtin_string_prototype_object_to_string(ecma_value_t this_arg)118 ecma_builtin_string_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */
119 {
120 if (ecma_is_value_string (this_arg))
121 {
122 return ecma_copy_value (this_arg);
123 }
124
125 if (ecma_is_value_object (this_arg))
126 {
127 ecma_object_t *object_p = ecma_get_object_from_value (this_arg);
128
129 if (ecma_object_class_is (object_p, LIT_MAGIC_STRING_STRING_UL))
130 {
131 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
132
133 JERRY_ASSERT (ecma_is_value_string (ext_object_p->u.class_prop.u.value));
134
135 return ecma_copy_value (ext_object_p->u.class_prop.u.value);
136 }
137 }
138
139 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a String or a String object."));
140 } /* ecma_builtin_string_prototype_object_to_string */
141
142 /**
143 * Helper function for the String.prototype object's 'charAt' and charCodeAt' routine
144 *
145 * @return ecma value
146 * Returned value must be freed with ecma_free_value.
147 */
148 static ecma_value_t
ecma_builtin_string_prototype_char_at_helper(ecma_value_t this_arg,ecma_value_t arg,bool charcode_mode)149 ecma_builtin_string_prototype_char_at_helper (ecma_value_t this_arg, /**< this argument */
150 ecma_value_t arg, /**< routine's argument */
151 bool charcode_mode) /**< routine mode */
152 {
153 /* 3 */
154 ecma_number_t index_num;
155 ecma_value_t to_num_result = ecma_op_to_integer (arg, &index_num);
156
157 if (JERRY_UNLIKELY (!ecma_is_value_empty (to_num_result)))
158 {
159 return to_num_result;
160 }
161
162 /* 2 */
163 ecma_string_t *original_string_p = ecma_op_to_string (this_arg);
164 if (JERRY_UNLIKELY (original_string_p == NULL))
165 {
166 return ECMA_VALUE_ERROR;
167 }
168
169 /* 4 */
170 const ecma_length_t len = ecma_string_get_length (original_string_p);
171
172 /* 5 */
173 // When index_num is NaN, then the first two comparisons are false
174 if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && len == 0))
175 {
176 ecma_deref_ecma_string (original_string_p);
177 return (charcode_mode ? ecma_make_nan_value ()
178 : ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY));
179 }
180
181 /* 6 */
182 /*
183 * String length is currently uint32_t, but index_num may be bigger,
184 * ToInteger performs floor, while ToUInt32 performs modulo 2^32,
185 * hence after the check 0 <= index_num < len we assume to_uint32 can be used.
186 * We assume to_uint32 (NaN) is 0.
187 */
188 JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num));
189
190 ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num));
191 ecma_deref_ecma_string (original_string_p);
192
193 return (charcode_mode ? ecma_make_uint32_value (new_ecma_char)
194 : ecma_make_string_value (ecma_new_ecma_string_from_code_unit (new_ecma_char)));
195 } /* ecma_builtin_string_prototype_char_at_helper */
196
197 /**
198 * The String.prototype object's 'concat' routine
199 *
200 * See also:
201 * ECMA-262 v5, 15.5.4.6
202 *
203 * @return ecma value
204 * Returned value must be freed with ecma_free_value.
205 */
206 static ecma_value_t
ecma_builtin_string_prototype_object_concat(ecma_string_t * this_string_p,const ecma_value_t * argument_list_p,ecma_length_t arguments_number)207 ecma_builtin_string_prototype_object_concat (ecma_string_t *this_string_p, /**< this argument */
208 const ecma_value_t *argument_list_p, /**< arguments list */
209 ecma_length_t arguments_number) /**< number of arguments */
210 {
211 ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (this_string_p);
212
213 /* 5 */
214 for (uint32_t arg_index = 0; arg_index < arguments_number; ++arg_index)
215 {
216 /* 5a, b */
217 ecma_string_t *get_arg_string_p = ecma_op_to_string (argument_list_p[arg_index]);
218
219 if (JERRY_UNLIKELY (get_arg_string_p == NULL))
220 {
221 ecma_stringbuilder_destroy (&builder);
222 return ECMA_VALUE_ERROR;
223 }
224
225 ecma_stringbuilder_append (&builder, get_arg_string_p);
226
227 ecma_deref_ecma_string (get_arg_string_p);
228 }
229
230 /* 6 */
231 return ecma_make_string_value (ecma_stringbuilder_finalize (&builder));
232 } /* ecma_builtin_string_prototype_object_concat */
233
234 /**
235 * The String.prototype object's 'localeCompare' routine
236 *
237 * See also:
238 * ECMA-262 v5, 15.5.4.9
239 *
240 * @return ecma value
241 * Returned value must be freed with ecma_free_value.
242 */
243 static ecma_value_t
ecma_builtin_string_prototype_object_locale_compare(ecma_string_t * this_string_p,ecma_value_t arg)244 ecma_builtin_string_prototype_object_locale_compare (ecma_string_t *this_string_p, /**< this argument */
245 ecma_value_t arg) /**< routine's argument */
246 {
247 /* 3. */
248 ecma_string_t *arg_string_p = ecma_op_to_string (arg);
249
250 if (JERRY_UNLIKELY (arg_string_p == NULL))
251 {
252 return ECMA_VALUE_ERROR;
253 }
254
255 ecma_number_t result = ECMA_NUMBER_ZERO;
256
257 if (ecma_compare_ecma_strings_relational (this_string_p, arg_string_p))
258 {
259 result = ECMA_NUMBER_MINUS_ONE;
260 }
261 else if (!ecma_compare_ecma_strings (this_string_p, arg_string_p))
262 {
263 result = ECMA_NUMBER_ONE;
264 }
265 else
266 {
267 result = ECMA_NUMBER_ZERO;
268 }
269
270 ecma_deref_ecma_string (arg_string_p);
271
272 return ecma_make_number_value (result);
273 } /* ecma_builtin_string_prototype_object_locale_compare */
274
275 #if ENABLED (JERRY_BUILTIN_REGEXP)
276 /**
277 * The String.prototype object's 'match' routine
278 *
279 * See also:
280 * ECMA-262 v5, 15.5.4.10
281 *
282 * @return ecma value
283 * Returned value must be freed with ecma_free_value.
284 */
285 static ecma_value_t
ecma_builtin_string_prototype_object_match(ecma_value_t this_argument,ecma_value_t regexp_arg)286 ecma_builtin_string_prototype_object_match (ecma_value_t this_argument, /**< this argument */
287 ecma_value_t regexp_arg) /**< routine's argument */
288 {
289 #if ENABLED (JERRY_ES2015)
290 /* 3. */
291 if (!(ecma_is_value_undefined (regexp_arg) || ecma_is_value_null (regexp_arg)))
292 {
293 /* 3.a */
294 ecma_value_t matcher = ecma_op_get_method_by_symbol_id (regexp_arg, LIT_GLOBAL_SYMBOL_MATCH);
295
296 /* 3.b */
297 if (ECMA_IS_VALUE_ERROR (matcher))
298 {
299 return matcher;
300 }
301
302 /* 3.c */
303 if (!ecma_is_value_undefined (matcher))
304 {
305 /* 3.c.i */
306 ecma_object_t *matcher_method = ecma_get_object_from_value (matcher);
307 ecma_value_t result = ecma_op_function_call (matcher_method, regexp_arg, &this_argument, 1);
308 ecma_deref_object (matcher_method);
309 return result;
310 }
311 }
312
313 /* 4. */
314 ecma_string_t *this_str_p = ecma_op_to_string (this_argument);
315
316 /* 5. */
317 if (JERRY_UNLIKELY (this_str_p == NULL))
318 {
319 return ECMA_VALUE_ERROR;
320 }
321
322 /* 6. */
323 ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
324
325 if (JERRY_UNLIKELY (regexp_obj_p == NULL))
326 {
327 ecma_deref_ecma_string (this_str_p);
328 return ECMA_VALUE_ERROR;
329 }
330
331 ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED);
332
333 /* 7. */
334 if (ECMA_IS_VALUE_ERROR (new_regexp))
335 {
336
337 ecma_deref_object (regexp_obj_p);
338 ecma_deref_ecma_string (this_str_p);
339 return new_regexp;
340 }
341 ecma_value_t this_str_value = ecma_make_string_value (this_str_p);
342
343 /* 8. */
344 ecma_value_t ret_value = ecma_op_invoke_by_symbol_id (new_regexp, LIT_GLOBAL_SYMBOL_MATCH, &this_str_value, 1);
345
346 ecma_deref_ecma_string (this_str_p);
347 ecma_free_value (new_regexp);
348
349 return ret_value;
350
351 #else /* !ENABLED (JERRY_ES2015) */
352 if (ecma_object_is_regexp_object (regexp_arg))
353 {
354 return ecma_regexp_match_helper (regexp_arg, this_argument);
355 }
356
357 ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
358
359 if (JERRY_UNLIKELY (regexp_obj_p == NULL))
360 {
361 return ECMA_VALUE_ERROR;
362 }
363
364 ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED);
365
366 if (ECMA_IS_VALUE_ERROR (new_regexp))
367 {
368 ecma_deref_object (regexp_obj_p);
369 return new_regexp;
370 }
371
372 ecma_value_t result = ecma_regexp_match_helper (new_regexp, this_argument);
373
374 ecma_free_value (new_regexp);
375
376 return result;
377 #endif /* ENABLED (JERRY_ES2015) */
378 } /* ecma_builtin_string_prototype_object_match */
379
380 /**
381 * The String.prototype object's 'replace' routine
382 *
383 * See also:
384 * ECMA-262 v5, 15.5.4.11
385 * ECMA-262 v6, 21.1.3.14
386 *
387 * @return ecma value
388 * Returned value must be freed with ecma_free_value.
389 */
390 static ecma_value_t
ecma_builtin_string_prototype_object_replace(ecma_value_t this_value,ecma_value_t search_value,ecma_value_t replace_value)391 ecma_builtin_string_prototype_object_replace (ecma_value_t this_value, /**< this argument */
392 ecma_value_t search_value, /**< routine's first argument */
393 ecma_value_t replace_value) /**< routine's second argument */
394 {
395 #if ENABLED (JERRY_ES2015)
396 if (!(ecma_is_value_undefined (search_value) || ecma_is_value_null (search_value)))
397 {
398 ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (search_value));
399 ecma_value_t replace_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_REPLACE);
400 ecma_deref_object (obj_p);
401
402 if (ECMA_IS_VALUE_ERROR (replace_symbol))
403 {
404 return replace_symbol;
405 }
406
407 if (!ecma_is_value_undefined (replace_symbol) && !ecma_is_value_null (replace_symbol))
408 {
409 if (!ecma_op_is_callable (replace_symbol))
410 {
411 ecma_free_value (replace_symbol);
412 return ecma_raise_type_error (ECMA_ERR_MSG ("@@replace is not callable"));
413 }
414
415 ecma_object_t *replace_method = ecma_get_object_from_value (replace_symbol);
416
417 ecma_value_t arguments[] = { this_value, replace_value };
418 ecma_value_t replace_result = ecma_op_function_call (replace_method, search_value, arguments, 2);
419
420 ecma_deref_object (replace_method);
421 return replace_result;
422 }
423 }
424 #else /* !ENABLED (JERRY_ES2015) */
425 if (ecma_object_is_regexp_object (search_value))
426 {
427 return ecma_regexp_replace_helper (search_value, this_value, replace_value);
428 }
429 #endif /* ENABLED (JERRY_ES2015) */
430
431 ecma_string_t *input_str_p = ecma_get_string_from_value (this_value);
432
433 ecma_value_t result = ECMA_VALUE_ERROR;
434
435 ecma_string_t *search_str_p = ecma_op_to_string (search_value);
436 if (search_str_p == NULL)
437 {
438 return result;
439 }
440
441 ecma_replace_context_t replace_ctx;
442 replace_ctx.capture_count = 0;
443 replace_ctx.u.captures_p = NULL;
444
445 replace_ctx.replace_str_p = NULL;
446 if (!ecma_op_is_callable (replace_value))
447 {
448 replace_ctx.replace_str_p = ecma_op_to_string (replace_value);
449 if (replace_ctx.replace_str_p == NULL)
450 {
451 goto cleanup_search;
452 }
453 }
454
455 uint8_t input_flags = ECMA_STRING_FLAG_IS_ASCII;
456 replace_ctx.string_p = ecma_string_get_chars (input_str_p,
457 &(replace_ctx.string_size),
458 NULL,
459 NULL,
460 &input_flags);
461
462 lit_utf8_size_t search_size;
463 uint8_t search_flags = ECMA_STRING_FLAG_IS_ASCII;
464 const lit_utf8_byte_t *search_buf_p = ecma_string_get_chars (search_str_p,
465 &search_size,
466 NULL,
467 NULL,
468 &search_flags);
469
470 ecma_string_t *result_string_p = NULL;
471
472 if (replace_ctx.string_size >= search_size)
473 {
474 replace_ctx.matched_size = search_size;
475 const lit_utf8_byte_t *const input_end_p = replace_ctx.string_p + replace_ctx.string_size;
476 const lit_utf8_byte_t *const loop_end_p = input_end_p - search_size;
477
478 uint32_t pos = 0;
479 for (const lit_utf8_byte_t *curr_p = replace_ctx.string_p;
480 curr_p <= loop_end_p;
481 lit_utf8_incr (&curr_p), pos++)
482 {
483 if (!memcmp (curr_p, search_buf_p, search_size))
484 {
485 const lit_utf8_size_t byte_offset = (lit_utf8_size_t) (curr_p - replace_ctx.string_p);
486 replace_ctx.builder = ecma_stringbuilder_create_raw (replace_ctx.string_p, byte_offset);
487
488 if (replace_ctx.replace_str_p == NULL)
489 {
490 ecma_object_t *function_p = ecma_get_object_from_value (replace_value);
491
492 ecma_value_t args[] =
493 {
494 ecma_make_string_value (search_str_p),
495 ecma_make_uint32_value (pos),
496 ecma_make_string_value (input_str_p)
497 };
498
499 result = ecma_op_function_call (function_p,
500 ECMA_VALUE_UNDEFINED,
501 args,
502 3);
503
504 if (ECMA_IS_VALUE_ERROR (result))
505 {
506 ecma_stringbuilder_destroy (&replace_ctx.builder);
507 goto cleanup_replace;
508 }
509
510 ecma_string_t *const result_str_p = ecma_op_to_string (result);
511 ecma_free_value (result);
512
513 if (result_str_p == NULL)
514 {
515 ecma_stringbuilder_destroy (&replace_ctx.builder);
516 result = ECMA_VALUE_ERROR;
517 goto cleanup_replace;
518 }
519
520 ecma_stringbuilder_append (&replace_ctx.builder, result_str_p);
521 ecma_deref_ecma_string (result_str_p);
522 }
523 else
524 {
525 replace_ctx.matched_p = curr_p;
526 replace_ctx.match_byte_pos = byte_offset;
527
528 ecma_builtin_replace_substitute (&replace_ctx);
529 }
530
531 const lit_utf8_byte_t *const match_end_p = curr_p + search_size;
532 ecma_stringbuilder_append_raw (&replace_ctx.builder,
533 match_end_p,
534 (lit_utf8_size_t) (input_end_p - match_end_p));
535 result_string_p = ecma_stringbuilder_finalize (&replace_ctx.builder);
536 break;
537 }
538 }
539 }
540
541 if (result_string_p == NULL)
542 {
543 ecma_ref_ecma_string (input_str_p);
544 result_string_p = input_str_p;
545 }
546
547 result = ecma_make_string_value (result_string_p);
548
549 cleanup_replace:
550 if (input_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
551 {
552 jmem_heap_free_block ((void *) replace_ctx.string_p, replace_ctx.string_size);
553 }
554
555 if (search_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
556 {
557 jmem_heap_free_block ((void *) search_buf_p, search_size);
558 }
559
560 if (replace_ctx.replace_str_p != NULL)
561 {
562 ecma_deref_ecma_string (replace_ctx.replace_str_p);
563 }
564
565 cleanup_search:
566 ecma_deref_ecma_string (search_str_p);
567 return result;
568 } /* ecma_builtin_string_prototype_object_replace */
569
570 /**
571 * The String.prototype object's 'search' routine
572 *
573 * See also:
574 * ECMA-262 v5, 15.5.4.12
575 * ECMA-262 v6, 21.1.3.15
576 *
577 * @return ecma value
578 * Returned value must be freed with ecma_free_value.
579 */
580 static ecma_value_t
ecma_builtin_string_prototype_object_search(ecma_value_t this_value,ecma_value_t regexp_value)581 ecma_builtin_string_prototype_object_search (ecma_value_t this_value, /**< this argument */
582 ecma_value_t regexp_value) /**< routine's argument */
583 {
584 #if ENABLED (JERRY_ES2015)
585 if (!(ecma_is_value_undefined (regexp_value) || ecma_is_value_null (regexp_value)))
586 {
587 ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (regexp_value));
588 ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SEARCH);
589 ecma_deref_object (obj_p);
590
591 if (ECMA_IS_VALUE_ERROR (search_symbol))
592 {
593 return search_symbol;
594 }
595
596 if (!ecma_is_value_undefined (search_symbol) && !ecma_is_value_null (search_symbol))
597 {
598 if (!ecma_op_is_callable (search_symbol))
599 {
600 ecma_free_value (search_symbol);
601 return ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable"));
602 }
603
604 ecma_object_t *search_method = ecma_get_object_from_value (search_symbol);
605 ecma_value_t search_result = ecma_op_function_call (search_method, regexp_value, &this_value, 1);
606
607 ecma_deref_object (search_method);
608 return search_result;
609 }
610 }
611 #else /* !ENABLED (JERRY_ES2015) */
612 if (ecma_object_is_regexp_object (regexp_value))
613 {
614 return ecma_regexp_search_helper (regexp_value, this_value);
615 }
616 #endif /* ENABLED (JERRY_ES2015) */
617
618 ecma_value_t result = ECMA_VALUE_ERROR;
619
620 ecma_string_t *string_p = ecma_op_to_string (this_value);
621 if (string_p == NULL)
622 {
623 return result;
624 }
625
626 ecma_string_t *pattern_p = ecma_regexp_read_pattern_str_helper (regexp_value);
627 if (pattern_p == NULL)
628 {
629 goto cleanup_string;
630 }
631
632 ecma_object_t *new_regexp_obj_p = ecma_op_regexp_alloc (NULL);
633
634 if (JERRY_UNLIKELY (new_regexp_obj_p == NULL))
635 {
636 ecma_deref_ecma_string (string_p);
637 ecma_deref_ecma_string (pattern_p);
638 return ECMA_VALUE_ERROR;
639 }
640
641 ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (new_regexp_obj_p,
642 ecma_make_string_value (pattern_p),
643 ECMA_VALUE_UNDEFINED);
644
645 ecma_deref_ecma_string (pattern_p);
646
647 if (ECMA_IS_VALUE_ERROR (new_regexp))
648 {
649 ecma_deref_object (new_regexp_obj_p);
650 goto cleanup_string;
651 }
652
653 #if !ENABLED (JERRY_ES2015)
654 result = ecma_regexp_search_helper (new_regexp, ecma_make_string_value (string_p));
655 ecma_deref_object (ecma_get_object_from_value (new_regexp));
656 #else /* ENABLED (JERRY_ES2015) */
657 ecma_object_t *regexp_obj_p = ecma_get_object_from_value (new_regexp);
658 ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (regexp_obj_p, LIT_GLOBAL_SYMBOL_SEARCH);
659 if (ECMA_IS_VALUE_ERROR (search_symbol))
660 {
661 goto cleanup_regexp;
662 }
663
664 if (!ecma_op_is_callable (search_symbol))
665 {
666 result = ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable"));
667 goto cleanup_regexp;
668 }
669
670 ecma_object_t *search_method_p = ecma_get_object_from_value (search_symbol);
671 ecma_value_t arguments[] = { ecma_make_string_value (string_p) };
672 result = ecma_op_function_call (search_method_p, new_regexp, arguments, 1);
673 ecma_deref_object (search_method_p);
674
675 cleanup_regexp:
676 ecma_deref_object (regexp_obj_p);
677 #endif /* !ENABLED (JERRY_ES2015) */
678
679 cleanup_string:
680 ecma_deref_ecma_string (string_p);
681 return result;
682 } /* ecma_builtin_string_prototype_object_search */
683
684 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
685
686 /**
687 * The String.prototype object's 'slice' routine
688 *
689 * See also:
690 * ECMA-262 v5, 15.5.4.13
691 *
692 * @return ecma value
693 * Returned value must be freed with ecma_free_value.
694 */
695 static ecma_value_t
ecma_builtin_string_prototype_object_slice(ecma_string_t * get_string_val,ecma_value_t arg1,ecma_value_t arg2)696 ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< this argument */
697 ecma_value_t arg1, /**< routine's first argument */
698 ecma_value_t arg2) /**< routine's second argument */
699 {
700 const ecma_length_t len = ecma_string_get_length (get_string_val);
701
702 /* 4. 6. */
703 ecma_length_t start = 0, end = len;
704
705 if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg1,
706 len,
707 &start)))
708 {
709 return ECMA_VALUE_ERROR;
710 }
711
712 /* 5. 7. */
713 if (ecma_is_value_undefined (arg2))
714 {
715 end = len;
716 }
717 else
718 {
719 if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg2,
720 len,
721 &end)))
722 {
723 return ECMA_VALUE_ERROR;
724 }
725 }
726
727 JERRY_ASSERT (start <= len && end <= len);
728
729 /* 8-9. */
730 ecma_string_t *new_str_p = ecma_string_substr (get_string_val, start, end);
731
732 return ecma_make_string_value (new_str_p);
733 } /* ecma_builtin_string_prototype_object_slice */
734
735 /**
736 * The String.prototype object's 'split' routine
737 *
738 * See also:
739 * ECMA-262 v5, 15.5.4.14
740 *
741 * @return ecma value
742 * Returned value must be freed with ecma_free_value.
743 */
744 static ecma_value_t
ecma_builtin_string_prototype_object_split(ecma_value_t this_value,ecma_value_t separator_value,ecma_value_t limit_value)745 ecma_builtin_string_prototype_object_split (ecma_value_t this_value, /**< this argument */
746 ecma_value_t separator_value, /**< separator */
747 ecma_value_t limit_value) /**< limit */
748 {
749 #if ENABLED (JERRY_ES2015)
750 if (!(ecma_is_value_undefined (separator_value) || ecma_is_value_null (separator_value)))
751 {
752 ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (separator_value));
753 ecma_value_t split_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SPLIT);
754 ecma_deref_object (obj_p);
755
756 if (ECMA_IS_VALUE_ERROR (split_symbol))
757 {
758 return split_symbol;
759 }
760
761 if (!ecma_is_value_undefined (split_symbol) && !ecma_is_value_null (split_symbol))
762 {
763 if (!ecma_op_is_callable (split_symbol))
764 {
765 ecma_free_value (split_symbol);
766 return ecma_raise_type_error (ECMA_ERR_MSG ("@@split is not callable"));
767 }
768
769 ecma_object_t *split_method_p = ecma_get_object_from_value (split_symbol);
770
771 ecma_value_t arguments[] = { this_value, limit_value };
772 ecma_value_t split_result = ecma_op_function_call (split_method_p, separator_value, arguments, 2);
773
774 ecma_deref_object (split_method_p);
775 return split_result;
776 }
777 }
778 #else /* !ENABLED (JERRY_ES2015) */
779 if (ecma_object_is_regexp_object (separator_value))
780 {
781 #if ENABLED (JERRY_BUILTIN_REGEXP)
782 return ecma_regexp_split_helper (separator_value, this_value, limit_value);
783 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
784 }
785 #endif /* ENABLED (JERRY_ES2015) */
786
787 ecma_value_t result = ECMA_VALUE_ERROR;
788
789 /* 4. */
790 ecma_string_t *string_p = ecma_op_to_string (this_value);
791 if (string_p == NULL)
792 {
793 return result;
794 }
795
796 /* 8. */
797 uint32_t limit = UINT32_MAX;
798 if (!ecma_is_value_undefined (limit_value))
799 {
800 if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (limit_value, &limit)))
801 {
802 goto cleanup_string;
803 }
804 }
805
806 /* 12. */
807 ecma_string_t *separator_p = ecma_op_to_string (separator_value);
808 if (separator_p == NULL)
809 {
810 goto cleanup_string;
811 }
812
813 /* 6. */
814 result = ecma_op_create_array_object (NULL, 0, false);
815
816 /* 14. */
817 if (limit == 0)
818 {
819 goto cleanup_separator;
820 }
821
822 ecma_object_t *array_p = ecma_get_object_from_value (result);
823 ecma_length_t array_length = 0;
824
825 /* 15. */
826 if (ecma_is_value_undefined (separator_value))
827 {
828 ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
829 array_length,
830 ecma_make_string_value (string_p),
831 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
832 JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
833 goto cleanup_separator;
834 }
835
836 /* 16. */
837 if (ecma_string_is_empty (string_p))
838 {
839 if (!ecma_string_is_empty (separator_p))
840 {
841 ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
842 array_length,
843 ecma_make_string_value (string_p),
844 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
845 JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
846 }
847
848 goto cleanup_separator;
849 }
850
851 lit_utf8_size_t string_size;
852 uint8_t string_flags = ECMA_STRING_FLAG_IS_ASCII;
853 const lit_utf8_byte_t *string_buffer_p = ecma_string_get_chars (string_p,
854 &string_size,
855 NULL,
856 NULL,
857 &string_flags);
858 lit_utf8_size_t separator_size;
859 uint8_t separator_flags = ECMA_STRING_FLAG_IS_ASCII;
860 const lit_utf8_byte_t *separator_buffer_p = ecma_string_get_chars (separator_p,
861 &separator_size,
862 NULL,
863 NULL,
864 &separator_flags);
865
866 const lit_utf8_byte_t *const string_end_p = string_buffer_p + string_size;
867 const lit_utf8_byte_t *const compare_end_p = JERRY_MIN (string_end_p - separator_size + 1,
868 string_end_p);
869 const lit_utf8_byte_t *current_p = string_buffer_p;
870 const lit_utf8_byte_t *last_str_begin_p = string_buffer_p;
871
872 while (current_p < compare_end_p)
873 {
874 if (!memcmp (current_p, separator_buffer_p, separator_size)
875 && (last_str_begin_p != current_p + separator_size))
876 {
877 ecma_string_t *substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p,
878 (lit_utf8_size_t) (current_p - last_str_begin_p));
879 ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
880 array_length++,
881 ecma_make_string_value (substr_p),
882 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
883 JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
884 ecma_deref_ecma_string (substr_p);
885
886 if (array_length >= limit)
887 {
888 goto cleanup_buffers;
889 }
890
891 current_p += separator_size;
892 last_str_begin_p = current_p;
893 continue;
894 }
895
896 lit_utf8_incr (¤t_p);
897 }
898
899 ecma_string_t *end_substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p,
900 (lit_utf8_size_t) (string_end_p - last_str_begin_p));
901 ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
902 array_length,
903 ecma_make_string_value (end_substr_p),
904 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
905 JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
906 ecma_deref_ecma_string (end_substr_p);
907
908 cleanup_buffers:
909 if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
910 {
911 jmem_heap_free_block ((void *) string_buffer_p, string_size);
912 }
913
914 if (separator_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
915 {
916 jmem_heap_free_block ((void *) separator_buffer_p, separator_size);
917 }
918
919 cleanup_separator:
920 ecma_deref_ecma_string (separator_p);
921 cleanup_string:
922 ecma_deref_ecma_string (string_p);
923 return result;
924 } /* ecma_builtin_string_prototype_object_split */
925
926 /**
927 * The String.prototype object's 'substring' routine
928 *
929 * See also:
930 * ECMA-262 v5, 15.5.4.15
931 *
932 * @return ecma value
933 * Returned value must be freed with ecma_free_value.
934 */
935 static ecma_value_t
ecma_builtin_string_prototype_object_substring(ecma_string_t * original_string_p,ecma_value_t arg1,ecma_value_t arg2)936 ecma_builtin_string_prototype_object_substring (ecma_string_t *original_string_p, /**< this argument */
937 ecma_value_t arg1, /**< routine's first argument */
938 ecma_value_t arg2) /**< routine's second argument */
939 {
940 /* 3 */
941 const ecma_length_t len = ecma_string_get_length (original_string_p);
942 ecma_length_t start = 0, end = len;
943
944 /* 4 */
945 ecma_number_t start_num;
946
947 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg1, &start_num)))
948 {
949 return ECMA_VALUE_ERROR;
950 }
951
952 /* 6 */
953 start = (uint32_t) JERRY_MIN (JERRY_MAX (start_num, 0), len);
954
955 /* 5 */
956 if (ecma_is_value_undefined (arg2))
957 {
958 end = len;
959 }
960 else
961 {
962 /* 5 part 2 */
963 ecma_number_t end_num;
964
965 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg2, &end_num)))
966 {
967 return ECMA_VALUE_ERROR;
968 }
969 /* 7 */
970 end = (uint32_t) JERRY_MIN (JERRY_MAX (end_num, 0), len);
971 }
972
973 JERRY_ASSERT (start <= len && end <= len);
974
975 /* 8 */
976 uint32_t from = start < end ? start : end;
977
978 /* 9 */
979 uint32_t to = start > end ? start : end;
980
981 /* 10 */
982 ecma_string_t *new_str_p = ecma_string_substr (original_string_p, from, to);
983 return ecma_make_string_value (new_str_p);
984 } /* ecma_builtin_string_prototype_object_substring */
985
986 /**
987 * The common implementation of the String.prototype object's
988 * 'toLowerCase', 'toLocaleLowerCase', 'toUpperCase', 'toLocalUpperCase' routines
989 *
990 * See also:
991 * ECMA-262 v5, 15.5.4.16
992 * ECMA-262 v5, 15.5.4.17
993 * ECMA-262 v5, 15.5.4.18
994 * ECMA-262 v5, 15.5.4.19
995 *
996 * Helper function to convert a string to upper or lower case.
997 *
998 * @return ecma value
999 * Returned value must be freed with ecma_free_value.
1000 */
1001 static ecma_value_t
ecma_builtin_string_prototype_object_conversion_helper(ecma_string_t * input_string_p,bool lower_case)1002 ecma_builtin_string_prototype_object_conversion_helper (ecma_string_t *input_string_p, /**< this argument */
1003 bool lower_case) /**< convert to lower (true)
1004 * or upper (false) case */
1005 {
1006 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1007
1008 /* 3. */
1009 ECMA_STRING_TO_UTF8_STRING (input_string_p, input_start_p, input_start_size);
1010
1011 /*
1012 * The URI encoding has two major phases: first we compute
1013 * the length of the lower case string, then we encode it.
1014 */
1015
1016 lit_utf8_size_t output_length = 0;
1017 const lit_utf8_byte_t *input_str_curr_p = input_start_p;
1018 const lit_utf8_byte_t *input_str_end_p = input_start_p + input_start_size;
1019
1020 while (input_str_curr_p < input_str_end_p)
1021 {
1022 ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p);
1023 ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH];
1024 ecma_length_t character_length;
1025 lit_utf8_byte_t utf8_byte_buffer[LIT_CESU8_MAX_BYTES_IN_CODE_POINT];
1026
1027 if (lower_case)
1028 {
1029 character_length = lit_char_to_lower_case (character,
1030 character_buffer,
1031 LIT_MAXIMUM_OTHER_CASE_LENGTH);
1032 }
1033 else
1034 {
1035 character_length = lit_char_to_upper_case (character,
1036 character_buffer,
1037 LIT_MAXIMUM_OTHER_CASE_LENGTH);
1038 }
1039
1040 JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH);
1041
1042 for (ecma_length_t i = 0; i < character_length; i++)
1043 {
1044 output_length += lit_code_unit_to_utf8 (character_buffer[i], utf8_byte_buffer);
1045 }
1046 }
1047
1048 /* Second phase. */
1049
1050 JMEM_DEFINE_LOCAL_ARRAY (output_start_p,
1051 output_length,
1052 lit_utf8_byte_t);
1053
1054 lit_utf8_byte_t *output_char_p = output_start_p;
1055
1056 /* Encoding the output. */
1057 input_str_curr_p = input_start_p;
1058
1059 while (input_str_curr_p < input_str_end_p)
1060 {
1061 ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p);
1062 ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH];
1063 ecma_length_t character_length;
1064
1065 if (lower_case)
1066 {
1067 character_length = lit_char_to_lower_case (character,
1068 character_buffer,
1069 LIT_MAXIMUM_OTHER_CASE_LENGTH);
1070 }
1071 else
1072 {
1073 character_length = lit_char_to_upper_case (character,
1074 character_buffer,
1075 LIT_MAXIMUM_OTHER_CASE_LENGTH);
1076 }
1077
1078 JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH);
1079
1080 for (ecma_length_t i = 0; i < character_length; i++)
1081 {
1082 output_char_p += lit_code_unit_to_utf8 (character_buffer[i], output_char_p);
1083 }
1084 }
1085
1086 JERRY_ASSERT (output_start_p + output_length == output_char_p);
1087
1088 ecma_string_t *output_string_p = ecma_new_ecma_string_from_utf8 (output_start_p, output_length);
1089
1090 ret_value = ecma_make_string_value (output_string_p);
1091
1092 JMEM_FINALIZE_LOCAL_ARRAY (output_start_p);
1093 ECMA_FINALIZE_UTF8_STRING (input_start_p, input_start_size);
1094
1095 return ret_value;
1096 } /* ecma_builtin_string_prototype_object_conversion_helper */
1097
1098 /**
1099 * The String.prototype object's 'trim' routine
1100 *
1101 * See also:
1102 * ECMA-262 v5, 15.5.4.20
1103 *
1104 * @return ecma value
1105 * Returned value must be freed with ecma_free_value.
1106 */
1107 static ecma_value_t
ecma_builtin_string_prototype_object_trim(ecma_string_t * original_string_p)1108 ecma_builtin_string_prototype_object_trim (ecma_string_t *original_string_p) /**< this argument */
1109 {
1110 ecma_string_t *trimmed_string_p = ecma_string_trim (original_string_p);
1111
1112 return ecma_make_string_value (trimmed_string_p);
1113 } /* ecma_builtin_string_prototype_object_trim */
1114
1115 #if ENABLED (JERRY_ES2015)
1116
1117 /**
1118 * The String.prototype object's 'repeat' routine
1119 *
1120 * See also:
1121 * ECMA-262 v6, 21.1.3.13
1122 *
1123 * @return ecma value
1124 * Returned value must be freed with ecma_free_value.
1125 */
1126 static ecma_value_t
ecma_builtin_string_prototype_object_repeat(ecma_string_t * original_string_p,ecma_value_t repeat)1127 ecma_builtin_string_prototype_object_repeat (ecma_string_t *original_string_p, /**< this argument */
1128 ecma_value_t repeat) /**< times to repeat */
1129 {
1130 ecma_string_t *ret_string_p;
1131
1132 /* 4 */
1133 ecma_number_t count_number;
1134 ecma_value_t count_value = ecma_op_to_integer (repeat, &count_number);
1135
1136 /* 5 */
1137 if (ECMA_IS_VALUE_ERROR (count_value))
1138 {
1139 return count_value;
1140 }
1141
1142 int32_t repeat_count = ecma_number_to_int32 (count_number);
1143
1144 bool isNan = ecma_number_is_nan (count_number);
1145
1146 /* 6, 7 */
1147 if (count_number < 0 || (!isNan && ecma_number_is_infinity (count_number)))
1148 {
1149 return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid count value"));
1150 }
1151
1152 lit_utf8_size_t size = ecma_string_get_size (original_string_p);
1153
1154 if (repeat_count == 0 || size == 0 || isNan)
1155 {
1156 return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
1157 }
1158
1159 if ((uint32_t) repeat_count >= (ECMA_STRING_SIZE_LIMIT / size))
1160 {
1161 return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid string length"));
1162 }
1163
1164 lit_utf8_size_t total_size = size * (lit_utf8_size_t) repeat_count;
1165
1166 JMEM_DEFINE_LOCAL_ARRAY (str_buffer, total_size, lit_utf8_byte_t);
1167
1168 lit_utf8_byte_t *buffer_ptr = str_buffer;
1169
1170 for (int32_t n = 0; n < repeat_count; n++)
1171 {
1172 buffer_ptr += ecma_string_copy_to_cesu8_buffer (original_string_p, buffer_ptr,
1173 (lit_utf8_size_t) (size));
1174 }
1175
1176 ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));
1177 JMEM_FINALIZE_LOCAL_ARRAY (str_buffer);
1178
1179 return ecma_make_string_value (ret_string_p);
1180 } /* ecma_builtin_string_prototype_object_repeat */
1181
1182 /**
1183 * The String.prototype object's 'codePointAt' routine
1184 *
1185 * See also:
1186 * ECMA-262 v6, 21.1.3.3
1187 *
1188 * @return lit_code_point_t
1189 */
1190 static ecma_value_t
ecma_builtin_string_prototype_object_code_point_at(ecma_string_t * this_string_p,ecma_value_t pos)1191 ecma_builtin_string_prototype_object_code_point_at (ecma_string_t *this_string_p, /**< this argument */
1192 ecma_value_t pos) /**< given position */
1193 {
1194 ecma_number_t pos_num;
1195 ecma_value_t error = ecma_op_to_integer (pos, &pos_num);
1196
1197 if (ECMA_IS_VALUE_ERROR (error))
1198 {
1199 return error;
1200 }
1201
1202 ecma_length_t size = ecma_string_get_length (this_string_p);
1203
1204 if (pos_num < 0 || pos_num >= size)
1205 {
1206 return ECMA_VALUE_UNDEFINED;
1207 }
1208
1209 uint32_t index = (uint32_t) pos_num;
1210
1211 ecma_char_t first = ecma_string_get_char_at_pos (this_string_p, index);
1212
1213 if (first < LIT_UTF16_HIGH_SURROGATE_MIN
1214 || first > LIT_UTF16_HIGH_SURROGATE_MAX
1215 || index + 1 == size)
1216 {
1217 return ecma_make_uint32_value (first);
1218 }
1219
1220 ecma_char_t second = ecma_string_get_char_at_pos (this_string_p, index + 1);
1221
1222 if (second < LIT_UTF16_LOW_SURROGATE_MARKER
1223 || second > LIT_UTF16_LOW_SURROGATE_MAX)
1224 {
1225 return ecma_make_uint32_value (first);
1226 }
1227
1228 return ecma_make_uint32_value (lit_convert_surrogate_pair_to_code_point (first, second));
1229 } /* ecma_builtin_string_prototype_object_code_point_at */
1230
1231 #endif /* ENABLED (JERRY_ES2015) */
1232
1233 #if ENABLED (JERRY_BUILTIN_ANNEXB)
1234
1235 /**
1236 * The String.prototype object's 'substr' routine
1237 *
1238 * See also:
1239 * ECMA-262 v5, B.2.3
1240 *
1241 * @return ecma value
1242 * Returned value must be freed with ecma_free_value.
1243 */
1244 static ecma_value_t
ecma_builtin_string_prototype_object_substr(ecma_string_t * this_string_p,ecma_value_t start,ecma_value_t length)1245 ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< this argument */
1246 ecma_value_t start, /**< routine's first argument */
1247 ecma_value_t length) /**< routine's second argument */
1248 {
1249 /* 2. */
1250 ecma_number_t start_num;
1251
1252 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (start, &start_num)))
1253 {
1254 return ECMA_VALUE_ERROR;
1255 }
1256
1257 /* 3. */
1258 ecma_number_t length_num = ecma_number_make_infinity (false);
1259
1260 if (!ecma_is_value_undefined (length))
1261 {
1262 ecma_number_t len;
1263
1264 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (length, &len)))
1265 {
1266 return ECMA_VALUE_ERROR;
1267 }
1268
1269 length_num = ecma_number_is_nan (len) ? 0 : len;
1270 }
1271
1272 /* 4. */
1273 ecma_length_t this_len = ecma_string_get_length (this_string_p);
1274
1275 /* 5. */
1276 uint32_t from = (uint32_t) ((start_num < 0) ? JERRY_MAX (this_len + start_num, 0) : start_num);
1277
1278 if (from > this_len)
1279 {
1280 from = this_len;
1281 }
1282
1283 /* 6. */
1284 ecma_number_t to_num = JERRY_MIN (JERRY_MAX (length_num, 0), this_len - from);
1285
1286 /* 7. */
1287 uint32_t to = from + (uint32_t) to_num;
1288
1289 /* 8. */
1290 ecma_string_t *new_str_p = ecma_string_substr (this_string_p, from, to);
1291 return ecma_make_string_value (new_str_p);
1292 } /* ecma_builtin_string_prototype_object_substr */
1293
1294 #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */
1295
1296 #if ENABLED (JERRY_ES2015)
1297
1298 /**
1299 * The String.prototype object's @@iterator routine
1300 *
1301 * See also:
1302 * ECMA-262 v6, 21.1.3.27
1303 *
1304 * @return ecma value
1305 * Returned value must be freed with ecma_free_value.
1306 */
1307 static ecma_value_t
ecma_builtin_string_prototype_object_iterator(ecma_value_t to_string)1308 ecma_builtin_string_prototype_object_iterator (ecma_value_t to_string) /**< this argument */
1309 {
1310 return ecma_op_create_iterator_object (ecma_copy_value (to_string),
1311 ecma_builtin_get (ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE),
1312 ECMA_PSEUDO_STRING_ITERATOR,
1313 0);
1314 } /* ecma_builtin_string_prototype_object_iterator */
1315
1316 #endif /* ENABLED (JERRY_ES2015) */
1317
1318 /**
1319 * Dispatcher of the built-in's routines
1320 *
1321 * @return ecma value
1322 * Returned value must be freed with ecma_free_value.
1323 */
1324 ecma_value_t
ecma_builtin_string_prototype_dispatch_routine(uint16_t builtin_routine_id,ecma_value_t this_arg,const ecma_value_t arguments_list_p[],ecma_length_t arguments_number)1325 ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine
1326 * identifier */
1327 ecma_value_t this_arg, /**< 'this' argument value */
1328 const ecma_value_t arguments_list_p[], /**< list of arguments
1329 * passed to routine */
1330 ecma_length_t arguments_number) /**< length of arguments' list */
1331 {
1332 if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_VALUE_OF)
1333 {
1334 return ecma_builtin_string_prototype_object_to_string (this_arg);
1335 }
1336
1337 ecma_value_t coercible = ecma_op_check_object_coercible (this_arg);
1338
1339 if (ECMA_IS_VALUE_ERROR (coercible))
1340 {
1341 return coercible;
1342 }
1343
1344 ecma_value_t arg1 = arguments_list_p[0];
1345 ecma_value_t arg2 = arguments_list_p[1];
1346
1347 #if ENABLED (JERRY_BUILTIN_REGEXP)
1348 if (builtin_routine_id == ECMA_STRING_PROTOTYPE_MATCH)
1349 {
1350 return ecma_builtin_string_prototype_object_match (this_arg, arg1);
1351 }
1352 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1353
1354 if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_CHAR_CODE_AT)
1355 {
1356 return ecma_builtin_string_prototype_char_at_helper (this_arg,
1357 arg1,
1358 builtin_routine_id == ECMA_STRING_PROTOTYPE_CHAR_CODE_AT);
1359 }
1360
1361 ecma_string_t *string_p = ecma_op_to_string (this_arg);
1362
1363 if (JERRY_UNLIKELY (string_p == NULL))
1364 {
1365 return ECMA_VALUE_ERROR;
1366 }
1367
1368 ecma_value_t to_string_val = ecma_make_string_value (string_p);
1369 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1370
1371 switch (builtin_routine_id)
1372 {
1373 case ECMA_STRING_PROTOTYPE_CONCAT:
1374 {
1375 ret_value = ecma_builtin_string_prototype_object_concat (string_p, arguments_list_p, arguments_number);
1376 break;
1377 }
1378 case ECMA_STRING_PROTOTYPE_SLICE:
1379 {
1380 ret_value = ecma_builtin_string_prototype_object_slice (string_p, arg1, arg2);
1381 break;
1382 }
1383 case ECMA_STRING_PROTOTYPE_LAST_INDEX_OF:
1384 case ECMA_STRING_PROTOTYPE_INDEX_OF:
1385 #if ENABLED (JERRY_ES2015)
1386 case ECMA_STRING_PROTOTYPE_STARTS_WITH:
1387 case ECMA_STRING_PROTOTYPE_INCLUDES:
1388 case ECMA_STRING_PROTOTYPE_ENDS_WITH:
1389 #endif /* ENABLED (JERRY_ES2015) */
1390 {
1391 ecma_string_index_of_mode_t mode;
1392 mode = (ecma_string_index_of_mode_t) (builtin_routine_id - ECMA_STRING_PROTOTYPE_LAST_INDEX_OF);
1393 ret_value = ecma_builtin_helper_string_prototype_object_index_of (string_p, arg1, arg2, mode);
1394 break;
1395 }
1396 case ECMA_STRING_PROTOTYPE_LOCALE_COMPARE:
1397 {
1398 ret_value = ecma_builtin_string_prototype_object_locale_compare (string_p, arg1);
1399 break;
1400 }
1401 #if ENABLED (JERRY_BUILTIN_REGEXP)
1402 case ECMA_STRING_PROTOTYPE_REPLACE:
1403 {
1404 ret_value = ecma_builtin_string_prototype_object_replace (to_string_val, arg1, arg2);
1405 break;
1406 }
1407 case ECMA_STRING_PROTOTYPE_SEARCH:
1408 {
1409 ret_value = ecma_builtin_string_prototype_object_search (to_string_val, arg1);
1410 break;
1411 }
1412 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1413 case ECMA_STRING_PROTOTYPE_SPLIT:
1414 {
1415 ret_value = ecma_builtin_string_prototype_object_split (to_string_val, arg1, arg2);
1416 break;
1417 }
1418 case ECMA_STRING_PROTOTYPE_SUBSTRING:
1419 {
1420 ret_value = ecma_builtin_string_prototype_object_substring (string_p, arg1, arg2);
1421 break;
1422 }
1423 case ECMA_STRING_PROTOTYPE_TO_LOWER_CASE:
1424 case ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE:
1425 case ECMA_STRING_PROTOTYPE_TO_UPPER_CASE:
1426 case ECMA_STRING_PROTOTYPE_TO_LOCAL_UPPER_CASE:
1427 {
1428 bool is_lower_case = builtin_routine_id <= ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE;
1429 ret_value = ecma_builtin_string_prototype_object_conversion_helper (string_p, is_lower_case);
1430 break;
1431 }
1432 case ECMA_STRING_PROTOTYPE_TRIM:
1433 {
1434 ret_value = ecma_builtin_string_prototype_object_trim (string_p);
1435 break;
1436 }
1437 #if ENABLED (JERRY_BUILTIN_ANNEXB)
1438 case ECMA_STRING_PROTOTYPE_SUBSTR:
1439 {
1440 ret_value = ecma_builtin_string_prototype_object_substr (string_p, arg1, arg2);
1441 break;
1442 }
1443 #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */
1444 #if ENABLED (JERRY_ES2015)
1445 case ECMA_STRING_PROTOTYPE_REPEAT:
1446 {
1447 ret_value = ecma_builtin_string_prototype_object_repeat (string_p, arg1);
1448 break;
1449 }
1450 case ECMA_STRING_PROTOTYPE_CODE_POINT_AT:
1451 {
1452 ret_value = ecma_builtin_string_prototype_object_code_point_at (string_p, arg1);
1453 break;
1454 }
1455 case ECMA_STRING_PROTOTYPE_ITERATOR:
1456 {
1457 ret_value = ecma_builtin_string_prototype_object_iterator (to_string_val);
1458 break;
1459 }
1460 #endif /* ENABLED (JERRY_ES2015) */
1461 default:
1462 {
1463 JERRY_UNREACHABLE ();
1464 }
1465 }
1466
1467 ecma_deref_ecma_string (string_p);
1468
1469 return ret_value;
1470 } /* ecma_builtin_string_prototype_dispatch_routine */
1471
1472 /**
1473 * @}
1474 * @}
1475 * @}
1476 */
1477
1478 #endif /* ENABLED (JERRY_BUILTIN_STRING) */
1479