1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // Function template for the following functions:
6 // * RegExpLocalReplaceOptSimple
7 // * RegExpLocalReplaceOptFunc
8 // * RegExpLocalReplaceOptSubst
9 // Define the following macro and include this file to declare function:
10 // * FUNC_NAME -- function name (required)
12 // #define FUNC_NAME RegExpLocalReplaceOpt
13 // Define one of the following macros (without value) to switch the code:
14 // * SUBSTITUTION -- replaceValue is a string with "$"
15 // * FUNCTIONAL -- replaceValue is a function
16 // * SIMPLE -- replaceValue is a string without "$"
18 // ES2023 draft rev 2c78e6f6b5bc6bfbf79dd8a12a9593e5b57afcd2
19 // 22.2.5.11 RegExp.prototype [ @@replace ] ( string, replaceValue )
21 // Optimized path for @@replace with the following conditions:
22 // * global flag is false
32 // 21.2.5.2.2 RegExpBuiltinExec, step 4.
33 var lastIndex = ToLength(rx.lastIndex);
35 // 21.2.5.2.2 RegExpBuiltinExec, step 5.
36 // Side-effects in step 4 can recompile the RegExp, so we need to read the
37 // flags again and handle the case when global was enabled even though this
38 // function is optimized for non-global RegExps.
39 var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
41 // 21.2.5.2.2 RegExpBuiltinExec, steps 6-7.
42 var globalOrSticky = !!(flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG));
45 // 21.2.5.2.2 RegExpBuiltinExec, step 12.a.
46 if (lastIndex > lengthS) {
55 // 21.2.5.2.2 RegExpBuiltinExec, step 8.
61 var result = RegExpMatcher(rx, S, lastIndex);
64 if (result === null) {
65 // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i.
75 var position = RegExpSearcher(rx, S, lastIndex);
78 if (position === -1) {
79 // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i.
93 assert(result.length >= 1, "RegExpMatcher doesn't return an empty array");
96 var matched = result[0];
99 var matchLength = matched.length;
102 var position = result.index;
104 // Step 15.m.iii (reordered)
105 // To set rx.lastIndex before RegExpGetFunctionalReplacement.
106 var nextSourcePosition = position + matchLength;
108 // Steps 15.a-f (skipped).
110 // Step 15.m.iii (reordered)
111 var nextSourcePosition = RegExpSearcherLastLimit(S);
114 // 21.2.5.2.2 RegExpBuiltinExec, step 15.
115 if (globalOrSticky) {
116 rx.lastIndex = nextSourcePosition;
121 #if defined(FUNCTIONAL)
122 replacement = RegExpGetFunctionalReplacement(
128 #elif defined(SUBSTITUTION)
130 var namedCaptures = result.groups;
131 if (namedCaptures !== undefined) {
132 namedCaptures = ToObject(namedCaptures);
135 replacement = RegExpGetSubstitution(
144 replacement = replaceValue;
148 var accumulatedResult = Substring(S, 0, position) + replacement;
151 if (nextSourcePosition >= lengthS) {
152 return accumulatedResult;
158 Substring(S, nextSourcePosition, lengthS - nextSourcePosition)