tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }