parseman 0.56.0 → 0.58.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 (106) hide show
  1. package/dist/analysis/diagnostics.js +2232 -1088
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +2247 -1103
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/dispatch.d.ts.map +1 -1
  6. package/dist/combinators/node.d.ts +1 -1
  7. package/dist/compiler/build-arity.d.ts +1 -1
  8. package/dist/compiler/build-arity.d.ts.map +1 -1
  9. package/dist/compiler/token-alphabet.d.ts +11 -1
  10. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  11. package/dist/compiler/token-capability.js +69 -16
  12. package/dist/compiler/token-capability.js.map +2 -2
  13. package/dist/cst/capture-buffer.d.ts +6 -0
  14. package/dist/cst/capture-buffer.d.ts.map +1 -1
  15. package/dist/cst/trivia-kinds.d.ts +9 -1
  16. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  17. package/dist/index.js +1446 -236
  18. package/dist/index.js.map +3 -3
  19. package/dist/language-service/index.js +1 -0
  20. package/dist/language-service/index.js.map +1 -1
  21. package/dist/parse-context.d.ts.map +1 -1
  22. package/dist/plugin/entry-supercompiler.d.ts +1 -1
  23. package/dist/plugin/entry-supercompiler.d.ts.map +1 -1
  24. package/dist/plugin/index.d.ts +51 -1
  25. package/dist/plugin/index.d.ts.map +1 -1
  26. package/dist/plugin/index.js +2126 -380
  27. package/dist/plugin/index.js.map +3 -3
  28. package/dist/plugin/ir-eval.d.ts +2 -0
  29. package/dist/plugin/ir-eval.d.ts.map +1 -1
  30. package/dist/regex/classes.d.ts.map +1 -1
  31. package/dist/run/index.js +1 -0
  32. package/dist/run/index.js.map +1 -1
  33. package/dist/table/assemble.d.ts +9 -0
  34. package/dist/table/assemble.d.ts.map +1 -1
  35. package/dist/table/child-slots.d.ts +4 -6
  36. package/dist/table/child-slots.d.ts.map +1 -1
  37. package/dist/table/compile-rule-map.d.ts +14 -2
  38. package/dist/table/compile-rule-map.d.ts.map +1 -1
  39. package/dist/table/emit-assembly.d.ts +17 -2
  40. package/dist/table/emit-assembly.d.ts.map +1 -1
  41. package/dist/table/emit.d.ts +5 -1
  42. package/dist/table/emit.d.ts.map +1 -1
  43. package/dist/table/encode.d.ts.map +1 -1
  44. package/dist/table/exec-baseline.d.ts.map +1 -1
  45. package/dist/table/exec.d.ts.map +1 -1
  46. package/dist/table/factor-choice.d.ts +42 -0
  47. package/dist/table/factor-choice.d.ts.map +1 -0
  48. package/dist/table/fail-clean.d.ts +3 -0
  49. package/dist/table/fail-clean.d.ts.map +1 -0
  50. package/dist/table/hold-gap.d.ts +8 -0
  51. package/dist/table/hold-gap.d.ts.map +1 -0
  52. package/dist/table/index.js +1798 -316
  53. package/dist/table/index.js.map +3 -3
  54. package/dist/table/lex-program.d.ts +7 -3
  55. package/dist/table/lex-program.d.ts.map +1 -1
  56. package/dist/table/ops.d.ts +17 -6
  57. package/dist/table/ops.d.ts.map +1 -1
  58. package/dist/table/program.d.ts +13 -0
  59. package/dist/table/program.d.ts.map +1 -1
  60. package/dist/table/run-support.d.ts +19 -0
  61. package/dist/table/run-support.d.ts.map +1 -1
  62. package/dist/table/scalar-terminal.d.ts +2 -0
  63. package/dist/table/scalar-terminal.d.ts.map +1 -1
  64. package/dist/table/select-hot.d.ts +6 -0
  65. package/dist/table/select-hot.d.ts.map +1 -0
  66. package/dist/table/site-labels.d.ts +66 -0
  67. package/dist/table/site-labels.d.ts.map +1 -1
  68. package/dist/table/trivia-gap.d.ts +31 -0
  69. package/dist/table/trivia-gap.d.ts.map +1 -0
  70. package/dist/types.d.ts +17 -0
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/version.d.ts +1 -1
  73. package/package.json +4 -1
  74. package/src/combinators/dispatch.ts +12 -3
  75. package/src/combinators/node.ts +6 -13
  76. package/src/combinators/trivia-skip.ts +44 -1
  77. package/src/compiler/build-arity.ts +3 -3
  78. package/src/compiler/token-alphabet.ts +57 -17
  79. package/src/cst/capture-buffer.ts +25 -0
  80. package/src/cst/trivia-kinds.ts +12 -1
  81. package/src/parse-context.ts +1 -0
  82. package/src/plugin/entry-supercompiler.ts +8 -9
  83. package/src/plugin/index.ts +362 -42
  84. package/src/plugin/ir-eval.ts +7 -1
  85. package/src/regex/classes.ts +3 -0
  86. package/src/table/assemble.ts +371 -83
  87. package/src/table/child-slots.ts +6 -8
  88. package/src/table/compile-rule-map.ts +64 -15
  89. package/src/table/emit-assembly.ts +244 -42
  90. package/src/table/emit.ts +11 -8
  91. package/src/table/encode.ts +149 -35
  92. package/src/table/exec-baseline.ts +1 -3
  93. package/src/table/exec.ts +34 -14
  94. package/src/table/factor-choice.ts +173 -0
  95. package/src/table/fail-clean.ts +130 -0
  96. package/src/table/hold-gap.ts +68 -0
  97. package/src/table/lex-program.ts +197 -43
  98. package/src/table/ops.ts +18 -7
  99. package/src/table/program.ts +24 -0
  100. package/src/table/run-support.ts +35 -0
  101. package/src/table/scalar-terminal.ts +8 -0
  102. package/src/table/select-hot.ts +70 -0
  103. package/src/table/site-labels.ts +135 -4
  104. package/src/table/trivia-gap.ts +109 -0
  105. package/src/types.ts +18 -0
  106. package/src/version.ts +1 -1
@@ -478,6 +478,31 @@ function pushCstChild(ctx, built, rawEntry2) {
478
478
  else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
479
479
  if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry2);
480
480
  }
