diff options
Diffstat (limited to 'js/src/builtin/RegExpLocalReplaceOpt.h.js')
-rw-r--r-- | js/src/builtin/RegExpLocalReplaceOpt.h.js | 141 |
1 files changed, 141 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..1fb30cb032 --- /dev/null +++ b/js/src/builtin/RegExpLocalReplaceOpt.h.js @@ -0,0 +1,141 @@ +/* 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 "$" + +// ES 2017 draft 6390c2f1b34b309895d31d8c0512eac8660a0210 21.2.5.8 +// steps 11.a-16. +// 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 11.a. + var result = RegExpMatcher(rx, S, lastIndex); + + // Step 11.b. + if (result === null) { + // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i. + if (globalOrSticky) + rx.lastIndex = 0; + + // Steps 12-16. + return S; + } +#else + // Step 11.a. + var result = RegExpSearcher(rx, S, lastIndex); + + // Step 11.b. + if (result === -1) { + // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i. + if (globalOrSticky) + rx.lastIndex = 0; + + // Steps 12-16. + return S; + } +#endif + + // Steps 11.c, 12-13. + +#if !defined(SHORT_STRING) + // Steps 14.a-b. + assert(result.length >= 1, "RegExpMatcher doesn't return an empty array"); + + // Step 14.c. + var matched = result[0]; + + // Step 14.d. + var matchLength = matched.length; + + // Step 14.e-f. + var position = result.index; + + // Step 14.m.iii (reordered) + // To set rx.lastIndex before RegExpGetFunctionalReplacement. + var nextSourcePosition = position + matchLength; +#else + // Steps 14.a-d (skipped). + + // Step 14.e-f. + var position = result & 0x7fff; + + // Step 14.l.iii (reordered) + var nextSourcePosition = (result >> 15) & 0x7fff; +#endif + + // 21.2.5.2.2 RegExpBuiltinExec, step 15. + if (globalOrSticky) + rx.lastIndex = nextSourcePosition; + + var replacement; + // Steps g-l. +#if defined(FUNCTIONAL) + replacement = RegExpGetFunctionalReplacement(result, S, position, replaceValue); +#elif defined(SUBSTITUTION) + // Step l.i + var namedCaptures = result.groups; + if (namedCaptures !== undefined) { + namedCaptures = ToObject(namedCaptures); + } + // Step l.ii + replacement = RegExpGetSubstitution(result, S, position, replaceValue, firstDollarIndex, + namedCaptures); +#else + replacement = replaceValue; +#endif + + // Step 14.m.ii. + var accumulatedResult = Substring(S, 0, position) + replacement; + + // Step 15. + if (nextSourcePosition >= lengthS) + return accumulatedResult; + + // Step 16. + return accumulatedResult + Substring(S, nextSourcePosition, lengthS - nextSourcePosition); +} |