@heroiclands/package-build 25.5.4 → 25.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +7 -0
  3. package/assets/styles/content-base.css +1 -1
  4. package/bin/content-commands.mjs +32 -8
  5. package/docs/api.md +81 -32
  6. package/docs/authoring/frontmatter.md +1 -1
  7. package/docs/authoring/links-and-markup.md +59 -10
  8. package/docs/commands.md +60 -17
  9. package/docs/configuration.md +3 -2
  10. package/docs/content-format.md +50 -1
  11. package/docs/diagnostics.md +17 -0
  12. package/docs/guides/module-project.md +11 -3
  13. package/docs/guides/reference-pages.md +4 -1
  14. package/docs/guides/site.md +13 -3
  15. package/docs/guides/writing-in-invented-scripts.md +5 -2
  16. package/docs/reference/format-details.md +233 -138
  17. package/docs/reference/note-types.md +165 -152
  18. package/docs/reference/theme-pages.md +1 -0
  19. package/e2e.mjs +1 -1
  20. package/engine/base-compiler.mjs +2 -0
  21. package/engine/compile-corpus.mjs +6 -2
  22. package/engine/content-charset.mjs +1 -1
  23. package/engine/content-format.yaml +9 -7
  24. package/engine/content-html.mjs +3 -2
  25. package/engine/content-index.mjs +23 -0
  26. package/engine/content-links.mjs +8 -0
  27. package/engine/content-render.mjs +14 -2
  28. package/engine/content-scripts.mjs +44 -6
  29. package/engine/content-session.mjs +11 -7
  30. package/engine/content-spans.mjs +3 -4
  31. package/engine/content-tables.mjs +12 -5
  32. package/engine/content-verse.mjs +52 -10
  33. package/engine/core-report.mjs +27 -18
  34. package/engine/culture-reach.mjs +3 -0
  35. package/engine/declared-sections.mjs +100 -0
  36. package/engine/derived-sections.mjs +36 -2
  37. package/engine/dictionary-rows.mjs +2 -1
  38. package/engine/generated-sections.mjs +2 -0
  39. package/engine/holdings.mjs +107 -3
  40. package/engine/index-records.mjs +3 -1
  41. package/engine/index.mjs +1 -1
  42. package/engine/language-data.mjs +0 -1
  43. package/engine/language-names.mjs +53 -23
  44. package/engine/language-rows.mjs +1 -3
  45. package/engine/language-terms.mjs +7 -10
  46. package/engine/map-dot.mjs +22 -0
  47. package/engine/markdown-blocks.mjs +23 -8
  48. package/engine/markdownlint-run.mjs +1 -1
  49. package/engine/markup-validation.mjs +2 -0
  50. package/engine/metadata-index.mjs +1 -0
  51. package/engine/note-addresses.mjs +16 -0
  52. package/engine/note-vocabulary.mjs +29 -13
  53. package/engine/npc-generate.mjs +52 -7
  54. package/engine/office-holders.mjs +76 -0
  55. package/engine/page-breaks.mjs +143 -0
  56. package/engine/pdf-build.mjs +12 -4
  57. package/engine/pdf-render.mjs +12 -2
  58. package/engine/place-kinds.mjs +106 -0
  59. package/engine/preview-index.mjs +4 -2
  60. package/engine/settlement-tables.mjs +410 -675
  61. package/engine/settlement-terms.mjs +118 -0
  62. package/engine/site-build.mjs +14 -7
  63. package/engine/site-preview.mjs +3 -0
  64. package/engine/site-render.mjs +18 -4
  65. package/engine/site-root.mjs +10 -1
  66. package/engine/site-serve-http.mjs +151 -0
  67. package/engine/site-serve.mjs +196 -126
  68. package/engine/sql-tables.mjs +101 -7
  69. package/engine/standing-terms.mjs +9 -5
  70. package/engine/standings.mjs +83 -31
  71. package/engine/unique-items.mjs +85 -0
  72. package/engine/verse-metre.mjs +50 -5
  73. package/engine/verse-regions.mjs +16 -0
  74. package/package.json +9 -4
  75. package/site-theme/data/banner-kinds.yaml +2 -0
  76. package/sohl/actors.mjs +4 -3
  77. package/types/e2e.d.mts +1 -1
  78. package/types/engine/content-html.d.mts +2 -1
  79. package/types/engine/content-scripts.d.mts +9 -1
  80. package/types/engine/content-verse.d.mts +11 -2
  81. package/types/engine/core-report.d.mts +6 -2
  82. package/types/engine/culture-reach.d.mts +3 -0
  83. package/types/engine/declared-sections.d.mts +30 -0
  84. package/types/engine/derived-sections.d.mts +5 -1
  85. package/types/engine/holdings.d.mts +34 -2
  86. package/types/engine/index-records.d.mts +2 -1
  87. package/types/engine/language-names.d.mts +18 -6
  88. package/types/engine/language-terms.d.mts +5 -1
  89. package/types/engine/markdown-blocks.d.mts +5 -1
  90. package/types/engine/npc-generate.d.mts +3 -0
  91. package/types/engine/office-holders.d.mts +33 -0
  92. package/types/engine/page-breaks.d.mts +38 -0
  93. package/types/engine/pdf-render.d.mts +2 -0
  94. package/types/engine/place-kinds.d.mts +18 -0
  95. package/types/engine/settlement-tables.d.mts +25 -158
  96. package/types/engine/settlement-terms.d.mts +53 -0
  97. package/types/engine/site-build.d.mts +3 -1
  98. package/types/engine/site-render.d.mts +6 -2
  99. package/types/engine/site-root.d.mts +3 -1
  100. package/types/engine/site-serve-http.d.mts +1 -0
  101. package/types/engine/site-serve.d.mts +12 -6
  102. package/types/engine/sql-tables.d.mts +35 -3
  103. package/types/engine/standing-terms.d.mts +3 -2
  104. package/types/engine/standings.d.mts +14 -2
  105. package/types/engine/unique-items.d.mts +12 -0
  106. package/types/engine/verse-metre.d.mts +2 -1
  107. package/types/engine/verse-regions.d.mts +8 -0
  108. package/vendor/markdownlint.mjs +855 -569
@@ -876,7 +876,7 @@
876
876
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
877
877
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
878
878
  *
879
- * re2js@2.8.6 (MIT)
879
+ * re2js@2.8.7 (MIT)
880
880
  *
881
881
  * MIT License
882
882
  *
@@ -2148,6 +2148,10 @@ var UnicodeTables = class {
2148
2148
  };
2149
2149
  var Unicode = class Unicode2 {
2150
2150
  static MAX_RUNE = 1114111;
2151
+ static RUNE_ERROR = 65533;
2152
+ static isUnsearchable(r) {
2153
+ return r === Unicode2.RUNE_ERROR || r >= Unicode2.MIN_HIGH_SURROGATE && r <= Unicode2.MAX_LOW_SURROGATE;
2154
+ }
2151
2155
  static MAX_ASCII = 127;
2152
2156
  static MAX_LATIN1 = 255;
2153
2157
  static MAX_BMP = 65535;
@@ -2234,7 +2238,7 @@ var Utils = class Utils2 {
2234
2238
  return [];
2235
2239
  }
2236
2240
  static isByteArray(input) {
2237
- return Array.isArray(input) || input instanceof Uint8Array;
2241
+ return Array.isArray(input) || Object.prototype.toString.call(input) === "[object Uint8Array]";
2238
2242
  }
2239
2243
  static isalnum(c) {
2240
2244
  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");
@@ -2293,7 +2297,7 @@ var Utils = class Utils2 {
2293
2297
  runes.push(cp);
2294
2298
  i += cp > Unicode.MAX_BMP ? 2 : 1;
2295
2299
  }
2296
- return runes;
2300
+ return new Int32Array(runes);
2297
2301
  }
2298
2302
  static runeToString(r) {
2299
2303
  return String.fromCodePoint(r);
@@ -2413,7 +2417,7 @@ var MatcherInputBase = class MatcherInputBase2 {
2413
2417
  asCharSequence() {
2414
2418
  throw Error("not implemented");
2415
2419
  }
2416
- /** @returns {Uint8Array|number[]} */
2420
+ /** @returns {Uint8Array|number[]|null} */
2417
2421
  asBytes() {
2418
2422
  throw Error("not implemented");
2419
2423
  }
@@ -2538,7 +2542,8 @@ var MachineInputBase = class {
2538
2542
  return 0;
2539
2543
  }
2540
2544
  };
2541
- var MachineUTF8Input = class extends MachineInputBase {
2545
+ var MachineUTF8Input = class MachineUTF8Input2 extends MachineInputBase {
2546
+ static RUNE_ERROR_STEP = Unicode.RUNE_ERROR << 3 | 1;
2542
2547
  constructor(bytes, start = 0, end = bytes.length) {
2543
2548
  super();
2544
2549
  this.bytes = bytes;
@@ -2552,33 +2557,46 @@ var MachineUTF8Input = class extends MachineInputBase {
2552
2557
  return idx !== -1 && idx <= this.end - target.length;
2553
2558
  }
2554
2559
  hasAnyString(prefilter, pos) {
2555
- if (!prefilter.ac8) return false;
2556
- return prefilter.ac8.searchUTF8(this.bytes, this.start + pos, this.end);
2560
+ return prefilter.automaton8().searchUTF8(this.bytes, this.start + pos, this.end);
2557
2561
  }
2558
2562
  step(pos) {
2559
2563
  pos += this.start;
2560
2564
  if (pos >= this.end) return MachineInputBase.EOF();
2561
2565
  const c = this.bytes[pos] & 255;
2562
2566
  if (c < 128) return c << 3 | 1;
2563
- else if (c >= 194 && c <= 223 && pos + 1 < this.end) {
2564
- const c1 = this.bytes[pos + 1] & 255;
2565
- if ((c1 & 192) !== 128) return c << 3 | 1;
2566
- return ((c & 31) << 6 | c1 & 63) << 3 | 2;
2567
- } else if (c >= 224 && c <= 239 && pos + 2 < this.end) {
2568
- const c1 = this.bytes[pos + 1] & 255;
2569
- if ((c1 & 192) !== 128) return c << 3 | 1;
2570
- const c2 = this.bytes[pos + 2] & 255;
2571
- if ((c2 & 192) !== 128) return c << 3 | 1;
2572
- return ((c & 15) << 12 | (c1 & 63) << 6 | c2 & 63) << 3 | 3;
2573
- } else if (c >= 240 && c <= 244 && pos + 3 < this.end) {
2574
- const c1 = this.bytes[pos + 1] & 255;
2575
- if ((c1 & 192) !== 128) return c << 3 | 1;
2567
+ let size;
2568
+ let rune;
2569
+ let lo = 128;
2570
+ let hi = 191;
2571
+ if (c >= 194 && c <= 223) {
2572
+ size = 2;
2573
+ rune = c & 31;
2574
+ } else if (c >= 224 && c <= 239) {
2575
+ size = 3;
2576
+ rune = c & 15;
2577
+ if (c === 224) lo = 160;
2578
+ else if (c === 237) hi = 159;
2579
+ } else if (c >= 240 && c <= 244) {
2580
+ size = 4;
2581
+ rune = c & 7;
2582
+ if (c === 240) lo = 144;
2583
+ else if (c === 244) hi = 143;
2584
+ } else return MachineUTF8Input2.RUNE_ERROR_STEP;
2585
+ if (pos + size > this.end) return MachineUTF8Input2.RUNE_ERROR_STEP;
2586
+ const c1 = this.bytes[pos + 1] & 255;
2587
+ if (c1 < lo || c1 > hi) return MachineUTF8Input2.RUNE_ERROR_STEP;
2588
+ rune = rune << 6 | c1 & 63;
2589
+ if (size > 2) {
2576
2590
  const c2 = this.bytes[pos + 2] & 255;
2577
- if ((c2 & 192) !== 128) return c << 3 | 1;
2578
- const c3 = this.bytes[pos + 3] & 255;
2579
- if ((c3 & 192) !== 128) return c << 3 | 1;
2580
- return ((c & 7) << 18 | (c1 & 63) << 12 | (c2 & 63) << 6 | c3 & 63) << 3 | 4;
2581
- } else return c << 3 | 1;
2591
+ if ((c2 & 192) !== 128) return MachineUTF8Input2.RUNE_ERROR_STEP;
2592
+ rune = rune << 6 | c2 & 63;
2593
+ if (size > 3) {
2594
+ const c3 = this.bytes[pos + 3] & 255;
2595
+ if ((c3 & 192) !== 128) return MachineUTF8Input2.RUNE_ERROR_STEP;
2596
+ rune = rune << 6 | c3 & 63;
2597
+ }
2598
+ }
2599
+ return rune << 3 | size;
2582
2600
  }
2583
2601
  index(re2, pos) {
2584
2602
  pos += this.start;
@@ -2643,8 +2661,7 @@ var MachineUTF16Input = class extends MachineInputBase {
2643
2661
  return idx !== -1 && idx <= this.end - prefilter.str.length;
2644
2662
  }
2645
2663
  hasAnyString(prefilter, pos) {
2646
- if (!prefilter.ac16) return false;
2647
- return prefilter.ac16.searchUTF16(this.charSequence, this.start + pos, this.end);
2664
+ return prefilter.automaton16().searchUTF16(this.charSequence, this.start + pos, this.end);
2648
2665
  }
2649
2666
  step(pos) {
2650
2667
  pos += this.start;
@@ -2786,6 +2803,7 @@ var Matcher = class Matcher2 {
2786
2803
  this.groups = [];
2787
2804
  this.namedGroups = re2.namedGroups;
2788
2805
  this.numberOfInstructions = re2.numberOfInstructions();
2806
+ this.lookbehindState = null;
2789
2807
  if (input instanceof MatcherInputBase) this.resetMatcherInput(input);
2790
2808
  else if (Utils.isByteArray(input)) this.resetMatcherInput(MatcherInput.utf8(input));
2791
2809
  else this.resetMatcherInput(MatcherInput.utf16(input));
@@ -2817,9 +2835,13 @@ var Matcher = class Matcher2 {
2817
2835
  */
2818
2836
  resetMatcherInput(input) {
2819
2837
  if (input === null) throw new Error("input is null");
2820
- if (!(input instanceof MatcherInputBase)) if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
2821
- else input = MatcherInput.utf16(input);
2838
+ if (!(input instanceof MatcherInputBase)) {
2839
+ if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
2840
+ else input = MatcherInput.utf16(input);
2841
+ }
2822
2842
  this.matcherInput = input;
2843
+ if (this.lookbehindState !== null) this.lookbehindState.reset();
2844
+ else this.lookbehindState = this.patternInput.re2().createLookbehindState();
2823
2845
  this.reset();
2824
2846
  return this;
2825
2847
  }
@@ -2907,11 +2929,11 @@ var Matcher = class Matcher2 {
2907
2929
  * @private
2908
2930
  */
2909
2931
  loadGroup(group) {
2910
- if (group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
2932
+ if (!Number.isInteger(group) || group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
2911
2933
  if (!this.hasMatch) throw new RE2JSGroupException("perhaps no match attempted");
2912
2934
  if (group === 0 || this.hasGroups) return;
2913
2935
  const end = this.matcherInputLength;
2914
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount);
2936
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount, this.lookbehindState);
2915
2937
  if (!res[0]) throw new RE2JSGroupException("inconsistency in matching group data");
2916
2938
  this.groups = res[1];
2917
2939
  this.hasGroups = true;
@@ -2944,7 +2966,7 @@ var Matcher = class Matcher2 {
2944
2966
  */
2945
2967
  find(start = null) {
2946
2968
  if (start !== null) {
2947
- if (start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
2969
+ if (!Number.isInteger(start) || start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
2948
2970
  this.reset();
2949
2971
  return this.genMatch(start, 0);
2950
2972
  }
@@ -2967,7 +2989,7 @@ var Matcher = class Matcher2 {
2967
2989
  * @private
2968
2990
  */
2969
2991
  genMatch(startByte, anchor) {
2970
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
2992
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1, this.lookbehindState);
2971
2993
  if (!res[0]) {
2972
2994
  this.hasMatch = false;
2973
2995
  return false;
@@ -3289,7 +3311,7 @@ var Inst = class Inst2 {
3289
3311
  this.op = op;
3290
3312
  this.out = 0;
3291
3313
  this.arg = 0;
3292
- this.runes = [];
3314
+ this.runes = /* @__PURE__ */ new Int32Array(0);
3293
3315
  this.next = null;
3294
3316
  }
3295
3317
  matchRune(r) {
@@ -3388,19 +3410,27 @@ var Inst = class Inst2 {
3388
3410
  }
3389
3411
  }
3390
3412
  };
3391
- var Queue = class {
3413
+ var Queue = class Queue2 {
3392
3414
  constructor(numInst) {
3393
3415
  this.sparse = new Int32Array(numInst);
3394
3416
  this.densePcs = new Int32Array(numInst);
3395
3417
  this.denseCaps = null;
3396
3418
  this.size = 0;
3397
3419
  this.ncap = 0;
3420
+ this.mainThreads = 0;
3398
3421
  }
3422
+ static INITIAL_THREADS = 32;
3399
3423
  init(ncap) {
3400
3424
  this.ncap = ncap;
3401
- const needed = this.densePcs.length * ncap;
3425
+ const needed = Math.min(this.densePcs.length, Queue2.INITIAL_THREADS) * ncap;
3402
3426
  if (!this.denseCaps || this.denseCaps.length < needed) this.denseCaps = new Int32Array(needed);
3403
3427
  }
3428
+ growCaps(needed) {
3429
+ const limit = this.densePcs.length * this.ncap;
3430
+ const grown = new Int32Array(Math.min(limit, Math.max(needed, 2 * this.denseCaps.length)));
3431
+ grown.set(this.denseCaps);
3432
+ this.denseCaps = grown;
3433
+ }
3404
3434
  contains(pc) {
3405
3435
  const j = this.sparse[pc];
3406
3436
  return j < this.size && this.densePcs[j] === pc;
@@ -3416,6 +3446,7 @@ var Queue = class {
3416
3446
  }
3417
3447
  clear() {
3418
3448
  this.size = 0;
3449
+ this.mainThreads = 0;
3419
3450
  }
3420
3451
  toString() {
3421
3452
  let out = "{";
@@ -3427,6 +3458,18 @@ var Queue = class {
3427
3458
  return out;
3428
3459
  }
3429
3460
  };
3461
+ var LookbehindState = class {
3462
+ constructor(prog) {
3463
+ this.pos = -1;
3464
+ this.pcs = new Int32Array(prog.numInst());
3465
+ this.size = 0;
3466
+ this.lbTable = new Int32Array(prog.numLb + 1);
3467
+ }
3468
+ reset() {
3469
+ this.pos = -1;
3470
+ this.size = 0;
3471
+ }
3472
+ };
3430
3473
  var Machine = class Machine2 {
3431
3474
  static fromRE2(re2) {
3432
3475
  const m = new Machine2();
@@ -3434,19 +3477,18 @@ var Machine = class Machine2 {
3434
3477
  m.re2 = re2;
3435
3478
  m.q0 = new Queue(m.prog.numInst());
3436
3479
  m.q1 = new Queue(m.prog.numInst());
3480
+ m.addStack = new Int32Array(2 * (m.prog.numInst() + 1));
3437
3481
  m.matched = false;
3438
3482
  m.matchcap = new Int32Array(m.prog.numCap < 2 ? 2 : m.prog.numCap);
3439
3483
  m.ncap = 0;
3440
3484
  return m;
3441
3485
  }
3442
- static fromMachine(machine) {
3443
- return Machine2.fromRE2(machine.re2);
3444
- }
3445
3486
  constructor() {
3446
3487
  this.prog = null;
3447
3488
  this.re2 = null;
3448
3489
  this.q0 = null;
3449
3490
  this.q1 = null;
3491
+ this.addStack = null;
3450
3492
  this.matched = false;
3451
3493
  this.matchcap = null;
3452
3494
  this.ncap = 0;
@@ -3467,14 +3509,23 @@ var Machine = class Machine2 {
3467
3509
  if (this.ncap === 0) return Utils.emptyInts();
3468
3510
  return Utils.toArray(this.matchcap.subarray(0, this.ncap));
3469
3511
  }
3470
- match(input, pos, anchor) {
3512
+ match(input, pos, anchor, lbState = null) {
3471
3513
  const startCond = this.re2.cond;
3472
3514
  if (startCond === Utils.EMPTY_ALL) return false;
3473
3515
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
3474
3516
  this.matched = false;
3475
3517
  this.matchcap.fill(-1);
3476
- let currentPos = this.prog.numLb > 0 ? 0 : pos;
3477
- let matchStartPos = pos;
3518
+ const hasLookbehinds = this.prog.numLb > 0;
3519
+ const matchStartPos = pos;
3520
+ let currentPos = pos;
3521
+ let resumeLookbehinds = false;
3522
+ if (hasLookbehinds) {
3523
+ if (lbState !== null && lbState.pos >= 0 && lbState.pos <= pos) {
3524
+ currentPos = lbState.pos;
3525
+ resumeLookbehinds = true;
3526
+ } else currentPos = 0;
3527
+ }
3528
+ let saveLookbehinds = hasLookbehinds && lbState !== null;
3478
3529
  let runq = this.q0;
3479
3530
  let nextq = this.q1;
3480
3531
  let r = input.step(currentPos);
@@ -3490,12 +3541,16 @@ var Machine = class Machine2 {
3490
3541
  let flag;
3491
3542
  if (currentPos === 0) flag = Utils.emptyOpContext(-1, rune);
3492
3543
  else flag = input.context(currentPos);
3544
+ if (hasLookbehinds) {
3545
+ if (resumeLookbehinds) this.restoreLookbehinds(lbState, runq, flag);
3546
+ else this.spawnLookbehinds(runq, currentPos, flag);
3547
+ }
3493
3548
  while (true) {
3494
- if (runq.isEmpty()) {
3549
+ if (runq.mainThreads === 0) {
3495
3550
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
3496
3551
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
3497
3552
  if (this.matched) break;
3498
- if (this.prog.numLb === 0 && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
3553
+ if (this.prog.numLb === 0 && runq.isEmpty() && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
3499
3554
  const advance = input.index(this.re2, currentPos);
3500
3555
  if (advance < 0) break;
3501
3556
  currentPos += advance;
@@ -3508,9 +3563,12 @@ var Machine = class Machine2 {
3508
3563
  flag = input.context(currentPos);
3509
3564
  }
3510
3565
  }
3511
- 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, 0, flag);
3512
- if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
3513
- if (currentPos >= matchStartPos) {
3566
+ if (currentPos >= matchStartPos) {
3567
+ if (saveLookbehinds) {
3568
+ this.saveLookbehinds(lbState, runq, currentPos);
3569
+ saveLookbehinds = false;
3570
+ }
3571
+ if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
3514
3572
  if (this.ncap > 0) this.matchcap[0] = currentPos;
3515
3573
  this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
3516
3574
  }
@@ -3532,6 +3590,7 @@ var Machine = class Machine2 {
3532
3590
  runq = nextq;
3533
3591
  nextq = tmpq;
3534
3592
  }
3593
+ runq.clear();
3535
3594
  nextq.clear();
3536
3595
  return this.matched;
3537
3596
  }
@@ -3555,12 +3614,12 @@ var Machine = class Machine2 {
3555
3614
  }
3556
3615
  let flag = currentPos === 0 ? Utils.emptyOpContext(-1, rune) : input.context(currentPos);
3557
3616
  const matches = /* @__PURE__ */ new Set();
3617
+ if (this.prog.numLb > 0) this.spawnLookbehinds(runq, currentPos, flag);
3558
3618
  while (true) {
3559
- if (runq.isEmpty()) {
3619
+ if (runq.mainThreads === 0) {
3560
3620
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
3561
3621
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
3562
3622
  }
3563
- 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, 0, flag);
3564
3623
  if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
3565
3624
  if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
3566
3625
  }
@@ -3647,68 +3706,86 @@ var Machine = class Machine2 {
3647
3706
  }
3648
3707
  runq.clear();
3649
3708
  }
3709
+ spawnLookbehinds(q, pos, flag) {
3710
+ for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(q, this.prog.lbStarts[i], pos, this.matchcap, 0, flag);
3711
+ }
3712
+ restoreLookbehinds(lbState, q, flag) {
3713
+ this.lbTable.set(lbState.lbTable);
3714
+ for (let j = 0; j < lbState.size; j++) this.add(q, lbState.pcs[j], lbState.pos, this.matchcap, 0, flag);
3715
+ }
3716
+ saveLookbehinds(lbState, q, pos) {
3717
+ let size = 0;
3718
+ for (let j = 0; j < q.size; j++) {
3719
+ const pc = q.densePcs[j];
3720
+ if (this.prog.lbInst[pc] === 1 && Inst.isRuneOp(this.prog.inst[pc].op)) lbState.pcs[size++] = pc;
3721
+ }
3722
+ lbState.size = size;
3723
+ lbState.pos = pos;
3724
+ lbState.lbTable.set(this.lbTable);
3725
+ }
3650
3726
  add(q, pc, pos, capArray, capOffset, cond) {
3651
- while (true) {
3652
- if (pc === 0) return;
3653
- if (q.contains(pc)) return;
3654
- const d = q.add(pc);
3655
- const inst = this.prog.inst[pc];
3656
- switch (inst.op) {
3657
- case Inst.FAIL:
3658
- return;
3659
- case Inst.ALT:
3660
- case Inst.ALT_MATCH:
3661
- this.add(q, inst.out, pos, capArray, capOffset, cond);
3662
- pc = inst.arg;
3663
- continue;
3664
- case Inst.EMPTY_WIDTH:
3665
- if ((inst.arg & ~cond) === 0) {
3727
+ const stk = this.addStack;
3728
+ let nstk = 0;
3729
+ for (; ; ) {
3730
+ while (pc !== 0 && !q.contains(pc)) {
3731
+ const d = q.add(pc);
3732
+ const inst = this.prog.inst[pc];
3733
+ switch (inst.op) {
3734
+ case Inst.FAIL:
3735
+ pc = 0;
3736
+ break;
3737
+ case Inst.ALT:
3738
+ case Inst.ALT_MATCH:
3739
+ stk[nstk++] = inst.arg;
3740
+ stk[nstk++] = 0;
3666
3741
  pc = inst.out;
3667
- continue;
3668
- }
3669
- return;
3670
- case Inst.NOP:
3671
- pc = inst.out;
3672
- continue;
3673
- case Inst.CAPTURE:
3674
- if (inst.arg < this.ncap) {
3675
- const opos = capArray[capOffset + inst.arg];
3676
- capArray[capOffset + inst.arg] = pos;
3677
- this.add(q, inst.out, pos, capArray, capOffset, cond);
3678
- capArray[capOffset + inst.arg] = opos;
3679
- return;
3680
- } else {
3742
+ break;
3743
+ case Inst.EMPTY_WIDTH:
3744
+ pc = (inst.arg & ~cond) === 0 ? inst.out : 0;
3745
+ break;
3746
+ case Inst.NOP:
3681
3747
  pc = inst.out;
3682
- continue;
3683
- }
3684
- case Inst.LB_WRITE:
3685
- this.lbTable[Math.abs(inst.arg)] = pos;
3686
- pc = inst.out;
3687
- continue;
3688
- case Inst.LB_CHECK:
3689
- if (inst.arg > 0) {
3690
- if (this.lbTable[inst.arg] === pos) {
3691
- pc = inst.out;
3692
- continue;
3748
+ break;
3749
+ case Inst.CAPTURE:
3750
+ if (inst.arg < this.ncap) {
3751
+ stk[nstk++] = -inst.arg - 1;
3752
+ stk[nstk++] = capArray[capOffset + inst.arg];
3753
+ capArray[capOffset + inst.arg] = pos;
3693
3754
  }
3694
- } else if (this.lbTable[-inst.arg] !== pos) {
3695
3755
  pc = inst.out;
3696
- continue;
3697
- }
3698
- return;
3699
- case Inst.MATCH:
3700
- case Inst.RUNE:
3701
- case Inst.RUNE1:
3702
- case Inst.RUNE_ANY:
3703
- case Inst.RUNE_ANY_NOT_NL:
3704
- if (this.ncap > 0) {
3705
- const destOffset = d * this.ncap;
3706
- for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
3707
- }
3708
- return;
3709
- default:
3710
- throw new RE2JSInternalException("unhandled");
3756
+ break;
3757
+ case Inst.LB_WRITE:
3758
+ this.lbTable[Math.abs(inst.arg)] = pos;
3759
+ pc = inst.out;
3760
+ break;
3761
+ case Inst.LB_CHECK:
3762
+ if (inst.arg > 0) pc = this.lbTable[inst.arg] === pos ? inst.out : 0;
3763
+ else pc = this.lbTable[-inst.arg] !== pos ? inst.out : 0;
3764
+ break;
3765
+ case Inst.MATCH:
3766
+ case Inst.RUNE:
3767
+ case Inst.RUNE1:
3768
+ case Inst.RUNE_ANY:
3769
+ case Inst.RUNE_ANY_NOT_NL:
3770
+ if (this.prog.lbInst[pc] === 0) q.mainThreads++;
3771
+ if (this.ncap > 0) {
3772
+ const destOffset = d * this.ncap;
3773
+ if (destOffset + this.ncap > q.denseCaps.length) q.growCaps(destOffset + this.ncap);
3774
+ for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
3775
+ }
3776
+ pc = 0;
3777
+ break;
3778
+ default:
3779
+ throw new RE2JSInternalException("unhandled");
3780
+ }
3711
3781
  }
3782
+ if (nstk === 0) return;
3783
+ nstk -= 2;
3784
+ const entry = stk[nstk];
3785
+ if (entry < 0) {
3786
+ capArray[capOffset - entry - 1] = stk[nstk + 1];
3787
+ pc = 0;
3788
+ } else pc = entry;
3712
3789
  }
3713
3790
  }
3714
3791
  };
@@ -3726,35 +3803,86 @@ var arraysEqual = (a, b) => {
3726
3803
  return true;
3727
3804
  };
3728
3805
  var DFAState = class {
3729
- constructor(nfaStates, isMatch, matchIDs = []) {
3806
+ constructor(nfaStates, isMatch, matchIDs) {
3730
3807
  this.nfaStates = nfaStates;
3731
3808
  this.isMatch = isMatch;
3732
3809
  this.matchIDs = matchIDs;
3733
- this.nextLatin1 = new Array(Unicode.MAX_LATIN1 + 1).fill(null);
3734
- this.nextLatin1Anchored = new Array(Unicode.MAX_LATIN1 + 1).fill(null);
3735
- this.transKeys = [];
3736
- this.transVals = [];
3737
- this.lastSeen = 0;
3810
+ this.next = null;
3811
+ this.nextAnchored = null;
3738
3812
  }
3739
3813
  };
3740
3814
  var DFA = class DFA2 {
3741
- static MAX_CACHE_CLEARS = 5;
3742
- static STATE_MEMORY_ESTIMATE = 838;
3815
+ static STATE_OVERHEAD = 160;
3816
+ static TABLE_OVERHEAD = 16;
3817
+ static PROGRESS_PER_STATE = 10;
3743
3818
  constructor(prog, maxMem = 8388608) {
3744
3819
  this.prog = prog;
3820
+ this.maxMem = maxMem;
3745
3821
  this.stateCache = /* @__PURE__ */ new Map();
3746
3822
  this.stateCount = 0;
3747
3823
  this.startState = null;
3748
- this.stateLimit = Math.max(1, Math.floor(maxMem / DFA2.STATE_MEMORY_ESTIMATE));
3749
- this.cacheClears = 0;
3750
3824
  this.failed = false;
3751
- this.clock = 0;
3825
+ for (let pc = 0; pc < prog.numInst(); pc++) {
3826
+ const op = prog.getInst(pc).op;
3827
+ if (op === Inst.EMPTY_WIDTH || op === Inst.LB_WRITE || op === Inst.LB_CHECK) {
3828
+ this.failed = true;
3829
+ break;
3830
+ }
3831
+ }
3832
+ this.computeRuneClasses();
3833
+ this.stateBudget = maxMem;
3834
+ this.memBudget = maxMem;
3835
+ }
3836
+ computeRuneClasses() {
3837
+ const bounds = /* @__PURE__ */ new Set();
3838
+ const addRune = (r) => {
3839
+ bounds.add(r);
3840
+ bounds.add(r + 1);
3841
+ };
3842
+ for (let pc = 0; pc < this.prog.numInst(); pc++) {
3843
+ const inst = this.prog.getInst(pc);
3844
+ switch (inst.op) {
3845
+ case Inst.RUNE:
3846
+ case Inst.RUNE1:
3847
+ if (inst.runes.length === 1) {
3848
+ addRune(inst.runes[0]);
3849
+ 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);
3850
+ } else for (let j = 0; j < inst.runes.length; j += 2) {
3851
+ bounds.add(inst.runes[j]);
3852
+ bounds.add(inst.runes[j + 1] + 1);
3853
+ }
3854
+ break;
3855
+ case Inst.RUNE_ANY_NOT_NL:
3856
+ addRune(10);
3857
+ }
3858
+ }
3859
+ bounds.delete(0);
3860
+ this.classBounds = Int32Array.from(bounds).sort();
3861
+ this.numClasses = this.classBounds.length + 1;
3862
+ const latin1Class = new Int32Array(Unicode.MAX_LATIN1 + 1);
3863
+ for (let r = 0; r <= Unicode.MAX_LATIN1; r++) latin1Class[r] = this.searchClass(r);
3864
+ this.latin1Class = latin1Class;
3865
+ }
3866
+ runeClass(r) {
3867
+ if (r <= Unicode.MAX_LATIN1) return this.latin1Class[r];
3868
+ return this.searchClass(r);
3869
+ }
3870
+ searchClass(r) {
3871
+ const bounds = this.classBounds;
3872
+ let lo = 0;
3873
+ let hi = bounds.length;
3874
+ while (lo < hi) {
3875
+ const mid = lo + hi >> 1;
3876
+ if (bounds[mid] <= r) lo = mid + 1;
3877
+ else hi = mid;
3878
+ }
3879
+ return lo;
3752
3880
  }
3753
3881
  computeClosure(pcs) {
3754
3882
  const closure = /* @__PURE__ */ new Set();
3755
3883
  const stack = [...pcs];
3756
3884
  let isMatch = false;
3757
- const matchIDs = [];
3885
+ const matchIDs = /* @__PURE__ */ new Set();
3758
3886
  while (stack.length > 0) {
3759
3887
  const pc = stack.pop();
3760
3888
  if (closure.has(pc)) continue;
@@ -3763,7 +3891,7 @@ var DFA = class DFA2 {
3763
3891
  switch (inst.op) {
3764
3892
  case Inst.MATCH:
3765
3893
  isMatch = true;
3766
- if (!matchIDs.includes(inst.arg)) matchIDs.push(inst.arg);
3894
+ matchIDs.add(inst.arg);
3767
3895
  break;
3768
3896
  case Inst.ALT:
3769
3897
  case Inst.ALT_MATCH:
@@ -3781,11 +3909,11 @@ var DFA = class DFA2 {
3781
3909
  }
3782
3910
  }
3783
3911
  const sortedPCs = Int32Array.from(closure).sort();
3784
- matchIDs.sort((a, b) => a - b);
3912
+ const ids = Array.from(matchIDs).sort((a, b) => a - b);
3785
3913
  return {
3786
3914
  pcs: sortedPCs,
3787
3915
  isMatch,
3788
- matchIDs
3916
+ matchIDs: ids
3789
3917
  };
3790
3918
  }
3791
3919
  getState(pcs) {
@@ -3796,163 +3924,133 @@ var DFA = class DFA2 {
3796
3924
  let bucket = this.stateCache.get(hash);
3797
3925
  if (bucket) for (let i = 0; i < bucket.length; i++) {
3798
3926
  const state2 = bucket[i];
3799
- if (arraysEqual(state2.nfaStates, sortedPCs)) {
3800
- state2.lastSeen = ++this.clock;
3801
- return state2;
3802
- }
3927
+ if (arraysEqual(state2.nfaStates, sortedPCs)) return state2;
3803
3928
  }
3804
- else {
3929
+ const cost = DFA2.STATE_OVERHEAD + 4 * sortedPCs.length + 8 * closureResult.matchIDs.length;
3930
+ if (this.memBudget < cost) return null;
3931
+ this.memBudget -= cost;
3932
+ if (!bucket) {
3805
3933
  bucket = [];
3806
3934
  this.stateCache.set(hash, bucket);
3807
3935
  }
3808
- if (this.failed) return null;
3809
- if (this.stateCount >= this.stateLimit) {
3810
- this.cacheClears++;
3811
- if (this.cacheClears >= DFA2.MAX_CACHE_CLEARS) {
3812
- this.failed = true;
3813
- this.stateCache.clear();
3814
- this.stateCount = 0;
3815
- this.startState = null;
3816
- return null;
3817
- }
3818
- this.evictCache();
3819
- bucket = this.stateCache.get(hash);
3820
- if (!bucket) {
3821
- bucket = [];
3822
- this.stateCache.set(hash, bucket);
3823
- }
3824
- }
3825
3936
  const state = new DFAState(sortedPCs, closureResult.isMatch, closureResult.matchIDs);
3826
- state.lastSeen = ++this.clock;
3827
3937
  bucket.push(state);
3828
3938
  this.stateCount++;
3829
3939
  return state;
3830
3940
  }
3831
- evictCache() {
3832
- const allStates = [];
3833
- for (const bucket of this.stateCache.values()) for (let i = 0; i < bucket.length; i++) allStates.push(bucket[i]);
3834
- allStates.sort((a, b) => a.lastSeen - b.lastSeen);
3835
- const keepCount = Math.max(1, Math.floor(this.stateLimit / 2));
3836
- const startIndex = allStates.length - keepCount;
3837
- const survivorsArray = allStates.slice(startIndex);
3838
- const survivors = new Set(survivorsArray);
3941
+ allocTable(state, anchor) {
3942
+ const cost = DFA2.TABLE_OVERHEAD + 8 * this.numClasses;
3943
+ if (this.memBudget < cost) return null;
3944
+ this.memBudget -= cost;
3945
+ const table = new Array(this.numClasses).fill(null);
3946
+ if (anchor === RE2Flags.UNANCHORED) state.next = table;
3947
+ else state.nextAnchored = table;
3948
+ return table;
3949
+ }
3950
+ clearCache() {
3839
3951
  this.stateCache.clear();
3840
3952
  this.stateCount = 0;
3841
- for (let i = 0; i < survivorsArray.length; i++) {
3842
- const state = survivorsArray[i];
3843
- state.nextLatin1.fill(null);
3844
- state.nextLatin1Anchored.fill(null);
3845
- state.transKeys.length = 0;
3846
- state.transVals.length = 0;
3847
- const hash = hashPCs(state.nfaStates);
3848
- let bucket = this.stateCache.get(hash);
3849
- if (!bucket) {
3850
- bucket = [];
3851
- this.stateCache.set(hash, bucket);
3852
- }
3853
- bucket.push(state);
3854
- this.stateCount++;
3855
- }
3856
- if (this.startState && !survivors.has(this.startState)) this.startState = null;
3857
- }
3858
- step(state, charCode, anchor) {
3859
- if (charCode <= Unicode.MAX_LATIN1) if (anchor === RE2Flags.UNANCHORED) {
3860
- const next = state.nextLatin1[charCode];
3861
- if (next !== null) return next;
3953
+ this.startState = null;
3954
+ this.memBudget = this.stateBudget;
3955
+ }
3956
+ resetCache(current) {
3957
+ this.clearCache();
3958
+ return this.getState(current.nfaStates);
3959
+ }
3960
+ step(state, cls, rune, anchor) {
3961
+ let table = anchor === RE2Flags.UNANCHORED ? state.next : state.nextAnchored;
3962
+ if (table !== null) {
3963
+ const cached = table[cls];
3964
+ if (cached !== null) return cached;
3862
3965
  } else {
3863
- const next = state.nextLatin1Anchored[charCode];
3864
- if (next !== null) return next;
3865
- }
3866
- else {
3867
- const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
3868
- const keys = state.transKeys;
3869
- const len = keys.length;
3870
- for (let i = 0; i < len; i++) if (keys[i] === key) return state.transVals[i];
3966
+ table = this.allocTable(state, anchor);
3967
+ if (table === null) return null;
3871
3968
  }
3872
3969
  const nextPCs = [];
3873
3970
  for (let i = 0; i < state.nfaStates.length; i++) {
3874
3971
  const pc = state.nfaStates[i];
3875
3972
  const inst = this.prog.getInst(pc);
3876
- if (Inst.isRuneOp(inst.op) && inst.matchRune(charCode)) nextPCs.push(inst.out);
3973
+ if (Inst.isRuneOp(inst.op) && inst.matchRune(rune)) nextPCs.push(inst.out);
3877
3974
  }
3878
3975
  if (anchor === RE2Flags.UNANCHORED) nextPCs.push(this.prog.start);
3879
3976
  const nextState = this.getState(nextPCs);
3880
- if (charCode <= Unicode.MAX_LATIN1) if (anchor === RE2Flags.UNANCHORED) state.nextLatin1[charCode] = nextState;
3881
- else state.nextLatin1Anchored[charCode] = nextState;
3882
- else {
3883
- const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
3884
- state.transKeys.push(key);
3885
- state.transVals.push(nextState);
3886
- }
3977
+ if (nextState === null) return null;
3978
+ table[cls] = nextState;
3887
3979
  return nextState;
3888
3980
  }
3889
- match(input, pos, anchor) {
3890
- if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
3891
- if (!this.startState) {
3981
+ start() {
3982
+ if (this.startState === null) {
3892
3983
  this.startState = this.getState([this.prog.start]);
3893
- if (!this.startState) return null;
3984
+ if (this.startState === null && !this.failed) {
3985
+ this.clearCache();
3986
+ this.startState = this.getState([this.prog.start]);
3987
+ }
3894
3988
  }
3895
- let endPos = input.endPos();
3896
- let currentState = this.startState;
3897
- if (currentState.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
3898
- if (pos === endPos) return true;
3899
- } else return true;
3989
+ return this.startState;
3990
+ }
3991
+ run(input, pos, anchor, state, onState, noMatch) {
3992
+ const endPos = input.endPos();
3993
+ const latin1Class = this.latin1Class;
3994
+ let resetPos = -1;
3900
3995
  let i = pos;
3901
3996
  while (i < endPos) {
3902
3997
  const r = input.step(i);
3903
3998
  const rune = r >> 3;
3904
3999
  const width = r & 7;
3905
4000
  if (width === 0) break;
3906
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
3907
- if (currentState === null) return null;
3908
- currentState.lastSeen = ++this.clock;
3909
- if (currentState.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
3910
- if (i + width === endPos) return true;
3911
- } else return true;
3912
- if (currentState.nfaStates.length === 0) {
3913
- if (anchor !== RE2Flags.UNANCHORED) return false;
4001
+ const cls = rune <= Unicode.MAX_LATIN1 ? latin1Class[rune] : this.runeClass(rune);
4002
+ let next = anchor === RE2Flags.UNANCHORED && state.next !== null ? state.next[cls] : null;
4003
+ if (next === null) {
4004
+ next = this.step(state, cls, rune, anchor);
4005
+ if (next === null) {
4006
+ if (resetPos >= 0 && i - resetPos < DFA2.PROGRESS_PER_STATE * this.stateCount) return null;
4007
+ resetPos = i;
4008
+ state = this.resetCache(state);
4009
+ if (state === null) return null;
4010
+ next = this.step(state, cls, rune, anchor);
4011
+ if (next === null) return null;
4012
+ }
3914
4013
  }
4014
+ state = next;
3915
4015
  i += width;
4016
+ const result = onState(state, i);
4017
+ if (result !== null) return result;
4018
+ if (state.nfaStates.length === 0 && anchor !== RE2Flags.UNANCHORED) return noMatch;
3916
4019
  }
3917
- return false;
4020
+ return noMatch;
4021
+ }
4022
+ match(input, pos, anchor) {
4023
+ if (this.failed) return null;
4024
+ if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
4025
+ const startState = this.start();
4026
+ if (startState === null) return null;
4027
+ const endPos = input.endPos();
4028
+ if (startState.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || pos === endPos)) return true;
4029
+ return this.run(input, pos, anchor, startState, (state, nextPos) => {
4030
+ if (state.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || nextPos === endPos)) return true;
4031
+ return null;
4032
+ }, false);
3918
4033
  }
3919
4034
  matchSet(input, pos, anchor) {
4035
+ if (this.failed) return null;
3920
4036
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return [];
3921
- if (!this.startState) {
3922
- this.startState = this.getState([this.prog.start]);
3923
- if (!this.startState) return null;
3924
- }
3925
- let endPos = input.endPos();
3926
- let currentState = this.startState;
4037
+ const startState = this.start();
4038
+ if (startState === null) return null;
4039
+ const endPos = input.endPos();
3927
4040
  const matches = /* @__PURE__ */ new Set();
3928
- const checkMatch = (state, currentPos) => {
3929
- if (state.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
3930
- if (currentPos === endPos) state.matchIDs.forEach((id) => matches.add(id));
3931
- } else state.matchIDs.forEach((id) => matches.add(id));
4041
+ const collect = (state, currentPos) => {
4042
+ if (state.isMatch && (anchor !== RE2Flags.ANCHOR_BOTH || currentPos === endPos)) for (let k = 0; k < state.matchIDs.length; k++) matches.add(state.matchIDs[k]);
4043
+ return null;
3932
4044
  };
3933
- checkMatch(currentState, pos);
3934
- let i = pos;
3935
- while (i < endPos) {
3936
- const r = input.step(i);
3937
- const rune = r >> 3;
3938
- const width = r & 7;
3939
- if (width === 0) break;
3940
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
3941
- if (currentState === null) return null;
3942
- currentState.lastSeen = ++this.clock;
3943
- i += width;
3944
- checkMatch(currentState, i);
3945
- if (currentState.nfaStates.length === 0) {
3946
- if (anchor !== RE2Flags.UNANCHORED) break;
3947
- }
3948
- }
4045
+ collect(startState, pos);
4046
+ if (this.run(input, pos, anchor, startState, collect, false) === null) return null;
3949
4047
  return Array.from(matches).sort((a, b) => a - b);
3950
4048
  }
3951
4049
  };
3952
4050
  var VISITED_BITS = 32;
3953
4051
  var MAX_BACKTRACK_PROG = 500;
3954
4052
  var INITIAL_JOB_CAPACITY = 256;
3955
- var MAX_BACKTRACK_VECTOR = 256 * 1024;
4053
+ var MAX_BACKTRACK_VECTOR = 262144;
3956
4054
  var BitState = class {
3957
4055
  constructor() {
3958
4056
  this.end = 0;
@@ -4238,7 +4336,7 @@ var OnePassProg = class {
4238
4336
  const inst = new Inst(orig.op);
4239
4337
  inst.out = orig.out;
4240
4338
  inst.arg = orig.arg;
4241
- inst.runes = orig.runes ? orig.runes.slice() : [];
4339
+ inst.runes = orig.runes ? new Int32Array(orig.runes) : /* @__PURE__ */ new Int32Array(0);
4242
4340
  inst.next = null;
4243
4341
  this.inst[i] = inst;
4244
4342
  }
@@ -4308,7 +4406,7 @@ var makeOnePass = (p) => {
4308
4406
  const rightRunes = onePassRunes[inst.arg] || [];
4309
4407
  const mergeRes = mergeRuneSets(leftRunes, rightRunes, inst.out, inst.arg);
4310
4408
  if (!mergeRes) return false;
4311
- onePassRunes[pc] = mergeRes.merged;
4409
+ onePassRunes[pc] = new Int32Array(mergeRes.merged);
4312
4410
  inst.next = new Uint32Array(mergeRes.next);
4313
4411
  break;
4314
4412
  }
@@ -4317,7 +4415,7 @@ var makeOnePass = (p) => {
4317
4415
  case Inst.NOP:
4318
4416
  ok = check(inst.out);
4319
4417
  m[pc] = m[inst.out];
4320
- onePassRunes[pc] = onePassRunes[inst.out] ? onePassRunes[inst.out].slice() : [];
4418
+ onePassRunes[pc] = onePassRunes[inst.out] ? new Int32Array(onePassRunes[inst.out]) : /* @__PURE__ */ new Int32Array(0);
4321
4419
  inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
4322
4420
  break;
4323
4421
  case Inst.MATCH:
@@ -4329,7 +4427,7 @@ var makeOnePass = (p) => {
4329
4427
  if (inst.next && inst.next.length > 0) break;
4330
4428
  instQueue.insert(inst.out);
4331
4429
  if (!inst.runes || inst.runes.length === 0) {
4332
- onePassRunes[pc] = [];
4430
+ onePassRunes[pc] = /* @__PURE__ */ new Int32Array(0);
4333
4431
  inst.next = new Uint32Array([inst.out]);
4334
4432
  break;
4335
4433
  }
@@ -4340,7 +4438,7 @@ var makeOnePass = (p) => {
4340
4438
  for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
4341
4439
  runes.sort((a, b) => a - b);
4342
4440
  } else for (let j = 0; j < inst.runes.length; j++) runes.push(inst.runes[j]);
4343
- onePassRunes[pc] = runes;
4441
+ onePassRunes[pc] = new Int32Array(runes);
4344
4442
  inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
4345
4443
  inst.op = Inst.RUNE;
4346
4444
  break;
@@ -4356,7 +4454,7 @@ var makeOnePass = (p) => {
4356
4454
  for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
4357
4455
  runes.sort((a, b) => a - b);
4358
4456
  } else runes.push(inst.runes[0], inst.runes[0]);
4359
- onePassRunes[pc] = runes;
4457
+ onePassRunes[pc] = new Int32Array(runes);
4360
4458
  inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
4361
4459
  inst.op = Inst.RUNE;
4362
4460
  break;
@@ -4365,21 +4463,20 @@ var makeOnePass = (p) => {
4365
4463
  m[pc] = false;
4366
4464
  if (inst.next && inst.next.length > 0) break;
4367
4465
  instQueue.insert(inst.out);
4368
- onePassRunes[pc] = [0, Unicode.MAX_RUNE];
4466
+ onePassRunes[pc] = new Int32Array([0, Unicode.MAX_RUNE]);
4369
4467
  inst.next = new Uint32Array([inst.out]);
4370
4468
  break;
4371
4469
  case Inst.RUNE_ANY_NOT_NL:
4372
4470
  m[pc] = false;
4373
4471
  if (inst.next && inst.next.length > 0) break;
4374
4472
  instQueue.insert(inst.out);
4375
- onePassRunes[pc] = [
4473
+ onePassRunes[pc] = new Int32Array([
4376
4474
  0,
4377
4475
  9,
4378
4476
  11,
4379
4477
  Unicode.MAX_RUNE
4380
- ];
4478
+ ]);
4381
4479
  inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
4382
- break;
4383
4480
  }
4384
4481
  return ok;
4385
4482
  };
@@ -4412,8 +4509,7 @@ var cleanupOnePass = (p, original) => {
4412
4509
  case Inst.RUNE_ANY_NOT_NL:
4413
4510
  p.inst[ix].next = null;
4414
4511
  p.inst[ix].op = instOriginal.op;
4415
- p.inst[ix].runes = instOriginal.runes ? instOriginal.runes.slice() : [];
4416
- break;
4512
+ p.inst[ix].runes = instOriginal.runes ? new Int32Array(instOriginal.runes) : /* @__PURE__ */ new Int32Array(0);
4417
4513
  }
4418
4514
  }
4419
4515
  };
@@ -4444,7 +4540,6 @@ var OnePass = class OnePass2 {
4444
4540
  break;
4445
4541
  default:
4446
4542
  if (opOut === Inst.MATCH && hasAlt) return null;
4447
- break;
4448
4543
  }
4449
4544
  }
4450
4545
  let p = onePassCopy(prog);
@@ -4592,7 +4687,7 @@ var Regexp = class Regexp2 {
4592
4687
  this.op = op;
4593
4688
  this.flags = 0;
4594
4689
  this.subs = Regexp2.emptySubs();
4595
- this.runes = [];
4690
+ this.runes = /* @__PURE__ */ new Int32Array(0);
4596
4691
  this.min = 0;
4597
4692
  this.max = 0;
4598
4693
  this.cap = 0;
@@ -4603,7 +4698,7 @@ var Regexp = class Regexp2 {
4603
4698
  reinit() {
4604
4699
  this.flags = 0;
4605
4700
  this.subs = Regexp2.emptySubs();
4606
- this.runes = [];
4701
+ this.runes = /* @__PURE__ */ new Int32Array(0);
4607
4702
  this.cap = 0;
4608
4703
  this.min = 0;
4609
4704
  this.max = 0;
@@ -4647,7 +4742,6 @@ var Regexp = class Regexp2 {
4647
4742
  if (this.max >= 0) out += this.max;
4648
4743
  }
4649
4744
  out += "}";
4650
- break;
4651
4745
  }
4652
4746
  if ((this.flags & RE2Flags.NON_GREEDY) !== 0) out += "?";
4653
4747
  break;
@@ -4742,7 +4836,6 @@ var Regexp = class Regexp2 {
4742
4836
  break;
4743
4837
  default:
4744
4838
  out += this.op;
4745
- break;
4746
4839
  }
4747
4840
  return out;
4748
4841
  }
@@ -4788,66 +4881,137 @@ var Regexp = class Regexp2 {
4788
4881
  case Regexp2.Op.PLB:
4789
4882
  case Regexp2.Op.NLB:
4790
4883
  if (this.lb !== that.lb || !this.subs[0].equals(that.subs[0])) return false;
4791
- break;
4792
4884
  }
4793
4885
  return true;
4794
4886
  }
4795
4887
  };
4888
+ var RegexpWalker = class {
4889
+ static walk(root, handler) {
4890
+ const stack = [];
4891
+ let re2 = root;
4892
+ let result;
4893
+ for (; ; ) {
4894
+ if (re2.subs.length === 0) result = handler.leaf(re2);
4895
+ else {
4896
+ const state = handler.enter(re2);
4897
+ if (state.result === void 0) {
4898
+ stack.push({
4899
+ re: re2,
4900
+ state,
4901
+ i: 0
4902
+ });
4903
+ re2 = re2.subs[0];
4904
+ continue;
4905
+ }
4906
+ result = state.result;
4907
+ }
4908
+ for (; ; ) {
4909
+ if (stack.length === 0) return result;
4910
+ const frame = stack[stack.length - 1];
4911
+ handler.child(frame.re, frame.state, result, frame.i);
4912
+ frame.i++;
4913
+ if (frame.state.result === void 0 && frame.i < frame.re.subs.length) {
4914
+ re2 = frame.re.subs[frame.i];
4915
+ break;
4916
+ }
4917
+ stack.pop();
4918
+ result = frame.state.result !== void 0 ? frame.state.result : handler.leave(frame.re, frame.state);
4919
+ }
4920
+ }
4921
+ }
4922
+ };
4796
4923
  var AhoCorasick = class {
4797
- constructor(wordArrays) {
4798
- this.next = [/* @__PURE__ */ Object.create(null)];
4799
- this.fail = [0];
4800
- this.match = [false];
4801
- for (const word of wordArrays) {
4924
+ constructor(words, alphabetSize) {
4925
+ const edges = /* @__PURE__ */ new Map();
4926
+ const parent = [0];
4927
+ const unit = [0];
4928
+ const depth = [0];
4929
+ const terminal = [0];
4930
+ for (const word of words) {
4802
4931
  let node = 0;
4803
4932
  for (let i = 0; i < word.length; i++) {
4804
- const val = word[i];
4805
- if (!(val in this.next[node])) {
4806
- this.next.push(/* @__PURE__ */ Object.create(null));
4807
- this.fail.push(0);
4808
- this.match.push(false);
4809
- this.next[node][val] = this.next.length - 1;
4933
+ const key = node * alphabetSize + word[i];
4934
+ let child = edges.get(key);
4935
+ if (child === void 0) {
4936
+ child = parent.length;
4937
+ edges.set(key, child);
4938
+ parent.push(node);
4939
+ unit.push(word[i]);
4940
+ depth.push(depth[node] + 1);
4941
+ terminal.push(0);
4942
+ }
4943
+ node = child;
4944
+ }
4945
+ terminal[node] = 1;
4946
+ }
4947
+ const numNodes = parent.length;
4948
+ const children = new Int32Array(numNodes - 1);
4949
+ for (let c = 1; c < numNodes; c++) children[c - 1] = c;
4950
+ children.sort((a, b) => parent[a] - parent[b] || unit[a] - unit[b]);
4951
+ const childStart = new Int32Array(numNodes + 1);
4952
+ for (let c = 1; c < numNodes; c++) childStart[parent[c] + 1]++;
4953
+ for (let n = 0; n < numNodes; n++) childStart[n + 1] += childStart[n];
4954
+ const childUnit = new Int32Array(numNodes - 1);
4955
+ for (let k = 0; k < children.length; k++) childUnit[k] = unit[children[k]];
4956
+ this.childStart = childStart;
4957
+ this.childUnit = childUnit;
4958
+ this.childNode = children;
4959
+ const byDepth = new Int32Array(numNodes);
4960
+ for (let n = 0; n < numNodes; n++) byDepth[n] = n;
4961
+ byDepth.sort((a, b) => depth[a] - depth[b]);
4962
+ const fail = new Int32Array(numNodes);
4963
+ const match = Uint8Array.from(terminal);
4964
+ for (let k = 1; k < numNodes; k++) {
4965
+ const c = byDepth[k];
4966
+ const p = parent[c];
4967
+ if (p !== 0) {
4968
+ let f = fail[p];
4969
+ let next = this.next(f, unit[c]);
4970
+ while (next < 0 && f !== 0) {
4971
+ f = fail[f];
4972
+ next = this.next(f, unit[c]);
4810
4973
  }
4811
- node = this.next[node][val];
4974
+ fail[c] = next >= 0 ? next : 0;
4812
4975
  }
4813
- this.match[node] = true;
4976
+ match[c] |= match[fail[c]];
4814
4977
  }
4815
- const queue = [];
4816
- for (const val in this.next[0]) if (Object.prototype.hasOwnProperty.call(this.next[0], val)) {
4817
- const child = this.next[0][val];
4818
- this.fail[child] = 0;
4819
- queue.push(child);
4978
+ this.fail = fail;
4979
+ this.match = match;
4980
+ }
4981
+ next(node, u) {
4982
+ let lo = this.childStart[node];
4983
+ let hi = this.childStart[node + 1];
4984
+ const units = this.childUnit;
4985
+ while (lo < hi) {
4986
+ const mid = lo + hi >> 1;
4987
+ const m = units[mid];
4988
+ if (m === u) return this.childNode[mid];
4989
+ if (m < u) lo = mid + 1;
4990
+ else hi = mid;
4820
4991
  }
4821
- while (queue.length > 0) {
4822
- const curr = queue.shift();
4823
- for (const val in this.next[curr]) if (Object.prototype.hasOwnProperty.call(this.next[curr], val)) {
4824
- const child = this.next[curr][val];
4825
- let failNode = this.fail[curr];
4826
- while (failNode !== 0 && !(val in this.next[failNode])) failNode = this.fail[failNode];
4827
- if (val in this.next[failNode]) this.fail[child] = this.next[failNode][val];
4828
- else this.fail[child] = 0;
4829
- this.match[child] = this.match[child] || this.match[this.fail[child]];
4830
- queue.push(child);
4831
- }
4992
+ return -1;
4993
+ }
4994
+ advance(node, u) {
4995
+ for (; ; ) {
4996
+ const next = this.next(node, u);
4997
+ if (next >= 0) return next;
4998
+ if (node === 0) return 0;
4999
+ node = this.fail[node];
4832
5000
  }
4833
5001
  }
4834
5002
  searchUTF16(charSeq, start, end) {
4835
5003
  let node = 0;
4836
5004
  for (let i = start; i < end; i++) {
4837
- const val = charSeq.charCodeAt(i);
4838
- while (node !== 0 && !(val in this.next[node])) node = this.fail[node];
4839
- if (val in this.next[node]) node = this.next[node][val];
4840
- if (this.match[node]) return true;
5005
+ node = this.advance(node, charSeq.charCodeAt(i));
5006
+ if (this.match[node] === 1) return true;
4841
5007
  }
4842
5008
  return false;
4843
5009
  }
4844
5010
  searchUTF8(bytes, start, end) {
4845
5011
  let node = 0;
4846
5012
  for (let i = start; i < end; i++) {
4847
- const val = bytes[i];
4848
- while (node !== 0 && !(val in this.next[node])) node = this.fail[node];
4849
- if (val in this.next[node]) node = this.next[node][val];
4850
- if (this.match[node]) return true;
5013
+ node = this.advance(node, bytes[i]);
5014
+ if (this.match[node] === 1) return true;
4851
5015
  }
4852
5016
  return false;
4853
5017
  }
@@ -4859,14 +5023,33 @@ var Prefilter = class Prefilter2 {
4859
5023
  AND: 2,
4860
5024
  OR: 3
4861
5025
  };
5026
+ static MAX_SCANS = 32;
5027
+ static MAX_AC_UNITS = 1 << 18;
4862
5028
  constructor(type) {
4863
5029
  this.type = type;
4864
5030
  this.subs = [];
4865
5031
  this.str = "";
4866
5032
  this.bytes = null;
5033
+ this.cost = type === Prefilter2.Type.EXACT ? 1 : 0;
5034
+ this.allExact = false;
4867
5035
  this.ac16 = null;
4868
5036
  this.ac8 = null;
4869
5037
  }
5038
+ automaton16() {
5039
+ if (this.ac16 === null) {
5040
+ const words = this.subs.map((s) => {
5041
+ const arr = new Array(s.str.length);
5042
+ for (let i = 0; i < s.str.length; i++) arr[i] = s.str.charCodeAt(i);
5043
+ return arr;
5044
+ });
5045
+ this.ac16 = new AhoCorasick(words, 65536);
5046
+ }
5047
+ return this.ac16;
5048
+ }
5049
+ automaton8() {
5050
+ if (this.ac8 === null) this.ac8 = new AhoCorasick(this.subs.map((s) => s.bytes), 256);
5051
+ return this.ac8;
5052
+ }
4870
5053
  eval(input, pos) {
4871
5054
  switch (this.type) {
4872
5055
  case Prefilter2.Type.NONE:
@@ -4877,7 +5060,7 @@ var Prefilter = class Prefilter2 {
4877
5060
  for (let i = 0; i < this.subs.length; i++) if (!this.subs[i].eval(input, pos)) return false;
4878
5061
  return true;
4879
5062
  case Prefilter2.Type.OR:
4880
- if (this.ac16 && this.ac8) return input.hasAnyString(this, pos);
5063
+ if (this.allExact) return input.hasAnyString(this, pos);
4881
5064
  for (let i = 0; i < this.subs.length; i++) if (this.subs[i].eval(input, pos)) return true;
4882
5065
  return false;
4883
5066
  default:
@@ -4887,103 +5070,119 @@ var Prefilter = class Prefilter2 {
4887
5070
  };
4888
5071
  var PrefilterTree = class PrefilterTree2 {
4889
5072
  static build(re2) {
4890
- const pf = PrefilterTree2.fromRegexp(re2);
4891
- return PrefilterTree2.simplify(pf);
4892
- }
4893
- static fromRegexp(re2) {
4894
5073
  if (!re2) return new Prefilter(Prefilter.Type.NONE);
5074
+ return RegexpWalker.walk(re2, PrefilterTree2.WALKER);
5075
+ }
5076
+ static WALKER = {
5077
+ leaf: (re2) => PrefilterTree2.leaf(re2),
5078
+ enter: (re2) => PrefilterTree2.enter(re2),
5079
+ child: (re2, state, result) => PrefilterTree2.child(re2, state, result),
5080
+ leave: (re2, state) => PrefilterTree2.leave(re2, state)
5081
+ };
5082
+ static leaf(re2) {
5083
+ if (re2.op !== Regexp.Op.LITERAL) return new Prefilter(Prefilter.Type.NONE);
5084
+ if (re2.runes.length === 0 || (re2.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
5085
+ let str = "";
5086
+ for (let i = 0; i < re2.runes.length; i++) {
5087
+ if (Unicode.isUnsearchable(re2.runes[i])) return new Prefilter(Prefilter.Type.NONE);
5088
+ str += String.fromCodePoint(re2.runes[i]);
5089
+ }
5090
+ const pf = new Prefilter(Prefilter.Type.EXACT);
5091
+ pf.str = str;
5092
+ pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
5093
+ return pf;
5094
+ }
5095
+ static enter(re2) {
4895
5096
  switch (re2.op) {
4896
- case Regexp.Op.PLB:
4897
- case Regexp.Op.NLB:
4898
- case Regexp.Op.NO_MATCH:
4899
- case Regexp.Op.EMPTY_MATCH:
4900
- case Regexp.Op.BEGIN_LINE:
4901
- case Regexp.Op.END_LINE:
4902
- case Regexp.Op.BEGIN_TEXT:
4903
- case Regexp.Op.END_TEXT:
4904
- case Regexp.Op.WORD_BOUNDARY:
4905
- case Regexp.Op.NO_WORD_BOUNDARY:
4906
- case Regexp.Op.CHAR_CLASS:
4907
- case Regexp.Op.ANY_CHAR_NOT_NL:
4908
- case Regexp.Op.ANY_CHAR:
4909
- return new Prefilter(Prefilter.Type.NONE);
4910
- case Regexp.Op.LITERAL: {
4911
- if (re2.runes.length === 0 || (re2.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
4912
- const pf = new Prefilter(Prefilter.Type.EXACT);
4913
- let str = "";
4914
- for (let i = 0; i < re2.runes.length; i++) str += String.fromCodePoint(re2.runes[i]);
4915
- pf.str = str;
4916
- pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
4917
- return pf;
4918
- }
4919
5097
  case Regexp.Op.CAPTURE:
4920
5098
  case Regexp.Op.PLUS:
4921
- return PrefilterTree2.fromRegexp(re2.subs[0]);
5099
+ return { sub: null };
4922
5100
  case Regexp.Op.REPEAT:
4923
- if (re2.min >= 1) return PrefilterTree2.fromRegexp(re2.subs[0]);
4924
- return new Prefilter(Prefilter.Type.NONE);
4925
- case Regexp.Op.CONCAT: {
4926
- const pf = new Prefilter(Prefilter.Type.AND);
4927
- for (const sub of re2.subs) pf.subs.push(PrefilterTree2.fromRegexp(sub));
4928
- return pf;
4929
- }
4930
- case Regexp.Op.ALTERNATE: {
4931
- const pf = new Prefilter(Prefilter.Type.OR);
4932
- for (const sub of re2.subs) pf.subs.push(PrefilterTree2.fromRegexp(sub));
4933
- return pf;
4934
- }
5101
+ if (re2.min >= 1) return { sub: null };
5102
+ return { result: new Prefilter(Prefilter.Type.NONE) };
5103
+ case Regexp.Op.CONCAT:
5104
+ return {
5105
+ pf: new Prefilter(Prefilter.Type.AND),
5106
+ subs: []
5107
+ };
5108
+ case Regexp.Op.ALTERNATE:
5109
+ return {
5110
+ pf: new Prefilter(Prefilter.Type.OR),
5111
+ subs: []
5112
+ };
4935
5113
  default:
4936
- return new Prefilter(Prefilter.Type.NONE);
5114
+ return { result: new Prefilter(Prefilter.Type.NONE) };
4937
5115
  }
4938
5116
  }
4939
- static simplify(pf) {
4940
- if (pf.type === Prefilter.Type.EXACT || pf.type === Prefilter.Type.NONE) return pf;
4941
- if (pf.type === Prefilter.Type.AND) {
4942
- const newSubs = [];
4943
- for (const sub of pf.subs) {
4944
- const s = PrefilterTree2.simplify(sub);
4945
- if (s.type !== Prefilter.Type.NONE) if (s.type === Prefilter.Type.AND) for (let j = 0; j < s.subs.length; j++) newSubs.push(s.subs[j]);
4946
- else newSubs.push(s);
4947
- }
4948
- if (newSubs.length === 0) return new Prefilter(Prefilter.Type.NONE);
4949
- if (newSubs.length === 1) return newSubs[0];
4950
- pf.subs = newSubs;
4951
- return pf;
5117
+ static child(re2, state, s) {
5118
+ if (state.subs === void 0) {
5119
+ state.sub = s;
5120
+ return;
4952
5121
  }
4953
- if (pf.type === Prefilter.Type.OR) {
4954
- const newSubs = [];
4955
- for (const sub of pf.subs) {
4956
- const s = PrefilterTree2.simplify(sub);
4957
- if (s.type === Prefilter.Type.NONE) return new Prefilter(Prefilter.Type.NONE);
4958
- if (s.type === Prefilter.Type.OR) for (let j = 0; j < s.subs.length; j++) newSubs.push(s.subs[j]);
4959
- else newSubs.push(s);
4960
- }
4961
- if (newSubs.length === 0) return new Prefilter(Prefilter.Type.NONE);
4962
- if (newSubs.length === 1) return newSubs[0];
4963
- const seen = /* @__PURE__ */ new Set();
4964
- const uniqueSubs = [];
4965
- for (const sub of newSubs) if (sub.type === Prefilter.Type.EXACT) {
4966
- if (!seen.has(sub.str)) {
4967
- seen.add(sub.str);
4968
- uniqueSubs.push(sub);
4969
- }
4970
- } else uniqueSubs.push(sub);
4971
- pf.subs = uniqueSubs;
4972
- let allExact = true;
4973
- for (const sub of uniqueSubs) if (sub.type !== Prefilter.Type.EXACT) {
4974
- allExact = false;
4975
- break;
5122
+ if (state.pf.type === Prefilter.Type.AND) {
5123
+ if (s.type === Prefilter.Type.NONE) return;
5124
+ if (s.type === Prefilter.Type.AND) {
5125
+ for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
5126
+ return;
4976
5127
  }
4977
- if (allExact && uniqueSubs.length > 1) {
4978
- pf.ac16 = new AhoCorasick(uniqueSubs.map((s) => {
4979
- const arr = [];
4980
- for (let i = 0; i < s.str.length; i++) arr.push(s.str.charCodeAt(i));
4981
- return arr;
4982
- }));
4983
- pf.ac8 = new AhoCorasick(uniqueSubs.map((s) => s.bytes));
5128
+ state.subs.push(s);
5129
+ return;
5130
+ }
5131
+ if (s.type === Prefilter.Type.NONE) {
5132
+ state.result = new Prefilter(Prefilter.Type.NONE);
5133
+ return;
5134
+ }
5135
+ if (s.type === Prefilter.Type.OR) {
5136
+ for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
5137
+ return;
5138
+ }
5139
+ state.subs.push(s);
5140
+ }
5141
+ static leave(re2, state) {
5142
+ if (state.subs === void 0) return state.sub;
5143
+ const pf = state.pf;
5144
+ const seen = /* @__PURE__ */ new Set();
5145
+ const subs = [];
5146
+ for (const sub of state.subs) {
5147
+ if (sub.type === Prefilter.Type.EXACT) {
5148
+ if (seen.has(sub.str)) continue;
5149
+ seen.add(sub.str);
4984
5150
  }
5151
+ subs.push(sub);
5152
+ }
5153
+ if (pf.type === Prefilter.Type.AND) {
5154
+ const kept = [];
5155
+ let cost2 = 0;
5156
+ for (const sub of subs) {
5157
+ if (cost2 + sub.cost > Prefilter.MAX_SCANS) continue;
5158
+ kept.push(sub);
5159
+ cost2 += sub.cost;
5160
+ }
5161
+ if (kept.length === 0) return new Prefilter(Prefilter.Type.NONE);
5162
+ if (kept.length === 1) return kept[0];
5163
+ pf.subs = kept;
5164
+ pf.cost = cost2;
5165
+ return pf;
5166
+ }
5167
+ if (subs.length === 0) return new Prefilter(Prefilter.Type.NONE);
5168
+ if (subs.length === 1) return subs[0];
5169
+ pf.subs = subs;
5170
+ let allExact = true;
5171
+ let cost = 0;
5172
+ let units = 0;
5173
+ for (const sub of subs) {
5174
+ if (sub.type !== Prefilter.Type.EXACT) allExact = false;
5175
+ else units += sub.bytes.length;
5176
+ cost += sub.cost;
5177
+ }
5178
+ if (allExact) {
5179
+ if (units > Prefilter.MAX_AC_UNITS) return new Prefilter(Prefilter.Type.NONE);
5180
+ pf.allExact = true;
5181
+ pf.cost = 1;
4985
5182
  return pf;
4986
5183
  }
5184
+ if (cost > Prefilter.MAX_SCANS) return new Prefilter(Prefilter.Type.NONE);
5185
+ pf.cost = cost;
4987
5186
  return pf;
4988
5187
  }
4989
5188
  };
@@ -5004,6 +5203,7 @@ var Prog = class {
5004
5203
  this.numCap = 2;
5005
5204
  this.lbStarts = [];
5006
5205
  this.numLb = 0;
5206
+ this.lbInst = null;
5007
5207
  }
5008
5208
  getInst(pc) {
5009
5209
  return this.inst[pc];
@@ -5014,6 +5214,28 @@ var Prog = class {
5014
5214
  addInst(op) {
5015
5215
  this.inst.push(new Inst(op));
5016
5216
  }
5217
+ markLookbehindInsts() {
5218
+ const lbInst = new Uint8Array(this.inst.length);
5219
+ const pending = this.lbStarts.slice();
5220
+ while (pending.length > 0) {
5221
+ const pc = pending.pop();
5222
+ if (pc === 0 || lbInst[pc] === 1) continue;
5223
+ lbInst[pc] = 1;
5224
+ const i = this.inst[pc];
5225
+ switch (i.op) {
5226
+ case Inst.ALT:
5227
+ case Inst.ALT_MATCH:
5228
+ pending.push(i.out, i.arg);
5229
+ break;
5230
+ case Inst.MATCH:
5231
+ case Inst.FAIL:
5232
+ break;
5233
+ default:
5234
+ pending.push(i.out);
5235
+ }
5236
+ }
5237
+ this.lbInst = lbInst;
5238
+ }
5017
5239
  skipNop(pc) {
5018
5240
  let i = this.inst[pc];
5019
5241
  while (i.op === Inst.NOP || i.op === Inst.CAPTURE) {
@@ -5026,7 +5248,7 @@ var Prog = class {
5026
5248
  let prefix = "";
5027
5249
  let i = this.skipNop(this.start);
5028
5250
  if (!Inst.isRuneOp(i.op) || i.runes.length !== 1) return [i.op === Inst.MATCH, prefix];
5029
- while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0) {
5251
+ while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0 && !Unicode.isUnsearchable(i.runes[0])) {
5030
5252
  prefix += String.fromCodePoint(i.runes[0]);
5031
5253
  i = this.skipNop(i.out);
5032
5254
  }
@@ -5091,6 +5313,13 @@ var Prog = class {
5091
5313
  return out;
5092
5314
  }
5093
5315
  };
5316
+ var ANY_RUNE_NOT_NL = new Int32Array([
5317
+ 0,
5318
+ Codepoint.CODES.get("\n") - 1,
5319
+ Codepoint.CODES.get("\n") + 1,
5320
+ Unicode.MAX_RUNE
5321
+ ]);
5322
+ var ANY_RUNE = new Int32Array([0, Unicode.MAX_RUNE]);
5094
5323
  var Frag = class {
5095
5324
  constructor(i = 0, out = new PatchList(), nullable = false) {
5096
5325
  this.i = i;
@@ -5099,28 +5328,19 @@ var Frag = class {
5099
5328
  }
5100
5329
  };
5101
5330
  var Compiler = class Compiler2 {
5102
- static ANY_RUNE_NOT_NL() {
5103
- return [
5104
- 0,
5105
- Codepoint.CODES.get("\n") - 1,
5106
- Codepoint.CODES.get("\n") + 1,
5107
- Unicode.MAX_RUNE
5108
- ];
5109
- }
5110
- static ANY_RUNE() {
5111
- return [0, Unicode.MAX_RUNE];
5112
- }
5113
5331
  static compileRegexp(re2) {
5114
5332
  const c = new Compiler2();
5115
5333
  const f = c.compile(re2);
5116
5334
  c.prog.patch(f.out, c.newInst(Inst.MATCH).i);
5117
5335
  c.prog.start = f.i;
5336
+ c.prog.markLookbehindInsts();
5118
5337
  return c.prog;
5119
5338
  }
5120
5339
  static compileSet(regexps) {
5121
5340
  const c = new Compiler2();
5122
5341
  if (regexps.length === 0) {
5123
5342
  c.prog.start = c.newInst(Inst.FAIL).i;
5343
+ c.prog.markLookbehindInsts();
5124
5344
  return c.prog;
5125
5345
  }
5126
5346
  let starts = [];
@@ -5140,11 +5360,19 @@ var Compiler = class Compiler2 {
5140
5360
  start = f.i;
5141
5361
  }
5142
5362
  c.prog.start = start;
5363
+ c.prog.markLookbehindInsts();
5143
5364
  return c.prog;
5144
5365
  }
5145
5366
  constructor() {
5146
5367
  this.prog = new Prog();
5147
5368
  this.newInst(Inst.FAIL);
5369
+ this.runeCache = /* @__PURE__ */ new Map();
5370
+ this.walker = {
5371
+ leaf: (re2) => this.leaf(re2),
5372
+ enter: (re2) => this.enter(re2),
5373
+ child: (re2, state, result) => this.child(re2, state, result),
5374
+ leave: (re2, state) => this.leave(re2, state)
5375
+ };
5148
5376
  }
5149
5377
  newInst(op) {
5150
5378
  this.prog.addInst(op);
@@ -5237,7 +5465,7 @@ var Compiler = class Compiler2 {
5237
5465
  lookBehind(a, lb) {
5238
5466
  const id = this.newInst(Inst.LB_WRITE);
5239
5467
  this.prog.getInst(id.i).arg = lb;
5240
- const any = this.rune(Compiler2.ANY_RUNE(), 0);
5468
+ const any = this.rune(ANY_RUNE, 0);
5241
5469
  const dotStar = this.star(any, true);
5242
5470
  const lbAutomaton = this.cat(dotStar, a);
5243
5471
  this.prog.patch(lbAutomaton.out, id.i);
@@ -5249,27 +5477,34 @@ var Compiler = class Compiler2 {
5249
5477
  return checkId;
5250
5478
  }
5251
5479
  compile(re2) {
5480
+ return RegexpWalker.walk(re2, this.walker);
5481
+ }
5482
+ leaf(re2) {
5252
5483
  switch (re2.op) {
5253
5484
  case Regexp.Op.NO_MATCH:
5254
5485
  return this.fail();
5255
5486
  case Regexp.Op.EMPTY_MATCH:
5256
5487
  return this.nop();
5257
- case Regexp.Op.LITERAL:
5488
+ case Regexp.Op.LITERAL: {
5258
5489
  if (re2.runes.length === 0) return this.nop();
5259
- else {
5260
- let f = null;
5261
- for (let r of re2.runes) {
5262
- const f1 = this.rune([r], re2.flags);
5263
- f = f === null ? f1 : this.cat(f, f1);
5490
+ let f = null;
5491
+ for (let r of re2.runes) {
5492
+ let singleRune = this.runeCache.get(r);
5493
+ if (singleRune === void 0) {
5494
+ singleRune = new Int32Array([r]);
5495
+ this.runeCache.set(r, singleRune);
5264
5496
  }
5265
- return f;
5497
+ const f1 = this.rune(singleRune, re2.flags);
5498
+ f = f === null ? f1 : this.cat(f, f1);
5266
5499
  }
5500
+ return f;
5501
+ }
5267
5502
  case Regexp.Op.CHAR_CLASS:
5268
5503
  return this.rune(re2.runes, re2.flags);
5269
5504
  case Regexp.Op.ANY_CHAR_NOT_NL:
5270
- return this.rune(Compiler2.ANY_RUNE_NOT_NL(), 0);
5505
+ return this.rune(ANY_RUNE_NOT_NL, 0);
5271
5506
  case Regexp.Op.ANY_CHAR:
5272
- return this.rune(Compiler2.ANY_RUNE(), 0);
5507
+ return this.rune(ANY_RUNE, 0);
5273
5508
  case Regexp.Op.BEGIN_LINE:
5274
5509
  return this.empty(Utils.EMPTY_BEGIN_LINE);
5275
5510
  case Regexp.Op.END_LINE:
@@ -5282,41 +5517,56 @@ var Compiler = class Compiler2 {
5282
5517
  return this.empty(Utils.EMPTY_WORD_BOUNDARY);
5283
5518
  case Regexp.Op.NO_WORD_BOUNDARY:
5284
5519
  return this.empty(Utils.EMPTY_NO_WORD_BOUNDARY);
5520
+ case Regexp.Op.CONCAT:
5521
+ case Regexp.Op.ALTERNATE:
5522
+ return this.nop();
5523
+ default:
5524
+ throw new RE2JSCompileException("regexp: unhandled case in compile");
5525
+ }
5526
+ }
5527
+ enter(re2) {
5528
+ switch (re2.op) {
5529
+ case Regexp.Op.PLB:
5530
+ case Regexp.Op.NLB:
5531
+ case Regexp.Op.STAR:
5532
+ case Regexp.Op.PLUS:
5533
+ case Regexp.Op.QUEST:
5534
+ return { sub: null };
5535
+ case Regexp.Op.CAPTURE:
5536
+ return {
5537
+ bra: this.cap(re2.cap << 1),
5538
+ sub: null
5539
+ };
5540
+ case Regexp.Op.CONCAT:
5541
+ case Regexp.Op.ALTERNATE:
5542
+ return { f: null };
5543
+ default:
5544
+ throw new RE2JSCompileException("regexp: unhandled case in compile");
5545
+ }
5546
+ }
5547
+ child(re2, state, f1) {
5548
+ if (re2.op === Regexp.Op.CONCAT) state.f = state.f === null ? f1 : this.cat(state.f, f1);
5549
+ else if (re2.op === Regexp.Op.ALTERNATE) state.f = state.f === null ? f1 : this.alt(state.f, f1);
5550
+ else state.sub = f1;
5551
+ }
5552
+ leave(re2, state) {
5553
+ switch (re2.op) {
5285
5554
  case Regexp.Op.PLB:
5286
5555
  case Regexp.Op.NLB:
5287
- return this.lookBehind(this.compile(re2.subs[0]), re2.lb);
5556
+ return this.lookBehind(state.sub, re2.lb);
5288
5557
  case Regexp.Op.CAPTURE: {
5289
- const bra = this.cap(re2.cap << 1);
5290
- const sub = this.compile(re2.subs[0]);
5291
5558
  const ket = this.cap(re2.cap << 1 | 1);
5292
- return this.cat(this.cat(bra, sub), ket);
5559
+ return this.cat(this.cat(state.bra, state.sub), ket);
5293
5560
  }
5294
5561
  case Regexp.Op.STAR:
5295
- return this.star(this.compile(re2.subs[0]), (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5562
+ return this.star(state.sub, (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5296
5563
  case Regexp.Op.PLUS:
5297
- return this.plus(this.compile(re2.subs[0]), (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5564
+ return this.plus(state.sub, (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5298
5565
  case Regexp.Op.QUEST:
5299
- return this.quest(this.compile(re2.subs[0]), (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5566
+ return this.quest(state.sub, (re2.flags & RE2Flags.NON_GREEDY) !== 0);
5300
5567
  case Regexp.Op.CONCAT:
5301
- if (re2.subs.length === 0) return this.nop();
5302
- else {
5303
- let f = null;
5304
- for (let sub of re2.subs) {
5305
- const f1 = this.compile(sub);
5306
- f = f === null ? f1 : this.cat(f, f1);
5307
- }
5308
- return f;
5309
- }
5310
5568
  case Regexp.Op.ALTERNATE:
5311
- if (re2.subs.length === 0) return this.nop();
5312
- else {
5313
- let f = null;
5314
- for (let sub of re2.subs) {
5315
- const f1 = this.compile(sub);
5316
- f = f === null ? f1 : this.alt(f, f1);
5317
- }
5318
- return f;
5319
- }
5569
+ return state.f;
5320
5570
  default:
5321
5571
  throw new RE2JSCompileException("regexp: unhandled case in compile");
5322
5572
  }
@@ -5325,111 +5575,155 @@ var Compiler = class Compiler2 {
5325
5575
  var Simplify = class Simplify2 {
5326
5576
  static simplify(re2) {
5327
5577
  if (re2 === null) return null;
5578
+ return RegexpWalker.walk(re2, Simplify2.WALKER);
5579
+ }
5580
+ static WALKER = {
5581
+ leaf: (re2) => Simplify2.leaf(re2),
5582
+ enter: (re2) => Simplify2.enter(re2),
5583
+ child: (re2, state, result, i) => Simplify2.child(re2, state, result, i),
5584
+ leave: (re2, state) => Simplify2.leave(re2, state)
5585
+ };
5586
+ static leaf(re2) {
5587
+ if (re2.op === Regexp.Op.CHAR_CLASS) {
5588
+ if (re2.runes === null) return re2;
5589
+ if (re2.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
5590
+ if (re2.runes.length === 2 && re2.runes[0] === 0 && re2.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
5591
+ if (re2.runes.length === 4 && re2.runes[0] === 0 && re2.runes[1] === Codepoint.CODES.get("\n") - 1 && re2.runes[2] === Codepoint.CODES.get("\n") + 1 && re2.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
5592
+ }
5593
+ return re2;
5594
+ }
5595
+ static enter(re2) {
5596
+ switch (re2.op) {
5597
+ case Regexp.Op.PLB:
5598
+ case Regexp.Op.NLB:
5599
+ case Regexp.Op.CAPTURE:
5600
+ case Regexp.Op.STAR:
5601
+ case Regexp.Op.PLUS:
5602
+ case Regexp.Op.QUEST:
5603
+ return { sub: null };
5604
+ case Regexp.Op.CONCAT:
5605
+ case Regexp.Op.ALTERNATE:
5606
+ return {
5607
+ subs: [],
5608
+ changed: false
5609
+ };
5610
+ case Regexp.Op.REPEAT:
5611
+ if (re2.min === 0 && re2.max === 0) return { result: new Regexp(Regexp.Op.EMPTY_MATCH) };
5612
+ return { sub: null };
5613
+ default:
5614
+ return { result: re2 };
5615
+ }
5616
+ }
5617
+ static child(re2, state, nsub, i) {
5618
+ if (state.subs === void 0) {
5619
+ state.sub = nsub;
5620
+ return;
5621
+ }
5622
+ if (nsub !== re2.subs[i]) state.changed = true;
5623
+ if (re2.op === Regexp.Op.CONCAT) {
5624
+ if (nsub.op === Regexp.Op.NO_MATCH) {
5625
+ state.result = new Regexp(Regexp.Op.NO_MATCH);
5626
+ return;
5627
+ }
5628
+ if (nsub.op === Regexp.Op.EMPTY_MATCH) {
5629
+ state.changed = true;
5630
+ return;
5631
+ }
5632
+ if (nsub.op === Regexp.Op.CONCAT) {
5633
+ state.changed = true;
5634
+ for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
5635
+ return;
5636
+ }
5637
+ } else {
5638
+ if (nsub.op === Regexp.Op.NO_MATCH) {
5639
+ state.changed = true;
5640
+ return;
5641
+ }
5642
+ if (nsub.op === Regexp.Op.ALTERNATE) {
5643
+ state.changed = true;
5644
+ for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
5645
+ return;
5646
+ }
5647
+ }
5648
+ state.subs.push(nsub);
5649
+ }
5650
+ static leave(re2, state) {
5328
5651
  switch (re2.op) {
5329
5652
  case Regexp.Op.PLB:
5330
5653
  case Regexp.Op.NLB:
5331
5654
  case Regexp.Op.CAPTURE: {
5332
- const sub = Simplify2.simplify(re2.subs[0]);
5655
+ const sub = state.sub;
5333
5656
  if (sub !== re2.subs[0]) {
5334
5657
  const nre = Regexp.fromRegexp(re2);
5335
- nre.runes = [];
5658
+ nre.runes = /* @__PURE__ */ new Int32Array(0);
5336
5659
  nre.subs = [sub];
5337
5660
  return nre;
5338
5661
  }
5339
5662
  return re2;
5340
5663
  }
5341
5664
  case Regexp.Op.CONCAT:
5342
- case Regexp.Op.ALTERNATE: {
5343
- const newSubs = [];
5344
- let changed = false;
5345
- for (let i = 0; i < re2.subs.length; i++) {
5346
- const sub = re2.subs[i];
5347
- const nsub = Simplify2.simplify(sub);
5348
- if (nsub !== sub) changed = true;
5349
- if (re2.op === Regexp.Op.CONCAT) {
5350
- if (nsub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
5351
- if (nsub.op === Regexp.Op.EMPTY_MATCH) {
5352
- changed = true;
5353
- continue;
5354
- }
5355
- if (nsub.op === Regexp.Op.CONCAT) {
5356
- changed = true;
5357
- for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
5358
- continue;
5359
- }
5360
- } else if (re2.op === Regexp.Op.ALTERNATE) {
5361
- if (nsub.op === Regexp.Op.NO_MATCH) {
5362
- changed = true;
5363
- continue;
5364
- }
5365
- if (nsub.op === Regexp.Op.ALTERNATE) {
5366
- changed = true;
5367
- for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
5368
- continue;
5369
- }
5370
- }
5371
- newSubs.push(nsub);
5372
- }
5373
- if (changed) {
5665
+ case Regexp.Op.ALTERNATE:
5666
+ if (state.changed) {
5667
+ const newSubs = state.subs;
5374
5668
  if (newSubs.length === 0) return new Regexp(re2.op === Regexp.Op.CONCAT ? Regexp.Op.EMPTY_MATCH : Regexp.Op.NO_MATCH);
5375
5669
  if (newSubs.length === 1) return newSubs[0];
5376
5670
  const nre = Regexp.fromRegexp(re2);
5377
- nre.runes = [];
5671
+ nre.runes = /* @__PURE__ */ new Int32Array(0);
5378
5672
  nre.subs = newSubs;
5379
5673
  return nre;
5380
5674
  }
5381
5675
  return re2;
5382
- }
5383
- case Regexp.Op.CHAR_CLASS:
5384
- if (re2.runes === null) return re2;
5385
- if (re2.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
5386
- if (re2.runes.length === 2 && re2.runes[0] === 0 && re2.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
5387
- if (re2.runes.length === 4 && re2.runes[0] === 0 && re2.runes[1] === Codepoint.CODES.get("\n") - 1 && re2.runes[2] === Codepoint.CODES.get("\n") + 1 && re2.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
5388
- return re2;
5389
5676
  case Regexp.Op.STAR:
5390
5677
  case Regexp.Op.PLUS:
5391
- case Regexp.Op.QUEST: {
5392
- const sub = Simplify2.simplify(re2.subs[0]);
5393
- return Simplify2.simplify1(re2.op, re2.flags, sub, re2);
5394
- }
5395
- case Regexp.Op.REPEAT: {
5396
- if (re2.min === 0 && re2.max === 0) return new Regexp(Regexp.Op.EMPTY_MATCH);
5397
- const sub = Simplify2.simplify(re2.subs[0]);
5398
- if (re2.max === -1) {
5399
- if (re2.min === 0) return Simplify2.simplify1(Regexp.Op.STAR, re2.flags, sub, null);
5400
- if (re2.min === 1) return Simplify2.simplify1(Regexp.Op.PLUS, re2.flags, sub, null);
5401
- const nre = new Regexp(Regexp.Op.CONCAT);
5402
- const subs = [];
5403
- for (let i = 0; i < re2.min - 1; i++) subs.push(sub);
5404
- subs.push(Simplify2.simplify1(Regexp.Op.PLUS, re2.flags, sub, null));
5405
- nre.subs = subs.slice(0);
5406
- return Simplify2.simplify(nre);
5407
- }
5408
- if (re2.min === 1 && re2.max === 1) return sub;
5409
- let prefixSubs = null;
5410
- if (re2.min > 0) {
5411
- prefixSubs = [];
5412
- for (let i = 0; i < re2.min; i++) prefixSubs.push(sub);
5413
- }
5414
- if (re2.max > re2.min) {
5415
- let suffix = Simplify2.simplify1(Regexp.Op.QUEST, re2.flags, sub, null);
5416
- for (let i = re2.min + 1; i < re2.max; i++) {
5417
- const nre2 = new Regexp(Regexp.Op.CONCAT);
5418
- nre2.subs = [sub, suffix];
5419
- suffix = Simplify2.simplify1(Regexp.Op.QUEST, re2.flags, nre2, null);
5420
- }
5421
- if (prefixSubs === null) return suffix;
5422
- prefixSubs.push(suffix);
5423
- }
5424
- if (prefixSubs !== null) {
5425
- const prefix = new Regexp(Regexp.Op.CONCAT);
5426
- prefix.subs = prefixSubs.slice(0);
5427
- return Simplify2.simplify(prefix);
5428
- }
5429
- return new Regexp(Regexp.Op.NO_MATCH);
5678
+ case Regexp.Op.QUEST:
5679
+ return Simplify2.simplify1(re2.op, re2.flags, state.sub, re2);
5680
+ case Regexp.Op.REPEAT:
5681
+ return Simplify2.simplifyRepeat(re2, state.sub);
5682
+ default:
5683
+ return re2;
5684
+ }
5685
+ }
5686
+ static simplifyRepeat(re2, sub) {
5687
+ if (re2.max === -1) {
5688
+ if (re2.min === 0) return Simplify2.simplify1(Regexp.Op.STAR, re2.flags, sub, null);
5689
+ if (re2.min === 1) return Simplify2.simplify1(Regexp.Op.PLUS, re2.flags, sub, null);
5690
+ const subs = [];
5691
+ for (let i = 0; i < re2.min - 1; i++) subs.push(sub);
5692
+ subs.push(Simplify2.simplify1(Regexp.Op.PLUS, re2.flags, sub, null));
5693
+ return Simplify2.concat(subs);
5694
+ }
5695
+ if (re2.min === 1 && re2.max === 1) return sub;
5696
+ let prefixSubs = null;
5697
+ if (re2.min > 0) {
5698
+ prefixSubs = [];
5699
+ for (let i = 0; i < re2.min; i++) prefixSubs.push(sub);
5700
+ }
5701
+ if (re2.max > re2.min) {
5702
+ let suffix = Simplify2.simplify1(Regexp.Op.QUEST, re2.flags, sub, null);
5703
+ for (let i = re2.min + 1; i < re2.max; i++) suffix = Simplify2.simplify1(Regexp.Op.QUEST, re2.flags, Simplify2.concat([sub, suffix]), null);
5704
+ if (prefixSubs === null) return suffix;
5705
+ prefixSubs.push(suffix);
5706
+ }
5707
+ if (prefixSubs !== null) return Simplify2.concat(prefixSubs);
5708
+ return new Regexp(Regexp.Op.NO_MATCH);
5709
+ }
5710
+ static concat(subs) {
5711
+ const newSubs = [];
5712
+ for (let i = 0; i < subs.length; i++) {
5713
+ const sub = subs[i];
5714
+ if (sub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
5715
+ if (sub.op === Regexp.Op.EMPTY_MATCH) continue;
5716
+ if (sub.op === Regexp.Op.CONCAT) {
5717
+ for (let j = 0; j < sub.subs.length; j++) newSubs.push(sub.subs[j]);
5718
+ continue;
5430
5719
  }
5720
+ newSubs.push(sub);
5431
5721
  }
5432
- return re2;
5722
+ if (newSubs.length === 0) return new Regexp(Regexp.Op.EMPTY_MATCH);
5723
+ if (newSubs.length === 1) return newSubs[0];
5724
+ const nre = new Regexp(Regexp.Op.CONCAT);
5725
+ nre.subs = newSubs;
5726
+ return nre;
5433
5727
  }
5434
5728
  static simplify1(op, flags, sub, re2) {
5435
5729
  if (sub.op === Regexp.Op.EMPTY_MATCH) return sub;
@@ -5587,46 +5881,35 @@ var CharClass = class CharClass2 {
5587
5881
  result += "]";
5588
5882
  return result;
5589
5883
  }
5590
- static cmp(array, i, pivotFrom, pivotTo) {
5591
- const cmp = array[i] - pivotFrom;
5592
- return cmp !== 0 ? cmp : pivotTo - array[i + 1];
5593
- }
5594
- static qsortIntPair(array, left, right) {
5595
- const pivotIndex = ((left + right) / 2 | 0) & -2;
5596
- const pivotFrom = array[pivotIndex];
5597
- const pivotTo = array[pivotIndex + 1];
5598
- let i = left;
5599
- let j = right;
5600
- while (i <= j) {
5601
- while (i < right && CharClass2.cmp(array, i, pivotFrom, pivotTo) < 0) i += 2;
5602
- while (j > left && CharClass2.cmp(array, j, pivotFrom, pivotTo) > 0) j -= 2;
5603
- if (i <= j) {
5604
- if (i !== j) {
5605
- let temp = array[i];
5606
- array[i] = array[j];
5607
- array[j] = temp;
5608
- temp = array[i + 1];
5609
- array[i + 1] = array[j + 1];
5610
- array[j + 1] = temp;
5611
- }
5612
- i += 2;
5613
- j -= 2;
5614
- }
5884
+ static sortRanges(array, len) {
5885
+ const n = len >> 1;
5886
+ const order = new Array(n);
5887
+ for (let i = 0; i < n; i++) order[i] = i;
5888
+ order.sort((a, b) => array[2 * a] - array[2 * b] || array[2 * b + 1] - array[2 * a + 1]);
5889
+ const sorted = array.slice(0, len);
5890
+ for (let i = 0; i < n; i++) {
5891
+ array[2 * i] = sorted[2 * order[i]];
5892
+ array[2 * i + 1] = sorted[2 * order[i] + 1];
5615
5893
  }
5616
- if (left < j) CharClass2.qsortIntPair(array, left, j);
5617
- if (i < right) CharClass2.qsortIntPair(array, i, right);
5618
5894
  }
5619
5895
  constructor(r = Utils.emptyInts()) {
5620
5896
  this.r = r;
5621
5897
  this.len = r.length;
5622
5898
  }
5623
5899
  toArray() {
5624
- if (this.len === this.r.length) return this.r;
5625
- else return this.r.slice(0, this.len);
5900
+ if (this.r instanceof Int32Array) return this.len === this.r.length ? this.r : this.r.subarray(0, this.len);
5901
+ return new Int32Array(this.len === this.r.length ? this.r : this.r.slice(0, this.len));
5902
+ }
5903
+ toGrowableArray() {
5904
+ if (Array.isArray(this.r)) {
5905
+ this.r.length = this.len;
5906
+ return this.r;
5907
+ }
5908
+ return Array.from(this.r.subarray(0, this.len));
5626
5909
  }
5627
5910
  cleanClass() {
5628
5911
  if (this.len < 4) return this;
5629
- CharClass2.qsortIntPair(this.r, 0, this.len - 2);
5912
+ CharClass2.sortRanges(this.r, this.len);
5630
5913
  let w = 2;
5631
5914
  for (let i = 2; i < this.len; i += 2) {
5632
5915
  const lo = this.r[i];
@@ -5823,7 +6106,7 @@ var Parser = class Parser2 {
5823
6106
  static ERR_LARGE = "expression too large";
5824
6107
  static ERR_INVALID_CAPTURE_IN_LOOKBEHIND = "invalid capture in lookbehind";
5825
6108
  static MAX_HEIGHT = 1e3;
5826
- static MAX_SIZE = 3355443;
6109
+ static MAX_SIZE = 1398101;
5827
6110
  static MAX_RUNES = 33554432;
5828
6111
  static ANY_TABLE = new UnicodeRangeTable(new Uint32Array([
5829
6112
  0,
@@ -5969,15 +6252,17 @@ var Parser = class Parser2 {
5969
6252
  case Regexp.Op.ANY_CHAR_NOT_NL:
5970
6253
  if (Parser2.matchRune(src, Codepoint.CODES.get("\n"))) dst.op = Regexp.Op.ANY_CHAR;
5971
6254
  break;
5972
- case Regexp.Op.CHAR_CLASS:
5973
- if (src.op === Regexp.Op.LITERAL) dst.runes = new CharClass(dst.runes).appendLiteral(src.runes[0], src.flags).toArray();
5974
- else dst.runes = new CharClass(dst.runes).appendClass(src.runes).toArray();
6255
+ case Regexp.Op.CHAR_CLASS: {
6256
+ const cc = new CharClass(Array.isArray(dst.runes) ? dst.runes : Array.from(dst.runes));
6257
+ if (src.op === Regexp.Op.LITERAL) cc.appendLiteral(src.runes[0], src.flags);
6258
+ else cc.appendClass(src.runes);
6259
+ dst.runes = cc.toGrowableArray();
5975
6260
  break;
6261
+ }
5976
6262
  case Regexp.Op.LITERAL:
5977
6263
  if (src.runes[0] === dst.runes[0] && src.flags === dst.flags) break;
5978
6264
  dst.op = Regexp.Op.CHAR_CLASS;
5979
- dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toArray();
5980
- break;
6265
+ dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toGrowableArray();
5981
6266
  }
5982
6267
  }
5983
6268
  static parseEscape(t) {
@@ -6043,7 +6328,6 @@ var Parser = class Parser2 {
6043
6328
  return Codepoint.CODES.get("\v");
6044
6329
  default:
6045
6330
  if (c <= Unicode.MAX_ASCII && !Utils.isalnum(c)) return c;
6046
- break;
6047
6331
  }
6048
6332
  throw new RE2JSSyntaxException(Parser2.ERR_INVALID_ESCAPE, t.from(startPos));
6049
6333
  }
@@ -6052,10 +6336,6 @@ var Parser = class Parser2 {
6052
6336
  if (t.lookingAt("\\")) return Parser2.parseEscape(t);
6053
6337
  return t.pop();
6054
6338
  }
6055
- static concatRunes(x, y) {
6056
- for (let i = 0; i < y.length; i++) x.push(y[i]);
6057
- return x;
6058
- }
6059
6339
  static hasCapture(re2) {
6060
6340
  if (re2 === null) return false;
6061
6341
  if (re2.op === Regexp.Op.CAPTURE) return true;
@@ -6186,9 +6466,7 @@ var Parser = class Parser2 {
6186
6466
  const n = this.stack.length;
6187
6467
  let i = n;
6188
6468
  while (i > 0 && !Regexp.isPseudoOp(this.stack[i - 1].op)) i--;
6189
- const r = this.stack.slice(i, n);
6190
- this.stack = this.stack.slice(0, i);
6191
- return r;
6469
+ return this.stack.splice(i, n - i);
6192
6470
  }
6193
6471
  push(re2) {
6194
6472
  this.numRunes += re2.runes.length;
@@ -6213,7 +6491,8 @@ var Parser = class Parser2 {
6213
6491
  const re1 = this.stack[n - 1];
6214
6492
  const re2 = this.stack[n - 2];
6215
6493
  if (re1.op !== Regexp.Op.LITERAL || re2.op !== Regexp.Op.LITERAL || (re1.flags & RE2Flags.FOLD_CASE) !== (re2.flags & RE2Flags.FOLD_CASE)) return false;
6216
- re2.runes = Parser2.concatRunes(re2.runes, re1.runes);
6494
+ if (!Array.isArray(re2.runes)) re2.runes = Array.from(re2.runes);
6495
+ for (let i = 0; i < re1.runes.length; i++) re2.runes.push(re1.runes[i]);
6217
6496
  if (r >= 0) {
6218
6497
  re1.runes = [r];
6219
6498
  re1.flags = flags;
@@ -6285,12 +6564,12 @@ var Parser = class Parser2 {
6285
6564
  }
6286
6565
  cleanAlt(re2) {
6287
6566
  if (re2.op === Regexp.Op.CHAR_CLASS) {
6288
- re2.runes = new CharClass(re2.runes).cleanClass().toArray();
6567
+ re2.runes = new CharClass(Array.from(re2.runes)).cleanClass().toArray();
6289
6568
  if (re2.runes.length === 2 && re2.runes[0] === 0 && re2.runes[1] === Unicode.MAX_RUNE) {
6290
- re2.runes = [];
6569
+ re2.runes = /* @__PURE__ */ new Int32Array(0);
6291
6570
  re2.op = Regexp.Op.ANY_CHAR;
6292
6571
  } else if (re2.runes.length === 4 && re2.runes[0] === 0 && re2.runes[1] === Codepoint.CODES.get("\n") - 1 && re2.runes[2] === Codepoint.CODES.get("\n") + 1 && re2.runes[3] === Unicode.MAX_RUNE) {
6293
- re2.runes = [];
6572
+ re2.runes = /* @__PURE__ */ new Int32Array(0);
6294
6573
  re2.op = Regexp.Op.ANY_CHAR_NOT_NL;
6295
6574
  }
6296
6575
  }
@@ -6455,7 +6734,6 @@ var Parser = class Parser2 {
6455
6734
  }
6456
6735
  default:
6457
6736
  re2.subs = re2.subs.slice(1, re2.subs.length);
6458
- break;
6459
6737
  }
6460
6738
  }
6461
6739
  return re2;
@@ -6556,7 +6834,6 @@ var Parser = class Parser2 {
6556
6834
  break;
6557
6835
  case Codepoint.CODES.get("?"):
6558
6836
  op = Regexp.Op.QUEST;
6559
- break;
6560
6837
  }
6561
6838
  this.repeat(op, min, max, repeatPos, t, lastRepeatPos);
6562
6839
  break;
@@ -6610,7 +6887,6 @@ var Parser = class Parser2 {
6610
6887
  break bigswitch;
6611
6888
  default:
6612
6889
  t.rewindTo(savedPos);
6613
- break;
6614
6890
  }
6615
6891
  else t.rewindTo(savedPos);
6616
6892
  const re2 = this.newRegexp(Regexp.Op.CHAR_CLASS);
@@ -6636,7 +6912,6 @@ var Parser = class Parser2 {
6636
6912
  }
6637
6913
  default:
6638
6914
  this.literal(t.pop());
6639
- break;
6640
6915
  }
6641
6916
  lastRepeatPos = repeatPos;
6642
6917
  }
@@ -6835,7 +7110,7 @@ var Parser = class Parser2 {
6835
7110
  if ((this.flags & RE2Flags.FOLD_CASE) === 0 || fold === null) cc.appendTableWithSign(tab, sign);
6836
7111
  else {
6837
7112
  const tmp = new CharClass().appendTable(tab).appendTable(fold).cleanClass().toArray();
6838
- cc.appendClassWithSign(tmp, sign);
7113
+ cc.appendClassWithSign(Array.from(tmp), sign);
6839
7114
  }
6840
7115
  return true;
6841
7116
  }
@@ -7001,7 +7276,10 @@ var RE2 = class RE22 {
7001
7276
  }
7002
7277
  return [];
7003
7278
  }
7004
- executeEngine(input, pos, anchor, ncap) {
7279
+ createLookbehindState() {
7280
+ return this.prog.numLb > 0 ? new LookbehindState(this.prog) : null;
7281
+ }
7282
+ executeEngine(input, pos, anchor, ncap, lbState = null) {
7005
7283
  if (this.prefixComplete && (ncap === 0 || this.numSubexp === 0)) return this.matchPrefixComplete(input, pos, anchor, ncap);
7006
7284
  if (this.prefilter !== null && anchor === RE2Flags.UNANCHORED) {
7007
7285
  if (!this.prefilter.eval(input, pos)) return null;
@@ -7009,14 +7287,14 @@ var RE2 = class RE22 {
7009
7287
  if (this.onepass !== null) return OnePass.execute(this, input, pos, anchor, ncap);
7010
7288
  if (ncap > 0) {
7011
7289
  if (this.prog.numLb === 0 && input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
7012
- return this.doExecuteNFA(input, pos, anchor, ncap);
7290
+ return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
7013
7291
  }
7014
7292
  if (this.prog.numLb === 0) {
7015
7293
  const dfaResult = this.dfa.match(input, pos, anchor);
7016
7294
  if (dfaResult !== null) return dfaResult ? [] : null;
7017
7295
  if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
7018
7296
  }
7019
- return this.doExecuteNFA(input, pos, anchor, ncap);
7297
+ return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
7020
7298
  }
7021
7299
  /**
7022
7300
  * Returns the number of parenthesized subexpressions in this regular expression.
@@ -7042,11 +7320,11 @@ var RE2 = class RE22 {
7042
7320
  toString() {
7043
7321
  return this.expr;
7044
7322
  }
7045
- doExecuteNFA(input, pos, anchor, ncap) {
7323
+ doExecuteNFA(input, pos, anchor, ncap, lbState = null) {
7046
7324
  let m = this.get();
7047
7325
  if (!m) m = Machine.fromRE2(this);
7048
7326
  m.init(ncap);
7049
- const cap = m.match(input, pos, anchor) ? m.submatches() : null;
7327
+ const cap = m.match(input, pos, anchor, lbState) ? m.submatches() : null;
7050
7328
  this.put(m);
7051
7329
  return cap;
7052
7330
  }
@@ -7065,17 +7343,21 @@ var RE2 = class RE22 {
7065
7343
  * @param anchor the anchoring flag (UNANCHORED, ANCHOR_START, ANCHOR_BOTH)
7066
7344
  * @param group the array to fill with submatch positions
7067
7345
  * @param ngroup the number of array pairs to fill in
7346
+ * @param lbState optional state carried between successive matches over the same input (see
7347
+ * createLookbehindState); omit it to evaluate lookbehinds from the beginning of the input
7068
7348
  * @returns true if a match was found
7069
7349
  */
7070
- matchWithGroup(input, start, end, anchor, ngroup) {
7071
- if (!(input instanceof MatcherInputBase)) if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
7072
- else input = MatcherInput.utf16(input);
7073
- return this.matchMachineInput(input, start, end, anchor, ngroup);
7350
+ matchWithGroup(input, start, end, anchor, ngroup, lbState = null) {
7351
+ if (!(input instanceof MatcherInputBase)) {
7352
+ if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
7353
+ else input = MatcherInput.utf16(input);
7354
+ }
7355
+ return this.matchMachineInput(input, start, end, anchor, ngroup, lbState);
7074
7356
  }
7075
- matchMachineInput(input, start, end, anchor, ngroup) {
7357
+ matchMachineInput(input, start, end, anchor, ngroup, lbState = null) {
7076
7358
  if (start > end) return [false, null];
7077
7359
  const machineInput = input.isUTF16Encoding() ? MachineInput.fromUTF16(input.asCharSequence(), 0, end) : MachineInput.fromUTF8(input.asBytes(), 0, end);
7078
- const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup);
7360
+ const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup, lbState);
7079
7361
  if (groupMatch === null) return [false, null];
7080
7362
  return [true, groupMatch];
7081
7363
  }
@@ -7112,9 +7394,10 @@ var RE2 = class RE22 {
7112
7394
  let searchPos = 0;
7113
7395
  let out = "";
7114
7396
  const input = MachineInput.fromUTF16(src);
7397
+ const lbState = this.createLookbehindState();
7115
7398
  let numReplaces = 0;
7116
7399
  while (searchPos <= src.length) {
7117
- const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2);
7400
+ const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2, lbState);
7118
7401
  if (a === null || a.length === 0) break;
7119
7402
  out += src.substring(lastMatchEnd, a[0]);
7120
7403
  if (a[1] > lastMatchEnd || a[0] === 0) {
@@ -7148,8 +7431,9 @@ var RE2 = class RE22 {
7148
7431
  let pos = 0;
7149
7432
  let i = 0;
7150
7433
  let prevMatchEnd = -1;
7434
+ const lbState = this.createLookbehindState();
7151
7435
  while (i < n && pos <= end) {
7152
- const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap);
7436
+ const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap, lbState);
7153
7437
  if (matches === null || matches.length === 0) break;
7154
7438
  let accept = true;
7155
7439
  if (matches[1] === pos) {
@@ -7417,7 +7701,9 @@ var RE2Set = class RE2Set2 {
7417
7701
  */
7418
7702
  compile() {
7419
7703
  if (this.prog) return;
7420
- this.prog = Compiler.compileSet(this.regexps);
7704
+ const prog = Compiler.compileSet(this.regexps);
7705
+ if (prog.numInst() > Parser.MAX_SIZE) throw new RE2JSCompileException(`${Parser.ERR_LARGE}: the set compiles to ${prog.numInst()} instructions, more than ${Parser.MAX_SIZE}`);
7706
+ this.prog = prog;
7421
7707
  this.dfa = new DFA(this.prog, this.maxMem);
7422
7708
  this.dummyRe2 = {
7423
7709
  prog: this.prog,