481
+ function popCstChild(ctx) {
482
+ const b = ctx._cstBuf;
483
+ if (b) {
484
+ const ch2 = b.ch;
485
+ if (b.rawOnly !== true && ch2) {
486
+ ch2.pop();
487
+ if (ch2.length === 1) {
488
+ b.single = ch2[0];
489
+ b.ch = void 0;
490
+ }
491
+ }
492
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1;
493
+ else if (b.raw) {
494
+ b.raw.pop();
495
+ if (b.raw.length === 1) {
496
+ b.rawSingle = b.raw[0];
497
+ b.raw = void 0;
498
+ }
499
+ } else b.rawSingle = void 0;
500
+ return;
501
+ }
502
+ if (ctx._cstChildren) ctx._cstChildren.pop();
503
+ else if (ctx._cstLeaves) ctx._cstLeaves.pop();
504
+ if (ctx._cstRawChildren) ctx._cstRawChildren.pop();
505
+ }
481
506
  function cstRawLen(ctx) {
482
507
  const b = ctx._cstBuf;
483
508
  if (b) {
@@ -707,6 +732,7 @@ function literalCodePoints(frag) {
707
732
  if (ch2 === "\\") {
708
733
  const e = frag[i + 1];
709
734
  if (e === void 0) return null;
735
+ if (!(e in CLASS_ESCAPES) && /\w/.test(e)) return null;
710
736
  out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
711
737
  i += 2;
712
738
  continue;
@@ -819,6 +845,7 @@ function createParseContext() {
819
845
  _rootTriviaKindIndex: void 0,
820
846
  _rootTriviaStrictScopes: void 0,
821
847
  _rootTriviaCapture: void 0,
848
+ _gap: void 0,
822
849
  _cstTriviaLog: void 0,
823
850
  _fields: void 0,
824
851
  _cstBuf: void 0,
@@ -1301,7 +1328,10 @@ function labeledTriviaSpec(arms, minRepeats) {
1301
1328
  arms,
1302
1329
  minRepeats,
1303
1330
  visitor: commonLabeledTriviaVisitor({ arms, minRepeats }),
1304
- charArms: charArmsFor({ arms, minRepeats })
1331
+ charArms: charArmsFor({ arms, minRepeats }),
1332
+ rootKinds: void 0,
1333
+ rootLeaders: [],
1334
+ rootScan: null
1305
1335
  };
1306
1336
  }
1307
1337
  function matchArmAt(input, pos, arm, state) {
@@ -1761,8 +1791,50 @@ function loopScanner(arms) {
1761
1791
  function regexTriviaScanner(parser2) {
1762
1792
  const d = parser2._def.tag === "label" ? parser2._def.parser._def : parser2._def;
1763
1793
  if (d.tag !== "regex" || d.flags) return null;
1764
- const source = d.source;
1765
- return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source);
1794
+ return sourceScanner(d.source);
1795
+ }
1796
+ function sourceScanner(source) {
1797
+ return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source) ?? sharedPrefixAltSource(source);
1798
+ }
1799
+ function sharedPrefixAltSource(source) {
1800
+ const m = /^((?:\\.|[^\\[\]()*+?|^$.{}])+)\(\?:(.*)\)$/.exec(source);
1801
+ if (!m) return null;
1802
+ const alts = [];
1803
+ const body = m[2];
1804
+ let depth = 0;
1805
+ let start = 0;
1806
+ for (let i = 0; i < body.length; i++) {
1807
+ const c = body[i];
1808
+ if (c === "\\") {
1809
+ i++;
1810
+ continue;
1811
+ }
1812
+ if (c === "[") {
1813
+ while (i < body.length && body[i] !== "]") i += body[i] === "\\" ? 2 : 1;
1814
+ continue;
1815
+ }
1816
+ if (c === "(") depth++;
1817
+ else if (c === ")" && --depth < 0) return null;
1818
+ else if (c === "|" && depth === 0) {
1819
+ alts.push(body.slice(start, i));
1820
+ start = i + 1;
1821
+ }
1822
+ }
1823
+ if (depth !== 0 || alts.length === 0) return null;
1824
+ alts.push(body.slice(start));
1825
+ const scanners = [];
1826
+ for (const alt of alts) {
1827
+ const scanner = sourceScanner(m[1] + alt);
1828
+ if (scanner === null) return null;
1829
+ scanners.push(scanner);
1830
+ }
1831
+ return (input, cur) => {
1832
+ for (const scanner of scanners) {
1833
+ const end = scanner(input, cur);
1834
+ if (end > cur) return end;
1835
+ }
1836
+ return cur;
1837
+ };
1766
1838
  }
1767
1839
  function bmpString(cps) {
1768
1840
  if (!cps) return null;
@@ -2299,6 +2371,9 @@ function parser(opts, root) {
2299
2371
  };
2300
2372
  return grammar;
2301
2373
  }
2374
+ function noTrivia(root) {
2375
+ return parser({ trivia: null }, root);
2376
+ }
2302
2377
  var _analyzed = /* @__PURE__ */ new WeakSet();
2303
2378
  function parse(combinator, input, opts = {}) {
2304
2379
  if (!_analyzed.has(combinator)) {
@@ -3793,17 +3868,59 @@ function buildLexBodyRecognizer(spec, constants) {
3793
3868
  };
3794
3869
  }
3795
3870
 
3871
+ // src/table/run-support.ts
3872
+ function lineCol(ctx, offset) {
3873
+ const starts = ctx._lineStarts ?? [0];
3874
+ let lo = 0, hi = starts.length - 1;
3875
+ while (lo < hi) {
3876
+ const mid = lo + hi + 1 >> 1;
3877
+ if (starts[mid] <= offset) lo = mid;
3878
+ else hi = mid - 1;
3879
+ }
3880
+ return [lo + 1, offset - starts[lo] + 1];
3881
+ }
3882
+ function spanLines(ctx, start, end) {
3883
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
3884
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
3885
+ }
3886
+ function rawEntry(v, input, s, e) {
3887
+ if (typeof v === "object" && v !== null) {
3888
+ const tg = v._tag;
3889
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
3890
+ }
3891
+ return {
3892
+ _tag: "leaf",
3893
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
3894
+ span: { start: s, end: e }
3895
+ };
3896
+ }
3897
+ function lead(input, pos) {
3898
+ if (pos >= input.length) return -1;
3899
+ const c = input.charCodeAt(pos);
3900
+ if (c < 55296 || c > 56319) return c;
3901
+ return input.codePointAt(pos) ?? c;
3902
+ }
3903
+ var EMPTY_KIDS = Object.freeze([]);
3904
+ var EMPTY_TRIVIA = Object.freeze([]);
3905
+ function collapseEmpty(ctx, build, input, pos, end, readsRaw) {
3906
+ const collected = ctx._cstBuf !== void 0 || ctx._cstChildren !== void 0;
3907
+ if (collected) popCstChild(ctx);
3908
+ const raw = readsRaw ? [rawEntry(void 0, input, pos, end)] : EMPTY_KIDS;
3909
+ const nd = build(EMPTY_KIDS, void 0, { start: pos, end }, raw, EMPTY_TRIVIA, void 0);
3910
+ if (collected) pushCstChild(ctx, nd, ctx._cstBuf?.noRaw === true ? void 0 : rawEntry(nd, input, pos, end));
3911
+ return nd;
3912
+ }
3913
+
3796
3914
  // src/table/lex-program.ts
3797
3915
  var LEX_NODE_TERMINAL = 0;
3798
3916
  var LEX_NODE_SEQUENCE2 = 1;
3799
3917
  var LEX_NODE_SEQUENCE3 = 2;
3800
3918
  var LEX_NODE_SEQUENCE4 = 3;
3801
3919
  var LEX_NODE_SEQUENCE5 = 4;
3802
- var LEX_NODE_CHOICE2 = 5;
3803
- var LEX_NODE_CHOICE4 = 6;
3804
- var LEX_NODE_CHOICE8 = 7;
3920
+ var LEX_NODE_CHOICE = 5;
3805
3921
  var LEX_NODE_NOT = 8;
3806
3922
  var LEX_NODE_OPTIONAL = 9;
3923
+ var LEX_NODE_REPEAT = 10;
3807
3924
  function lexProgramDigest(words) {
3808
3925
  let hash = 2166136261;
3809
3926
  for (const word of words) {
@@ -3832,85 +3949,114 @@ function trackLexLines(ctx, input, end) {
3832
3949
  ctx._lineScannedTo = end;
3833
3950
  }
3834
3951
  function terminalNode(matcher, failure, tracksLines) {
3835
- const match = (input, pos) => {
3836
- const result = matcher(input, pos);
3837
- return result < 0 ? -1 : result / 2;
3838
- };
3839
3952
  return {
3840
- match,
3953
+ match: (input, pos) => {
3954
+ const result = matcher(input, pos);
3955
+ return result < 0 ? -1 : result / 2;
3956
+ },
3841
3957
  run: (input, pos, ctx) => {
3842
- const end = match(input, pos);
3843
- if (end < 0) {
3958
+ const result = matcher(input, pos);
3959
+ if (result < 0) {
3844
3960
  ctx._fe = pos;
3845
3961
  ctx._fx = failure;
3846
3962
  if (ctx._probe !== void 0) failAt(ctx, ctx._fx, pos);
3847
3963
  return -1;
3848
3964
  }
3965
+ const end = result / 2;
3849
3966
  if (tracksLines) trackLexLines(ctx, input, end);
3850
3967
  return end;
3851
3968
  }
3852
3969
  };
3853
3970
  }
3854
3971
  function sequence2(a, b) {
3972
+ const am = a.match, bm = b.match, ar = a.run, br = b.run;
3855
3973
  return {
3856
3974
  match: (input, pos) => {
3857
- const e0 = a.match(input, pos);
3858
- return e0 < 0 ? -1 : b.match(input, e0);
3975
+ const e0 = am(input, pos);
3976
+ return e0 < 0 ? -1 : bm(input, e0);
3859
3977
  },
3860
3978
  run: (input, pos, ctx) => {
3861
- const e0 = a.run(input, pos, ctx);
3979
+ const e0 = ar(input, pos, ctx);
3862
3980
  if (e0 < 0) return -1;
3863
3981
  ctx._fc = false;
3864
- return b.run(input, e0, ctx);
3982
+ return br(input, e0, ctx);
3865
3983
  }
3866
3984
  };
3867
3985
  }
3868
3986
  function sequence3(a, b, c) {
3987
+ const am = a.match, bm = b.match, cm = c.match, ar = a.run, br = b.run, cr = c.run;
3869
3988
  return {
3870
3989
  match: (input, pos) => {
3871
- const e0 = a.match(input, pos);
3990
+ const e0 = am(input, pos);
3872
3991
  if (e0 < 0) return -1;
3873
- const e1 = b.match(input, e0);
3874
- return e1 < 0 ? -1 : c.match(input, e1);
3992
+ const e1 = bm(input, e0);
3993
+ return e1 < 0 ? -1 : cm(input, e1);
3875
3994
  },
3876
3995
  run: (input, pos, ctx) => {
3877
- const e0 = a.run(input, pos, ctx);
3996
+ const e0 = ar(input, pos, ctx);
3878
3997
  if (e0 < 0) return -1;
3879
3998
  ctx._fc = false;
3880
- const e1 = b.run(input, e0, ctx);
3999
+ const e1 = br(input, e0, ctx);
3881
4000
  if (e1 < 0) return -1;
3882
4001
  ctx._fc = false;
3883
- return c.run(input, e1, ctx);
4002
+ return cr(input, e1, ctx);
3884
4003
  }
3885
4004
  };
3886
4005
  }
3887
4006
  function sequence4(a, b, c, d) {
3888
- const abc = sequence3(a, b, c);
4007
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match;
4008
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run;
3889
4009
  return {
3890
4010
  match: (input, pos) => {
3891
- const end = abc.match(input, pos);
3892
- return end < 0 ? -1 : d.match(input, end);
4011
+ const e0 = am(input, pos);
4012
+ if (e0 < 0) return -1;
4013
+ const e1 = bm(input, e0);
4014
+ if (e1 < 0) return -1;
4015
+ const e2 = cm(input, e1);
4016
+ return e2 < 0 ? -1 : dm(input, e2);
3893
4017
  },
3894
4018
  run: (input, pos, ctx) => {
3895
- const end = abc.run(input, pos, ctx);
3896
- if (end < 0) return -1;
4019
+ const e0 = ar(input, pos, ctx);
4020
+ if (e0 < 0) return -1;
4021
+ ctx._fc = false;
4022
+ const e1 = br(input, e0, ctx);
4023
+ if (e1 < 0) return -1;
4024
+ ctx._fc = false;
4025
+ const e2 = cr(input, e1, ctx);
4026
+ if (e2 < 0) return -1;
3897
4027
  ctx._fc = false;
3898
- return d.run(input, end, ctx);
4028
+ return dr(input, e2, ctx);
3899
4029
  }
3900
4030
  };
3901
4031
  }
3902
4032
  function sequence5(a, b, c, d, e) {
3903
- const abcd = sequence4(a, b, c, d);
4033
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match, em = e.match;
4034
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run, er = e.run;
3904
4035
  return {
3905
4036
  match: (input, pos) => {
3906
- const end = abcd.match(input, pos);
3907
- return end < 0 ? -1 : e.match(input, end);
4037
+ const e0 = am(input, pos);
4038
+ if (e0 < 0) return -1;
4039
+ const e1 = bm(input, e0);
4040
+ if (e1 < 0) return -1;
4041
+ const e2 = cm(input, e1);
4042
+ if (e2 < 0) return -1;
4043
+ const e3 = dm(input, e2);
4044
+ return e3 < 0 ? -1 : em(input, e3);
3908
4045
  },
3909
4046
  run: (input, pos, ctx) => {
3910
- const end = abcd.run(input, pos, ctx);
3911
- if (end < 0) return -1;
4047
+ const e0 = ar(input, pos, ctx);
4048
+ if (e0 < 0) return -1;
4049
+ ctx._fc = false;
4050
+ const e1 = br(input, e0, ctx);
4051
+ if (e1 < 0) return -1;
4052
+ ctx._fc = false;
4053
+ const e2 = cr(input, e1, ctx);
4054
+ if (e2 < 0) return -1;
3912
4055
  ctx._fc = false;
3913
- return e.run(input, end, ctx);
4056
+ const e3 = dr(input, e2, ctx);
4057
+ if (e3 < 0) return -1;
4058
+ ctx._fc = false;
4059
+ return er(input, e3, ctx);
3914
4060
  }
3915
4061
  };
3916
4062
  }
@@ -3923,9 +4069,9 @@ function appendExpected(acc, values) {
3923
4069
  function choiceNode(arms, classes, armExpected, choiceExpected) {
3924
4070
  let matchTail = () => -1;
3925
4071
  for (let i = arms.length - 1; i >= 0; i--) {
3926
- const arm = arms[i], next = matchTail;
4072
+ const armMatch = arms[i].match, next = matchTail;
3927
4073
  matchTail = (input, pos) => {
3928
- const end = arm.match(input, pos);
4074
+ const end = armMatch(input, pos);
3929
4075
  return end < 0 ? next(input, pos) : end;
3930
4076
  };
3931
4077
  }
@@ -3935,7 +4081,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
3935
4081
  return -1;
3936
4082
  };
3937
4083
  for (let i = arms.length - 1; i >= 0; i--) {
3938
- const arm = arms[i], cls = classes[i], staticExpected = armExpected[i], next = tail;
4084
+ const armRun = arms[i].run, cls = classes[i], staticExpected = armExpected[i], next = tail;
3939
4085
  tail = (input, pos, ctx, lead2, acc, best) => {
3940
4086
  if (cls !== void 0 && !classHas(cls, lead2)) {
3941
4087
  return next(
@@ -3948,7 +4094,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
3948
4094
  );
3949
4095
  }
3950
4096
  ctx._fc = false;
3951
- const end = arm.run(input, pos, ctx);
4097
+ const end = armRun(input, pos, ctx);
3952
4098
  if (end >= 0) return end;
3953
4099
  const at = ctx._fe ?? pos;
3954
4100
  if (at > best) {
@@ -3975,11 +4121,58 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
3975
4121
  )
3976
4122
  };
3977
4123
  }
4124
+ function exclusiveChoiceNode(arms, classes, choiceFx) {
4125
+ const ascii = (classes.length <= 128 ? new Int8Array(128) : new Int32Array(128)).fill(-1);
4126
+ const hi = [];
4127
+ for (let i = 0; i < classes.length; i++) {
4128
+ const cls = classes[i];
4129
+ for (let c = 0; c < 128; c++) if (cls.ascii[c] === 1) ascii[c] = i;
4130
+ for (let r = 0; r < cls.hi.length; r += 2) hi.push(cls.hi[r], cls.hi[r + 1], i);
4131
+ }
4132
+ const select = (code) => {
4133
+ if (code < 0) return -1;
4134
+ if (code < 128) return ascii[code];
4135
+ for (let r = 0; r < hi.length; r += 3) if (code >= hi[r] && code <= hi[r + 1]) return hi[r + 2];
4136
+ return -1;
4137
+ };
4138
+ let matchArm = () => -1;
4139
+ let selectRun = () => -1;
4140
+ for (let i = arms.length - 1; i >= 0; i--) {
4141
+ const armMatch = arms[i].match, armRun = arms[i].run, nextMatch = matchArm, nextRun = selectRun;
4142
+ matchArm = (selected, input, pos) => selected === i ? armMatch(input, pos) : nextMatch(selected, input, pos);
4143
+ selectRun = (selected, input, pos, ctx) => selected === i ? armRun(input, pos, ctx) : nextRun(selected, input, pos, ctx);
4144
+ }
4145
+ const runArm = (input, pos, ctx) => {
4146
+ const arm = select(lead(input, pos));
4147
+ if (arm >= 0) {
4148
+ ctx._fc = false;
4149
+ const end = selectRun(arm, input, pos, ctx);
4150
+ if (end >= 0) return end;
4151
+ if (committed(ctx)) return -1;
4152
+ const failed = ctx._fx;
4153
+ if (failed !== void 0 && failed.length > 0) {
4154
+ ctx._fe = pos;
4155
+ return -1;
4156
+ }
4157
+ }
4158
+ ctx._fe = pos;
4159
+ ctx._fx = choiceFx;
4160
+ return -1;
4161
+ };
4162
+ return {
4163
+ match: (input, pos) => {
4164
+ const arm = select(lead(input, pos));
4165
+ return arm < 0 ? -1 : matchArm(arm, input, pos);
4166
+ },
4167
+ run: runArm
4168
+ };
4169
+ }
3978
4170
  function notNode(body, failure) {
4171
+ const bodyMatch = body.match;
3979
4172
  return {
3980
- match: (input, pos) => body.match(input, pos) < 0 ? pos : -1,
4173
+ match: (input, pos) => bodyMatch(input, pos) < 0 ? pos : -1,
3981
4174
  run: (input, pos, ctx) => {
3982
- if (body.match(input, pos) < 0) return pos;
4175
+ if (bodyMatch(input, pos) < 0) return pos;
3983
4176
  ctx._fe = pos;
3984
4177
  ctx._fx = failure;
3985
4178
  return -1;
@@ -3987,18 +4180,57 @@ function notNode(body, failure) {
3987
4180
  };
3988
4181
  }
3989
4182
  function optionalNode(body) {
4183
+ const bodyMatch = body.match, bodyRun = body.run;
3990
4184
  return {
3991
4185
  match: (input, pos) => {
3992
- const end = body.match(input, pos);
4186
+ const end = bodyMatch(input, pos);
3993
4187
  return end < 0 ? pos : end;
3994
4188
  },
3995
4189
  run: (input, pos, ctx) => {
3996
4190
  ctx._fc = false;
3997
- const end = body.run(input, pos, ctx);
4191
+ const end = bodyRun(input, pos, ctx);
3998
4192
  return end < 0 && !committed(ctx) ? pos : end;
3999
4193
  }
4000
4194
  };
4001
4195
  }
4196
+ function repeatNode(item, min, max) {
4197
+ const itemMatch = item.match, itemRun = item.run;
4198
+ return {
4199
+ match: (input, pos) => {
4200
+ let cur = pos;
4201
+ let count = 0;
4202
+ for (; ; ) {
4203
+ if (max >= 0 && count >= max) break;
4204
+ const optional2 = count >= min && (count > 0 || min === 0);
4205
+ if (optional2 && cur >= input.length) break;
4206
+ const end = itemMatch(input, cur);
4207
+ if (end < 0 || optional2 && end === cur) break;
4208
+ cur = end;
4209
+ count++;
4210
+ }
4211
+ return count < min ? -1 : cur;
4212
+ },
4213
+ run: (input, pos, ctx) => {
4214
+ let cur = pos;
4215
+ let count = 0;
4216
+ for (; ; ) {
4217
+ if (max >= 0 && count >= max) break;
4218
+ const optional2 = count >= min && (count > 0 || min === 0);
4219
+ if (optional2 && cur >= input.length) break;
4220
+ ctx._fc = false;
4221
+ const end = itemRun(input, cur, ctx);
4222
+ if (end < 0) {
4223
+ if (committed(ctx)) return -1;
4224
+ break;
4225
+ }
4226
+ if (optional2 && end === cur) break;
4227
+ cur = end;
4228
+ count++;
4229
+ }
4230
+ return count < min ? -1 : cur;
4231
+ }
4232
+ };
4233
+ }
4002
4234
  function fixedTreeRunner(words, matchers, classes, expected) {
4003
4235
  const stack = [];
4004
4236
  const pop = () => {
@@ -4026,9 +4258,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4026
4258
  else stack.push(sequence5(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4]));
4027
4259
  continue;
4028
4260
  }
4029
- if (op >= LEX_NODE_CHOICE2 && op <= LEX_NODE_CHOICE8) {
4030
- const count = op === LEX_NODE_CHOICE2 ? 2 : op === LEX_NODE_CHOICE4 ? 4 : 8;
4261
+ if (op === LEX_NODE_CHOICE) {
4262
+ const count = words[at++];
4263
+ const exclusive = words[at++];
4264
+ if (exclusive !== 0 && exclusive !== 1) throw new TypeError("table lexical tree choice has an invalid dispatch mode");
4031
4265
  const choiceFx = expected[words[at++]];
4266
+ if (!Number.isInteger(count) || count < 2 || count > stack.length) {
4267
+ throw new TypeError("table lexical tree choice has an invalid arm count");
4268
+ }
4032
4269
  if (choiceFx === void 0) throw new TypeError("table lexical tree choice has an invalid expected set");
4033
4270
  const armClasses = [];
4034
4271
  const armFx = [];
@@ -4041,7 +4278,7 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4041
4278
  armFx.push(fx);
4042
4279
  }
4043
4280
  const arms = Array.from({ length: count }, pop).reverse();
4044
- stack.push(choiceNode(arms, armClasses, armFx, choiceFx));
4281
+ stack.push(exclusive === 1 ? exclusiveChoiceNode(arms, armClasses, choiceFx) : choiceNode(arms, armClasses, armFx, choiceFx));
4045
4282
  continue;
4046
4283
  }
4047
4284
  if (op === LEX_NODE_NOT) {
@@ -4054,6 +4291,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4054
4291
  stack.push(optionalNode(pop()));
4055
4292
  continue;
4056
4293
  }
4294
+ if (op === LEX_NODE_REPEAT) {
4295
+ const min = words[at++], max = words[at++];
4296
+ if (!Number.isInteger(min) || min < 0 || !Number.isInteger(max) || max >= 0 && max < min) {
4297
+ throw new TypeError("table lexical tree repeat has invalid bounds");
4298
+ }
4299
+ stack.push(repeatNode(pop(), min, max));
4300
+ continue;
4301
+ }
4057
4302
  throw new TypeError("table lexical tree has an unknown fixed body");
4058
4303
  }
4059
4304
  if (stack.length !== 1) throw new TypeError("table lexical tree does not resolve to one root body");
@@ -4208,6 +4453,12 @@ function scanRefs(s) {
4208
4453
  refs.push(...s.skip);
4209
4454
  return refs;
4210
4455
  }
4456
+ function assemblyExtraIps(prog) {
4457
+ const ips = [];
4458
+ for (const s of prog.scans ?? []) for (const r of scanRefs(s)) ips.push(r[0]);
4459
+ for (const set of prog.scanSkip ?? []) for (const r of set) ips.push(r[0]);
4460
+ return ips;
4461
+ }
4211
4462
  function expandCompact(p) {
4212
4463
  if ("code" in p) return p;
4213
4464
  return ownTableProgram({
@@ -4338,6 +4589,11 @@ function classHas2(cls, code) {
4338
4589
  for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
4339
4590
  return false;
4340
4591
  }
4592
+ function dispatchIsExclusive(arms, cc) {
4593
+ const resolved = [];
4594
+ for (const ci of arms) if (ci >= 0) resolved[ci] = resolveClass(cc[ci]);
4595
+ return resolveDispatch(arms, resolved).exclusive;
4596
+ }
4341
4597
  function resolveDispatch(arms, cc) {
4342
4598
  const ascii = new Uint8Array(128);
4343
4599
  const hi = [];
@@ -4411,117 +4667,738 @@ function resolveTable(prog) {
4411
4667
  return built;
4412
4668
  }
4413
4669
 
4414
- // src/analysis/gating.ts
4415
- var choiceArms = (c) => c.arms;
4416
- function childrenOf(d) {
4417
- switch (d.tag) {
4418
- case "sequence":
4419
- case "choice":
4420
- return d.parsers;
4421
- case "dispatch":
4422
- return [
4423
- d.selector,
4424
- ...d.cases.map((c) => c.parser),
4425
- ...d.matchers ? d.matchers.map((c) => c.parser) : [],
4426
- ...d.otherwise === void 0 ? [] : [d.otherwise]
4427
- ];
4428
- case "sepBy":
4429
- return [d.parser, d.separator];
4430
- case "recover":
4431
- return [d.parser, d.sentinel];
4432
- case "scanTo":
4433
- return [
4434
- d.sentinel,
4435
- ...d.skip,
4436
- ...d.recoverAt === void 0 ? [] : [d.recoverAt],
4437
- ...d.stopAt === void 0 ? [] : [d.stopAt]
4438
- ];
4439
- case "grammar":
4440
- return d.triviaParser ? [d.parser, d.triviaParser] : [d.parser];
4441
- case "routed":
4442
- return d.fallback ? [d.fallback] : [];
4443
- case "lines":
4444
- return [d.prefix, d.body, ...d.first === void 0 ? [] : [d.first], ...d.lazy === void 0 ? [] : [d.lazy]];
4445
- case "columns":
4446
- return [];
4447
- // A `lazy` is a REFERENCE, not a subtree. Descending through it would make
4448
- // every rule's walk cover the whole reachable grammar — site paths become
4449
- // nonsense, and a structural hash includes half the grammar. Treated as a
4450
- // leaf, keyed by the rule name it refers to, which is also the right
4451
- // semantics: two productions referencing `g.Ident` really do fill that slot
4452
- // the same way.
4453
- case "lazy":
4454
- case "literal":
4455
- case "regex":
4456
- case "keywords":
4457
- case "guard":
4458
- case "adjacency":
4459
- case "unknown":
4460
- return [];
4461
- default: {
4462
- const rec = d;
4463
- return rec.parser ? [rec.parser] : [];
4464
- }
4465
- }
4670
+ // src/combinators/adjacency.ts
4671
+ function adjacencyOf(p) {
4672
+ return p._def.tag === "adjacency" ? p._def : null;
4466
4673
  }
4467
- var isAny = (fs) => fs.kind === "any";
4468
- function intersection(a, b) {
4469
- if (a.kind === "any") return b;
4470
- if (b.kind === "any") return a;
4471
- if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
4472
- const ranges = [];
4473
- for (const ra of a.ranges) for (const rb of b.ranges) {
4474
- const lo = Math.max(ra.lo, rb.lo);
4475
- const hi = Math.min(ra.hi, rb.hi);
4476
- if (lo <= hi) ranges.push({ lo, hi });
4477
- }
4478
- return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
4674
+ function adjacencyExpected(def) {
4675
+ if (def.polarity === "adjacent") return "adjacent";
4676
+ return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
4479
4677
  }
4480
- function combine(sets) {
4481
- let acc = { kind: "empty" };
4482
- for (const s of sets) {
4483
- if (s.kind === "any") return { kind: "any" };
4484
- if (s.kind === "empty") continue;
4485
- acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
4486
- }
4487
- return acc;
4678
+ function holdsAdjacency(input, cur, ctx, def) {
4679
+ return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
4488
4680
  }
4489
- var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
4490
- function firstSetToString(fs) {
4491
- if (fs.kind === "any") return "ANY";
4492
- if (fs.kind === "empty") return "(empty)";
4493
- return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
4681
+ function adjacencyHolds(input, cur, ctx, negated, kinds) {
4682
+ const end = probeTriviaEnd(input, cur, ctx);
4683
+ if (!negated) return end === cur;
4684
+ if (end === cur) return false;
4685
+ if (kinds === void 0) return true;
4686
+ const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
4687
+ const spec = analyzeLabeledTrivia(ctx.trivia);
4688
+ return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
4494
4689
  }
4495
- var ruleNameOf = (p) => p._ruleName;
4496
- var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
4497
- var SUGGESTIONS = {
4498
- "broad-recognizer": "This arm can begin with any character, so no single-character test can rule it out. The parser has to enter it \u2014 set up, try, and undo \u2014 at every position it reaches, instead of skipping it for free.\nTo fix: make the arm begin with a fixed character, word or keyword. If it is meant to be a catch-all that matches anything, leave it and add the choice to the accept list at the end.",
4499
- "leading-not": "This arm begins with a not(...) check, which matches nothing and so says nothing about which character the arm starts with. The parser then cannot rule the arm out and enters it everywhere.\nTo fix: put the term that actually consumes text first and keep not(...) after it as a trailing boundary. If you need to REQUIRE something ahead without consuming it, use peek(X) \u2014 it checks the same thing but still tells parseman that the arm starts with X.",
4500
- "nullable-prefix": "This arm begins with something optional \u2014 an optional(...) or a repeat that allows zero items \u2014 so the arm can also start with whatever comes AFTER it, and that is broad enough that no character rules the arm out.\nTo fix: give the optional part its own arm so each arm has a definite beginning, or require at least one item. A plain sepBy(item, sep) also matches nothing at all; pass { min: 1 } when the list must not be empty.",
4501
- "cross-artifact-ref": "This arm hands off to another rule, and that rule has the same problem \u2014 it can begin with any character \u2014 so the cost is inherited rather than caused here.\nTo fix: run this check on the rule it refers to and fix it there. One rule given a definite beginning fixes every choice that uses it.",
4502
- "opaque-wrapper": "This arm begins with a wrapper that only inspects parser state (a gate/withCtx/recover) and consumes no text, so it says nothing about which character the arm starts with.\nTo fix: put a term that actually matches text in front of the wrapper.",
4503
- "ref-cycle": "This arm refers back to itself through a cycle of rules, and parseman could not work out a definite first character for any of them.\nTo fix: make sure the base case of the recursion begins with a fixed character or keyword, so the cycle has somewhere definite to start."
4504
- };
4505
- function refineSuggestion(cause, arm) {
4506
- if (cause !== "broad-recognizer") return SUGGESTIONS[cause];
4507
- const lead2 = peelToLeading(arm);
4508
- const d = lead2._def;
4509
- if (d.tag === "regex" && KEYWORD_REGEX_RE.test(d.source)) {
4510
- return `This arm matches the fixed word \`${d.source}\` with a regular expression, and parseman cannot always tell from a regular expression which character it starts with.
4511
- To fix: write it as word('\u2026') or keywords([\u2026]) instead. They match exactly the same text and compile to the same character scan, but they also tell parseman the first character, which is what lets the parser skip this arm when it cannot match.`;
4512
- }
4513
- if (d.tag === "scanTo") {
4514
- return "This arm ends in a scanTo(...) catch-all, which reads forward until it finds something and so can begin at any character. The parser can never rule it out. That is usually exactly what you want from a fallback.\nTo fix: usually nothing. Add this choice to the accept list at the end so the check keeps flagging the choices that are real problems.";
4515
- }
4516
- return SUGGESTIONS[cause];
4690
+ function adjacencyFail(pos, def) {
4691
+ return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
4517
4692
  }
4518
- function classifyBroadArm(arm, resolve) {
4519
- const seen = /* @__PURE__ */ new Set();
4520
- const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
4521
- const walk = (p) => {
4522
- if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
4523
- seen.add(p);
4524
- const d = p._def;
4693
+ var NO_STANDALONE_PARSE = "adjacency assertions are boundary tests: use adjacent()/notAdjacent() as a NON-FIRST term of a sequence(), where the preceding term defines the gap being asserted.";
4694
+ function adjacencyMisuse(polarity) {
4695
+ return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
4696
+ }
4697
+ function adjacencyCombinator(def) {
4698
+ const meta = {
4699
+ // Zero-width and never leading (sequence() rejects index 0), so it contributes
4700
+ // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
4701
+ // rather than letting `any` poison the enclosing choice's dispatch.
4702
+ firstSet: { kind: "any" },
4703
+ canMatchNewline: false,
4704
+ isTrivia: false
4705
+ };
4706
+ return {
4707
+ _tag: "adjacency",
4708
+ _meta: meta,
4709
+ _def: def,
4710
+ parse() {
4711
+ throw adjacencyMisuse(def.polarity);
4712
+ }
4713
+ };
4714
+ }
4715
+ function adjacent() {
4716
+ return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
4717
+ }
4718
+ function notAdjacent(options) {
4719
+ const kinds = options?.kinds;
4720
+ if (kinds !== void 0) {
4721
+ if (!Array.isArray(kinds) || kinds.length === 0) {
4722
+ throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
4723
+ }
4724
+ for (const k of kinds) {
4725
+ if (typeof k !== "string" || k.length === 0) {
4726
+ throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
4727
+ }
4728
+ }
4729
+ }
4730
+ return adjacencyCombinator(
4731
+ kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
4732
+ );
4733
+ }
4734
+
4735
+ // src/combinators/sequence.ts
4736
+ function sequence(...parsers) {
4737
+ let adjacency = null;
4738
+ for (let i = 0; i < parsers.length; i++) {
4739
+ const a = adjacencyOf(parsers[i]);
4740
+ if (a === null) continue;
4741
+ if (i === 0) {
4742
+ throw new TypeError(
4743
+ `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
4744
+ );
4745
+ }
4746
+ ;
4747
+ (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
4748
+ }
4749
+ const hasAdjacency = adjacency !== null;
4750
+ let leading = null;
4751
+ for (let i = 1; i < parsers.length; i++) {
4752
+ if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
4753
+ }
4754
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
4755
+ const meta = {
4756
+ // Union through the nullable prefix — a leading optional()/many() lets a later
4757
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
4758
+ firstSet: sequenceFirstSet(parsers),
4759
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
4760
+ isTrivia: false
4761
+ };
4762
+ const def = { tag: "sequence", parsers };
4763
+ const scalarParsers = parsers.map(scalarOf);
4764
+ const parseScalar = (input, pos, ctx) => {
4765
+ let cur = pos;
4766
+ if (strictArity !== 0) {
4767
+ cur = scalarParsers[0](input, cur, ctx);
4768
+ if (cur < 0) return cur;
4769
+ const first = ctx._sv;
4770
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
4771
+ cur = scalarParsers[1](input, cur, ctx);
4772
+ if (cur < 0) return cur;
4773
+ const second = ctx._sv;
4774
+ if (strictArity === 2) {
4775
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
4776
+ return cur;
4777
+ }
4778
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
4779
+ cur = scalarParsers[2](input, cur, ctx);
4780
+ if (cur < 0) return cur;
4781
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
4782
+ return cur;
4783
+ }
4784
+ const values = def.valueUnused ? void 0 : [];
4785
+ for (let i = 0; i < scalarParsers.length; i++) {
4786
+ let termPos = cur;
4787
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
4788
+ const end = scalarParsers[i](input, termPos, ctx);
4789
+ if (end < 0) return end;
4790
+ if (values !== void 0) values.push(ctx._sv);
4791
+ if (end > termPos || termPos === cur) cur = end;
4792
+ }
4793
+ ctx._sv = values;
4794
+ return cur;
4795
+ };
4796
+ let followSentinels;
4797
+ return {
4798
+ _tag: "sequence",
4799
+ _meta: meta,
4800
+ _def: def,
4801
+ _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
4802
+ parse(input, pos, ctx) {
4803
+ const tolerant = ctx._tolerant === true;
4804
+ if (tolerant) {
4805
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
4806
+ parsers.slice(i + 1).reduce(
4807
+ (set, parser2) => union(set, firstSetOf(parser2)),
4808
+ { kind: "empty" }
4809
+ )
4810
+ ));
4811
+ }
4812
+ const inheritedSync = ctx._sync;
4813
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
4814
+ const values = def.valueUnused ? void 0 : [];
4815
+ let cur = pos;
4816
+ try {
4817
+ for (let i = 0; i < parsers.length; i++) {
4818
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
4819
+ const assertion = adjacency?.[i];
4820
+ if (assertion) {
4821
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
4822
+ if (values !== void 0) values.push(null);
4823
+ continue;
4824
+ }
4825
+ let termPos = cur;
4826
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
4827
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
4828
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
4829
+ if (ctx.trivia && i > 0) {
4830
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
4831
+ }
4832
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
4833
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
4834
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
4835
+ if (leading?.[i] === true) LEAD.at = cur;
4836
+ const result = parsers[i].parse(input, termPos, ctx);
4837
+ if (!result.ok) return result;
4838
+ if (values !== void 0) values.push(result.value);
4839
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
4840
+ else if (deferredTrivia) {
4841
+ rollbackScannedTriviaAt(
4842
+ ctx,
4843
+ markTlog,
4844
+ scanTlog,
4845
+ markLog,
4846
+ scanLog,
4847
+ markRootLog,
4848
+ scanRootLog
4849
+ );
4850
+ }
4851
+ }
4852
+ } finally {
4853
+ if (tolerant) ctx._sync = inheritedSync;
4854
+ }
4855
+ return {
4856
+ ok: true,
4857
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
4858
+ value: values ?? void 0,
4859
+ span: { start: pos, end: cur }
4860
+ };
4861
+ }
4862
+ };
4863
+ }
4864
+
4865
+ // src/compiler/degradation.ts
4866
+ function formatDegradation(d) {
4867
+ return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
4868
+ }
4869
+ var DETAIL_CAP = 8;
4870
+ function formatDegradations(list) {
4871
+ const byCode = /* @__PURE__ */ new Map();
4872
+ for (const d of list) {
4873
+ const bucket = byCode.get(d.code);
4874
+ if (bucket) bucket.push(d);
4875
+ else byCode.set(d.code, [d]);
4876
+ }
4877
+ const out = [];
4878
+ for (const [code, items] of byCode) {
4879
+ for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
4880
+ if (items.length > DETAIL_CAP) {
4881
+ out.push(
4882
+ `[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
4883
+ );
4884
+ }
4885
+ }
4886
+ return out;
4887
+ }
4888
+ var _sinks = [];
4889
+ function beginDegradationCapture() {
4890
+ _sinks.push(/* @__PURE__ */ new Map());
4891
+ }
4892
+ function degradationCaptureDepth() {
4893
+ return _sinks.length;
4894
+ }
4895
+ function unwindDegradationCapture(depth) {
4896
+ const found = [];
4897
+ while (_sinks.length > depth) {
4898
+ const sink = _sinks.pop();
4899
+ found.unshift(...sink.values());
4900
+ }
4901
+ return found;
4902
+ }
4903
+ function resolveDegradationLevel(explicit) {
4904
+ if (explicit !== void 0) return explicit;
4905
+ const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
4906
+ if (env === "off" || env === "warn" || env === "error") return env;
4907
+ return "warn";
4908
+ }
4909
+ function degradationKey(d) {
4910
+ return JSON.stringify([d.code, d.where, d.subject]);
4911
+ }
4912
+ function recordDegradation(d) {
4913
+ const level = resolveDegradationLevel();
4914
+ if (level === "off") return;
4915
+ const key = degradationKey(d);
4916
+ const sink = _sinks[_sinks.length - 1];
4917
+ if (sink) {
4918
+ if (!sink.has(key)) sink.set(key, d);
4919
+ return;
4920
+ }
4921
+ if (_immediate.has(key)) return;
4922
+ _immediate.add(key);
4923
+ if (level === "error") throw new Error(`parseman: degraded compilation path
4924
+ ${formatDegradation(d)}`);
4925
+ console.warn(formatDegradation(d));
4926
+ }
4927
+ var _immediate = /* @__PURE__ */ new Set();
4928
+ function beginCompileDegradationDrain() {
4929
+ if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
4930
+ };
4931
+ const depth = degradationCaptureDepth();
4932
+ beginDegradationCapture();
4933
+ return (report) => {
4934
+ const found = unwindDegradationCapture(depth);
4935
+ if (!report || found.length === 0) return;
4936
+ const fresh = found.filter((d) => {
4937
+ const k = degradationKey(d);
4938
+ if (_immediate.has(k)) return false;
4939
+ _immediate.add(k);
4940
+ return true;
4941
+ });
4942
+ if (fresh.length === 0) return;
4943
+ const lines2 = formatDegradations(fresh);
4944
+ if (resolveDegradationLevel() === "error") {
4945
+ throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
4946
+ ${lines2.join("\n")}`);
4947
+ }
4948
+ for (const l of lines2) console.warn(l);
4949
+ };
4950
+ }
4951
+
4952
+ // src/compiler/build-arity.ts
4953
+ function cstOutputHost(build) {
4954
+ return build?._parsemanCstOutput === true;
4955
+ }
4956
+ var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
4957
+ var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
4958
+ var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
4959
+ var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
4960
+ function confirmedBuildArity(src) {
4961
+ const s = src.trim();
4962
+ if (NATIVE_CODE_RE.test(s)) return null;
4963
+ if (/\barguments\b/.test(s)) return null;
4964
+ if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
4965
+ const inner = paramListText(s);
4966
+ if (inner === null) return null;
4967
+ if (inner.trim() === "") return 0;
4968
+ const parts = splitTopLevel(inner);
4969
+ if (parts === null) return null;
4970
+ for (const part of parts) {
4971
+ if (!isConfirmableParam(part.trim())) return null;
4972
+ }
4973
+ return parts.length;
4974
+ }
4975
+ function paramListText(s) {
4976
+ const open = PARAM_LIST_OPEN_RE.exec(s);
4977
+ if (!open) return null;
4978
+ const start = open[0].length;
4979
+ const end = matchingParen(s, start);
4980
+ if (end === null) return null;
4981
+ if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
4982
+ return s.slice(start, end);
4983
+ }
4984
+ function matchingParen(s, start) {
4985
+ let depth = 0;
4986
+ for (let i = start; i < s.length; i++) {
4987
+ const c = s[i];
4988
+ if (c === '"' || c === "'" || c === "`") {
4989
+ const close = skipString(s, i);
4990
+ if (close === null) return null;
4991
+ i = close;
4992
+ continue;
4993
+ }
4994
+ if (c === "(" || c === "[" || c === "{") depth++;
4995
+ else if (c === "]" || c === "}") {
4996
+ if (--depth < 0) return null;
4997
+ } else if (c === ")") {
4998
+ if (depth === 0) return i;
4999
+ depth--;
5000
+ }
5001
+ }
5002
+ return null;
5003
+ }
5004
+ function skipString(s, open) {
5005
+ const quote = s[open];
5006
+ for (let i = open + 1; i < s.length; i++) {
5007
+ if (s[i] === "\\") {
5008
+ i++;
5009
+ continue;
5010
+ }
5011
+ if (s[i] === quote) return i;
5012
+ }
5013
+ return null;
5014
+ }
5015
+ function splitTopLevel(inner) {
5016
+ const parts = [];
5017
+ let depth = 0;
5018
+ let angle = 0;
5019
+ let last = 0;
5020
+ for (let i = 0; i < inner.length; i++) {
5021
+ const c = inner[i];
5022
+ if (c === "=" && inner[i + 1] === ">") {
5023
+ i++;
5024
+ continue;
5025
+ }
5026
+ if (c === '"' || c === "'" || c === "`") {
5027
+ const close = skipString(inner, i);
5028
+ if (close === null) return null;
5029
+ i = close;
5030
+ continue;
5031
+ }
5032
+ if (c === "(" || c === "[" || c === "{") depth++;
5033
+ else if (c === ")" || c === "]" || c === "}") {
5034
+ if (--depth < 0) return null;
5035
+ } else if (c === "<") angle++;
5036
+ else if (c === ">") {
5037
+ if (--angle < 0) return null;
5038
+ } else if (c === "," && depth === 0 && angle === 0) {
5039
+ parts.push(inner.slice(last, i));
5040
+ last = i + 1;
5041
+ }
5042
+ }
5043
+ if (depth !== 0 || angle !== 0) return null;
5044
+ parts.push(inner.slice(last));
5045
+ return parts;
5046
+ }
5047
+ function isConfirmableParam(part) {
5048
+ const head = PARAM_HEAD_RE.exec(part);
5049
+ if (!head) return false;
5050
+ const rest = part.slice(head[0].length);
5051
+ if (rest === "") return true;
5052
+ if (rest[0] !== ":") return false;
5053
+ return !hasDefaultAssign(rest.slice(1));
5054
+ }
5055
+ function hasDefaultAssign(annotation) {
5056
+ for (let i = 0; i < annotation.length; i++) {
5057
+ if (annotation[i] !== "=") continue;
5058
+ if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5059
+ i++;
5060
+ continue;
5061
+ }
5062
+ const prev = annotation[i - 1];
5063
+ if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5064
+ return true;
5065
+ }
5066
+ return false;
5067
+ }
5068
+ function buildAnalysisSrc(def) {
5069
+ return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
5070
+ }
5071
+ var RESOLVER_REASONS = {
5072
+ "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5073
+ "arguments": "its body references `arguments`",
5074
+ "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5075
+ "not-a-function": "the binding it names is not a function declaration",
5076
+ "unresolved-import": "its module could not be resolved or parsed",
5077
+ "not-found": "the name did not resolve to any binding",
5078
+ "computed": "it is a computed expression",
5079
+ "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5080
+ "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5081
+ };
5082
+ function unconfirmableReason(def, src) {
5083
+ const declared = def.buildArityUnresolved;
5084
+ if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5085
+ const s = src.trim();
5086
+ const params = s.slice(0, s.indexOf(")") + 1);
5087
+ if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5088
+ if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5089
+ if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5090
+ return "it names a binding this build could not resolve to a function declaration";
5091
+ }
5092
+ return "its parameter list could not be parsed";
5093
+ }
5094
+ function confirmedArityForDef(def) {
5095
+ if (def.buildArity !== void 0) return def.buildArity;
5096
+ const src = buildAnalysisSrc(def);
5097
+ const arity = confirmedBuildArity(src);
5098
+ if (arity !== null) return arity;
5099
+ const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5100
+ recordDegradation({
5101
+ code: "build-arity-unconfirmed",
5102
+ severity: "warn",
5103
+ where: `node("${def.type ?? "<inferred>"}")`,
5104
+ subject,
5105
+ fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and hands it \`_ctx.state\` on every match`,
5106
+ otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
5107
+ });
5108
+ return null;
5109
+ }
5110
+ function buildReadsRaw(def) {
5111
+ if (!def.build) return true;
5112
+ if (def.buildRawUnused === true) return false;
5113
+ const arity = confirmedArityForDef(def);
5114
+ if (arity === null) return true;
5115
+ return arity >= 4;
5116
+ }
5117
+ function buildReadsTrivia(def) {
5118
+ if (!def.build) return true;
5119
+ const arity = confirmedArityForDef(def);
5120
+ if (arity === null) return true;
5121
+ return arity >= 5;
5122
+ }
5123
+ function buildReadsState(def) {
5124
+ if (!def.build) return true;
5125
+ const arity = confirmedArityForDef(def);
5126
+ if (arity === null) return true;
5127
+ return arity >= 6;
5128
+ }
5129
+
5130
+ // src/combinators/token.ts
5131
+ function semanticLeafValue(_ctx, _input, _start, _end, value) {
5132
+ return value;
5133
+ }
5134
+ function sourceLeafValue(ctx, input, start, end, value) {
5135
+ return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
5136
+ }
5137
+ function token(root) {
5138
+ const meta = {
5139
+ firstSet: root._meta.firstSet,
5140
+ canMatchNewline: root._meta.canMatchNewline,
5141
+ isTrivia: false
5142
+ };
5143
+ return {
5144
+ _tag: "token",
5145
+ _meta: meta,
5146
+ _def: { tag: "token", parser: root },
5147
+ parse(input, pos, ctx) {
5148
+ const savedTrivia = ctx.trivia;
5149
+ const savedKinds = ctx.triviaKindLabels;
5150
+ const savedBuf = ctx._cstBuf;
5151
+ const savedChildren = ctx._cstChildren;
5152
+ const savedLeaves = ctx._cstLeaves;
5153
+ const savedRaw = ctx._cstRawChildren;
5154
+ const savedTriviaLog = ctx._cstTriviaLog;
5155
+ const savedOuterTriviaLog = ctx._triviaLog;
5156
+ const savedRootTriviaLog = ctx._rootTriviaLog;
5157
+ const wasCapturing = cstCaptureActive(ctx);
5158
+ ctx.trivia = void 0;
5159
+ ctx.triviaKindLabels = void 0;
5160
+ ctx._cstBuf = void 0;
5161
+ ctx._cstChildren = void 0;
5162
+ ctx._cstLeaves = void 0;
5163
+ ctx._cstRawChildren = void 0;
5164
+ ctx._cstTriviaLog = void 0;
5165
+ ctx._triviaLog = void 0;
5166
+ ctx._rootTriviaLog = void 0;
5167
+ let result;
5168
+ try {
5169
+ result = root.parse(input, pos, ctx);
5170
+ } finally {
5171
+ ctx.trivia = savedTrivia;
5172
+ ctx.triviaKindLabels = savedKinds;
5173
+ ctx._cstBuf = savedBuf;
5174
+ ctx._cstChildren = savedChildren;
5175
+ ctx._cstLeaves = savedLeaves;
5176
+ ctx._cstRawChildren = savedRaw;
5177
+ ctx._cstTriviaLog = savedTriviaLog;
5178
+ ctx._triviaLog = savedOuterTriviaLog;
5179
+ ctx._rootTriviaLog = savedRootTriviaLog;
5180
+ }
5181
+ if (!result.ok) return result;
5182
+ const span = result.span;
5183
+ const value = input.slice(pos, span.end);
5184
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
5185
+ return { ok: true, value, span };
5186
+ }
5187
+ };
5188
+ }
5189
+ function makeLeaf(root, fn, sourceCstValue) {
5190
+ const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
5191
+ const meta = {
5192
+ firstSet: root._meta.firstSet,
5193
+ canMatchNewline: root._meta.canMatchNewline,
5194
+ isTrivia: false
5195
+ };
5196
+ return {
5197
+ _tag: "leaf",
5198
+ _meta: meta,
5199
+ _def: {
5200
+ tag: "leaf",
5201
+ parser: root,
5202
+ fn,
5203
+ ...sourceCstValue ? { cstValue: "source" } : {}
5204
+ },
5205
+ parse(input, pos, ctx) {
5206
+ const savedBuf = ctx._cstBuf;
5207
+ const savedChildren = ctx._cstChildren;
5208
+ const savedLeaves = ctx._cstLeaves;
5209
+ const savedRaw = ctx._cstRawChildren;
5210
+ const savedTriviaLog = ctx._cstTriviaLog;
5211
+ const savedOuterTriviaLog = ctx._triviaLog;
5212
+ const wasCapturing = cstCaptureActive(ctx);
5213
+ ctx._cstBuf = void 0;
5214
+ ctx._cstChildren = void 0;
5215
+ ctx._cstLeaves = void 0;
5216
+ ctx._cstRawChildren = void 0;
5217
+ ctx._cstTriviaLog = void 0;
5218
+ ctx._triviaLog = void 0;
5219
+ let result;
5220
+ try {
5221
+ result = root.parse(input, pos, ctx);
5222
+ } finally {
5223
+ ctx._cstBuf = savedBuf;
5224
+ ctx._cstChildren = savedChildren;
5225
+ ctx._cstLeaves = savedLeaves;
5226
+ ctx._cstRawChildren = savedRaw;
5227
+ ctx._cstTriviaLog = savedTriviaLog;
5228
+ ctx._triviaLog = savedOuterTriviaLog;
5229
+ }
5230
+ if (!result.ok) return result;
5231
+ const value = fn(result.value, result.span);
5232
+ if (wasCapturing) pushCstLeaf(ctx, {
5233
+ _tag: "leaf",
5234
+ value: cstValue(ctx, input, pos, result.span.end, value),
5235
+ span: result.span
5236
+ });
5237
+ return { ok: true, value, span: result.span };
5238
+ }
5239
+ };
5240
+ }
5241
+ function leaf(root, fn) {
5242
+ return makeLeaf(root, fn, false);
5243
+ }
5244
+ function sourceLeaf(root, fn) {
5245
+ return makeLeaf(root, fn, true);
5246
+ }
5247
+
5248
+ // src/combinators/attempt.ts
5249
+ function containOption(options) {
5250
+ if (options === void 0) return false;
5251
+ for (const key of Object.keys(options)) {
5252
+ if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
5253
+ }
5254
+ if (options.contain !== void 0 && typeof options.contain !== "boolean") {
5255
+ throw new TypeError("attempt(): `contain` must be a boolean");
5256
+ }
5257
+ return options.contain === true;
5258
+ }
5259
+ function attempt(parser2, options) {
5260
+ const contain = containOption(options);
5261
+ const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
5262
+ let failExpected;
5263
+ return {
5264
+ _tag: "attempt",
5265
+ _meta: parser2._meta,
5266
+ _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
5267
+ parse(input, pos, ctx) {
5268
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
5269
+ if (failExpected === void 0) {
5270
+ const e = deriveExpected(parser2);
5271
+ failExpected = e.length > 0 ? e : [parser2._tag];
5272
+ }
5273
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
5274
+ }
5275
+ const mark = saveCstMark(ctx);
5276
+ const log = ctx._triviaLog?.length;
5277
+ const rootLog = ctx._rootTriviaLog?.length;
5278
+ const split = ctx._columnsSplit;
5279
+ const result = parser2.parse(input, pos, ctx);
5280
+ if (result.ok) return result;
5281
+ rollbackCstCapture(ctx, mark);
5282
+ ctx._columnsSplit = split;
5283
+ if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
5284
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
5285
+ if (result.committed && !contain) return result;
5286
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
5287
+ }
5288
+ };
5289
+ }
5290
+
5291
+ // src/analysis/gating.ts
5292
+ var choiceArms = (c) => c.arms;
5293
+ function childrenOf(d) {
5294
+ switch (d.tag) {
5295
+ case "sequence":
5296
+ case "choice":
5297
+ return d.parsers;
5298
+ case "dispatch":
5299
+ return [
5300
+ d.selector,
5301
+ ...d.cases.map((c) => c.parser),
5302
+ ...d.matchers ? d.matchers.map((c) => c.parser) : [],
5303
+ ...d.otherwise === void 0 ? [] : [d.otherwise]
5304
+ ];
5305
+ case "sepBy":
5306
+ return [d.parser, d.separator];
5307
+ case "recover":
5308
+ return [d.parser, d.sentinel];
5309
+ case "scanTo":
5310
+ return [
5311
+ d.sentinel,
5312
+ ...d.skip,
5313
+ ...d.recoverAt === void 0 ? [] : [d.recoverAt],
5314
+ ...d.stopAt === void 0 ? [] : [d.stopAt]
5315
+ ];
5316
+ case "grammar":
5317
+ return d.triviaParser ? [d.parser, d.triviaParser] : [d.parser];
5318
+ case "routed":
5319
+ return d.fallback ? [d.fallback] : [];
5320
+ case "lines":
5321
+ return [d.prefix, d.body, ...d.first === void 0 ? [] : [d.first], ...d.lazy === void 0 ? [] : [d.lazy]];
5322
+ case "columns":
5323
+ return [];
5324
+ // A `lazy` is a REFERENCE, not a subtree. Descending through it would make
5325
+ // every rule's walk cover the whole reachable grammar — site paths become
5326
+ // nonsense, and a structural hash includes half the grammar. Treated as a
5327
+ // leaf, keyed by the rule name it refers to, which is also the right
5328
+ // semantics: two productions referencing `g.Ident` really do fill that slot
5329
+ // the same way.
5330
+ case "lazy":
5331
+ case "literal":
5332
+ case "regex":
5333
+ case "keywords":
5334
+ case "guard":
5335
+ case "adjacency":
5336
+ case "unknown":
5337
+ return [];
5338
+ default: {
5339
+ const rec = d;
5340
+ return rec.parser ? [rec.parser] : [];
5341
+ }
5342
+ }
5343
+ }
5344
+ var isAny = (fs) => fs.kind === "any";
5345
+ function intersection(a, b) {
5346
+ if (a.kind === "any") return b;
5347
+ if (b.kind === "any") return a;
5348
+ if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
5349
+ const ranges = [];
5350
+ for (const ra of a.ranges) for (const rb of b.ranges) {
5351
+ const lo = Math.max(ra.lo, rb.lo);
5352
+ const hi = Math.min(ra.hi, rb.hi);
5353
+ if (lo <= hi) ranges.push({ lo, hi });
5354
+ }
5355
+ return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
5356
+ }
5357
+ function combine(sets) {
5358
+ let acc = { kind: "empty" };
5359
+ for (const s of sets) {
5360
+ if (s.kind === "any") return { kind: "any" };
5361
+ if (s.kind === "empty") continue;
5362
+ acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
5363
+ }
5364
+ return acc;
5365
+ }
5366
+ var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
5367
+ function firstSetToString(fs) {
5368
+ if (fs.kind === "any") return "ANY";
5369
+ if (fs.kind === "empty") return "(empty)";
5370
+ return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
5371
+ }
5372
+ var ruleNameOf = (p) => p._ruleName;
5373
+ var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
5374
+ var SUGGESTIONS = {
5375
+ "broad-recognizer": "This arm can begin with any character, so no single-character test can rule it out. The parser has to enter it \u2014 set up, try, and undo \u2014 at every position it reaches, instead of skipping it for free.\nTo fix: make the arm begin with a fixed character, word or keyword. If it is meant to be a catch-all that matches anything, leave it and add the choice to the accept list at the end.",
5376
+ "leading-not": "This arm begins with a not(...) check, which matches nothing and so says nothing about which character the arm starts with. The parser then cannot rule the arm out and enters it everywhere.\nTo fix: put the term that actually consumes text first and keep not(...) after it as a trailing boundary. If you need to REQUIRE something ahead without consuming it, use peek(X) \u2014 it checks the same thing but still tells parseman that the arm starts with X.",
5377
+ "nullable-prefix": "This arm begins with something optional \u2014 an optional(...) or a repeat that allows zero items \u2014 so the arm can also start with whatever comes AFTER it, and that is broad enough that no character rules the arm out.\nTo fix: give the optional part its own arm so each arm has a definite beginning, or require at least one item. A plain sepBy(item, sep) also matches nothing at all; pass { min: 1 } when the list must not be empty.",
5378
+ "cross-artifact-ref": "This arm hands off to another rule, and that rule has the same problem \u2014 it can begin with any character \u2014 so the cost is inherited rather than caused here.\nTo fix: run this check on the rule it refers to and fix it there. One rule given a definite beginning fixes every choice that uses it.",
5379
+ "opaque-wrapper": "This arm begins with a wrapper that only inspects parser state (a gate/withCtx/recover) and consumes no text, so it says nothing about which character the arm starts with.\nTo fix: put a term that actually matches text in front of the wrapper.",
5380
+ "ref-cycle": "This arm refers back to itself through a cycle of rules, and parseman could not work out a definite first character for any of them.\nTo fix: make sure the base case of the recursion begins with a fixed character or keyword, so the cycle has somewhere definite to start."
5381
+ };
5382
+ function refineSuggestion(cause, arm) {
5383
+ if (cause !== "broad-recognizer") return SUGGESTIONS[cause];
5384
+ const lead2 = peelToLeading(arm);
5385
+ const d = lead2._def;
5386
+ if (d.tag === "regex" && KEYWORD_REGEX_RE.test(d.source)) {
5387
+ return `This arm matches the fixed word \`${d.source}\` with a regular expression, and parseman cannot always tell from a regular expression which character it starts with.
5388
+ To fix: write it as word('\u2026') or keywords([\u2026]) instead. They match exactly the same text and compile to the same character scan, but they also tell parseman the first character, which is what lets the parser skip this arm when it cannot match.`;
5389
+ }
5390
+ if (d.tag === "scanTo") {
5391
+ return "This arm ends in a scanTo(...) catch-all, which reads forward until it finds something and so can begin at any character. The parser can never rule it out. That is usually exactly what you want from a fallback.\nTo fix: usually nothing. Add this choice to the accept list at the end so the check keeps flagging the choices that are real problems.";
5392
+ }
5393
+ return SUGGESTIONS[cause];
5394
+ }
5395
+ function classifyBroadArm(arm, resolve) {
5396
+ const seen = /* @__PURE__ */ new Set();
5397
+ const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
5398
+ const walk = (p) => {
5399
+ if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
5400
+ seen.add(p);
5401
+ const d = p._def;
4525
5402
  switch (d.tag) {
4526
5403
  case "literal":
4527
5404
  case "regex":
@@ -5148,323 +6025,163 @@ function commitFailureSuccessors(p, resolve) {
5148
6025
  return [d.thunk()];
5149
6026
  } catch {
5150
6027
  const name = p._ruleName;
5151
- const target = name === void 0 ? void 0 : resolve?.(name);
5152
- return target === void 0 ? true : [target];
5153
- }
5154
- }
5155
- default:
5156
- return NO_EDGES;
5157
- }
5158
- }
5159
- function reachesMarked(root, successors, memo) {
5160
- const known = memo.get(root);
5161
- if (known !== void 0) return known;
5162
- const order = /* @__PURE__ */ new Map();
5163
- const low = [];
5164
- const found = [];
5165
- const stack = [];
5166
- const visit = (node2) => {
5167
- const at = low.length;
5168
- order.set(node2, at);
5169
- low.push(at);
5170
- found.push(false);
5171
- stack.push(node2);
5172
- const next = successors(node2);
5173
- if (next === true) found[at] = true;
5174
- else {
5175
- for (const child of next) {
5176
- if (found[at]) break;
5177
- const hit = memo.get(child);
5178
- if (hit !== void 0) {
5179
- if (hit) found[at] = true;
5180
- continue;
5181
- }
5182
- const seen = order.get(child);
5183
- if (seen !== void 0) {
5184
- if (seen < low[at]) low[at] = seen;
5185
- continue;
5186
- }
5187
- const k = visit(child);
5188
- if (low[k] < low[at]) low[at] = low[k];
5189
- if (found[k]) found[at] = true;
5190
- }
5191
- }
5192
- if (low[at] === at) {
5193
- const answer = found[at];
5194
- let member;
5195
- do {
5196
- member = stack.pop();
5197
- memo.set(member, answer);
5198
- } while (member !== node2);
5199
- }
5200
- return at;
5201
- };
5202
- return found[visit(root)];
5203
- }
5204
-
5205
- // src/compiler/degradation.ts
5206
- function formatDegradation(d) {
5207
- return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
5208
- }
5209
- var DETAIL_CAP = 8;
5210
- function formatDegradations(list) {
5211
- const byCode = /* @__PURE__ */ new Map();
5212
- for (const d of list) {
5213
- const bucket = byCode.get(d.code);
5214
- if (bucket) bucket.push(d);
5215
- else byCode.set(d.code, [d]);
5216
- }
5217
- const out = [];
5218
- for (const [code, items] of byCode) {
5219
- for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
5220
- if (items.length > DETAIL_CAP) {
5221
- out.push(
5222
- `[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
5223
- );
5224
- }
5225
- }
5226
- return out;
5227
- }
5228
- var _sinks = [];
5229
- function beginDegradationCapture() {
5230
- _sinks.push(/* @__PURE__ */ new Map());
5231
- }
5232
- function degradationCaptureDepth() {
5233
- return _sinks.length;
5234
- }
5235
- function unwindDegradationCapture(depth) {
5236
- const found = [];
5237
- while (_sinks.length > depth) {
5238
- const sink = _sinks.pop();
5239
- found.unshift(...sink.values());
5240
- }
5241
- return found;
5242
- }
5243
- function resolveDegradationLevel(explicit) {
5244
- if (explicit !== void 0) return explicit;
5245
- const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
5246
- if (env === "off" || env === "warn" || env === "error") return env;
5247
- return "warn";
5248
- }
5249
- function degradationKey(d) {
5250
- return JSON.stringify([d.code, d.where, d.subject]);
5251
- }
5252
- function recordDegradation(d) {
5253
- const level = resolveDegradationLevel();
5254
- if (level === "off") return;
5255
- const key = degradationKey(d);
5256
- const sink = _sinks[_sinks.length - 1];
5257
- if (sink) {
5258
- if (!sink.has(key)) sink.set(key, d);
5259
- return;
5260
- }
5261
- if (_immediate.has(key)) return;
5262
- _immediate.add(key);
5263
- if (level === "error") throw new Error(`parseman: degraded compilation path
5264
- ${formatDegradation(d)}`);
5265
- console.warn(formatDegradation(d));
5266
- }
5267
- var _immediate = /* @__PURE__ */ new Set();
5268
- function beginCompileDegradationDrain() {
5269
- if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
5270
- };
5271
- const depth = degradationCaptureDepth();
5272
- beginDegradationCapture();
5273
- return (report) => {
5274
- const found = unwindDegradationCapture(depth);
5275
- if (!report || found.length === 0) return;
5276
- const fresh = found.filter((d) => {
5277
- const k = degradationKey(d);
5278
- if (_immediate.has(k)) return false;
5279
- _immediate.add(k);
5280
- return true;
5281
- });
5282
- if (fresh.length === 0) return;
5283
- const lines2 = formatDegradations(fresh);
5284
- if (resolveDegradationLevel() === "error") {
5285
- throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
5286
- ${lines2.join("\n")}`);
5287
- }
5288
- for (const l of lines2) console.warn(l);
5289
- };
5290
- }
5291
-
5292
- // src/compiler/build-arity.ts
5293
- function cstOutputHost(build) {
5294
- return build?._parsemanCstOutput === true;
5295
- }
5296
- var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
5297
- var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
5298
- var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
5299
- var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
5300
- function confirmedBuildArity(src) {
5301
- const s = src.trim();
5302
- if (NATIVE_CODE_RE.test(s)) return null;
5303
- if (/\barguments\b/.test(s)) return null;
5304
- if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
5305
- const inner = paramListText(s);
5306
- if (inner === null) return null;
5307
- if (inner.trim() === "") return 0;
5308
- const parts = splitTopLevel(inner);
5309
- if (parts === null) return null;
5310
- for (const part of parts) {
5311
- if (!isConfirmableParam(part.trim())) return null;
5312
- }
5313
- return parts.length;
5314
- }
5315
- function paramListText(s) {
5316
- const open = PARAM_LIST_OPEN_RE.exec(s);
5317
- if (!open) return null;
5318
- const start = open[0].length;
5319
- const end = matchingParen(s, start);
5320
- if (end === null) return null;
5321
- if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
5322
- return s.slice(start, end);
5323
- }
5324
- function matchingParen(s, start) {
5325
- let depth = 0;
5326
- for (let i = start; i < s.length; i++) {
5327
- const c = s[i];
5328
- if (c === '"' || c === "'" || c === "`") {
5329
- const close = skipString(s, i);
5330
- if (close === null) return null;
5331
- i = close;
5332
- continue;
5333
- }
5334
- if (c === "(" || c === "[" || c === "{") depth++;
5335
- else if (c === "]" || c === "}") {
5336
- if (--depth < 0) return null;
5337
- } else if (c === ")") {
5338
- if (depth === 0) return i;
5339
- depth--;
5340
- }
5341
- }
5342
- return null;
5343
- }
5344
- function skipString(s, open) {
5345
- const quote = s[open];
5346
- for (let i = open + 1; i < s.length; i++) {
5347
- if (s[i] === "\\") {
5348
- i++;
5349
- continue;
6028
+ const target = name === void 0 ? void 0 : resolve?.(name);
6029
+ return target === void 0 ? true : [target];
6030
+ }
5350
6031
  }
5351
- if (s[i] === quote) return i;
6032
+ default:
6033
+ return NO_EDGES;
5352
6034
  }
5353
- return null;
5354
6035
  }
5355
- function splitTopLevel(inner) {
5356
- const parts = [];
5357
- let depth = 0;
5358
- let angle = 0;
5359
- let last = 0;
5360
- for (let i = 0; i < inner.length; i++) {
5361
- const c = inner[i];
5362
- if (c === "=" && inner[i + 1] === ">") {
5363
- i++;
5364
- continue;
5365
- }
5366
- if (c === '"' || c === "'" || c === "`") {
5367
- const close = skipString(inner, i);
5368
- if (close === null) return null;
5369
- i = close;
5370
- continue;
6036
+ function reachesMarked(root, successors, memo) {
6037
+ const known = memo.get(root);
6038
+ if (known !== void 0) return known;
6039
+ const order = /* @__PURE__ */ new Map();
6040
+ const low = [];
6041
+ const found = [];
6042
+ const stack = [];
6043
+ const visit = (node2) => {
6044
+ const at = low.length;
6045
+ order.set(node2, at);
6046
+ low.push(at);
6047
+ found.push(false);
6048
+ stack.push(node2);
6049
+ const next = successors(node2);
6050
+ if (next === true) found[at] = true;
6051
+ else {
6052
+ for (const child of next) {
6053
+ if (found[at]) break;
6054
+ const hit = memo.get(child);
6055
+ if (hit !== void 0) {
6056
+ if (hit) found[at] = true;
6057
+ continue;
6058
+ }
6059
+ const seen = order.get(child);
6060
+ if (seen !== void 0) {
6061
+ if (seen < low[at]) low[at] = seen;
6062
+ continue;
6063
+ }
6064
+ const k = visit(child);
6065
+ if (low[k] < low[at]) low[at] = low[k];
6066
+ if (found[k]) found[at] = true;
6067
+ }
5371
6068
  }
5372
- if (c === "(" || c === "[" || c === "{") depth++;
5373
- else if (c === ")" || c === "]" || c === "}") {
5374
- if (--depth < 0) return null;
5375
- } else if (c === "<") angle++;
5376
- else if (c === ">") {
5377
- if (--angle < 0) return null;
5378
- } else if (c === "," && depth === 0 && angle === 0) {
5379
- parts.push(inner.slice(last, i));
5380
- last = i + 1;
6069
+ if (low[at] === at) {
6070
+ const answer = found[at];
6071
+ let member;
6072
+ do {
6073
+ member = stack.pop();
6074
+ memo.set(member, answer);
6075
+ } while (member !== node2);
5381
6076
  }
5382
- }
5383
- if (depth !== 0 || angle !== 0) return null;
5384
- parts.push(inner.slice(last));
5385
- return parts;
6077
+ return at;
6078
+ };
6079
+ return found[visit(root)];
5386
6080
  }
5387
- function isConfirmableParam(part) {
5388
- const head = PARAM_HEAD_RE.exec(part);
5389
- if (!head) return false;
5390
- const rest = part.slice(head[0].length);
5391
- if (rest === "") return true;
5392
- if (rest[0] !== ":") return false;
5393
- return !hasDefaultAssign(rest.slice(1));
6081
+
6082
+ // src/table/factor-choice.ts
6083
+ var DERIVED = /* @__PURE__ */ new Set(["_tag", "_meta", "_def", "_parseScalar", "_stickyRegex", "parse"]);
6084
+ function isCombinator(v) {
6085
+ return typeof v === "object" && v !== null && "_def" in v && "_meta" in v;
6086
+ }
6087
+ function sameComb(a, b, depth) {
6088
+ if (a === b) return true;
6089
+ if (depth > 32 || a._tag !== b._tag) return false;
6090
+ for (const k of Object.keys(a)) if (!DERIVED.has(k)) return false;
6091
+ for (const k of Object.keys(b)) if (!DERIVED.has(k)) return false;
6092
+ return sameFields(a._def, b._def, depth, void 0);
6093
+ }
6094
+ function sameValue(u, v, depth) {
6095
+ if (u === v) return true;
6096
+ if (isCombinator(u) && isCombinator(v)) return sameComb(u, v, depth + 1);
6097
+ if (Array.isArray(u) && Array.isArray(v)) return u.length === v.length && u.every((x, i) => sameValue(x, v[i], depth));
6098
+ if (typeof u === "object" && u !== null && typeof v === "object" && v !== null && Object.getPrototypeOf(u) === Object.prototype && Object.getPrototypeOf(v) === Object.prototype) {
6099
+ return sameFields(u, v, depth, void 0);
6100
+ }
6101
+ return false;
5394
6102
  }
5395
- function hasDefaultAssign(annotation) {
5396
- for (let i = 0; i < annotation.length; i++) {
5397
- if (annotation[i] !== "=") continue;
5398
- if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5399
- i++;
6103
+ function sameFields(x, y, depth, skip) {
6104
+ const kx = Object.keys(x).filter((k) => k !== skip && x[k] !== void 0);
6105
+ const ky = Object.keys(y).filter((k) => k !== skip && y[k] !== void 0);
6106
+ if (kx.length !== ky.length) return false;
6107
+ for (const k of kx) {
6108
+ if (!(k in y)) return false;
6109
+ const u = x[k];
6110
+ const v = y[k];
6111
+ if (k === "fn" && typeof u === "function" && typeof v === "function" && u !== v) {
6112
+ if (typeof x.fnSrc !== "string" || x.fnSrc === "" || x.fnSrc !== y.fnSrc) return false;
5400
6113
  continue;
5401
6114
  }
5402
- const prev = annotation[i - 1];
5403
- if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5404
- return true;
6115
+ if (!sameValue(u, v, depth)) return false;
5405
6116
  }
5406
- return false;
5407
- }
5408
- function buildAnalysisSrc(def) {
5409
- return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
6117
+ return true;
5410
6118
  }
5411
- var RESOLVER_REASONS = {
5412
- "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5413
- "arguments": "its body references `arguments`",
5414
- "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5415
- "not-a-function": "the binding it names is not a function declaration",
5416
- "unresolved-import": "its module could not be resolved or parsed",
5417
- "not-found": "the name did not resolve to any binding",
5418
- "computed": "it is a computed expression",
5419
- "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5420
- "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5421
- };
5422
- function unconfirmableReason(def, src) {
5423
- const declared = def.buildArityUnresolved;
5424
- if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5425
- const s = src.trim();
5426
- const params = s.slice(0, s.indexOf(")") + 1);
5427
- if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5428
- if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5429
- if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5430
- return "it names a binding this build could not resolve to a function declaration";
6119
+ function rewrap(w, body) {
6120
+ const d = w._def;
6121
+ let out;
6122
+ if (d.tag === "leaf") {
6123
+ out = d.cstValue === "source" ? sourceLeaf(body, d.fn) : leaf(body, d.fn);
6124
+ if (d.fnSrc !== void 0) out._def.fnSrc = d.fnSrc;
6125
+ } else if (d.tag === "grammar") {
6126
+ out = d.clearTrivia === true ? noTrivia(body) : parser({ trivia: d.triviaParser ?? null }, body);
6127
+ } else return void 0;
6128
+ return sameFields(d, out._def, 0, "parser") ? out : void 0;
6129
+ }
6130
+ function unusedOf(seq) {
6131
+ return seq._def.tag === "sequence" && seq._def.valueUnused === true;
6132
+ }
6133
+ function never(c) {
6134
+ const t2 = c._def.tag;
6135
+ return t2 === "optional" || t2 === "many";
6136
+ }
6137
+ function factorSharedEnds(d) {
6138
+ const arms = d.parsers;
6139
+ if (arms.length < 2) return void 0;
6140
+ if (d.strategy.tag !== "firstMatch" && d.strategy.tag !== "sharedPrefix") return void 0;
6141
+ if (d.gates.some((g) => g !== null) || d.autoNot.some((a) => a !== null)) return void 0;
6142
+ const shapes = [];
6143
+ for (const arm of arms) {
6144
+ const wrappers = [];
6145
+ let c = arm;
6146
+ while ((c._def.tag === "leaf" || c._def.tag === "grammar") && wrappers.length < 4) {
6147
+ wrappers.push(c);
6148
+ c = c._def.parser;
6149
+ }
6150
+ if (c._def.tag !== "sequence" || c._def.parsers.length < 2) return void 0;
6151
+ shapes.push({ wrappers, terms: c._def.parsers, seq: c });
6152
+ }
6153
+ const first = shapes[0];
6154
+ const n = first.terms.length;
6155
+ for (const s of shapes) {
6156
+ if (s.wrappers.length !== first.wrappers.length || s.terms.length !== n) return void 0;
6157
+ if (unusedOf(s.seq) !== unusedOf(first.seq)) return void 0;
6158
+ for (let j = 0; j < s.wrappers.length; j++) {
6159
+ const a = first.wrappers[j]._def;
6160
+ const b = s.wrappers[j]._def;
6161
+ if (a.tag !== b.tag || !sameFields(a, b, 0, "parser")) return void 0;
6162
+ }
6163
+ }
6164
+ let at = -1;
6165
+ for (let i = 0; i < n; i++) {
6166
+ if (shapes.every((s) => sameComb(s.terms[i], first.terms[i], 0))) continue;
6167
+ if (at >= 0) return void 0;
6168
+ at = i;
6169
+ }
6170
+ if (at < 0) return void 0;
6171
+ for (let i = at + 1; i < n; i++) if (!never(first.terms[i])) return void 0;
6172
+ if (arms.some((a) => mayCommitFailure(a))) return void 0;
6173
+ const middle = choice(...shapes.map((s) => s.terms[at]));
6174
+ if (middle._def.tag === "choice" && middle._def.autoNot.some((a) => a !== null)) return void 0;
6175
+ const st = middle._def.tag === "choice" ? middle._def.strategy : void 0;
6176
+ if (st === void 0 || st.tag !== "firstMatch" && st.tag !== "sharedPrefix" && !(st.tag === "literalsLongestFirst" && st.sortedIndices.every((x, i) => x === i))) return void 0;
6177
+ let out = sequence(
6178
+ ...[...first.terms.slice(0, at), middle, ...first.terms.slice(at + 1)]
6179
+ );
6180
+ if (unusedOf(first.seq)) {
6181
+ out._def.valueUnused = true;
5431
6182
  }
5432
- return "its parameter list could not be parsed";
5433
- }
5434
- function confirmedArityForDef(def) {
5435
- if (def.buildArity !== void 0) return def.buildArity;
5436
- const src = buildAnalysisSrc(def);
5437
- const arity = confirmedBuildArity(src);
5438
- if (arity !== null) return arity;
5439
- const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5440
- recordDegradation({
5441
- code: "build-arity-unconfirmed",
5442
- severity: "warn",
5443
- where: `node("${def.type ?? "<inferred>"}")`,
5444
- subject,
5445
- fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
5446
- otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
5447
- });
5448
- return null;
5449
- }
5450
- function buildReadsRaw(def) {
5451
- if (!def.build) return true;
5452
- if (def.buildRawUnused === true) return false;
5453
- const arity = confirmedArityForDef(def);
5454
- if (arity === null) return true;
5455
- return arity >= 4;
5456
- }
5457
- function buildReadsTrivia(def) {
5458
- if (!def.build) return true;
5459
- const arity = confirmedArityForDef(def);
5460
- if (arity === null) return true;
5461
- return arity >= 5;
5462
- }
5463
- function buildReadsState(def) {
5464
- if (!def.build) return true;
5465
- const arity = confirmedArityForDef(def);
5466
- if (arity === null) return true;
5467
- return arity >= 6;
6183
+ for (let j = first.wrappers.length - 1; j >= 0 && out !== void 0; j--) out = rewrap(first.wrappers[j], out);
6184
+ return out === void 0 ? void 0 : attempt(out);
5468
6185
  }
5469
6186
 
5470
6187
  // src/compiler/fields.ts
@@ -5592,10 +6309,16 @@ function branchUsesRouted(branch) {
5592
6309
  return branch.usesRouted === true || parserUsesRouted(branch.parser);
5593
6310
  }
5594
6311
  function asciiFoldKey(key) {
5595
- let out = "";
5596
- for (let i = 0; i < key.length; i++) {
6312
+ let i = 0;
6313
+ for (; i < key.length; i++) {
6314
+ const c = key.charCodeAt(i);
6315
+ if (c >= 65 && c <= 90) break;
6316
+ }
6317
+ if (i === key.length) return key;
6318
+ let out = key.slice(0, i);
6319
+ for (; i < key.length; i++) {
5597
6320
  const c = key.charCodeAt(i);
5598
- out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
6321
+ out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : key[i];
5599
6322
  }
5600
6323
  return out;
5601
6324
  }
@@ -5643,6 +6366,7 @@ var OP_SCOPE_PLAIN = 41;
5643
6366
  var OP_LEX_BODY = 42;
5644
6367
  var OP_LEX_PROGRAM = 43;
5645
6368
  var OP_SOURCE_LEAF = 44;
6369
+ var OP_RGATE = 45;
5646
6370
  var OP_DISPATCH = 25;
5647
6371
  var OP_ROUTED = 26;
5648
6372
  var OP_NAMES = {
@@ -5662,100 +6386,36 @@ var OP_NAMES = {
5662
6386
  [OP_PEEK]: "PEEK",
5663
6387
  [OP_LEAF]: "LEAF",
5664
6388
  [OP_SOURCE_LEAF]: "SOURCE_LEAF",
6389
+ [OP_RGATE]: "RGATE",
5665
6390
  [OP_EMPTY]: "EMPTY",
5666
- [OP_LIT_TRACK]: "LIT_TRACK",
5667
- [OP_RX_TRACK]: "RX_TRACK",
5668
- [OP_NODE_TRACK]: "NODE_TRACK",
5669
- [OP_SCOPE]: "SCOPE",
5670
- [OP_EXPECT]: "EXPECT",
5671
- [OP_SEQX]: "SEQX",
5672
- [OP_SCAN]: "SCAN",
5673
- [OP_FIELD]: "FIELD",
5674
- [OP_LIT_CI]: "LIT_CI",
5675
- [OP_LIT_CI_TRACK]: "LIT_CI_TRACK",
5676
- [OP_DISPATCH]: "DISPATCH",
5677
- [OP_ROUTED]: "ROUTED",
5678
- [OP_TOKEN]: "TOKEN",
5679
- [OP_SCOPE_CAP]: "SCOPE_CAP",
5680
- [OP_WITHCTX]: "WITHCTX",
5681
- [OP_GUARD]: "GUARD",
5682
- [OP_ADJ]: "ADJ",
5683
- [OP_GREEDY]: "GREEDY",
5684
- [OP_REJECT]: "REJECT",
5685
- [OP_ARMGATE]: "ARMGATE",
5686
- [OP_LIVE]: "LIVE",
5687
- [OP_ATTEMPT]: "ATTEMPT",
5688
- [OP_LABEL]: "LABEL",
5689
- [OP_COV]: "COV",
5690
- [OP_SCOPE_PLAIN]: "SCOPE_PLAIN",
5691
- [OP_LEX_BODY]: "LEX_BODY",
5692
- [OP_LEX_PROGRAM]: "LEX_PROGRAM"
5693
- };
5694
-
5695
- // src/combinators/adjacency.ts
5696
- function adjacencyOf(p) {
5697
- return p._def.tag === "adjacency" ? p._def : null;
5698
- }
5699
- function adjacencyExpected(def) {
5700
- if (def.polarity === "adjacent") return "adjacent";
5701
- return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5702
- }
5703
- function holdsAdjacency(input, cur, ctx, def) {
5704
- return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5705
- }
5706
- function adjacencyHolds(input, cur, ctx, negated, kinds) {
5707
- const end = probeTriviaEnd(input, cur, ctx);
5708
- if (!negated) return end === cur;
5709
- if (end === cur) return false;
5710
- if (kinds === void 0) return true;
5711
- const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
5712
- const spec = analyzeLabeledTrivia(ctx.trivia);
5713
- return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
5714
- }
5715
- function adjacencyFail(pos, def) {
5716
- return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5717
- }
5718
- var NO_STANDALONE_PARSE = "adjacency assertions are boundary tests: use adjacent()/notAdjacent() as a NON-FIRST term of a sequence(), where the preceding term defines the gap being asserted.";
5719
- function adjacencyMisuse(polarity) {
5720
- return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
5721
- }
5722
- function adjacencyCombinator(def) {
5723
- const meta = {
5724
- // Zero-width and never leading (sequence() rejects index 0), so it contributes
5725
- // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
5726
- // rather than letting `any` poison the enclosing choice's dispatch.
5727
- firstSet: { kind: "any" },
5728
- canMatchNewline: false,
5729
- isTrivia: false
5730
- };
5731
- return {
5732
- _tag: "adjacency",
5733
- _meta: meta,
5734
- _def: def,
5735
- parse() {
5736
- throw adjacencyMisuse(def.polarity);
5737
- }
5738
- };
5739
- }
5740
- function adjacent() {
5741
- return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
5742
- }
5743
- function notAdjacent(options) {
5744
- const kinds = options?.kinds;
5745
- if (kinds !== void 0) {
5746
- if (!Array.isArray(kinds) || kinds.length === 0) {
5747
- throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
5748
- }
5749
- for (const k of kinds) {
5750
- if (typeof k !== "string" || k.length === 0) {
5751
- throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
5752
- }
5753
- }
5754
- }
5755
- return adjacencyCombinator(
5756
- kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
5757
- );
5758
- }
6391
+ [OP_LIT_TRACK]: "LIT_TRACK",
6392
+ [OP_RX_TRACK]: "RX_TRACK",
6393
+ [OP_NODE_TRACK]: "NODE_TRACK",
6394
+ [OP_SCOPE]: "SCOPE",
6395
+ [OP_EXPECT]: "EXPECT",
6396
+ [OP_SEQX]: "SEQX",
6397
+ [OP_SCAN]: "SCAN",
6398
+ [OP_FIELD]: "FIELD",
6399
+ [OP_LIT_CI]: "LIT_CI",
6400
+ [OP_LIT_CI_TRACK]: "LIT_CI_TRACK",
6401
+ [OP_DISPATCH]: "DISPATCH",
6402
+ [OP_ROUTED]: "ROUTED",
6403
+ [OP_TOKEN]: "TOKEN",
6404
+ [OP_SCOPE_CAP]: "SCOPE_CAP",
6405
+ [OP_WITHCTX]: "WITHCTX",
6406
+ [OP_GUARD]: "GUARD",
6407
+ [OP_ADJ]: "ADJ",
6408
+ [OP_GREEDY]: "GREEDY",
6409
+ [OP_REJECT]: "REJECT",
6410
+ [OP_ARMGATE]: "ARMGATE",
6411
+ [OP_LIVE]: "LIVE",
6412
+ [OP_ATTEMPT]: "ATTEMPT",
6413
+ [OP_LABEL]: "LABEL",
6414
+ [OP_COV]: "COV",
6415
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN",
6416
+ [OP_LEX_BODY]: "LEX_BODY",
6417
+ [OP_LEX_PROGRAM]: "LEX_PROGRAM"
6418
+ };
5759
6419
 
5760
6420
  // src/combinators/node.ts
5761
6421
  function unwrapChild(child) {
@@ -5818,7 +6478,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5818
6478
  }
5819
6479
  const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
5820
6480
  const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
5821
- const clonesState = build ? buildReadsState(def) : project === void 0;
6481
+ const readsState = build ? buildReadsState(def) : project === void 0;
5822
6482
  const hasOwnFields = parserHasOwnFields(combinator);
5823
6483
  const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
5824
6484
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
@@ -5859,12 +6519,11 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5859
6519
  ctx._triviaCaptureMask = savedMask;
5860
6520
  const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
5861
6521
  if (!r.ok) return r;
5862
- const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
6522
+ const st = readsState ? ctx.state : void 0;
5863
6523
  const nodeType = def.type ?? missingInferredType();
5864
6524
  const cstOutput = cstOutputHost(ctx.build);
5865
6525
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
5866
- const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
5867
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !build && project === void 0) && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
6526
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !build && project === void 0) && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, ctx.state, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, ctx.state, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
5868
6527
  const rawEntry2 = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
5869
6528
  if (saved.buf !== void 0 || saved.ch !== void 0) {
5870
6529
  pushCstChild(ctx, built, rawEntry2);
@@ -5960,7 +6619,10 @@ function selectOptionalSuffixLexBody(ir) {
5960
6619
  const token2 = { strategy: "token", estimatedOps: 2, body };
5961
6620
  return token2.estimatedOps < character.estimatedOps ? token2 : character;
5962
6621
  }
5963
- function directTokenBodyParser(parser2, resolve) {
6622
+ function reinstallsRuleTrivia(reference, target) {
6623
+ return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
6624
+ }
6625
+ function directTokenBodyParser(parser2, resolve, scope) {
5964
6626
  const outer = parser2._def;
5965
6627
  if (outer.tag !== "token") return void 0;
5966
6628
  let body = outer.parser;
@@ -5970,12 +6632,13 @@ function directTokenBodyParser(parser2, resolve) {
5970
6632
  const wrapper = body._def;
5971
6633
  if (wrapper.tag === "grammar") {
5972
6634
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
6635
+ if (scope !== void 0) scope.cleared = true;
5973
6636
  body = wrapper.parser;
5974
6637
  continue;
5975
6638
  }
5976
6639
  if (wrapper.tag === "lazy") {
5977
6640
  const target = resolvedLazyTarget(body, resolve);
5978
- if (target === void 0) return void 0;
6641
+ if (target === void 0 || reinstallsRuleTrivia(body, target)) return void 0;
5979
6642
  body = target;
5980
6643
  continue;
5981
6644
  }
@@ -6147,7 +6810,7 @@ function directNot2TokenBody(parser2, resolve) {
6147
6810
  terminal
6148
6811
  };
6149
6812
  }
6150
- function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6813
+ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared = false) {
6151
6814
  let current = parser2;
6152
6815
  const wrappers = /* @__PURE__ */ new Set();
6153
6816
  while (!wrappers.has(current)) {
@@ -6155,7 +6818,7 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6155
6818
  const def = current._def;
6156
6819
  if (def.tag === "lazy") {
6157
6820
  const target = resolvedLazyTarget(current, resolve);
6158
- if (target === void 0) return void 0;
6821
+ if (target === void 0 || reinstallsRuleTrivia(current, target)) return void 0;
6159
6822
  current = target;
6160
6823
  continue;
6161
6824
  }
@@ -6173,30 +6836,33 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6173
6836
  if (terminal !== void 0) return { kind: "terminal", terminal };
6174
6837
  const def = current._def;
6175
6838
  if (def.tag === "grammar") {
6839
+ if (def.triviaParser === void 0 && def.captureTrivia !== true && def.rootCapture !== "opaque" && def.constructionCaptureTriviaKinds === void 0) {
6840
+ return directFixedLexNode(def.parser, resolve, active, pureOnly, cleared || def.clearTrivia === true);
6841
+ }
6176
6842
  if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
6177
- return directFixedLexNode(def.parser, resolve, active, true);
6843
+ return directFixedLexNode(def.parser, resolve, active, true, cleared);
6178
6844
  }
6179
6845
  if (def.tag === "sequence") {
6180
6846
  if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
6181
- const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly));
6847
+ const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly, cleared));
6182
6848
  if (parts.some((part) => part === void 0)) return void 0;
6183
6849
  return { kind: "sequence", parts };
6184
6850
  }
6185
6851
  if (def.tag === "choice") {
6186
- if (def.parsers.length !== 2 && def.parsers.length !== 4 && def.parsers.length !== 8 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
6187
- const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly));
6852
+ if (def.parsers.length < 2 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
6853
+ const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly, cleared));
6188
6854
  if (arms.some((arm) => arm === void 0)) return void 0;
6189
- const final = classifyFinalChoice(def.parsers, resolve);
6190
6855
  return {
6191
6856
  kind: "choice",
6192
6857
  arms,
6193
- firstSets: final.firstSets,
6858
+ parsers: def.parsers,
6859
+ cleared,
6194
6860
  armExpected: def.parsers.map(deriveExpected),
6195
6861
  expected: def.parsers.flatMap(deriveExpected)
6196
6862
  };
6197
6863
  }
6198
6864
  if (def.tag === "not") {
6199
- const body = directFixedLexNode(def.parser, resolve, active, true);
6865
+ const body = directFixedLexNode(def.parser, resolve, active, true, cleared);
6200
6866
  return body === void 0 ? void 0 : {
6201
6867
  kind: "not",
6202
6868
  body,
@@ -6204,18 +6870,28 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6204
6870
  };
6205
6871
  }
6206
6872
  if (def.tag === "optional") {
6207
- const body = directFixedLexNode(def.parser, resolve, active, pureOnly);
6873
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
6208
6874
  return body === void 0 ? void 0 : { kind: "optional", body };
6209
6875
  }
6876
+ if (def.tag === "many" || def.tag === "oneOrMore") {
6877
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
6878
+ return body === void 0 ? void 0 : {
6879
+ kind: "repeat",
6880
+ body,
6881
+ min: def.tag === "many" ? 0 : def.min,
6882
+ max: def.max ?? -1
6883
+ };
6884
+ }
6210
6885
  return void 0;
6211
6886
  } finally {
6212
6887
  active.delete(current);
6213
6888
  }
6214
6889
  }
6215
6890
  function directFixedTokenBody(parser2, resolve) {
6216
- const body = directTokenBodyParser(parser2, resolve);
6891
+ const scope = { cleared: false };
6892
+ const body = directTokenBodyParser(parser2, resolve, scope);
6217
6893
  if (body === void 0) return void 0;
6218
- const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set());
6894
+ const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope.cleared);
6219
6895
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
6220
6896
  }
6221
6897
  function directBalancedTokenBody(parser2, resolve) {
@@ -6462,13 +7138,16 @@ var Encoder = class {
6462
7138
  }
6463
7139
  case "choice": {
6464
7140
  for (const arm of node2.arms) if (!emitNode(arm)) return false;
6465
- const op = node2.arms.length === 2 ? LEX_NODE_CHOICE2 : node2.arms.length === 4 ? LEX_NODE_CHOICE4 : node2.arms.length === 8 ? LEX_NODE_CHOICE8 : -1;
6466
- if (op < 0) return false;
6467
- words.push(op, this.expected(node2.expected));
7141
+ const final = classifyFinalChoice(
7142
+ node2.parsers,
7143
+ this.refResolver(),
7144
+ node2.cleared ? void 0 : this.activeTrivia
7145
+ );
7146
+ const classes = final.firstSets.map((first, i) => final.nullable[i] ? -1 : this.charClass(first));
7147
+ const exclusive = final.exclusive && classes.every((cls) => cls >= 0);
7148
+ words.push(LEX_NODE_CHOICE, node2.arms.length, exclusive ? 1 : 0, this.expected(node2.expected));
6468
7149
  for (let i = 0; i < node2.arms.length; i++) {
6469
- const first = node2.firstSets[i];
6470
- words.push(first.kind === "ranges" ? this.charClass(first) : -1);
6471
- words.push(this.expected(node2.armExpected[i]));
7150
+ words.push(classes[i], this.expected(node2.armExpected[i]));
6472
7151
  }
6473
7152
  return true;
6474
7153
  }
@@ -6480,6 +7159,10 @@ var Encoder = class {
6480
7159
  if (!emitNode(node2.body)) return false;
6481
7160
  words.push(LEX_NODE_OPTIONAL);
6482
7161
  return true;
7162
+ case "repeat":
7163
+ if (!emitNode(node2.body)) return false;
7164
+ words.push(LEX_NODE_REPEAT, node2.min, node2.max);
7165
+ return true;
6483
7166
  }
6484
7167
  };
6485
7168
  if (!emitNode(body.root)) return void 0;
@@ -6807,6 +7490,33 @@ var Encoder = class {
6807
7490
  return childrenOf(def);
6808
7491
  }
6809
7492
  }
7493
+ /**
7494
+ * THE FIRST-CHARACTER GATE OF AN `optional`, `not` OR `peek` CHILD.
7495
+ *
7496
+ * A non-nullable child cannot match at a character outside its first set, so
7497
+ * the wrapper's outcome there is already decided: `optional` yields `null`,
7498
+ * `not` succeeds, `peek` fails with its own set. The interpreter's `optional`
7499
+ * makes that test itself (`repeat.ts` `startsFirstSet`); the table entered the
7500
+ * child — a rollback mark, the call, the child's own failure — to learn it.
7501
+ *
7502
+ * The gate is an `OP_GATE` row around the child, so every engine runs it
7503
+ * unchanged, a probe or tolerant parse forwards through it as for a node's
7504
+ * gate, and the wrapper's row keeps its layout. The engines test the class
7505
+ * before taking the wrapper's mark. The first set is resolved through
7506
+ * `winners`, the analysis a choice arm's gate uses, so a composed rule's set
7507
+ * is the merged one. A scalar `not` child stays bare: `scalarTerminalNotChild`
7508
+ * already reduces it to one recognizer call.
7509
+ */
7510
+ lookaheadGate(p, child) {
7511
+ const op = this.code[child];
7512
+ if (op === OP_GATE || op === OP_LIT || op === OP_LIT_CI || op === OP_LIT_TRACK || op === OP_LIT_CI_TRACK || op === OP_RX || op === OP_RX_TRACK) return child;
7513
+ const rr = this.refResolver();
7514
+ if (matchesEmpty(p, /* @__PURE__ */ new Set(), rr)) return child;
7515
+ const cls = this.charClass(firstSetOf(p, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7516
+ if (cls < 0) return child;
7517
+ const e = deriveExpected(p);
7518
+ return this.emit(OP_GATE, cls, child, this.expected(e.length > 0 ? e : [p._tag]));
7519
+ }
6810
7520
  /** A first set becomes a char class string, or −1 for `any`. */
6811
7521
  charClass(fs) {
6812
7522
  if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
@@ -6818,12 +7528,19 @@ var Encoder = class {
6818
7528
  this.ccIndex.set(spec, i);
6819
7529
  return i;
6820
7530
  }
6821
- /** Bind a guard only when its class is already part of the program. Repeat
6822
- * gating must not grow the compact artifact merely to avoid a failed call. */
6823
- existingCharClass(fs) {
6824
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
6825
- const hit = this.ccIndex.get(encodeClassSpec(fs.ranges));
6826
- return hit !== void 0 && hit < 100 ? hit : -1;
7531
+ /**
7532
+ * The first set a node's or an attempt's fail-fast gate tests. A bare
7533
+ * cross-rule ref resolves through `winners` (a compose OVERRIDE may widen
7534
+ * it). Any other body keeps its construction-time `_meta.firstSet`, except
7535
+ * where that is `any`: under `compose()` a body that reaches a rule of
7536
+ * another piece is built before that rule exists, so its cached set is
7537
+ * `any` and the node got NO gate (jess's `CompoundSelector` was entered at
7538
+ * `{`, `Call` at `}`). The resolved set is the one a choice arm's gate uses,
7539
+ * over the final merged map.
7540
+ */
7541
+ gateFirstSet(p) {
7542
+ const cached = p._meta.firstSet;
7543
+ return p._def.tag === "lazy" || cached.kind === "any" ? firstSetOf(p, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : cached;
6827
7544
  }
6828
7545
  /**
6829
7546
  * Wrap one choice arm in its `autoNot` checks (`OP_REJECT`).
@@ -6951,6 +7668,50 @@ var Encoder = class {
6951
7668
  if (!hasOwnTriviaBoundary(target)) return ip;
6952
7669
  return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
6953
7670
  }
7671
+ /**
7672
+ * The `OP_RGATE` operands of a choice arm that opens with `routed()`, or
7673
+ * `undefined`. Through `node()`/scope wrappers and first sequence terms, the
7674
+ * arm's next term after the routed token is found; the gate is that term's
7675
+ * first characters, with the trivia in force at the boundary before it, so
7676
+ * the arm is entered only where it can get past the token. The term must be
7677
+ * unable to match empty or to commit, so a miss is exactly that term failing
7678
+ * at the token's end with its own set.
7679
+ */
7680
+ routedArmGate(arm) {
7681
+ const walk = (p, trivia2, depth) => {
7682
+ if (depth > 16) return void 0;
7683
+ const d = p._def;
7684
+ switch (d.tag) {
7685
+ case "routed":
7686
+ return "end";
7687
+ case "node":
7688
+ return walk(d.parser, trivia2, depth + 1);
7689
+ case "grammar":
7690
+ return walk(d.parser, d.clearTrivia === true ? void 0 : d.triviaParser ?? trivia2, depth + 1);
7691
+ case "sequence": {
7692
+ const head = d.parsers[0];
7693
+ if (head === void 0) return void 0;
7694
+ const r = walk(head, trivia2, depth + 1);
7695
+ if (r !== "end") return r;
7696
+ const next2 = d.parsers[1];
7697
+ return next2 === void 0 ? "end" : { next: next2, boundary: trivia2 };
7698
+ }
7699
+ default:
7700
+ return void 0;
7701
+ }
7702
+ };
7703
+ const follow = walk(arm, this.activeTrivia, 0);
7704
+ if (follow === void 0 || follow === "end") return void 0;
7705
+ const rr = this.refResolver();
7706
+ const { next, boundary } = follow;
7707
+ if (matchesEmpty(next, /* @__PURE__ */ new Set(), rr) || mayCommitFailure(next, rr, this.commitFailureMemo)) return void 0;
7708
+ const nextTag = next._def.tag;
7709
+ if (nextTag !== "literal" && nextTag !== "regex" && nextTag !== "keywords" && nextTag !== "label") return void 0;
7710
+ const first = firstSetOf(next, /* @__PURE__ */ new Set(), rr, boundary);
7711
+ const cls = this.charClass(boundary === void 0 ? first : union(first, firstSetOf(boundary, /* @__PURE__ */ new Set(), rr)));
7712
+ if (cls < 0) return void 0;
7713
+ return { cls, fx: this.expected(deriveExpected(next)) };
7714
+ }
6954
7715
  node(p) {
6955
7716
  const lazyRef = p._def.tag === "lazy";
6956
7717
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -7075,6 +7836,10 @@ var Encoder = class {
7075
7836
  return head;
7076
7837
  }
7077
7838
  case "choice": {
7839
+ if (this.plan === void 0) {
7840
+ const factored = factorSharedEnds(d);
7841
+ if (factored !== void 0) return this.node(factored).ip;
7842
+ }
7078
7843
  if (d.strategy.tag === "greedyClassify") {
7079
7844
  const superIndex = d.strategy.superIndex;
7080
7845
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -7098,9 +7863,12 @@ var Encoder = class {
7098
7863
  const kids = arms.map((c, k) => {
7099
7864
  const src = order[k];
7100
7865
  const checks = d.autoNot[src];
7101
- const inner = this.node(c).ip;
7102
- const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
7103
7866
  const gate = d.gates[src];
7867
+ const plain2 = (checks === null || checks === void 0 || checks.length === 0) && (gate === null || gate === void 0);
7868
+ const routedGate = plain2 ? this.routedArmGate(c) : void 0;
7869
+ const body = this.node(c).ip;
7870
+ const inner = routedGate === void 0 ? body : this.emit(OP_RGATE, routedGate.cls, body, routedGate.fx);
7871
+ const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
7104
7872
  const gated = gate === null || gate === void 0 ? ip : this.emit(OP_ARMGATE, this.fn(gate, d.gateSrcs?.[src] ?? null), ip, this.expected(deriveExpected(c)));
7105
7873
  return this.covWrap(gated, armCovIds?.[src], 1);
7106
7874
  });
@@ -7128,6 +7896,12 @@ var Encoder = class {
7128
7896
  if (transactionalFirst[i] !== void 0) classes[i] = -1;
7129
7897
  }
7130
7898
  }
7899
+ if (d.gates.some((g) => g !== null && g !== void 0) && !dispatchIsExclusive(classes, this.cc)) {
7900
+ for (let k = 0; k < classes.length; k++) {
7901
+ const gate = d.gates[order[k]];
7902
+ if (gate !== null && gate !== void 0) classes[k] = -1;
7903
+ }
7904
+ }
7131
7905
  const dispIdx = this.disp.length;
7132
7906
  this.disp.push(classes);
7133
7907
  let rollbackMask = kids.length > 31 ? -1 : 0;
@@ -7157,7 +7931,7 @@ var Encoder = class {
7157
7931
  case "oneOrMore": {
7158
7932
  const child = this.node(d.parser).ip;
7159
7933
  const rr = this.refResolver();
7160
- const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.existingCharClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7934
+ const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.charClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7161
7935
  const op = d.valueUnused ? OP_REPV : OP_REP;
7162
7936
  const min = d.tag === "many" ? 0 : d.min;
7163
7937
  return this.rec ? this.emit(op, child, min, d.max ?? -1, -1, 0, this.expected(deriveExpected(d.parser)), itemClass) : this.emit(op, child, min, d.max ?? -1, -1, 0);
@@ -7181,7 +7955,7 @@ var Encoder = class {
7181
7955
  return d.min >= 2 ? this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags, this.expected(deriveExpected(d.parser))) : this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags);
7182
7956
  }
7183
7957
  case "optional": {
7184
- const head = this.emit(OP_OPT, this.node(d.parser).ip);
7958
+ const head = this.emit(OP_OPT, this.lookaheadGate(d.parser, this.node(d.parser).ip));
7185
7959
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(head);
7186
7960
  return head;
7187
7961
  }
@@ -7229,8 +8003,8 @@ var Encoder = class {
7229
8003
  // every CST node, so this is load-bearing, not reflection trivia.
7230
8004
  d.tags === void 0 ? -1 : this.constant(d.tags)
7231
8005
  );
7232
- if (matchesEmpty(d.parser)) return body;
7233
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
8006
+ if (matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return body;
8007
+ const fs = this.gateFirstSet(d.parser);
7234
8008
  if (fs.kind === "any") return body;
7235
8009
  const cls = this.charClass(fs);
7236
8010
  if (cls < 0) return body;
@@ -7322,7 +8096,7 @@ var Encoder = class {
7322
8096
  // other engine reported `['not(literal)']`. It hid because `expected` is a
7323
8097
  // TOP-LEVEL field on `RunResult` and is NOT part of the identity digest.
7324
8098
  case "not":
7325
- return this.emit(OP_NOT, this.node(d.parser).ip, this.expected(assertionFailureExpected(false, d.parser._tag)));
8099
+ return this.emit(OP_NOT, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(false, d.parser._tag)));
7326
8100
  case "guard":
7327
8101
  return this.emit(OP_GUARD, this.fn(d.predicate, d.predSrc ?? null), this.expected(["gate"]));
7328
8102
  case "adjacency":
@@ -7343,14 +8117,14 @@ var Encoder = class {
7343
8117
  return this.emit(OP_WITHCTX, this.constant(d.extra), this.node(d.parser).ip);
7344
8118
  }
7345
8119
  case "peek":
7346
- return this.emit(OP_PEEK, this.node(d.parser).ip, this.expected(assertionFailureExpected(true, d.parser._tag)));
8120
+ return this.emit(OP_PEEK, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(true, d.parser._tag)));
7347
8121
  // A TRANSACTION IS A ROW. See `OP_ATTEMPT` for why the transparent
7348
8122
  // lowering was correct only for a choice arm.
7349
8123
  case "attempt": {
7350
8124
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip, d.contain === true ? 1 : 0);
7351
8125
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7352
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
7353
- if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
8126
+ const fs = this.gateFirstSet(d.parser);
8127
+ if (fs.kind === "any" || matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return inner;
7354
8128
  const cls = this.charClass(fs);
7355
8129
  if (cls < 0) return inner;
7356
8130
  const e = deriveExpected(d.parser);
@@ -7418,6 +8192,7 @@ var Encoder = class {
7418
8192
  const slots = (ip) => {
7419
8193
  switch (this.code[ip]) {
7420
8194
  case OP_GATE:
8195
+ case OP_RGATE:
7421
8196
  return [ip + 2];
7422
8197
  case OP_RULE:
7423
8198
  case OP_OPT:
@@ -8645,6 +9420,7 @@ function childSlots(code, ip, out) {
8645
9420
  case OP_LEAF:
8646
9421
  case OP_SOURCE_LEAF:
8647
9422
  case OP_ARMGATE:
9423
+ case OP_RGATE:
8648
9424
  out.push(code[ip + 2]);
8649
9425
  return true;
8650
9426
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -8728,6 +9504,42 @@ function reachableSites(code, roots) {
8728
9504
  }
8729
9505
  return seen;
8730
9506
  }
9507
+ function passCollapse(code, ip, hostCst) {
9508
+ const flags = code[ip + 3];
9509
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
9510
+ if (flags !== 32 && flags !== 34) return false;
9511
+ let at = code[ip + 2];
9512
+ for (let n = 0; n < 8; n++) {
9513
+ const op = code[at];
9514
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
9515
+ else if (op === OP_RULE) at = code[at + 1];
9516
+ else break;
9517
+ }
9518
+ return code[at] === OP_NODE;
9519
+ }
9520
+ function gatedPassCollapse(code, ip, hostCst) {
9521
+ const flags = code[ip + 3];
9522
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
9523
+ if (flags !== 32 && flags !== 34) return void 0;
9524
+ const seq = code[ip + 2];
9525
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
9526
+ const n = code[seq + 1];
9527
+ if (n < 2) return void 0;
9528
+ const leads = [];
9529
+ const lits = [];
9530
+ for (let i = 0; i < n - 1; i++) {
9531
+ const t2 = code[seq + 2 + i];
9532
+ if (code[t2] !== OP_OPT && code[t2] !== OP_NOT) return void 0;
9533
+ const g = code[t2 + 1];
9534
+ if (code[g] === OP_GATE) leads.push(g);
9535
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
9536
+ else return void 0;
9537
+ }
9538
+ const last = code[seq + 2 + n - 1];
9539
+ let at = last;
9540
+ for (let k = 0; k < 8 && (code[at] === OP_GATE || code[at] === OP_RULE); k++) at = code[at] === OP_RULE ? code[at + 1] : code[at + 2];
9541
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
9542
+ }
8731
9543
  function transfer(code, ip, at, hostCst) {
8732
9544
  const op = code[ip];
8733
9545
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -8739,14 +9551,18 @@ function transfer(code, ip, at, hostCst) {
8739
9551
  }
8740
9552
  if (op === OP_NODE || op === OP_NODE_TRACK) {
8741
9553
  const flags = code[ip + 3];
9554
+ if (passCollapse(code, ip, hostCst)) return at;
9555
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
8742
9556
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
8743
9557
  if (directChildren) {
8744
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9558
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9559
+ return gated ? meet(at, framed2) : framed2;
8745
9560
  }
8746
9561
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
8747
9562
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
8748
9563
  if (at.buf && raw === at.raw && cap === at.cap) return at;
8749
- return { tri: at.tri, buf: true, raw, cap };
9564
+ const framed = { tri: at.tri, buf: true, raw, cap };
9565
+ return gated ? meet(at, framed) : framed;
8750
9566
  }
8751
9567
  if (op === OP_TOKEN) {
8752
9568
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -8784,6 +9600,40 @@ function computeSiteLabels(code, roots, hostCst) {
8784
9600
  }
8785
9601
  return { at: (ip) => labels.get(ip) ?? TOP };
8786
9602
  }
9603
+ function scopeIsIdentity(code, ip, at) {
9604
+ const op = code[ip];
9605
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
9606
+ const ki = code[ip + 1];
9607
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
9608
+ }
9609
+ function scanHandoffNeeded(code, ip, labels) {
9610
+ const seen = /* @__PURE__ */ new Set();
9611
+ const stack = [ip];
9612
+ const kids = [];
9613
+ while (stack.length > 0) {
9614
+ const at = stack.pop();
9615
+ if (seen.has(at)) continue;
9616
+ seen.add(at);
9617
+ const l = labels.at(at);
9618
+ if (l.tri === TRI_UNKNOWN) return true;
9619
+ const op = code[at];
9620
+ if (op === OP_SCAN) return true;
9621
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue;
9622
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1] >= 0 && l.tri === code[at + 1] && (op === OP_SCOPE_PLAIN || code[at + 3] === 0))) continue;
9623
+ kids.length = 0;
9624
+ if (!childSlots(code, at, kids)) return true;
9625
+ for (const c of kids) stack.push(c);
9626
+ }
9627
+ return false;
9628
+ }
9629
+ function triviaLeadRanges(tri, trivia2) {
9630
+ if (tri === TRI_NONE) return [];
9631
+ if (tri < 0) return void 0;
9632
+ const fs = trivia2[tri]?._meta.firstSet;
9633
+ if (fs === void 0) return void 0;
9634
+ if (fs.kind === "empty") return [];
9635
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
9636
+ }
8787
9637
 
8788
9638
  // src/table/scalar-terminal.ts
8789
9639
  function makeScalarRecognizer(op, spec) {
@@ -8821,6 +9671,12 @@ function scalarTerminalNotChild(code, ip) {
8821
9671
  const op = code[child];
8822
9672
  return op === OP_RX || op === OP_LIT ? child : -1;
8823
9673
  }
9674
+ function scalarTerminalPeekChild(code, ip) {
9675
+ if (code[ip] !== OP_PEEK) return -1;
9676
+ const child = code[ip + 1];
9677
+ const op = code[child];
9678
+ return op === OP_RX || op === OP_LIT ? child : -1;
9679
+ }
8824
9680
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
8825
9681
  const seen = /* @__PURE__ */ new Set();
8826
9682
  let at = ip;
@@ -8998,6 +9854,59 @@ function leadingTriviaFieldAt(code, k, ip) {
8998
9854
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
8999
9855
  }
9000
9856
 
9857
+ // src/table/hold-gap.ts
9858
+ var WRAPPERS = /* @__PURE__ */ new Set([
9859
+ OP_NODE,
9860
+ OP_XFORM,
9861
+ OP_LEAF,
9862
+ OP_SOURCE_LEAF,
9863
+ OP_TOKEN,
9864
+ OP_SCOPE,
9865
+ OP_SCOPE_CAP,
9866
+ OP_SCOPE_PLAIN,
9867
+ OP_FIELD,
9868
+ OP_LABEL,
9869
+ OP_EXPECT,
9870
+ OP_WITHCTX,
9871
+ OP_RULE,
9872
+ OP_ATTEMPT,
9873
+ OP_COV
9874
+ ]);
9875
+ function rowNullable(code, k, ip, memo) {
9876
+ const hit = memo.get(ip);
9877
+ if (hit !== void 0) return hit;
9878
+ memo.set(ip, true);
9879
+ const op = code[ip];
9880
+ const kids = [];
9881
+ let out = true;
9882
+ if (op === OP_GATE) out = false;
9883
+ else if (op === OP_LIT || op === OP_LIT_CI) out = k[code[ip + 1]].length === 0;
9884
+ else if (op === OP_RX) {
9885
+ const re = k[code[ip + 1]];
9886
+ out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
9887
+ } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
9888
+ childSlots(code, ip, kids);
9889
+ out = kids.every((c) => rowNullable(code, k, c, memo));
9890
+ } else if (op === OP_CHOICE) {
9891
+ childSlots(code, ip, kids);
9892
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
9893
+ } else if (op === OP_REP || op === OP_REPV) {
9894
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
9895
+ } else if (WRAPPERS.has(op)) {
9896
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
9897
+ }
9898
+ memo.set(ip, out);
9899
+ return out;
9900
+ }
9901
+ function holdsGap(code, k, base, n, i, memo) {
9902
+ if (i < 1 || i + 1 >= n) return false;
9903
+ const term = code[base + i];
9904
+ if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
9905
+ const next = code[base + i + 1];
9906
+ if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
9907
+ return !rowNullable(code, k, next, memo);
9908
+ }
9909
+
9001
9910
  // src/table/emit-assembly.ts
9002
9911
  var Unemittable = class extends Error {
9003
9912
  construct;
@@ -9075,7 +9984,13 @@ var EMITTED_PARAMS = [
9075
9984
  // Appended for trivia-attributing fields (`field(…, { leadingTrivia })`);
9076
9985
  // old factories ignore them.
9077
9986
  "LEAD",
9078
- "triviaFieldCapture"
9987
+ "triviaFieldCapture",
9988
+ // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
9989
+ // factories ignore it.
9990
+ "skipDeferredTrivia",
9991
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
9992
+ // ignore it.
9993
+ "collapseEmpty"
9079
9994
  ];
9080
9995
  var RUNTIME_PRELUDE = `
9081
9996
  let _pfScan=null
@@ -9096,7 +10011,7 @@ function _skipTrivia(input,cur,ctx){
9096
10011
  const s=_pfScan
9097
10012
  if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
9098
10013
  if(s!==null)return skipTriviaScanned(s,input,cur,ctx)
9099
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
10014
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
9100
10015
  return advanceTrivia(input,cur,ctx)
9101
10016
  }
9102
10017
  function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,{_tag:'leaf',value,span:{start:s,end:e}})}
@@ -9272,6 +10187,24 @@ ${fast}
9272
10187
  ${scanned}
9273
10188
  }`;
9274
10189
  }
10190
+ function emitHoldTerm(callee, dst, t2, l, skip) {
10191
+ const fast = `const ${t2}v=${callee}(input,cur,ctx)
10192
+ if(${t2}v===FAIL)return FAIL
10193
+ ${dst}=${t2}v
10194
+ cur=EC.e`;
10195
+ if (l.tri === TRI_NONE) return fast;
10196
+ const held = `const ${t2}s=${skip}(input,cur,ctx)
10197
+ const ${t2}v=${callee}(input,${t2}s,ctx)
10198
+ if(${t2}v===FAIL)return FAIL
10199
+ ${dst}=${t2}v
10200
+ cur=${t2}s`;
10201
+ if (l.tri !== TRI_UNKNOWN) return held;
10202
+ return `if(ctx.trivia===undefined){
10203
+ ${fast}
10204
+ }else{
10205
+ ${held}
10206
+ }`;
10207
+ }
9275
10208
  function leadSkip(hasTrivia, leadTrivia, skip) {
9276
10209
  if (hasTrivia === "false") return "{}";
9277
10210
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -9303,7 +10236,7 @@ function rebuildPools(cc, fx, disp, plan) {
9303
10236
  })
9304
10237
  };
9305
10238
  }
9306
- function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
10239
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select) {
9307
10240
  const { code, k, fx, disp, dsp, triviaLabelled } = t2;
9308
10241
  const swapLegal = !cfg.trackLines;
9309
10242
  const hostCst = cfg.hostCst;
@@ -9313,6 +10246,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9313
10246
  const reachable = [...reachableSites(code, roots)];
9314
10247
  const labels = computeSiteLabels(code, roots, hostCst);
9315
10248
  const scalarSpecs = /* @__PURE__ */ new Set();
10249
+ const nullable2 = /* @__PURE__ */ new Map();
9316
10250
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
9317
10251
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
9318
10252
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -9402,6 +10336,8 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9402
10336
  };
9403
10337
  const bodies = [];
9404
10338
  const byIp = /* @__PURE__ */ new Map();
10339
+ const externals = [];
10340
+ const siteBytes = /* @__PURE__ */ new Map();
9405
10341
  const reached = /* @__PURE__ */ new Set();
9406
10342
  const prelude = [];
9407
10343
  const skipDefs = [];
@@ -9537,6 +10473,18 @@ return 1
9537
10473
  tokenDecisionRefs.set(dispatchIp, made);
9538
10474
  return made;
9539
10475
  }
10476
+ function gateMissTest(gip) {
10477
+ const resolved = t2.cc[code[gip + 1]];
10478
+ const ci = classes.push([resolved]) - 1;
10479
+ classPlan.push([code[gip + 1]]);
10480
+ const cls = hoist("cl", `CLS[${ci}][0]`);
10481
+ return isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`;
10482
+ }
10483
+ function lookaheadMiss(child, miss) {
10484
+ if (code[child] !== OP_GATE || cfg.tolerant || cfg.probe) return "";
10485
+ return `if(${gateMissTest(child)}){${miss}}
10486
+ `;
10487
+ }
9540
10488
  function skipFor(l) {
9541
10489
  if (l.tri < 0) return "_skipTrivia";
9542
10490
  const ki = l.tri;
@@ -9547,8 +10495,8 @@ return 1
9547
10495
  const nm = `_sk${skipPool.size}`;
9548
10496
  skipPool.set(key, nm);
9549
10497
  if (!hasScan) {
9550
- skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return commitTriviaScan(scanTriviaCompact(input,cur,ctx))}` : `function ${nm}(input,cur,ctx){
9551
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
10498
+ skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10499
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
9552
10500
  return advanceTrivia(input,cur,ctx)}`);
9553
10501
  return nm;
9554
10502
  }
@@ -9593,9 +10541,17 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9593
10541
  const target = resolveAlias(ip);
9594
10542
  const done = byIp.get(target);
9595
10543
  if (done !== void 0) return done;
10544
+ if (select !== void 0 && !select.has(target)) {
10545
+ const ext = `_px${target}`;
10546
+ byIp.set(target, ext);
10547
+ externals.push(target);
10548
+ return ext;
10549
+ }
9596
10550
  const fname = `_pf${target}`;
9597
10551
  byIp.set(target, fname);
9598
- bodies.push(lower(target, fname));
10552
+ const body = lower(target, fname);
10553
+ siteBytes.set(target, body.length);
10554
+ bodies.push(body);
9599
10555
  return fname;
9600
10556
  }
9601
10557
  function resolveAlias(ip) {
@@ -9615,9 +10571,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9615
10571
  const op = code[ip];
9616
10572
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
9617
10573
  if (op === OP_RULE) return code[ip + 1];
9618
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
9619
- return code[ip + 2];
9620
- }
10574
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
9621
10575
  return void 0;
9622
10576
  }
9623
10577
  function lower(ip, fname) {
@@ -9735,14 +10689,44 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9735
10689
  return `${head}EC.e=pos;return ''}`;
9736
10690
  case OP_GATE: {
9737
10691
  const child = link(code[ip + 2]);
10692
+ const xf = fxRef(code[ip + 3]);
10693
+ return `${head}
10694
+ if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10695
+ return ${child}(input,pos,ctx)
10696
+ }`;
10697
+ }
10698
+ case OP_RGATE: {
10699
+ const child = link(code[ip + 2]);
10700
+ if (cfg.tolerant || cfg.probe) return `${head}
10701
+ return ${child}(input,pos,ctx)
10702
+ }`;
9738
10703
  const resolved = t2.cc[code[ip + 1]];
9739
10704
  const ci = classes.push([resolved]) - 1;
9740
10705
  classPlan.push([code[ip + 1]]);
9741
10706
  const cls = hoist("cl", `CLS[${ci}][0]`);
9742
10707
  const xf = fxRef(code[ip + 3]);
9743
10708
  return `${head}
9744
- if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10709
+ const it=ctx._routed
10710
+ if(it!==undefined&&it.span.start===pos&&!classHas(${cls},lead(input,it.span.end))){ctx._fe=it.span.end;ctx._fx=${xf};return FAIL}
10711
+ return ${child}(input,pos,ctx)
10712
+ }`;
10713
+ }
10714
+ case OP_ARMGATE: {
10715
+ const pred = fnRef(code[ip + 1]);
10716
+ const child = link(code[ip + 2]);
10717
+ const xf = fxRef(code[ip + 3]);
10718
+ return `${head}
10719
+ if(!${pred}(ctx.state)){ctx._fc=false;ctx._fe=-1;ctx._fx=${xf};return FAIL}
9745
10720
  return ${child}(input,pos,ctx)
10721
+ }`;
10722
+ }
10723
+ case OP_WITHCTX: {
10724
+ const ki = code[ip + 1];
10725
+ const child = link(code[ip + 2]);
10726
+ return `${head}
10727
+ const saved=ctx.state
10728
+ ctx.state=${ki < 0 ? `${fnRef(~ki)}(saved)` : kRef(ki)}
10729
+ try{return ${child}(input,pos,ctx)}finally{ctx.state=saved}
9746
10730
  }`;
9747
10731
  }
9748
10732
  case OP_XFORM: {
@@ -9998,24 +10982,34 @@ return FAIL
9998
10982
  const xf = fxRef(code[ip + 2]);
9999
10983
  const p = tmp();
10000
10984
  return `${head}
10001
- ${emitMark(p, L.buf, L.raw, sinks)}
10002
- const v=${child}(input,pos,ctx)
10985
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
10986
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10003
10987
  ${emitRollback(p, L.buf, L.raw, sinks)}
10004
- if(v===FAIL){EC.e=pos;return null}
10988
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){EC.e=pos;return null}
10005
10989
  ctx._fe=pos
10006
10990
  ctx._fx=${xf}
10007
10991
  return FAIL
10008
10992
  }`;
10009
10993
  }
10010
10994
  case OP_PEEK: {
10995
+ const scalarChild = scalarTerminalPeekChild(code, ip);
10996
+ if (scalarChild >= 0) {
10997
+ const recognize = recognizerRef(code[scalarChild + 1]);
10998
+ const xf2 = fxRef(code[ip + 2]);
10999
+ return `${head}
11000
+ if(${recognize}(input,pos)<0){ctx._fe=pos;ctx._fx=${xf2};return FAIL}
11001
+ EC.e=pos
11002
+ return null
11003
+ }`;
11004
+ }
10011
11005
  const child = link(code[ip + 1]);
10012
11006
  const xf = fxRef(code[ip + 2]);
10013
11007
  const p = tmp();
10014
11008
  return `${head}
10015
- ${emitMark(p, L.buf, L.raw, sinks)}
10016
- const v=${child}(input,pos,ctx)
11009
+ ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
11010
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10017
11011
  ${emitRollback(p, L.buf, L.raw, sinks)}
10018
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11012
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10019
11013
  EC.e=pos
10020
11014
  return null
10021
11015
  }`;
@@ -10025,7 +11019,7 @@ return null
10025
11019
  const clean = !REC && failureRollbackClean(prog, ip);
10026
11020
  const p = tmp();
10027
11021
  return `${head}
10028
- ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
11022
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
10029
11023
  ctx._fc=false
10030
11024
  const v=${child}(input,pos,ctx)
10031
11025
  if(v===FAIL){
@@ -10086,7 +11080,7 @@ return v
10086
11080
  );
10087
11081
  } else {
10088
11082
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
10089
- parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
11083
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
10090
11084
  }
10091
11085
  names.push(vn);
10092
11086
  }
@@ -10106,7 +11100,7 @@ return v
10106
11100
  const asc = hoist("as", `DISP[${di}].ascii`);
10107
11101
  const hiArr = table.hi;
10108
11102
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
10109
- const directAscii = staticBuild && table.hi.length === 0;
11103
+ const directAscii = table.hi.length === 0;
10110
11104
  return `${head}
10111
11105
  const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10112
11106
  let arm=-1
@@ -10133,7 +11127,7 @@ return FAIL
10133
11127
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10134
11128
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10135
11129
  const maskable = n <= 32;
10136
- const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
11130
+ const directAsciiMask = maskable && gates.every(isAsciiOnlyClass);
10137
11131
  const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10138
11132
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10139
11133
  const pretests = Array.from({ length: n }, (_, i) => {
@@ -10175,7 +11169,7 @@ return FAIL
10175
11169
  if (choiceCannotCommit(prog, ip) && !startFailureExact) {
10176
11170
  const deepAt = Array.from({ length: n }, () => tmp());
10177
11171
  const deepFx = Array.from({ length: n }, () => tmp());
10178
- const remember = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
11172
+ const remember2 = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
10179
11173
  const lazyArms = (ascii) => arms.map((arm, i) => {
10180
11174
  const pretest = pretests[i];
10181
11175
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
@@ -10187,13 +11181,13 @@ return FAIL
10187
11181
  if(${decision}===0){
10188
11182
  ctx._fc=false
10189
11183
  {const at=_pfTokEnd
10190
- ${remember(i, "at", pretest.token.expected)}}
11184
+ ${remember2(i, "at", pretest.token.expected)}}
10191
11185
  }`;
10192
11186
  const sequenceMiss = pretest?.sequence === void 0 ? "" : `
10193
11187
  else if(${ascii ? `(bits&${1 << i})!==0&&` : ""}${decision}<0){
10194
11188
  ctx._fc=false
10195
11189
  {const at=_pfSeqEnd
10196
- ${remember(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
11190
+ ${remember2(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
10197
11191
  }`;
10198
11192
  return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10199
11193
  `}if(${gate}){
@@ -10201,7 +11195,7 @@ ctx._fc=false
10201
11195
  {const v=${arm}(input,pos,ctx)
10202
11196
  if(v!==FAIL)return v}
10203
11197
  {const at=ctx._fe??pos
10204
- ${remember(i, "at", "ctx._fx")}}
11198
+ ${remember2(i, "at", "ctx._fx")}}
10205
11199
  ${rollbackFor(i)}
10206
11200
  }${routeMiss}${sequenceMiss}`;
10207
11201
  }).join("\n");
@@ -10314,7 +11308,7 @@ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10314
11308
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10315
11309
  ${startFailureExact ? "" : "let prev=0"}
10316
11310
  ${maskArms}
10317
- ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${n},prev,acc)`}
11311
+ ${startFailureExact ? "" : `if(best===pos&&prev!==0)acc=${catchName}(${n},prev,acc)`}
10318
11312
  ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
10319
11313
  return FAIL
10320
11314
  }
@@ -10413,7 +11407,7 @@ return [key,v]
10413
11407
  const ci = classes.push([resolved]) - 1;
10414
11408
  classPlan.push([itemClassIndex]);
10415
11409
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10416
- itemAscii = staticBuild && isAsciiOnlyClass(resolved);
11410
+ itemAscii = isAsciiOnlyClass(resolved);
10417
11411
  }
10418
11412
  }
10419
11413
  const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
@@ -10569,6 +11563,26 @@ return nd
10569
11563
  const trailingTrivia = (flags & 128) !== 0;
10570
11564
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
10571
11565
  const leanFlags = flags & ~128;
11566
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
11567
+ return `${head}
11568
+ const v=${child}(input,pos,ctx)
11569
+ if(v!==undefined)return v
11570
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11571
+ }`;
11572
+ }
11573
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
11574
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t2.trivia);
11575
+ const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
11576
+ if(!(${[
11577
+ ...gated.leads.map((g) => `!(${gateMissTest(g)})`),
11578
+ ...gated.lits.map((i) => `gc===${k[i].codePointAt(0)}`),
11579
+ ...triviaLead.map((r) => r.lo === r.hi ? `gc===${r.lo}` : `(gc>=${r.lo}&&gc<=${r.hi})`)
11580
+ ].join("||") || "false"})){
11581
+ const gv=${link(gated.last)}(input,pos,ctx)
11582
+ if(gv!==undefined)return gv
11583
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11584
+ }
11585
+ ` : "";
10572
11586
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
10573
11587
  const fields = flags === 18;
10574
11588
  const collapseChildren = flags === 34;
@@ -10603,7 +11617,7 @@ sCh.push(nd)
10603
11617
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
10604
11618
  }`;
10605
11619
  return `${head}
10606
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11620
+ ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10607
11621
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
10608
11622
  const flat=[]
10609
11623
  ctx._cstBuf=undefined
@@ -10639,7 +11653,7 @@ return nd
10639
11653
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
10640
11654
  const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
10641
11655
  const ty = q(type);
10642
- const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
11656
+ const stArg = "ctx.state";
10643
11657
  const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
10644
11658
  let value;
10645
11659
  if (proj >= 0) {
@@ -10678,7 +11692,7 @@ const hostKids=kids
10678
11692
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
10679
11693
  const tlog=buf.tl??EMPTY_TLOG`;
10680
11694
  return `${head}
10681
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11695
+ ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10682
11696
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
10683
11697
  ${openCapture}
10684
11698
  ctx.captureTrivia=${captureWide}
@@ -10700,7 +11714,7 @@ ctx.captureTrivia=sCap
10700
11714
  if(v===FAIL)return FAIL
10701
11715
  const end=EC.e
10702
11716
  const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
10703
- const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
11717
+ const st=${readsState ? "ctx.state" : "undefined"}
10704
11718
  let nd
10705
11719
  ${unwrap ? "if(kids.length===1)nd=unwrapChild(kids[0])\nelse " : ""}${collapse ? "if(kids.length===1)nd=kids[0]\nelse " : ""}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
10706
11720
  else ` : ""}{${value}}
@@ -10713,21 +11727,57 @@ return nd
10713
11727
  throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
10714
11728
  }
10715
11729
  }
11730
+ const served = (ip) => select === void 0 || select.has(resolveAlias(ip));
10716
11731
  const ruleEntries = [];
10717
11732
  for (const [rname, entryIp] of Object.entries(prog.rules)) {
11733
+ if (!served(entryIp)) continue;
10718
11734
  const target = link(entryIp);
10719
11735
  const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
10720
11736
  bodies.push(`const ${rn}=${target}`);
10721
11737
  ruleEntries.push(`${q(rname)}:${rn}`);
10722
11738
  }
10723
11739
  const extra = [];
10724
- for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
11740
+ const exported = /* @__PURE__ */ new Set();
11741
+ for (const ip of extraIps) {
11742
+ if (!served(ip)) continue;
11743
+ exported.add(ip);
11744
+ extra.push(`${ip}:${link(ip)}`);
11745
+ }
11746
+ if (select !== void 0) {
11747
+ const kids = [];
11748
+ for (const ip of reachable) {
11749
+ if (select.has(resolveAlias(ip))) continue;
11750
+ kids.length = 0;
11751
+ childSlots(code, ip, kids);
11752
+ for (const kid of kids) {
11753
+ const target = resolveAlias(kid);
11754
+ if (!select.has(target) || exported.has(target)) continue;
11755
+ exported.add(target);
11756
+ extra.push(`${target}:${link(target)}`);
11757
+ }
11758
+ }
11759
+ }
11760
+ const hybrid = select === void 0 ? "" : `,
11761
+ ext:[${externals.join(",")}],
11762
+ bind:function(xs,ps){_xScan=xs
11763
+ ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
11764
+ scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
11765
+ const scannerFor = (ip) => {
11766
+ const ki = labels.at(ip).tri;
11767
+ if (ki === TRI_UNKNOWN) return "_pfScan";
11768
+ if (ki === TRI_NONE) return "null";
11769
+ return swapLegal && !triviaLabelled[ki] && t2.triviaScan[ki] != null ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
11770
+ };
11771
+ const externalDefs = select === void 0 ? "" : `let _xScan
11772
+ ${externals.map((ip) => `let _xp${ip}
11773
+ function _px${ip}(input,pos,ctx){const o=_xScan(${scannerFor(ip)});const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
11774
+ `;
10725
11775
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10726
11776
  ${prelude.join("\n")}
10727
11777
  ${skipDefs.join("\n")}
10728
11778
  ${choiceDefs.join("\n")}
10729
11779
  ${bodies.join("\n")}
10730
- function _begin(ctx){
11780
+ ${externalDefs}function _begin(ctx){
10731
11781
  const host=ctx.build
10732
11782
  if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
10733
11783
  _pfDepth++
@@ -10754,7 +11804,7 @@ pieces:{${ruleEntries.join(",")}},
10754
11804
  byIp:{${extra.join(",")}},
10755
11805
  end:function(){return EC.e},
10756
11806
  begin:_begin,
10757
- finish:_finish
11807
+ finish:_finish${hybrid}
10758
11808
  }`;
10759
11809
  return {
10760
11810
  source,
@@ -10762,6 +11812,7 @@ finish:_finish
10762
11812
  masks,
10763
11813
  classes,
10764
11814
  armExpected,
11815
+ siteBytes,
10765
11816
  plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
10766
11817
  };
10767
11818
  }
@@ -10982,187 +12033,57 @@ function literal(value, opts = {}) {
10982
12033
  })() : (input, pos, ctx) => {
10983
12034
  const end = pos + value.length;
10984
12035
  if (end <= input.length) {
10985
- const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
10986
- if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
10987
- ctx._sv = matchedValue;
10988
- return end;
10989
- }
10990
- }
10991
- ctx._fx = expected;
10992
- return ~pos;
10993
- };
10994
- if (caseInsensitive) {
10995
- const upper = value.toUpperCase();
10996
- const lower = value.toLowerCase();
10997
- const firstUpper = upper.codePointAt(0);
10998
- const firstLower = lower.codePointAt(0);
10999
- meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
11000
- { lo: firstLower, hi: firstLower },
11001
- { lo: firstUpper, hi: firstUpper }
11002
- ] } : firstSet2;
11003
- }
11004
- const expected = directTerminalFailureExpected({ tag: "literal", value, caseInsensitive });
11005
- const parse2 = !caseInsensitive && value.length === 1 ? (() => {
11006
- const code = value.charCodeAt(0);
11007
- return function parse3(input, pos, ctx) {
11008
- if (input.charCodeAt(pos) === code) {
11009
- const span = { start: pos, end: pos + 1 };
11010
- if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
11011
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11012
- return { ok: true, value, span };
11013
- }
11014
- return failAt(ctx, expected, pos);
11015
- };
11016
- })() : function parse3(input, pos, ctx) {
11017
- const end = pos + value.length;
11018
- if (end > input.length) {
11019
- return failAt(ctx, expected, pos);
11020
- }
11021
- const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
11022
- if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
11023
- const span = { start: pos, end };
11024
- if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
11025
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
11026
- return { ok: true, value: matchedValue, span };
11027
- }
11028
- return failAt(ctx, expected, pos);
11029
- };
11030
- return {
11031
- _tag: "literal",
11032
- _meta: meta,
11033
- _def: { tag: "literal", value, caseInsensitive },
11034
- _parseScalar: parseScalar,
11035
- parse: parse2
11036
- };
11037
- }
11038
-
11039
- // src/combinators/sequence.ts
11040
- function sequence(...parsers) {
11041
- let adjacency = null;
11042
- for (let i = 0; i < parsers.length; i++) {
11043
- const a = adjacencyOf(parsers[i]);
11044
- if (a === null) continue;
11045
- if (i === 0) {
11046
- throw new TypeError(
11047
- `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
11048
- );
11049
- }
11050
- ;
11051
- (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
11052
- }
11053
- const hasAdjacency = adjacency !== null;
11054
- let leading = null;
11055
- for (let i = 1; i < parsers.length; i++) {
11056
- if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
11057
- }
11058
- const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
11059
- const meta = {
11060
- // Union through the nullable prefix — a leading optional()/many() lets a later
11061
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
11062
- firstSet: sequenceFirstSet(parsers),
11063
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
11064
- isTrivia: false
11065
- };
11066
- const def = { tag: "sequence", parsers };
11067
- const scalarParsers = parsers.map(scalarOf);
11068
- const parseScalar = (input, pos, ctx) => {
11069
- let cur = pos;
11070
- if (strictArity !== 0) {
11071
- cur = scalarParsers[0](input, cur, ctx);
11072
- if (cur < 0) return cur;
11073
- const first = ctx._sv;
11074
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11075
- cur = scalarParsers[1](input, cur, ctx);
11076
- if (cur < 0) return cur;
11077
- const second = ctx._sv;
11078
- if (strictArity === 2) {
11079
- ctx._sv = def.valueUnused ? void 0 : [first, second];
11080
- return cur;
12036
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
12037
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
12038
+ ctx._sv = matchedValue;
12039
+ return end;
11081
12040
  }
11082
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11083
- cur = scalarParsers[2](input, cur, ctx);
11084
- if (cur < 0) return cur;
11085
- ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
11086
- return cur;
11087
12041
  }
11088
- const values = def.valueUnused ? void 0 : [];
11089
- for (let i = 0; i < scalarParsers.length; i++) {
11090
- let termPos = cur;
11091
- if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
11092
- const end = scalarParsers[i](input, termPos, ctx);
11093
- if (end < 0) return end;
11094
- if (values !== void 0) values.push(ctx._sv);
11095
- if (end > termPos || termPos === cur) cur = end;
12042
+ ctx._fx = expected;
12043
+ return ~pos;
12044
+ };
12045
+ if (caseInsensitive) {
12046
+ const upper = value.toUpperCase();
12047
+ const lower = value.toLowerCase();
12048
+ const firstUpper = upper.codePointAt(0);
12049
+ const firstLower = lower.codePointAt(0);
12050
+ meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
12051
+ { lo: firstLower, hi: firstLower },
12052
+ { lo: firstUpper, hi: firstUpper }
12053
+ ] } : firstSet2;
12054
+ }
12055
+ const expected = directTerminalFailureExpected({ tag: "literal", value, caseInsensitive });
12056
+ const parse2 = !caseInsensitive && value.length === 1 ? (() => {
12057
+ const code = value.charCodeAt(0);
12058
+ return function parse3(input, pos, ctx) {
12059
+ if (input.charCodeAt(pos) === code) {
12060
+ const span = { start: pos, end: pos + 1 };
12061
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
12062
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
12063
+ return { ok: true, value, span };
12064
+ }
12065
+ return failAt(ctx, expected, pos);
12066
+ };
12067
+ })() : function parse3(input, pos, ctx) {
12068
+ const end = pos + value.length;
12069
+ if (end > input.length) {
12070
+ return failAt(ctx, expected, pos);
11096
12071
  }
11097
- ctx._sv = values;
11098
- return cur;
12072
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
12073
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
12074
+ const span = { start: pos, end };
12075
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
12076
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
12077
+ return { ok: true, value: matchedValue, span };
12078
+ }
12079
+ return failAt(ctx, expected, pos);
11099
12080
  };
11100
- let followSentinels;
11101
12081
  return {
11102
- _tag: "sequence",
12082
+ _tag: "literal",
11103
12083
  _meta: meta,
11104
- _def: def,
11105
- _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
11106
- parse(input, pos, ctx) {
11107
- const tolerant = ctx._tolerant === true;
11108
- if (tolerant) {
11109
- followSentinels ??= parsers.map((_, i) => firstSetSentinel(
11110
- parsers.slice(i + 1).reduce(
11111
- (set, parser2) => union(set, firstSetOf(parser2)),
11112
- { kind: "empty" }
11113
- )
11114
- ));
11115
- }
11116
- const inheritedSync = ctx._sync;
11117
- const deferredTrivia = needsDeferredTriviaCommit(ctx);
11118
- const values = def.valueUnused ? void 0 : [];
11119
- let cur = pos;
11120
- try {
11121
- for (let i = 0; i < parsers.length; i++) {
11122
- if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
11123
- const assertion = adjacency?.[i];
11124
- if (assertion) {
11125
- if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
11126
- if (values !== void 0) values.push(null);
11127
- continue;
11128
- }
11129
- let termPos = cur;
11130
- const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11131
- const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11132
- const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11133
- if (ctx.trivia && i > 0) {
11134
- termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
11135
- }
11136
- const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11137
- const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11138
- const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11139
- if (leading?.[i] === true) LEAD.at = cur;
11140
- const result = parsers[i].parse(input, termPos, ctx);
11141
- if (!result.ok) return result;
11142
- if (values !== void 0) values.push(result.value);
11143
- if (result.span.end > termPos || termPos === cur) cur = result.span.end;
11144
- else if (deferredTrivia) {
11145
- rollbackScannedTriviaAt(
11146
- ctx,
11147
- markTlog,
11148
- scanTlog,
11149
- markLog,
11150
- scanLog,
11151
- markRootLog,
11152
- scanRootLog
11153
- );
11154
- }
11155
- }
11156
- } finally {
11157
- if (tolerant) ctx._sync = inheritedSync;
11158
- }
11159
- return {
11160
- ok: true,
11161
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
11162
- value: values ?? void 0,
11163
- span: { start: pos, end: cur }
11164
- };
11165
- }
12084
+ _def: { tag: "literal", value, caseInsensitive },
12085
+ _parseScalar: parseScalar,
12086
+ parse: parse2
11166
12087
  };
11167
12088
  }
11168
12089
 
@@ -11209,146 +12130,28 @@ function ref() {
11209
12130
  },
11210
12131
  parse(input, pos, ctx) {
11211
12132
  const parser2 = resolved;
11212
- if (!parser2) throw new Error("ref<T>() used before .define() was called");
11213
- const gt = meta.grammarTrivia;
11214
- if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
11215
- return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
11216
- }
11217
- return parser2.parse(input, pos, ctx);
11218
- },
11219
- define(p) {
11220
- if (resolved) throw new Error("ref<T>() already defined");
11221
- resolved = p;
11222
- resolvedScalar = scalarOf(p);
11223
- ownBoundary = hasOwnTriviaBoundary(p);
11224
- meta.firstSet = p._meta.firstSet;
11225
- meta.canMatchNewline = p._meta.canMatchNewline;
11226
- meta.isTrivia = p._meta.isTrivia;
11227
- if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
11228
- else delete meta.triviaKindLabels;
11229
- if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
11230
- else delete meta.disjoint;
11231
- }
11232
- };
11233
- return slot;
11234
- }
11235
-
11236
- // src/combinators/token.ts
11237
- function semanticLeafValue(_ctx, _input, _start, _end, value) {
11238
- return value;
11239
- }
11240
- function sourceLeafValue(ctx, input, start, end, value) {
11241
- return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
11242
- }
11243
- function token(root) {
11244
- const meta = {
11245
- firstSet: root._meta.firstSet,
11246
- canMatchNewline: root._meta.canMatchNewline,
11247
- isTrivia: false
11248
- };
11249
- return {
11250
- _tag: "token",
11251
- _meta: meta,
11252
- _def: { tag: "token", parser: root },
11253
- parse(input, pos, ctx) {
11254
- const savedTrivia = ctx.trivia;
11255
- const savedKinds = ctx.triviaKindLabels;
11256
- const savedBuf = ctx._cstBuf;
11257
- const savedChildren = ctx._cstChildren;
11258
- const savedLeaves = ctx._cstLeaves;
11259
- const savedRaw = ctx._cstRawChildren;
11260
- const savedTriviaLog = ctx._cstTriviaLog;
11261
- const savedOuterTriviaLog = ctx._triviaLog;
11262
- const savedRootTriviaLog = ctx._rootTriviaLog;
11263
- const wasCapturing = cstCaptureActive(ctx);
11264
- ctx.trivia = void 0;
11265
- ctx.triviaKindLabels = void 0;
11266
- ctx._cstBuf = void 0;
11267
- ctx._cstChildren = void 0;
11268
- ctx._cstLeaves = void 0;
11269
- ctx._cstRawChildren = void 0;
11270
- ctx._cstTriviaLog = void 0;
11271
- ctx._triviaLog = void 0;
11272
- ctx._rootTriviaLog = void 0;
11273
- let result;
11274
- try {
11275
- result = root.parse(input, pos, ctx);
11276
- } finally {
11277
- ctx.trivia = savedTrivia;
11278
- ctx.triviaKindLabels = savedKinds;
11279
- ctx._cstBuf = savedBuf;
11280
- ctx._cstChildren = savedChildren;
11281
- ctx._cstLeaves = savedLeaves;
11282
- ctx._cstRawChildren = savedRaw;
11283
- ctx._cstTriviaLog = savedTriviaLog;
11284
- ctx._triviaLog = savedOuterTriviaLog;
11285
- ctx._rootTriviaLog = savedRootTriviaLog;
11286
- }
11287
- if (!result.ok) return result;
11288
- const span = result.span;
11289
- const value = input.slice(pos, span.end);
11290
- if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11291
- return { ok: true, value, span };
11292
- }
11293
- };
11294
- }
11295
- function makeLeaf(root, fn, sourceCstValue) {
11296
- const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
11297
- const meta = {
11298
- firstSet: root._meta.firstSet,
11299
- canMatchNewline: root._meta.canMatchNewline,
11300
- isTrivia: false
11301
- };
11302
- return {
11303
- _tag: "leaf",
11304
- _meta: meta,
11305
- _def: {
11306
- tag: "leaf",
11307
- parser: root,
11308
- fn,
11309
- ...sourceCstValue ? { cstValue: "source" } : {}
11310
- },
11311
- parse(input, pos, ctx) {
11312
- const savedBuf = ctx._cstBuf;
11313
- const savedChildren = ctx._cstChildren;
11314
- const savedLeaves = ctx._cstLeaves;
11315
- const savedRaw = ctx._cstRawChildren;
11316
- const savedTriviaLog = ctx._cstTriviaLog;
11317
- const savedOuterTriviaLog = ctx._triviaLog;
11318
- const wasCapturing = cstCaptureActive(ctx);
11319
- ctx._cstBuf = void 0;
11320
- ctx._cstChildren = void 0;
11321
- ctx._cstLeaves = void 0;
11322
- ctx._cstRawChildren = void 0;
11323
- ctx._cstTriviaLog = void 0;
11324
- ctx._triviaLog = void 0;
11325
- let result;
11326
- try {
11327
- result = root.parse(input, pos, ctx);
11328
- } finally {
11329
- ctx._cstBuf = savedBuf;
11330
- ctx._cstChildren = savedChildren;
11331
- ctx._cstLeaves = savedLeaves;
11332
- ctx._cstRawChildren = savedRaw;
11333
- ctx._cstTriviaLog = savedTriviaLog;
11334
- ctx._triviaLog = savedOuterTriviaLog;
11335
- }
11336
- if (!result.ok) return result;
11337
- const value = fn(result.value, result.span);
11338
- if (wasCapturing) pushCstLeaf(ctx, {
11339
- _tag: "leaf",
11340
- value: cstValue(ctx, input, pos, result.span.end, value),
11341
- span: result.span
11342
- });
11343
- return { ok: true, value, span: result.span };
12133
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
12134
+ const gt = meta.grammarTrivia;
12135
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
12136
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
12137
+ }
12138
+ return parser2.parse(input, pos, ctx);
12139
+ },
12140
+ define(p) {
12141
+ if (resolved) throw new Error("ref<T>() already defined");
12142
+ resolved = p;
12143
+ resolvedScalar = scalarOf(p);
12144
+ ownBoundary = hasOwnTriviaBoundary(p);
12145
+ meta.firstSet = p._meta.firstSet;
12146
+ meta.canMatchNewline = p._meta.canMatchNewline;
12147
+ meta.isTrivia = p._meta.isTrivia;
12148
+ if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
12149
+ else delete meta.triviaKindLabels;
12150
+ if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
12151
+ else delete meta.disjoint;
11344
12152
  }
11345
12153
  };
11346
- }
11347
- function leaf(root, fn) {
11348
- return makeLeaf(root, fn, false);
11349
- }
11350
- function sourceLeaf(root, fn) {
11351
- return makeLeaf(root, fn, true);
12154
+ return slot;
11352
12155
  }
11353
12156
 
11354
12157
  // src/combinators/scanTo.ts
@@ -11595,37 +12398,184 @@ function escapeClassChar(ch2) {
11595
12398
  return ch2.replace(/[\\\]^-]/g, "\\$&");
11596
12399
  }
11597
12400
 
11598
- // src/table/run-support.ts
11599
- function lineCol(ctx, offset) {
11600
- const starts = ctx._lineStarts ?? [0];
11601
- let lo = 0, hi = starts.length - 1;
11602
- while (lo < hi) {
11603
- const mid = lo + hi + 1 >> 1;
11604
- if (starts[mid] <= offset) lo = mid;
11605
- else hi = mid - 1;
12401
+ // src/table/trivia-gap.ts
12402
+ function skipDeferredTrivia(input, cur, ctx) {
12403
+ const triviaP = ctx.trivia;
12404
+ const plain2 = ctx.trackLines !== true && ctx.captureTrivia !== true;
12405
+ const gap = ctx._gap;
12406
+ if (plain2 && gap !== void 0 && cur === gap.at && input === gap.input && triviaP === gap.of && ctx._rootTriviaCapture === gap.root && ctx.state === gap.state && ctx._rootTriviaKindIndex === gap.rootKinds && ctx._triviaLog === gap.log) return gap.end;
12407
+ const end = clearRunEnd(input, cur, ctx, triviaP, plain2);
12408
+ if (end >= 0) {
12409
+ remember(cur, end, ctx, input, triviaP);
12410
+ return end;
11606
12411
  }
11607
- return [lo + 1, offset - starts[lo] + 1];
12412
+ const scan = scanTriviaCompact(input, cur, ctx);
12413
+ if (typeof scan !== "number") return commitTriviaScan(scan);
12414
+ if (plain2) remember(cur, scan, ctx, input, triviaP);
12415
+ return scan;
11608
12416
  }
11609
- function spanLines(ctx, start, end) {
11610
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
11611
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
12417
+ function clearRunEnd(input, cur, ctx, triviaP, plain2) {
12418
+ const rootKinds = ctx._rootTriviaKindIndex;
12419
+ const spec = triviaP?._meta.labeledTriviaSpec;
12420
+ if (!plain2 || triviaP === void 0 || spec == null || rootKinds === void 0 || ctx._triviaLog !== void 0) return -1;
12421
+ if (spec.rootKinds !== rootKinds) prime(spec, triviaP, rootKinds);
12422
+ const fast = spec.rootScan;
12423
+ if (fast === null) return -1;
12424
+ const end = fast(input, cur);
12425
+ return ctx._rootTriviaCapture === false || clearOf(spec.rootLeaders, input, cur, end) ? end : -1;
12426
+ }
12427
+ function remember(cur, end, ctx, input, triviaP) {
12428
+ const gap = ctx._gap;
12429
+ if (gap === void 0) {
12430
+ ctx._gap = { at: cur, end, input, of: triviaP, root: ctx._rootTriviaCapture, rootKinds: ctx._rootTriviaKindIndex, log: ctx._triviaLog, state: ctx.state };
12431
+ return;
12432
+ }
12433
+ gap.at = cur;
12434
+ gap.end = end;
12435
+ gap.input = input;
12436
+ gap.of = triviaP;
12437
+ gap.root = ctx._rootTriviaCapture;
12438
+ gap.rootKinds = ctx._rootTriviaKindIndex;
12439
+ gap.log = ctx._triviaLog;
12440
+ gap.state = ctx.state;
11612
12441
  }
11613
- function rawEntry(v, input, s, e) {
11614
- if (typeof v === "object" && v !== null) {
11615
- const tg = v._tag;
11616
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
12442
+ function prime(spec, triviaP, rootKinds) {
12443
+ const ranges = [];
12444
+ let bounded = true;
12445
+ for (const arm of spec.arms) {
12446
+ if (rootKinds[arm.label] === void 0) continue;
12447
+ const fs = arm.parser._meta.firstSet;
12448
+ if (fs.kind === "any") bounded = false;
12449
+ else if (fs.kind === "ranges") ranges.push(...fs.ranges);
12450
+ }
12451
+ const classified = triviaP._meta.triviaScanner;
12452
+ spec.rootKinds = rootKinds;
12453
+ spec.rootLeaders = ranges;
12454
+ spec.rootScan = !bounded ? null : classified === void 0 ? fastTriviaScanner(triviaP) : classified;
12455
+ }
12456
+ function clearOf(ranges, input, from, to) {
12457
+ for (let i = from; i < to; i++) {
12458
+ const c = input.charCodeAt(i);
12459
+ if (c >= 55296 && c <= 57343) return false;
12460
+ for (const r of ranges) if (c >= r.lo && c <= r.hi) return false;
11617
12461
  }
11618
- return {
11619
- _tag: "leaf",
11620
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
11621
- span: { start: s, end: e }
11622
- };
12462
+ return true;
11623
12463
  }
11624
- function lead(input, pos) {
11625
- if (pos >= input.length) return -1;
11626
- const c = input.charCodeAt(pos);
11627
- if (c < 55296 || c > 56319) return c;
11628
- return input.codePointAt(pos) ?? c;
12464
+
12465
+ // src/table/fail-clean.ts
12466
+ function passChild(code, ip) {
12467
+ switch (code[ip]) {
12468
+ case OP_RULE:
12469
+ case OP_LABEL:
12470
+ case OP_COV:
12471
+ case OP_TOKEN:
12472
+ return code[ip + 1];
12473
+ case OP_GATE:
12474
+ case OP_NODE:
12475
+ case OP_NODE_TRACK:
12476
+ case OP_XFORM:
12477
+ case OP_FIELD:
12478
+ case OP_SCOPE:
12479
+ case OP_SCOPE_CAP:
12480
+ case OP_SCOPE_PLAIN:
12481
+ case OP_WITHCTX:
12482
+ case OP_LEAF:
12483
+ case OP_SOURCE_LEAF:
12484
+ return code[ip + 2];
12485
+ default:
12486
+ return -1;
12487
+ }
12488
+ }
12489
+ function seqCount(code, ip) {
12490
+ const op = code[ip];
12491
+ return op === OP_SEQ || op === OP_SEQV ? ip + 1 : op === OP_SEQX ? ip + 2 : -1;
12492
+ }
12493
+ function failCleanAnalysis(code) {
12494
+ const cleanAt = new Uint8Array(code.length);
12495
+ const neverAt = new Uint8Array(code.length);
12496
+ const neverFails = (ip) => {
12497
+ const hit = neverAt[ip];
12498
+ if (hit !== 0) return hit === 1;
12499
+ neverAt[ip] = 3;
12500
+ let out = false;
12501
+ const op = code[ip];
12502
+ if (op === OP_OPT || op === OP_EMPTY || op === OP_EXPECT) out = true;
12503
+ else if (op === OP_REP || op === OP_REPV) out = code[ip + 2] === 0;
12504
+ else {
12505
+ const at = seqCount(code, ip);
12506
+ if (at >= 0) {
12507
+ out = true;
12508
+ for (let i = 1, n = code[at]; out && i <= n; i++) out = neverFails(code[at + i]);
12509
+ } else if (op !== OP_GATE) {
12510
+ const c = passChild(code, ip);
12511
+ out = c >= 0 && neverFails(c);
12512
+ }
12513
+ }
12514
+ neverAt[ip] = out ? 1 : 2;
12515
+ return out;
12516
+ };
12517
+ const clean = (ip) => {
12518
+ const hit = cleanAt[ip];
12519
+ if (hit !== 0) return hit === 1;
12520
+ cleanAt[ip] = 3;
12521
+ let out = false;
12522
+ switch (code[ip]) {
12523
+ // A terminal pushes its leaf only on a match; NOT/PEEK/ATTEMPT restore
12524
+ // their own mark; OPT, EMPTY and EXPECT do not fail uncommitted.
12525
+ case OP_LIT:
12526
+ case OP_RX:
12527
+ case OP_LIT_TRACK:
12528
+ case OP_RX_TRACK:
12529
+ case OP_LIT_CI:
12530
+ case OP_LIT_CI_TRACK:
12531
+ case OP_GUARD:
12532
+ case OP_NOT:
12533
+ case OP_PEEK:
12534
+ case OP_ATTEMPT:
12535
+ case OP_EMPTY:
12536
+ case OP_OPT:
12537
+ case OP_EXPECT:
12538
+ out = true;
12539
+ break;
12540
+ // Min 0 does not fail uncommitted; min 1 fails only with no item kept, and
12541
+ // restores the failed item itself.
12542
+ case OP_REP:
12543
+ case OP_REPV:
12544
+ out = code[ip + 2] <= 1;
12545
+ break;
12546
+ // Only the first term may fail: a later one fails after the terms before it
12547
+ // wrote, and after the trivia scanned in front of it.
12548
+ case OP_SEQ:
12549
+ case OP_SEQV:
12550
+ case OP_SEQX: {
12551
+ const at = seqCount(code, ip);
12552
+ const n = code[at];
12553
+ out = n > 0 && clean(code[at + 1]);
12554
+ for (let i = 2; out && i <= n; i++) out = neverFails(code[at + i]);
12555
+ break;
12556
+ }
12557
+ case OP_CHOICE: {
12558
+ out = true;
12559
+ for (let i = 0, n = code[ip + 2]; out && i < n; i++) out = clean(code[ip + 4 + i]);
12560
+ break;
12561
+ }
12562
+ case OP_ROUTED:
12563
+ out = code[ip + 1] < 0 || clean(code[ip + 1]);
12564
+ break;
12565
+ // An arm's failure and the fallback's are committed; only the selector's is
12566
+ // not, and without a fallback an unknown key fails after the selector wrote.
12567
+ case OP_DISPATCH:
12568
+ out = code[ip + 3] >= 0 && clean(code[ip + 1]);
12569
+ break;
12570
+ default: {
12571
+ const c = passChild(code, ip);
12572
+ out = c >= 0 && clean(c);
12573
+ }
12574
+ }
12575
+ cleanAt[ip] = out ? 1 : 2;
12576
+ return out;
12577
+ };
12578
+ return clean;
11629
12579
  }
11630
12580
 
11631
12581
  // src/cst/host-mode.ts
@@ -11777,6 +12727,7 @@ function assemble(t2, prog, cfg) {
11777
12727
  const swapLegal = !cfg.trackLines;
11778
12728
  const hostCst = cfg.hostCst;
11779
12729
  const REC = prog.rec === 1 && cfg.tolerant;
12730
+ const PROBE = cfg.probe;
11780
12731
  const sentinels = /* @__PURE__ */ new Map();
11781
12732
  function sentinelFor(cls) {
11782
12733
  if (cls < 0) return void 0;
@@ -11791,6 +12742,9 @@ function assemble(t2, prog, cfg) {
11791
12742
  const EC = newEndCell();
11792
12743
  const scalarRecognizers = [];
11793
12744
  const rawScalarSpecs = /* @__PURE__ */ new Set();
12745
+ function lookaheadClass(child) {
12746
+ return code[child] === OP_GATE && !cfg.tolerant && !cfg.probe ? cc[code[child + 1]] : null;
12747
+ }
11794
12748
  function scalarFor(child) {
11795
12749
  const spec = code[child + 1];
11796
12750
  let recognize = scalarRecognizers[spec];
@@ -11800,17 +12754,27 @@ function assemble(t2, prog, cfg) {
11800
12754
  }
11801
12755
  return recognize;
11802
12756
  }
11803
- const labelExtraIps = [];
11804
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) labelExtraIps.push(r[0]);
11805
- for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0]);
12757
+ const labelExtraIps = assemblyExtraIps(prog);
11806
12758
  const closureLabels = computeSiteLabels(
11807
12759
  code,
11808
12760
  [...Object.values(prog.rules), ...labelExtraIps],
11809
12761
  hostCst
11810
12762
  );
11811
12763
  let SCAN = null;
12764
+ let HYBRID;
12765
+ function hybridPiece(piece) {
12766
+ const setScan = HYBRID.scan;
12767
+ return (input, pos, ctx) => {
12768
+ const saved = setScan(SCAN);
12769
+ const value = piece(input, pos, ctx);
12770
+ setScan(saved);
12771
+ return value;
12772
+ };
12773
+ }
11812
12774
  const memo = /* @__PURE__ */ new Map();
11813
12775
  const reached = /* @__PURE__ */ new Set();
12776
+ const NULLABLE = /* @__PURE__ */ new Map();
12777
+ const CLEAN = REC ? () => false : failCleanAnalysis(code);
11814
12778
  function pushLeaf(ctx, value, s, e) {
11815
12779
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
11816
12780
  pushCstLeaf(ctx, lf);
@@ -12009,6 +12973,22 @@ function assemble(t2, prog, cfg) {
12009
12973
  return node2;
12010
12974
  };
12011
12975
  }
12976
+ function passCollapseNode(child, build, readsRaw) {
12977
+ return (input, pos, ctx) => {
12978
+ const v = child(input, pos, ctx);
12979
+ if (v !== void 0) return v;
12980
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
12981
+ };
12982
+ }
12983
+ function gatedPassCollapseNode(blockers, last, classic, build, readsRaw) {
12984
+ return (input, pos, ctx) => {
12985
+ const c = lead(input, pos);
12986
+ for (let i = 0; i < blockers.length; i++) if (classHas2(blockers[i], c)) return classic(input, pos, ctx);
12987
+ const v = last(input, pos, ctx);
12988
+ if (v !== void 0) return v;
12989
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
12990
+ };
12991
+ }
12012
12992
  function plainProjectNode(child, projection, type) {
12013
12993
  return (input, pos, ctx) => {
12014
12994
  const sCh = ctx._cstChildren;
@@ -12100,9 +13080,7 @@ function assemble(t2, prog, cfg) {
12100
13080
  return s(input, cur);
12101
13081
  }
12102
13082
  if (s !== null) return skipTriviaScanned(s, input, cur, ctx);
12103
- if (needsDeferredTriviaCommit(ctx)) {
12104
- return commitTriviaScan(scanTriviaCompact(input, cur, ctx));
12105
- }
13083
+ if (needsDeferredTriviaCommit(ctx)) return skipDeferredTrivia(input, cur, ctx);
12106
13084
  return advanceTrivia(input, cur, ctx);
12107
13085
  }
12108
13086
  let TERMV;
@@ -12272,7 +13250,7 @@ function assemble(t2, prog, cfg) {
12272
13250
  if (next !== void 0) {
12273
13251
  return next(input, pos, ctx, bits, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12274
13252
  }
12275
- if (best === pos) acc = through(total, prev, acc);
13253
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12276
13254
  ctx._fe = pos;
12277
13255
  ctx._fx = acc ?? choiceFx;
12278
13256
  return FAIL;
@@ -12355,7 +13333,7 @@ function assemble(t2, prog, cfg) {
12355
13333
  if (next !== void 0) {
12356
13334
  return next(input, pos, ctx, c, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12357
13335
  }
12358
- if (best === pos) acc = through(total, prev, acc);
13336
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12359
13337
  ctx._fe = pos;
12360
13338
  ctx._fx = acc ?? choiceFx;
12361
13339
  return FAIL;
@@ -12381,21 +13359,27 @@ function assemble(t2, prog, cfg) {
12381
13359
  }
12382
13360
  function dispatchBranch(child, usesRouted) {
12383
13361
  if (!usesRouted) {
12384
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
12385
- const mark = saveTriviaMark(ctx);
13362
+ return (input, _pos, selEnd, key, ctx) => {
13363
+ const need = markCst(ctx);
13364
+ const mRaw = MRAW;
13365
+ const mTl = MTL;
13366
+ const mLv = MLV;
13367
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13368
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13369
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13370
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
12386
13371
  const v = child(input, selEnd, ctx);
12387
13372
  if (v === FAIL) {
12388
- rollbackTrivia(ctx, mark);
13373
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12389
13374
  ctx._fc = true;
12390
13375
  return FAIL;
12391
13376
  }
12392
13377
  return [key, v];
12393
13378
  };
12394
13379
  }
12395
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13380
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
12396
13381
  const savedRouted = ctx._routed;
12397
- rollbackTrivia(ctx, selectorMark);
12398
- const mark = saveTriviaMark(ctx);
13382
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12399
13383
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
12400
13384
  let v;
12401
13385
  try {
@@ -12404,7 +13388,7 @@ function assemble(t2, prog, cfg) {
12404
13388
  ctx._routed = savedRouted;
12405
13389
  }
12406
13390
  if (v === FAIL) {
12407
- rollbackTrivia(ctx, mark);
13391
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12408
13392
  ctx._fc = true;
12409
13393
  return FAIL;
12410
13394
  }
@@ -12412,12 +13396,12 @@ function assemble(t2, prog, cfg) {
12412
13396
  };
12413
13397
  }
12414
13398
  function dispatchArmBlock(start, a0, a1, a2, a3, next) {
12415
- return (arm, input, pos, selEnd, key, selectorMark, ctx) => {
12416
- if (arm === start) return a0(input, pos, selEnd, key, selectorMark, ctx);
12417
- if (arm === start + 1) return a1(input, pos, selEnd, key, selectorMark, ctx);
12418
- if (arm === start + 2) return a2(input, pos, selEnd, key, selectorMark, ctx);
12419
- if (arm === start + 3) return a3(input, pos, selEnd, key, selectorMark, ctx);
12420
- return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, selectorMark, ctx);
13399
+ return (arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
13400
+ if (arm === start) return a0(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13401
+ if (arm === start + 1) return a1(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13402
+ if (arm === start + 2) return a2(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13403
+ if (arm === start + 3) return a3(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13404
+ return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12421
13405
  };
12422
13406
  }
12423
13407
  function trackLinesInto(ctx, input, end) {
@@ -12434,20 +13418,68 @@ function assemble(t2, prog, cfg) {
12434
13418
  if (done !== void 0) return done;
12435
13419
  const flight = inFlight.get(ip);
12436
13420
  if (flight !== void 0) return flight.fwd;
13421
+ const selected = HYBRID?.byIp[ip];
13422
+ if (selected !== void 0) {
13423
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
13424
+ memo.set(ip, piece2);
13425
+ reached.add(ip);
13426
+ return piece2;
13427
+ }
12437
13428
  let target;
12438
13429
  const fwd = (input, pos, ctx) => target(input, pos, ctx);
12439
13430
  const holder = { fwd, set: (p) => {
12440
13431
  target = p;
12441
13432
  } };
12442
13433
  inFlight.set(ip, holder);
12443
- const op = code[ip];
12444
- const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : lower(ip);
13434
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
12445
13435
  inFlight.delete(ip);
12446
13436
  holder.set(piece);
12447
13437
  memo.set(ip, piece);
12448
13438
  reached.add(ip);
12449
13439
  return piece;
12450
13440
  }
13441
+ let FIRST_DECIDED;
13442
+ let NODE_BODY;
13443
+ const DECIDED = (_input, pos) => {
13444
+ EC.e = pos;
13445
+ return null;
13446
+ };
13447
+ function lookaheadLedNode(ip) {
13448
+ const op = code[ip];
13449
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
13450
+ if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
13451
+ const body = code[ip + 2];
13452
+ const bop = code[body];
13453
+ if (bop !== OP_SEQ && bop !== OP_SEQV && bop !== OP_SEQX) return void 0;
13454
+ const base = bop === OP_SEQX ? body + 3 : body + 2;
13455
+ if (code[bop === OP_SEQX ? body + 2 : body + 1] < 2) return void 0;
13456
+ const first = code[base];
13457
+ const negative = code[first] === OP_NOT;
13458
+ const terminal = negative ? scalarTerminalNotChild(code, first) : code[first] === OP_PEEK ? scalarTerminalPeekChild(code, first) : -1;
13459
+ if (terminal < 0) return void 0;
13460
+ const recognize = scalarFor(terminal);
13461
+ const xf = fx[code[first + 2]];
13462
+ FIRST_DECIDED = DECIDED;
13463
+ NODE_BODY = lower(body);
13464
+ const node2 = lower(ip);
13465
+ NODE_BODY = void 0;
13466
+ return negative ? (input, pos, ctx) => {
13467
+ if (recognize(input, pos) >= 0) {
13468
+ ctx._fe = pos;
13469
+ ctx._fx = xf;
13470
+ EC.e = pos;
13471
+ return FAIL;
13472
+ }
13473
+ return node2(input, pos, ctx);
13474
+ } : (input, pos, ctx) => {
13475
+ if (recognize(input, pos) < 0) {
13476
+ ctx._fe = pos;
13477
+ ctx._fx = xf;
13478
+ return FAIL;
13479
+ }
13480
+ return node2(input, pos, ctx);
13481
+ };
13482
+ }
12451
13483
  function lower(ip) {
12452
13484
  const op = code[ip];
12453
13485
  switch (op) {
@@ -12978,7 +14010,12 @@ function assemble(t2, prog, cfg) {
12978
14010
  }
12979
14011
  const child = link(code[ip + 1]);
12980
14012
  const xf = fx[code[ip + 2]];
14013
+ const gate = lookaheadClass(code[ip + 1]);
12981
14014
  return (input, pos, ctx) => {
14015
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14016
+ EC.e = pos;
14017
+ return null;
14018
+ }
12982
14019
  const need = markCst(ctx);
12983
14020
  const mRaw = MRAW;
12984
14021
  const mTl = MTL;
@@ -12987,8 +14024,10 @@ function assemble(t2, prog, cfg) {
12987
14024
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
12988
14025
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
12989
14026
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14027
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
12990
14028
  const v = child(input, pos, ctx);
12991
14029
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14030
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
12992
14031
  if (v === FAIL) {
12993
14032
  EC.e = pos;
12994
14033
  return null;
@@ -12999,9 +14038,29 @@ function assemble(t2, prog, cfg) {
12999
14038
  };
13000
14039
  }
13001
14040
  case OP_PEEK: {
14041
+ const scalarChild = scalarTerminalPeekChild(code, ip);
14042
+ if (scalarChild >= 0) {
14043
+ const recognize = scalarFor(scalarChild);
14044
+ const xf2 = fx[code[ip + 2]];
14045
+ return (input, pos, ctx) => {
14046
+ if (recognize(input, pos) < 0) {
14047
+ ctx._fe = pos;
14048
+ ctx._fx = xf2;
14049
+ return FAIL;
14050
+ }
14051
+ EC.e = pos;
14052
+ return null;
14053
+ };
14054
+ }
13002
14055
  const child = link(code[ip + 1]);
13003
14056
  const xf = fx[code[ip + 2]];
14057
+ const gate = lookaheadClass(code[ip + 1]);
13004
14058
  return (input, pos, ctx) => {
14059
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14060
+ ctx._fe = pos;
14061
+ ctx._fx = xf;
14062
+ return FAIL;
14063
+ }
13005
14064
  const need = markCst(ctx);
13006
14065
  const mRaw = MRAW;
13007
14066
  const mTl = MTL;
@@ -13010,8 +14069,10 @@ function assemble(t2, prog, cfg) {
13010
14069
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13011
14070
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13012
14071
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14072
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13013
14073
  const v = child(input, pos, ctx);
13014
14074
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14075
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13015
14076
  if (v === FAIL) {
13016
14077
  ctx._fe = pos;
13017
14078
  ctx._fx = xf;
@@ -13023,8 +14084,14 @@ function assemble(t2, prog, cfg) {
13023
14084
  }
13024
14085
  case OP_OPT: {
13025
14086
  const child = link(code[ip + 1]);
14087
+ const gate = lookaheadClass(code[ip + 1]);
14088
+ const childClean = CLEAN(code[ip + 1]);
13026
14089
  return (input, pos, ctx) => {
13027
- const need = markCst(ctx);
14090
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14091
+ EC.e = pos;
14092
+ return null;
14093
+ }
14094
+ const need = !childClean && markCst(ctx);
13028
14095
  const mRaw = MRAW;
13029
14096
  const mTl = MTL;
13030
14097
  const mLv = MLV;
@@ -13222,6 +14289,9 @@ function assemble(t2, prog, cfg) {
13222
14289
  const projection = reducer < 0 ? ~reducer : -1;
13223
14290
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
13224
14291
  const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
14292
+ const decided = FIRST_DECIDED;
14293
+ FIRST_DECIDED = void 0;
14294
+ const linkFirst = () => decided ?? link(code[base]);
13225
14295
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
13226
14296
  if (count === 1) return (input, cur, ctx, values, inherited) => {
13227
14297
  cur = r0(input, cur, ctx, inherited);
@@ -13267,7 +14337,7 @@ function assemble(t2, prog, cfg) {
13267
14337
  };
13268
14338
  };
13269
14339
  if (REC) {
13270
- const first2 = link(code[base]);
14340
+ const first2 = linkFirst();
13271
14341
  const firstSync = sentinelFor(code[base + n]);
13272
14342
  const runnerAt = (i) => {
13273
14343
  const sync = sentinelFor(code[base + n + i]);
@@ -13303,13 +14373,13 @@ function assemble(t2, prog, cfg) {
13303
14373
  const bindRunners = (start) => {
13304
14374
  const count = Math.min(4, n - start);
13305
14375
  const at = (offset) => runnerAt(start + offset);
13306
- const never = () => -1;
14376
+ const never2 = () => -1;
13307
14377
  return runnerBlock(
13308
14378
  count,
13309
14379
  at(0),
13310
- count > 1 ? at(1) : never,
13311
- count > 2 ? at(2) : never,
13312
- count > 3 ? at(3) : never,
14380
+ count > 1 ? at(1) : never2,
14381
+ count > 2 ? at(2) : never2,
14382
+ count > 3 ? at(3) : never2,
13313
14383
  start + count < n ? bindRunners(start + count) : void 0
13314
14384
  );
13315
14385
  };
@@ -13359,15 +14429,31 @@ function assemble(t2, prog, cfg) {
13359
14429
  let hasAdj = false;
13360
14430
  for (let i = 1; i < n; i++) {
13361
14431
  const kidIp = code[base + i];
13362
- if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
14432
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp) || holdsGap(code, k, base, n, i, NULLABLE)) {
13363
14433
  hasAdj = true;
13364
14434
  break;
13365
14435
  }
13366
14436
  }
13367
14437
  if (hasAdj) {
13368
- const first2 = link(code[base]);
14438
+ const first2 = linkFirst();
13369
14439
  const runnerAt = (i) => {
13370
14440
  const kidIp = code[base + i];
14441
+ if (holdsGap(code, k, base, n, i, NULLABLE)) {
14442
+ const kid = link(kidIp);
14443
+ return (input, cur, ctx) => {
14444
+ if (ctx.trivia === void 0) {
14445
+ const v2 = kid(input, cur, ctx);
14446
+ if (v2 === FAIL) return -1;
14447
+ TERMV = v2;
14448
+ return EC.e;
14449
+ }
14450
+ const scanEnd = skipTrivia(input, cur, ctx);
14451
+ const v = kid(input, scanEnd, ctx);
14452
+ if (v === FAIL) return -1;
14453
+ TERMV = v;
14454
+ return scanEnd;
14455
+ };
14456
+ }
13371
14457
  if (code[kidIp] !== OP_ADJ) {
13372
14458
  const kid = link(kidIp);
13373
14459
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -13392,13 +14478,13 @@ function assemble(t2, prog, cfg) {
13392
14478
  const bindRunners = (start) => {
13393
14479
  const count = Math.min(4, n - start);
13394
14480
  const at = (offset) => runnerAt(start + offset);
13395
- const never = () => -1;
14481
+ const never2 = () => -1;
13396
14482
  return runnerBlock(
13397
14483
  count,
13398
14484
  at(0),
13399
- count > 1 ? at(1) : never,
13400
- count > 2 ? at(2) : never,
13401
- count > 3 ? at(3) : never,
14485
+ count > 1 ? at(1) : never2,
14486
+ count > 2 ? at(2) : never2,
14487
+ count > 3 ? at(3) : never2,
13402
14488
  start + count < n ? bindRunners(start + count) : void 0
13403
14489
  );
13404
14490
  };
@@ -13435,7 +14521,7 @@ function assemble(t2, prog, cfg) {
13435
14521
  };
13436
14522
  }
13437
14523
  if (n === 1) {
13438
- const k0 = link(code[base]);
14524
+ const k0 = linkFirst();
13439
14525
  if (fused) {
13440
14526
  return (input, pos, ctx) => {
13441
14527
  const v = k0(input, pos, ctx);
@@ -13457,7 +14543,7 @@ function assemble(t2, prog, cfg) {
13457
14543
  };
13458
14544
  }
13459
14545
  if (n === 2) {
13460
- const k0 = link(code[base]), k1 = link(code[base + 1]);
14546
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
13461
14547
  if (fused) {
13462
14548
  return (input, pos, ctx) => {
13463
14549
  const v0 = k0(input, pos, ctx);
@@ -13488,7 +14574,7 @@ function assemble(t2, prog, cfg) {
13488
14574
  };
13489
14575
  }
13490
14576
  if (n === 3) {
13491
- const k0 = link(code[base]), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
14577
+ const k0 = linkFirst(), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
13492
14578
  if (fused) {
13493
14579
  return (input, pos, ctx) => {
13494
14580
  const v0 = k0(input, pos, ctx);
@@ -13582,7 +14668,7 @@ function assemble(t2, prog, cfg) {
13582
14668
  start + count < n ? bind(start + count) : void 0
13583
14669
  );
13584
14670
  };
13585
- const first = link(code[base]);
14671
+ const first = linkFirst();
13586
14672
  const tail = bind(1);
13587
14673
  const runDirectTerms = (input, pos, ctx, values) => {
13588
14674
  const v0 = first(input, pos, ctx);
@@ -13621,6 +14707,8 @@ function assemble(t2, prog, cfg) {
13621
14707
  const n = code[ip + 2];
13622
14708
  const choiceFx = fx[code[ip + 3]];
13623
14709
  const base = ip + 4;
14710
+ for (let i = 0; i < n; i++) link(code[base + i]);
14711
+ const armsClean = CLEAN(ip);
13624
14712
  if (table.exclusive) {
13625
14713
  const ascii = table.ascii;
13626
14714
  const hi = table.hi;
@@ -13760,7 +14848,7 @@ function assemble(t2, prog, cfg) {
13760
14848
  if (n === 3) addGate(g2, 4);
13761
14849
  return (input, pos, ctx) => {
13762
14850
  const c = lead(input, pos);
13763
- const need = markCst(ctx);
14851
+ const need = !armsClean && markCst(ctx);
13764
14852
  const mRaw = MRAW;
13765
14853
  const mTl = MTL;
13766
14854
  const mLv = MLV;
@@ -13830,6 +14918,11 @@ function assemble(t2, prog, cfg) {
13830
14918
  }
13831
14919
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13832
14920
  }
14921
+ if (prev === 0) {
14922
+ ctx._fe = pos;
14923
+ ctx._fx = choiceFx;
14924
+ return FAIL;
14925
+ }
13833
14926
  if (best === pos && prev < 1) acc = accSet(e0, acc);
13834
14927
  if (best === pos && prev < 2) acc = accSet(e1, acc);
13835
14928
  if (best === pos && n === 3 && prev < 3) acc = accSet(e2, acc);
@@ -13972,7 +15065,7 @@ function assemble(t2, prog, cfg) {
13972
15065
  if (pn !== 0) {
13973
15066
  return (input, pos, ctx) => {
13974
15067
  const c = lead(input, pos);
13975
- const need = markCst(ctx);
15068
+ const need = !armsClean && markCst(ctx);
13976
15069
  const mRaw = MRAW;
13977
15070
  const mTl = MTL;
13978
15071
  const mLv = MLV;
@@ -14029,7 +15122,7 @@ function assemble(t2, prog, cfg) {
14029
15122
  }
14030
15123
  return (input, pos, ctx) => {
14031
15124
  const c = lead(input, pos);
14032
- const need = markCst(ctx);
15125
+ const need = !armsClean && markCst(ctx);
14033
15126
  const mRaw = MRAW;
14034
15127
  const mTl = MTL;
14035
15128
  const mLv = MLV;
@@ -14077,7 +15170,7 @@ function assemble(t2, prog, cfg) {
14077
15170
  }
14078
15171
  return (input, pos, ctx) => {
14079
15172
  const c = lead(input, pos);
14080
- const need = markCst(ctx);
15173
+ const need = !armsClean && markCst(ctx);
14081
15174
  const mRaw = MRAW;
14082
15175
  const mTl = MTL;
14083
15176
  const mLv = MLV;
@@ -14131,6 +15224,21 @@ function assemble(t2, prog, cfg) {
14131
15224
  return lit(input, pos, ctx);
14132
15225
  };
14133
15226
  }
15227
+ case OP_RGATE: {
15228
+ const cls = cc[code[ip + 1]];
15229
+ const xf = fx[code[ip + 3]];
15230
+ const child = link(code[ip + 2]);
15231
+ if (cfg.tolerant || cfg.probe) return child;
15232
+ return (input, pos, ctx) => {
15233
+ const item = ctx._routed;
15234
+ if (item !== void 0 && item.span.start === pos && !classHas2(cls, lead(input, item.span.end))) {
15235
+ ctx._fe = item.span.end;
15236
+ ctx._fx = xf;
15237
+ return FAIL;
15238
+ }
15239
+ return child(input, pos, ctx);
15240
+ };
15241
+ }
14134
15242
  case OP_ARMGATE: {
14135
15243
  const pred = fns[code[ip + 1]];
14136
15244
  const child = link(code[ip + 2]);
@@ -14138,7 +15246,7 @@ function assemble(t2, prog, cfg) {
14138
15246
  return (input, pos, ctx) => {
14139
15247
  if (!pred(ctx.state)) {
14140
15248
  ctx._fc = false;
14141
- ctx._fe = pos;
15249
+ ctx._fe = -1;
14142
15250
  ctx._fx = xf;
14143
15251
  return FAIL;
14144
15252
  }
@@ -14199,6 +15307,7 @@ function assemble(t2, prog, cfg) {
14199
15307
  const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
14200
15308
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
14201
15309
  const skipBeforeFirst = sepIp < 0 && min === 0;
15310
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
14202
15311
  if (REC) {
14203
15312
  const itemFx2 = fx[code[ip + 6]];
14204
15313
  const sepSent = sentinelFor(code[ip + 7]);
@@ -14295,6 +15404,8 @@ function assemble(t2, prog, cfg) {
14295
15404
  const out = collect ? [] : void 0;
14296
15405
  const hasTrivia = ctx.trivia !== void 0;
14297
15406
  const needMark = rollbackNeeded(ctx);
15407
+ const markLater = needMark && (!itemClean || hasTrivia);
15408
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
14298
15409
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
14299
15410
  let cur = pos;
14300
15411
  let count = 0;
@@ -14302,14 +15413,15 @@ function assemble(t2, prog, cfg) {
14302
15413
  if (max >= 0 && count >= max) break;
14303
15414
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
14304
15415
  if (count >= min && sep === void 0 && !hasTrivia && gateItems && !itemMayStart(input, cur)) break;
14305
- if (needMark) markCst(ctx);
14306
- const mRaw = needMark ? MRAW : 0;
14307
- const mTl = needMark ? MTL : 0;
14308
- const mLv = needMark ? MLV : 0;
14309
- const mFl = needMark ? ctx._fields?.length ?? 0 : 0;
14310
- const mEr = needMark ? ctx._errors?.length ?? 0 : 0;
14311
- const mLog = needMark ? ctx._triviaLog?.length ?? 0 : 0;
14312
- const mRoot = needMark ? ctx._rootTriviaLog?.length ?? 0 : 0;
15416
+ const markIt = count > 0 ? markLater : markFirst;
15417
+ if (markIt) markCst(ctx);
15418
+ const mRaw = markIt ? MRAW : 0;
15419
+ const mTl = markIt ? MTL : 0;
15420
+ const mLv = markIt ? MLV : 0;
15421
+ const mFl = markIt ? ctx._fields?.length ?? 0 : 0;
15422
+ const mEr = markIt ? ctx._errors?.length ?? 0 : 0;
15423
+ const mLog = markIt ? ctx._triviaLog?.length ?? 0 : 0;
15424
+ const mRoot = markIt ? ctx._rootTriviaLog?.length ?? 0 : 0;
14313
15425
  let itemStart = cur;
14314
15426
  let sepEnd = -1;
14315
15427
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -14321,7 +15433,7 @@ function assemble(t2, prog, cfg) {
14321
15433
  if (sepLeads) LEAD.at = cur;
14322
15434
  const sv = sep(input, sp, ctx);
14323
15435
  if (sv === FAIL) {
14324
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15436
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14325
15437
  if (committed3(ctx)) return FAIL;
14326
15438
  break;
14327
15439
  }
@@ -14332,25 +15444,25 @@ function assemble(t2, prog, cfg) {
14332
15444
  itemStart = skipTrivia(input, itemStart, ctx);
14333
15445
  }
14334
15446
  if (itemStart >= input.length && viaRepItem) {
14335
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15447
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14336
15448
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14337
15449
  break;
14338
15450
  }
14339
15451
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
14340
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15452
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14341
15453
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14342
15454
  break;
14343
15455
  }
14344
15456
  ctx._fc = false;
14345
15457
  const v = child(input, itemStart, ctx);
14346
15458
  if (v === FAIL) {
14347
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15459
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14348
15460
  if (committed3(ctx)) return FAIL;
14349
15461
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14350
15462
  break;
14351
15463
  }
14352
15464
  if (EC.e === itemStart && viaRepItem) {
14353
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15465
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14354
15466
  break;
14355
15467
  }
14356
15468
  if (out !== void 0) out.push(v);
@@ -14424,7 +15536,14 @@ function assemble(t2, prog, cfg) {
14424
15536
  const runArm = n === 0 ? void 0 : bindArms(0);
14425
15537
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
14426
15538
  return (input, pos, ctx) => {
14427
- const selectorMark = saveTriviaMark(ctx);
15539
+ const need = markCst(ctx);
15540
+ const mRaw = MRAW;
15541
+ const mTl = MTL;
15542
+ const mLv = MLV;
15543
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
15544
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
15545
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
15546
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14428
15547
  const selVal = selector(input, pos, ctx);
14429
15548
  if (selVal === FAIL) return FAIL;
14430
15549
  const selEnd = EC.e;
@@ -14436,9 +15555,9 @@ function assemble(t2, prog, cfg) {
14436
15555
  ctx._fx = expected;
14437
15556
  return FAIL;
14438
15557
  }
14439
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
15558
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14440
15559
  }
14441
- return runArm(arm, input, pos, selEnd, key, selectorMark, ctx);
15560
+ return runArm(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14442
15561
  };
14443
15562
  }
14444
15563
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -14474,7 +15593,8 @@ function assemble(t2, prog, cfg) {
14474
15593
  return nd;
14475
15594
  };
14476
15595
  }
14477
- const child = link(code[ip + 2]);
15596
+ const child = NODE_BODY ?? link(code[ip + 2]);
15597
+ NODE_BODY = void 0;
14478
15598
  const proj = code[ip + 4];
14479
15599
  const buildIdx = code[ip + 1];
14480
15600
  const type = k[code[ip + 5]];
@@ -14498,6 +15618,30 @@ function assemble(t2, prog, cfg) {
14498
15618
  if (build !== void 0 && proj < 0 && flags === 18) {
14499
15619
  return childrenOnlyFieldsBuildNode(child, build);
14500
15620
  }
15621
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
15622
+ return passCollapseNode(child, build, flags === 32);
15623
+ }
15624
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
15625
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(closureLabels.at(code[ip + 2]).tri, trivia2);
15626
+ if (build !== void 0 && gated !== void 0 && triviaLead !== void 0) {
15627
+ const classic = flags === 32 ? collapseBuildNode(child, build) : childrenOnlyCollapseBuildNode(child, build);
15628
+ return gatedPassCollapseNode(
15629
+ [
15630
+ ...gated.leads.map((g) => cc[code[g + 1]]),
15631
+ resolveClass(encodeClassSpec([
15632
+ ...triviaLead,
15633
+ ...gated.lits.map((i) => {
15634
+ const c = k[i].codePointAt(0);
15635
+ return { lo: c, hi: c };
15636
+ })
15637
+ ]))
15638
+ ],
15639
+ link(gated.last),
15640
+ classic,
15641
+ build,
15642
+ flags === 32
15643
+ );
15644
+ }
14501
15645
  if (build !== void 0 && proj < 0 && flags === 32) {
14502
15646
  return collapseBuildNode(child, build);
14503
15647
  }
@@ -14544,7 +15688,7 @@ function assemble(t2, prog, cfg) {
14544
15688
  if (v === FAIL) return FAIL;
14545
15689
  const end = EC.e;
14546
15690
  const span = tracked ? spanLines(ctx, pos, end) : { start: pos, end };
14547
- const st = readsState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
15691
+ const st = readsState ? ctx.state : void 0;
14548
15692
  let nd;
14549
15693
  if (unwrap && kids.length === 1) {
14550
15694
  nd = unwrapChild(kids[0]);
@@ -14557,10 +15701,10 @@ function assemble(t2, prog, cfg) {
14557
15701
  ) {
14558
15702
  nd = kids[0];
14559
15703
  } else if (proj >= 0) {
14560
- nd = hostCst && host !== void 0 ? host(type, kids, fieldMap, span, rawKids, tlog, readsState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0, tags) : projectChild(kids, proj, type);
15704
+ nd = hostCst && host !== void 0 ? host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags) : projectChild(kids, proj, type);
14561
15705
  } else if (build !== void 0) {
14562
15706
  if (hostCst && host !== void 0) {
14563
- nd = host(type, kids, fieldMap, span, rawKids, tlog, readsState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0, tags);
15707
+ nd = host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags);
14564
15708
  } else {
14565
15709
  nd = build(kids, fieldMap, span, rawKids, captureWide ? tlog : EMPTY_TL2, st);
14566
15710
  }
@@ -14611,9 +15755,7 @@ function assemble(t2, prog, cfg) {
14611
15755
  let emitRefusal;
14612
15756
  let emitReached;
14613
15757
  {
14614
- const extraIps = [];
14615
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
14616
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
15758
+ const extraIps = assemblyExtraIps(prog);
14617
15759
  const roots = [...Object.values(prog.rules), ...extraIps];
14618
15760
  for (const ip of reachableSites(code, roots)) {
14619
15761
  if (code[ip] === OP_DISPATCH) {
@@ -14648,6 +15790,8 @@ function assemble(t2, prog, cfg) {
14648
15790
  }
14649
15791
  const notChild = scalarTerminalNotChild(code, ip);
14650
15792
  if (notChild >= 0) scalarFor(notChild);
15793
+ const peekChild = scalarTerminalPeekChild(code, ip);
15794
+ if (peekChild >= 0) scalarFor(peekChild);
14651
15795
  }
14652
15796
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
14653
15797
  if (pre !== void 0) {
@@ -14706,9 +15850,12 @@ function assemble(t2, prog, cfg) {
14706
15850
  adjacencyHolds,
14707
15851
  t2.lexPrograms,
14708
15852
  LEAD,
14709
- triviaFieldCapture
15853
+ triviaFieldCapture,
15854
+ skipDeferredTrivia,
15855
+ collapseEmpty
14710
15856
  );
14711
15857
  emitReached = new Set(pre.reached);
15858
+ if (emitted.ext !== void 0) HYBRID = emitted;
14712
15859
  }
14713
15860
  try {
14714
15861
  if (emitted !== void 0) throw new ServedByBuild();
@@ -14790,7 +15937,9 @@ function assemble(t2, prog, cfg) {
14790
15937
  adjacencyHolds,
14791
15938
  t2.lexPrograms,
14792
15939
  LEAD,
14793
- triviaFieldCapture
15940
+ triviaFieldCapture,
15941
+ skipDeferredTrivia,
15942
+ collapseEmpty
14794
15943
  );
14795
15944
  emitReached = em.reached;
14796
15945
  } catch (e) {
@@ -14801,7 +15950,7 @@ function assemble(t2, prog, cfg) {
14801
15950
  }
14802
15951
  function pieceAt(ip) {
14803
15952
  const em = emitted;
14804
- if (em !== void 0) {
15953
+ if (em !== void 0 && HYBRID === void 0) {
14805
15954
  const p = em.byIp[ip];
14806
15955
  if (p === void 0) throw new Error(`table emitter: no emitted body for site ${ip}`);
14807
15956
  return p;
@@ -14831,6 +15980,37 @@ function assemble(t2, prog, cfg) {
14831
15980
  }
14832
15981
  const scans = scansArr;
14833
15982
  const scanSkip = (prog.scanSkip ?? []).map((set) => set.map((r) => subtreeComb(r)));
15983
+ if (HYBRID !== void 0) {
15984
+ const em = HYBRID;
15985
+ em.bind(
15986
+ (s) => {
15987
+ const saved = SCAN;
15988
+ SCAN = s;
15989
+ return saved;
15990
+ },
15991
+ em.ext.map((ip) => link(ip))
15992
+ );
15993
+ const pieces2 = {};
15994
+ for (const [name, entryIp] of Object.entries(prog.rules)) {
15995
+ pieces2[name] = em.pieces[name] ?? link(entryIp);
15996
+ }
15997
+ for (const ip of emitReached) reached.add(ip);
15998
+ return {
15999
+ pieces: pieces2,
16000
+ end: () => EC.e,
16001
+ begin: (ctx) => {
16002
+ begin(ctx);
16003
+ em.begin(ctx);
16004
+ },
16005
+ finish: () => {
16006
+ em.finish();
16007
+ finish();
16008
+ },
16009
+ scanSkip,
16010
+ reached,
16011
+ emitRefusal: void 0
16012
+ };
16013
+ }
14834
16014
  if (emitted !== void 0) {
14835
16015
  const em = emitted;
14836
16016
  return {
@@ -14866,6 +16046,15 @@ function assemble(t2, prog, cfg) {
14866
16046
  }
14867
16047
  return { pieces, end: () => EC.e, begin, finish, scanSkip, reached, emitRefusal };
14868
16048
  }
16049
+ var SITE_COUNTS;
16050
+ function countedPiece(piece, ip) {
16051
+ const counts = SITE_COUNTS;
16052
+ if (counts === void 0) return piece;
16053
+ return (input, pos, ctx) => {
16054
+ counts[ip]++;
16055
+ return piece(input, pos, ctx);
16056
+ };
16057
+ }
14869
16058
  var AssemblyCache = class {
14870
16059
  t;
14871
16060
  prog;
@@ -15017,7 +16206,7 @@ function emitClassPool(classes) {
15017
16206
  if (classes.length < 2) return array;
15018
16207
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
15019
16208
  if (delimiter === void 0) return array;
15020
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16209
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
15021
16210
  return split.length < array.length ? split : array;
15022
16211
  }
15023
16212
  function emitConst(v) {
@@ -15068,9 +16257,7 @@ function emitDispatchSpec(d) {
15068
16257
  function emitAssemblies(prog, cfgs) {
15069
16258
  if (cfgs.length === 0) return ["a:[],"];
15070
16259
  const t2 = resolveTable(prog);
15071
- const extraIps = [];
15072
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
15073
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
16260
+ const extraIps = assemblyExtraIps(prog);
15074
16261
  const out = [];
15075
16262
  const seen = /* @__PURE__ */ new Set();
15076
16263
  for (const cfg of cfgs) {
@@ -15079,7 +16266,7 @@ function emitAssemblies(prog, cfgs) {
15079
16266
  seen.add(key);
15080
16267
  let em;
15081
16268
  try {
15082
- em = emitAssemblySource(t2, prog, cfg, extraIps, true);
16269
+ em = emitAssemblySource(t2, prog, cfg, extraIps, true, cfg.select);
15083
16270
  } catch (e) {
15084
16271
  if (e instanceof Unemittable) continue;
15085
16272
  throw e;
@@ -16878,16 +18065,16 @@ function ownSource(fn) {
16878
18065
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
16879
18066
  }
16880
18067
  function compile(target, second, third) {
16881
- if (!isCombinator(target)) return compileMap(target, second);
18068
+ if (!isCombinator2(target)) return compileMap(target, second);
16882
18069
  return compileRoot(target, second, third);
16883
18070
  }
16884
- function isCombinator(x) {
18071
+ function isCombinator2(x) {
16885
18072
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
16886
18073
  }
16887
18074
  function compileMap(grammar, opts = {}) {
16888
18075
  const entries = [];
16889
18076
  for (const [key, value] of Object.entries(grammar)) {
16890
- if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
18077
+ if (!isCombinator2(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
16891
18078
  if (value._def.tag === "lazy") {
16892
18079
  try {
16893
18080
  value._def.thunk();
@@ -17201,49 +18388,6 @@ function digestValue(value, prefix = "", options) {
17201
18388
  return sha.digest("hex");
17202
18389
  }
17203
18390
 
17204
- // src/combinators/attempt.ts
17205
- function containOption(options) {
17206
- if (options === void 0) return false;
17207
- for (const key of Object.keys(options)) {
17208
- if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
17209
- }
17210
- if (options.contain !== void 0 && typeof options.contain !== "boolean") {
17211
- throw new TypeError("attempt(): `contain` must be a boolean");
17212
- }
17213
- return options.contain === true;
17214
- }
17215
- function attempt(parser2, options) {
17216
- const contain = containOption(options);
17217
- const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
17218
- let failExpected;
17219
- return {
17220
- _tag: "attempt",
17221
- _meta: parser2._meta,
17222
- _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
17223
- parse(input, pos, ctx) {
17224
- if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
17225
- if (failExpected === void 0) {
17226
- const e = deriveExpected(parser2);
17227
- failExpected = e.length > 0 ? e : [parser2._tag];
17228
- }
17229
- return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
17230
- }
17231
- const mark = saveCstMark(ctx);
17232
- const log = ctx._triviaLog?.length;
17233
- const rootLog = ctx._rootTriviaLog?.length;
17234
- const split = ctx._columnsSplit;
17235
- const result = parser2.parse(input, pos, ctx);
17236
- if (result.ok) return result;
17237
- rollbackCstCapture(ctx, mark);
17238
- ctx._columnsSplit = split;
17239
- if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
17240
- if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
17241
- if (result.committed && !contain) return result;
17242
- return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
17243
- }
17244
- };
17245
- }
17246
-
17247
18391
  // src/combinators/not.ts
17248
18392
  function not(combinator) {
17249
18393
  const meta = {