re2js 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -2
- package/build/index.cjs.cjs +144 -43
- package/build/index.cjs.cjs.map +1 -1
- package/build/index.esm.d.ts +31 -5
- package/build/index.esm.d.ts.map +1 -1
- package/build/index.esm.js +144 -43
- package/build/index.esm.js.map +1 -1
- package/build/index.umd.js +144 -43
- package/build/index.umd.js.map +1 -1
- package/package.json +6 -6
package/build/index.esm.d.ts
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
* @author rsc@google.com (Russ Cox)
|
|
22
22
|
*/
|
|
23
23
|
export class Matcher {
|
|
24
|
+
/**
|
|
25
|
+
* V8 and WebKit have historical hard limits on the number of arguments
|
|
26
|
+
* that can be passed to a function. We cap replacer arguments to prevent
|
|
27
|
+
* Call Stack Overflow (DoS) vulnerabilities on massive ASTs.
|
|
28
|
+
*/
|
|
29
|
+
static MAX_REPLACER_ARGS: number;
|
|
24
30
|
/**
|
|
25
31
|
* Quotes '\' and '$' in {@code s}, so that the returned string could be used in
|
|
26
32
|
* {@link #appendReplacement} as a literal replacement of {@code s}.
|
|
@@ -210,31 +216,51 @@ export class Matcher {
|
|
|
210
216
|
* Returns the input with all matches replaced by {@code replacement}, interpreted as for
|
|
211
217
|
* {@code appendReplacement}.
|
|
212
218
|
*
|
|
213
|
-
* @param {string} replacement - the replacement string
|
|
219
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
214
220
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
215
221
|
* @returns {string} the input string with the matches replaced
|
|
216
222
|
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
|
|
217
223
|
*/
|
|
218
|
-
replaceAll(replacement: string, javaMode?: boolean): string;
|
|
224
|
+
replaceAll(replacement: string | Function, javaMode?: boolean): string;
|
|
219
225
|
/**
|
|
220
226
|
* Returns the input with the first match replaced by {@code replacement}, interpreted as for
|
|
221
227
|
* {@code appendReplacement}.
|
|
222
228
|
*
|
|
223
|
-
* @param {string} replacement - the replacement string
|
|
229
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
224
230
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
225
231
|
* @returns {string} the input string with the first match replaced
|
|
226
232
|
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
|
|
227
233
|
*/
|
|
228
|
-
replaceFirst(replacement: string, javaMode?: boolean): string;
|
|
234
|
+
replaceFirst(replacement: string | Function, javaMode?: boolean): string;
|
|
229
235
|
/**
|
|
230
236
|
* Helper: replaceAll/replaceFirst hybrid.
|
|
231
|
-
* @param {string} replacement - the replacement string
|
|
237
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
232
238
|
* @param {boolean} [all=true] - replace all matches
|
|
233
239
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
234
240
|
* @returns {string}
|
|
235
241
|
* @private
|
|
236
242
|
*/
|
|
237
243
|
private replace;
|
|
244
|
+
/**
|
|
245
|
+
* Evaluates a replacer function for the current match and appends the result,
|
|
246
|
+
* along with any un-matched preceding text, advancing the append position.
|
|
247
|
+
* @param {Function} replacer - the replacer function
|
|
248
|
+
* @param {boolean} hasNamedGroups - cached flag if pattern has named groups
|
|
249
|
+
* @param {string|Uint8Array|number[]} originalInput - the cached original input reference
|
|
250
|
+
* @returns {string} the evaluated string to append
|
|
251
|
+
* @private
|
|
252
|
+
*/
|
|
253
|
+
private appendReplacementFunc;
|
|
254
|
+
/**
|
|
255
|
+
* Builds the argument array for the replacer function matching the standard
|
|
256
|
+
* JS String.prototype.replace(regex, replacer) signature.
|
|
257
|
+
* @param {number} matchStart - the start index of the match
|
|
258
|
+
* @param {boolean} hasNamedGroups - cached flag if pattern has named groups
|
|
259
|
+
* @param {string|Uint8Array|number[]} originalInput - the cached original input reference
|
|
260
|
+
* @returns {Array} array of arguments
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
private buildReplacerArgs;
|
|
238
264
|
}
|
|
239
265
|
/**
|
|
240
266
|
* A compiled representation of an RE2 regular expression
|
package/build/index.esm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.d.ts","sourceRoot":"","sources":["index.esm.js"],"names":[],"mappings":"AA22CA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;IACE;;;;;;;OAOG;IACH,6BAJW,MAAM,aACN,OAAO,GACL,MAAM,CA2BlB;IACD;;;;OAIG;IACH,qBAHW,KAAK,SACL,MAAM,GAAC,MAAM,EAAE,GAAC,UAAU,EA6BpC;IAvBC;;;OAGG;IACH,cAFU,KAAK,CAEY;IAG3B,qBAAqB;IACrB,mBADW,MAAM,CACqC;IAEtD,uBAAuB;IACvB,QADW,MAAM,EAAE,CACH;IAChB,qCAAqC;IACrC,aADW,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CACC;IAClC,qBAAqB;IACrB,sBADW,MAAM,CACqC;IAUxD;;;OAGG;IACH,WAFa,KAAK,CAIjB;IAED;;;;OAIG;IACH,SAFa,OAAO,CAiBnB;IAbC,qBAAqB;IACrB,uCAAoD;IAEpD,qBAAqB;IACrB,8BAAkB;IAElB,8BAAqB;IAGrB,+BAAsB;IAEtB,+BAAmB;IAIrB;;;;OAIG;IACH,yBAHW,gBAAgB,GACd,OAAO,CASnB;IAHC,2CAAyB;IAK3B;;;;;OAKG;IACH,cAHW,MAAM,GAAC,MAAM,GACX,MAAM,CAYlB;IAED;;;;;OAKG;IACH,YAHW,MAAM,GAAC,MAAM,GACX,MAAM,CAYlB;IAED;;;;;;;;;OASG;IACH,eAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,MAAM,GACX,MAAM,GAAC,IAAI,CAgBvB;IAED;;;;OAIG;IACH,kBAFa,MAAM,CAAC,MAAM,EAAE,MAAM,GAAC,IAAI,CAAC,CAWvC;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,kBAkBC;IAED;;;;;OAKG;IACH,WAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,aAFa,OAAO,CAInB;IAED;;;;;;;OAOG;IACH,aAJW,MAAM,GAAC,IAAI,GACT,OAAO,CA4BnB;IAED;;;;;;OAMG;IACH,
|
|
1
|
+
{"version":3,"file":"index.esm.d.ts","sourceRoot":"","sources":["index.esm.js"],"names":[],"mappings":"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"}
|
package/build/index.esm.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* re2js
|
|
3
3
|
* RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching
|
|
4
4
|
*
|
|
5
|
-
* @version v2.
|
|
5
|
+
* @version v2.8.0
|
|
6
6
|
* @author Oleksii Vasyliev
|
|
7
7
|
* @homepage https://github.com/le0pard/re2js#readme
|
|
8
8
|
* @repository github:le0pard/re2js
|
|
@@ -1409,6 +1409,13 @@ class RE2JSInternalException extends RE2JSException {
|
|
|
1409
1409
|
*/
|
|
1410
1410
|
|
|
1411
1411
|
class Matcher {
|
|
1412
|
+
/**
|
|
1413
|
+
* V8 and WebKit have historical hard limits on the number of arguments
|
|
1414
|
+
* that can be passed to a function. We cap replacer arguments to prevent
|
|
1415
|
+
* Call Stack Overflow (DoS) vulnerabilities on massive ASTs.
|
|
1416
|
+
*/
|
|
1417
|
+
static MAX_REPLACER_ARGS = 65535;
|
|
1418
|
+
|
|
1412
1419
|
/**
|
|
1413
1420
|
* Quotes '\' and '$' in {@code s}, so that the returned string could be used in
|
|
1414
1421
|
* {@link #appendReplacement} as a literal replacement of {@code s}.
|
|
@@ -1705,16 +1712,14 @@ class Matcher {
|
|
|
1705
1712
|
* @private
|
|
1706
1713
|
*/
|
|
1707
1714
|
genMatch(startByte, anchor) {
|
|
1708
|
-
const
|
|
1709
|
-
const ngroup = hasLookbehinds ? 1 + this.patternGroupCount : 1;
|
|
1710
|
-
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, ngroup);
|
|
1715
|
+
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
|
|
1711
1716
|
const ok = res[0];
|
|
1712
1717
|
if (!ok) {
|
|
1713
1718
|
return false;
|
|
1714
1719
|
}
|
|
1715
1720
|
this.groups = res[1];
|
|
1716
1721
|
this.hasMatch = true;
|
|
1717
|
-
this.hasGroups =
|
|
1722
|
+
this.hasGroups = this.patternGroupCount === 0;
|
|
1718
1723
|
this.anchorFlag = anchor;
|
|
1719
1724
|
return true;
|
|
1720
1725
|
}
|
|
@@ -1967,7 +1972,7 @@ class Matcher {
|
|
|
1967
1972
|
* Returns the input with all matches replaced by {@code replacement}, interpreted as for
|
|
1968
1973
|
* {@code appendReplacement}.
|
|
1969
1974
|
*
|
|
1970
|
-
* @param {string} replacement - the replacement string
|
|
1975
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
1971
1976
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
1972
1977
|
* @returns {string} the input string with the matches replaced
|
|
1973
1978
|
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
|
|
@@ -1980,7 +1985,7 @@ class Matcher {
|
|
|
1980
1985
|
* Returns the input with the first match replaced by {@code replacement}, interpreted as for
|
|
1981
1986
|
* {@code appendReplacement}.
|
|
1982
1987
|
*
|
|
1983
|
-
* @param {string} replacement - the replacement string
|
|
1988
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
1984
1989
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
1985
1990
|
* @returns {string} the input string with the first match replaced
|
|
1986
1991
|
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
|
|
@@ -1991,7 +1996,7 @@ class Matcher {
|
|
|
1991
1996
|
|
|
1992
1997
|
/**
|
|
1993
1998
|
* Helper: replaceAll/replaceFirst hybrid.
|
|
1994
|
-
* @param {string} replacement - the replacement string
|
|
1999
|
+
* @param {string|Function} replacement - the replacement string or a replacer function
|
|
1995
2000
|
* @param {boolean} [all=true] - replace all matches
|
|
1996
2001
|
* @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
|
|
1997
2002
|
* @returns {string}
|
|
@@ -2000,8 +2005,21 @@ class Matcher {
|
|
|
2000
2005
|
replace(replacement, all = true, javaMode = false) {
|
|
2001
2006
|
let res = '';
|
|
2002
2007
|
this.reset();
|
|
2008
|
+
const isFunc = typeof replacement === 'function';
|
|
2009
|
+
|
|
2010
|
+
// Cache named groups check to avoid GC thrashing on every match
|
|
2011
|
+
const hasNamedGroups = Object.keys(this.namedGroups).length > 0;
|
|
2012
|
+
let originalInput = null;
|
|
2013
|
+
if (isFunc) {
|
|
2014
|
+
// Prevent V8 Call Stack Overflow (DoS vector) on massive capture group counts
|
|
2015
|
+
if (this.groupCount() >= Matcher.MAX_REPLACER_ARGS) {
|
|
2016
|
+
throw new RE2JSGroupException('Too many capture groups to safely invoke replacer function');
|
|
2017
|
+
}
|
|
2018
|
+
// Resolve the original input reference exactly once outside the hot loop
|
|
2019
|
+
originalInput = this.matcherInput.isUTF8Encoding() ? this.matcherInput.asBytes() : this.matcherInput.asCharSequence();
|
|
2020
|
+
}
|
|
2003
2021
|
while (this.find()) {
|
|
2004
|
-
res += this.appendReplacement(replacement, javaMode);
|
|
2022
|
+
res += isFunc ? this.appendReplacementFunc(replacement, hasNamedGroups, originalInput) : this.appendReplacement(replacement, javaMode);
|
|
2005
2023
|
if (!all) {
|
|
2006
2024
|
break;
|
|
2007
2025
|
}
|
|
@@ -2009,6 +2027,66 @@ class Matcher {
|
|
|
2009
2027
|
res += this.appendTail();
|
|
2010
2028
|
return res;
|
|
2011
2029
|
}
|
|
2030
|
+
|
|
2031
|
+
/**
|
|
2032
|
+
* Evaluates a replacer function for the current match and appends the result,
|
|
2033
|
+
* along with any un-matched preceding text, advancing the append position.
|
|
2034
|
+
* @param {Function} replacer - the replacer function
|
|
2035
|
+
* @param {boolean} hasNamedGroups - cached flag if pattern has named groups
|
|
2036
|
+
* @param {string|Uint8Array|number[]} originalInput - the cached original input reference
|
|
2037
|
+
* @returns {string} the evaluated string to append
|
|
2038
|
+
* @private
|
|
2039
|
+
*/
|
|
2040
|
+
appendReplacementFunc(replacer, hasNamedGroups, originalInput) {
|
|
2041
|
+
let res = '';
|
|
2042
|
+
const s = this.start();
|
|
2043
|
+
const e = this.end();
|
|
2044
|
+
if (this.appendPos < s) {
|
|
2045
|
+
res += this.substring(this.appendPos, s);
|
|
2046
|
+
}
|
|
2047
|
+
this.appendPos = e;
|
|
2048
|
+
const args = this.buildReplacerArgs(s, hasNamedGroups, originalInput);
|
|
2049
|
+
res += String(replacer(...args));
|
|
2050
|
+
return res;
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
/**
|
|
2054
|
+
* Builds the argument array for the replacer function matching the standard
|
|
2055
|
+
* JS String.prototype.replace(regex, replacer) signature.
|
|
2056
|
+
* @param {number} matchStart - the start index of the match
|
|
2057
|
+
* @param {boolean} hasNamedGroups - cached flag if pattern has named groups
|
|
2058
|
+
* @param {string|Uint8Array|number[]} originalInput - the cached original input reference
|
|
2059
|
+
* @returns {Array} array of arguments
|
|
2060
|
+
* @private
|
|
2061
|
+
*/
|
|
2062
|
+
buildReplacerArgs(matchStart, hasNamedGroups, originalInput) {
|
|
2063
|
+
const args = [this.group(0)]; // match
|
|
2064
|
+
|
|
2065
|
+
const numGroups = this.groupCount();
|
|
2066
|
+
// Fast-path capture group extraction
|
|
2067
|
+
for (let i = 1; i <= numGroups; i++) {
|
|
2068
|
+
const start = this.start(i);
|
|
2069
|
+
if (start < 0) {
|
|
2070
|
+
args.push(void 0);
|
|
2071
|
+
} else {
|
|
2072
|
+
args.push(this.substring(start, this.end(i)));
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
args.push(matchStart); // offset
|
|
2076
|
+
args.push(originalInput); // original string (cached)
|
|
2077
|
+
|
|
2078
|
+
// Append named groups object if pattern contains them
|
|
2079
|
+
if (hasNamedGroups) {
|
|
2080
|
+
const parsedGroups = this.getNamedGroups();
|
|
2081
|
+
for (const key in parsedGroups) {
|
|
2082
|
+
if (parsedGroups[key] === null) {
|
|
2083
|
+
parsedGroups[key] = void 0;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
args.push(parsedGroups);
|
|
2087
|
+
}
|
|
2088
|
+
return args;
|
|
2089
|
+
}
|
|
2012
2090
|
}
|
|
2013
2091
|
|
|
2014
2092
|
/**
|
|
@@ -2335,30 +2413,35 @@ class Machine {
|
|
|
2335
2413
|
}
|
|
2336
2414
|
this.matched = false;
|
|
2337
2415
|
this.matchcap.fill(-1);
|
|
2416
|
+
|
|
2417
|
+
// Lookbehinds must scan from the beginning of the string to build their state table,
|
|
2418
|
+
// even if the main pattern search is requested to start mid-string.
|
|
2419
|
+
let currentPos = this.prog.numLb > 0 ? 0 : pos;
|
|
2420
|
+
let matchStartPos = pos;
|
|
2338
2421
|
let runq = this.q0;
|
|
2339
2422
|
let nextq = this.q1;
|
|
2340
|
-
let r = input.step(
|
|
2423
|
+
let r = input.step(currentPos);
|
|
2341
2424
|
let rune = r >> 3;
|
|
2342
2425
|
let width = r & 7;
|
|
2343
2426
|
let rune1 = -1;
|
|
2344
2427
|
let width1 = 0;
|
|
2345
2428
|
if (r !== MachineInputBase.EOF()) {
|
|
2346
|
-
r = input.step(
|
|
2429
|
+
r = input.step(currentPos + width);
|
|
2347
2430
|
rune1 = r >> 3;
|
|
2348
2431
|
width1 = r & 7;
|
|
2349
2432
|
}
|
|
2350
2433
|
let flag;
|
|
2351
|
-
if (
|
|
2434
|
+
if (currentPos === 0) {
|
|
2352
2435
|
flag = Utils.emptyOpContext(-1, rune);
|
|
2353
2436
|
} else {
|
|
2354
|
-
flag = input.context(
|
|
2437
|
+
flag = input.context(currentPos);
|
|
2355
2438
|
}
|
|
2356
2439
|
while (true) {
|
|
2357
2440
|
if (runq.isEmpty()) {
|
|
2358
|
-
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 &&
|
|
2441
|
+
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) {
|
|
2359
2442
|
break;
|
|
2360
2443
|
}
|
|
2361
|
-
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) &&
|
|
2444
|
+
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) {
|
|
2362
2445
|
break;
|
|
2363
2446
|
}
|
|
2364
2447
|
if (this.matched) {
|
|
@@ -2368,43 +2451,50 @@ class Machine {
|
|
|
2368
2451
|
// Fast-forwarding the string pointer will skip over the positions where
|
|
2369
2452
|
// the parallel lookbehind automata need to be spawned.
|
|
2370
2453
|
if (this.prog.numLb === 0 && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
|
|
2371
|
-
const advance = input.index(this.re2,
|
|
2454
|
+
const advance = input.index(this.re2, currentPos);
|
|
2372
2455
|
if (advance < 0) {
|
|
2373
2456
|
break;
|
|
2374
2457
|
}
|
|
2375
|
-
|
|
2376
|
-
r = input.step(
|
|
2458
|
+
currentPos += advance;
|
|
2459
|
+
r = input.step(currentPos);
|
|
2377
2460
|
rune = r >> 3;
|
|
2378
2461
|
width = r & 7;
|
|
2379
|
-
r = input.step(
|
|
2462
|
+
r = input.step(currentPos + width);
|
|
2380
2463
|
rune1 = r >> 3;
|
|
2381
2464
|
width1 = r & 7;
|
|
2382
2465
|
}
|
|
2383
2466
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
// Spawn Lookbehind threads BEFORE the main pattern
|
|
2467
|
+
|
|
2468
|
+
// Optimize lookbehind spawning. Because lookbehinds are prefixed with `.*` by the compiler,
|
|
2469
|
+
// they only need to be spawned exactly once at the beginning of the string (currentPos === 0).
|
|
2470
|
+
if (currentPos === 0 && this.prog.numLb > 0) {
|
|
2389
2471
|
for (let i = 0; i < this.prog.lbStarts.length; i++) {
|
|
2390
|
-
this.add(runq, this.prog.lbStarts[i],
|
|
2472
|
+
this.add(runq, this.prog.lbStarts[i], currentPos, this.matchcap, flag, null);
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
|
|
2476
|
+
// ONLY spawn the main pattern if we have reached the requested search start boundary
|
|
2477
|
+
if (currentPos >= matchStartPos) {
|
|
2478
|
+
if (this.ncap > 0) {
|
|
2479
|
+
this.matchcap[0] = currentPos;
|
|
2480
|
+
}
|
|
2481
|
+
this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
|
|
2391
2482
|
}
|
|
2392
|
-
this.add(runq, this.prog.start, pos, this.matchcap, flag, null);
|
|
2393
2483
|
}
|
|
2394
|
-
const nextPos =
|
|
2484
|
+
const nextPos = currentPos + width;
|
|
2395
2485
|
flag = input.context(nextPos);
|
|
2396
|
-
this.step(runq, nextq,
|
|
2486
|
+
this.step(runq, nextq, currentPos, nextPos, rune, flag, anchor, currentPos === input.endPos());
|
|
2397
2487
|
if (width === 0) {
|
|
2398
2488
|
break;
|
|
2399
2489
|
}
|
|
2400
2490
|
if (this.ncap === 0 && this.matched) {
|
|
2401
2491
|
break;
|
|
2402
2492
|
}
|
|
2403
|
-
|
|
2493
|
+
currentPos += width;
|
|
2404
2494
|
rune = rune1;
|
|
2405
2495
|
width = width1;
|
|
2406
2496
|
if (rune !== -1) {
|
|
2407
|
-
r = input.step(
|
|
2497
|
+
r = input.step(currentPos + width);
|
|
2408
2498
|
rune1 = r >> 3;
|
|
2409
2499
|
width1 = r & 7;
|
|
2410
2500
|
}
|
|
@@ -2421,35 +2511,46 @@ class Machine {
|
|
|
2421
2511
|
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) {
|
|
2422
2512
|
return [];
|
|
2423
2513
|
}
|
|
2514
|
+
|
|
2515
|
+
// Lookbehinds must scan from the beginning of the string to build their state table,
|
|
2516
|
+
// even if the main pattern search is requested to start mid-string.
|
|
2517
|
+
let currentPos = this.prog.numLb > 0 ? 0 : pos;
|
|
2518
|
+
let matchStartPos = pos;
|
|
2424
2519
|
let runq = this.q0;
|
|
2425
2520
|
let nextq = this.q1;
|
|
2426
|
-
let r = input.step(
|
|
2521
|
+
let r = input.step(currentPos);
|
|
2427
2522
|
let rune = r >> 3;
|
|
2428
2523
|
let width = r & 7;
|
|
2429
2524
|
let rune1 = -1;
|
|
2430
2525
|
let width1 = 0;
|
|
2431
2526
|
if (r !== MachineInputBase.EOF()) {
|
|
2432
|
-
r = input.step(
|
|
2527
|
+
r = input.step(currentPos + width);
|
|
2433
2528
|
rune1 = r >> 3;
|
|
2434
2529
|
width1 = r & 7;
|
|
2435
2530
|
}
|
|
2436
|
-
let flag =
|
|
2531
|
+
let flag = currentPos === 0 ? Utils.emptyOpContext(-1, rune) : input.context(currentPos);
|
|
2437
2532
|
const matches = new Set();
|
|
2438
2533
|
while (true) {
|
|
2439
2534
|
if (runq.isEmpty()) {
|
|
2440
|
-
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 &&
|
|
2441
|
-
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) &&
|
|
2535
|
+
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
|
|
2536
|
+
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) {
|
|
2442
2537
|
break;
|
|
2443
2538
|
}
|
|
2444
2539
|
}
|
|
2445
|
-
|
|
2446
|
-
|
|
2540
|
+
|
|
2541
|
+
// Optimize lookbehind spawning to exactly once at BOF
|
|
2542
|
+
if (currentPos === 0 && this.prog.numLb > 0) {
|
|
2447
2543
|
for (let i = 0; i < this.prog.lbStarts.length; i++) {
|
|
2448
|
-
this.add(runq, this.prog.lbStarts[i],
|
|
2544
|
+
this.add(runq, this.prog.lbStarts[i], currentPos, this.matchcap, flag, null);
|
|
2449
2545
|
}
|
|
2450
|
-
this.add(runq, this.prog.start, pos, this.matchcap, flag, null);
|
|
2451
2546
|
}
|
|
2452
|
-
|
|
2547
|
+
if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
|
|
2548
|
+
// ONLY spawn the main pattern if we have reached the requested search start boundary
|
|
2549
|
+
if (currentPos >= matchStartPos) {
|
|
2550
|
+
this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
const nextPos = currentPos + width;
|
|
2453
2554
|
flag = input.context(nextPos);
|
|
2454
2555
|
for (let j = 0; j < runq.size; j++) {
|
|
2455
2556
|
let t = runq.denseThreads[j];
|
|
@@ -2458,7 +2559,7 @@ class Machine {
|
|
|
2458
2559
|
let add = false;
|
|
2459
2560
|
switch (i.op) {
|
|
2460
2561
|
case Inst.MATCH:
|
|
2461
|
-
if (anchor === RE2Flags.ANCHOR_BOTH &&
|
|
2562
|
+
if (anchor === RE2Flags.ANCHOR_BOTH && currentPos !== input.endPos()) break;
|
|
2462
2563
|
matches.add(i.arg); // Record the matched Set ID
|
|
2463
2564
|
break;
|
|
2464
2565
|
case Inst.RUNE:
|
|
@@ -2486,11 +2587,11 @@ class Machine {
|
|
|
2486
2587
|
}
|
|
2487
2588
|
runq.clear();
|
|
2488
2589
|
if (width === 0) break;
|
|
2489
|
-
|
|
2590
|
+
currentPos += width;
|
|
2490
2591
|
rune = rune1;
|
|
2491
2592
|
width = width1;
|
|
2492
2593
|
if (rune !== -1) {
|
|
2493
|
-
r = input.step(
|
|
2594
|
+
r = input.step(currentPos + width);
|
|
2494
2595
|
rune1 = r >> 3;
|
|
2495
2596
|
width1 = r & 7;
|
|
2496
2597
|
}
|