re2js 2.8.5 → 2.8.7
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 +94 -104
- package/build/index.cjs +940 -732
- package/build/index.d.cts +284 -226
- package/build/index.d.ts +284 -226
- package/build/index.js +940 -732
- package/build/index.umd.js +940 -732
- package/package.json +30 -24
package/build/index.umd.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
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.8.
|
|
5
|
+
* @version v2.8.7
|
|
6
6
|
* @author Oleksii Vasyliev
|
|
7
7
|
* @homepage https://github.com/le0pard/re2js#readme
|
|
8
|
-
* @repository
|
|
8
|
+
* @repository [object Object]
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
(function(global, factory) {
|
|
@@ -503,6 +503,10 @@
|
|
|
503
503
|
*/
|
|
504
504
|
var Unicode = class Unicode {
|
|
505
505
|
static MAX_RUNE = 1114111;
|
|
506
|
+
static RUNE_ERROR = 65533;
|
|
507
|
+
static isUnsearchable(r) {
|
|
508
|
+
return r === Unicode.RUNE_ERROR || r >= Unicode.MIN_HIGH_SURROGATE && r <= Unicode.MAX_LOW_SURROGATE;
|
|
509
|
+
}
|
|
506
510
|
static MAX_ASCII = 127;
|
|
507
511
|
static MAX_LATIN1 = 255;
|
|
508
512
|
static MAX_BMP = 65535;
|
|
@@ -605,7 +609,7 @@
|
|
|
605
609
|
return [];
|
|
606
610
|
}
|
|
607
611
|
static isByteArray(input) {
|
|
608
|
-
return Array.isArray(input) || input
|
|
612
|
+
return Array.isArray(input) || Object.prototype.toString.call(input) === "[object Uint8Array]";
|
|
609
613
|
}
|
|
610
614
|
static isalnum(c) {
|
|
611
615
|
return Codepoint.CODES.get("0") <= c && c <= Codepoint.CODES.get("9") || Codepoint.CODES.get("a") <= c && c <= Codepoint.CODES.get("z") || Codepoint.CODES.get("A") <= c && c <= Codepoint.CODES.get("Z");
|
|
@@ -664,7 +668,7 @@
|
|
|
664
668
|
runes.push(cp);
|
|
665
669
|
i += cp > Unicode.MAX_BMP ? 2 : 1;
|
|
666
670
|
}
|
|
667
|
-
return runes;
|
|
671
|
+
return new Int32Array(runes);
|
|
668
672
|
}
|
|
669
673
|
static runeToString(r) {
|
|
670
674
|
return String.fromCodePoint(r);
|
|
@@ -711,7 +715,7 @@
|
|
|
711
715
|
static stringToUtf8ByteArray(str) {
|
|
712
716
|
if (globalThis.TextEncoder) {
|
|
713
717
|
if (!cachedNativeEncoder) cachedNativeEncoder = new TextEncoder();
|
|
714
|
-
return
|
|
718
|
+
return cachedNativeEncoder.encode(str);
|
|
715
719
|
} else {
|
|
716
720
|
let out = [], p = 0;
|
|
717
721
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -791,7 +795,7 @@
|
|
|
791
795
|
asCharSequence() {
|
|
792
796
|
throw Error("not implemented");
|
|
793
797
|
}
|
|
794
|
-
/** @returns {Uint8Array|number[]} */
|
|
798
|
+
/** @returns {Uint8Array|number[]|null} */
|
|
795
799
|
asBytes() {
|
|
796
800
|
throw Error("not implemented");
|
|
797
801
|
}
|
|
@@ -922,7 +926,8 @@
|
|
|
922
926
|
return 0;
|
|
923
927
|
}
|
|
924
928
|
};
|
|
925
|
-
var MachineUTF8Input = class extends MachineInputBase {
|
|
929
|
+
var MachineUTF8Input = class MachineUTF8Input extends MachineInputBase {
|
|
930
|
+
static RUNE_ERROR_STEP = Unicode.RUNE_ERROR << 3 | 1;
|
|
926
931
|
constructor(bytes, start = 0, end = bytes.length) {
|
|
927
932
|
super();
|
|
928
933
|
this.bytes = bytes;
|
|
@@ -936,33 +941,46 @@
|
|
|
936
941
|
return idx !== -1 && idx <= this.end - target.length;
|
|
937
942
|
}
|
|
938
943
|
hasAnyString(prefilter, pos) {
|
|
939
|
-
|
|
940
|
-
return prefilter.ac8.searchUTF8(this.bytes, this.start + pos, this.end);
|
|
944
|
+
return prefilter.automaton8().searchUTF8(this.bytes, this.start + pos, this.end);
|
|
941
945
|
}
|
|
942
946
|
step(pos) {
|
|
943
947
|
pos += this.start;
|
|
944
948
|
if (pos >= this.end) return MachineInputBase.EOF();
|
|
945
949
|
const c = this.bytes[pos] & 255;
|
|
946
950
|
if (c < 128) return c << 3 | 1;
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
951
|
+
let size;
|
|
952
|
+
let rune;
|
|
953
|
+
let lo = 128;
|
|
954
|
+
let hi = 191;
|
|
955
|
+
if (c >= 194 && c <= 223) {
|
|
956
|
+
size = 2;
|
|
957
|
+
rune = c & 31;
|
|
958
|
+
} else if (c >= 224 && c <= 239) {
|
|
959
|
+
size = 3;
|
|
960
|
+
rune = c & 15;
|
|
961
|
+
if (c === 224) lo = 160;
|
|
962
|
+
else if (c === 237) hi = 159;
|
|
963
|
+
} else if (c >= 240 && c <= 244) {
|
|
964
|
+
size = 4;
|
|
965
|
+
rune = c & 7;
|
|
966
|
+
if (c === 240) lo = 144;
|
|
967
|
+
else if (c === 244) hi = 143;
|
|
968
|
+
} else return MachineUTF8Input.RUNE_ERROR_STEP;
|
|
969
|
+
if (pos + size > this.end) return MachineUTF8Input.RUNE_ERROR_STEP;
|
|
970
|
+
const c1 = this.bytes[pos + 1] & 255;
|
|
971
|
+
if (c1 < lo || c1 > hi) return MachineUTF8Input.RUNE_ERROR_STEP;
|
|
972
|
+
rune = rune << 6 | c1 & 63;
|
|
973
|
+
if (size > 2) {
|
|
960
974
|
const c2 = this.bytes[pos + 2] & 255;
|
|
961
|
-
if ((c2 & 192) !== 128) return
|
|
962
|
-
|
|
963
|
-
if (
|
|
964
|
-
|
|
965
|
-
|
|
975
|
+
if ((c2 & 192) !== 128) return MachineUTF8Input.RUNE_ERROR_STEP;
|
|
976
|
+
rune = rune << 6 | c2 & 63;
|
|
977
|
+
if (size > 3) {
|
|
978
|
+
const c3 = this.bytes[pos + 3] & 255;
|
|
979
|
+
if ((c3 & 192) !== 128) return MachineUTF8Input.RUNE_ERROR_STEP;
|
|
980
|
+
rune = rune << 6 | c3 & 63;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return rune << 3 | size;
|
|
966
984
|
}
|
|
967
985
|
index(re2, pos) {
|
|
968
986
|
pos += this.start;
|
|
@@ -1027,8 +1045,7 @@
|
|
|
1027
1045
|
return idx !== -1 && idx <= this.end - prefilter.str.length;
|
|
1028
1046
|
}
|
|
1029
1047
|
hasAnyString(prefilter, pos) {
|
|
1030
|
-
|
|
1031
|
-
return prefilter.ac16.searchUTF16(this.charSequence, this.start + pos, this.end);
|
|
1048
|
+
return prefilter.automaton16().searchUTF16(this.charSequence, this.start + pos, this.end);
|
|
1032
1049
|
}
|
|
1033
1050
|
step(pos) {
|
|
1034
1051
|
pos += this.start;
|
|
@@ -1221,6 +1238,8 @@
|
|
|
1221
1238
|
this.namedGroups = re2.namedGroups;
|
|
1222
1239
|
/** @type {number} */
|
|
1223
1240
|
this.numberOfInstructions = re2.numberOfInstructions();
|
|
1241
|
+
/** @type {import('./Machine.js').LookbehindState|null} */
|
|
1242
|
+
this.lookbehindState = null;
|
|
1224
1243
|
if (input instanceof MatcherInputBase) this.resetMatcherInput(input);
|
|
1225
1244
|
else if (Utils.isByteArray(input)) this.resetMatcherInput(MatcherInput.utf8(input));
|
|
1226
1245
|
else this.resetMatcherInput(MatcherInput.utf16(input));
|
|
@@ -1254,9 +1273,13 @@
|
|
|
1254
1273
|
*/
|
|
1255
1274
|
resetMatcherInput(input) {
|
|
1256
1275
|
if (input === null) throw new Error("input is null");
|
|
1257
|
-
if (!(input instanceof MatcherInputBase))
|
|
1258
|
-
|
|
1276
|
+
if (!(input instanceof MatcherInputBase)) {
|
|
1277
|
+
if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
|
|
1278
|
+
else input = MatcherInput.utf16(input);
|
|
1279
|
+
}
|
|
1259
1280
|
this.matcherInput = input;
|
|
1281
|
+
if (this.lookbehindState !== null) this.lookbehindState.reset();
|
|
1282
|
+
else this.lookbehindState = this.patternInput.re2().createLookbehindState();
|
|
1260
1283
|
this.reset();
|
|
1261
1284
|
return this;
|
|
1262
1285
|
}
|
|
@@ -1344,11 +1367,11 @@
|
|
|
1344
1367
|
* @private
|
|
1345
1368
|
*/
|
|
1346
1369
|
loadGroup(group) {
|
|
1347
|
-
if (group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
|
|
1370
|
+
if (!Number.isInteger(group) || group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
|
|
1348
1371
|
if (!this.hasMatch) throw new RE2JSGroupException("perhaps no match attempted");
|
|
1349
1372
|
if (group === 0 || this.hasGroups) return;
|
|
1350
1373
|
const end = this.matcherInputLength;
|
|
1351
|
-
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount);
|
|
1374
|
+
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount, this.lookbehindState);
|
|
1352
1375
|
if (!res[0]) throw new RE2JSGroupException("inconsistency in matching group data");
|
|
1353
1376
|
this.groups = res[1];
|
|
1354
1377
|
this.hasGroups = true;
|
|
@@ -1381,7 +1404,7 @@
|
|
|
1381
1404
|
*/
|
|
1382
1405
|
find(start = null) {
|
|
1383
1406
|
if (start !== null) {
|
|
1384
|
-
if (start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
|
|
1407
|
+
if (!Number.isInteger(start) || start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
|
|
1385
1408
|
this.reset();
|
|
1386
1409
|
return this.genMatch(start, 0);
|
|
1387
1410
|
}
|
|
@@ -1404,8 +1427,11 @@
|
|
|
1404
1427
|
* @private
|
|
1405
1428
|
*/
|
|
1406
1429
|
genMatch(startByte, anchor) {
|
|
1407
|
-
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
|
|
1408
|
-
if (!res[0])
|
|
1430
|
+
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1, this.lookbehindState);
|
|
1431
|
+
if (!res[0]) {
|
|
1432
|
+
this.hasMatch = false;
|
|
1433
|
+
return false;
|
|
1434
|
+
}
|
|
1409
1435
|
this.groups = res[1];
|
|
1410
1436
|
this.hasMatch = true;
|
|
1411
1437
|
this.hasGroups = this.patternGroupCount === 0;
|
|
@@ -1468,43 +1494,47 @@
|
|
|
1468
1494
|
let res = "";
|
|
1469
1495
|
let last = 0;
|
|
1470
1496
|
const m = replacement.length;
|
|
1471
|
-
|
|
1472
|
-
|
|
1497
|
+
let i = 0;
|
|
1498
|
+
while (i < m) {
|
|
1499
|
+
const cCode = replacement.codePointAt(i);
|
|
1500
|
+
if (cCode === Codepoint.CODES.get("\\")) {
|
|
1473
1501
|
if (last < i) res += replacement.substring(last, i);
|
|
1474
1502
|
i++;
|
|
1503
|
+
if (i >= m) throw new RE2JSGroupException("character to be escaped is missing");
|
|
1475
1504
|
last = i;
|
|
1505
|
+
i++;
|
|
1476
1506
|
continue;
|
|
1477
1507
|
}
|
|
1478
|
-
if (
|
|
1479
|
-
|
|
1480
|
-
if (
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1508
|
+
if (cCode === Codepoint.CODES.get("$")) {
|
|
1509
|
+
if (last < i) res += replacement.substring(last, i);
|
|
1510
|
+
if (i + 1 >= m) throw new RE2JSGroupException("Illegal group reference: group index is missing");
|
|
1511
|
+
const nextCode = replacement.codePointAt(i + 1);
|
|
1512
|
+
if (Codepoint.CODES.get("0") <= nextCode && nextCode <= Codepoint.CODES.get("9")) {
|
|
1513
|
+
let n = nextCode - Codepoint.CODES.get("0");
|
|
1514
|
+
let j = i + 2;
|
|
1515
|
+
for (; j < m; j++) {
|
|
1516
|
+
const digit = replacement.codePointAt(j);
|
|
1517
|
+
if (digit < Codepoint.CODES.get("0") || digit > Codepoint.CODES.get("9") || n * 10 + digit - Codepoint.CODES.get("0") > this.patternGroupCount) break;
|
|
1518
|
+
n = n * 10 + digit - Codepoint.CODES.get("0");
|
|
1487
1519
|
}
|
|
1488
1520
|
if (n > this.patternGroupCount) throw new RE2JSGroupException(`n > number of groups: ${n}`);
|
|
1489
1521
|
const group = this.group(n);
|
|
1490
1522
|
if (group !== null) res += group;
|
|
1523
|
+
i = j;
|
|
1491
1524
|
last = i;
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
if (
|
|
1496
|
-
i
|
|
1497
|
-
let j = i + 1;
|
|
1498
|
-
while (j < replacement.length && replacement.codePointAt(j) !== Codepoint.CODES.get("}") && replacement.codePointAt(j) !== Codepoint.CODES.get(" ")) j++;
|
|
1499
|
-
if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get("}")) throw new RE2JSGroupException("named capture group is missing trailing '}'");
|
|
1500
|
-
const groupName = replacement.substring(i + 1, j);
|
|
1525
|
+
} else if (nextCode === Codepoint.CODES.get("{")) {
|
|
1526
|
+
let j = i + 2;
|
|
1527
|
+
while (j < m && replacement.codePointAt(j) !== Codepoint.CODES.get("}")) j++;
|
|
1528
|
+
if (j >= m) throw new RE2JSGroupException("named capture group is missing trailing '}'");
|
|
1529
|
+
const groupName = replacement.substring(i + 2, j);
|
|
1501
1530
|
const groupVal = this.group(groupName);
|
|
1502
1531
|
if (groupVal !== null) res += groupVal;
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1532
|
+
i = j + 1;
|
|
1533
|
+
last = i;
|
|
1534
|
+
} else throw new RE2JSGroupException("Illegal group reference");
|
|
1535
|
+
continue;
|
|
1507
1536
|
}
|
|
1537
|
+
i++;
|
|
1508
1538
|
}
|
|
1509
1539
|
if (last < m) res += replacement.substring(last, m);
|
|
1510
1540
|
return res;
|
|
@@ -1726,7 +1756,8 @@
|
|
|
1726
1756
|
this.op = op;
|
|
1727
1757
|
this.out = 0;
|
|
1728
1758
|
this.arg = 0;
|
|
1729
|
-
|
|
1759
|
+
/** @type {Int32Array} */
|
|
1760
|
+
this.runes = /* @__PURE__ */ new Int32Array(0);
|
|
1730
1761
|
/** @type {Uint32Array | number[] | null} */
|
|
1731
1762
|
this.next = null;
|
|
1732
1763
|
}
|
|
@@ -1815,18 +1846,26 @@
|
|
|
1815
1846
|
};
|
|
1816
1847
|
//#endregion
|
|
1817
1848
|
//#region src/Machine.js
|
|
1818
|
-
var
|
|
1819
|
-
constructor() {
|
|
1820
|
-
this.inst = null;
|
|
1821
|
-
this.cap = null;
|
|
1822
|
-
}
|
|
1823
|
-
};
|
|
1824
|
-
var Queue = class {
|
|
1849
|
+
var Queue = class Queue {
|
|
1825
1850
|
constructor(numInst) {
|
|
1826
1851
|
this.sparse = new Int32Array(numInst);
|
|
1827
1852
|
this.densePcs = new Int32Array(numInst);
|
|
1828
|
-
this.
|
|
1853
|
+
this.denseCaps = null;
|
|
1829
1854
|
this.size = 0;
|
|
1855
|
+
this.ncap = 0;
|
|
1856
|
+
this.mainThreads = 0;
|
|
1857
|
+
}
|
|
1858
|
+
static INITIAL_THREADS = 32;
|
|
1859
|
+
init(ncap) {
|
|
1860
|
+
this.ncap = ncap;
|
|
1861
|
+
const needed = Math.min(this.densePcs.length, Queue.INITIAL_THREADS) * ncap;
|
|
1862
|
+
if (!this.denseCaps || this.denseCaps.length < needed) this.denseCaps = new Int32Array(needed);
|
|
1863
|
+
}
|
|
1864
|
+
growCaps(needed) {
|
|
1865
|
+
const limit = this.densePcs.length * this.ncap;
|
|
1866
|
+
const grown = new Int32Array(Math.min(limit, Math.max(needed, 2 * this.denseCaps.length)));
|
|
1867
|
+
grown.set(this.denseCaps);
|
|
1868
|
+
this.denseCaps = grown;
|
|
1830
1869
|
}
|
|
1831
1870
|
contains(pc) {
|
|
1832
1871
|
const j = this.sparse[pc];
|
|
@@ -1838,13 +1877,12 @@
|
|
|
1838
1877
|
add(pc) {
|
|
1839
1878
|
const j = this.size++;
|
|
1840
1879
|
this.sparse[pc] = j;
|
|
1841
|
-
this.denseThreads[j] = null;
|
|
1842
1880
|
this.densePcs[j] = pc;
|
|
1843
1881
|
return j;
|
|
1844
1882
|
}
|
|
1845
1883
|
clear() {
|
|
1846
|
-
for (let i = 0; i < this.size; i++) this.denseThreads[i] = null;
|
|
1847
1884
|
this.size = 0;
|
|
1885
|
+
this.mainThreads = 0;
|
|
1848
1886
|
}
|
|
1849
1887
|
toString() {
|
|
1850
1888
|
let out = "{";
|
|
@@ -1856,31 +1894,37 @@
|
|
|
1856
1894
|
return out;
|
|
1857
1895
|
}
|
|
1858
1896
|
};
|
|
1897
|
+
var LookbehindState = class {
|
|
1898
|
+
constructor(prog) {
|
|
1899
|
+
this.pos = -1;
|
|
1900
|
+
this.pcs = new Int32Array(prog.numInst());
|
|
1901
|
+
this.size = 0;
|
|
1902
|
+
this.lbTable = new Int32Array(prog.numLb + 1);
|
|
1903
|
+
}
|
|
1904
|
+
reset() {
|
|
1905
|
+
this.pos = -1;
|
|
1906
|
+
this.size = 0;
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1859
1909
|
var Machine = class Machine {
|
|
1860
|
-
static THREADS_CHUNK_SIZE = 128;
|
|
1861
1910
|
static fromRE2(re2) {
|
|
1862
1911
|
const m = new Machine();
|
|
1863
1912
|
m.prog = re2.prog;
|
|
1864
1913
|
m.re2 = re2;
|
|
1865
1914
|
m.q0 = new Queue(m.prog.numInst());
|
|
1866
1915
|
m.q1 = new Queue(m.prog.numInst());
|
|
1867
|
-
m.
|
|
1868
|
-
m.poolSize = 0;
|
|
1916
|
+
m.addStack = new Int32Array(2 * (m.prog.numInst() + 1));
|
|
1869
1917
|
m.matched = false;
|
|
1870
1918
|
m.matchcap = new Int32Array(m.prog.numCap < 2 ? 2 : m.prog.numCap);
|
|
1871
1919
|
m.ncap = 0;
|
|
1872
1920
|
return m;
|
|
1873
1921
|
}
|
|
1874
|
-
static fromMachine(machine) {
|
|
1875
|
-
return Machine.fromRE2(machine.re2);
|
|
1876
|
-
}
|
|
1877
1922
|
constructor() {
|
|
1878
1923
|
this.prog = null;
|
|
1879
1924
|
this.re2 = null;
|
|
1880
1925
|
this.q0 = null;
|
|
1881
1926
|
this.q1 = null;
|
|
1882
|
-
this.
|
|
1883
|
-
this.poolSize = 0;
|
|
1927
|
+
this.addStack = null;
|
|
1884
1928
|
this.matched = false;
|
|
1885
1929
|
this.matchcap = null;
|
|
1886
1930
|
this.ncap = 0;
|
|
@@ -1888,59 +1932,36 @@
|
|
|
1888
1932
|
}
|
|
1889
1933
|
init(ncap) {
|
|
1890
1934
|
this.ncap = ncap;
|
|
1891
|
-
if (ncap > this.matchcap.length) this.
|
|
1892
|
-
else this.
|
|
1935
|
+
if (ncap > this.matchcap.length) this.matchcap = new Int32Array(ncap).fill(-1);
|
|
1936
|
+
else this.matchcap.fill(-1);
|
|
1937
|
+
this.q0.init(ncap);
|
|
1938
|
+
this.q1.init(ncap);
|
|
1893
1939
|
if (this.prog.numLb > 0) {
|
|
1894
1940
|
if (!this.lbTable || this.lbTable.length < this.prog.numLb + 1) this.lbTable = new Int32Array(this.prog.numLb + 1);
|
|
1895
1941
|
this.lbTable.fill(-1);
|
|
1896
1942
|
}
|
|
1897
1943
|
}
|
|
1898
|
-
resetCap() {
|
|
1899
|
-
for (let i = 0; i < this.poolSize; i++) this.pool[i].cap.fill(-1);
|
|
1900
|
-
}
|
|
1901
|
-
initNewCap(ncap) {
|
|
1902
|
-
for (let i = 0; i < this.poolSize; i++) {
|
|
1903
|
-
const t = this.pool[i];
|
|
1904
|
-
t.cap = new Int32Array(ncap).fill(-1);
|
|
1905
|
-
}
|
|
1906
|
-
this.matchcap = new Int32Array(ncap).fill(-1);
|
|
1907
|
-
}
|
|
1908
1944
|
submatches() {
|
|
1909
1945
|
if (this.ncap === 0) return Utils.emptyInts();
|
|
1910
1946
|
return Utils.toArray(this.matchcap.subarray(0, this.ncap));
|
|
1911
1947
|
}
|
|
1912
|
-
|
|
1913
|
-
if (this.poolSize === 0) {
|
|
1914
|
-
const capLen = this.matchcap.length;
|
|
1915
|
-
for (let i = 0; i < Machine.THREADS_CHUNK_SIZE; i++) {
|
|
1916
|
-
const t = new Thread();
|
|
1917
|
-
t.cap = new Int32Array(capLen);
|
|
1918
|
-
this.pool[this.poolSize++] = t;
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
this.poolSize--;
|
|
1922
|
-
const t = this.pool[this.poolSize];
|
|
1923
|
-
t.inst = inst;
|
|
1924
|
-
return t;
|
|
1925
|
-
}
|
|
1926
|
-
freeQueue(queue, from = 0) {
|
|
1927
|
-
for (let i = from; i < queue.size; i++) {
|
|
1928
|
-
const t = queue.denseThreads[i];
|
|
1929
|
-
if (t !== null) this.pool[this.poolSize++] = t;
|
|
1930
|
-
}
|
|
1931
|
-
queue.clear();
|
|
1932
|
-
}
|
|
1933
|
-
freeThread(t) {
|
|
1934
|
-
this.pool[this.poolSize++] = t;
|
|
1935
|
-
}
|
|
1936
|
-
match(input, pos, anchor) {
|
|
1948
|
+
match(input, pos, anchor, lbState = null) {
|
|
1937
1949
|
const startCond = this.re2.cond;
|
|
1938
1950
|
if (startCond === Utils.EMPTY_ALL) return false;
|
|
1939
1951
|
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
|
|
1940
1952
|
this.matched = false;
|
|
1941
1953
|
this.matchcap.fill(-1);
|
|
1942
|
-
|
|
1943
|
-
|
|
1954
|
+
const hasLookbehinds = this.prog.numLb > 0;
|
|
1955
|
+
const matchStartPos = pos;
|
|
1956
|
+
let currentPos = pos;
|
|
1957
|
+
let resumeLookbehinds = false;
|
|
1958
|
+
if (hasLookbehinds) {
|
|
1959
|
+
if (lbState !== null && lbState.pos >= 0 && lbState.pos <= pos) {
|
|
1960
|
+
currentPos = lbState.pos;
|
|
1961
|
+
resumeLookbehinds = true;
|
|
1962
|
+
} else currentPos = 0;
|
|
1963
|
+
}
|
|
1964
|
+
let saveLookbehinds = hasLookbehinds && lbState !== null;
|
|
1944
1965
|
let runq = this.q0;
|
|
1945
1966
|
let nextq = this.q1;
|
|
1946
1967
|
let r = input.step(currentPos);
|
|
@@ -1956,12 +1977,16 @@
|
|
|
1956
1977
|
let flag;
|
|
1957
1978
|
if (currentPos === 0) flag = Utils.emptyOpContext(-1, rune);
|
|
1958
1979
|
else flag = input.context(currentPos);
|
|
1980
|
+
if (hasLookbehinds) {
|
|
1981
|
+
if (resumeLookbehinds) this.restoreLookbehinds(lbState, runq, flag);
|
|
1982
|
+
else this.spawnLookbehinds(runq, currentPos, flag);
|
|
1983
|
+
}
|
|
1959
1984
|
while (true) {
|
|
1960
|
-
if (runq.
|
|
1985
|
+
if (runq.mainThreads === 0) {
|
|
1961
1986
|
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
|
|
1962
1987
|
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
|
|
1963
1988
|
if (this.matched) break;
|
|
1964
|
-
if (this.prog.numLb === 0 && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
|
|
1989
|
+
if (this.prog.numLb === 0 && runq.isEmpty() && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
|
|
1965
1990
|
const advance = input.index(this.re2, currentPos);
|
|
1966
1991
|
if (advance < 0) break;
|
|
1967
1992
|
currentPos += advance;
|
|
@@ -1971,13 +1996,17 @@
|
|
|
1971
1996
|
r = input.step(currentPos + width);
|
|
1972
1997
|
rune1 = r >> 3;
|
|
1973
1998
|
width1 = r & 7;
|
|
1999
|
+
flag = input.context(currentPos);
|
|
1974
2000
|
}
|
|
1975
2001
|
}
|
|
1976
|
-
if (currentPos
|
|
1977
|
-
|
|
1978
|
-
|
|
2002
|
+
if (currentPos >= matchStartPos) {
|
|
2003
|
+
if (saveLookbehinds) {
|
|
2004
|
+
this.saveLookbehinds(lbState, runq, currentPos);
|
|
2005
|
+
saveLookbehinds = false;
|
|
2006
|
+
}
|
|
2007
|
+
if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
|
|
1979
2008
|
if (this.ncap > 0) this.matchcap[0] = currentPos;
|
|
1980
|
-
this.add(runq, this.prog.start, currentPos, this.matchcap,
|
|
2009
|
+
this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
|
|
1981
2010
|
}
|
|
1982
2011
|
}
|
|
1983
2012
|
const nextPos = currentPos + width;
|
|
@@ -1997,7 +2026,8 @@
|
|
|
1997
2026
|
runq = nextq;
|
|
1998
2027
|
nextq = tmpq;
|
|
1999
2028
|
}
|
|
2000
|
-
|
|
2029
|
+
runq.clear();
|
|
2030
|
+
nextq.clear();
|
|
2001
2031
|
return this.matched;
|
|
2002
2032
|
}
|
|
2003
2033
|
matchSet(input, pos, anchor) {
|
|
@@ -2020,21 +2050,21 @@
|
|
|
2020
2050
|
}
|
|
2021
2051
|
let flag = currentPos === 0 ? Utils.emptyOpContext(-1, rune) : input.context(currentPos);
|
|
2022
2052
|
const matches = /* @__PURE__ */ new Set();
|
|
2053
|
+
if (this.prog.numLb > 0) this.spawnLookbehinds(runq, currentPos, flag);
|
|
2023
2054
|
while (true) {
|
|
2024
|
-
if (runq.
|
|
2055
|
+
if (runq.mainThreads === 0) {
|
|
2025
2056
|
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
|
|
2026
2057
|
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
|
|
2027
2058
|
}
|
|
2028
|
-
if (currentPos === 0 && this.prog.numLb > 0) for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(runq, this.prog.lbStarts[i], currentPos, this.matchcap, flag, null);
|
|
2029
2059
|
if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
|
|
2030
|
-
if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap,
|
|
2060
|
+
if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
|
|
2031
2061
|
}
|
|
2032
2062
|
const nextPos = currentPos + width;
|
|
2033
2063
|
flag = input.context(nextPos);
|
|
2034
2064
|
for (let j = 0; j < runq.size; j++) {
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
const
|
|
2065
|
+
const pc = runq.densePcs[j];
|
|
2066
|
+
const i = this.prog.inst[pc];
|
|
2067
|
+
const capOffset = j * this.ncap;
|
|
2038
2068
|
let add = false;
|
|
2039
2069
|
switch (i.op) {
|
|
2040
2070
|
case Inst.MATCH:
|
|
@@ -2051,15 +2081,11 @@
|
|
|
2051
2081
|
add = true;
|
|
2052
2082
|
break;
|
|
2053
2083
|
case Inst.RUNE_ANY_NOT_NL:
|
|
2054
|
-
add = rune !==
|
|
2084
|
+
add = rune !== 10;
|
|
2055
2085
|
break;
|
|
2056
|
-
default:
|
|
2057
|
-
}
|
|
2058
|
-
if (add) t = this.add(nextq, i.out, nextPos, t.cap, flag, t);
|
|
2059
|
-
if (t !== null) {
|
|
2060
|
-
this.freeThread(t);
|
|
2061
|
-
runq.denseThreads[j] = null;
|
|
2086
|
+
default: continue;
|
|
2062
2087
|
}
|
|
2088
|
+
if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, flag);
|
|
2063
2089
|
}
|
|
2064
2090
|
runq.clear();
|
|
2065
2091
|
if (width === 0) break;
|
|
@@ -2075,28 +2101,25 @@
|
|
|
2075
2101
|
runq = nextq;
|
|
2076
2102
|
nextq = tmpq;
|
|
2077
2103
|
}
|
|
2078
|
-
|
|
2104
|
+
nextq.clear();
|
|
2079
2105
|
return Array.from(matches).sort((a, b) => a - b);
|
|
2080
2106
|
}
|
|
2081
2107
|
step(runq, nextq, pos, nextPos, c, nextCond, anchor, atEnd) {
|
|
2082
2108
|
const longest = this.re2.longest;
|
|
2083
2109
|
for (let j = 0; j < runq.size; j++) {
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
if (longest && this.matched && this.ncap > 0 && this.matchcap[0] <
|
|
2087
|
-
|
|
2088
|
-
continue;
|
|
2089
|
-
}
|
|
2090
|
-
const i = t.inst;
|
|
2110
|
+
const pc = runq.densePcs[j];
|
|
2111
|
+
const capOffset = j * this.ncap;
|
|
2112
|
+
if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < runq.denseCaps[capOffset]) continue;
|
|
2113
|
+
const i = this.prog.inst[pc];
|
|
2091
2114
|
let add = false;
|
|
2092
2115
|
switch (i.op) {
|
|
2093
2116
|
case Inst.MATCH:
|
|
2094
2117
|
if (anchor === RE2Flags.ANCHOR_BOTH && !atEnd) break;
|
|
2095
2118
|
if (this.ncap > 0 && (!longest || !this.matched || this.matchcap[1] < pos)) {
|
|
2096
|
-
|
|
2097
|
-
|
|
2119
|
+
runq.denseCaps[capOffset + 1] = pos;
|
|
2120
|
+
for (let k = 0; k < this.ncap; k++) this.matchcap[k] = runq.denseCaps[capOffset + k];
|
|
2098
2121
|
}
|
|
2099
|
-
if (!longest)
|
|
2122
|
+
if (!longest) runq.size = 0;
|
|
2100
2123
|
this.matched = true;
|
|
2101
2124
|
break;
|
|
2102
2125
|
case Inst.RUNE:
|
|
@@ -2109,78 +2132,93 @@
|
|
|
2109
2132
|
add = true;
|
|
2110
2133
|
break;
|
|
2111
2134
|
case Inst.RUNE_ANY_NOT_NL:
|
|
2112
|
-
add = c !==
|
|
2135
|
+
add = c !== 10;
|
|
2113
2136
|
break;
|
|
2114
|
-
default:
|
|
2115
|
-
}
|
|
2116
|
-
if (add) t = this.add(nextq, i.out, nextPos, t.cap, nextCond, t);
|
|
2117
|
-
if (t !== null) {
|
|
2118
|
-
this.freeThread(t);
|
|
2119
|
-
runq.denseThreads[j] = null;
|
|
2137
|
+
default: continue;
|
|
2120
2138
|
}
|
|
2139
|
+
if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, nextCond);
|
|
2121
2140
|
}
|
|
2122
2141
|
runq.clear();
|
|
2123
2142
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2143
|
+
spawnLookbehinds(q, pos, flag) {
|
|
2144
|
+
for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(q, this.prog.lbStarts[i], pos, this.matchcap, 0, flag);
|
|
2145
|
+
}
|
|
2146
|
+
restoreLookbehinds(lbState, q, flag) {
|
|
2147
|
+
this.lbTable.set(lbState.lbTable);
|
|
2148
|
+
for (let j = 0; j < lbState.size; j++) this.add(q, lbState.pcs[j], lbState.pos, this.matchcap, 0, flag);
|
|
2149
|
+
}
|
|
2150
|
+
saveLookbehinds(lbState, q, pos) {
|
|
2151
|
+
let size = 0;
|
|
2152
|
+
for (let j = 0; j < q.size; j++) {
|
|
2153
|
+
const pc = q.densePcs[j];
|
|
2154
|
+
if (this.prog.lbInst[pc] === 1 && Inst.isRuneOp(this.prog.inst[pc].op)) lbState.pcs[size++] = pc;
|
|
2155
|
+
}
|
|
2156
|
+
lbState.size = size;
|
|
2157
|
+
lbState.pos = pos;
|
|
2158
|
+
lbState.lbTable.set(this.lbTable);
|
|
2159
|
+
}
|
|
2160
|
+
add(q, pc, pos, capArray, capOffset, cond) {
|
|
2161
|
+
const stk = this.addStack;
|
|
2162
|
+
let nstk = 0;
|
|
2163
|
+
for (;;) {
|
|
2164
|
+
while (pc !== 0 && !q.contains(pc)) {
|
|
2165
|
+
const d = q.add(pc);
|
|
2166
|
+
const inst = this.prog.inst[pc];
|
|
2167
|
+
switch (inst.op) {
|
|
2168
|
+
case Inst.FAIL:
|
|
2169
|
+
pc = 0;
|
|
2170
|
+
break;
|
|
2171
|
+
case Inst.ALT:
|
|
2172
|
+
case Inst.ALT_MATCH:
|
|
2173
|
+
stk[nstk++] = inst.arg;
|
|
2174
|
+
stk[nstk++] = 0;
|
|
2139
2175
|
pc = inst.out;
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
} else {
|
|
2153
|
-
pc = inst.out;
|
|
2154
|
-
continue;
|
|
2155
|
-
}
|
|
2156
|
-
case Inst.LB_WRITE:
|
|
2157
|
-
this.lbTable[Math.abs(inst.arg)] = pos;
|
|
2158
|
-
pc = inst.out;
|
|
2159
|
-
continue;
|
|
2160
|
-
case Inst.LB_CHECK:
|
|
2161
|
-
if (inst.arg > 0) {
|
|
2162
|
-
if (this.lbTable[inst.arg] === pos) {
|
|
2163
|
-
pc = inst.out;
|
|
2164
|
-
continue;
|
|
2176
|
+
break;
|
|
2177
|
+
case Inst.EMPTY_WIDTH:
|
|
2178
|
+
pc = (inst.arg & ~cond) === 0 ? inst.out : 0;
|
|
2179
|
+
break;
|
|
2180
|
+
case Inst.NOP:
|
|
2181
|
+
pc = inst.out;
|
|
2182
|
+
break;
|
|
2183
|
+
case Inst.CAPTURE:
|
|
2184
|
+
if (inst.arg < this.ncap) {
|
|
2185
|
+
stk[nstk++] = -inst.arg - 1;
|
|
2186
|
+
stk[nstk++] = capArray[capOffset + inst.arg];
|
|
2187
|
+
capArray[capOffset + inst.arg] = pos;
|
|
2165
2188
|
}
|
|
2166
|
-
} else if (this.lbTable[-inst.arg] !== pos) {
|
|
2167
2189
|
pc = inst.out;
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2190
|
+
break;
|
|
2191
|
+
case Inst.LB_WRITE:
|
|
2192
|
+
this.lbTable[Math.abs(inst.arg)] = pos;
|
|
2193
|
+
pc = inst.out;
|
|
2194
|
+
break;
|
|
2195
|
+
case Inst.LB_CHECK:
|
|
2196
|
+
if (inst.arg > 0) pc = this.lbTable[inst.arg] === pos ? inst.out : 0;
|
|
2197
|
+
else pc = this.lbTable[-inst.arg] !== pos ? inst.out : 0;
|
|
2198
|
+
break;
|
|
2199
|
+
case Inst.MATCH:
|
|
2200
|
+
case Inst.RUNE:
|
|
2201
|
+
case Inst.RUNE1:
|
|
2202
|
+
case Inst.RUNE_ANY:
|
|
2203
|
+
case Inst.RUNE_ANY_NOT_NL:
|
|
2204
|
+
if (this.prog.lbInst[pc] === 0) q.mainThreads++;
|
|
2205
|
+
if (this.ncap > 0) {
|
|
2206
|
+
const destOffset = d * this.ncap;
|
|
2207
|
+
if (destOffset + this.ncap > q.denseCaps.length) q.growCaps(destOffset + this.ncap);
|
|
2208
|
+
for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
|
|
2209
|
+
}
|
|
2210
|
+
pc = 0;
|
|
2211
|
+
break;
|
|
2212
|
+
default: throw new RE2JSInternalException("unhandled");
|
|
2213
|
+
}
|
|
2183
2214
|
}
|
|
2215
|
+
if (nstk === 0) return;
|
|
2216
|
+
nstk -= 2;
|
|
2217
|
+
const entry = stk[nstk];
|
|
2218
|
+
if (entry < 0) {
|
|
2219
|
+
capArray[capOffset - entry - 1] = stk[nstk + 1];
|
|
2220
|
+
pc = 0;
|
|
2221
|
+
} else pc = entry;
|
|
2184
2222
|
}
|
|
2185
2223
|
}
|
|
2186
2224
|
};
|
|
@@ -2200,35 +2238,85 @@
|
|
|
2200
2238
|
return true;
|
|
2201
2239
|
};
|
|
2202
2240
|
var DFAState = class {
|
|
2203
|
-
constructor(nfaStates, isMatch, matchIDs
|
|
2241
|
+
constructor(nfaStates, isMatch, matchIDs) {
|
|
2204
2242
|
this.nfaStates = nfaStates;
|
|
2205
2243
|
this.isMatch = isMatch;
|
|
2206
2244
|
this.matchIDs = matchIDs;
|
|
2207
|
-
this.
|
|
2208
|
-
this.
|
|
2209
|
-
this.transKeys = [];
|
|
2210
|
-
this.transVals = [];
|
|
2211
|
-
this.lastSeen = 0;
|
|
2245
|
+
this.next = null;
|
|
2246
|
+
this.nextAnchored = null;
|
|
2212
2247
|
}
|
|
2213
2248
|
};
|
|
2214
2249
|
var DFA = class DFA {
|
|
2215
|
-
static
|
|
2216
|
-
static
|
|
2250
|
+
static STATE_OVERHEAD = 160;
|
|
2251
|
+
static TABLE_OVERHEAD = 16;
|
|
2252
|
+
static PROGRESS_PER_STATE = 10;
|
|
2217
2253
|
constructor(prog, maxMem = 8388608) {
|
|
2218
2254
|
this.prog = prog;
|
|
2255
|
+
this.maxMem = maxMem;
|
|
2219
2256
|
this.stateCache = /* @__PURE__ */ new Map();
|
|
2220
2257
|
this.stateCount = 0;
|
|
2221
2258
|
this.startState = null;
|
|
2222
|
-
this.stateLimit = Math.max(1, Math.floor(maxMem / DFA.STATE_MEMORY_ESTIMATE));
|
|
2223
|
-
this.cacheClears = 0;
|
|
2224
2259
|
this.failed = false;
|
|
2225
|
-
|
|
2260
|
+
for (let pc = 0; pc < prog.numInst(); pc++) {
|
|
2261
|
+
const op = prog.getInst(pc).op;
|
|
2262
|
+
if (op === Inst.EMPTY_WIDTH || op === Inst.LB_WRITE || op === Inst.LB_CHECK) {
|
|
2263
|
+
this.failed = true;
|
|
2264
|
+
break;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
this.computeRuneClasses();
|
|
2268
|
+
this.stateBudget = maxMem;
|
|
2269
|
+
this.memBudget = maxMem;
|
|
2270
|
+
}
|
|
2271
|
+
computeRuneClasses() {
|
|
2272
|
+
const bounds = /* @__PURE__ */ new Set();
|
|
2273
|
+
const addRune = (r) => {
|
|
2274
|
+
bounds.add(r);
|
|
2275
|
+
bounds.add(r + 1);
|
|
2276
|
+
};
|
|
2277
|
+
for (let pc = 0; pc < this.prog.numInst(); pc++) {
|
|
2278
|
+
const inst = this.prog.getInst(pc);
|
|
2279
|
+
switch (inst.op) {
|
|
2280
|
+
case Inst.RUNE:
|
|
2281
|
+
case Inst.RUNE1:
|
|
2282
|
+
if (inst.runes.length === 1) {
|
|
2283
|
+
addRune(inst.runes[0]);
|
|
2284
|
+
if ((inst.arg & RE2Flags.FOLD_CASE) !== 0) for (let f = Unicode.simpleFold(inst.runes[0]); f !== inst.runes[0]; f = Unicode.simpleFold(f)) addRune(f);
|
|
2285
|
+
} else for (let j = 0; j < inst.runes.length; j += 2) {
|
|
2286
|
+
bounds.add(inst.runes[j]);
|
|
2287
|
+
bounds.add(inst.runes[j + 1] + 1);
|
|
2288
|
+
}
|
|
2289
|
+
break;
|
|
2290
|
+
case Inst.RUNE_ANY_NOT_NL: addRune(10);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
bounds.delete(0);
|
|
2294
|
+
this.classBounds = Int32Array.from(bounds).sort();
|
|
2295
|
+
this.numClasses = this.classBounds.length + 1;
|
|
2296
|
+
const latin1Class = new Int32Array(Unicode.MAX_LATIN1 + 1);
|
|
2297
|
+
for (let r = 0; r <= Unicode.MAX_LATIN1; r++) latin1Class[r] = this.searchClass(r);
|
|
2298
|
+
this.latin1Class = latin1Class;
|
|
2299
|
+
}
|
|
2300
|
+
runeClass(r) {
|
|
2301
|
+
if (r <= Unicode.MAX_LATIN1) return this.latin1Class[r];
|
|
2302
|
+
return this.searchClass(r);
|
|
2303
|
+
}
|
|
2304
|
+
searchClass(r) {
|
|
2305
|
+
const bounds = this.classBounds;
|
|
2306
|
+
let lo = 0;
|
|
2307
|
+
let hi = bounds.length;
|
|
2308
|
+
while (lo < hi) {
|
|
2309
|
+
const mid = lo + hi >> 1;
|
|
2310
|
+
if (bounds[mid] <= r) lo = mid + 1;
|
|
2311
|
+
else hi = mid;
|
|
2312
|
+
}
|
|
2313
|
+
return lo;
|
|
2226
2314
|
}
|
|
2227
2315
|
computeClosure(pcs) {
|
|
2228
2316
|
const closure = /* @__PURE__ */ new Set();
|
|
2229
2317
|
const stack = [...pcs];
|
|
2230
2318
|
let isMatch = false;
|
|
2231
|
-
const matchIDs =
|
|
2319
|
+
const matchIDs = /* @__PURE__ */ new Set();
|
|
2232
2320
|
while (stack.length > 0) {
|
|
2233
2321
|
const pc = stack.pop();
|
|
2234
2322
|
if (closure.has(pc)) continue;
|
|
@@ -2237,7 +2325,7 @@
|
|
|
2237
2325
|
switch (inst.op) {
|
|
2238
2326
|
case Inst.MATCH:
|
|
2239
2327
|
isMatch = true;
|
|
2240
|
-
|
|
2328
|
+
matchIDs.add(inst.arg);
|
|
2241
2329
|
break;
|
|
2242
2330
|
case Inst.ALT:
|
|
2243
2331
|
case Inst.ALT_MATCH:
|
|
@@ -2254,11 +2342,11 @@
|
|
|
2254
2342
|
}
|
|
2255
2343
|
}
|
|
2256
2344
|
const sortedPCs = Int32Array.from(closure).sort();
|
|
2257
|
-
matchIDs.sort((a, b) => a - b);
|
|
2345
|
+
const ids = Array.from(matchIDs).sort((a, b) => a - b);
|
|
2258
2346
|
return {
|
|
2259
2347
|
pcs: sortedPCs,
|
|
2260
2348
|
isMatch,
|
|
2261
|
-
matchIDs
|
|
2349
|
+
matchIDs: ids
|
|
2262
2350
|
};
|
|
2263
2351
|
}
|
|
2264
2352
|
getState(pcs) {
|
|
@@ -2269,156 +2357,126 @@
|
|
|
2269
2357
|
let bucket = this.stateCache.get(hash);
|
|
2270
2358
|
if (bucket) for (let i = 0; i < bucket.length; i++) {
|
|
2271
2359
|
const state = bucket[i];
|
|
2272
|
-
if (arraysEqual(state.nfaStates, sortedPCs))
|
|
2273
|
-
state.lastSeen = ++this.clock;
|
|
2274
|
-
return state;
|
|
2275
|
-
}
|
|
2360
|
+
if (arraysEqual(state.nfaStates, sortedPCs)) return state;
|
|
2276
2361
|
}
|
|
2277
|
-
|
|
2362
|
+
const cost = DFA.STATE_OVERHEAD + 4 * sortedPCs.length + 8 * closureResult.matchIDs.length;
|
|
2363
|
+
if (this.memBudget < cost) return null;
|
|
2364
|
+
this.memBudget -= cost;
|
|
2365
|
+
if (!bucket) {
|
|
2278
2366
|
bucket = [];
|
|
2279
2367
|
this.stateCache.set(hash, bucket);
|
|
2280
2368
|
}
|
|
2281
|
-
if (this.failed) return null;
|
|
2282
|
-
if (this.stateCount >= this.stateLimit) {
|
|
2283
|
-
this.cacheClears++;
|
|
2284
|
-
if (this.cacheClears >= DFA.MAX_CACHE_CLEARS) {
|
|
2285
|
-
this.failed = true;
|
|
2286
|
-
this.stateCache.clear();
|
|
2287
|
-
this.stateCount = 0;
|
|
2288
|
-
this.startState = null;
|
|
2289
|
-
return null;
|
|
2290
|
-
}
|
|
2291
|
-
this.evictCache();
|
|
2292
|
-
bucket = this.stateCache.get(hash);
|
|
2293
|
-
if (!bucket) {
|
|
2294
|
-
bucket = [];
|
|
2295
|
-
this.stateCache.set(hash, bucket);
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
2369
|
const state = new DFAState(sortedPCs, closureResult.isMatch, closureResult.matchIDs);
|
|
2299
|
-
state.lastSeen = ++this.clock;
|
|
2300
2370
|
bucket.push(state);
|
|
2301
2371
|
this.stateCount++;
|
|
2302
2372
|
return state;
|
|
2303
2373
|
}
|
|
2304
|
-
|
|
2305
|
-
const
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
const
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2374
|
+
allocTable(state, anchor) {
|
|
2375
|
+
const cost = DFA.TABLE_OVERHEAD + 8 * this.numClasses;
|
|
2376
|
+
if (this.memBudget < cost) return null;
|
|
2377
|
+
this.memBudget -= cost;
|
|
2378
|
+
const table = new Array(this.numClasses).fill(null);
|
|
2379
|
+
if (anchor === RE2Flags.UNANCHORED) state.next = table;
|
|
2380
|
+
else state.nextAnchored = table;
|
|
2381
|
+
return table;
|
|
2382
|
+
}
|
|
2383
|
+
clearCache() {
|
|
2312
2384
|
this.stateCache.clear();
|
|
2313
2385
|
this.stateCount = 0;
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
const hash = hashPCs(state.nfaStates);
|
|
2321
|
-
let bucket = this.stateCache.get(hash);
|
|
2322
|
-
if (!bucket) {
|
|
2323
|
-
bucket = [];
|
|
2324
|
-
this.stateCache.set(hash, bucket);
|
|
2325
|
-
}
|
|
2326
|
-
bucket.push(state);
|
|
2327
|
-
this.stateCount++;
|
|
2328
|
-
}
|
|
2329
|
-
if (this.startState && !survivors.has(this.startState)) this.startState = null;
|
|
2386
|
+
this.startState = null;
|
|
2387
|
+
this.memBudget = this.stateBudget;
|
|
2388
|
+
}
|
|
2389
|
+
resetCache(current) {
|
|
2390
|
+
this.clearCache();
|
|
2391
|
+
return this.getState(current.nfaStates);
|
|
2330
2392
|
}
|
|
2331
|
-
step(state,
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2393
|
+
step(state, cls, rune, anchor) {
|
|
2394
|
+
let table = anchor === RE2Flags.UNANCHORED ? state.next : state.nextAnchored;
|
|
2395
|
+
if (table !== null) {
|
|
2396
|
+
const cached = table[cls];
|
|
2397
|
+
if (cached !== null) return cached;
|
|
2335
2398
|
} else {
|
|
2336
|
-
|
|
2337
|
-
if (
|
|
2338
|
-
}
|
|
2339
|
-
else {
|
|
2340
|
-
const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
|
|
2341
|
-
const keys = state.transKeys;
|
|
2342
|
-
const len = keys.length;
|
|
2343
|
-
for (let i = 0; i < len; i++) if (keys[i] === key) return state.transVals[i];
|
|
2399
|
+
table = this.allocTable(state, anchor);
|
|
2400
|
+
if (table === null) return null;
|
|
2344
2401
|
}
|
|
2345
2402
|
const nextPCs = [];
|
|
2346
2403
|
for (let i = 0; i < state.nfaStates.length; i++) {
|
|
2347
2404
|
const pc = state.nfaStates[i];
|
|
2348
2405
|
const inst = this.prog.getInst(pc);
|
|
2349
|
-
if (Inst.isRuneOp(inst.op) && inst.matchRune(
|
|
2406
|
+
if (Inst.isRuneOp(inst.op) && inst.matchRune(rune)) nextPCs.push(inst.out);
|
|
2350
2407
|
}
|
|
2351
2408
|
if (anchor === RE2Flags.UNANCHORED) nextPCs.push(this.prog.start);
|
|
2352
2409
|
const nextState = this.getState(nextPCs);
|
|
2353
|
-
if (
|
|
2354
|
-
|
|
2355
|
-
else {
|
|
2356
|
-
const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
|
|
2357
|
-
state.transKeys.push(key);
|
|
2358
|
-
state.transVals.push(nextState);
|
|
2359
|
-
}
|
|
2410
|
+
if (nextState === null) return null;
|
|
2411
|
+
table[cls] = nextState;
|
|
2360
2412
|
return nextState;
|
|
2361
2413
|
}
|
|
2362
|
-
|
|
2363
|
-
if (
|
|
2364
|
-
if (!this.startState) {
|
|
2414
|
+
start() {
|
|
2415
|
+
if (this.startState === null) {
|
|
2365
2416
|
this.startState = this.getState([this.prog.start]);
|
|
2366
|
-
if (
|
|
2417
|
+
if (this.startState === null && !this.failed) {
|
|
2418
|
+
this.clearCache();
|
|
2419
|
+
this.startState = this.getState([this.prog.start]);
|
|
2420
|
+
}
|
|
2367
2421
|
}
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2422
|
+
return this.startState;
|
|
2423
|
+
}
|
|
2424
|
+
run(input, pos, anchor, state, onState, noMatch) {
|
|
2425
|
+
const endPos = input.endPos();
|
|
2426
|
+
const latin1Class = this.latin1Class;
|
|
2427
|
+
let resetPos = -1;
|
|
2373
2428
|
let i = pos;
|
|
2374
2429
|
while (i < endPos) {
|
|
2375
2430
|
const r = input.step(i);
|
|
2376
2431
|
const rune = r >> 3;
|
|
2377
2432
|
const width = r & 7;
|
|
2378
2433
|
if (width === 0) break;
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
if (
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2434
|
+
const cls = rune <= Unicode.MAX_LATIN1 ? latin1Class[rune] : this.runeClass(rune);
|
|
2435
|
+
let next = anchor === RE2Flags.UNANCHORED && state.next !== null ? state.next[cls] : null;
|
|
2436
|
+
if (next === null) {
|
|
2437
|
+
next = this.step(state, cls, rune, anchor);
|
|
2438
|
+
if (next === null) {
|
|
2439
|
+
if (resetPos >= 0 && i - resetPos < DFA.PROGRESS_PER_STATE * this.stateCount) return null;
|
|
2440
|
+
resetPos = i;
|
|
2441
|
+
state = this.resetCache(state);
|
|
2442
|
+
if (state === null) return null;
|
|
2443
|
+
next = this.step(state, cls, rune, anchor);
|
|
2444
|
+
if (next === null) return null;
|
|
2445
|
+
}
|
|
2387
2446
|
}
|
|
2447
|
+
state = next;
|
|
2388
2448
|
i += width;
|
|
2449
|
+
const result = onState(state, i);
|
|
2450
|
+
if (result !== null) return result;
|
|
2451
|
+
if (state.nfaStates.length === 0 && anchor !== RE2Flags.UNANCHORED) return noMatch;
|
|
2389
2452
|
}
|
|
2390
|
-
return
|
|
2453
|
+
return noMatch;
|
|
2454
|
+
}
|
|
2455
|
+
match(input, pos, anchor) {
|
|
2456
|
+
if (this.failed) return null;
|
|
2457
|
+
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
|
|
2458
|
+
const startState = this.start();
|
|
2459
|
+
if (startState === null) return null;
|
|
2460
|
+
const endPos = input.endPos();
|
|
2461
|
+
if (startState.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || pos === endPos)) return true;
|
|
2462
|
+
return this.run(input, pos, anchor, startState, (state, nextPos) => {
|
|
2463
|
+
if (state.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || nextPos === endPos)) return true;
|
|
2464
|
+
return null;
|
|
2465
|
+
}, false);
|
|
2391
2466
|
}
|
|
2392
2467
|
matchSet(input, pos, anchor) {
|
|
2468
|
+
if (this.failed) return null;
|
|
2393
2469
|
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return [];
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
}
|
|
2398
|
-
let endPos = input.endPos();
|
|
2399
|
-
let currentState = this.startState;
|
|
2470
|
+
const startState = this.start();
|
|
2471
|
+
if (startState === null) return null;
|
|
2472
|
+
const endPos = input.endPos();
|
|
2400
2473
|
const matches = /* @__PURE__ */ new Set();
|
|
2401
|
-
const
|
|
2402
|
-
if (state.isMatch
|
|
2403
|
-
|
|
2404
|
-
} else state.matchIDs.forEach((id) => matches.add(id));
|
|
2474
|
+
const collect = (state, currentPos) => {
|
|
2475
|
+
if (state.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || currentPos === endPos)) for (let k = 0; k < state.matchIDs.length; k++) matches.add(state.matchIDs[k]);
|
|
2476
|
+
return null;
|
|
2405
2477
|
};
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
while (i < endPos) {
|
|
2409
|
-
const r = input.step(i);
|
|
2410
|
-
const rune = r >> 3;
|
|
2411
|
-
const width = r & 7;
|
|
2412
|
-
if (width === 0) break;
|
|
2413
|
-
currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
|
|
2414
|
-
if (currentState === null) return null;
|
|
2415
|
-
currentState.lastSeen = ++this.clock;
|
|
2416
|
-
i += width;
|
|
2417
|
-
checkMatch(currentState, i);
|
|
2418
|
-
if (currentState.nfaStates.length === 0) {
|
|
2419
|
-
if (anchor !== RE2Flags.UNANCHORED) break;
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2478
|
+
collect(startState, pos);
|
|
2479
|
+
if (this.run(input, pos, anchor, startState, collect, false) === null) return null;
|
|
2422
2480
|
return Array.from(matches).sort((a, b) => a - b);
|
|
2423
2481
|
}
|
|
2424
2482
|
};
|
|
@@ -2427,7 +2485,7 @@
|
|
|
2427
2485
|
const VISITED_BITS = 32;
|
|
2428
2486
|
const MAX_BACKTRACK_PROG = 500;
|
|
2429
2487
|
const INITIAL_JOB_CAPACITY = 256;
|
|
2430
|
-
const MAX_BACKTRACK_VECTOR =
|
|
2488
|
+
const MAX_BACKTRACK_VECTOR = 262144;
|
|
2431
2489
|
var BitState = class {
|
|
2432
2490
|
constructor() {
|
|
2433
2491
|
this.end = 0;
|
|
@@ -2710,7 +2768,7 @@
|
|
|
2710
2768
|
const inst = new Inst(orig.op);
|
|
2711
2769
|
inst.out = orig.out;
|
|
2712
2770
|
inst.arg = orig.arg;
|
|
2713
|
-
inst.runes = orig.runes ? orig.runes
|
|
2771
|
+
inst.runes = orig.runes ? new Int32Array(orig.runes) : /* @__PURE__ */ new Int32Array(0);
|
|
2714
2772
|
inst.next = null;
|
|
2715
2773
|
this.inst[i] = inst;
|
|
2716
2774
|
}
|
|
@@ -2776,9 +2834,11 @@
|
|
|
2776
2834
|
m[pc] = true;
|
|
2777
2835
|
inst.op = Inst.ALT_MATCH;
|
|
2778
2836
|
}
|
|
2779
|
-
const
|
|
2837
|
+
const leftRunes = onePassRunes[inst.out] || [];
|
|
2838
|
+
const rightRunes = onePassRunes[inst.arg] || [];
|
|
2839
|
+
const mergeRes = mergeRuneSets(leftRunes, rightRunes, inst.out, inst.arg);
|
|
2780
2840
|
if (!mergeRes) return false;
|
|
2781
|
-
onePassRunes[pc] = mergeRes.merged;
|
|
2841
|
+
onePassRunes[pc] = new Int32Array(mergeRes.merged);
|
|
2782
2842
|
inst.next = new Uint32Array(mergeRes.next);
|
|
2783
2843
|
break;
|
|
2784
2844
|
}
|
|
@@ -2787,7 +2847,7 @@
|
|
|
2787
2847
|
case Inst.NOP:
|
|
2788
2848
|
ok = check(inst.out);
|
|
2789
2849
|
m[pc] = m[inst.out];
|
|
2790
|
-
onePassRunes[pc] = onePassRunes[inst.out] ? onePassRunes[inst.out]
|
|
2850
|
+
onePassRunes[pc] = onePassRunes[inst.out] ? new Int32Array(onePassRunes[inst.out]) : /* @__PURE__ */ new Int32Array(0);
|
|
2791
2851
|
inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
|
|
2792
2852
|
break;
|
|
2793
2853
|
case Inst.MATCH:
|
|
@@ -2799,7 +2859,7 @@
|
|
|
2799
2859
|
if (inst.next && inst.next.length > 0) break;
|
|
2800
2860
|
instQueue.insert(inst.out);
|
|
2801
2861
|
if (!inst.runes || inst.runes.length === 0) {
|
|
2802
|
-
onePassRunes[pc] =
|
|
2862
|
+
onePassRunes[pc] = /* @__PURE__ */ new Int32Array(0);
|
|
2803
2863
|
inst.next = new Uint32Array([inst.out]);
|
|
2804
2864
|
break;
|
|
2805
2865
|
}
|
|
@@ -2810,7 +2870,7 @@
|
|
|
2810
2870
|
for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
|
|
2811
2871
|
runes.sort((a, b) => a - b);
|
|
2812
2872
|
} else for (let j = 0; j < inst.runes.length; j++) runes.push(inst.runes[j]);
|
|
2813
|
-
onePassRunes[pc] = runes;
|
|
2873
|
+
onePassRunes[pc] = new Int32Array(runes);
|
|
2814
2874
|
inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
|
|
2815
2875
|
inst.op = Inst.RUNE;
|
|
2816
2876
|
break;
|
|
@@ -2826,7 +2886,7 @@
|
|
|
2826
2886
|
for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
|
|
2827
2887
|
runes.sort((a, b) => a - b);
|
|
2828
2888
|
} else runes.push(inst.runes[0], inst.runes[0]);
|
|
2829
|
-
onePassRunes[pc] = runes;
|
|
2889
|
+
onePassRunes[pc] = new Int32Array(runes);
|
|
2830
2890
|
inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
|
|
2831
2891
|
inst.op = Inst.RUNE;
|
|
2832
2892
|
break;
|
|
@@ -2835,21 +2895,20 @@
|
|
|
2835
2895
|
m[pc] = false;
|
|
2836
2896
|
if (inst.next && inst.next.length > 0) break;
|
|
2837
2897
|
instQueue.insert(inst.out);
|
|
2838
|
-
onePassRunes[pc] = [0, Unicode.MAX_RUNE];
|
|
2898
|
+
onePassRunes[pc] = new Int32Array([0, Unicode.MAX_RUNE]);
|
|
2839
2899
|
inst.next = new Uint32Array([inst.out]);
|
|
2840
2900
|
break;
|
|
2841
2901
|
case Inst.RUNE_ANY_NOT_NL:
|
|
2842
2902
|
m[pc] = false;
|
|
2843
2903
|
if (inst.next && inst.next.length > 0) break;
|
|
2844
2904
|
instQueue.insert(inst.out);
|
|
2845
|
-
onePassRunes[pc] = [
|
|
2905
|
+
onePassRunes[pc] = new Int32Array([
|
|
2846
2906
|
0,
|
|
2847
2907
|
9,
|
|
2848
2908
|
11,
|
|
2849
2909
|
Unicode.MAX_RUNE
|
|
2850
|
-
];
|
|
2910
|
+
]);
|
|
2851
2911
|
inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
|
|
2852
|
-
break;
|
|
2853
2912
|
}
|
|
2854
2913
|
return ok;
|
|
2855
2914
|
};
|
|
@@ -2881,8 +2940,7 @@
|
|
|
2881
2940
|
case Inst.RUNE_ANY_NOT_NL:
|
|
2882
2941
|
p.inst[ix].next = null;
|
|
2883
2942
|
p.inst[ix].op = instOriginal.op;
|
|
2884
|
-
p.inst[ix].runes = instOriginal.runes ? instOriginal.runes
|
|
2885
|
-
break;
|
|
2943
|
+
p.inst[ix].runes = instOriginal.runes ? new Int32Array(instOriginal.runes) : /* @__PURE__ */ new Int32Array(0);
|
|
2886
2944
|
}
|
|
2887
2945
|
}
|
|
2888
2946
|
};
|
|
@@ -2911,9 +2969,7 @@
|
|
|
2911
2969
|
return null;
|
|
2912
2970
|
}
|
|
2913
2971
|
break;
|
|
2914
|
-
default:
|
|
2915
|
-
if (opOut === Inst.MATCH && hasAlt) return null;
|
|
2916
|
-
break;
|
|
2972
|
+
default: if (opOut === Inst.MATCH && hasAlt) return null;
|
|
2917
2973
|
}
|
|
2918
2974
|
}
|
|
2919
2975
|
let p = onePassCopy(prog);
|
|
@@ -3064,7 +3120,7 @@
|
|
|
3064
3120
|
this.op = op;
|
|
3065
3121
|
this.flags = 0;
|
|
3066
3122
|
this.subs = Regexp.emptySubs();
|
|
3067
|
-
this.runes =
|
|
3123
|
+
this.runes = /* @__PURE__ */ new Int32Array(0);
|
|
3068
3124
|
this.min = 0;
|
|
3069
3125
|
this.max = 0;
|
|
3070
3126
|
this.cap = 0;
|
|
@@ -3075,7 +3131,7 @@
|
|
|
3075
3131
|
reinit() {
|
|
3076
3132
|
this.flags = 0;
|
|
3077
3133
|
this.subs = Regexp.emptySubs();
|
|
3078
|
-
this.runes =
|
|
3134
|
+
this.runes = /* @__PURE__ */ new Int32Array(0);
|
|
3079
3135
|
this.cap = 0;
|
|
3080
3136
|
this.min = 0;
|
|
3081
3137
|
this.max = 0;
|
|
@@ -3119,7 +3175,6 @@
|
|
|
3119
3175
|
if (this.max >= 0) out += this.max;
|
|
3120
3176
|
}
|
|
3121
3177
|
out += "}";
|
|
3122
|
-
break;
|
|
3123
3178
|
}
|
|
3124
3179
|
if ((this.flags & RE2Flags.NON_GREEDY) !== 0) out += "?";
|
|
3125
3180
|
break;
|
|
@@ -3212,9 +3267,7 @@
|
|
|
3212
3267
|
}
|
|
3213
3268
|
out += "]";
|
|
3214
3269
|
break;
|
|
3215
|
-
default:
|
|
3216
|
-
out += this.op;
|
|
3217
|
-
break;
|
|
3270
|
+
default: out += this.op;
|
|
3218
3271
|
}
|
|
3219
3272
|
return out;
|
|
3220
3273
|
}
|
|
@@ -3258,70 +3311,158 @@
|
|
|
3258
3311
|
if (this.cap !== that.cap || (this.name === null ? that.name !== null : this.name !== that.name) || !this.subs[0].equals(that.subs[0])) return false;
|
|
3259
3312
|
break;
|
|
3260
3313
|
case Regexp.Op.PLB:
|
|
3261
|
-
case Regexp.Op.NLB:
|
|
3262
|
-
if (this.lb !== that.lb || !this.subs[0].equals(that.subs[0])) return false;
|
|
3263
|
-
break;
|
|
3314
|
+
case Regexp.Op.NLB: if (this.lb !== that.lb || !this.subs[0].equals(that.subs[0])) return false;
|
|
3264
3315
|
}
|
|
3265
3316
|
return true;
|
|
3266
3317
|
}
|
|
3267
3318
|
};
|
|
3268
3319
|
//#endregion
|
|
3320
|
+
//#region src/RegexpWalker.js
|
|
3321
|
+
/**
|
|
3322
|
+
* Walks a Regexp tree without recursion, visiting nodes in the same order a recursive walk
|
|
3323
|
+
* would (RE2: re2/walker-inl.h, "Helper class for traversing Regexps without recursion").
|
|
3324
|
+
*
|
|
3325
|
+
* The handler sees a node without subexpressions once, through `leaf(re)`, which returns its
|
|
3326
|
+
* result. Any other node is seen up to three times:
|
|
3327
|
+
* - `enter(re)` before its children. It returns the state kept for `re` while its children are
|
|
3328
|
+
* visited; a state whose `result` is already set skips the children.
|
|
3329
|
+
* - `child(re, state, result, i)` after child `i` produced `result`. Setting `state.result`
|
|
3330
|
+
* stops visiting the remaining children.
|
|
3331
|
+
* - `leave(re, state)` after the last child; it returns the result for `re`.
|
|
3332
|
+
*
|
|
3333
|
+
* Counted repetitions expand into one nesting level per copy, so the simplified tree can be
|
|
3334
|
+
* thousands of levels deep; recursion over it would overflow the JS stack, which has no fixed
|
|
3335
|
+
* relation to the parser's nesting limit. This walk keeps its frames on the heap instead.
|
|
3336
|
+
*/
|
|
3337
|
+
var RegexpWalker = class {
|
|
3338
|
+
static walk(root, handler) {
|
|
3339
|
+
const stack = [];
|
|
3340
|
+
let re = root;
|
|
3341
|
+
let result;
|
|
3342
|
+
for (;;) {
|
|
3343
|
+
if (re.subs.length === 0) result = handler.leaf(re);
|
|
3344
|
+
else {
|
|
3345
|
+
const state = handler.enter(re);
|
|
3346
|
+
if (state.result === void 0) {
|
|
3347
|
+
stack.push({
|
|
3348
|
+
re,
|
|
3349
|
+
state,
|
|
3350
|
+
i: 0
|
|
3351
|
+
});
|
|
3352
|
+
re = re.subs[0];
|
|
3353
|
+
continue;
|
|
3354
|
+
}
|
|
3355
|
+
result = state.result;
|
|
3356
|
+
}
|
|
3357
|
+
for (;;) {
|
|
3358
|
+
if (stack.length === 0) return result;
|
|
3359
|
+
const frame = stack[stack.length - 1];
|
|
3360
|
+
handler.child(frame.re, frame.state, result, frame.i);
|
|
3361
|
+
frame.i++;
|
|
3362
|
+
if (frame.state.result === void 0 && frame.i < frame.re.subs.length) {
|
|
3363
|
+
re = frame.re.subs[frame.i];
|
|
3364
|
+
break;
|
|
3365
|
+
}
|
|
3366
|
+
stack.pop();
|
|
3367
|
+
result = frame.state.result !== void 0 ? frame.state.result : handler.leave(frame.re, frame.state);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
};
|
|
3372
|
+
//#endregion
|
|
3269
3373
|
//#region src/Prefilter.js
|
|
3270
3374
|
var AhoCorasick = class {
|
|
3271
|
-
constructor(
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3375
|
+
constructor(words, alphabetSize) {
|
|
3376
|
+
const edges = /* @__PURE__ */ new Map();
|
|
3377
|
+
const parent = [0];
|
|
3378
|
+
const unit = [0];
|
|
3379
|
+
const depth = [0];
|
|
3380
|
+
const terminal = [0];
|
|
3381
|
+
for (const word of words) {
|
|
3276
3382
|
let node = 0;
|
|
3277
3383
|
for (let i = 0; i < word.length; i++) {
|
|
3278
|
-
const
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3384
|
+
const key = node * alphabetSize + word[i];
|
|
3385
|
+
let child = edges.get(key);
|
|
3386
|
+
if (child === void 0) {
|
|
3387
|
+
child = parent.length;
|
|
3388
|
+
edges.set(key, child);
|
|
3389
|
+
parent.push(node);
|
|
3390
|
+
unit.push(word[i]);
|
|
3391
|
+
depth.push(depth[node] + 1);
|
|
3392
|
+
terminal.push(0);
|
|
3284
3393
|
}
|
|
3285
|
-
node =
|
|
3394
|
+
node = child;
|
|
3286
3395
|
}
|
|
3287
|
-
|
|
3288
|
-
}
|
|
3289
|
-
const
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3396
|
+
terminal[node] = 1;
|
|
3397
|
+
}
|
|
3398
|
+
const numNodes = parent.length;
|
|
3399
|
+
const children = new Int32Array(numNodes - 1);
|
|
3400
|
+
for (let c = 1; c < numNodes; c++) children[c - 1] = c;
|
|
3401
|
+
children.sort((a, b) => parent[a] - parent[b] || unit[a] - unit[b]);
|
|
3402
|
+
const childStart = new Int32Array(numNodes + 1);
|
|
3403
|
+
for (let c = 1; c < numNodes; c++) childStart[parent[c] + 1]++;
|
|
3404
|
+
for (let n = 0; n < numNodes; n++) childStart[n + 1] += childStart[n];
|
|
3405
|
+
const childUnit = new Int32Array(numNodes - 1);
|
|
3406
|
+
for (let k = 0; k < children.length; k++) childUnit[k] = unit[children[k]];
|
|
3407
|
+
this.childStart = childStart;
|
|
3408
|
+
this.childUnit = childUnit;
|
|
3409
|
+
this.childNode = children;
|
|
3410
|
+
const byDepth = new Int32Array(numNodes);
|
|
3411
|
+
for (let n = 0; n < numNodes; n++) byDepth[n] = n;
|
|
3412
|
+
byDepth.sort((a, b) => depth[a] - depth[b]);
|
|
3413
|
+
const fail = new Int32Array(numNodes);
|
|
3414
|
+
const match = Uint8Array.from(terminal);
|
|
3415
|
+
for (let k = 1; k < numNodes; k++) {
|
|
3416
|
+
const c = byDepth[k];
|
|
3417
|
+
const p = parent[c];
|
|
3418
|
+
if (p !== 0) {
|
|
3419
|
+
let f = fail[p];
|
|
3420
|
+
let next = this.next(f, unit[c]);
|
|
3421
|
+
while (next < 0 && f !== 0) {
|
|
3422
|
+
f = fail[f];
|
|
3423
|
+
next = this.next(f, unit[c]);
|
|
3424
|
+
}
|
|
3425
|
+
fail[c] = next >= 0 ? next : 0;
|
|
3305
3426
|
}
|
|
3427
|
+
match[c] |= match[fail[c]];
|
|
3428
|
+
}
|
|
3429
|
+
this.fail = fail;
|
|
3430
|
+
this.match = match;
|
|
3431
|
+
}
|
|
3432
|
+
next(node, u) {
|
|
3433
|
+
let lo = this.childStart[node];
|
|
3434
|
+
let hi = this.childStart[node + 1];
|
|
3435
|
+
const units = this.childUnit;
|
|
3436
|
+
while (lo < hi) {
|
|
3437
|
+
const mid = lo + hi >> 1;
|
|
3438
|
+
const m = units[mid];
|
|
3439
|
+
if (m === u) return this.childNode[mid];
|
|
3440
|
+
if (m < u) lo = mid + 1;
|
|
3441
|
+
else hi = mid;
|
|
3442
|
+
}
|
|
3443
|
+
return -1;
|
|
3444
|
+
}
|
|
3445
|
+
advance(node, u) {
|
|
3446
|
+
for (;;) {
|
|
3447
|
+
const next = this.next(node, u);
|
|
3448
|
+
if (next >= 0) return next;
|
|
3449
|
+
if (node === 0) return 0;
|
|
3450
|
+
node = this.fail[node];
|
|
3306
3451
|
}
|
|
3307
3452
|
}
|
|
3308
3453
|
searchUTF16(charSeq, start, end) {
|
|
3309
3454
|
let node = 0;
|
|
3310
3455
|
for (let i = start; i < end; i++) {
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
if (val in this.next[node]) node = this.next[node][val];
|
|
3314
|
-
if (this.match[node]) return true;
|
|
3456
|
+
node = this.advance(node, charSeq.charCodeAt(i));
|
|
3457
|
+
if (this.match[node] === 1) return true;
|
|
3315
3458
|
}
|
|
3316
3459
|
return false;
|
|
3317
3460
|
}
|
|
3318
3461
|
searchUTF8(bytes, start, end) {
|
|
3319
3462
|
let node = 0;
|
|
3320
3463
|
for (let i = start; i < end; i++) {
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
if (val in this.next[node]) node = this.next[node][val];
|
|
3324
|
-
if (this.match[node]) return true;
|
|
3464
|
+
node = this.advance(node, bytes[i]);
|
|
3465
|
+
if (this.match[node] === 1) return true;
|
|
3325
3466
|
}
|
|
3326
3467
|
return false;
|
|
3327
3468
|
}
|
|
@@ -3333,14 +3474,33 @@
|
|
|
3333
3474
|
AND: 2,
|
|
3334
3475
|
OR: 3
|
|
3335
3476
|
};
|
|
3477
|
+
static MAX_SCANS = 32;
|
|
3478
|
+
static MAX_AC_UNITS = 1 << 18;
|
|
3336
3479
|
constructor(type) {
|
|
3337
3480
|
this.type = type;
|
|
3338
3481
|
this.subs = [];
|
|
3339
3482
|
this.str = "";
|
|
3340
3483
|
this.bytes = null;
|
|
3484
|
+
this.cost = type === Prefilter.Type.EXACT ? 1 : 0;
|
|
3485
|
+
this.allExact = false;
|
|
3341
3486
|
this.ac16 = null;
|
|
3342
3487
|
this.ac8 = null;
|
|
3343
3488
|
}
|
|
3489
|
+
automaton16() {
|
|
3490
|
+
if (this.ac16 === null) {
|
|
3491
|
+
const words = this.subs.map((s) => {
|
|
3492
|
+
const arr = new Array(s.str.length);
|
|
3493
|
+
for (let i = 0; i < s.str.length; i++) arr[i] = s.str.charCodeAt(i);
|
|
3494
|
+
return arr;
|
|
3495
|
+
});
|
|
3496
|
+
this.ac16 = new AhoCorasick(words, 65536);
|
|
3497
|
+
}
|
|
3498
|
+
return this.ac16;
|
|
3499
|
+
}
|
|
3500
|
+
automaton8() {
|
|
3501
|
+
if (this.ac8 === null) this.ac8 = new AhoCorasick(this.subs.map((s) => s.bytes), 256);
|
|
3502
|
+
return this.ac8;
|
|
3503
|
+
}
|
|
3344
3504
|
eval(input, pos) {
|
|
3345
3505
|
switch (this.type) {
|
|
3346
3506
|
case Prefilter.Type.NONE: return true;
|
|
@@ -3349,7 +3509,7 @@
|
|
|
3349
3509
|
for (let i = 0; i < this.subs.length; i++) if (!this.subs[i].eval(input, pos)) return false;
|
|
3350
3510
|
return true;
|
|
3351
3511
|
case Prefilter.Type.OR:
|
|
3352
|
-
if (this.
|
|
3512
|
+
if (this.allExact) return input.hasAnyString(this, pos);
|
|
3353
3513
|
for (let i = 0; i < this.subs.length; i++) if (this.subs[i].eval(input, pos)) return true;
|
|
3354
3514
|
return false;
|
|
3355
3515
|
default: return true;
|
|
@@ -3358,100 +3518,115 @@
|
|
|
3358
3518
|
};
|
|
3359
3519
|
var PrefilterTree = class PrefilterTree {
|
|
3360
3520
|
static build(re) {
|
|
3361
|
-
const pf = PrefilterTree.fromRegexp(re);
|
|
3362
|
-
return PrefilterTree.simplify(pf);
|
|
3363
|
-
}
|
|
3364
|
-
static fromRegexp(re) {
|
|
3365
3521
|
if (!re) return new Prefilter(Prefilter.Type.NONE);
|
|
3522
|
+
return RegexpWalker.walk(re, PrefilterTree.WALKER);
|
|
3523
|
+
}
|
|
3524
|
+
static WALKER = {
|
|
3525
|
+
leaf: (re) => PrefilterTree.leaf(re),
|
|
3526
|
+
enter: (re) => PrefilterTree.enter(re),
|
|
3527
|
+
child: (re, state, result) => PrefilterTree.child(re, state, result),
|
|
3528
|
+
leave: (re, state) => PrefilterTree.leave(re, state)
|
|
3529
|
+
};
|
|
3530
|
+
static leaf(re) {
|
|
3531
|
+
if (re.op !== Regexp.Op.LITERAL) return new Prefilter(Prefilter.Type.NONE);
|
|
3532
|
+
if (re.runes.length === 0 || (re.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
|
|
3533
|
+
let str = "";
|
|
3534
|
+
for (let i = 0; i < re.runes.length; i++) {
|
|
3535
|
+
if (Unicode.isUnsearchable(re.runes[i])) return new Prefilter(Prefilter.Type.NONE);
|
|
3536
|
+
str += String.fromCodePoint(re.runes[i]);
|
|
3537
|
+
}
|
|
3538
|
+
const pf = new Prefilter(Prefilter.Type.EXACT);
|
|
3539
|
+
pf.str = str;
|
|
3540
|
+
pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
|
|
3541
|
+
return pf;
|
|
3542
|
+
}
|
|
3543
|
+
static enter(re) {
|
|
3366
3544
|
switch (re.op) {
|
|
3367
|
-
case Regexp.Op.PLB:
|
|
3368
|
-
case Regexp.Op.NLB:
|
|
3369
|
-
case Regexp.Op.NO_MATCH:
|
|
3370
|
-
case Regexp.Op.EMPTY_MATCH:
|
|
3371
|
-
case Regexp.Op.BEGIN_LINE:
|
|
3372
|
-
case Regexp.Op.END_LINE:
|
|
3373
|
-
case Regexp.Op.BEGIN_TEXT:
|
|
3374
|
-
case Regexp.Op.END_TEXT:
|
|
3375
|
-
case Regexp.Op.WORD_BOUNDARY:
|
|
3376
|
-
case Regexp.Op.NO_WORD_BOUNDARY:
|
|
3377
|
-
case Regexp.Op.CHAR_CLASS:
|
|
3378
|
-
case Regexp.Op.ANY_CHAR_NOT_NL:
|
|
3379
|
-
case Regexp.Op.ANY_CHAR: return new Prefilter(Prefilter.Type.NONE);
|
|
3380
|
-
case Regexp.Op.LITERAL: {
|
|
3381
|
-
if (re.runes.length === 0 || (re.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
|
|
3382
|
-
const pf = new Prefilter(Prefilter.Type.EXACT);
|
|
3383
|
-
let str = "";
|
|
3384
|
-
for (let i = 0; i < re.runes.length; i++) str += String.fromCodePoint(re.runes[i]);
|
|
3385
|
-
pf.str = str;
|
|
3386
|
-
pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
|
|
3387
|
-
return pf;
|
|
3388
|
-
}
|
|
3389
3545
|
case Regexp.Op.CAPTURE:
|
|
3390
|
-
case Regexp.Op.PLUS: return
|
|
3546
|
+
case Regexp.Op.PLUS: return { sub: null };
|
|
3391
3547
|
case Regexp.Op.REPEAT:
|
|
3392
|
-
if (re.min >= 1) return
|
|
3393
|
-
return new Prefilter(Prefilter.Type.NONE);
|
|
3394
|
-
case Regexp.Op.CONCAT: {
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3548
|
+
if (re.min >= 1) return { sub: null };
|
|
3549
|
+
return { result: new Prefilter(Prefilter.Type.NONE) };
|
|
3550
|
+
case Regexp.Op.CONCAT: return {
|
|
3551
|
+
pf: new Prefilter(Prefilter.Type.AND),
|
|
3552
|
+
subs: []
|
|
3553
|
+
};
|
|
3554
|
+
case Regexp.Op.ALTERNATE: return {
|
|
3555
|
+
pf: new Prefilter(Prefilter.Type.OR),
|
|
3556
|
+
subs: []
|
|
3557
|
+
};
|
|
3558
|
+
default: return { result: new Prefilter(Prefilter.Type.NONE) };
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
static child(re, state, s) {
|
|
3562
|
+
if (state.subs === void 0) {
|
|
3563
|
+
state.sub = s;
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3566
|
+
if (state.pf.type === Prefilter.Type.AND) {
|
|
3567
|
+
if (s.type === Prefilter.Type.NONE) return;
|
|
3568
|
+
if (s.type === Prefilter.Type.AND) {
|
|
3569
|
+
for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
|
|
3570
|
+
return;
|
|
3398
3571
|
}
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3572
|
+
state.subs.push(s);
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
if (s.type === Prefilter.Type.NONE) {
|
|
3576
|
+
state.result = new Prefilter(Prefilter.Type.NONE);
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
if (s.type === Prefilter.Type.OR) {
|
|
3580
|
+
for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
state.subs.push(s);
|
|
3584
|
+
}
|
|
3585
|
+
static leave(re, state) {
|
|
3586
|
+
if (state.subs === void 0) return state.sub;
|
|
3587
|
+
const pf = state.pf;
|
|
3588
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3589
|
+
const subs = [];
|
|
3590
|
+
for (const sub of state.subs) {
|
|
3591
|
+
if (sub.type === Prefilter.Type.EXACT) {
|
|
3592
|
+
if (seen.has(sub.str)) continue;
|
|
3593
|
+
seen.add(sub.str);
|
|
3403
3594
|
}
|
|
3404
|
-
|
|
3595
|
+
subs.push(sub);
|
|
3405
3596
|
}
|
|
3406
|
-
}
|
|
3407
|
-
static simplify(pf) {
|
|
3408
|
-
if (pf.type === Prefilter.Type.EXACT || pf.type === Prefilter.Type.NONE) return pf;
|
|
3409
3597
|
if (pf.type === Prefilter.Type.AND) {
|
|
3410
|
-
const
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
if (
|
|
3414
|
-
|
|
3598
|
+
const kept = [];
|
|
3599
|
+
let cost = 0;
|
|
3600
|
+
for (const sub of subs) {
|
|
3601
|
+
if (cost + sub.cost > Prefilter.MAX_SCANS) continue;
|
|
3602
|
+
kept.push(sub);
|
|
3603
|
+
cost += sub.cost;
|
|
3415
3604
|
}
|
|
3416
|
-
if (
|
|
3417
|
-
if (
|
|
3418
|
-
pf.subs =
|
|
3605
|
+
if (kept.length === 0) return new Prefilter(Prefilter.Type.NONE);
|
|
3606
|
+
if (kept.length === 1) return kept[0];
|
|
3607
|
+
pf.subs = kept;
|
|
3608
|
+
pf.cost = cost;
|
|
3419
3609
|
return pf;
|
|
3420
3610
|
}
|
|
3421
|
-
if (
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
uniqueSubs.push(sub);
|
|
3437
|
-
}
|
|
3438
|
-
} else uniqueSubs.push(sub);
|
|
3439
|
-
pf.subs = uniqueSubs;
|
|
3440
|
-
let allExact = true;
|
|
3441
|
-
for (const sub of uniqueSubs) if (sub.type !== Prefilter.Type.EXACT) {
|
|
3442
|
-
allExact = false;
|
|
3443
|
-
break;
|
|
3444
|
-
}
|
|
3445
|
-
if (allExact && uniqueSubs.length > 1) {
|
|
3446
|
-
pf.ac16 = new AhoCorasick(uniqueSubs.map((s) => {
|
|
3447
|
-
const arr = [];
|
|
3448
|
-
for (let i = 0; i < s.str.length; i++) arr.push(s.str.charCodeAt(i));
|
|
3449
|
-
return arr;
|
|
3450
|
-
}));
|
|
3451
|
-
pf.ac8 = new AhoCorasick(uniqueSubs.map((s) => s.bytes));
|
|
3452
|
-
}
|
|
3611
|
+
if (subs.length === 0) return new Prefilter(Prefilter.Type.NONE);
|
|
3612
|
+
if (subs.length === 1) return subs[0];
|
|
3613
|
+
pf.subs = subs;
|
|
3614
|
+
let allExact = true;
|
|
3615
|
+
let cost = 0;
|
|
3616
|
+
let units = 0;
|
|
3617
|
+
for (const sub of subs) {
|
|
3618
|
+
if (sub.type !== Prefilter.Type.EXACT) allExact = false;
|
|
3619
|
+
else units += sub.bytes.length;
|
|
3620
|
+
cost += sub.cost;
|
|
3621
|
+
}
|
|
3622
|
+
if (allExact) {
|
|
3623
|
+
if (units > Prefilter.MAX_AC_UNITS) return new Prefilter(Prefilter.Type.NONE);
|
|
3624
|
+
pf.allExact = true;
|
|
3625
|
+
pf.cost = 1;
|
|
3453
3626
|
return pf;
|
|
3454
3627
|
}
|
|
3628
|
+
if (cost > Prefilter.MAX_SCANS) return new Prefilter(Prefilter.Type.NONE);
|
|
3629
|
+
pf.cost = cost;
|
|
3455
3630
|
return pf;
|
|
3456
3631
|
}
|
|
3457
3632
|
};
|
|
@@ -3487,6 +3662,7 @@
|
|
|
3487
3662
|
this.numCap = 2;
|
|
3488
3663
|
this.lbStarts = [];
|
|
3489
3664
|
this.numLb = 0;
|
|
3665
|
+
this.lbInst = null;
|
|
3490
3666
|
}
|
|
3491
3667
|
getInst(pc) {
|
|
3492
3668
|
return this.inst[pc];
|
|
@@ -3497,6 +3673,26 @@
|
|
|
3497
3673
|
addInst(op) {
|
|
3498
3674
|
this.inst.push(new Inst(op));
|
|
3499
3675
|
}
|
|
3676
|
+
markLookbehindInsts() {
|
|
3677
|
+
const lbInst = new Uint8Array(this.inst.length);
|
|
3678
|
+
const pending = this.lbStarts.slice();
|
|
3679
|
+
while (pending.length > 0) {
|
|
3680
|
+
const pc = pending.pop();
|
|
3681
|
+
if (pc === 0 || lbInst[pc] === 1) continue;
|
|
3682
|
+
lbInst[pc] = 1;
|
|
3683
|
+
const i = this.inst[pc];
|
|
3684
|
+
switch (i.op) {
|
|
3685
|
+
case Inst.ALT:
|
|
3686
|
+
case Inst.ALT_MATCH:
|
|
3687
|
+
pending.push(i.out, i.arg);
|
|
3688
|
+
break;
|
|
3689
|
+
case Inst.MATCH:
|
|
3690
|
+
case Inst.FAIL: break;
|
|
3691
|
+
default: pending.push(i.out);
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
this.lbInst = lbInst;
|
|
3695
|
+
}
|
|
3500
3696
|
skipNop(pc) {
|
|
3501
3697
|
let i = this.inst[pc];
|
|
3502
3698
|
while (i.op === Inst.NOP || i.op === Inst.CAPTURE) {
|
|
@@ -3509,7 +3705,7 @@
|
|
|
3509
3705
|
let prefix = "";
|
|
3510
3706
|
let i = this.skipNop(this.start);
|
|
3511
3707
|
if (!Inst.isRuneOp(i.op) || i.runes.length !== 1) return [i.op === Inst.MATCH, prefix];
|
|
3512
|
-
while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0) {
|
|
3708
|
+
while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0 && !Unicode.isUnsearchable(i.runes[0])) {
|
|
3513
3709
|
prefix += String.fromCodePoint(i.runes[0]);
|
|
3514
3710
|
i = this.skipNop(i.out);
|
|
3515
3711
|
}
|
|
@@ -3573,6 +3769,13 @@
|
|
|
3573
3769
|
};
|
|
3574
3770
|
//#endregion
|
|
3575
3771
|
//#region src/Compiler.js
|
|
3772
|
+
const ANY_RUNE_NOT_NL = new Int32Array([
|
|
3773
|
+
0,
|
|
3774
|
+
Codepoint.CODES.get("\n") - 1,
|
|
3775
|
+
Codepoint.CODES.get("\n") + 1,
|
|
3776
|
+
Unicode.MAX_RUNE
|
|
3777
|
+
]);
|
|
3778
|
+
const ANY_RUNE = new Int32Array([0, Unicode.MAX_RUNE]);
|
|
3576
3779
|
/**
|
|
3577
3780
|
* A fragment of a compiled regular expression program.
|
|
3578
3781
|
*
|
|
@@ -3592,28 +3795,19 @@
|
|
|
3592
3795
|
* The only entry point is {@link #compileRegexp}.
|
|
3593
3796
|
*/
|
|
3594
3797
|
var Compiler = class Compiler {
|
|
3595
|
-
static ANY_RUNE_NOT_NL() {
|
|
3596
|
-
return [
|
|
3597
|
-
0,
|
|
3598
|
-
Codepoint.CODES.get("\n") - 1,
|
|
3599
|
-
Codepoint.CODES.get("\n") + 1,
|
|
3600
|
-
Unicode.MAX_RUNE
|
|
3601
|
-
];
|
|
3602
|
-
}
|
|
3603
|
-
static ANY_RUNE() {
|
|
3604
|
-
return [0, Unicode.MAX_RUNE];
|
|
3605
|
-
}
|
|
3606
3798
|
static compileRegexp(re) {
|
|
3607
3799
|
const c = new Compiler();
|
|
3608
3800
|
const f = c.compile(re);
|
|
3609
3801
|
c.prog.patch(f.out, c.newInst(Inst.MATCH).i);
|
|
3610
3802
|
c.prog.start = f.i;
|
|
3803
|
+
c.prog.markLookbehindInsts();
|
|
3611
3804
|
return c.prog;
|
|
3612
3805
|
}
|
|
3613
3806
|
static compileSet(regexps) {
|
|
3614
3807
|
const c = new Compiler();
|
|
3615
3808
|
if (regexps.length === 0) {
|
|
3616
3809
|
c.prog.start = c.newInst(Inst.FAIL).i;
|
|
3810
|
+
c.prog.markLookbehindInsts();
|
|
3617
3811
|
return c.prog;
|
|
3618
3812
|
}
|
|
3619
3813
|
let starts = [];
|
|
@@ -3633,11 +3827,19 @@
|
|
|
3633
3827
|
start = f.i;
|
|
3634
3828
|
}
|
|
3635
3829
|
c.prog.start = start;
|
|
3830
|
+
c.prog.markLookbehindInsts();
|
|
3636
3831
|
return c.prog;
|
|
3637
3832
|
}
|
|
3638
3833
|
constructor() {
|
|
3639
3834
|
this.prog = new Prog();
|
|
3640
3835
|
this.newInst(Inst.FAIL);
|
|
3836
|
+
this.runeCache = /* @__PURE__ */ new Map();
|
|
3837
|
+
this.walker = {
|
|
3838
|
+
leaf: (re) => this.leaf(re),
|
|
3839
|
+
enter: (re) => this.enter(re),
|
|
3840
|
+
child: (re, state, result) => this.child(re, state, result),
|
|
3841
|
+
leave: (re, state) => this.leave(re, state)
|
|
3842
|
+
};
|
|
3641
3843
|
}
|
|
3642
3844
|
newInst(op) {
|
|
3643
3845
|
this.prog.addInst(op);
|
|
@@ -3730,7 +3932,7 @@
|
|
|
3730
3932
|
lookBehind(a, lb) {
|
|
3731
3933
|
const id = this.newInst(Inst.LB_WRITE);
|
|
3732
3934
|
this.prog.getInst(id.i).arg = lb;
|
|
3733
|
-
const any = this.rune(
|
|
3935
|
+
const any = this.rune(ANY_RUNE, 0);
|
|
3734
3936
|
const dotStar = this.star(any, true);
|
|
3735
3937
|
const lbAutomaton = this.cat(dotStar, a);
|
|
3736
3938
|
this.prog.patch(lbAutomaton.out, id.i);
|
|
@@ -3742,56 +3944,74 @@
|
|
|
3742
3944
|
return checkId;
|
|
3743
3945
|
}
|
|
3744
3946
|
compile(re) {
|
|
3947
|
+
return RegexpWalker.walk(re, this.walker);
|
|
3948
|
+
}
|
|
3949
|
+
leaf(re) {
|
|
3745
3950
|
switch (re.op) {
|
|
3746
3951
|
case Regexp.Op.NO_MATCH: return this.fail();
|
|
3747
3952
|
case Regexp.Op.EMPTY_MATCH: return this.nop();
|
|
3748
|
-
case Regexp.Op.LITERAL:
|
|
3749
|
-
|
|
3953
|
+
case Regexp.Op.LITERAL: {
|
|
3954
|
+
if (re.runes.length === 0) return this.nop();
|
|
3750
3955
|
let f = null;
|
|
3751
3956
|
for (let r of re.runes) {
|
|
3752
|
-
|
|
3957
|
+
let singleRune = this.runeCache.get(r);
|
|
3958
|
+
if (singleRune === void 0) {
|
|
3959
|
+
singleRune = new Int32Array([r]);
|
|
3960
|
+
this.runeCache.set(r, singleRune);
|
|
3961
|
+
}
|
|
3962
|
+
const f1 = this.rune(singleRune, re.flags);
|
|
3753
3963
|
f = f === null ? f1 : this.cat(f, f1);
|
|
3754
3964
|
}
|
|
3755
3965
|
return f;
|
|
3756
3966
|
}
|
|
3757
3967
|
case Regexp.Op.CHAR_CLASS: return this.rune(re.runes, re.flags);
|
|
3758
|
-
case Regexp.Op.ANY_CHAR_NOT_NL: return this.rune(
|
|
3759
|
-
case Regexp.Op.ANY_CHAR: return this.rune(
|
|
3968
|
+
case Regexp.Op.ANY_CHAR_NOT_NL: return this.rune(ANY_RUNE_NOT_NL, 0);
|
|
3969
|
+
case Regexp.Op.ANY_CHAR: return this.rune(ANY_RUNE, 0);
|
|
3760
3970
|
case Regexp.Op.BEGIN_LINE: return this.empty(Utils.EMPTY_BEGIN_LINE);
|
|
3761
3971
|
case Regexp.Op.END_LINE: return this.empty(Utils.EMPTY_END_LINE);
|
|
3762
3972
|
case Regexp.Op.BEGIN_TEXT: return this.empty(Utils.EMPTY_BEGIN_TEXT);
|
|
3763
3973
|
case Regexp.Op.END_TEXT: return this.empty(Utils.EMPTY_END_TEXT);
|
|
3764
3974
|
case Regexp.Op.WORD_BOUNDARY: return this.empty(Utils.EMPTY_WORD_BOUNDARY);
|
|
3765
3975
|
case Regexp.Op.NO_WORD_BOUNDARY: return this.empty(Utils.EMPTY_NO_WORD_BOUNDARY);
|
|
3976
|
+
case Regexp.Op.CONCAT:
|
|
3977
|
+
case Regexp.Op.ALTERNATE: return this.nop();
|
|
3978
|
+
default: throw new RE2JSCompileException("regexp: unhandled case in compile");
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
enter(re) {
|
|
3982
|
+
switch (re.op) {
|
|
3983
|
+
case Regexp.Op.PLB:
|
|
3984
|
+
case Regexp.Op.NLB:
|
|
3985
|
+
case Regexp.Op.STAR:
|
|
3986
|
+
case Regexp.Op.PLUS:
|
|
3987
|
+
case Regexp.Op.QUEST: return { sub: null };
|
|
3988
|
+
case Regexp.Op.CAPTURE: return {
|
|
3989
|
+
bra: this.cap(re.cap << 1),
|
|
3990
|
+
sub: null
|
|
3991
|
+
};
|
|
3992
|
+
case Regexp.Op.CONCAT:
|
|
3993
|
+
case Regexp.Op.ALTERNATE: return { f: null };
|
|
3994
|
+
default: throw new RE2JSCompileException("regexp: unhandled case in compile");
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
child(re, state, f1) {
|
|
3998
|
+
if (re.op === Regexp.Op.CONCAT) state.f = state.f === null ? f1 : this.cat(state.f, f1);
|
|
3999
|
+
else if (re.op === Regexp.Op.ALTERNATE) state.f = state.f === null ? f1 : this.alt(state.f, f1);
|
|
4000
|
+
else state.sub = f1;
|
|
4001
|
+
}
|
|
4002
|
+
leave(re, state) {
|
|
4003
|
+
switch (re.op) {
|
|
3766
4004
|
case Regexp.Op.PLB:
|
|
3767
|
-
case Regexp.Op.NLB: return this.lookBehind(
|
|
4005
|
+
case Regexp.Op.NLB: return this.lookBehind(state.sub, re.lb);
|
|
3768
4006
|
case Regexp.Op.CAPTURE: {
|
|
3769
|
-
const bra = this.cap(re.cap << 1);
|
|
3770
|
-
const sub = this.compile(re.subs[0]);
|
|
3771
4007
|
const ket = this.cap(re.cap << 1 | 1);
|
|
3772
|
-
return this.cat(this.cat(bra, sub), ket);
|
|
3773
|
-
}
|
|
3774
|
-
case Regexp.Op.STAR: return this.star(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
3775
|
-
case Regexp.Op.PLUS: return this.plus(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
3776
|
-
case Regexp.Op.QUEST: return this.quest(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
3777
|
-
case Regexp.Op.CONCAT: if (re.subs.length === 0) return this.nop();
|
|
3778
|
-
else {
|
|
3779
|
-
let f = null;
|
|
3780
|
-
for (let sub of re.subs) {
|
|
3781
|
-
const f1 = this.compile(sub);
|
|
3782
|
-
f = f === null ? f1 : this.cat(f, f1);
|
|
3783
|
-
}
|
|
3784
|
-
return f;
|
|
3785
|
-
}
|
|
3786
|
-
case Regexp.Op.ALTERNATE: if (re.subs.length === 0) return this.nop();
|
|
3787
|
-
else {
|
|
3788
|
-
let f = null;
|
|
3789
|
-
for (let sub of re.subs) {
|
|
3790
|
-
const f1 = this.compile(sub);
|
|
3791
|
-
f = f === null ? f1 : this.alt(f, f1);
|
|
3792
|
-
}
|
|
3793
|
-
return f;
|
|
4008
|
+
return this.cat(this.cat(state.bra, state.sub), ket);
|
|
3794
4009
|
}
|
|
4010
|
+
case Regexp.Op.STAR: return this.star(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
4011
|
+
case Regexp.Op.PLUS: return this.plus(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
4012
|
+
case Regexp.Op.QUEST: return this.quest(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
|
|
4013
|
+
case Regexp.Op.CONCAT:
|
|
4014
|
+
case Regexp.Op.ALTERNATE: return state.f;
|
|
3795
4015
|
default: throw new RE2JSCompileException("regexp: unhandled case in compile");
|
|
3796
4016
|
}
|
|
3797
4017
|
}
|
|
@@ -3801,111 +4021,149 @@
|
|
|
3801
4021
|
var Simplify = class Simplify {
|
|
3802
4022
|
static simplify(re) {
|
|
3803
4023
|
if (re === null) return null;
|
|
4024
|
+
return RegexpWalker.walk(re, Simplify.WALKER);
|
|
4025
|
+
}
|
|
4026
|
+
static WALKER = {
|
|
4027
|
+
leaf: (re) => Simplify.leaf(re),
|
|
4028
|
+
enter: (re) => Simplify.enter(re),
|
|
4029
|
+
child: (re, state, result, i) => Simplify.child(re, state, result, i),
|
|
4030
|
+
leave: (re, state) => Simplify.leave(re, state)
|
|
4031
|
+
};
|
|
4032
|
+
static leaf(re) {
|
|
4033
|
+
if (re.op === Regexp.Op.CHAR_CLASS) {
|
|
4034
|
+
if (re.runes === null) return re;
|
|
4035
|
+
if (re.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
|
|
4036
|
+
if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
|
|
4037
|
+
if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
|
|
4038
|
+
}
|
|
4039
|
+
return re;
|
|
4040
|
+
}
|
|
4041
|
+
static enter(re) {
|
|
4042
|
+
switch (re.op) {
|
|
4043
|
+
case Regexp.Op.PLB:
|
|
4044
|
+
case Regexp.Op.NLB:
|
|
4045
|
+
case Regexp.Op.CAPTURE:
|
|
4046
|
+
case Regexp.Op.STAR:
|
|
4047
|
+
case Regexp.Op.PLUS:
|
|
4048
|
+
case Regexp.Op.QUEST: return { sub: null };
|
|
4049
|
+
case Regexp.Op.CONCAT:
|
|
4050
|
+
case Regexp.Op.ALTERNATE: return {
|
|
4051
|
+
subs: [],
|
|
4052
|
+
changed: false
|
|
4053
|
+
};
|
|
4054
|
+
case Regexp.Op.REPEAT:
|
|
4055
|
+
if (re.min === 0 && re.max === 0) return { result: new Regexp(Regexp.Op.EMPTY_MATCH) };
|
|
4056
|
+
return { sub: null };
|
|
4057
|
+
default: return { result: re };
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
static child(re, state, nsub, i) {
|
|
4061
|
+
if (state.subs === void 0) {
|
|
4062
|
+
state.sub = nsub;
|
|
4063
|
+
return;
|
|
4064
|
+
}
|
|
4065
|
+
if (nsub !== re.subs[i]) state.changed = true;
|
|
4066
|
+
if (re.op === Regexp.Op.CONCAT) {
|
|
4067
|
+
if (nsub.op === Regexp.Op.NO_MATCH) {
|
|
4068
|
+
state.result = new Regexp(Regexp.Op.NO_MATCH);
|
|
4069
|
+
return;
|
|
4070
|
+
}
|
|
4071
|
+
if (nsub.op === Regexp.Op.EMPTY_MATCH) {
|
|
4072
|
+
state.changed = true;
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
if (nsub.op === Regexp.Op.CONCAT) {
|
|
4076
|
+
state.changed = true;
|
|
4077
|
+
for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
} else {
|
|
4081
|
+
if (nsub.op === Regexp.Op.NO_MATCH) {
|
|
4082
|
+
state.changed = true;
|
|
4083
|
+
return;
|
|
4084
|
+
}
|
|
4085
|
+
if (nsub.op === Regexp.Op.ALTERNATE) {
|
|
4086
|
+
state.changed = true;
|
|
4087
|
+
for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
|
|
4088
|
+
return;
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
state.subs.push(nsub);
|
|
4092
|
+
}
|
|
4093
|
+
static leave(re, state) {
|
|
3804
4094
|
switch (re.op) {
|
|
3805
4095
|
case Regexp.Op.PLB:
|
|
3806
4096
|
case Regexp.Op.NLB:
|
|
3807
4097
|
case Regexp.Op.CAPTURE: {
|
|
3808
|
-
const sub =
|
|
4098
|
+
const sub = state.sub;
|
|
3809
4099
|
if (sub !== re.subs[0]) {
|
|
3810
4100
|
const nre = Regexp.fromRegexp(re);
|
|
3811
|
-
nre.runes =
|
|
4101
|
+
nre.runes = /* @__PURE__ */ new Int32Array(0);
|
|
3812
4102
|
nre.subs = [sub];
|
|
3813
4103
|
return nre;
|
|
3814
4104
|
}
|
|
3815
4105
|
return re;
|
|
3816
4106
|
}
|
|
3817
4107
|
case Regexp.Op.CONCAT:
|
|
3818
|
-
case Regexp.Op.ALTERNATE:
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
for (let i = 0; i < re.subs.length; i++) {
|
|
3822
|
-
const sub = re.subs[i];
|
|
3823
|
-
const nsub = Simplify.simplify(sub);
|
|
3824
|
-
if (nsub !== sub) changed = true;
|
|
3825
|
-
if (re.op === Regexp.Op.CONCAT) {
|
|
3826
|
-
if (nsub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
|
|
3827
|
-
if (nsub.op === Regexp.Op.EMPTY_MATCH) {
|
|
3828
|
-
changed = true;
|
|
3829
|
-
continue;
|
|
3830
|
-
}
|
|
3831
|
-
if (nsub.op === Regexp.Op.CONCAT) {
|
|
3832
|
-
changed = true;
|
|
3833
|
-
for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
|
|
3834
|
-
continue;
|
|
3835
|
-
}
|
|
3836
|
-
} else if (re.op === Regexp.Op.ALTERNATE) {
|
|
3837
|
-
if (nsub.op === Regexp.Op.NO_MATCH) {
|
|
3838
|
-
changed = true;
|
|
3839
|
-
continue;
|
|
3840
|
-
}
|
|
3841
|
-
if (nsub.op === Regexp.Op.ALTERNATE) {
|
|
3842
|
-
changed = true;
|
|
3843
|
-
for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
|
|
3844
|
-
continue;
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
newSubs.push(nsub);
|
|
3848
|
-
}
|
|
3849
|
-
if (changed) {
|
|
4108
|
+
case Regexp.Op.ALTERNATE:
|
|
4109
|
+
if (state.changed) {
|
|
4110
|
+
const newSubs = state.subs;
|
|
3850
4111
|
if (newSubs.length === 0) return new Regexp(re.op === Regexp.Op.CONCAT ? Regexp.Op.EMPTY_MATCH : Regexp.Op.NO_MATCH);
|
|
3851
4112
|
if (newSubs.length === 1) return newSubs[0];
|
|
3852
4113
|
const nre = Regexp.fromRegexp(re);
|
|
3853
|
-
nre.runes =
|
|
4114
|
+
nre.runes = /* @__PURE__ */ new Int32Array(0);
|
|
3854
4115
|
nre.subs = newSubs;
|
|
3855
4116
|
return nre;
|
|
3856
4117
|
}
|
|
3857
4118
|
return re;
|
|
3858
|
-
}
|
|
3859
|
-
case Regexp.Op.CHAR_CLASS:
|
|
3860
|
-
if (re.runes === null) return re;
|
|
3861
|
-
if (re.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
|
|
3862
|
-
if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
|
|
3863
|
-
if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
|
|
3864
|
-
return re;
|
|
3865
4119
|
case Regexp.Op.STAR:
|
|
3866
4120
|
case Regexp.Op.PLUS:
|
|
3867
|
-
case Regexp.Op.QUEST:
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
return new Regexp(Regexp.Op.NO_MATCH);
|
|
4121
|
+
case Regexp.Op.QUEST: return Simplify.simplify1(re.op, re.flags, state.sub, re);
|
|
4122
|
+
case Regexp.Op.REPEAT: return Simplify.simplifyRepeat(re, state.sub);
|
|
4123
|
+
default: return re;
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
static simplifyRepeat(re, sub) {
|
|
4127
|
+
if (re.max === -1) {
|
|
4128
|
+
if (re.min === 0) return Simplify.simplify1(Regexp.Op.STAR, re.flags, sub, null);
|
|
4129
|
+
if (re.min === 1) return Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null);
|
|
4130
|
+
const subs = [];
|
|
4131
|
+
for (let i = 0; i < re.min - 1; i++) subs.push(sub);
|
|
4132
|
+
subs.push(Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null));
|
|
4133
|
+
return Simplify.concat(subs);
|
|
4134
|
+
}
|
|
4135
|
+
if (re.min === 1 && re.max === 1) return sub;
|
|
4136
|
+
let prefixSubs = null;
|
|
4137
|
+
if (re.min > 0) {
|
|
4138
|
+
prefixSubs = [];
|
|
4139
|
+
for (let i = 0; i < re.min; i++) prefixSubs.push(sub);
|
|
4140
|
+
}
|
|
4141
|
+
if (re.max > re.min) {
|
|
4142
|
+
let suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, sub, null);
|
|
4143
|
+
for (let i = re.min + 1; i < re.max; i++) suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, Simplify.concat([sub, suffix]), null);
|
|
4144
|
+
if (prefixSubs === null) return suffix;
|
|
4145
|
+
prefixSubs.push(suffix);
|
|
4146
|
+
}
|
|
4147
|
+
if (prefixSubs !== null) return Simplify.concat(prefixSubs);
|
|
4148
|
+
return new Regexp(Regexp.Op.NO_MATCH);
|
|
4149
|
+
}
|
|
4150
|
+
static concat(subs) {
|
|
4151
|
+
const newSubs = [];
|
|
4152
|
+
for (let i = 0; i < subs.length; i++) {
|
|
4153
|
+
const sub = subs[i];
|
|
4154
|
+
if (sub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
|
|
4155
|
+
if (sub.op === Regexp.Op.EMPTY_MATCH) continue;
|
|
4156
|
+
if (sub.op === Regexp.Op.CONCAT) {
|
|
4157
|
+
for (let j = 0; j < sub.subs.length; j++) newSubs.push(sub.subs[j]);
|
|
4158
|
+
continue;
|
|
3906
4159
|
}
|
|
4160
|
+
newSubs.push(sub);
|
|
3907
4161
|
}
|
|
3908
|
-
return
|
|
4162
|
+
if (newSubs.length === 0) return new Regexp(Regexp.Op.EMPTY_MATCH);
|
|
4163
|
+
if (newSubs.length === 1) return newSubs[0];
|
|
4164
|
+
const nre = new Regexp(Regexp.Op.CONCAT);
|
|
4165
|
+
nre.subs = newSubs;
|
|
4166
|
+
return nre;
|
|
3909
4167
|
}
|
|
3910
4168
|
static simplify1(op, flags, sub, re) {
|
|
3911
4169
|
if (sub.op === Regexp.Op.EMPTY_MATCH) return sub;
|
|
@@ -4073,46 +4331,35 @@
|
|
|
4073
4331
|
result += "]";
|
|
4074
4332
|
return result;
|
|
4075
4333
|
}
|
|
4076
|
-
static
|
|
4077
|
-
const
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
const
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
let j = right;
|
|
4086
|
-
while (i <= j) {
|
|
4087
|
-
while (i < right && CharClass.cmp(array, i, pivotFrom, pivotTo) < 0) i += 2;
|
|
4088
|
-
while (j > left && CharClass.cmp(array, j, pivotFrom, pivotTo) > 0) j -= 2;
|
|
4089
|
-
if (i <= j) {
|
|
4090
|
-
if (i !== j) {
|
|
4091
|
-
let temp = array[i];
|
|
4092
|
-
array[i] = array[j];
|
|
4093
|
-
array[j] = temp;
|
|
4094
|
-
temp = array[i + 1];
|
|
4095
|
-
array[i + 1] = array[j + 1];
|
|
4096
|
-
array[j + 1] = temp;
|
|
4097
|
-
}
|
|
4098
|
-
i += 2;
|
|
4099
|
-
j -= 2;
|
|
4100
|
-
}
|
|
4334
|
+
static sortRanges(array, len) {
|
|
4335
|
+
const n = len >> 1;
|
|
4336
|
+
const order = new Array(n);
|
|
4337
|
+
for (let i = 0; i < n; i++) order[i] = i;
|
|
4338
|
+
order.sort((a, b) => array[2 * a] - array[2 * b] || array[2 * b + 1] - array[2 * a + 1]);
|
|
4339
|
+
const sorted = array.slice(0, len);
|
|
4340
|
+
for (let i = 0; i < n; i++) {
|
|
4341
|
+
array[2 * i] = sorted[2 * order[i]];
|
|
4342
|
+
array[2 * i + 1] = sorted[2 * order[i] + 1];
|
|
4101
4343
|
}
|
|
4102
|
-
if (left < j) CharClass.qsortIntPair(array, left, j);
|
|
4103
|
-
if (i < right) CharClass.qsortIntPair(array, i, right);
|
|
4104
4344
|
}
|
|
4105
4345
|
constructor(r = Utils.emptyInts()) {
|
|
4106
4346
|
this.r = r;
|
|
4107
4347
|
this.len = r.length;
|
|
4108
4348
|
}
|
|
4109
4349
|
toArray() {
|
|
4110
|
-
if (this.len === this.r.length
|
|
4111
|
-
|
|
4350
|
+
if (this.r instanceof Int32Array) return this.len === this.r.length ? this.r : this.r.subarray(0, this.len);
|
|
4351
|
+
return new Int32Array(this.len === this.r.length ? this.r : this.r.slice(0, this.len));
|
|
4352
|
+
}
|
|
4353
|
+
toGrowableArray() {
|
|
4354
|
+
if (Array.isArray(this.r)) {
|
|
4355
|
+
this.r.length = this.len;
|
|
4356
|
+
return this.r;
|
|
4357
|
+
}
|
|
4358
|
+
return Array.from(this.r.subarray(0, this.len));
|
|
4112
4359
|
}
|
|
4113
4360
|
cleanClass() {
|
|
4114
4361
|
if (this.len < 4) return this;
|
|
4115
|
-
CharClass.
|
|
4362
|
+
CharClass.sortRanges(this.r, this.len);
|
|
4116
4363
|
let w = 2;
|
|
4117
4364
|
for (let i = 2; i < this.len; i += 2) {
|
|
4118
4365
|
const lo = this.r[i];
|
|
@@ -4316,7 +4563,7 @@
|
|
|
4316
4563
|
static ERR_LARGE = "expression too large";
|
|
4317
4564
|
static ERR_INVALID_CAPTURE_IN_LOOKBEHIND = "invalid capture in lookbehind";
|
|
4318
4565
|
static MAX_HEIGHT = 1e3;
|
|
4319
|
-
static MAX_SIZE =
|
|
4566
|
+
static MAX_SIZE = 1398101;
|
|
4320
4567
|
static MAX_RUNES = 33554432;
|
|
4321
4568
|
static ANY_TABLE = new UnicodeRangeTable(new Uint32Array([
|
|
4322
4569
|
0,
|
|
@@ -4458,15 +4705,17 @@
|
|
|
4458
4705
|
case Regexp.Op.ANY_CHAR_NOT_NL:
|
|
4459
4706
|
if (Parser.matchRune(src, Codepoint.CODES.get("\n"))) dst.op = Regexp.Op.ANY_CHAR;
|
|
4460
4707
|
break;
|
|
4461
|
-
case Regexp.Op.CHAR_CLASS:
|
|
4462
|
-
|
|
4463
|
-
|
|
4708
|
+
case Regexp.Op.CHAR_CLASS: {
|
|
4709
|
+
const cc = new CharClass(Array.isArray(dst.runes) ? dst.runes : Array.from(dst.runes));
|
|
4710
|
+
if (src.op === Regexp.Op.LITERAL) cc.appendLiteral(src.runes[0], src.flags);
|
|
4711
|
+
else cc.appendClass(src.runes);
|
|
4712
|
+
dst.runes = cc.toGrowableArray();
|
|
4464
4713
|
break;
|
|
4714
|
+
}
|
|
4465
4715
|
case Regexp.Op.LITERAL:
|
|
4466
4716
|
if (src.runes[0] === dst.runes[0] && src.flags === dst.flags) break;
|
|
4467
4717
|
dst.op = Regexp.Op.CHAR_CLASS;
|
|
4468
|
-
dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).
|
|
4469
|
-
break;
|
|
4718
|
+
dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toGrowableArray();
|
|
4470
4719
|
}
|
|
4471
4720
|
}
|
|
4472
4721
|
static parseEscape(t) {
|
|
@@ -4523,9 +4772,7 @@
|
|
|
4523
4772
|
case Codepoint.CODES.get("r"): return Codepoint.CODES.get("\r");
|
|
4524
4773
|
case Codepoint.CODES.get("t"): return Codepoint.CODES.get(" ");
|
|
4525
4774
|
case Codepoint.CODES.get("v"): return Codepoint.CODES.get("\v");
|
|
4526
|
-
default:
|
|
4527
|
-
if (c <= Unicode.MAX_ASCII && !Utils.isalnum(c)) return c;
|
|
4528
|
-
break;
|
|
4775
|
+
default: if (c <= Unicode.MAX_ASCII && !Utils.isalnum(c)) return c;
|
|
4529
4776
|
}
|
|
4530
4777
|
throw new RE2JSSyntaxException(Parser.ERR_INVALID_ESCAPE, t.from(startPos));
|
|
4531
4778
|
}
|
|
@@ -4534,10 +4781,6 @@
|
|
|
4534
4781
|
if (t.lookingAt("\\")) return Parser.parseEscape(t);
|
|
4535
4782
|
return t.pop();
|
|
4536
4783
|
}
|
|
4537
|
-
static concatRunes(x, y) {
|
|
4538
|
-
for (let i = 0; i < y.length; i++) x.push(y[i]);
|
|
4539
|
-
return x;
|
|
4540
|
-
}
|
|
4541
4784
|
static hasCapture(re) {
|
|
4542
4785
|
if (re === null) return false;
|
|
4543
4786
|
if (re.op === Regexp.Op.CAPTURE) return true;
|
|
@@ -4668,9 +4911,7 @@
|
|
|
4668
4911
|
const n = this.stack.length;
|
|
4669
4912
|
let i = n;
|
|
4670
4913
|
while (i > 0 && !Regexp.isPseudoOp(this.stack[i - 1].op)) i--;
|
|
4671
|
-
|
|
4672
|
-
this.stack = this.stack.slice(0, i);
|
|
4673
|
-
return r;
|
|
4914
|
+
return this.stack.splice(i, n - i);
|
|
4674
4915
|
}
|
|
4675
4916
|
push(re) {
|
|
4676
4917
|
this.numRunes += re.runes.length;
|
|
@@ -4695,7 +4936,8 @@
|
|
|
4695
4936
|
const re1 = this.stack[n - 1];
|
|
4696
4937
|
const re2 = this.stack[n - 2];
|
|
4697
4938
|
if (re1.op !== Regexp.Op.LITERAL || re2.op !== Regexp.Op.LITERAL || (re1.flags & RE2Flags.FOLD_CASE) !== (re2.flags & RE2Flags.FOLD_CASE)) return false;
|
|
4698
|
-
re2.runes =
|
|
4939
|
+
if (!Array.isArray(re2.runes)) re2.runes = Array.from(re2.runes);
|
|
4940
|
+
for (let i = 0; i < re1.runes.length; i++) re2.runes.push(re1.runes[i]);
|
|
4699
4941
|
if (r >= 0) {
|
|
4700
4942
|
re1.runes = [r];
|
|
4701
4943
|
re1.flags = flags;
|
|
@@ -4767,12 +5009,12 @@
|
|
|
4767
5009
|
}
|
|
4768
5010
|
cleanAlt(re) {
|
|
4769
5011
|
if (re.op === Regexp.Op.CHAR_CLASS) {
|
|
4770
|
-
re.runes = new CharClass(re.runes).cleanClass().toArray();
|
|
5012
|
+
re.runes = new CharClass(Array.from(re.runes)).cleanClass().toArray();
|
|
4771
5013
|
if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) {
|
|
4772
|
-
re.runes =
|
|
5014
|
+
re.runes = /* @__PURE__ */ new Int32Array(0);
|
|
4773
5015
|
re.op = Regexp.Op.ANY_CHAR;
|
|
4774
5016
|
} else if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) {
|
|
4775
|
-
re.runes =
|
|
5017
|
+
re.runes = /* @__PURE__ */ new Int32Array(0);
|
|
4776
5018
|
re.op = Regexp.Op.ANY_CHAR_NOT_NL;
|
|
4777
5019
|
}
|
|
4778
5020
|
}
|
|
@@ -4932,9 +5174,7 @@
|
|
|
4932
5174
|
this.reuse(old);
|
|
4933
5175
|
break;
|
|
4934
5176
|
}
|
|
4935
|
-
default:
|
|
4936
|
-
re.subs = re.subs.slice(1, re.subs.length);
|
|
4937
|
-
break;
|
|
5177
|
+
default: re.subs = re.subs.slice(1, re.subs.length);
|
|
4938
5178
|
}
|
|
4939
5179
|
}
|
|
4940
5180
|
return re;
|
|
@@ -5033,9 +5273,7 @@
|
|
|
5033
5273
|
case Codepoint.CODES.get("+"):
|
|
5034
5274
|
op = Regexp.Op.PLUS;
|
|
5035
5275
|
break;
|
|
5036
|
-
case Codepoint.CODES.get("?"):
|
|
5037
|
-
op = Regexp.Op.QUEST;
|
|
5038
|
-
break;
|
|
5276
|
+
case Codepoint.CODES.get("?"): op = Regexp.Op.QUEST;
|
|
5039
5277
|
}
|
|
5040
5278
|
this.repeat(op, min, max, repeatPos, t, lastRepeatPos);
|
|
5041
5279
|
break;
|
|
@@ -5086,9 +5324,7 @@
|
|
|
5086
5324
|
case Codepoint.CODES.get("z"):
|
|
5087
5325
|
this.op(Regexp.Op.END_TEXT);
|
|
5088
5326
|
break bigswitch;
|
|
5089
|
-
default:
|
|
5090
|
-
t.rewindTo(savedPos);
|
|
5091
|
-
break;
|
|
5327
|
+
default: t.rewindTo(savedPos);
|
|
5092
5328
|
}
|
|
5093
5329
|
else t.rewindTo(savedPos);
|
|
5094
5330
|
const re = this.newRegexp(Regexp.Op.CHAR_CLASS);
|
|
@@ -5112,9 +5348,7 @@
|
|
|
5112
5348
|
this.literal(Parser.parseEscape(t));
|
|
5113
5349
|
break;
|
|
5114
5350
|
}
|
|
5115
|
-
default:
|
|
5116
|
-
this.literal(t.pop());
|
|
5117
|
-
break;
|
|
5351
|
+
default: this.literal(t.pop());
|
|
5118
5352
|
}
|
|
5119
5353
|
lastRepeatPos = repeatPos;
|
|
5120
5354
|
}
|
|
@@ -5312,7 +5546,7 @@
|
|
|
5312
5546
|
if ((this.flags & RE2Flags.FOLD_CASE) === 0 || fold === null) cc.appendTableWithSign(tab, sign);
|
|
5313
5547
|
else {
|
|
5314
5548
|
const tmp = new CharClass().appendTable(tab).appendTable(fold).cleanClass().toArray();
|
|
5315
|
-
cc.appendClassWithSign(tmp, sign);
|
|
5549
|
+
cc.appendClassWithSign(Array.from(tmp), sign);
|
|
5316
5550
|
}
|
|
5317
5551
|
return true;
|
|
5318
5552
|
}
|
|
@@ -5368,24 +5602,6 @@
|
|
|
5368
5602
|
};
|
|
5369
5603
|
//#endregion
|
|
5370
5604
|
//#region src/RE2.js
|
|
5371
|
-
var AtomicReference = class {
|
|
5372
|
-
constructor(initialValue) {
|
|
5373
|
-
this.value = initialValue;
|
|
5374
|
-
}
|
|
5375
|
-
get() {
|
|
5376
|
-
return this.value;
|
|
5377
|
-
}
|
|
5378
|
-
set(newValue) {
|
|
5379
|
-
this.value = newValue;
|
|
5380
|
-
}
|
|
5381
|
-
compareAndSet(expect, update) {
|
|
5382
|
-
if (this.value === expect) {
|
|
5383
|
-
this.value = update;
|
|
5384
|
-
return true;
|
|
5385
|
-
}
|
|
5386
|
-
return false;
|
|
5387
|
-
}
|
|
5388
|
-
};
|
|
5389
5605
|
/**
|
|
5390
5606
|
* An RE2 class instance is a compiled representation of an RE2 regular expression, independent of
|
|
5391
5607
|
* the public Java-like Pattern/Matcher API.
|
|
@@ -5474,7 +5690,7 @@
|
|
|
5474
5690
|
this.prefixUTF8 = null;
|
|
5475
5691
|
this.prefixComplete = false;
|
|
5476
5692
|
this.prefixRune = 0;
|
|
5477
|
-
this.
|
|
5693
|
+
this.machinePool = [];
|
|
5478
5694
|
this.dfa = new DFA(this.prog);
|
|
5479
5695
|
this.onepass = OnePass.compile(this.prog);
|
|
5480
5696
|
this.prefilter = null;
|
|
@@ -5508,7 +5724,10 @@
|
|
|
5508
5724
|
}
|
|
5509
5725
|
return [];
|
|
5510
5726
|
}
|
|
5511
|
-
|
|
5727
|
+
createLookbehindState() {
|
|
5728
|
+
return this.prog.numLb > 0 ? new LookbehindState(this.prog) : null;
|
|
5729
|
+
}
|
|
5730
|
+
executeEngine(input, pos, anchor, ncap, lbState = null) {
|
|
5512
5731
|
if (this.prefixComplete && (ncap === 0 || this.numSubexp === 0)) return this.matchPrefixComplete(input, pos, anchor, ncap);
|
|
5513
5732
|
if (this.prefilter !== null && anchor === RE2Flags.UNANCHORED) {
|
|
5514
5733
|
if (!this.prefilter.eval(input, pos)) return null;
|
|
@@ -5516,14 +5735,14 @@
|
|
|
5516
5735
|
if (this.onepass !== null) return OnePass.execute(this, input, pos, anchor, ncap);
|
|
5517
5736
|
if (ncap > 0) {
|
|
5518
5737
|
if (this.prog.numLb === 0 && input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
|
|
5519
|
-
return this.doExecuteNFA(input, pos, anchor, ncap);
|
|
5738
|
+
return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
|
|
5520
5739
|
}
|
|
5521
5740
|
if (this.prog.numLb === 0) {
|
|
5522
5741
|
const dfaResult = this.dfa.match(input, pos, anchor);
|
|
5523
5742
|
if (dfaResult !== null) return dfaResult ? [] : null;
|
|
5524
5743
|
if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
|
|
5525
5744
|
}
|
|
5526
|
-
return this.doExecuteNFA(input, pos, anchor, ncap);
|
|
5745
|
+
return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
|
|
5527
5746
|
}
|
|
5528
5747
|
/**
|
|
5529
5748
|
* Returns the number of parenthesized subexpressions in this regular expression.
|
|
@@ -5538,42 +5757,23 @@
|
|
|
5538
5757
|
return this.prog.numInst();
|
|
5539
5758
|
}
|
|
5540
5759
|
get() {
|
|
5541
|
-
|
|
5542
|
-
do
|
|
5543
|
-
head = this.pooled.get();
|
|
5544
|
-
while (head && !this.pooled.compareAndSet(head, head.next));
|
|
5545
|
-
return head;
|
|
5760
|
+
return this.machinePool.length > 0 ? this.machinePool.pop() : null;
|
|
5546
5761
|
}
|
|
5547
5762
|
reset() {
|
|
5548
|
-
this.
|
|
5549
|
-
}
|
|
5550
|
-
put(m
|
|
5551
|
-
|
|
5552
|
-
do {
|
|
5553
|
-
head = this.pooled.get();
|
|
5554
|
-
if (!isNew && head) {
|
|
5555
|
-
m = Machine.fromMachine(m);
|
|
5556
|
-
isNew = true;
|
|
5557
|
-
}
|
|
5558
|
-
if (m.next !== head) m.next = head;
|
|
5559
|
-
} while (!this.pooled.compareAndSet(head, m));
|
|
5763
|
+
this.machinePool.length = 0;
|
|
5764
|
+
}
|
|
5765
|
+
put(m) {
|
|
5766
|
+
this.machinePool.push(m);
|
|
5560
5767
|
}
|
|
5561
5768
|
toString() {
|
|
5562
5769
|
return this.expr;
|
|
5563
5770
|
}
|
|
5564
|
-
doExecuteNFA(input, pos, anchor, ncap) {
|
|
5771
|
+
doExecuteNFA(input, pos, anchor, ncap, lbState = null) {
|
|
5565
5772
|
let m = this.get();
|
|
5566
|
-
|
|
5567
|
-
if (!m) {
|
|
5568
|
-
m = Machine.fromRE2(this);
|
|
5569
|
-
isNew = true;
|
|
5570
|
-
} else if (m.next !== null) {
|
|
5571
|
-
m = Machine.fromMachine(m);
|
|
5572
|
-
isNew = true;
|
|
5573
|
-
}
|
|
5773
|
+
if (!m) m = Machine.fromRE2(this);
|
|
5574
5774
|
m.init(ncap);
|
|
5575
|
-
const cap = m.match(input, pos, anchor) ? m.submatches() : null;
|
|
5576
|
-
this.put(m
|
|
5775
|
+
const cap = m.match(input, pos, anchor, lbState) ? m.submatches() : null;
|
|
5776
|
+
this.put(m);
|
|
5577
5777
|
return cap;
|
|
5578
5778
|
}
|
|
5579
5779
|
match(s) {
|
|
@@ -5591,17 +5791,21 @@
|
|
|
5591
5791
|
* @param anchor the anchoring flag (UNANCHORED, ANCHOR_START, ANCHOR_BOTH)
|
|
5592
5792
|
* @param group the array to fill with submatch positions
|
|
5593
5793
|
* @param ngroup the number of array pairs to fill in
|
|
5794
|
+
* @param lbState optional state carried between successive matches over the same input (see
|
|
5795
|
+
* createLookbehindState); omit it to evaluate lookbehinds from the beginning of the input
|
|
5594
5796
|
* @returns true if a match was found
|
|
5595
5797
|
*/
|
|
5596
|
-
matchWithGroup(input, start, end, anchor, ngroup) {
|
|
5597
|
-
if (!(input instanceof MatcherInputBase))
|
|
5598
|
-
|
|
5599
|
-
|
|
5798
|
+
matchWithGroup(input, start, end, anchor, ngroup, lbState = null) {
|
|
5799
|
+
if (!(input instanceof MatcherInputBase)) {
|
|
5800
|
+
if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
|
|
5801
|
+
else input = MatcherInput.utf16(input);
|
|
5802
|
+
}
|
|
5803
|
+
return this.matchMachineInput(input, start, end, anchor, ngroup, lbState);
|
|
5600
5804
|
}
|
|
5601
|
-
matchMachineInput(input, start, end, anchor, ngroup) {
|
|
5805
|
+
matchMachineInput(input, start, end, anchor, ngroup, lbState = null) {
|
|
5602
5806
|
if (start > end) return [false, null];
|
|
5603
5807
|
const machineInput = input.isUTF16Encoding() ? MachineInput.fromUTF16(input.asCharSequence(), 0, end) : MachineInput.fromUTF8(input.asBytes(), 0, end);
|
|
5604
|
-
const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup);
|
|
5808
|
+
const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup, lbState);
|
|
5605
5809
|
if (groupMatch === null) return [false, null];
|
|
5606
5810
|
return [true, groupMatch];
|
|
5607
5811
|
}
|
|
@@ -5638,9 +5842,10 @@
|
|
|
5638
5842
|
let searchPos = 0;
|
|
5639
5843
|
let out = "";
|
|
5640
5844
|
const input = MachineInput.fromUTF16(src);
|
|
5845
|
+
const lbState = this.createLookbehindState();
|
|
5641
5846
|
let numReplaces = 0;
|
|
5642
5847
|
while (searchPos <= src.length) {
|
|
5643
|
-
const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2);
|
|
5848
|
+
const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2, lbState);
|
|
5644
5849
|
if (a === null || a.length === 0) break;
|
|
5645
5850
|
out += src.substring(lastMatchEnd, a[0]);
|
|
5646
5851
|
if (a[1] > lastMatchEnd || a[0] === 0) {
|
|
@@ -5674,8 +5879,9 @@
|
|
|
5674
5879
|
let pos = 0;
|
|
5675
5880
|
let i = 0;
|
|
5676
5881
|
let prevMatchEnd = -1;
|
|
5882
|
+
const lbState = this.createLookbehindState();
|
|
5677
5883
|
while (i < n && pos <= end) {
|
|
5678
|
-
const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap);
|
|
5884
|
+
const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap, lbState);
|
|
5679
5885
|
if (matches === null || matches.length === 0) break;
|
|
5680
5886
|
let accept = true;
|
|
5681
5887
|
if (matches[1] === pos) {
|
|
@@ -5945,7 +6151,9 @@
|
|
|
5945
6151
|
*/
|
|
5946
6152
|
compile() {
|
|
5947
6153
|
if (this.prog) return;
|
|
5948
|
-
|
|
6154
|
+
const prog = Compiler.compileSet(this.regexps);
|
|
6155
|
+
if (prog.numInst() > Parser.MAX_SIZE) throw new RE2JSCompileException(`${Parser.ERR_LARGE}: the set compiles to ${prog.numInst()} instructions, more than ${Parser.MAX_SIZE}`);
|
|
6156
|
+
this.prog = prog;
|
|
5949
6157
|
this.dfa = new DFA(this.prog, this.maxMem);
|
|
5950
6158
|
this.dummyRe2 = {
|
|
5951
6159
|
prog: this.prog,
|
|
@@ -6439,7 +6647,7 @@
|
|
|
6439
6647
|
}
|
|
6440
6648
|
result.push(m.substring(last, m.inputLength()));
|
|
6441
6649
|
}
|
|
6442
|
-
if (limit !== 0 || result.length === 0) result.push(m.substring(last, m.inputLength()));
|
|
6650
|
+
if (limit !== 0 || result.length === 0 && !(last === m.inputLength() && last > 0)) result.push(m.substring(last, m.inputLength()));
|
|
6443
6651
|
return result;
|
|
6444
6652
|
}
|
|
6445
6653
|
/**
|