RegExpLocalReplaceOpt.h.js (4030B)
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/. */ 4 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) 11 // e.g. 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 "$" 17 18 // ES2023 draft rev 2c78e6f6b5bc6bfbf79dd8a12a9593e5b57afcd2 19 // 22.2.5.11 RegExp.prototype [ @@replace ] ( string, replaceValue ) 20 // Steps 12.a-17. 21 // Optimized path for @@replace with the following conditions: 22 // * global flag is false 23 function FUNC_NAME( 24 rx, 25 S, 26 lengthS, 27 replaceValue, 28 #ifdef SUBSTITUTION 29 firstDollarIndex 30 #endif 31 ) { 32 // 21.2.5.2.2 RegExpBuiltinExec, step 4. 33 var lastIndex = ToLength(rx.lastIndex); 34 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); 40 41 // 21.2.5.2.2 RegExpBuiltinExec, steps 6-7. 42 var globalOrSticky = !!(flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG)); 43 44 if (globalOrSticky) { 45 // 21.2.5.2.2 RegExpBuiltinExec, step 12.a. 46 if (lastIndex > lengthS) { 47 if (globalOrSticky) { 48 rx.lastIndex = 0; 49 } 50 51 // Steps 12-16. 52 return S; 53 } 54 } else { 55 // 21.2.5.2.2 RegExpBuiltinExec, step 8. 56 lastIndex = 0; 57 } 58 59 #if !defined(SIMPLE) 60 // Step 12.a. 61 var result = RegExpMatcher(rx, S, lastIndex); 62 63 // Step 12.b. 64 if (result === null) { 65 // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i. 66 if (globalOrSticky) { 67 rx.lastIndex = 0; 68 } 69 70 // Steps 13-17. 71 return S; 72 } 73 #else 74 // Step 12.a. 75 var position = RegExpSearcher(rx, S, lastIndex); 76 77 // Step 12.b. 78 if (position === -1) { 79 // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i. 80 if (globalOrSticky) { 81 rx.lastIndex = 0; 82 } 83 84 // Steps 13-17. 85 return S; 86 } 87 #endif 88 89 // Steps 12.c, 13-14. 90 91 #if !defined(SIMPLE) 92 // Steps 15.a-b. 93 assert(result.length >= 1, "RegExpMatcher doesn't return an empty array"); 94 95 // Step 15.c. 96 var matched = result[0]; 97 98 // Step 15.d. 99 var matchLength = matched.length; 100 101 // Step 15.e-f. 102 var position = result.index; 103 104 // Step 15.m.iii (reordered) 105 // To set rx.lastIndex before RegExpGetFunctionalReplacement. 106 var nextSourcePosition = position + matchLength; 107 #else 108 // Steps 15.a-f (skipped). 109 110 // Step 15.m.iii (reordered) 111 var nextSourcePosition = RegExpSearcherLastLimit(S); 112 #endif 113 114 // 21.2.5.2.2 RegExpBuiltinExec, step 15. 115 if (globalOrSticky) { 116 rx.lastIndex = nextSourcePosition; 117 } 118 119 var replacement; 120 // Steps 15.g-l. 121 #if defined(FUNCTIONAL) 122 replacement = RegExpGetFunctionalReplacement( 123 result, 124 S, 125 position, 126 replaceValue 127 ); 128 #elif defined(SUBSTITUTION) 129 // Step 15.l.i 130 var namedCaptures = result.groups; 131 if (namedCaptures !== undefined) { 132 namedCaptures = ToObject(namedCaptures); 133 } 134 // Step 15.l.ii 135 replacement = RegExpGetSubstitution( 136 result, 137 S, 138 position, 139 replaceValue, 140 firstDollarIndex, 141 namedCaptures 142 ); 143 #else 144 replacement = replaceValue; 145 #endif 146 147 // Step 15.m.ii. 148 var accumulatedResult = Substring(S, 0, position) + replacement; 149 150 // Step 16. 151 if (nextSourcePosition >= lengthS) { 152 return accumulatedResult; 153 } 154 155 // Step 17. 156 return ( 157 accumulatedResult + 158 Substring(S, nextSourcePosition, lengthS - nextSourcePosition) 159 ); 160 }