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

Unified Diff: src/objects.cc

Issue 2398423002: [regexp] Port RegExp.prototype[@@replace] (Closed)
Patch Set: Smi::kZero Created 4 years, 2 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/objects.h ('k') | src/runtime/runtime.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index b7fa0b2c5e577cdb6988edb8934eb98f6c49f4b8..551e4a35dbb17be555bed0591d8bccb384f9d066 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -11652,6 +11652,101 @@ int String::IndexOf(Isolate* isolate, Handle<String> receiver,
start_index);
}
+MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
+ Handle<String> replacement) {
+ Factory* factory = isolate->factory();
+
+ const int replacement_length = replacement->length();
+ const int captures_length = match->CaptureCount();
+
+ replacement = String::Flatten(replacement);
+
+ Handle<String> dollar_string =
+ factory->LookupSingleCharacterStringFromCode('$');
+ int next = String::IndexOf(isolate, replacement, dollar_string, 0);
+ if (next < 0) {
+ return replacement;
+ }
+
+ IncrementalStringBuilder builder(isolate);
+
+ if (next > 0) {
+ builder.AppendString(factory->NewSubString(replacement, 0, next));
+ }
+
+ while (true) {
+ int pos = next + 1;
+ if (pos < replacement_length) {
+ const uint16_t peek = replacement->Get(pos);
+ if (peek == '$') { // $$
+ pos++;
+ builder.AppendCharacter('$');
+ } else if (peek == '&') { // $& - match
+ pos++;
+ builder.AppendString(match->GetMatch());
+ } else if (peek == '`') { // $` - prefix
+ pos++;
+ builder.AppendString(match->GetPrefix());
+ } else if (peek == '\'') { // $' - suffix
+ pos++;
+ builder.AppendString(match->GetSuffix());
+ } else if (peek >= '0' && peek <= '9') {
+ // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
+ int scaled_index = (peek - '0');
+ int advance = 1;
+
+ if (pos + 1 < replacement_length) {
+ const uint16_t next_peek = replacement->Get(pos + 1);
+ if (next_peek >= '0' && next_peek <= '9') {
+ const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
+ if (new_scaled_index < captures_length) {
+ scaled_index = new_scaled_index;
+ advance = 2;
+ }
+ }
+ }
+
+ if (scaled_index != 0 && scaled_index < captures_length) {
+ bool capture_exists;
+ Handle<String> capture;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, capture,
+ match->GetCapture(scaled_index, &capture_exists), String);
+ if (capture_exists) builder.AppendString(capture);
+ pos += advance;
+ } else {
+ builder.AppendCharacter('$');
+ }
+ } else {
+ builder.AppendCharacter('$');
+ }
+ } else {
+ builder.AppendCharacter('$');
+ }
+
+ // Go the the next $ in the replacement.
+ next = String::IndexOf(isolate, replacement, dollar_string, pos);
+
+ // Return if there are no more $ characters in the replacement. If we
+ // haven't reached the end, we need to append the suffix.
+ if (next < 0) {
+ if (pos < replacement_length) {
+ builder.AppendString(
+ factory->NewSubString(replacement, pos, replacement_length));
+ }
+ return builder.Finish();
+ }
+
+ // Append substring between the previous and the next $ character.
+ if (next > pos) {
+ builder.AppendString(factory->NewSubString(replacement, pos, next));
+ }
+ }
+
+ UNREACHABLE();
+ return MaybeHandle<String>();
+}
+
namespace { // for String.Prototype.lastIndexOf
template <typename schar, typename pchar>
« no previous file with comments | « src/objects.h ('k') | src/runtime/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698