diff options
Diffstat (limited to 'deps/v8/src/string.js')
-rw-r--r-- | deps/v8/src/string.js | 151 |
1 files changed, 62 insertions, 89 deletions
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 84dde3dc27..6115930b6c 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -189,7 +189,9 @@ function StringMatch(regexp) { if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); // lastMatchInfo is defined in regexp.js. - return %StringMatch(subject, regexp, lastMatchInfo); + var result = %StringMatch(subject, regexp, lastMatchInfo); + if (result !== null) lastMatchInfoOverride = null; + return result; } // Non-regexp argument. regexp = new $RegExp(regexp); @@ -235,10 +237,28 @@ function StringReplace(search, replace) { replace); } } else { - return %StringReplaceRegExpWithString(subject, - search, - TO_STRING_INLINE(replace), - lastMatchInfo); + if (lastMatchInfoOverride == null) { + return %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); + } else { + // We use this hack to detect whether StringReplaceRegExpWithString + // found at least one hit. In that case we need to remove any + // override. + var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX]; + lastMatchInfo[LAST_SUBJECT_INDEX] = 0; + var answer = %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); + if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) { + lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; + } else { + lastMatchInfoOverride = null; + } + return answer; + } } } @@ -257,47 +277,34 @@ function StringReplace(search, replace) { if (start < 0) return subject; var end = start + search.length; - var builder = new ReplaceResultBuilder(subject); - // prefix - builder.addSpecialSlice(0, start); + var result = SubString(subject, 0, start); // Compute the string to replace with. if (IS_SPEC_FUNCTION(replace)) { var receiver = %GetDefaultReceiver(replace); - builder.add(%_CallFunction(receiver, - search, - start, - subject, - replace)); + result += %_CallFunction(receiver, search, start, subject, replace); } else { reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE1] = end; replace = TO_STRING_INLINE(replace); - ExpandReplacement(replace, subject, reusableMatchInfo, builder); + result = ExpandReplacement(replace, subject, reusableMatchInfo, result); } - // suffix - builder.addSpecialSlice(end, subject.length); - - return builder.generate(); + return result + SubString(subject, end, subject.length); } // Expand the $-expressions in the string and return a new string with // the result. -function ExpandReplacement(string, subject, matchInfo, builder) { +function ExpandReplacement(string, subject, matchInfo, result) { var length = string.length; - var builder_elements = builder.elements; var next = %StringIndexOf(string, '$', 0); if (next < 0) { - if (length > 0) builder_elements.push(string); - return; + if (length > 0) result += string; + return result; } - // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. - var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match. - - if (next > 0) builder_elements.push(SubString(string, 0, next)); + if (next > 0) result += SubString(string, 0, next); while (true) { var expansion = '$'; @@ -306,51 +313,21 @@ function ExpandReplacement(string, subject, matchInfo, builder) { var peek = %_StringCharCodeAt(string, position); if (peek == 36) { // $$ ++position; - builder_elements.push('$'); + result += '$'; } else if (peek == 38) { // $& - match ++position; - builder.addSpecialSlice(matchInfo[CAPTURE0], - matchInfo[CAPTURE1]); + result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]); } else if (peek == 96) { // $` - prefix ++position; - builder.addSpecialSlice(0, matchInfo[CAPTURE0]); + result += SubString(subject, 0, matchInfo[CAPTURE0]); } else if (peek == 39) { // $' - suffix ++position; - builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length); - } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9 - ++position; - var n = peek - 48; - if (position < length) { - peek = %_StringCharCodeAt(string, position); - // $nn, 01 <= nn <= 99 - if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) { - var nn = n * 10 + (peek - 48); - if (nn < m) { - // If the two digit capture reference is within range of - // the captures, we use it instead of the single digit - // one. Otherwise, we fall back to using the single - // digit reference. This matches the behavior of - // SpiderMonkey. - ++position; - n = nn; - } - } - } - if (0 < n && n < m) { - addCaptureString(builder, matchInfo, n); - } else { - // Because of the captures range check in the parsing of two - // digit capture references, we can only enter here when a - // single digit capture reference is outside the range of - // captures. - builder_elements.push('$'); - --position; - } + result += SubString(subject, matchInfo[CAPTURE1], subject.length); } else { - builder_elements.push('$'); + result += '$'; } } else { - builder_elements.push('$'); + result += '$'; } // Go the the next $ in the string. @@ -360,16 +337,17 @@ function ExpandReplacement(string, subject, matchInfo, builder) { // haven't reached the end, we need to append the suffix. if (next < 0) { if (position < length) { - builder_elements.push(SubString(string, position, length)); + result += SubString(string, position, length); } - return; + return result; } // Append substring between the previous and the next $ character. if (next > position) { - builder_elements.push(SubString(string, position, next)); + result += SubString(string, position, next); } } + return result; } @@ -386,18 +364,6 @@ function CaptureString(string, lastCaptureInfo, index) { } -// Add the string of a given regular expression capture to the -// ReplaceResultBuilder -function addCaptureString(builder, matchInfo, index) { - // Scale the index. - var scaled = index << 1; - // Compute start and end. - var start = matchInfo[CAPTURE(scaled)]; - if (start < 0) return; - var end = matchInfo[CAPTURE(scaled + 1)]; - builder.addSpecialSlice(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. @@ -427,14 +393,22 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { return subject; } var len = res.length; - var i = 0; if (NUMBER_OF_CAPTURES(lastMatchInfo) == 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; var override = new InternalArray(null, 0, subject); var receiver = %GetDefaultReceiver(replace); - while (i < len) { + for (var i = 0; i < len; i++) { var elem = res[i]; if (%_IsSmi(elem)) { + // Integers represent slices of the original string. Use these to + // get the offsets we need for the override array (so things like + // RegExp.leftContext work during the callback function. if (elem > 0) { match_start = (elem >> 11) + (elem & 0x7ff); } else { @@ -446,23 +420,25 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { lastMatchInfoOverride = override; var func_result = %_CallFunction(receiver, elem, match_start, subject, replace); + // Overwrite the i'th element in the results with the string we got + // back from the callback function. res[i] = TO_STRING_INLINE(func_result); match_start += elem.length; } - i++; } } else { var receiver = %GetDefaultReceiver(replace); - while (i < len) { + 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. lastMatchInfoOverride = elem; var func_result = %Apply(replace, receiver, 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_INLINE(func_result); } - i++; } } var resultBuilder = new ReplaceResultBuilder(subject, res); @@ -476,9 +452,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { var matchInfo = DoRegExpExec(regexp, subject, 0); if (IS_NULL(matchInfo)) return subject; - var result = new ReplaceResultBuilder(subject); var index = matchInfo[CAPTURE0]; - result.addSpecialSlice(0, index); + 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. @@ -490,8 +465,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { // 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 = - %_CallFunction(receiver, s, index, subject, replace); + replacement = %_CallFunction(receiver, s, index, subject, replace); } else { var parameters = new InternalArray(m + 2); for (var j = 0; j < m; j++) { @@ -503,11 +477,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { replacement = %Apply(replace, receiver, parameters, 0, j + 2); } - result.add(replacement); // The add method converts to string if necessary. + result += replacement; // The add method converts to string if necessary. // Can't use matchInfo any more from here, since the function could // overwrite it. - result.addSpecialSlice(endOfMatch, subject.length); - return result.generate(); + return result + SubString(subject, endOfMatch, subject.length); } |