113 lines
3.4 KiB
JavaScript
113 lines
3.4 KiB
JavaScript
// 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
|
|
// * 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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Steps 11.c, 12-13, 14.a-b (skipped).
|
|
|
|
#if defined(FUNCTIONAL) || defined(SUBSTITUTION)
|
|
// Steps 14.a-b.
|
|
var nCaptures = std_Math_max(result.length - 1, 0);
|
|
#endif
|
|
|
|
// Step 14.c.
|
|
var matched = result[0];
|
|
|
|
// Step 14.d.
|
|
var matchLength = matched.length;
|
|
|
|
// Step 14.e-f.
|
|
var position = result.index;
|
|
|
|
// Step 14.l.iii (reordered)
|
|
// To set rx.lastIndex before RegExpGetComplexReplacement.
|
|
var nextSourcePosition = position + matchLength;
|
|
|
|
// 21.2.5.2.2 RegExpBuiltinExec, step 15.
|
|
if (globalOrSticky)
|
|
rx.lastIndex = nextSourcePosition;
|
|
|
|
var replacement;
|
|
// Steps g-j.
|
|
#if defined(FUNCTIONAL)
|
|
replacement = RegExpGetComplexReplacement(result, matched, S, position,
|
|
|
|
nCaptures, replaceValue,
|
|
true, -1);
|
|
#elif defined(SUBSTITUTION)
|
|
replacement = RegExpGetComplexReplacement(result, matched, S, position,
|
|
|
|
nCaptures, replaceValue,
|
|
false, firstDollarIndex);
|
|
#else
|
|
replacement = replaceValue;
|
|
#endif
|
|
|
|
// Step 14.l.ii.
|
|
var accumulatedResult = Substring(S, 0, position) + replacement;
|
|
|
|
// Step 15.
|
|
if (nextSourcePosition >= lengthS)
|
|
return accumulatedResult;
|
|
|
|
// Step 16.
|
|
return accumulatedResult + Substring(S, nextSourcePosition, lengthS - nextSourcePosition);
|
|
}
|