diff options
Diffstat (limited to '')
-rw-r--r-- | js/src/builtin/RegExpGlobalReplaceOpt.h.js | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/js/src/builtin/RegExpGlobalReplaceOpt.h.js b/js/src/builtin/RegExpGlobalReplaceOpt.h.js new file mode 100644 index 0000000000..9a88ff9ae6 --- /dev/null +++ b/js/src/builtin/RegExpGlobalReplaceOpt.h.js @@ -0,0 +1,174 @@ +/* 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: +// * RegExpGlobalReplaceOpt +// * RegExpGlobalReplaceOptFunc +// * RegExpGlobalReplaceOptSubst +// * RegExpGlobalReplaceOptElemBase +// Define the following macro and include this file to declare function: +// * FUNC_NAME -- function name (required) +// e.g. +// #define FUNC_NAME RegExpGlobalReplaceOpt +// Define the following macro (without value) to switch the code: +// * SUBSTITUTION -- replaceValue is a string with "$" +// * FUNCTIONAL -- replaceValue is a function +// * ELEMBASE -- replaceValue is a function that returns an element +// of an object +// * none of above -- replaceValue is a string without "$" + +// ES2023 draft rev 2c78e6f6b5bc6bfbf79dd8a12a9593e5b57afcd2 +// 22.2.5.11 RegExp.prototype [ @@replace ] ( string, replaceValue ) +// steps 9-17. +// Optimized path for @@replace with the following conditions: +// * global flag is true +function FUNC_NAME( + rx, + S, + lengthS, + replaceValue, + flags, +#ifdef SUBSTITUTION + firstDollarIndex, +#endif +#ifdef ELEMBASE + elemBase +#endif +) { + // Step 9.a. + var fullUnicode = !!(flags & REGEXP_UNICODE_FLAG); + + // Step 9.b. + var lastIndex = 0; + rx.lastIndex = 0; + +#if defined(FUNCTIONAL) || defined(ELEMBASE) + // Save the original source and flags, so we can check if the replacer + // function recompiled the regexp. + var originalSource = UnsafeGetStringFromReservedSlot(rx, REGEXP_SOURCE_SLOT); + var originalFlags = flags; +#endif + + // Step 13 (reordered). + var accumulatedResult = ""; + + // Step 14 (reordered). + var nextSourcePosition = 0; + + // Step 12. + while (true) { + // Step 12.a. + var result = RegExpMatcher(rx, S, lastIndex); + + // Step 12.b. + if (result === null) { + break; + } + + // Steps 15.a-b (skipped). + 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 | 0; + + // Steps 15.e-f. + var position = result.index | 0; + lastIndex = position + matchLength; + + // Steps 15.g-l. + var replacement; +#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 + ); +#elif defined(ELEMBASE) + if (IsObject(elemBase)) { + var prop = GetStringDataProperty(elemBase, matched); + if (prop !== undefined) { + assert( + typeof prop === "string", + "GetStringDataProperty should return either string or undefined" + ); + replacement = prop; + } else { + elemBase = undefined; + } + } + + if (!IsObject(elemBase)) { + replacement = RegExpGetFunctionalReplacement( + result, + S, + position, + replaceValue + ); + } +#else + replacement = replaceValue; +#endif + + // Step 15.m.ii. + accumulatedResult += + Substring(S, nextSourcePosition, position - nextSourcePosition) + + replacement; + + // Step 15.m.iii. + nextSourcePosition = lastIndex; + + // Step 12.c.iii.2. + if (matchLength === 0) { + lastIndex = fullUnicode + ? AdvanceStringIndex(S, lastIndex) + : lastIndex + 1; + if (lastIndex > lengthS) { + break; + } + lastIndex |= 0; + } + +#if defined(FUNCTIONAL) || defined(ELEMBASE) + // Ensure the current source and flags match the original regexp, the + // replaceValue function may have called RegExp#compile. + if ( + UnsafeGetStringFromReservedSlot(rx, REGEXP_SOURCE_SLOT) !== + originalSource || + UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT) !== originalFlags + ) { + rx = RegExpConstructRaw(originalSource, originalFlags); + } +#endif + } + + // Step 16. + if (nextSourcePosition >= lengthS) { + return accumulatedResult; + } + + // Step 17. + return ( + accumulatedResult + + Substring(S, nextSourcePosition, lengthS - nextSourcePosition) + ); +} |