| Index: src/js/string.js
|
| diff --git a/src/js/string.js b/src/js/string.js
|
| index b220038b74ce1283f0575943533d8fde8e9180ae..e906a563652782ace88005b3aa11fbbbef1d9503 100644
|
| --- a/src/js/string.js
|
| +++ b/src/js/string.js
|
| @@ -20,9 +20,8 @@ var MakeTypeError;
|
| var MathMax;
|
| var MathMin;
|
| var matchSymbol = utils.ImportNow("match_symbol");
|
| -var RegExpExec;
|
| var RegExpExecNoTests;
|
| -var RegExpLastMatchInfo;
|
| +var replaceSymbol = utils.ImportNow("replace_symbol");
|
| var searchSymbol = utils.ImportNow("search_symbol");
|
| var splitSymbol = utils.ImportNow("split_symbol");
|
|
|
| @@ -33,9 +32,7 @@ utils.Import(function(from) {
|
| MakeTypeError = from.MakeTypeError;
|
| MathMax = from.MathMax;
|
| MathMin = from.MathMin;
|
| - RegExpExec = from.RegExpExec;
|
| RegExpExecNoTests = from.RegExpExecNoTests;
|
| - RegExpLastMatchInfo = from.RegExpLastMatchInfo;
|
| });
|
|
|
| //-------------------------------------------------------------------
|
| @@ -206,14 +203,12 @@ function StringNormalizeJS() {
|
| var reusableMatchInfo = [2, "", "", -1, -1];
|
|
|
|
|
| -// ECMA-262, section 15.5.4.11
|
| +// ES6, section 21.1.3.14
|
| function StringReplace(search, replace) {
|
| CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace");
|
|
|
| - var subject = TO_STRING(this);
|
| -
|
| // Decision tree for dispatch
|
| - // .. regexp search
|
| + // .. regexp search (in src/js/regexp.js, RegExpReplace)
|
| // .... string replace
|
| // ...... non-global search
|
| // ........ empty string replace
|
| @@ -229,40 +224,15 @@ function StringReplace(search, replace) {
|
| // ...... function replace
|
| // ...... string replace (with $-expansion)
|
|
|
| - if (IS_REGEXP(search)) {
|
| - if (!IS_CALLABLE(replace)) {
|
| - replace = TO_STRING(replace);
|
| -
|
| - if (!REGEXP_GLOBAL(search)) {
|
| - // Non-global regexp search, string replace.
|
| - var match = RegExpExec(search, subject, 0);
|
| - if (match == null) {
|
| - search.lastIndex = 0
|
| - return subject;
|
| - }
|
| - if (replace.length == 0) {
|
| - return %_SubString(subject, 0, match[CAPTURE0]) +
|
| - %_SubString(subject, match[CAPTURE1], subject.length)
|
| - }
|
| - return ExpandReplacement(replace, subject, RegExpLastMatchInfo,
|
| - %_SubString(subject, 0, match[CAPTURE0])) +
|
| - %_SubString(subject, match[CAPTURE1], subject.length);
|
| - }
|
| -
|
| - // Global regexp search, string replace.
|
| - search.lastIndex = 0;
|
| - return %StringReplaceGlobalRegExpWithString(
|
| - subject, search, replace, RegExpLastMatchInfo);
|
| + if (!IS_NULL_OR_UNDEFINED(search)) {
|
| + var replacer = search[replaceSymbol];
|
| + if (!IS_UNDEFINED(replacer)) {
|
| + return %_Call(replacer, search, this, replace);
|
| }
|
| -
|
| - if (REGEXP_GLOBAL(search)) {
|
| - // Global regexp search, function replace.
|
| - return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
|
| - }
|
| - // Non-global regexp search, function replace.
|
| - return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace);
|
| }
|
|
|
| + var subject = TO_STRING(this);
|
| +
|
| search = TO_STRING(search);
|
|
|
| if (search.length == 1 &&
|
| @@ -379,130 +349,6 @@ function ExpandReplacement(string, subject, matchInfo, result) {
|
| }
|
|
|
|
|
| -// Compute the string of a given regular expression capture.
|
| -function CaptureString(string, lastCaptureInfo, index) {
|
| - // Scale the index.
|
| - var scaled = index << 1;
|
| - // Compute start and end.
|
| - var start = lastCaptureInfo[CAPTURE(scaled)];
|
| - // If start isn't valid, return undefined.
|
| - if (start < 0) return;
|
| - var end = lastCaptureInfo[CAPTURE(scaled + 1)];
|
| - return %_SubString(string, start, end);
|
| -}
|
| -
|
| -
|
| -// TODO(lrn): This array will survive indefinitely if replace is never
|
| -// called again. However, it will be empty, since the contents are cleared
|
| -// in the finally block.
|
| -var reusableReplaceArray = new InternalArray(4);
|
| -
|
| -// Helper function for replacing regular expressions with the result of a
|
| -// function application in String.prototype.replace.
|
| -function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
|
| - var resultArray = reusableReplaceArray;
|
| - if (resultArray) {
|
| - reusableReplaceArray = null;
|
| - } else {
|
| - // Inside a nested replace (replace called from the replacement function
|
| - // of another replace) or we have failed to set the reusable array
|
| - // back due to an exception in a replacement function. Create a new
|
| - // array to use in the future, or until the original is written back.
|
| - resultArray = new InternalArray(16);
|
| - }
|
| - var res = %RegExpExecMultiple(regexp,
|
| - subject,
|
| - RegExpLastMatchInfo,
|
| - resultArray);
|
| - regexp.lastIndex = 0;
|
| - if (IS_NULL(res)) {
|
| - // No matches at all.
|
| - reusableReplaceArray = resultArray;
|
| - return subject;
|
| - }
|
| - var len = res.length;
|
| - if (NUMBER_OF_CAPTURES(RegExpLastMatchInfo) == 2) {
|
| - // If the number of captures is two then there are no explicit captures in
|
| - // the regexp, just the implicit capture that captures the whole match. In
|
| - // this case we can simplify quite a bit and end up with something faster.
|
| - // The builder will consist of some integers that indicate slices of the
|
| - // input string and some replacements that were returned from the replace
|
| - // function.
|
| - var match_start = 0;
|
| - for (var i = 0; i < len; i++) {
|
| - var elem = res[i];
|
| - if (%_IsSmi(elem)) {
|
| - // Integers represent slices of the original string.
|
| - if (elem > 0) {
|
| - match_start = (elem >> 11) + (elem & 0x7ff);
|
| - } else {
|
| - match_start = res[++i] - elem;
|
| - }
|
| - } else {
|
| - var func_result = replace(elem, match_start, subject);
|
| - // Overwrite the i'th element in the results with the string we got
|
| - // back from the callback function.
|
| - res[i] = TO_STRING(func_result);
|
| - match_start += elem.length;
|
| - }
|
| - }
|
| - } else {
|
| - for (var i = 0; i < len; i++) {
|
| - var elem = res[i];
|
| - if (!%_IsSmi(elem)) {
|
| - // elem must be an Array.
|
| - // Use the apply argument as backing for global RegExp properties.
|
| - var func_result = %Apply(replace, UNDEFINED, elem, 0, elem.length);
|
| - // Overwrite the i'th element in the results with the string we got
|
| - // back from the callback function.
|
| - res[i] = TO_STRING(func_result);
|
| - }
|
| - }
|
| - }
|
| - var result = %StringBuilderConcat(res, len, subject);
|
| - resultArray.length = 0;
|
| - reusableReplaceArray = resultArray;
|
| - return result;
|
| -}
|
| -
|
| -
|
| -function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
|
| - var matchInfo = RegExpExec(regexp, subject, 0);
|
| - if (IS_NULL(matchInfo)) {
|
| - regexp.lastIndex = 0;
|
| - return subject;
|
| - }
|
| - var index = matchInfo[CAPTURE0];
|
| - var result = %_SubString(subject, 0, index);
|
| - var endOfMatch = matchInfo[CAPTURE1];
|
| - // Compute the parameter list consisting of the match, captures, index,
|
| - // and subject for the replace function invocation.
|
| - // The number of captures plus one for the match.
|
| - var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
|
| - var replacement;
|
| - if (m == 1) {
|
| - // No captures, only the match, which is always valid.
|
| - var s = %_SubString(subject, index, endOfMatch);
|
| - // Don't call directly to avoid exposing the built-in global object.
|
| - replacement = replace(s, index, subject);
|
| - } else {
|
| - var parameters = new InternalArray(m + 2);
|
| - for (var j = 0; j < m; j++) {
|
| - parameters[j] = CaptureString(subject, matchInfo, j);
|
| - }
|
| - parameters[j] = index;
|
| - parameters[j + 1] = subject;
|
| -
|
| - replacement = %Apply(replace, UNDEFINED, parameters, 0, j + 2);
|
| - }
|
| -
|
| - result += replacement; // The add method converts to string if necessary.
|
| - // Can't use matchInfo any more from here, since the function could
|
| - // overwrite it.
|
| - return result + %_SubString(subject, endOfMatch, subject.length);
|
| -}
|
| -
|
| -
|
| // ES6 21.1.3.15.
|
| function StringSearch(pattern) {
|
| CHECK_OBJECT_COERCIBLE(this, "String.prototype.search");
|
| @@ -1098,6 +944,7 @@ utils.InstallFunctions(GlobalString.prototype, DONT_ENUM, [
|
| // Exports
|
|
|
| utils.Export(function(to) {
|
| + to.ExpandReplacement = ExpandReplacement;
|
| to.StringCharAt = StringCharAtJS;
|
| to.StringIndexOf = StringIndexOfJS;
|
| to.StringLastIndexOf = StringLastIndexOfJS;
|
|
|