Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Unified Diff: src/string.js

Issue 12177015: Refactor implementation for String.prototype.replace. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: rebased Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime.cc ('k') | test/mjsunit/string-replace.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/string.js
diff --git a/src/string.js b/src/string.js
index 0349837ccb2d855edcfd389186c96f76b14d2743..6054e908ae51e655b757e8b1f7be9e39eb608cf2 100644
--- a/src/string.js
+++ b/src/string.js
@@ -219,60 +219,79 @@ function StringReplace(search, replace) {
}
var subject = TO_STRING_INLINE(this);
- // Delegate to one of the regular expression variants if necessary.
+ // Decision tree for dispatch
+ // .. regexp search
+ // .... string replace
+ // ...... non-global search
+ // ........ empty string replace
+ // ........ non-empty string replace (with $-expansion)
+ // ...... global search
+ // ........ no need to circumvent last match info override
+ // ........ need to circument last match info override
+ // .... function replace
+ // ...... global search
+ // ...... non-global search
+ // .. string search
+ // .... special case that replaces with one single character
+ // ...... function replace
+ // ...... string replace (with $-expansion)
+
if (IS_REGEXP(search)) {
- // Emulate RegExp.prototype.exec's side effect in step 5, even though
+ // Emulate RegExp.prototype.exec's side effect in step 5, even if
// value is discarded.
ToInteger(search.lastIndex);
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
- if (IS_SPEC_FUNCTION(replace)) {
- if (search.global) {
- return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
- } else {
- return StringReplaceNonGlobalRegExpWithFunction(subject,
- search,
- replace);
- }
- } else {
- if (lastMatchInfoOverride == null) {
- var answer = %StringReplaceRegExpWithString(subject,
- search,
- TO_STRING_INLINE(replace),
- lastMatchInfo);
- if (IS_UNDEFINED(answer)) { // No match. Return subject string.
- search.lastIndex = 0;
+
+ if (!IS_SPEC_FUNCTION(replace)) {
+ if (!search.global) {
+ // Non-global regexp search, string replace.
+ var match = DoRegExpExec(search, subject, 0);
+ if (match == null) {
+ search.lastIndex = 0
return subject;
}
- if (search.global) search.lastIndex = 0;
- return answer;
+ replace = TO_STRING_INLINE(replace);
+ if (replace.length == 0) {
+ return %_SubString(subject, 0, match[CAPTURE0]) +
+ %_SubString(subject, match[CAPTURE1], subject.length)
+ }
+ return ExpandReplacement(replace, subject, lastMatchInfo,
+ %_SubString(subject, 0, match[CAPTURE0])) +
+ %_SubString(subject, match[CAPTURE1], subject.length);
+ }
+
+ // Global regexp search, string replace.
+ search.lastIndex = 0;
+ if (lastMatchInfoOverride == null) {
+ return %StringReplaceGlobalRegExpWithString(
+ subject, search, 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 (IS_UNDEFINED(answer)) { // No match. Return subject string.
- search.lastIndex = 0;
- lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
- return subject;
- }
+ var answer = %StringReplaceGlobalRegExpWithString(
+ subject, search, replace, lastMatchInfo);
if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
} else {
lastMatchInfoOverride = null;
}
- if (search.global) search.lastIndex = 0;
return answer;
}
}
+
+ if (search.global) {
+ // Global regexp search, function replace.
+ return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
+ }
+ // Non-global regexp search, function replace.
+ return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace);
}
- // Convert the search argument to a string and search for it.
search = TO_STRING_INLINE(search);
+
if (search.length == 1 &&
subject.length > 0xFF &&
IS_STRING(replace) &&
@@ -295,8 +314,10 @@ function StringReplace(search, replace) {
} else {
reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end;
- replace = TO_STRING_INLINE(replace);
- result = ExpandReplacement(replace, subject, reusableMatchInfo, result);
+ result = ExpandReplacement(TO_STRING_INLINE(replace),
+ subject,
+ reusableMatchInfo,
+ result);
}
return result + %_SubString(subject, end, subject.length);
@@ -333,6 +354,31 @@ function ExpandReplacement(string, subject, matchInfo, result) {
} else if (peek == 39) { // $' - suffix
++position;
result += %_SubString(subject, matchInfo[CAPTURE1], subject.length);
+ } else if (peek >= 48 && peek <= 57) {
+ // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
+ var scaled_index = (peek - 48) << 1;
+ var advance = 1;
+ var number_of_captures = NUMBER_OF_CAPTURES(matchInfo);
+ if (position + 1 < string.length) {
+ var next = %_StringCharCodeAt(string, position + 1);
+ if (next >= 48 && next <= 57) {
+ var new_scaled_index = scaled_index * 10 + ((next - 48) << 1);
+ if (new_scaled_index < number_of_captures) {
+ scaled_index = new_scaled_index;
+ advance = 2;
+ }
+ }
+ }
+ if (scaled_index != 0 && scaled_index < number_of_captures) {
+ var start = matchInfo[CAPTURE(scaled_index)];
+ if (start >= 0) {
+ result +=
+ %_SubString(subject, start, matchInfo[CAPTURE(scaled_index + 1)]);
+ }
+ position += advance;
+ } else {
+ result += '$';
+ }
} else {
result += '$';
}
« no previous file with comments | « src/runtime.cc ('k') | test/mjsunit/string-replace.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698