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