summaryrefslogtreecommitdiff
path: root/deps/v8/src/string.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/string.js')
-rw-r--r--deps/v8/src/string.js151
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);
}