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-builtin-helpers.h" 17 18#include "ecma-alloc.h" 19#include "ecma-array-object.h" 20#include "ecma-builtins.h" 21#include "ecma-builtin-object.h" 22#include "ecma-conversion.h" 23#include "ecma-function-object.h" 24#include "ecma-exceptions.h" 25#include "ecma-gc.h" 26#include "ecma-helpers.h" 27#include "jmem.h" 28#include "ecma-objects.h" 29#include "ecma-try-catch-macro.h" 30#include "lit-magic-strings.h" 31#include "lit-char-helpers.h" 32 33/** \addtogroup ecma ECMA 34 * @{ 35 * 36 * \addtogroup ecmabuiltinhelpers ECMA builtin helper operations 37 * @{ 38 */ 39 40#if ENABLED (JERRY_ES2015) 41/** 42 * Helper function for Object.prototype.toString routine when 43 * the @@toStringTag property is present 44 * 45 * See also: 46 * ECMA-262 v6, 19.1.3.6 47 * 48 * @return ecma value 49 * Returned value must be freed with ecma_free_value. 50 */ 51static ecma_value_t 52ecma_builtin_helper_object_to_string_tag_helper (ecma_value_t tag_value) /**< string tag */ 53{ 54 JERRY_ASSERT (ecma_is_value_string (tag_value)); 55 56 ecma_string_t *tag_str_p = ecma_get_string_from_value (tag_value); 57 ecma_string_t *ret_string_p; 58 59 /* Building string "[object #@@toStringTag#]" 60 The string size will be size("[object ") + size(#@@toStringTag#) + size ("]"). */ 61 const lit_utf8_size_t buffer_size = 9 + ecma_string_get_size (tag_str_p); 62 JMEM_DEFINE_LOCAL_ARRAY (str_buffer, buffer_size, lit_utf8_byte_t); 63 64 lit_utf8_byte_t *buffer_ptr = str_buffer; 65 66 const lit_magic_string_id_t magic_string_ids[] = 67 { 68 LIT_MAGIC_STRING_LEFT_SQUARE_CHAR, 69 LIT_MAGIC_STRING_OBJECT, 70 LIT_MAGIC_STRING_SPACE_CHAR, 71 }; 72 73 /* Copy to buffer the "[object " string */ 74 for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i) 75 { 76 buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr, 77 (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr)); 78 79 JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size); 80 } 81 82 /* Copy to buffer the #@@toStringTag# string */ 83 buffer_ptr += ecma_string_copy_to_cesu8_buffer (tag_str_p, buffer_ptr, 84 (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr)); 85 86 JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size); 87 88 /* Copy to buffer the "]" string */ 89 buffer_ptr = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR, buffer_ptr, 90 (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr)); 91 92 JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size); 93 94 ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer)); 95 96 JMEM_FINALIZE_LOCAL_ARRAY (str_buffer); 97 ecma_deref_ecma_string (tag_str_p); 98 99 return ecma_make_string_value (ret_string_p); 100} /* ecma_builtin_helper_object_to_string_tag_helper */ 101#endif /* ENABLED (JERRY_ES2015) */ 102 103/** 104 * Common implementation of the Object.prototype.toString routine 105 * 106 * See also: 107 * ECMA-262 v5, 15.2.4.2 108 * 109 * Used by: 110 * - The Object.prototype.toString routine. 111 * - The Array.prototype.toString routine as fallback. 112 * 113 * @return ecma value 114 * Returned value must be freed with ecma_free_value. 115 */ 116 117ecma_value_t 118ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this argument */ 119{ 120 lit_magic_string_id_t type_string; 121 122 if (ecma_is_value_undefined (this_arg)) 123 { 124 type_string = LIT_MAGIC_STRING_UNDEFINED_UL; 125 } 126 else if (ecma_is_value_null (this_arg)) 127 { 128 type_string = LIT_MAGIC_STRING_NULL_UL; 129 } 130 else 131 { 132 ecma_value_t obj_this = ecma_op_to_object (this_arg); 133 134 if (ECMA_IS_VALUE_ERROR (obj_this)) 135 { 136 return obj_this; 137 } 138 139 JERRY_ASSERT (ecma_is_value_object (obj_this)); 140 141 ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); 142 143 type_string = ecma_object_get_class_name (obj_p); 144 145#if ENABLED (JERRY_ES2015) 146 ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG); 147 148 if (ECMA_IS_VALUE_ERROR (tag_value)) 149 { 150 ecma_deref_object (obj_p); 151 return tag_value; 152 } 153 154 if (ecma_is_value_string (tag_value)) 155 { 156 ecma_deref_object (obj_p); 157 return ecma_builtin_helper_object_to_string_tag_helper (tag_value); 158 } 159 160 ecma_free_value (tag_value); 161#endif /* ENABLED (JERRY_ES2015) */ 162 163 ecma_deref_object (obj_p); 164 } 165 166 ecma_string_t *ret_string_p; 167 168 /* Building string "[object #type#]" where type is 'Undefined', 169 'Null' or one of possible object's classes. 170 The string with null character is maximum 27 characters long. */ 171 const lit_utf8_size_t buffer_size = 27; 172 JERRY_VLA (lit_utf8_byte_t, str_buffer, buffer_size); 173 174 lit_utf8_byte_t *buffer_ptr = str_buffer; 175 176 const lit_magic_string_id_t magic_string_ids[] = 177 { 178 LIT_MAGIC_STRING_LEFT_SQUARE_CHAR, 179 LIT_MAGIC_STRING_OBJECT, 180 LIT_MAGIC_STRING_SPACE_CHAR, 181 type_string, 182 LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR 183 }; 184 185 for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i) 186 { 187 buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr, 188 (lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr)); 189 JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size); 190 } 191 192 ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer)); 193 194 return ecma_make_string_value (ret_string_p); 195} /* ecma_builtin_helper_object_to_string */ 196 197/** 198 * The Array.prototype's 'toLocaleString' single element operation routine 199 * 200 * See also: 201 * ECMA-262 v5, 15.4.4.3 steps 6-8 and 10.b-d 202 * 203 * @return ecma value 204 * Returned value must be freed with ecma_free_value. 205 */ 206ecma_string_t * 207ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /**< this object */ 208 uint32_t index) /**< array index */ 209{ 210 ecma_value_t index_value = ecma_op_object_get_by_uint32_index (obj_p, index); 211 212 if (ECMA_IS_VALUE_ERROR (index_value)) 213 { 214 return NULL; 215 } 216 217 if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) 218 { 219 return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); 220 } 221 222 ecma_value_t index_obj_value = ecma_op_to_object (index_value); 223 224 if (ECMA_IS_VALUE_ERROR (index_obj_value)) 225 { 226 ecma_free_value (index_value); 227 return NULL; 228 } 229 230 ecma_string_t *ret_string_p = NULL; 231 ecma_object_t *index_obj_p = ecma_get_object_from_value (index_obj_value); 232 ecma_value_t to_locale_value = ecma_op_object_get_by_magic_id (index_obj_p, LIT_MAGIC_STRING_TO_LOCALE_STRING_UL); 233 234 if (ECMA_IS_VALUE_ERROR (to_locale_value)) 235 { 236 goto cleanup; 237 } 238 239 if (!ecma_op_is_callable (to_locale_value)) 240 { 241 ecma_free_value (to_locale_value); 242 ecma_raise_type_error (ECMA_ERR_MSG ("'toLocaleString' is missing or not a function.")); 243 goto cleanup; 244 } 245 246 ecma_object_t *locale_func_obj_p = ecma_get_object_from_value (to_locale_value); 247 ecma_value_t call_value = ecma_op_function_call (locale_func_obj_p, 248 index_obj_value, 249 NULL, 250 0); 251 ecma_deref_object (locale_func_obj_p); 252 253 if (ECMA_IS_VALUE_ERROR (call_value)) 254 { 255 goto cleanup; 256 } 257 258 ret_string_p = ecma_op_to_string (call_value); 259 ecma_free_value (call_value); 260 261cleanup: 262 ecma_deref_object (index_obj_p); 263 ecma_free_value (index_value); 264 265 return ret_string_p; 266} /* ecma_builtin_helper_get_to_locale_string_at_index */ 267 268/** 269 * The Object.keys and Object.getOwnPropertyNames routine's common part. 270 * 271 * See also: 272 * ECMA-262 v5, 15.2.3.4 steps 2-5 273 * ECMA-262 v5, 15.2.3.14 steps 3-6 274 * 275 * @return ecma value - Array of property names. 276 * Returned value must be freed with ecma_free_value. 277 */ 278ecma_value_t 279ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ 280 uint32_t opts) /**< any combination of ecma_list_properties_options_t */ 281{ 282 JERRY_ASSERT (obj_p != NULL); 283 284 ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, opts); 285 286#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) 287 if (props_p == NULL) 288 { 289 return ECMA_VALUE_ERROR; 290 } 291#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ 292 293 if (props_p->item_count == 0) 294 { 295 ecma_collection_destroy (props_p); 296 return ecma_op_create_array_object (NULL, 0, false); 297 } 298 299 ecma_value_t new_array = ecma_op_create_array_object (props_p->buffer_p, props_p->item_count, false); 300 ecma_collection_free (props_p); 301 302 return new_array; 303} /* ecma_builtin_helper_object_get_properties */ 304 305/** 306 * Helper function to normalizing an array index 307 * 308 * See also: 309 * ECMA-262 v5, 15.4.4.10 steps 5, 6, 7 part 2, 8 310 * ECMA-262 v5, 15.4.4.12 steps 5, 6 311 * ECMA-262 v5, 15.5.4.13 steps 4 - 7 312 * ECMA-262 v6, 22.1.3.6 steps 5 - 7, 8 part 2, 9, 10 313 * ECMA-262 v6, 22.1.3.3 steps 5 - 10, 11 part 2, 12, 13 314 * ECMA-262 v6, 22.2.3.5 steps 5 - 10, 11 part 2, 12, 13 315 * ECMA-262 v6, 22.2.3.23 steps 5 - 10 316 * ECMA-262 v6, 24.1.4.3 steps 6 - 8, 9 part 2, 10, 11 317 * ECMA-262 v6, 22.2.3.26 steps 7 - 9, 10 part 2, 11, 12 318 * ECMA-262 v6, 22.2.3.8 steps 5 - 7, 8 part 2, 9, 10 319 * 320 * Used by: 321 * - The Array.prototype.slice routine. 322 * - The Array.prototype.splice routine. 323 * - The String.prototype.slice routine. 324 * - The Array.prototype.fill routine. 325 * - The Array.prototype.copyWithin routine. 326 * - The TypedArray.prototype.copyWithin routine. 327 * - The TypedArray.prototype.slice routine. 328 * - The ArrayBuffer.prototype.slice routine. 329 * - The TypedArray.prototype.subarray routine. 330 * - The TypedArray.prototype.fill routine. 331 * 332 * @return ECMA_VALUE_EMPTY if successful 333 * conversion error otherwise 334 */ 335uint32_t 336ecma_builtin_helper_array_index_normalize (ecma_value_t arg, /**< index */ 337 uint32_t length, /**< array's length */ 338 uint32_t *number_p) /**< [out] uint32_t */ 339{ 340 ecma_number_t to_int; 341 342 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg, &to_int))) 343 { 344 return ECMA_VALUE_ERROR; 345 } 346 347 *number_p = ((to_int < 0) ? (uint32_t) JERRY_MAX ((length + to_int), 0) 348 : (uint32_t) JERRY_MIN (to_int, length)); 349 350 return ECMA_VALUE_EMPTY; 351} /* ecma_builtin_helper_array_index_normalize */ 352 353/** 354 * Helper function for concatenating an ecma_value_t to an Array. 355 * 356 * See also: 357 * ECMA-262 v5, 15.4.4.4 steps 5.b - 5.c 358 * 359 * Used by: 360 * - The Array.prototype.concat routine. 361 * 362 * @return ecma value 363 * Returned value must be freed with ecma_free_value. 364 */ 365ecma_value_t 366ecma_builtin_helper_array_concat_value (ecma_object_t *array_obj_p, /**< array */ 367 uint32_t *length_p, /**< [in,out] array's length */ 368 ecma_value_t value) /**< value to concat */ 369{ 370 /* 5.b */ 371#if ENABLED (JERRY_ES2015) 372 ecma_value_t is_spreadable = ecma_op_is_concat_spreadable (value); 373 374 if (ECMA_IS_VALUE_ERROR (is_spreadable)) 375 { 376 return is_spreadable; 377 } 378 379 bool spread_object = is_spreadable == ECMA_VALUE_TRUE; 380#else /* !ENABLED (JERRY_ES2015) */ 381 bool spread_object = ecma_is_value_true (ecma_is_value_array (value)); 382#endif /* ENABLED (JERRY_ES2015) */ 383 384 if (spread_object) 385 { 386 ecma_object_t *obj_p = ecma_get_object_from_value (value); 387 388#if ENABLED (JERRY_ES2015) 389 uint32_t arg_len; 390 ecma_value_t error = ecma_op_object_get_length (obj_p, &arg_len); 391 392 if (ECMA_IS_VALUE_ERROR (error)) 393 { 394 return error; 395 } 396#else /* !ENABLED (JERRY_ES2015) */ 397 /* 5.b.ii */ 398 uint32_t arg_len = ecma_array_get_length (obj_p); 399#endif /* ENABLED (JERRY_ES2015) */ 400 /* 5.b.iii */ 401 for (uint32_t array_index = 0; array_index < arg_len; array_index++) 402 { 403 /* 5.b.iii.2 */ 404 ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, array_index); 405 406 if (ECMA_IS_VALUE_ERROR (get_value)) 407 { 408 return get_value; 409 } 410 411 if (!ecma_is_value_found (get_value)) 412 { 413 continue; 414 } 415 416 /* 5.b.iii.3.b */ 417 /* This will always be a simple value since 'is_throw' is false, so no need to free. */ 418 ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, 419 *length_p + array_index, 420 get_value, 421 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); 422 423 JERRY_ASSERT (ecma_is_value_true (put_comp)); 424 ecma_free_value (get_value); 425 } 426 427 *length_p += arg_len; 428 return ECMA_VALUE_EMPTY; 429 } 430 431 /* 5.c.i */ 432 /* This will always be a simple value since 'is_throw' is false, so no need to free. */ 433 ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, 434 (*length_p)++, 435 value, 436 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); 437 JERRY_ASSERT (ecma_is_value_true (put_comp)); 438 439 return ECMA_VALUE_EMPTY; 440} /* ecma_builtin_helper_array_concat_value */ 441 442/** 443 * Helper function to normalizing a string index 444 * 445 * This function clamps the given index to the [0, length] range. 446 * If the index is negative, 0 value is used. 447 * If the index is greater than the length of the string, the normalized index will be the length of the string. 448 * NaN is mapped to zero or length depending on the nan_to_zero parameter. 449 * 450 * See also: 451 * ECMA-262 v5, 15.5.4.15 452 * 453 * Used by: 454 * - The String.prototype.substring routine. 455 * - The ecma_builtin_helper_string_prototype_object_index_of helper routine. 456 * 457 * @return uint32_t - the normalized value of the index 458 */ 459uint32_t 460ecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */ 461 uint32_t length, /**< string's length */ 462 bool nan_to_zero) /**< whether NaN is mapped to zero (t) or length (f) */ 463{ 464 uint32_t norm_index = 0; 465 466 if (ecma_number_is_nan (index)) 467 { 468 if (!nan_to_zero) 469 { 470 norm_index = length; 471 } 472 } 473 else if (!ecma_number_is_negative (index)) 474 { 475 if (ecma_number_is_infinity (index)) 476 { 477 norm_index = length; 478 } 479 else 480 { 481 norm_index = ecma_number_to_uint32 (index); 482 483 if (norm_index > length) 484 { 485 norm_index = length; 486 } 487 } 488 } 489 490 return norm_index; 491} /* ecma_builtin_helper_string_index_normalize */ 492 493/** 494 * Helper function for string indexOf, lastIndexOf, startsWith, includes, endsWith functions 495 * 496 * See also: 497 * ECMA-262 v5, 15.5.4.7 498 * ECMA-262 v5, 15.5.4.8 499 * ECMA-262 v6, 21.1.3.6 500 * ECMA-262 v6, 21.1.3.7 501 * ECMA-262 v6, 21.1.3.18 502 * 503 * Used by: 504 * - The String.prototype.indexOf routine. 505 * - The String.prototype.lastIndexOf routine. 506 * - The String.prototype.startsWith routine. 507 * - The String.prototype.includes routine. 508 * - The String.prototype.endsWith routine. 509 * 510 * @return ecma_value_t - Returns index (last index) or a 511 * boolean value 512 */ 513ecma_value_t 514ecma_builtin_helper_string_prototype_object_index_of (ecma_string_t *original_str_p, /**< this argument */ 515 ecma_value_t arg1, /**< routine's first argument */ 516 ecma_value_t arg2, /**< routine's second argument */ 517 ecma_string_index_of_mode_t mode) /**< routine's mode */ 518{ 519 /* 5 (indexOf) -- 6 (lastIndexOf) */ 520 const ecma_length_t original_len = ecma_string_get_length (original_str_p); 521 522#if ENABLED (JERRY_ES2015) 523 /* 4, 6 (startsWith, includes, endsWith) */ 524 if (mode >= ECMA_STRING_STARTS_WITH) 525 { 526 ecma_value_t regexp = ecma_op_is_regexp (arg1); 527 528 if (ECMA_IS_VALUE_ERROR (regexp)) 529 { 530 return regexp; 531 } 532 533 if (regexp == ECMA_VALUE_TRUE) 534 { 535 JERRY_ASSERT (ECMA_STRING_LAST_INDEX_OF < mode && mode <= ECMA_STRING_ENDS_WITH); 536 return ecma_raise_type_error (ECMA_ERR_MSG ("Search string can't be of type: RegExp")); 537 } 538 } 539#endif /* ENABLED (JERRY_ES2015) */ 540 541 /* 7, 8 */ 542 ecma_string_t *search_str_p = ecma_op_to_string (arg1); 543 544 if (JERRY_UNLIKELY (search_str_p == NULL)) 545 { 546 return ECMA_VALUE_ERROR; 547 } 548 549 /* 4 (indexOf, lastIndexOf), 9 (startsWith, includes), 10 (endsWith) */ 550 ecma_number_t pos_num; 551 ecma_value_t ret_value; 552#if ENABLED (JERRY_ES2015) 553 if (mode > ECMA_STRING_LAST_INDEX_OF) 554 { 555 ret_value = ecma_op_to_integer (arg2, &pos_num); 556 } 557 else 558 { 559#endif /* ENABLED (JERRY_ES2015) */ 560 ret_value = ecma_get_number (arg2, &pos_num); 561#if ENABLED (JERRY_ES2015) 562 } 563#endif /* ENABLED (JERRY_ES2015) */ 564 565 /* 10 (startsWith, includes), 11 (endsWith) */ 566 if (ECMA_IS_VALUE_ERROR (ret_value)) 567 { 568 ecma_deref_ecma_string (search_str_p); 569 return ret_value; 570 } 571 572 bool use_first_index = mode != ECMA_STRING_LAST_INDEX_OF; 573 574 /* 4b, 6 (indexOf) - 4b, 5, 7 (lastIndexOf) */ 575 ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, use_first_index); 576 577 ecma_number_t ret_num = ECMA_NUMBER_MINUS_ONE; 578 579 ecma_length_t index_of = 0; 580 581 ret_value = ECMA_VALUE_FALSE; 582 583 switch (mode) 584 { 585#if ENABLED (JERRY_ES2015) 586 case ECMA_STRING_STARTS_WITH: 587 { 588 const ecma_length_t search_len = ecma_string_get_length (search_str_p); 589 590 if (search_len + start > original_len) 591 { 592 break; 593 } 594 595 if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true, start, &index_of)) 596 { 597 /* 15, 16 (startsWith) */ 598 ret_value = ecma_make_boolean_value (index_of == start); 599 } 600 break; 601 } 602 case ECMA_STRING_INCLUDES: 603 { 604 if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true, start, &index_of)) 605 { 606 ret_value = ECMA_VALUE_TRUE; 607 } 608 break; 609 } 610 case ECMA_STRING_ENDS_WITH: 611 { 612 if (start == 0) 613 { 614 start = original_len; 615 } 616 617 ecma_length_t search_str_len = ecma_string_get_length (search_str_p); 618 619 if (search_str_len == 0) 620 { 621 ret_value = ECMA_VALUE_TRUE; 622 break; 623 } 624 625 int32_t start_ends_with = (int32_t) (start - search_str_len); 626 627 if (start_ends_with < 0) 628 { 629 break; 630 } 631 if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, true, 632 (ecma_length_t) start_ends_with, &index_of)) 633 { 634 ret_value = ecma_make_boolean_value (index_of == (ecma_length_t) start_ends_with); 635 } 636 break; 637 } 638#endif /* ENABLED (JERRY_ES2015) */ 639 640 case ECMA_STRING_INDEX_OF: 641 case ECMA_STRING_LAST_INDEX_OF: 642 default: 643 { 644 /* 8 (indexOf) -- 9 (lastIndexOf) */ 645 if (ecma_builtin_helper_string_find_index (original_str_p, search_str_p, use_first_index, start, &index_of)) 646 { 647 ret_num = ((ecma_number_t) index_of); 648 } 649 ret_value = ecma_make_number_value (ret_num); 650 break; 651 } 652 } 653 654 ecma_deref_ecma_string (search_str_p); 655 656 return ret_value; 657} /* ecma_builtin_helper_string_prototype_object_index_of */ 658 659/** 660 * Helper function for finding index of a search string 661 * 662 * This function clamps the given index to the [0, length] range. 663 * If the index is negative, 0 value is used. 664 * If the index is greater than the length of the string, the normalized index will be the length of the string. 665 * NaN is mapped to zero or length depending on the nan_to_zero parameter. 666 * 667 * See also: 668 * ECMA-262 v5, 15.5.4.7,8,11 669 * 670 * Used by: 671 * - The ecma_builtin_helper_string_prototype_object_index_of helper routine. 672 * - The ecma_builtin_string_prototype_object_replace_match helper routine. 673 * 674 * @return bool - whether there is a match for the search string 675 */ 676bool 677ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index */ 678 ecma_string_t *search_str_p, /**< string's length */ 679 bool first_index, /**< whether search for first (t) or last (f) index */ 680 ecma_length_t start_pos, /**< start position */ 681 ecma_length_t *ret_index_p) /**< [out] position found in original string */ 682{ 683 bool match_found = false; 684 const ecma_length_t original_len = ecma_string_get_length (original_str_p); 685 const ecma_length_t search_len = ecma_string_get_length (search_str_p); 686 687 if (search_len <= original_len) 688 { 689 if (!search_len) 690 { 691 match_found = true; 692 *ret_index_p = first_index ? start_pos : original_len; 693 } 694 else 695 { 696 /* create utf8 string from original string and advance to position */ 697 ECMA_STRING_TO_UTF8_STRING (original_str_p, original_str_utf8_p, original_str_size); 698 699 ecma_length_t index = start_pos; 700 701 const lit_utf8_byte_t *original_str_curr_p = original_str_utf8_p; 702 for (ecma_length_t idx = 0; idx < index; idx++) 703 { 704 lit_utf8_incr (&original_str_curr_p); 705 } 706 707 /* create utf8 string from search string */ 708 ECMA_STRING_TO_UTF8_STRING (search_str_p, search_str_utf8_p, search_str_size); 709 710 const lit_utf8_byte_t *search_str_curr_p = search_str_utf8_p; 711 712 /* iterate original string and try to match at each position */ 713 bool searching = true; 714 ecma_char_t first_char = lit_cesu8_read_next (&search_str_curr_p); 715 while (searching) 716 { 717 /* match as long as possible */ 718 ecma_length_t match_len = 0; 719 const lit_utf8_byte_t *stored_original_str_curr_p = original_str_curr_p; 720 721 if (match_len < search_len && 722 index + match_len < original_len && 723 lit_cesu8_read_next (&original_str_curr_p) == first_char) 724 { 725 const lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p; 726 match_len++; 727 728 while (match_len < search_len && 729 index + match_len < original_len && 730 lit_cesu8_read_next (&original_str_curr_p) == lit_cesu8_read_next (&nested_search_str_curr_p)) 731 { 732 match_len++; 733 } 734 } 735 736 /* check for match */ 737 if (match_len == search_len) 738 { 739 match_found = true; 740 *ret_index_p = index; 741 742 break; 743 } 744 else 745 { 746 /* inc/dec index and update iterators and search condition */ 747 original_str_curr_p = stored_original_str_curr_p; 748 749 if (first_index) 750 { 751 if ((searching = (index <= original_len - search_len))) 752 { 753 lit_utf8_incr (&original_str_curr_p); 754 index++; 755 } 756 } 757 else 758 { 759 if ((searching = (index > 0))) 760 { 761 lit_utf8_decr (&original_str_curr_p); 762 index--; 763 } 764 } 765 } 766 } 767 768 ECMA_FINALIZE_UTF8_STRING (search_str_utf8_p, search_str_size); 769 ECMA_FINALIZE_UTF8_STRING (original_str_utf8_p, original_str_size); 770 } 771 } 772 773 return match_found; 774} /* ecma_builtin_helper_string_find_index */ 775 776/** 777 * Helper function for using [[DefineOwnProperty]] specialized for indexed property names 778 * 779 * Note: this method falls back to the general ecma_builtin_helper_def_prop 780 * 781 * @return ecma value 782 * Returned value must be freed with ecma_free_value. 783 */ 784ecma_value_t 785ecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, /**< object */ 786 uint32_t index, /**< property index */ 787 ecma_value_t value, /**< value */ 788 uint32_t opts) /**< any combination of ecma_property_flag_t bits */ 789{ 790 if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM)) 791 { 792 return ecma_builtin_helper_def_prop (obj_p, 793 ECMA_CREATE_DIRECT_UINT32_STRING (index), 794 value, 795 opts); 796 } 797 798 ecma_string_t *index_str_p = ecma_new_non_direct_string_from_uint32 (index); 799 ecma_value_t ret_value = ecma_builtin_helper_def_prop (obj_p, 800 index_str_p, 801 value, 802 opts); 803 ecma_deref_ecma_string (index_str_p); 804 805 return ret_value; 806} /* ecma_builtin_helper_def_prop_by_index */ 807 808/** 809 * Helper function for using [[DefineOwnProperty]]. 810 * 811 * See also: 812 * ECMA-262 v5, 8.12.9 813 * ECMA-262 v5, 15.4.5.1 814 * 815 * @return ecma value 816 * Returned value must be freed with ecma_free_value. 817 */ 818ecma_value_t 819ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ 820 ecma_string_t *name_p, /**< name string */ 821 ecma_value_t value, /**< value */ 822 uint32_t opts) /**< any combination of ecma_property_flag_t bits 823 * with the optional ECMA_IS_THROW flag */ 824{ 825 ecma_property_descriptor_t prop_desc; 826 827 prop_desc.flags = (uint16_t) (ECMA_NAME_DATA_PROPERTY_DESCRIPTOR_BITS | opts); 828 829 prop_desc.value = value; 830 831 return ecma_op_object_define_own_property (obj_p, 832 name_p, 833 &prop_desc); 834} /* ecma_builtin_helper_def_prop */ 835 836/** 837 * GetSubstitution abstract operation 838 * 839 * See: 840 * ECMA-262 v6.0 21.1.3.14.1 841 */ 842void 843ecma_builtin_replace_substitute (ecma_replace_context_t *ctx_p) /**< replace context */ 844{ 845 JERRY_ASSERT (ctx_p->string_p != NULL); 846 JERRY_ASSERT (ctx_p->matched_p == NULL 847 || (ctx_p->matched_p >= ctx_p->string_p 848 && ctx_p->matched_p <= ctx_p->string_p + ctx_p->string_size)); 849 850 lit_utf8_size_t replace_size; 851 uint8_t replace_flags = ECMA_STRING_FLAG_IS_ASCII; 852 const lit_utf8_byte_t *replace_buf_p = ecma_string_get_chars (ctx_p->replace_str_p, 853 &replace_size, 854 NULL, 855 NULL, 856 &replace_flags); 857 858 const lit_utf8_byte_t *const replace_end_p = replace_buf_p + replace_size; 859 const lit_utf8_byte_t *curr_p = replace_buf_p; 860 const lit_utf8_byte_t *last_inserted_end_p = replace_buf_p; 861 862 while (curr_p < replace_end_p) 863 { 864 if (*curr_p++ == LIT_CHAR_DOLLAR_SIGN) 865 { 866 ecma_stringbuilder_append_raw (&(ctx_p->builder), 867 last_inserted_end_p, 868 (lit_utf8_size_t) (curr_p - last_inserted_end_p - 1)); 869 if (curr_p >= replace_end_p) 870 { 871 last_inserted_end_p = curr_p - 1; 872 break; 873 } 874 875 const lit_utf8_byte_t c = *curr_p++; 876 877 switch (c) 878 { 879 case LIT_CHAR_DOLLAR_SIGN: 880 { 881 ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN); 882 break; 883 } 884 case LIT_CHAR_AMPERSAND: 885 { 886#if ENABLED (JERRY_ES2015) 887 if (JERRY_UNLIKELY (ctx_p->matched_p == NULL)) 888 { 889 JERRY_ASSERT (ctx_p->capture_count == 0); 890 JERRY_ASSERT (ctx_p->u.collection_p != NULL); 891 JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0); 892 const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0]; 893 894 JERRY_ASSERT (ecma_is_value_string (match_value)); 895 ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (match_value)); 896 break; 897 } 898#endif /* ENABLED (JERRY_ES2015) */ 899 900 JERRY_ASSERT (ctx_p->matched_p != NULL); 901 ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->matched_p, ctx_p->matched_size); 902 break; 903 } 904 case LIT_CHAR_GRAVE_ACCENT: 905 { 906 ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->string_p, ctx_p->match_byte_pos); 907 break; 908 } 909 case LIT_CHAR_SINGLE_QUOTE: 910 { 911#if ENABLED (JERRY_ES2015) 912 if (JERRY_UNLIKELY (ctx_p->matched_p == NULL)) 913 { 914 JERRY_ASSERT (ctx_p->capture_count == 0); 915 JERRY_ASSERT (ctx_p->u.collection_p != NULL); 916 JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0); 917 const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0]; 918 919 JERRY_ASSERT (ecma_is_value_string (match_value)); 920 const ecma_string_t *const matched_p = ecma_get_string_from_value (match_value); 921 const lit_utf8_size_t match_size = ecma_string_get_size (matched_p); 922 const lit_utf8_byte_t *const begin_p = ctx_p->string_p + ctx_p->match_byte_pos + match_size; 923 924 ecma_stringbuilder_append_raw (&(ctx_p->builder), 925 begin_p, 926 (lit_utf8_size_t) (ctx_p->string_p + ctx_p->string_size - begin_p)); 927 break; 928 } 929#endif /* ENABLED (JERRY_ES2015) */ 930 931 JERRY_ASSERT (ctx_p->matched_p != NULL); 932 ecma_stringbuilder_append_raw (&(ctx_p->builder), 933 ctx_p->matched_p + ctx_p->matched_size, 934 ctx_p->string_size - ctx_p->match_byte_pos - ctx_p->matched_size); 935 break; 936 } 937 default: 938 { 939 const lit_utf8_byte_t *const number_begin_p = curr_p - 1; 940 941 if (lit_char_is_decimal_digit (c)) 942 { 943 uint32_t capture_count = ctx_p->capture_count; 944#if ENABLED (JERRY_ES2015) 945 if (capture_count == 0 && ctx_p->u.collection_p != NULL) 946 { 947 capture_count = ctx_p->u.collection_p->item_count; 948 } 949#endif /* ENABLED (JERRY_ES2015) */ 950 951 uint8_t idx = (uint8_t) (c - LIT_CHAR_0); 952 if (curr_p < replace_end_p && lit_char_is_decimal_digit (*(curr_p))) 953 { 954 uint8_t two_digit_index = (uint8_t) (idx * 10 + (uint8_t) (*(curr_p) - LIT_CHAR_0)); 955 if (two_digit_index < capture_count) 956 { 957 idx = two_digit_index; 958 curr_p++; 959 } 960 } 961 962 if (idx > 0 && idx < capture_count) 963 { 964 if (ctx_p->capture_count > 0) 965 { 966#if ENABLED (JERRY_BUILTIN_REGEXP) 967 JERRY_ASSERT (ctx_p->u.captures_p != NULL); 968 const ecma_regexp_capture_t *const capture_p = ctx_p->u.captures_p + idx; 969 970 if (ECMA_RE_IS_CAPTURE_DEFINED (capture_p)) 971 { 972 ecma_stringbuilder_append_raw (&(ctx_p->builder), 973 capture_p->begin_p, 974 (lit_utf8_size_t) (capture_p->end_p - capture_p->begin_p)); 975 } 976 977 break; 978#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ 979 } 980#if ENABLED (JERRY_ES2015) 981 else if (ctx_p->u.collection_p != NULL) 982 { 983 const ecma_value_t capture_value = ctx_p->u.collection_p->buffer_p[idx]; 984 if (!ecma_is_value_undefined (capture_value)) 985 { 986 ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (capture_value)); 987 } 988 989 break; 990 } 991#endif /* ENABLED (JERRY_ES2015) */ 992 } 993 } 994 995 ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN); 996 curr_p = number_begin_p; 997 break; 998 } 999 } 1000 1001 last_inserted_end_p = curr_p; 1002 } 1003 } 1004 1005 ecma_stringbuilder_append_raw (&(ctx_p->builder), 1006 last_inserted_end_p, 1007 (lit_utf8_size_t) (replace_end_p - last_inserted_end_p)); 1008 1009 if (replace_flags & ECMA_STRING_FLAG_MUST_BE_FREED) 1010 { 1011 jmem_heap_free_block ((void *) replace_buf_p, replace_size); 1012 } 1013} /* ecma_builtin_replace_substitute */ 1014 1015/** 1016 * @} 1017 * @} 1018 */ 1019