Index: src/js/string.js |
diff --git a/src/js/string.js b/src/js/string.js |
index 5d87ffce9ec9bd937b8eaad62f99f7029d34dfc4..3a9254c7130858b24ea3177a3eb5d818149fa513 100644 |
--- a/src/js/string.js |
+++ b/src/js/string.js |
@@ -10,7 +10,6 @@ |
// Imports |
var ArrayJoin; |
-var GetSubstitution; |
var GlobalRegExp = global.RegExp; |
var GlobalString = global.String; |
var MaxSimple; |
@@ -22,7 +21,6 @@ var splitSymbol = utils.ImportNow("split_symbol"); |
utils.Import(function(from) { |
ArrayJoin = from.ArrayJoin; |
- GetSubstitution = from.GetSubstitution; |
MaxSimple = from.MaxSimple; |
MinSimple = from.MinSimple; |
}); |
@@ -60,6 +58,90 @@ function StringMatchJS(pattern) { |
return regexp[matchSymbol](subject); |
} |
+// ES#sec-getsubstitution |
+// GetSubstitution(matched, str, position, captures, replacement) |
+// Expand the $-expressions in the string and return a new string with |
+// the result. |
+function GetSubstitution(matched, string, position, captures, replacement) { |
+ var matchLength = matched.length; |
+ var stringLength = string.length; |
+ var capturesLength = captures.length; |
+ var tailPos = position + matchLength; |
+ var result = ""; |
+ var pos, expansion, peek, next, scaledIndex, advance, newScaledIndex; |
+ |
+ var next = %StringIndexOf(replacement, '$', 0); |
+ if (next < 0) { |
+ result += replacement; |
+ return result; |
+ } |
+ |
+ if (next > 0) result += %_SubString(replacement, 0, next); |
+ |
+ while (true) { |
+ expansion = '$'; |
+ pos = next + 1; |
+ if (pos < replacement.length) { |
+ peek = %_StringCharCodeAt(replacement, pos); |
+ if (peek == 36) { // $$ |
+ ++pos; |
+ result += '$'; |
+ } else if (peek == 38) { // $& - match |
+ ++pos; |
+ result += matched; |
+ } else if (peek == 96) { // $` - prefix |
+ ++pos; |
+ result += %_SubString(string, 0, position); |
+ } else if (peek == 39) { // $' - suffix |
+ ++pos; |
+ result += %_SubString(string, tailPos, stringLength); |
+ } else if (peek >= 48 && peek <= 57) { |
+ // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99 |
+ scaledIndex = (peek - 48); |
+ advance = 1; |
+ if (pos + 1 < replacement.length) { |
+ next = %_StringCharCodeAt(replacement, pos + 1); |
+ if (next >= 48 && next <= 57) { |
+ newScaledIndex = scaledIndex * 10 + ((next - 48)); |
+ if (newScaledIndex < capturesLength) { |
+ scaledIndex = newScaledIndex; |
+ advance = 2; |
+ } |
+ } |
+ } |
+ if (scaledIndex != 0 && scaledIndex < capturesLength) { |
+ var capture = captures.at(scaledIndex); |
+ if (!IS_UNDEFINED(capture)) result += capture; |
+ pos += advance; |
+ } else { |
+ result += '$'; |
+ } |
+ } else { |
+ result += '$'; |
+ } |
+ } else { |
+ result += '$'; |
+ } |
+ |
+ // Go the the next $ in the replacement. |
+ next = %StringIndexOf(replacement, '$', 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) { |
+ result += %_SubString(replacement, pos, replacement.length); |
+ } |
+ return result; |
+ } |
+ |
+ // Append substring between the previous and the next $ character. |
+ if (next > pos) { |
+ result += %_SubString(replacement, pos, next); |
+ } |
+ } |
+ return result; |
+} |
// ES6, section 21.1.3.14 |
function StringReplace(search, replace) { |