summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/RegExpLocalReplaceOpt.h.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/RegExpLocalReplaceOpt.h.js')
-rw-r--r--js/src/builtin/RegExpLocalReplaceOpt.h.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/js/src/builtin/RegExpLocalReplaceOpt.h.js b/js/src/builtin/RegExpLocalReplaceOpt.h.js
new file mode 100644
index 0000000000..35bb8a3bd9
--- /dev/null
+++ b/js/src/builtin/RegExpLocalReplaceOpt.h.js
@@ -0,0 +1,164 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Function template for the following functions:
+// * RegExpLocalReplaceOpt
+// * RegExpLocalReplaceOptFunc
+// * RegExpLocalReplaceOptSubst
+// Define the following macro and include this file to declare function:
+// * FUNC_NAME -- function name (required)
+// e.g.
+// #define FUNC_NAME RegExpLocalReplaceOpt
+// Define the following macro (without value) to switch the code:
+// * SUBSTITUTION -- replaceValue is a string with "$"
+// * FUNCTIONAL -- replaceValue is a function
+// * SHORT_STRING -- replaceValue is a string without "$" and lengthS < 0x7fff
+// * neither of above -- replaceValue is a string without "$"
+
+// ES2023 draft rev 2c78e6f6b5bc6bfbf79dd8a12a9593e5b57afcd2
+// 22.2.5.11 RegExp.prototype [ @@replace ] ( string, replaceValue )
+// Steps 12.a-17.
+// Optimized path for @@replace with the following conditions:
+// * global flag is false
+function FUNC_NAME(
+ rx,
+ S,
+ lengthS,
+ replaceValue,
+#ifdef SUBSTITUTION
+ firstDollarIndex
+#endif
+) {
+ // 21.2.5.2.2 RegExpBuiltinExec, step 4.
+ var lastIndex = ToLength(rx.lastIndex);
+
+ // 21.2.5.2.2 RegExpBuiltinExec, step 5.
+ // Side-effects in step 4 can recompile the RegExp, so we need to read the
+ // flags again and handle the case when global was enabled even though this
+ // function is optimized for non-global RegExps.
+ var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
+
+ // 21.2.5.2.2 RegExpBuiltinExec, steps 6-7.
+ var globalOrSticky = !!(flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG));
+
+ if (globalOrSticky) {
+ // 21.2.5.2.2 RegExpBuiltinExec, step 12.a.
+ if (lastIndex > lengthS) {
+ if (globalOrSticky) {
+ rx.lastIndex = 0;
+ }
+
+ // Steps 12-16.
+ return S;
+ }
+ } else {
+ // 21.2.5.2.2 RegExpBuiltinExec, step 8.
+ lastIndex = 0;
+ }
+
+#if !defined(SHORT_STRING)
+ // Step 12.a.
+ var result = RegExpMatcher(rx, S, lastIndex);
+
+ // Step 12.b.
+ if (result === null) {
+ // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i.
+ if (globalOrSticky) {
+ rx.lastIndex = 0;
+ }
+
+ // Steps 13-17.
+ return S;
+ }
+#else
+ // Step 12.a.
+ var result = RegExpSearcher(rx, S, lastIndex);
+
+ // Step 12.b.
+ if (result === -1) {
+ // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i.
+ if (globalOrSticky) {
+ rx.lastIndex = 0;
+ }
+
+ // Steps 13-17.
+ return S;
+ }
+#endif
+
+ // Steps 12.c, 13-14.
+
+#if !defined(SHORT_STRING)
+ // Steps 15.a-b.
+ assert(result.length >= 1, "RegExpMatcher doesn't return an empty array");
+
+ // Step 15.c.
+ var matched = result[0];
+
+ // Step 15.d.
+ var matchLength = matched.length;
+
+ // Step 15.e-f.
+ var position = result.index;
+
+ // Step 15.m.iii (reordered)
+ // To set rx.lastIndex before RegExpGetFunctionalReplacement.
+ var nextSourcePosition = position + matchLength;
+#else
+ // Steps 15.a-d (skipped).
+
+ // Step 15.e-f.
+ var position = result & 0x7fff;
+
+ // Step 15.m.iii (reordered)
+ var nextSourcePosition = (result >> 15) & 0x7fff;
+#endif
+
+ // 21.2.5.2.2 RegExpBuiltinExec, step 15.
+ if (globalOrSticky) {
+ rx.lastIndex = nextSourcePosition;
+ }
+
+ var replacement;
+ // Steps 15.g-l.
+#if defined(FUNCTIONAL)
+ replacement = RegExpGetFunctionalReplacement(
+ result,
+ S,
+ position,
+ replaceValue
+ );
+#elif defined(SUBSTITUTION)
+ // Step 15.l.i
+ var namedCaptures = result.groups;
+ if (namedCaptures !== undefined) {
+ namedCaptures = ToObject(namedCaptures);
+ }
+ // Step 15.l.ii
+ replacement = RegExpGetSubstitution(
+ result,
+ S,
+ position,
+ replaceValue,
+ firstDollarIndex,
+ namedCaptures
+ );
+#else
+ replacement = replaceValue;
+#endif
+
+ // Step 15.m.ii.
+ var accumulatedResult = Substring(S, 0, position) + replacement;
+
+ // Step 16.
+ if (nextSourcePosition >= lengthS) {
+ return accumulatedResult;
+ }
+
+ // Step 17.
+ return (
+ accumulatedResult +
+ Substring(S, nextSourcePosition, lengthS - nextSourcePosition)
+ );
+}