String.js (24797B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 function ThrowIncompatibleMethod(name, thisv) { 6 ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "String", name, ToString(thisv)); 7 } 8 9 // ES 2016 draft Mar 25, 2016 21.1.3.11. 10 function String_match(regexp) { 11 // Step 1. 12 if (IsNullOrUndefined(this)) { 13 ThrowIncompatibleMethod("match", this); 14 } 15 16 // Step 2. 17 if (IsObject(regexp)) { 18 // Fast path for regular expressions with the original 19 // RegExp.prototype[@@match] function. 20 if (IsOptimizableRegExpObject(regexp)) { 21 return callFunction(RegExpMatch, regexp, this); 22 } 23 24 // Step 2.a. 25 var matcher = GetMethod(regexp, GetBuiltinSymbol("match")); 26 27 // Step 2.b. 28 if (matcher !== undefined) { 29 return callContentFunction(matcher, regexp, this); 30 } 31 } 32 33 // Step 3. 34 var S = ToString(this); 35 36 if (typeof regexp === "string" && IsRegExpPrototypeOptimizable()) { 37 var flatResult = FlatStringMatch(S, regexp); 38 if (flatResult !== undefined) { 39 return flatResult; 40 } 41 } 42 43 // Step 4. 44 var rx = RegExpCreate(regexp); 45 46 // Step 5 (optimized case). 47 if (IsRegExpPrototypeOptimizable()) { 48 return RegExpMatcher(rx, S, 0); 49 } 50 51 // Step 5. 52 return callContentFunction(GetMethod(rx, GetBuiltinSymbol("match")), rx, S); 53 } 54 55 // String.prototype.matchAll proposal. 56 // 57 // String.prototype.matchAll ( regexp ) 58 function String_matchAll(regexp) { 59 // Step 1. 60 if (IsNullOrUndefined(this)) { 61 ThrowIncompatibleMethod("matchAll", this); 62 } 63 64 // Step 2. 65 if (IsObject(regexp)) { 66 // Steps 2.a-b. 67 if (IsRegExp(regexp)) { 68 // Step 2.b.i. 69 var flags = regexp.flags; 70 71 // Step 2.b.ii. 72 if (IsNullOrUndefined(flags)) { 73 ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL); 74 } 75 76 // Step 2.b.iii. 77 if (!callFunction(std_String_includes, ToString(flags), "g")) { 78 ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "matchAll"); 79 } 80 } 81 82 // Fast path for regular expressions with the original 83 // RegExp.prototype[@@matchAll] function. 84 if (IsOptimizableRegExpObject(regexp)) { 85 return callFunction(RegExpMatchAll, regexp, this); 86 } 87 88 // Step 2.c. 89 var matcher = GetMethod(regexp, GetBuiltinSymbol("matchAll")); 90 91 // Step 2.d. 92 if (matcher !== undefined) { 93 return callContentFunction(matcher, regexp, this); 94 } 95 } 96 97 // Step 3. 98 var string = ToString(this); 99 100 // Step 4. 101 var rx = RegExpCreate(regexp, "g"); 102 103 // Step 5. 104 return callContentFunction( 105 GetMethod(rx, GetBuiltinSymbol("matchAll")), 106 rx, 107 string 108 ); 109 } 110 111 /** 112 * A helper function implementing the logic for both String.prototype.padStart 113 * and String.prototype.padEnd as described in ES7 Draft March 29, 2016 114 */ 115 function String_pad(maxLength, fillString, padEnd) { 116 // Step 1. 117 if (IsNullOrUndefined(this)) { 118 ThrowIncompatibleMethod(padEnd ? "padEnd" : "padStart", this); 119 } 120 121 // Step 2. 122 var str = ToString(this); 123 124 // Steps 3-4. 125 var intMaxLength = ToLength(maxLength); 126 var strLen = str.length; 127 128 // Step 5. 129 if (intMaxLength <= strLen) { 130 return str; 131 } 132 133 // Steps 6-7. 134 assert(fillString !== undefined, "never called when fillString is undefined"); 135 var filler = ToString(fillString); 136 137 // Step 8. 138 if (filler === "") { 139 return str; 140 } 141 142 // Throw an error if the final string length exceeds the maximum string 143 // length. Perform this check early so we can use int32 operations below. 144 if (intMaxLength > MAX_STRING_LENGTH) { 145 ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE); 146 } 147 148 // Step 9. 149 var fillLen = intMaxLength - strLen; 150 151 // Step 10. 152 // Perform an int32 division to ensure String_repeat is not called with a 153 // double to avoid repeated bailouts in ToInteger. 154 var truncatedStringFiller = callFunction( 155 String_repeat, 156 filler, 157 (fillLen / filler.length) | 0 158 ); 159 160 truncatedStringFiller += Substring(filler, 0, fillLen % filler.length); 161 162 // Step 11. 163 if (padEnd === true) { 164 return str + truncatedStringFiller; 165 } 166 return truncatedStringFiller + str; 167 } 168 169 function String_pad_start(maxLength, fillString = " ") { 170 return callFunction(String_pad, this, maxLength, fillString, false); 171 } 172 173 function String_pad_end(maxLength, fillString = " ") { 174 return callFunction(String_pad, this, maxLength, fillString, true); 175 } 176 177 // A thin wrapper to call SubstringKernel with int32-typed arguments. 178 // Caller should check the range of |from| and |length|. 179 function Substring(str, from, length) { 180 assert(typeof str === "string", "|str| should be a string"); 181 assert( 182 (from | 0) === from, 183 "coercing |from| into int32 should not change the value" 184 ); 185 assert( 186 (length | 0) === length, 187 "coercing |length| into int32 should not change the value" 188 ); 189 190 return SubstringKernel( 191 str, 192 std_Math_max(from, 0) | 0, 193 std_Math_max(length, 0) | 0 194 ); 195 } 196 197 // ES 2016 draft Mar 25, 2016 21.1.3.14. 198 function String_replace(searchValue, replaceValue) { 199 // Step 1. 200 if (IsNullOrUndefined(this)) { 201 ThrowIncompatibleMethod("replace", this); 202 } 203 204 // Step 2. 205 if (IsObject(searchValue)) { 206 // Fast path for regular expressions with the original 207 // RegExp.prototype[@@replace] function. 208 if (IsOptimizableRegExpObject(searchValue)) { 209 return callFunction(RegExpReplace, searchValue, this, replaceValue); 210 } 211 212 // Step 2.a. 213 var replacer = GetMethod(searchValue, GetBuiltinSymbol("replace")); 214 215 // Step 2.b. 216 if (replacer !== undefined) { 217 return callContentFunction(replacer, searchValue, this, replaceValue); 218 } 219 } 220 221 // Step 3. 222 var string = ToString(this); 223 224 // Step 4. 225 var searchString = ToString(searchValue); 226 227 if (typeof replaceValue === "string") { 228 // Steps 6-12: Optimized for string case. 229 return StringReplaceString(string, searchString, replaceValue); 230 } 231 232 // Step 5. 233 if (!IsCallable(replaceValue)) { 234 // Steps 6-12. 235 return StringReplaceString(string, searchString, ToString(replaceValue)); 236 } 237 238 // Step 7. 239 var pos = callFunction(std_String_indexOf, string, searchString); 240 if (pos === -1) { 241 return string; 242 } 243 244 // Step 8. 245 var replStr = ToString( 246 callContentFunction(replaceValue, undefined, searchString, pos, string) 247 ); 248 249 // Step 10. 250 var tailPos = pos + searchString.length; 251 252 // Step 11. 253 var newString; 254 if (pos === 0) { 255 newString = ""; 256 } else { 257 newString = Substring(string, 0, pos); 258 } 259 260 newString += replStr; 261 var stringLength = string.length; 262 if (tailPos < stringLength) { 263 newString += Substring(string, tailPos, stringLength - tailPos); 264 } 265 266 // Step 12. 267 return newString; 268 } 269 270 // String.prototype.replaceAll (Stage 3 proposal) 271 // https://tc39.es/proposal-string-replaceall/ 272 // 273 // String.prototype.replaceAll ( searchValue, replaceValue ) 274 function String_replaceAll(searchValue, replaceValue) { 275 // Step 1. 276 if (IsNullOrUndefined(this)) { 277 ThrowIncompatibleMethod("replaceAll", this); 278 } 279 280 // Step 2. 281 if (IsObject(searchValue)) { 282 // Steps 2.a-b. 283 if (IsRegExp(searchValue)) { 284 // Step 2.b.i. 285 var flags = searchValue.flags; 286 287 // Step 2.b.ii. 288 if (IsNullOrUndefined(flags)) { 289 ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL); 290 } 291 292 // Step 2.b.iii. 293 if (!callFunction(std_String_includes, ToString(flags), "g")) { 294 ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "replaceAll"); 295 } 296 } 297 298 // Fast path for regular expressions with the original 299 // RegExp.prototype[@@replace] function. 300 if (IsOptimizableRegExpObject(searchValue)) { 301 return callFunction(RegExpReplace, searchValue, this, replaceValue); 302 } 303 304 // Step 2.c. 305 var replacer = GetMethod(searchValue, GetBuiltinSymbol("replace")); 306 307 // Step 2.b. 308 if (replacer !== undefined) { 309 return callContentFunction(replacer, searchValue, this, replaceValue); 310 } 311 } 312 313 // Step 3. 314 var string = ToString(this); 315 316 // Step 4. 317 var searchString = ToString(searchValue); 318 319 // Steps 5-6. 320 if (!IsCallable(replaceValue)) { 321 // Steps 7-16. 322 return StringReplaceAllString(string, searchString, ToString(replaceValue)); 323 } 324 325 // Step 7. 326 var searchLength = searchString.length; 327 328 // Step 8. 329 var advanceBy = std_Math_max(1, searchLength); 330 331 // Step 9 (not needed in this implementation). 332 333 // Step 12. 334 var endOfLastMatch = 0; 335 336 // Step 13. 337 var result = ""; 338 339 // Steps 10-11, 14. 340 var position = 0; 341 while (true) { 342 // Steps 10-11. 343 // 344 // StringIndexOf doesn't clamp the |position| argument to the input 345 // string length, i.e. |StringIndexOf("abc", "", 4)| returns -1, 346 // whereas |"abc".indexOf("", 4)| returns 3. That means we need to 347 // exit the loop when |nextPosition| is smaller than |position| and 348 // not just when |nextPosition| is -1. 349 var nextPosition = callFunction( 350 std_String_indexOf, 351 string, 352 searchString, 353 position 354 ); 355 if (nextPosition < position) { 356 break; 357 } 358 position = nextPosition; 359 360 // Step 14.a. 361 var replacement = ToString( 362 callContentFunction( 363 replaceValue, 364 undefined, 365 searchString, 366 position, 367 string 368 ) 369 ); 370 371 // Step 14.b (not applicable). 372 373 // Step 14.c. 374 var stringSlice = Substring( 375 string, 376 endOfLastMatch, 377 position - endOfLastMatch 378 ); 379 380 // Step 14.d. 381 result += stringSlice + replacement; 382 383 // Step 14.e. 384 endOfLastMatch = position + searchLength; 385 386 // Step 11.b. 387 position += advanceBy; 388 } 389 390 // Step 15. 391 if (endOfLastMatch < string.length) { 392 // Step 15.a. 393 result += Substring(string, endOfLastMatch, string.length - endOfLastMatch); 394 } 395 396 // Step 16. 397 return result; 398 } 399 400 // ES 2016 draft Mar 25, 2016 21.1.3.15. 401 function String_search(regexp) { 402 // Step 1. 403 if (IsNullOrUndefined(this)) { 404 ThrowIncompatibleMethod("search", this); 405 } 406 407 // Step 2. 408 var isPatternString = typeof regexp === "string"; 409 if (IsObject(regexp)) { 410 // Fast path for regular expressions with the original 411 // RegExp.prototype[@@search] function. 412 if (IsOptimizableRegExpObject(regexp)) { 413 return callFunction(RegExpSearch, regexp, this); 414 } 415 416 // Step 2.a. 417 var searcher = GetMethod(regexp, GetBuiltinSymbol("search")); 418 419 // Step 2.b. 420 if (searcher !== undefined) { 421 return callContentFunction(searcher, regexp, this); 422 } 423 } 424 425 // Step 3. 426 var string = ToString(this); 427 428 if (isPatternString && IsRegExpPrototypeOptimizable()) { 429 var flatResult = FlatStringSearch(string, regexp); 430 if (flatResult !== -2) { 431 return flatResult; 432 } 433 } 434 435 // Step 4. 436 var rx = RegExpCreate(regexp); 437 438 // Step 5. 439 return callContentFunction( 440 GetMethod(rx, GetBuiltinSymbol("search")), 441 rx, 442 string 443 ); 444 } 445 446 // ES 2016 draft Mar 25, 2016 21.1.3.17. 447 function String_split(separator, limit) { 448 // Step 1. 449 if (IsNullOrUndefined(this)) { 450 ThrowIncompatibleMethod("split", this); 451 } 452 453 // Optimized path for string.split(string), especially when both strings 454 // are constants. Following sequence of if's cannot be put together in 455 // order that IonMonkey sees the constant if present (bug 1246141). 456 if (typeof this === "string") { 457 if (typeof separator === "string") { 458 if (limit === undefined) { 459 // inlineConstantStringSplitString needs both arguments to 460 // be MConstant, so pass them directly. 461 return StringSplitString(this, separator); 462 } 463 } 464 } 465 466 // Step 2. 467 if (IsObject(separator)) { 468 // Fast path for regular expressions with the original 469 // RegExp.prototype[@@split] function. 470 if (IsOptimizableRegExpObject(separator)) { 471 return callFunction(RegExpSplit, separator, this, limit); 472 } 473 474 // Step 2.a. 475 var splitter = GetMethod(separator, GetBuiltinSymbol("split")); 476 477 // Step 2.b. 478 if (splitter !== undefined) { 479 return callContentFunction(splitter, separator, this, limit); 480 } 481 } 482 483 // Step 3. 484 var S = ToString(this); 485 486 // Step 6. 487 var R; 488 if (limit !== undefined) { 489 var lim = limit >>> 0; 490 491 // Step 9. 492 R = ToString(separator); 493 494 // Step 10. 495 if (lim === 0) { 496 return []; 497 } 498 499 // Step 11. 500 if (separator === undefined) { 501 return [S]; 502 } 503 504 // Steps 4, 8, 12-18. 505 return StringSplitStringLimit(S, R, lim); 506 } 507 508 // Step 9. 509 R = ToString(separator); 510 511 // Step 11. 512 if (separator === undefined) { 513 return [S]; 514 } 515 516 // Optimized path. 517 // Steps 4, 8, 12-18. 518 return StringSplitString(S, R); 519 } 520 521 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 522 // 21.1.3.22 String.prototype.substring ( start, end ) 523 // 524 // NOTE: When changing this method, make sure that GVN can still optimize common 525 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo. 526 // 527 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270. 528 function String_substring(start, end) { 529 // Step 1. 530 if (IsNullOrUndefined(this)) { 531 ThrowIncompatibleMethod("substring", this); 532 } 533 534 // Step 2. 535 var str = ToString(this); 536 537 // Step 3. 538 var len = str.length; 539 540 // Step 4. 541 var intStart = ToInteger(start); 542 543 // Step 5. 544 var intEnd = end === undefined ? len : ToInteger(end); 545 546 // Step 6. 547 var finalStart = std_Math_min(std_Math_max(intStart, 0), len); 548 549 // Step 7. 550 var finalEnd = std_Math_min(std_Math_max(intEnd, 0), len); 551 552 // Step 8. 553 var from = std_Math_min(finalStart, finalEnd); 554 555 // Step 9. 556 var to = std_Math_max(finalStart, finalEnd); 557 558 // Step 10. 559 // While |from| and |to - from| are bounded to the length of |str| and this 560 // and thus definitely in the int32 range, they can still be typed as 561 // double. Eagerly truncate since SubstringKernel only accepts int32. 562 return SubstringKernel(str, from | 0, (to - from) | 0); 563 } 564 SetIsInlinableLargeFunction(String_substring); 565 566 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 567 // B.2.3.1 String.prototype.substr ( start, length ) 568 // 569 // NOTE: When changing this method, make sure that GVN can still optimize common 570 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo. 571 // 572 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270. 573 function String_substr(start, length) { 574 // Steps 1. 575 if (IsNullOrUndefined(this)) { 576 ThrowIncompatibleMethod("substr", this); 577 } 578 579 // Step 2. 580 var str = ToString(this); 581 582 // Step 3. 583 var intStart = ToInteger(start); 584 585 // Steps 4-5. 586 var size = str.length; 587 // Use |size| instead of +Infinity to avoid performing calculations with 588 // doubles. (The result is the same either way.) 589 var end = length === undefined ? size : ToInteger(length); 590 591 // Step 6. 592 if (intStart < 0) { 593 intStart = std_Math_max(intStart + size, 0); 594 } else { 595 // Restrict the input range to allow better Ion optimizations. 596 intStart = std_Math_min(intStart, size); 597 } 598 599 // Step 7. 600 var resultLength = std_Math_min(std_Math_max(end, 0), size - intStart); 601 602 // Step 8. 603 assert( 604 0 <= resultLength && resultLength <= size - intStart, 605 "resultLength is a valid substring length value" 606 ); 607 608 // Step 9. 609 // While |intStart| and |resultLength| are bounded to the length of |str| 610 // and thus definitely in the int32 range, they can still be typed as 611 // double. Eagerly truncate since SubstringKernel only accepts int32. 612 return SubstringKernel(str, intStart | 0, resultLength | 0); 613 } 614 SetIsInlinableLargeFunction(String_substr); 615 616 // ES2021 draft rev 12a546b92275a0e2f834017db2727bb9c6f6c8fd 617 // 21.1.3.4 String.prototype.concat ( ...args ) 618 // Note: String.prototype.concat.length is 1. 619 function String_concat(arg1) { 620 // Step 1. 621 if (IsNullOrUndefined(this)) { 622 ThrowIncompatibleMethod("concat", this); 623 } 624 625 // Step 2. 626 var str = ToString(this); 627 628 // Specialize for the most common number of arguments for better inlining. 629 if (ArgumentsLength() === 0) { 630 return str; 631 } 632 if (ArgumentsLength() === 1) { 633 return str + ToString(GetArgument(0)); 634 } 635 if (ArgumentsLength() === 2) { 636 return str + ToString(GetArgument(0)) + ToString(GetArgument(1)); 637 } 638 639 // Step 3. (implicit) 640 // Step 4. 641 var result = str; 642 643 // Step 5. 644 for (var i = 0; i < ArgumentsLength(); i++) { 645 // Steps 5.a-b. 646 var nextString = ToString(GetArgument(i)); 647 // Step 5.c. 648 result += nextString; 649 } 650 651 // Step 6. 652 return result; 653 } 654 655 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 656 // 21.1.3.19 String.prototype.slice ( start, end ) 657 // 658 // NOTE: When changing this method, make sure that GVN can still optimize common 659 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo. 660 // 661 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270. 662 function String_slice(start, end) { 663 // Step 1. 664 if (IsNullOrUndefined(this)) { 665 ThrowIncompatibleMethod("slice", this); 666 } 667 668 // Step 2. 669 var str = ToString(this); 670 671 // Step 3. 672 var len = str.length; 673 674 // Step 4. 675 var intStart = ToInteger(start); 676 677 // Step 5. 678 var intEnd = end === undefined ? len : ToInteger(end); 679 680 // Step 6. 681 var from = 682 intStart < 0 683 ? std_Math_max(len + intStart, 0) 684 : std_Math_min(intStart, len); 685 686 // Step 7. 687 var to = 688 intEnd < 0 ? std_Math_max(len + intEnd, 0) : std_Math_min(intEnd, len); 689 690 // Step 8. 691 var span = std_Math_max(to - from, 0); 692 693 // Step 9. 694 // While |from| and |span| are bounded to the length of |str| 695 // and thus definitely in the int32 range, they can still be typed as 696 // double. Eagerly truncate since SubstringKernel only accepts int32. 697 return SubstringKernel(str, from | 0, span | 0); 698 } 699 SetIsInlinableLargeFunction(String_slice); 700 701 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 702 // 21.1.3.16 String.prototype.repeat ( count ) 703 function String_repeat(count) { 704 // Step 1. 705 if (IsNullOrUndefined(this)) { 706 ThrowIncompatibleMethod("repeat", this); 707 } 708 709 // Step 2. 710 var S = ToString(this); 711 712 // Step 3. 713 var n = ToInteger(count); 714 715 // Step 4. 716 if (n < 0) { 717 ThrowRangeError(JSMSG_NEGATIVE_REPETITION_COUNT); 718 } 719 720 // Step 5. 721 // Inverted condition to handle |Infinity * 0 = NaN| correctly. 722 if (!(n * S.length <= MAX_STRING_LENGTH)) { 723 ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE); 724 } 725 726 // Communicate |n|'s possible range to the compiler. We actually use 727 // MAX_STRING_LENGTH + 1 as range because that's a valid bit mask. That's 728 // fine because it's only used as optimization hint. 729 assert( 730 TO_INT32(MAX_STRING_LENGTH + 1) === MAX_STRING_LENGTH + 1, 731 "MAX_STRING_LENGTH + 1 must fit in int32" 732 ); 733 assert( 734 ((MAX_STRING_LENGTH + 1) & (MAX_STRING_LENGTH + 2)) === 0, 735 "MAX_STRING_LENGTH + 1 can be used as a bitmask" 736 ); 737 n = n & (MAX_STRING_LENGTH + 1); 738 739 // Steps 6-7. 740 var T = ""; 741 for (;;) { 742 if (n & 1) { 743 T += S; 744 } 745 n >>= 1; 746 if (n) { 747 S += S; 748 } else { 749 break; 750 } 751 } 752 return T; 753 } 754 755 // ES6 draft specification, section 21.1.3.27, version 2013-09-27. 756 function String_iterator() { 757 // Step 1. 758 if (IsNullOrUndefined(this)) { 759 ThrowTypeError( 760 JSMSG_INCOMPATIBLE_PROTO2, 761 "String", 762 "Symbol.iterator", 763 ToString(this) 764 ); 765 } 766 767 // Step 2. 768 var S = ToString(this); 769 770 // Step 3. 771 var iterator = NewStringIterator(); 772 UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, S); 773 UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0); 774 return iterator; 775 } 776 777 function StringIteratorNext() { 778 var obj = this; 779 if (!IsObject(obj) || (obj = GuardToStringIterator(obj)) === null) { 780 return callFunction( 781 CallStringIteratorMethodIfWrapped, 782 this, 783 "StringIteratorNext" 784 ); 785 } 786 787 var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET); 788 // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in 789 // SelfHostring.cpp) so our current index can never be anything other than 790 // an Int32Value. 791 var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); 792 var size = S.length; 793 var result = { value: undefined, done: false }; 794 795 if (index >= size) { 796 result.done = true; 797 return result; 798 } 799 800 var codePoint = callFunction(std_String_codePointAt, S, index); 801 var charCount = 1 + (codePoint > 0xffff); 802 803 UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount); 804 805 result.value = callFunction(std_String_fromCodePoint, null, codePoint); 806 807 return result; 808 } 809 SetIsInlinableLargeFunction(StringIteratorNext); 810 811 // ES2018 draft rev 8fadde42cf6a9879b4ab0cb6142b31c4ee501667 812 // 21.1.2.4 String.raw ( template, ...substitutions ) 813 function String_static_raw(callSite /*, ...substitutions*/) { 814 // Steps 1-2 (not applicable). 815 816 // Step 3. 817 var cooked = ToObject(callSite); 818 819 // Step 4. 820 var raw = ToObject(cooked.raw); 821 822 // Step 5. 823 var literalSegments = ToLength(raw.length); 824 825 // Step 6. 826 if (literalSegments === 0) { 827 return ""; 828 } 829 830 // Special case for |String.raw `<literal>`| callers to avoid falling into 831 // the loop code below. 832 if (literalSegments === 1) { 833 return ToString(raw[0]); 834 } 835 836 // Steps 7-9 were reordered to use ArgumentsLength/GetArgument instead of a 837 // rest parameter, because the former is currently more optimized. 838 // 839 // String.raw intersperses the substitution elements between the literal 840 // segments, i.e. a substitution is added iff there are still pending 841 // literal segments. Furthermore by moving the access to |raw[0]| outside 842 // of the loop, we can use |nextIndex| to index into both, the |raw| array 843 // and the arguments. 844 845 // Steps 7 (implicit) and 9.a-c. 846 var resultString = ToString(raw[0]); 847 848 // Steps 8-9, 9.d, and 9.i. 849 for (var nextIndex = 1; nextIndex < literalSegments; nextIndex++) { 850 // Steps 9.e-h. 851 if (nextIndex < ArgumentsLength()) { 852 resultString += ToString(GetArgument(nextIndex)); 853 } 854 855 // Steps 9.a-c. 856 resultString += ToString(raw[nextIndex]); 857 } 858 859 // Step 9.d.i. 860 return resultString; 861 } 862 863 // ES6 draft 2014-04-27 B.2.3.3 864 function String_big() { 865 if (IsNullOrUndefined(this)) { 866 ThrowIncompatibleMethod("big", this); 867 } 868 return "<big>" + ToString(this) + "</big>"; 869 } 870 871 // ES6 draft 2014-04-27 B.2.3.4 872 function String_blink() { 873 if (IsNullOrUndefined(this)) { 874 ThrowIncompatibleMethod("blink", this); 875 } 876 return "<blink>" + ToString(this) + "</blink>"; 877 } 878 879 // ES6 draft 2014-04-27 B.2.3.5 880 function String_bold() { 881 if (IsNullOrUndefined(this)) { 882 ThrowIncompatibleMethod("bold", this); 883 } 884 return "<b>" + ToString(this) + "</b>"; 885 } 886 887 // ES6 draft 2014-04-27 B.2.3.6 888 function String_fixed() { 889 if (IsNullOrUndefined(this)) { 890 ThrowIncompatibleMethod("fixed", this); 891 } 892 return "<tt>" + ToString(this) + "</tt>"; 893 } 894 895 // ES6 draft 2014-04-27 B.2.3.9 896 function String_italics() { 897 if (IsNullOrUndefined(this)) { 898 ThrowIncompatibleMethod("italics", this); 899 } 900 return "<i>" + ToString(this) + "</i>"; 901 } 902 903 // ES6 draft 2014-04-27 B.2.3.11 904 function String_small() { 905 if (IsNullOrUndefined(this)) { 906 ThrowIncompatibleMethod("small", this); 907 } 908 return "<small>" + ToString(this) + "</small>"; 909 } 910 911 // ES6 draft 2014-04-27 B.2.3.12 912 function String_strike() { 913 if (IsNullOrUndefined(this)) { 914 ThrowIncompatibleMethod("strike", this); 915 } 916 return "<strike>" + ToString(this) + "</strike>"; 917 } 918 919 // ES6 draft 2014-04-27 B.2.3.13 920 function String_sub() { 921 if (IsNullOrUndefined(this)) { 922 ThrowIncompatibleMethod("sub", this); 923 } 924 return "<sub>" + ToString(this) + "</sub>"; 925 } 926 927 // ES6 draft 2014-04-27 B.2.3.14 928 function String_sup() { 929 if (IsNullOrUndefined(this)) { 930 ThrowIncompatibleMethod("sup", this); 931 } 932 return "<sup>" + ToString(this) + "</sup>"; 933 } 934 935 function EscapeAttributeValue(v) { 936 var inputStr = ToString(v); 937 return StringReplaceAllString(inputStr, '"', """); 938 } 939 940 // ES6 draft 2014-04-27 B.2.3.2 941 function String_anchor(name) { 942 if (IsNullOrUndefined(this)) { 943 ThrowIncompatibleMethod("anchor", this); 944 } 945 var S = ToString(this); 946 return '<a name="' + EscapeAttributeValue(name) + '">' + S + "</a>"; 947 } 948 949 // ES6 draft 2014-04-27 B.2.3.7 950 function String_fontcolor(color) { 951 if (IsNullOrUndefined(this)) { 952 ThrowIncompatibleMethod("fontcolor", this); 953 } 954 var S = ToString(this); 955 return '<font color="' + EscapeAttributeValue(color) + '">' + S + "</font>"; 956 } 957 958 // ES6 draft 2014-04-27 B.2.3.8 959 function String_fontsize(size) { 960 if (IsNullOrUndefined(this)) { 961 ThrowIncompatibleMethod("fontsize", this); 962 } 963 var S = ToString(this); 964 return '<font size="' + EscapeAttributeValue(size) + '">' + S + "</font>"; 965 } 966 967 // ES6 draft 2014-04-27 B.2.3.10 968 function String_link(url) { 969 if (IsNullOrUndefined(this)) { 970 ThrowIncompatibleMethod("link", this); 971 } 972 var S = ToString(this); 973 return '<a href="' + EscapeAttributeValue(url) + '">' + S + "</a>"; 974 }