| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 (function(global, utils) { | 5 (function(global, utils) { |
| 6 | 6 |
| 7 %CheckIsBootstrapping(); | 7 %CheckIsBootstrapping(); |
| 8 | 8 |
| 9 // ------------------------------------------------------------------- | 9 // ------------------------------------------------------------------- |
| 10 // Imports | 10 // Imports |
| 11 | 11 |
| 12 var GlobalRegExp = global.RegExp; | 12 var GlobalRegExp = global.RegExp; |
| 13 var GlobalString = global.String; | 13 var GlobalString = global.String; |
| 14 var InternalArray = utils.InternalArray; | 14 var InternalArray = utils.InternalArray; |
| 15 var InternalPackedArray = utils.InternalPackedArray; | 15 var InternalPackedArray = utils.InternalPackedArray; |
| 16 | 16 |
| 17 var MathMax; | 17 var MathMax; |
| 18 var MathMin; | 18 var MathMin; |
| 19 var RegExpExec; |
| 20 var RegExpExecNoTests; |
| 21 var RegExpLastMatchInfo; |
| 19 | 22 |
| 20 utils.Import(function(from) { | 23 utils.Import(function(from) { |
| 21 MathMax = from.MathMax; | 24 MathMax = from.MathMax; |
| 22 MathMin = from.MathMin; | 25 MathMin = from.MathMin; |
| 26 RegExpExec = from.RegExpExec; |
| 27 RegExpExecNoTests = from.RegExpExecNoTests; |
| 28 RegExpLastMatchInfo = from.RegExpLastMatchInfo; |
| 23 }); | 29 }); |
| 24 | 30 |
| 25 //------------------------------------------------------------------- | 31 //------------------------------------------------------------------- |
| 26 | 32 |
| 27 function StringConstructor(x) { | 33 function StringConstructor(x) { |
| 28 if (%_ArgumentsLength() == 0) x = ''; | 34 if (%_ArgumentsLength() == 0) x = ''; |
| 29 if (%_IsConstructCall()) { | 35 if (%_IsConstructCall()) { |
| 30 %_SetValueOf(this, TO_STRING_INLINE(x)); | 36 %_SetValueOf(this, TO_STRING_INLINE(x)); |
| 31 } else { | 37 } else { |
| 32 return IS_SYMBOL(x) ? | 38 return IS_SYMBOL(x) ? |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 // ECMA-262 section 15.5.4.10 | 161 // ECMA-262 section 15.5.4.10 |
| 156 function StringMatchJS(regexp) { | 162 function StringMatchJS(regexp) { |
| 157 CHECK_OBJECT_COERCIBLE(this, "String.prototype.match"); | 163 CHECK_OBJECT_COERCIBLE(this, "String.prototype.match"); |
| 158 | 164 |
| 159 var subject = TO_STRING_INLINE(this); | 165 var subject = TO_STRING_INLINE(this); |
| 160 if (IS_REGEXP(regexp)) { | 166 if (IS_REGEXP(regexp)) { |
| 161 // Emulate RegExp.prototype.exec's side effect in step 5, even though | 167 // Emulate RegExp.prototype.exec's side effect in step 5, even though |
| 162 // value is discarded. | 168 // value is discarded. |
| 163 var lastIndex = regexp.lastIndex; | 169 var lastIndex = regexp.lastIndex; |
| 164 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex); | 170 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex); |
| 165 if (!regexp.global) return $regexpExecNoTests(regexp, subject, 0); | 171 if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0); |
| 166 var result = %StringMatch(subject, regexp, $regexpLastMatchInfo); | 172 var result = %StringMatch(subject, regexp, RegExpLastMatchInfo); |
| 167 if (result !== null) $regexpLastMatchInfoOverride = null; | 173 if (result !== null) $regexpLastMatchInfoOverride = null; |
| 168 regexp.lastIndex = 0; | 174 regexp.lastIndex = 0; |
| 169 return result; | 175 return result; |
| 170 } | 176 } |
| 171 // Non-regexp argument. | 177 // Non-regexp argument. |
| 172 regexp = new GlobalRegExp(regexp); | 178 regexp = new GlobalRegExp(regexp); |
| 173 return $regexpExecNoTests(regexp, subject, 0); | 179 return RegExpExecNoTests(regexp, subject, 0); |
| 174 } | 180 } |
| 175 | 181 |
| 176 | 182 |
| 177 // ECMA-262 v6, section 21.1.3.12 | 183 // ECMA-262 v6, section 21.1.3.12 |
| 178 // | 184 // |
| 179 // For now we do nothing, as proper normalization requires big tables. | 185 // For now we do nothing, as proper normalization requires big tables. |
| 180 // If Intl is enabled, then i18n.js will override it and provide the the | 186 // If Intl is enabled, then i18n.js will override it and provide the the |
| 181 // proper functionality. | 187 // proper functionality. |
| 182 function StringNormalizeJS(form) { | 188 function StringNormalizeJS(form) { |
| 183 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); | 189 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); |
| 184 | 190 |
| 185 var form = form ? TO_STRING_INLINE(form) : 'NFC'; | 191 var form = form ? TO_STRING_INLINE(form) : 'NFC'; |
| 186 | 192 |
| 187 var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; | 193 var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; |
| 188 | 194 |
| 189 var normalizationForm = NORMALIZATION_FORMS.indexOf(form); | 195 var normalizationForm = NORMALIZATION_FORMS.indexOf(form); |
| 190 if (normalizationForm === -1) { | 196 if (normalizationForm === -1) { |
| 191 throw MakeRangeError(kNormalizationForm, NORMALIZATION_FORMS.join(', ')); | 197 throw MakeRangeError(kNormalizationForm, NORMALIZATION_FORMS.join(', ')); |
| 192 } | 198 } |
| 193 | 199 |
| 194 return %_ValueOf(this); | 200 return %_ValueOf(this); |
| 195 } | 201 } |
| 196 | 202 |
| 197 | 203 |
| 198 // This has the same size as the $regexpLastMatchInfo array, and can be used | 204 // This has the same size as the RegExpLastMatchInfo array, and can be used |
| 199 // for functions that expect that structure to be returned. It is used when | 205 // for functions that expect that structure to be returned. It is used when |
| 200 // the needle is a string rather than a regexp. In this case we can't update | 206 // the needle is a string rather than a regexp. In this case we can't update |
| 201 // lastMatchArray without erroneously affecting the properties on the global | 207 // lastMatchArray without erroneously affecting the properties on the global |
| 202 // RegExp object. | 208 // RegExp object. |
| 203 var reusableMatchInfo = [2, "", "", -1, -1]; | 209 var reusableMatchInfo = [2, "", "", -1, -1]; |
| 204 | 210 |
| 205 | 211 |
| 206 // ECMA-262, section 15.5.4.11 | 212 // ECMA-262, section 15.5.4.11 |
| 207 function StringReplace(search, replace) { | 213 function StringReplace(search, replace) { |
| 208 CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace"); | 214 CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace"); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 230 // Emulate RegExp.prototype.exec's side effect in step 5, even if | 236 // Emulate RegExp.prototype.exec's side effect in step 5, even if |
| 231 // value is discarded. | 237 // value is discarded. |
| 232 var lastIndex = search.lastIndex; | 238 var lastIndex = search.lastIndex; |
| 233 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex); | 239 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex); |
| 234 | 240 |
| 235 if (!IS_SPEC_FUNCTION(replace)) { | 241 if (!IS_SPEC_FUNCTION(replace)) { |
| 236 replace = TO_STRING_INLINE(replace); | 242 replace = TO_STRING_INLINE(replace); |
| 237 | 243 |
| 238 if (!search.global) { | 244 if (!search.global) { |
| 239 // Non-global regexp search, string replace. | 245 // Non-global regexp search, string replace. |
| 240 var match = $regexpExec(search, subject, 0); | 246 var match = RegExpExec(search, subject, 0); |
| 241 if (match == null) { | 247 if (match == null) { |
| 242 search.lastIndex = 0 | 248 search.lastIndex = 0 |
| 243 return subject; | 249 return subject; |
| 244 } | 250 } |
| 245 if (replace.length == 0) { | 251 if (replace.length == 0) { |
| 246 return %_SubString(subject, 0, match[CAPTURE0]) + | 252 return %_SubString(subject, 0, match[CAPTURE0]) + |
| 247 %_SubString(subject, match[CAPTURE1], subject.length) | 253 %_SubString(subject, match[CAPTURE1], subject.length) |
| 248 } | 254 } |
| 249 return ExpandReplacement(replace, subject, $regexpLastMatchInfo, | 255 return ExpandReplacement(replace, subject, RegExpLastMatchInfo, |
| 250 %_SubString(subject, 0, match[CAPTURE0])) + | 256 %_SubString(subject, 0, match[CAPTURE0])) + |
| 251 %_SubString(subject, match[CAPTURE1], subject.length); | 257 %_SubString(subject, match[CAPTURE1], subject.length); |
| 252 } | 258 } |
| 253 | 259 |
| 254 // Global regexp search, string replace. | 260 // Global regexp search, string replace. |
| 255 search.lastIndex = 0; | 261 search.lastIndex = 0; |
| 256 if ($regexpLastMatchInfoOverride == null) { | 262 if ($regexpLastMatchInfoOverride == null) { |
| 257 return %StringReplaceGlobalRegExpWithString( | 263 return %StringReplaceGlobalRegExpWithString( |
| 258 subject, search, replace, $regexpLastMatchInfo); | 264 subject, search, replace, RegExpLastMatchInfo); |
| 259 } else { | 265 } else { |
| 260 // We use this hack to detect whether StringReplaceRegExpWithString | 266 // We use this hack to detect whether StringReplaceRegExpWithString |
| 261 // found at least one hit. In that case we need to remove any | 267 // found at least one hit. In that case we need to remove any |
| 262 // override. | 268 // override. |
| 263 var saved_subject = $regexpLastMatchInfo[LAST_SUBJECT_INDEX]; | 269 var saved_subject = RegExpLastMatchInfo[LAST_SUBJECT_INDEX]; |
| 264 $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = 0; | 270 RegExpLastMatchInfo[LAST_SUBJECT_INDEX] = 0; |
| 265 var answer = %StringReplaceGlobalRegExpWithString( | 271 var answer = %StringReplaceGlobalRegExpWithString( |
| 266 subject, search, replace, $regexpLastMatchInfo); | 272 subject, search, replace, RegExpLastMatchInfo); |
| 267 if (%_IsSmi($regexpLastMatchInfo[LAST_SUBJECT_INDEX])) { | 273 if (%_IsSmi(RegExpLastMatchInfo[LAST_SUBJECT_INDEX])) { |
| 268 $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; | 274 RegExpLastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; |
| 269 } else { | 275 } else { |
| 270 $regexpLastMatchInfoOverride = null; | 276 $regexpLastMatchInfoOverride = null; |
| 271 } | 277 } |
| 272 return answer; | 278 return answer; |
| 273 } | 279 } |
| 274 } | 280 } |
| 275 | 281 |
| 276 if (search.global) { | 282 if (search.global) { |
| 277 // Global regexp search, function replace. | 283 // Global regexp search, function replace. |
| 278 return StringReplaceGlobalRegExpWithFunction(subject, search, replace); | 284 return StringReplaceGlobalRegExpWithFunction(subject, search, replace); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 reusableReplaceArray = null; | 430 reusableReplaceArray = null; |
| 425 } else { | 431 } else { |
| 426 // Inside a nested replace (replace called from the replacement function | 432 // Inside a nested replace (replace called from the replacement function |
| 427 // of another replace) or we have failed to set the reusable array | 433 // of another replace) or we have failed to set the reusable array |
| 428 // back due to an exception in a replacement function. Create a new | 434 // back due to an exception in a replacement function. Create a new |
| 429 // array to use in the future, or until the original is written back. | 435 // array to use in the future, or until the original is written back. |
| 430 resultArray = new InternalArray(16); | 436 resultArray = new InternalArray(16); |
| 431 } | 437 } |
| 432 var res = %RegExpExecMultiple(regexp, | 438 var res = %RegExpExecMultiple(regexp, |
| 433 subject, | 439 subject, |
| 434 $regexpLastMatchInfo, | 440 RegExpLastMatchInfo, |
| 435 resultArray); | 441 resultArray); |
| 436 regexp.lastIndex = 0; | 442 regexp.lastIndex = 0; |
| 437 if (IS_NULL(res)) { | 443 if (IS_NULL(res)) { |
| 438 // No matches at all. | 444 // No matches at all. |
| 439 reusableReplaceArray = resultArray; | 445 reusableReplaceArray = resultArray; |
| 440 return subject; | 446 return subject; |
| 441 } | 447 } |
| 442 var len = res.length; | 448 var len = res.length; |
| 443 if (NUMBER_OF_CAPTURES($regexpLastMatchInfo) == 2) { | 449 if (NUMBER_OF_CAPTURES(RegExpLastMatchInfo) == 2) { |
| 444 // If the number of captures is two then there are no explicit captures in | 450 // If the number of captures is two then there are no explicit captures in |
| 445 // the regexp, just the implicit capture that captures the whole match. In | 451 // the regexp, just the implicit capture that captures the whole match. In |
| 446 // this case we can simplify quite a bit and end up with something faster. | 452 // this case we can simplify quite a bit and end up with something faster. |
| 447 // The builder will consist of some integers that indicate slices of the | 453 // The builder will consist of some integers that indicate slices of the |
| 448 // input string and some replacements that were returned from the replace | 454 // input string and some replacements that were returned from the replace |
| 449 // function. | 455 // function. |
| 450 var match_start = 0; | 456 var match_start = 0; |
| 451 var override = new InternalPackedArray(null, 0, subject); | 457 var override = new InternalPackedArray(null, 0, subject); |
| 452 for (var i = 0; i < len; i++) { | 458 for (var i = 0; i < len; i++) { |
| 453 var elem = res[i]; | 459 var elem = res[i]; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 } | 493 } |
| 488 } | 494 } |
| 489 var result = %StringBuilderConcat(res, res.length, subject); | 495 var result = %StringBuilderConcat(res, res.length, subject); |
| 490 resultArray.length = 0; | 496 resultArray.length = 0; |
| 491 reusableReplaceArray = resultArray; | 497 reusableReplaceArray = resultArray; |
| 492 return result; | 498 return result; |
| 493 } | 499 } |
| 494 | 500 |
| 495 | 501 |
| 496 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { | 502 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { |
| 497 var matchInfo = $regexpExec(regexp, subject, 0); | 503 var matchInfo = RegExpExec(regexp, subject, 0); |
| 498 if (IS_NULL(matchInfo)) { | 504 if (IS_NULL(matchInfo)) { |
| 499 regexp.lastIndex = 0; | 505 regexp.lastIndex = 0; |
| 500 return subject; | 506 return subject; |
| 501 } | 507 } |
| 502 var index = matchInfo[CAPTURE0]; | 508 var index = matchInfo[CAPTURE0]; |
| 503 var result = %_SubString(subject, 0, index); | 509 var result = %_SubString(subject, 0, index); |
| 504 var endOfMatch = matchInfo[CAPTURE1]; | 510 var endOfMatch = matchInfo[CAPTURE1]; |
| 505 // Compute the parameter list consisting of the match, captures, index, | 511 // Compute the parameter list consisting of the match, captures, index, |
| 506 // and subject for the replace function invocation. | 512 // and subject for the replace function invocation. |
| 507 // The number of captures plus one for the match. | 513 // The number of captures plus one for the match. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 535 CHECK_OBJECT_COERCIBLE(this, "String.prototype.search"); | 541 CHECK_OBJECT_COERCIBLE(this, "String.prototype.search"); |
| 536 | 542 |
| 537 var regexp; | 543 var regexp; |
| 538 if (IS_STRING(re)) { | 544 if (IS_STRING(re)) { |
| 539 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re); | 545 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re); |
| 540 } else if (IS_REGEXP(re)) { | 546 } else if (IS_REGEXP(re)) { |
| 541 regexp = re; | 547 regexp = re; |
| 542 } else { | 548 } else { |
| 543 regexp = new GlobalRegExp(re); | 549 regexp = new GlobalRegExp(re); |
| 544 } | 550 } |
| 545 var match = $regexpExec(regexp, TO_STRING_INLINE(this), 0); | 551 var match = RegExpExec(regexp, TO_STRING_INLINE(this), 0); |
| 546 if (match) { | 552 if (match) { |
| 547 return match[CAPTURE0]; | 553 return match[CAPTURE0]; |
| 548 } | 554 } |
| 549 return -1; | 555 return -1; |
| 550 } | 556 } |
| 551 | 557 |
| 552 | 558 |
| 553 // ECMA-262 section 15.5.4.13 | 559 // ECMA-262 section 15.5.4.13 |
| 554 function StringSlice(start, end) { | 560 function StringSlice(start, end) { |
| 555 CHECK_OBJECT_COERCIBLE(this, "String.prototype.slice"); | 561 CHECK_OBJECT_COERCIBLE(this, "String.prototype.slice"); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 | 627 |
| 622 if (limit === 0) return []; | 628 if (limit === 0) return []; |
| 623 | 629 |
| 624 // Separator is a regular expression. | 630 // Separator is a regular expression. |
| 625 return StringSplitOnRegExp(subject, separator, limit, length); | 631 return StringSplitOnRegExp(subject, separator, limit, length); |
| 626 } | 632 } |
| 627 | 633 |
| 628 | 634 |
| 629 function StringSplitOnRegExp(subject, separator, limit, length) { | 635 function StringSplitOnRegExp(subject, separator, limit, length) { |
| 630 if (length === 0) { | 636 if (length === 0) { |
| 631 if ($regexpExec(separator, subject, 0, 0) != null) { | 637 if (RegExpExec(separator, subject, 0, 0) != null) { |
| 632 return []; | 638 return []; |
| 633 } | 639 } |
| 634 return [subject]; | 640 return [subject]; |
| 635 } | 641 } |
| 636 | 642 |
| 637 var currentIndex = 0; | 643 var currentIndex = 0; |
| 638 var startIndex = 0; | 644 var startIndex = 0; |
| 639 var startMatch = 0; | 645 var startMatch = 0; |
| 640 var result = new InternalArray(); | 646 var result = new InternalArray(); |
| 641 | 647 |
| 642 outer_loop: | 648 outer_loop: |
| 643 while (true) { | 649 while (true) { |
| 644 | 650 |
| 645 if (startIndex === length) { | 651 if (startIndex === length) { |
| 646 result[result.length] = %_SubString(subject, currentIndex, length); | 652 result[result.length] = %_SubString(subject, currentIndex, length); |
| 647 break; | 653 break; |
| 648 } | 654 } |
| 649 | 655 |
| 650 var matchInfo = $regexpExec(separator, subject, startIndex); | 656 var matchInfo = RegExpExec(separator, subject, startIndex); |
| 651 if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) { | 657 if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) { |
| 652 result[result.length] = %_SubString(subject, currentIndex, length); | 658 result[result.length] = %_SubString(subject, currentIndex, length); |
| 653 break; | 659 break; |
| 654 } | 660 } |
| 655 var endIndex = matchInfo[CAPTURE1]; | 661 var endIndex = matchInfo[CAPTURE1]; |
| 656 | 662 |
| 657 // We ignore a zero-length match at the currentIndex. | 663 // We ignore a zero-length match at the currentIndex. |
| 658 if (startIndex === endIndex && endIndex === currentIndex) { | 664 if (startIndex === endIndex && endIndex === currentIndex) { |
| 659 startIndex++; | 665 startIndex++; |
| 660 continue; | 666 continue; |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1117 | 1123 |
| 1118 // Set the String function and constructor. | 1124 // Set the String function and constructor. |
| 1119 %SetCode(GlobalString, StringConstructor); | 1125 %SetCode(GlobalString, StringConstructor); |
| 1120 %FunctionSetPrototype(GlobalString, new GlobalString()); | 1126 %FunctionSetPrototype(GlobalString, new GlobalString()); |
| 1121 | 1127 |
| 1122 // Set up the constructor property on the String prototype object. | 1128 // Set up the constructor property on the String prototype object. |
| 1123 %AddNamedProperty( | 1129 %AddNamedProperty( |
| 1124 GlobalString.prototype, "constructor", GlobalString, DONT_ENUM); | 1130 GlobalString.prototype, "constructor", GlobalString, DONT_ENUM); |
| 1125 | 1131 |
| 1126 // Set up the non-enumerable functions on the String object. | 1132 // Set up the non-enumerable functions on the String object. |
| 1127 $installFunctions(GlobalString, DONT_ENUM, [ | 1133 utils.InstallFunctions(GlobalString, DONT_ENUM, [ |
| 1128 "fromCharCode", StringFromCharCode, | 1134 "fromCharCode", StringFromCharCode, |
| 1129 "fromCodePoint", StringFromCodePoint, | 1135 "fromCodePoint", StringFromCodePoint, |
| 1130 "raw", StringRaw | 1136 "raw", StringRaw |
| 1131 ]); | 1137 ]); |
| 1132 | 1138 |
| 1133 // Set up the non-enumerable functions on the String prototype object. | 1139 // Set up the non-enumerable functions on the String prototype object. |
| 1134 $installFunctions(GlobalString.prototype, DONT_ENUM, [ | 1140 utils.InstallFunctions(GlobalString.prototype, DONT_ENUM, [ |
| 1135 "valueOf", StringValueOf, | 1141 "valueOf", StringValueOf, |
| 1136 "toString", StringToString, | 1142 "toString", StringToString, |
| 1137 "charAt", StringCharAtJS, | 1143 "charAt", StringCharAtJS, |
| 1138 "charCodeAt", StringCharCodeAtJS, | 1144 "charCodeAt", StringCharCodeAtJS, |
| 1139 "codePointAt", StringCodePointAt, | 1145 "codePointAt", StringCodePointAt, |
| 1140 "concat", StringConcat, | 1146 "concat", StringConcat, |
| 1141 "endsWith", StringEndsWith, | 1147 "endsWith", StringEndsWith, |
| 1142 "includes", StringIncludes, | 1148 "includes", StringIncludes, |
| 1143 "indexOf", StringIndexOfJS, | 1149 "indexOf", StringIndexOfJS, |
| 1144 "lastIndexOf", StringLastIndexOfJS, | 1150 "lastIndexOf", StringLastIndexOfJS, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1179 // ------------------------------------------------------------------- | 1185 // ------------------------------------------------------------------- |
| 1180 // Exports | 1186 // Exports |
| 1181 | 1187 |
| 1182 utils.Export(function(to) { | 1188 utils.Export(function(to) { |
| 1183 to.StringCharAt = StringCharAtJS; | 1189 to.StringCharAt = StringCharAtJS; |
| 1184 to.StringIndexOf = StringIndexOfJS; | 1190 to.StringIndexOf = StringIndexOfJS; |
| 1185 to.StringSubstring = StringSubstring; | 1191 to.StringSubstring = StringSubstring; |
| 1186 }); | 1192 }); |
| 1187 | 1193 |
| 1188 }) | 1194 }) |
| OLD | NEW |