1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// 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 (skipped).
#if defined(FUNCTIONAL)
// 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)
// 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);
}
|