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
package/dist/cli/index.js CHANGED
@@ -819,6 +819,31 @@ function pushCstChild(ctx, built, rawEntry2) {
819
819
  else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
820
820
  if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry2);
821
821
  }
822
+ function popCstChild(ctx) {
823
+ const b = ctx._cstBuf;
824
+ if (b) {
825
+ const ch2 = b.ch;
826
+ if (b.rawOnly !== true && ch2) {
827
+ ch2.pop();
828
+ if (ch2.length === 1) {
829
+ b.single = ch2[0];
830
+ b.ch = void 0;
831
+ }
832
+ }
833
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1;
834
+ else if (b.raw) {
835
+ b.raw.pop();
836
+ if (b.raw.length === 1) {
837
+ b.rawSingle = b.raw[0];
838
+ b.raw = void 0;
839
+ }
840
+ } else b.rawSingle = void 0;
841
+ return;
842
+ }
843
+ if (ctx._cstChildren) ctx._cstChildren.pop();
844
+ else if (ctx._cstLeaves) ctx._cstLeaves.pop();
845
+ if (ctx._cstRawChildren) ctx._cstRawChildren.pop();
846
+ }
822
847
  function cstRawLen(ctx) {
823
848
  const b = ctx._cstBuf;
824
849
  if (b) {
@@ -977,6 +1002,7 @@ function literalCodePoints(frag) {
977
1002
  if (ch2 === "\\") {
978
1003
  const e = frag[i + 1];
979
1004
  if (e === void 0) return null;
1005
+ if (!(e in CLASS_ESCAPES) && /\w/.test(e)) return null;
980
1006
  out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
981
1007
  i += 2;
982
1008
  continue;
@@ -1089,6 +1115,7 @@ function createParseContext() {
1089
1115
  _rootTriviaKindIndex: void 0,
1090
1116
  _rootTriviaStrictScopes: void 0,
1091
1117
  _rootTriviaCapture: void 0,
1118
+ _gap: void 0,
1092
1119
  _cstTriviaLog: void 0,
1093
1120
  _fields: void 0,
1094
1121
  _cstBuf: void 0,
@@ -1571,7 +1598,10 @@ function labeledTriviaSpec(arms, minRepeats) {
1571
1598
  arms,
1572
1599
  minRepeats,
1573
1600
  visitor: commonLabeledTriviaVisitor({ arms, minRepeats }),
1574
- charArms: charArmsFor({ arms, minRepeats })
1601
+ charArms: charArmsFor({ arms, minRepeats }),
1602
+ rootKinds: void 0,
1603
+ rootLeaders: [],
1604
+ rootScan: null
1575
1605
  };
1576
1606
  }
1577
1607
  function matchArmAt(input, pos, arm, state) {
@@ -2031,8 +2061,50 @@ function loopScanner(arms) {
2031
2061
  function regexTriviaScanner(parser2) {
2032
2062
  const d = parser2._def.tag === "label" ? parser2._def.parser._def : parser2._def;
2033
2063
  if (d.tag !== "regex" || d.flags) return null;
2034
- const source = d.source;
2035
- return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source);
2064
+ return sourceScanner(d.source);
2065
+ }
2066
+ function sourceScanner(source) {
2067
+ return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source) ?? sharedPrefixAltSource(source);
2068
+ }
2069
+ function sharedPrefixAltSource(source) {
2070
+ const m = /^((?:\\.|[^\\[\]()*+?|^$.{}])+)\(\?:(.*)\)$/.exec(source);
2071
+ if (!m) return null;
2072
+ const alts = [];
2073
+ const body = m[2];
2074
+ let depth = 0;
2075
+ let start = 0;
2076
+ for (let i = 0; i < body.length; i++) {
2077
+ const c = body[i];
2078
+ if (c === "\\") {
2079
+ i++;
2080
+ continue;
2081
+ }
2082
+ if (c === "[") {
2083
+ while (i < body.length && body[i] !== "]") i += body[i] === "\\" ? 2 : 1;
2084
+ continue;
2085
+ }
2086
+ if (c === "(") depth++;
2087
+ else if (c === ")" && --depth < 0) return null;
2088
+ else if (c === "|" && depth === 0) {
2089
+ alts.push(body.slice(start, i));
2090
+ start = i + 1;
2091
+ }
2092
+ }
2093
+ if (depth !== 0 || alts.length === 0) return null;
2094
+ alts.push(body.slice(start));
2095
+ const scanners = [];
2096
+ for (const alt of alts) {
2097
+ const scanner = sourceScanner(m[1] + alt);
2098
+ if (scanner === null) return null;
2099
+ scanners.push(scanner);
2100
+ }
2101
+ return (input, cur) => {
2102
+ for (const scanner of scanners) {
2103
+ const end = scanner(input, cur);
2104
+ if (end > cur) return end;
2105
+ }
2106
+ return cur;
2107
+ };
2036
2108
  }
2037
2109
  function bmpString(cps) {
2038
2110
  if (!cps) return null;
@@ -2348,10 +2420,16 @@ function branchUsesRouted(branch) {
2348
2420
  return branch.usesRouted === true || parserUsesRouted(branch.parser);
2349
2421
  }
2350
2422
  function asciiFoldKey(key) {
2351
- let out = "";
2352
- for (let i = 0; i < key.length; i++) {
2423
+ let i = 0;
2424
+ for (; i < key.length; i++) {
2425
+ const c = key.charCodeAt(i);
2426
+ if (c >= 65 && c <= 90) break;
2427
+ }
2428
+ if (i === key.length) return key;
2429
+ let out = key.slice(0, i);
2430
+ for (; i < key.length; i++) {
2353
2431
  const c = key.charCodeAt(i);
2354
- out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
2432
+ out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : key[i];
2355
2433
  }
2356
2434
  return out;
2357
2435
  }
@@ -2680,6 +2758,42 @@ function keywords(words, opts = {}) {
2680
2758
  };
2681
2759
  }
2682
2760
 
2761
+ // src/combinators/trivia-boundary.ts
2762
+ var MAX_DEPTH = 12;
2763
+ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
2764
+ if (depth === 0) return true;
2765
+ const d = p._def;
2766
+ switch (d.tag) {
2767
+ // Multi-term forms: the gaps BETWEEN terms are the ambient-trivia positions.
2768
+ case "sequence":
2769
+ return d.parsers.length > 1;
2770
+ case "many":
2771
+ case "oneOrMore":
2772
+ case "sepBy":
2773
+ return true;
2774
+ // Transparent wrappers — they add no position, so ask what they wrap.
2775
+ case "node":
2776
+ case "transform":
2777
+ case "leaf":
2778
+ case "label":
2779
+ case "field":
2780
+ case "token":
2781
+ case "attempt":
2782
+ case "optional":
2783
+ case "expect":
2784
+ case "withCtx":
2785
+ case "recover":
2786
+ case "trivia":
2787
+ return hasOwnTriviaBoundary(d.parser, depth - 1);
2788
+ // An alternation adds no position either, but ONE arm that has one is enough
2789
+ // to make the scope meaningful for this rule.
2790
+ case "choice":
2791
+ return d.parsers.some((a) => hasOwnTriviaBoundary(a, depth - 1));
2792
+ default:
2793
+ return false;
2794
+ }
2795
+ }
2796
+
2683
2797
  // src/compiler/token-alphabet.ts
2684
2798
  function optionalSuffixLexBody(ir) {
2685
2799
  if (ir.kind !== "sequence" || ir.parts.length !== 2) return void 0;
@@ -2699,7 +2813,10 @@ function selectOptionalSuffixLexBody(ir) {
2699
2813
  const token2 = { strategy: "token", estimatedOps: 2, body };
2700
2814
  return token2.estimatedOps < character.estimatedOps ? token2 : character;
2701
2815
  }
2702
- function directTokenBodyParser(parser2, resolve2) {
2816
+ function reinstallsRuleTrivia(reference, target) {
2817
+ return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
2818
+ }
2819
+ function directTokenBodyParser(parser2, resolve2, scope) {
2703
2820
  const outer = parser2._def;
2704
2821
  if (outer.tag !== "token") return void 0;
2705
2822
  let body = outer.parser;
@@ -2709,12 +2826,13 @@ function directTokenBodyParser(parser2, resolve2) {
2709
2826
  const wrapper = body._def;
2710
2827
  if (wrapper.tag === "grammar") {
2711
2828
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
2829
+ if (scope !== void 0) scope.cleared = true;
2712
2830
  body = wrapper.parser;
2713
2831
  continue;
2714
2832
  }
2715
2833
  if (wrapper.tag === "lazy") {
2716
2834
  const target = resolvedLazyTarget(body, resolve2);
2717
- if (target === void 0) return void 0;
2835
+ if (target === void 0 || reinstallsRuleTrivia(body, target)) return void 0;
2718
2836
  body = target;
2719
2837
  continue;
2720
2838
  }
@@ -2886,7 +3004,7 @@ function directNot2TokenBody(parser2, resolve2) {
2886
3004
  terminal
2887
3005
  };
2888
3006
  }
2889
- function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
3007
+ function directFixedLexNode(parser2, resolve2, active, pureOnly = false, cleared = false) {
2890
3008
  let current = parser2;
2891
3009
  const wrappers = /* @__PURE__ */ new Set();
2892
3010
  while (!wrappers.has(current)) {
@@ -2894,7 +3012,7 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2894
3012
  const def = current._def;
2895
3013
  if (def.tag === "lazy") {
2896
3014
  const target = resolvedLazyTarget(current, resolve2);
2897
- if (target === void 0) return void 0;
3015
+ if (target === void 0 || reinstallsRuleTrivia(current, target)) return void 0;
2898
3016
  current = target;
2899
3017
  continue;
2900
3018
  }
@@ -2912,30 +3030,33 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2912
3030
  if (terminal !== void 0) return { kind: "terminal", terminal };
2913
3031
  const def = current._def;
2914
3032
  if (def.tag === "grammar") {
3033
+ if (def.triviaParser === void 0 && def.captureTrivia !== true && def.rootCapture !== "opaque" && def.constructionCaptureTriviaKinds === void 0) {
3034
+ return directFixedLexNode(def.parser, resolve2, active, pureOnly, cleared || def.clearTrivia === true);
3035
+ }
2915
3036
  if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
2916
- return directFixedLexNode(def.parser, resolve2, active, true);
3037
+ return directFixedLexNode(def.parser, resolve2, active, true, cleared);
2917
3038
  }
2918
3039
  if (def.tag === "sequence") {
2919
3040
  if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
2920
- const parts = def.parsers.map((part) => directFixedLexNode(part, resolve2, active, pureOnly));
3041
+ const parts = def.parsers.map((part) => directFixedLexNode(part, resolve2, active, pureOnly, cleared));
2921
3042
  if (parts.some((part) => part === void 0)) return void 0;
2922
3043
  return { kind: "sequence", parts };
2923
3044
  }
2924
3045
  if (def.tag === "choice") {
2925
- 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;
2926
- const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve2, active, pureOnly));
3046
+ if (def.parsers.length < 2 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
3047
+ const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve2, active, pureOnly, cleared));
2927
3048
  if (arms.some((arm) => arm === void 0)) return void 0;
2928
- const final = classifyFinalChoice(def.parsers, resolve2);
2929
3049
  return {
2930
3050
  kind: "choice",
2931
3051
  arms,
2932
- firstSets: final.firstSets,
3052
+ parsers: def.parsers,
3053
+ cleared,
2933
3054
  armExpected: def.parsers.map(deriveExpected),
2934
3055
  expected: def.parsers.flatMap(deriveExpected)
2935
3056
  };
2936
3057
  }
2937
3058
  if (def.tag === "not") {
2938
- const body = directFixedLexNode(def.parser, resolve2, active, true);
3059
+ const body = directFixedLexNode(def.parser, resolve2, active, true, cleared);
2939
3060
  return body === void 0 ? void 0 : {
2940
3061
  kind: "not",
2941
3062
  body,
@@ -2943,18 +3064,28 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2943
3064
  };
2944
3065
  }
2945
3066
  if (def.tag === "optional") {
2946
- const body = directFixedLexNode(def.parser, resolve2, active, pureOnly);
3067
+ const body = directFixedLexNode(def.parser, resolve2, active, pureOnly, cleared);
2947
3068
  return body === void 0 ? void 0 : { kind: "optional", body };
2948
3069
  }
3070
+ if (def.tag === "many" || def.tag === "oneOrMore") {
3071
+ const body = directFixedLexNode(def.parser, resolve2, active, pureOnly, cleared);
3072
+ return body === void 0 ? void 0 : {
3073
+ kind: "repeat",
3074
+ body,
3075
+ min: def.tag === "many" ? 0 : def.min,
3076
+ max: def.max ?? -1
3077
+ };
3078
+ }
2949
3079
  return void 0;
2950
3080
  } finally {
2951
3081
  active.delete(current);
2952
3082
  }
2953
3083
  }
2954
3084
  function directFixedTokenBody(parser2, resolve2) {
2955
- const body = directTokenBodyParser(parser2, resolve2);
3085
+ const scope = { cleared: false };
3086
+ const body = directTokenBodyParser(parser2, resolve2, scope);
2956
3087
  if (body === void 0) return void 0;
2957
- const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set());
3088
+ const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set(), false, scope.cleared);
2958
3089
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
2959
3090
  }
2960
3091
  function directBalancedTokenBody(parser2, resolve2) {
@@ -4863,17 +4994,59 @@ function buildLexBodyRecognizer(spec, constants) {
4863
4994
  };
4864
4995
  }
4865
4996
 
4997
+ // src/table/run-support.ts
4998
+ function lineCol(ctx, offset) {
4999
+ const starts = ctx._lineStarts ?? [0];
5000
+ let lo = 0, hi = starts.length - 1;
5001
+ while (lo < hi) {
5002
+ const mid = lo + hi + 1 >> 1;
5003
+ if (starts[mid] <= offset) lo = mid;
5004
+ else hi = mid - 1;
5005
+ }
5006
+ return [lo + 1, offset - starts[lo] + 1];
5007
+ }
5008
+ function spanLines(ctx, start, end) {
5009
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
5010
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
5011
+ }
5012
+ function rawEntry(v, input, s, e) {
5013
+ if (typeof v === "object" && v !== null) {
5014
+ const tg = v._tag;
5015
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
5016
+ }
5017
+ return {
5018
+ _tag: "leaf",
5019
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
5020
+ span: { start: s, end: e }
5021
+ };
5022
+ }
5023
+ function lead(input, pos) {
5024
+ if (pos >= input.length) return -1;
5025
+ const c = input.charCodeAt(pos);
5026
+ if (c < 55296 || c > 56319) return c;
5027
+ return input.codePointAt(pos) ?? c;
5028
+ }
5029
+ var EMPTY_KIDS = Object.freeze([]);
5030
+ var EMPTY_TRIVIA = Object.freeze([]);
5031
+ function collapseEmpty(ctx, build, input, pos, end, readsRaw) {
5032
+ const collected = ctx._cstBuf !== void 0 || ctx._cstChildren !== void 0;
5033
+ if (collected) popCstChild(ctx);
5034
+ const raw = readsRaw ? [rawEntry(void 0, input, pos, end)] : EMPTY_KIDS;
5035
+ const nd = build(EMPTY_KIDS, void 0, { start: pos, end }, raw, EMPTY_TRIVIA, void 0);
5036
+ if (collected) pushCstChild(ctx, nd, ctx._cstBuf?.noRaw === true ? void 0 : rawEntry(nd, input, pos, end));
5037
+ return nd;
5038
+ }
5039
+
4866
5040
  // src/table/lex-program.ts
4867
5041
  var LEX_NODE_TERMINAL = 0;
4868
5042
  var LEX_NODE_SEQUENCE2 = 1;
4869
5043
  var LEX_NODE_SEQUENCE3 = 2;
4870
5044
  var LEX_NODE_SEQUENCE4 = 3;
4871
5045
  var LEX_NODE_SEQUENCE5 = 4;
4872
- var LEX_NODE_CHOICE2 = 5;
4873
- var LEX_NODE_CHOICE4 = 6;
4874
- var LEX_NODE_CHOICE8 = 7;
5046
+ var LEX_NODE_CHOICE = 5;
4875
5047
  var LEX_NODE_NOT = 8;
4876
5048
  var LEX_NODE_OPTIONAL = 9;
5049
+ var LEX_NODE_REPEAT = 10;
4877
5050
  function lexProgramDigest(words) {
4878
5051
  let hash = 2166136261;
4879
5052
  for (const word of words) {
@@ -4902,85 +5075,114 @@ function trackLexLines(ctx, input, end) {
4902
5075
  ctx._lineScannedTo = end;
4903
5076
  }
4904
5077
  function terminalNode(matcher, failure, tracksLines) {
4905
- const match = (input, pos) => {
4906
- const result = matcher(input, pos);
4907
- return result < 0 ? -1 : result / 2;
4908
- };
4909
5078
  return {
4910
- match,
5079
+ match: (input, pos) => {
5080
+ const result = matcher(input, pos);
5081
+ return result < 0 ? -1 : result / 2;
5082
+ },
4911
5083
  run: (input, pos, ctx) => {
4912
- const end = match(input, pos);
4913
- if (end < 0) {
5084
+ const result = matcher(input, pos);
5085
+ if (result < 0) {
4914
5086
  ctx._fe = pos;
4915
5087
  ctx._fx = failure;
4916
5088
  if (ctx._probe !== void 0) failAt(ctx, ctx._fx, pos);
4917
5089
  return -1;
4918
5090
  }
5091
+ const end = result / 2;
4919
5092
  if (tracksLines) trackLexLines(ctx, input, end);
4920
5093
  return end;
4921
5094
  }
4922
5095
  };
4923
5096
  }
4924
5097
  function sequence2(a, b) {
5098
+ const am = a.match, bm = b.match, ar = a.run, br = b.run;
4925
5099
  return {
4926
5100
  match: (input, pos) => {
4927
- const e0 = a.match(input, pos);
4928
- return e0 < 0 ? -1 : b.match(input, e0);
5101
+ const e0 = am(input, pos);
5102
+ return e0 < 0 ? -1 : bm(input, e0);
4929
5103
  },
4930
5104
  run: (input, pos, ctx) => {
4931
- const e0 = a.run(input, pos, ctx);
5105
+ const e0 = ar(input, pos, ctx);
4932
5106
  if (e0 < 0) return -1;
4933
5107
  ctx._fc = false;
4934
- return b.run(input, e0, ctx);
5108
+ return br(input, e0, ctx);
4935
5109
  }
4936
5110
  };
4937
5111
  }
4938
5112
  function sequence3(a, b, c) {
5113
+ const am = a.match, bm = b.match, cm = c.match, ar = a.run, br = b.run, cr = c.run;
4939
5114
  return {
4940
5115
  match: (input, pos) => {
4941
- const e0 = a.match(input, pos);
5116
+ const e0 = am(input, pos);
4942
5117
  if (e0 < 0) return -1;
4943
- const e1 = b.match(input, e0);
4944
- return e1 < 0 ? -1 : c.match(input, e1);
5118
+ const e1 = bm(input, e0);
5119
+ return e1 < 0 ? -1 : cm(input, e1);
4945
5120
  },
4946
5121
  run: (input, pos, ctx) => {
4947
- const e0 = a.run(input, pos, ctx);
5122
+ const e0 = ar(input, pos, ctx);
4948
5123
  if (e0 < 0) return -1;
4949
5124
  ctx._fc = false;
4950
- const e1 = b.run(input, e0, ctx);
5125
+ const e1 = br(input, e0, ctx);
4951
5126
  if (e1 < 0) return -1;
4952
5127
  ctx._fc = false;
4953
- return c.run(input, e1, ctx);
5128
+ return cr(input, e1, ctx);
4954
5129
  }
4955
5130
  };
4956
5131
  }
4957
5132
  function sequence4(a, b, c, d) {
4958
- const abc = sequence3(a, b, c);
5133
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match;
5134
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run;
4959
5135
  return {
4960
5136
  match: (input, pos) => {
4961
- const end = abc.match(input, pos);
4962
- return end < 0 ? -1 : d.match(input, end);
5137
+ const e0 = am(input, pos);
5138
+ if (e0 < 0) return -1;
5139
+ const e1 = bm(input, e0);
5140
+ if (e1 < 0) return -1;
5141
+ const e2 = cm(input, e1);
5142
+ return e2 < 0 ? -1 : dm(input, e2);
4963
5143
  },
4964
5144
  run: (input, pos, ctx) => {
4965
- const end = abc.run(input, pos, ctx);
4966
- if (end < 0) return -1;
5145
+ const e0 = ar(input, pos, ctx);
5146
+ if (e0 < 0) return -1;
5147
+ ctx._fc = false;
5148
+ const e1 = br(input, e0, ctx);
5149
+ if (e1 < 0) return -1;
4967
5150
  ctx._fc = false;
4968
- return d.run(input, end, ctx);
5151
+ const e2 = cr(input, e1, ctx);
5152
+ if (e2 < 0) return -1;
5153
+ ctx._fc = false;
5154
+ return dr(input, e2, ctx);
4969
5155
  }
4970
5156
  };
4971
5157
  }
4972
5158
  function sequence5(a, b, c, d, e) {
4973
- const abcd = sequence4(a, b, c, d);
5159
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match, em = e.match;
5160
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run, er = e.run;
4974
5161
  return {
4975
5162
  match: (input, pos) => {
4976
- const end = abcd.match(input, pos);
4977
- return end < 0 ? -1 : e.match(input, end);
5163
+ const e0 = am(input, pos);
5164
+ if (e0 < 0) return -1;
5165
+ const e1 = bm(input, e0);
5166
+ if (e1 < 0) return -1;
5167
+ const e2 = cm(input, e1);
5168
+ if (e2 < 0) return -1;
5169
+ const e3 = dm(input, e2);
5170
+ return e3 < 0 ? -1 : em(input, e3);
4978
5171
  },
4979
5172
  run: (input, pos, ctx) => {
4980
- const end = abcd.run(input, pos, ctx);
4981
- if (end < 0) return -1;
5173
+ const e0 = ar(input, pos, ctx);
5174
+ if (e0 < 0) return -1;
5175
+ ctx._fc = false;
5176
+ const e1 = br(input, e0, ctx);
5177
+ if (e1 < 0) return -1;
5178
+ ctx._fc = false;
5179
+ const e2 = cr(input, e1, ctx);
5180
+ if (e2 < 0) return -1;
5181
+ ctx._fc = false;
5182
+ const e3 = dr(input, e2, ctx);
5183
+ if (e3 < 0) return -1;
4982
5184
  ctx._fc = false;
4983
- return e.run(input, end, ctx);
5185
+ return er(input, e3, ctx);
4984
5186
  }
4985
5187
  };
4986
5188
  }
@@ -4993,9 +5195,9 @@ function appendExpected(acc, values) {
4993
5195
  function choiceNode(arms, classes, armExpected, choiceExpected) {
4994
5196
  let matchTail = () => -1;
4995
5197
  for (let i = arms.length - 1; i >= 0; i--) {
4996
- const arm = arms[i], next = matchTail;
5198
+ const armMatch = arms[i].match, next = matchTail;
4997
5199
  matchTail = (input, pos) => {
4998
- const end = arm.match(input, pos);
5200
+ const end = armMatch(input, pos);
4999
5201
  return end < 0 ? next(input, pos) : end;
5000
5202
  };
5001
5203
  }
@@ -5005,7 +5207,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5005
5207
  return -1;
5006
5208
  };
5007
5209
  for (let i = arms.length - 1; i >= 0; i--) {
5008
- const arm = arms[i], cls = classes[i], staticExpected = armExpected[i], next = tail;
5210
+ const armRun = arms[i].run, cls = classes[i], staticExpected = armExpected[i], next = tail;
5009
5211
  tail = (input, pos, ctx, lead2, acc, best) => {
5010
5212
  if (cls !== void 0 && !classHas(cls, lead2)) {
5011
5213
  return next(
@@ -5018,7 +5220,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5018
5220
  );
5019
5221
  }
5020
5222
  ctx._fc = false;
5021
- const end = arm.run(input, pos, ctx);
5223
+ const end = armRun(input, pos, ctx);
5022
5224
  if (end >= 0) return end;
5023
5225
  const at = ctx._fe ?? pos;
5024
5226
  if (at > best) {
@@ -5045,11 +5247,58 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5045
5247
  )
5046
5248
  };
5047
5249
  }
5250
+ function exclusiveChoiceNode(arms, classes, choiceFx) {
5251
+ const ascii = (classes.length <= 128 ? new Int8Array(128) : new Int32Array(128)).fill(-1);
5252
+ const hi = [];
5253
+ for (let i = 0; i < classes.length; i++) {
5254
+ const cls = classes[i];
5255
+ for (let c = 0; c < 128; c++) if (cls.ascii[c] === 1) ascii[c] = i;
5256
+ for (let r = 0; r < cls.hi.length; r += 2) hi.push(cls.hi[r], cls.hi[r + 1], i);
5257
+ }
5258
+ const select = (code) => {
5259
+ if (code < 0) return -1;
5260
+ if (code < 128) return ascii[code];
5261
+ for (let r = 0; r < hi.length; r += 3) if (code >= hi[r] && code <= hi[r + 1]) return hi[r + 2];
5262
+ return -1;
5263
+ };
5264
+ let matchArm = () => -1;
5265
+ let selectRun = () => -1;
5266
+ for (let i = arms.length - 1; i >= 0; i--) {
5267
+ const armMatch = arms[i].match, armRun = arms[i].run, nextMatch = matchArm, nextRun = selectRun;
5268
+ matchArm = (selected, input, pos) => selected === i ? armMatch(input, pos) : nextMatch(selected, input, pos);
5269
+ selectRun = (selected, input, pos, ctx) => selected === i ? armRun(input, pos, ctx) : nextRun(selected, input, pos, ctx);
5270
+ }
5271
+ const runArm = (input, pos, ctx) => {
5272
+ const arm = select(lead(input, pos));
5273
+ if (arm >= 0) {
5274
+ ctx._fc = false;
5275
+ const end = selectRun(arm, input, pos, ctx);
5276
+ if (end >= 0) return end;
5277
+ if (committed(ctx)) return -1;
5278
+ const failed = ctx._fx;
5279
+ if (failed !== void 0 && failed.length > 0) {
5280
+ ctx._fe = pos;
5281
+ return -1;
5282
+ }
5283
+ }
5284
+ ctx._fe = pos;
5285
+ ctx._fx = choiceFx;
5286
+ return -1;
5287
+ };
5288
+ return {
5289
+ match: (input, pos) => {
5290
+ const arm = select(lead(input, pos));
5291
+ return arm < 0 ? -1 : matchArm(arm, input, pos);
5292
+ },
5293
+ run: runArm
5294
+ };
5295
+ }
5048
5296
  function notNode(body, failure) {
5297
+ const bodyMatch = body.match;
5049
5298
  return {
5050
- match: (input, pos) => body.match(input, pos) < 0 ? pos : -1,
5299
+ match: (input, pos) => bodyMatch(input, pos) < 0 ? pos : -1,
5051
5300
  run: (input, pos, ctx) => {
5052
- if (body.match(input, pos) < 0) return pos;
5301
+ if (bodyMatch(input, pos) < 0) return pos;
5053
5302
  ctx._fe = pos;
5054
5303
  ctx._fx = failure;
5055
5304
  return -1;
@@ -5057,18 +5306,57 @@ function notNode(body, failure) {
5057
5306
  };
5058
5307
  }
5059
5308
  function optionalNode(body) {
5309
+ const bodyMatch = body.match, bodyRun = body.run;
5060
5310
  return {
5061
5311
  match: (input, pos) => {
5062
- const end = body.match(input, pos);
5312
+ const end = bodyMatch(input, pos);
5063
5313
  return end < 0 ? pos : end;
5064
5314
  },
5065
5315
  run: (input, pos, ctx) => {
5066
5316
  ctx._fc = false;
5067
- const end = body.run(input, pos, ctx);
5317
+ const end = bodyRun(input, pos, ctx);
5068
5318
  return end < 0 && !committed(ctx) ? pos : end;
5069
5319
  }
5070
5320
  };
5071
5321
  }
5322
+ function repeatNode(item, min, max) {
5323
+ const itemMatch = item.match, itemRun = item.run;
5324
+ return {
5325
+ match: (input, pos) => {
5326
+ let cur = pos;
5327
+ let count = 0;
5328
+ for (; ; ) {
5329
+ if (max >= 0 && count >= max) break;
5330
+ const optional2 = count >= min && (count > 0 || min === 0);
5331
+ if (optional2 && cur >= input.length) break;
5332
+ const end = itemMatch(input, cur);
5333
+ if (end < 0 || optional2 && end === cur) break;
5334
+ cur = end;
5335
+ count++;
5336
+ }
5337
+ return count < min ? -1 : cur;
5338
+ },
5339
+ run: (input, pos, ctx) => {
5340
+ let cur = pos;
5341
+ let count = 0;
5342
+ for (; ; ) {
5343
+ if (max >= 0 && count >= max) break;
5344
+ const optional2 = count >= min && (count > 0 || min === 0);
5345
+ if (optional2 && cur >= input.length) break;
5346
+ ctx._fc = false;
5347
+ const end = itemRun(input, cur, ctx);
5348
+ if (end < 0) {
5349
+ if (committed(ctx)) return -1;
5350
+ break;
5351
+ }
5352
+ if (optional2 && end === cur) break;
5353
+ cur = end;
5354
+ count++;
5355
+ }
5356
+ return count < min ? -1 : cur;
5357
+ }
5358
+ };
5359
+ }
5072
5360
  function fixedTreeRunner(words, matchers, classes, expected) {
5073
5361
  const stack = [];
5074
5362
  const pop = () => {
@@ -5096,9 +5384,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5096
5384
  else stack.push(sequence5(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4]));
5097
5385
  continue;
5098
5386
  }
5099
- if (op >= LEX_NODE_CHOICE2 && op <= LEX_NODE_CHOICE8) {
5100
- const count = op === LEX_NODE_CHOICE2 ? 2 : op === LEX_NODE_CHOICE4 ? 4 : 8;
5387
+ if (op === LEX_NODE_CHOICE) {
5388
+ const count = words[at++];
5389
+ const exclusive = words[at++];
5390
+ if (exclusive !== 0 && exclusive !== 1) throw new TypeError("table lexical tree choice has an invalid dispatch mode");
5101
5391
  const choiceFx = expected[words[at++]];
5392
+ if (!Number.isInteger(count) || count < 2 || count > stack.length) {
5393
+ throw new TypeError("table lexical tree choice has an invalid arm count");
5394
+ }
5102
5395
  if (choiceFx === void 0) throw new TypeError("table lexical tree choice has an invalid expected set");
5103
5396
  const armClasses = [];
5104
5397
  const armFx = [];
@@ -5111,7 +5404,7 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5111
5404
  armFx.push(fx);
5112
5405
  }
5113
5406
  const arms = Array.from({ length: count }, pop).reverse();
5114
- stack.push(choiceNode(arms, armClasses, armFx, choiceFx));
5407
+ stack.push(exclusive === 1 ? exclusiveChoiceNode(arms, armClasses, choiceFx) : choiceNode(arms, armClasses, armFx, choiceFx));
5115
5408
  continue;
5116
5409
  }
5117
5410
  if (op === LEX_NODE_NOT) {
@@ -5124,6 +5417,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5124
5417
  stack.push(optionalNode(pop()));
5125
5418
  continue;
5126
5419
  }
5420
+ if (op === LEX_NODE_REPEAT) {
5421
+ const min = words[at++], max = words[at++];
5422
+ if (!Number.isInteger(min) || min < 0 || !Number.isInteger(max) || max >= 0 && max < min) {
5423
+ throw new TypeError("table lexical tree repeat has invalid bounds");
5424
+ }
5425
+ stack.push(repeatNode(pop(), min, max));
5426
+ continue;
5427
+ }
5127
5428
  throw new TypeError("table lexical tree has an unknown fixed body");
5128
5429
  }
5129
5430
  if (stack.length !== 1) throw new TypeError("table lexical tree does not resolve to one root body");
@@ -5278,6 +5579,12 @@ function scanRefs(s) {
5278
5579
  refs.push(...s.skip);
5279
5580
  return refs;
5280
5581
  }
5582
+ function assemblyExtraIps(prog) {
5583
+ const ips = [];
5584
+ for (const s of prog.scans ?? []) for (const r of scanRefs(s)) ips.push(r[0]);
5585
+ for (const set of prog.scanSkip ?? []) for (const r of set) ips.push(r[0]);
5586
+ return ips;
5587
+ }
5281
5588
  function expandCompact(p) {
5282
5589
  if ("code" in p) return p;
5283
5590
  return ownTableProgram({
@@ -5408,6 +5715,11 @@ function classHas2(cls, code) {
5408
5715
  for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
5409
5716
  return false;
5410
5717
  }
5718
+ function dispatchIsExclusive(arms, cc) {
5719
+ const resolved = [];
5720
+ for (const ci of arms) if (ci >= 0) resolved[ci] = resolveClass(cc[ci]);
5721
+ return resolveDispatch(arms, resolved).exclusive;
5722
+ }
5411
5723
  function resolveDispatch(arms, cc) {
5412
5724
  const ascii = new Uint8Array(128);
5413
5725
  const hi = [];
@@ -5481,66 +5793,261 @@ function resolveTable(prog) {
5481
5793
  return built;
5482
5794
  }
5483
5795
 
5484
- // src/compiler/degradation.ts
5485
- function formatDegradation(d) {
5486
- return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
5487
- }
5488
- var DETAIL_CAP = 8;
5489
- function formatDegradations(list) {
5490
- const byCode = /* @__PURE__ */ new Map();
5491
- for (const d of list) {
5492
- const bucket = byCode.get(d.code);
5493
- if (bucket) bucket.push(d);
5494
- else byCode.set(d.code, [d]);
5495
- }
5496
- const out = [];
5497
- for (const [code, items] of byCode) {
5498
- for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
5499
- if (items.length > DETAIL_CAP) {
5500
- out.push(
5501
- `[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.`
5502
- );
5503
- }
5504
- }
5505
- return out;
5796
+ // src/combinators/adjacency.ts
5797
+ function adjacencyOf(p) {
5798
+ return p._def.tag === "adjacency" ? p._def : null;
5506
5799
  }
5507
- var _sinks = [];
5508
- function beginDegradationCapture() {
5509
- _sinks.push(/* @__PURE__ */ new Map());
5800
+ function adjacencyExpected(def) {
5801
+ if (def.polarity === "adjacent") return "adjacent";
5802
+ return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5510
5803
  }
5511
- function degradationCaptureDepth() {
5512
- return _sinks.length;
5804
+ function holdsAdjacency(input, cur, ctx, def) {
5805
+ return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5513
5806
  }
5514
- function unwindDegradationCapture(depth) {
5515
- const found = [];
5516
- while (_sinks.length > depth) {
5517
- const sink = _sinks.pop();
5518
- found.unshift(...sink.values());
5519
- }
5520
- return found;
5807
+ function adjacencyHolds(input, cur, ctx, negated, kinds) {
5808
+ const end = probeTriviaEnd(input, cur, ctx);
5809
+ if (!negated) return end === cur;
5810
+ if (end === cur) return false;
5811
+ if (kinds === void 0) return true;
5812
+ const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
5813
+ const spec = analyzeLabeledTrivia(ctx.trivia);
5814
+ return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
5521
5815
  }
5522
- function resolveDegradationLevel(explicit) {
5523
- if (explicit !== void 0) return explicit;
5524
- const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
5525
- if (env === "off" || env === "warn" || env === "error") return env;
5526
- return "warn";
5816
+ function adjacencyFail(pos, def) {
5817
+ return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5527
5818
  }
5528
- function degradationKey(d) {
5529
- return JSON.stringify([d.code, d.where, d.subject]);
5819
+ 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.";
5820
+ function adjacencyMisuse(polarity) {
5821
+ return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
5530
5822
  }
5531
- function recordDegradation(d) {
5532
- const level = resolveDegradationLevel();
5533
- if (level === "off") return;
5534
- const key = degradationKey(d);
5535
- const sink = _sinks[_sinks.length - 1];
5536
- if (sink) {
5537
- if (!sink.has(key)) sink.set(key, d);
5538
- return;
5539
- }
5540
- if (_immediate.has(key)) return;
5541
- _immediate.add(key);
5542
- if (level === "error") throw new Error(`parseman: degraded compilation path
5543
- ${formatDegradation(d)}`);
5823
+ function adjacencyCombinator(def) {
5824
+ const meta = {
5825
+ // Zero-width and never leading (sequence() rejects index 0), so it contributes
5826
+ // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
5827
+ // rather than letting `any` poison the enclosing choice's dispatch.
5828
+ firstSet: { kind: "any" },
5829
+ canMatchNewline: false,
5830
+ isTrivia: false
5831
+ };
5832
+ return {
5833
+ _tag: "adjacency",
5834
+ _meta: meta,
5835
+ _def: def,
5836
+ parse() {
5837
+ throw adjacencyMisuse(def.polarity);
5838
+ }
5839
+ };
5840
+ }
5841
+ function adjacent() {
5842
+ return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
5843
+ }
5844
+ function notAdjacent(options) {
5845
+ const kinds = options?.kinds;
5846
+ if (kinds !== void 0) {
5847
+ if (!Array.isArray(kinds) || kinds.length === 0) {
5848
+ throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
5849
+ }
5850
+ for (const k of kinds) {
5851
+ if (typeof k !== "string" || k.length === 0) {
5852
+ throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
5853
+ }
5854
+ }
5855
+ }
5856
+ return adjacencyCombinator(
5857
+ kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
5858
+ );
5859
+ }
5860
+
5861
+ // src/combinators/sequence.ts
5862
+ function sequence(...parsers) {
5863
+ let adjacency = null;
5864
+ for (let i = 0; i < parsers.length; i++) {
5865
+ const a = adjacencyOf(parsers[i]);
5866
+ if (a === null) continue;
5867
+ if (i === 0) {
5868
+ throw new TypeError(
5869
+ `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
5870
+ );
5871
+ }
5872
+ ;
5873
+ (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
5874
+ }
5875
+ const hasAdjacency = adjacency !== null;
5876
+ let leading = null;
5877
+ for (let i = 1; i < parsers.length; i++) {
5878
+ if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
5879
+ }
5880
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
5881
+ const meta = {
5882
+ // Union through the nullable prefix — a leading optional()/many() lets a later
5883
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
5884
+ firstSet: sequenceFirstSet(parsers),
5885
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
5886
+ isTrivia: false
5887
+ };
5888
+ const def = { tag: "sequence", parsers };
5889
+ const scalarParsers = parsers.map(scalarOf);
5890
+ const parseScalar = (input, pos, ctx) => {
5891
+ let cur = pos;
5892
+ if (strictArity !== 0) {
5893
+ cur = scalarParsers[0](input, cur, ctx);
5894
+ if (cur < 0) return cur;
5895
+ const first = ctx._sv;
5896
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
5897
+ cur = scalarParsers[1](input, cur, ctx);
5898
+ if (cur < 0) return cur;
5899
+ const second = ctx._sv;
5900
+ if (strictArity === 2) {
5901
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
5902
+ return cur;
5903
+ }
5904
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
5905
+ cur = scalarParsers[2](input, cur, ctx);
5906
+ if (cur < 0) return cur;
5907
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
5908
+ return cur;
5909
+ }
5910
+ const values = def.valueUnused ? void 0 : [];
5911
+ for (let i = 0; i < scalarParsers.length; i++) {
5912
+ let termPos = cur;
5913
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
5914
+ const end = scalarParsers[i](input, termPos, ctx);
5915
+ if (end < 0) return end;
5916
+ if (values !== void 0) values.push(ctx._sv);
5917
+ if (end > termPos || termPos === cur) cur = end;
5918
+ }
5919
+ ctx._sv = values;
5920
+ return cur;
5921
+ };
5922
+ let followSentinels;
5923
+ return {
5924
+ _tag: "sequence",
5925
+ _meta: meta,
5926
+ _def: def,
5927
+ _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
5928
+ parse(input, pos, ctx) {
5929
+ const tolerant = ctx._tolerant === true;
5930
+ if (tolerant) {
5931
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
5932
+ parsers.slice(i + 1).reduce(
5933
+ (set, parser2) => union(set, firstSetOf(parser2)),
5934
+ { kind: "empty" }
5935
+ )
5936
+ ));
5937
+ }
5938
+ const inheritedSync = ctx._sync;
5939
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
5940
+ const values = def.valueUnused ? void 0 : [];
5941
+ let cur = pos;
5942
+ try {
5943
+ for (let i = 0; i < parsers.length; i++) {
5944
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
5945
+ const assertion = adjacency?.[i];
5946
+ if (assertion) {
5947
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
5948
+ if (values !== void 0) values.push(null);
5949
+ continue;
5950
+ }
5951
+ let termPos = cur;
5952
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
5953
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
5954
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
5955
+ if (ctx.trivia && i > 0) {
5956
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
5957
+ }
5958
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
5959
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
5960
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
5961
+ if (leading?.[i] === true) LEAD.at = cur;
5962
+ const result = parsers[i].parse(input, termPos, ctx);
5963
+ if (!result.ok) return result;
5964
+ if (values !== void 0) values.push(result.value);
5965
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
5966
+ else if (deferredTrivia) {
5967
+ rollbackScannedTriviaAt(
5968
+ ctx,
5969
+ markTlog,
5970
+ scanTlog,
5971
+ markLog,
5972
+ scanLog,
5973
+ markRootLog,
5974
+ scanRootLog
5975
+ );
5976
+ }
5977
+ }
5978
+ } finally {
5979
+ if (tolerant) ctx._sync = inheritedSync;
5980
+ }
5981
+ return {
5982
+ ok: true,
5983
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
5984
+ value: values ?? void 0,
5985
+ span: { start: pos, end: cur }
5986
+ };
5987
+ }
5988
+ };
5989
+ }
5990
+
5991
+ // src/compiler/degradation.ts
5992
+ function formatDegradation(d) {
5993
+ return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
5994
+ }
5995
+ var DETAIL_CAP = 8;
5996
+ function formatDegradations(list) {
5997
+ const byCode = /* @__PURE__ */ new Map();
5998
+ for (const d of list) {
5999
+ const bucket = byCode.get(d.code);
6000
+ if (bucket) bucket.push(d);
6001
+ else byCode.set(d.code, [d]);
6002
+ }
6003
+ const out = [];
6004
+ for (const [code, items] of byCode) {
6005
+ for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
6006
+ if (items.length > DETAIL_CAP) {
6007
+ out.push(
6008
+ `[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.`
6009
+ );
6010
+ }
6011
+ }
6012
+ return out;
6013
+ }
6014
+ var _sinks = [];
6015
+ function beginDegradationCapture() {
6016
+ _sinks.push(/* @__PURE__ */ new Map());
6017
+ }
6018
+ function degradationCaptureDepth() {
6019
+ return _sinks.length;
6020
+ }
6021
+ function unwindDegradationCapture(depth) {
6022
+ const found = [];
6023
+ while (_sinks.length > depth) {
6024
+ const sink = _sinks.pop();
6025
+ found.unshift(...sink.values());
6026
+ }
6027
+ return found;
6028
+ }
6029
+ function resolveDegradationLevel(explicit) {
6030
+ if (explicit !== void 0) return explicit;
6031
+ const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
6032
+ if (env === "off" || env === "warn" || env === "error") return env;
6033
+ return "warn";
6034
+ }
6035
+ function degradationKey(d) {
6036
+ return JSON.stringify([d.code, d.where, d.subject]);
6037
+ }
6038
+ function recordDegradation(d) {
6039
+ const level = resolveDegradationLevel();
6040
+ if (level === "off") return;
6041
+ const key = degradationKey(d);
6042
+ const sink = _sinks[_sinks.length - 1];
6043
+ if (sink) {
6044
+ if (!sink.has(key)) sink.set(key, d);
6045
+ return;
6046
+ }
6047
+ if (_immediate.has(key)) return;
6048
+ _immediate.add(key);
6049
+ if (level === "error") throw new Error(`parseman: degraded compilation path
6050
+ ${formatDegradation(d)}`);
5544
6051
  console.warn(formatDegradation(d));
5545
6052
  }
5546
6053
  var _immediate = /* @__PURE__ */ new Set();
@@ -5659,91 +6166,620 @@ function splitTopLevel(inner) {
5659
6166
  last = i + 1;
5660
6167
  }
5661
6168
  }
5662
- if (depth !== 0 || angle !== 0) return null;
5663
- parts.push(inner.slice(last));
5664
- return parts;
6169
+ if (depth !== 0 || angle !== 0) return null;
6170
+ parts.push(inner.slice(last));
6171
+ return parts;
6172
+ }
6173
+ function isConfirmableParam(part) {
6174
+ const head = PARAM_HEAD_RE.exec(part);
6175
+ if (!head) return false;
6176
+ const rest = part.slice(head[0].length);
6177
+ if (rest === "") return true;
6178
+ if (rest[0] !== ":") return false;
6179
+ return !hasDefaultAssign(rest.slice(1));
6180
+ }
6181
+ function hasDefaultAssign(annotation) {
6182
+ for (let i = 0; i < annotation.length; i++) {
6183
+ if (annotation[i] !== "=") continue;
6184
+ if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
6185
+ i++;
6186
+ continue;
6187
+ }
6188
+ const prev = annotation[i - 1];
6189
+ if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
6190
+ return true;
6191
+ }
6192
+ return false;
6193
+ }
6194
+ function buildAnalysisSrc(def) {
6195
+ return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
6196
+ }
6197
+ var RESOLVER_REASONS = {
6198
+ "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
6199
+ "arguments": "its body references `arguments`",
6200
+ "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
6201
+ "not-a-function": "the binding it names is not a function declaration",
6202
+ "unresolved-import": "its module could not be resolved or parsed",
6203
+ "not-found": "the name did not resolve to any binding",
6204
+ "computed": "it is a computed expression",
6205
+ "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
6206
+ "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
6207
+ };
6208
+ function unconfirmableReason(def, src) {
6209
+ const declared = def.buildArityUnresolved;
6210
+ if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
6211
+ const s = src.trim();
6212
+ const params = s.slice(0, s.indexOf(")") + 1);
6213
+ if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
6214
+ if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
6215
+ if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
6216
+ return "it names a binding this build could not resolve to a function declaration";
6217
+ }
6218
+ return "its parameter list could not be parsed";
6219
+ }
6220
+ function confirmedArityForDef(def) {
6221
+ if (def.buildArity !== void 0) return def.buildArity;
6222
+ const src = buildAnalysisSrc(def);
6223
+ const arity = confirmedBuildArity(src);
6224
+ if (arity !== null) return arity;
6225
+ const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
6226
+ recordDegradation({
6227
+ code: "build-arity-unconfirmed",
6228
+ severity: "warn",
6229
+ where: `node("${def.type ?? "<inferred>"}")`,
6230
+ subject,
6231
+ 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`,
6232
+ 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"
6233
+ });
6234
+ return null;
6235
+ }
6236
+ function buildReadsRaw(def) {
6237
+ if (!def.build) return true;
6238
+ if (def.buildRawUnused === true) return false;
6239
+ const arity = confirmedArityForDef(def);
6240
+ if (arity === null) return true;
6241
+ return arity >= 4;
6242
+ }
6243
+ function buildReadsTrivia(def) {
6244
+ if (!def.build) return true;
6245
+ const arity = confirmedArityForDef(def);
6246
+ if (arity === null) return true;
6247
+ return arity >= 5;
6248
+ }
6249
+ function buildReadsState(def) {
6250
+ if (!def.build) return true;
6251
+ const arity = confirmedArityForDef(def);
6252
+ if (arity === null) return true;
6253
+ return arity >= 6;
6254
+ }
6255
+
6256
+ // src/combinators/token.ts
6257
+ function semanticLeafValue(_ctx, _input, _start, _end, value) {
6258
+ return value;
6259
+ }
6260
+ function sourceLeafValue(ctx, input, start, end, value) {
6261
+ return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
6262
+ }
6263
+ function token(root) {
6264
+ const meta = {
6265
+ firstSet: root._meta.firstSet,
6266
+ canMatchNewline: root._meta.canMatchNewline,
6267
+ isTrivia: false
6268
+ };
6269
+ return {
6270
+ _tag: "token",
6271
+ _meta: meta,
6272
+ _def: { tag: "token", parser: root },
6273
+ parse(input, pos, ctx) {
6274
+ const savedTrivia = ctx.trivia;
6275
+ const savedKinds = ctx.triviaKindLabels;
6276
+ const savedBuf = ctx._cstBuf;
6277
+ const savedChildren = ctx._cstChildren;
6278
+ const savedLeaves = ctx._cstLeaves;
6279
+ const savedRaw = ctx._cstRawChildren;
6280
+ const savedTriviaLog = ctx._cstTriviaLog;
6281
+ const savedOuterTriviaLog = ctx._triviaLog;
6282
+ const savedRootTriviaLog = ctx._rootTriviaLog;
6283
+ const wasCapturing = cstCaptureActive(ctx);
6284
+ ctx.trivia = void 0;
6285
+ ctx.triviaKindLabels = void 0;
6286
+ ctx._cstBuf = void 0;
6287
+ ctx._cstChildren = void 0;
6288
+ ctx._cstLeaves = void 0;
6289
+ ctx._cstRawChildren = void 0;
6290
+ ctx._cstTriviaLog = void 0;
6291
+ ctx._triviaLog = void 0;
6292
+ ctx._rootTriviaLog = void 0;
6293
+ let result;
6294
+ try {
6295
+ result = root.parse(input, pos, ctx);
6296
+ } finally {
6297
+ ctx.trivia = savedTrivia;
6298
+ ctx.triviaKindLabels = savedKinds;
6299
+ ctx._cstBuf = savedBuf;
6300
+ ctx._cstChildren = savedChildren;
6301
+ ctx._cstLeaves = savedLeaves;
6302
+ ctx._cstRawChildren = savedRaw;
6303
+ ctx._cstTriviaLog = savedTriviaLog;
6304
+ ctx._triviaLog = savedOuterTriviaLog;
6305
+ ctx._rootTriviaLog = savedRootTriviaLog;
6306
+ }
6307
+ if (!result.ok) return result;
6308
+ const span = result.span;
6309
+ const value = input.slice(pos, span.end);
6310
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
6311
+ return { ok: true, value, span };
6312
+ }
6313
+ };
6314
+ }
6315
+ function makeLeaf(root, fn, sourceCstValue) {
6316
+ const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
6317
+ const meta = {
6318
+ firstSet: root._meta.firstSet,
6319
+ canMatchNewline: root._meta.canMatchNewline,
6320
+ isTrivia: false
6321
+ };
6322
+ return {
6323
+ _tag: "leaf",
6324
+ _meta: meta,
6325
+ _def: {
6326
+ tag: "leaf",
6327
+ parser: root,
6328
+ fn,
6329
+ ...sourceCstValue ? { cstValue: "source" } : {}
6330
+ },
6331
+ parse(input, pos, ctx) {
6332
+ const savedBuf = ctx._cstBuf;
6333
+ const savedChildren = ctx._cstChildren;
6334
+ const savedLeaves = ctx._cstLeaves;
6335
+ const savedRaw = ctx._cstRawChildren;
6336
+ const savedTriviaLog = ctx._cstTriviaLog;
6337
+ const savedOuterTriviaLog = ctx._triviaLog;
6338
+ const wasCapturing = cstCaptureActive(ctx);
6339
+ ctx._cstBuf = void 0;
6340
+ ctx._cstChildren = void 0;
6341
+ ctx._cstLeaves = void 0;
6342
+ ctx._cstRawChildren = void 0;
6343
+ ctx._cstTriviaLog = void 0;
6344
+ ctx._triviaLog = void 0;
6345
+ let result;
6346
+ try {
6347
+ result = root.parse(input, pos, ctx);
6348
+ } finally {
6349
+ ctx._cstBuf = savedBuf;
6350
+ ctx._cstChildren = savedChildren;
6351
+ ctx._cstLeaves = savedLeaves;
6352
+ ctx._cstRawChildren = savedRaw;
6353
+ ctx._cstTriviaLog = savedTriviaLog;
6354
+ ctx._triviaLog = savedOuterTriviaLog;
6355
+ }
6356
+ if (!result.ok) return result;
6357
+ const value = fn(result.value, result.span);
6358
+ if (wasCapturing) pushCstLeaf(ctx, {
6359
+ _tag: "leaf",
6360
+ value: cstValue(ctx, input, pos, result.span.end, value),
6361
+ span: result.span
6362
+ });
6363
+ return { ok: true, value, span: result.span };
6364
+ }
6365
+ };
6366
+ }
6367
+ function leaf(root, fn) {
6368
+ return makeLeaf(root, fn, false);
6369
+ }
6370
+ function sourceLeaf(root, fn) {
6371
+ return makeLeaf(root, fn, true);
6372
+ }
6373
+
6374
+ // src/compiler/value-usage.ts
6375
+ function markUnusedValues(root) {
6376
+ const seenConsumed = /* @__PURE__ */ new WeakSet();
6377
+ const seenUnconsumed = /* @__PURE__ */ new WeakSet();
6378
+ const mark = (def, consumed) => {
6379
+ if (consumed) def.valueUnused = false;
6380
+ else if (def.valueUnused !== false) def.valueUnused = true;
6381
+ };
6382
+ const visit = (c, consumed) => {
6383
+ const seen = consumed ? seenConsumed : seenUnconsumed;
6384
+ if (seen.has(c)) return;
6385
+ seen.add(c);
6386
+ const def = c._def;
6387
+ switch (def.tag) {
6388
+ case "many":
6389
+ case "oneOrMore":
6390
+ mark(def, consumed);
6391
+ visit(def.parser, consumed);
6392
+ return;
6393
+ case "optional":
6394
+ visit(def.parser, consumed);
6395
+ return;
6396
+ case "sequence":
6397
+ mark(def, consumed);
6398
+ for (const p of def.parsers) visit(p, consumed);
6399
+ return;
6400
+ case "choice":
6401
+ for (const p of def.parsers) visit(p, consumed);
6402
+ return;
6403
+ case "dispatch":
6404
+ visit(def.selector, consumed);
6405
+ for (const entry of def.cases) visit(entry.parser, consumed);
6406
+ if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
6407
+ if (def.otherwise) visit(def.otherwise, consumed);
6408
+ return;
6409
+ case "node":
6410
+ visit(def.parser, false);
6411
+ return;
6412
+ case "transform":
6413
+ visit(def.parser, true);
6414
+ return;
6415
+ case "field":
6416
+ visit(def.parser, true);
6417
+ return;
6418
+ case "sepBy":
6419
+ visit(def.parser, true);
6420
+ visit(def.separator, false);
6421
+ return;
6422
+ case "not":
6423
+ case "peek":
6424
+ visit(def.parser, false);
6425
+ return;
6426
+ case "grammar":
6427
+ visit(def.parser, consumed);
6428
+ if (def.triviaParser) visit(def.triviaParser, false);
6429
+ return;
6430
+ case "recover":
6431
+ visit(def.parser, consumed);
6432
+ visit(def.sentinel, false);
6433
+ return;
6434
+ case "token":
6435
+ visit(def.parser, false);
6436
+ return;
6437
+ case "label":
6438
+ case "trivia":
6439
+ case "attempt":
6440
+ case "withCtx":
6441
+ case "expect":
6442
+ visit(def.parser, consumed);
6443
+ return;
6444
+ case "leaf":
6445
+ visit(def.parser, true);
6446
+ return;
6447
+ case "lazy":
6448
+ return;
6449
+ default:
6450
+ return;
6451
+ }
6452
+ };
6453
+ const resolveRoot = (c) => {
6454
+ const guard = /* @__PURE__ */ new Set();
6455
+ let cur = c;
6456
+ while (!guard.has(cur)) {
6457
+ const d = cur._def;
6458
+ if (d.tag === "grammar") {
6459
+ guard.add(cur);
6460
+ cur = d.parser;
6461
+ continue;
6462
+ }
6463
+ if (d.tag !== "lazy") return cur;
6464
+ guard.add(cur);
6465
+ try {
6466
+ cur = d.thunk();
6467
+ } catch {
6468
+ return c;
6469
+ }
6470
+ }
6471
+ return cur;
6472
+ };
6473
+ visit(resolveRoot(root), true);
6474
+ }
6475
+
6476
+ // src/cst/root-trivia-scope.ts
6477
+ var ROOT_TRIVIA_SCOPE_REFUSAL = "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.";
6478
+ function refuseUnclassifiedRootScope(strict) {
6479
+ if (strict === true) throw new TypeError(ROOT_TRIVIA_SCOPE_REFUSAL);
6480
+ }
6481
+
6482
+ // src/combinators/grammar.ts
6483
+ function annotateResultLines(result, index) {
6484
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
6485
+ const errors = annotated.errors;
6486
+ if (errors) {
6487
+ ;
6488
+ annotated.errors = errors.map((error) => ({
6489
+ ...error,
6490
+ span: annotateSpan(error.span, index)
6491
+ }));
6492
+ }
6493
+ return annotated;
6494
+ }
6495
+ function createParseLineContext(input, pos) {
6496
+ const lineIndex = createLineIndex();
6497
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
6498
+ return { lineIndex, lineScannedTo: pos };
6499
+ }
6500
+ var TRACK_LINES_ON = () => true;
6501
+ var TRACK_LINES_OFF = () => false;
6502
+ var TRACK_LINES_INHERIT = (ctx) => ctx?.trackLines === true;
6503
+ function parser(opts, root) {
6504
+ const clearTrivia = opts.trivia === null;
6505
+ const opaqueRootCapture = opts.rootCapture === "opaque";
6506
+ if (opaqueRootCapture && opts.trivia === void 0) {
6507
+ throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
6508
+ }
6509
+ const scopeTrivia = clearTrivia ? void 0 : opts.trivia ?? void 0;
6510
+ const scopeLabels = scopeTrivia?._meta?.triviaKindLabels;
6511
+ const refuseUnclassified = scopeTrivia !== void 0 && !scopeTrivia._meta?.rootTriviaClassified && !opaqueRootCapture;
6512
+ const forceCaptureTrivia = opts.captureTrivia === true;
6513
+ const trackLinesPolicy = opts.trackLines === true ? "on" : opts.trackLines === false ? "off" : "inherit";
6514
+ const trackLinesOf = trackLinesPolicy === "on" ? TRACK_LINES_ON : trackLinesPolicy === "off" ? TRACK_LINES_OFF : TRACK_LINES_INHERIT;
6515
+ const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
6516
+ const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
6517
+ const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
6518
+ const rootScalar = scalarOf(root);
6519
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
6520
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
6521
+ const savedTrivia = ctx.trivia;
6522
+ const savedLabels = ctx.triviaKindLabels;
6523
+ if (clearTrivia) {
6524
+ ctx.trivia = void 0;
6525
+ ctx.triviaKindLabels = void 0;
6526
+ } else if (scopeTrivia !== void 0) {
6527
+ ctx.trivia = scopeTrivia;
6528
+ ctx.triviaKindLabels = scopeLabels;
6529
+ }
6530
+ const end = rootScalar(input, pos, ctx);
6531
+ ctx.trivia = savedTrivia;
6532
+ ctx.triviaKindLabels = savedLabels;
6533
+ return end;
6534
+ } : void 0;
6535
+ let publicScalar;
6536
+ const grammar = {
6537
+ _tag: "grammar",
6538
+ _meta: {
6539
+ ...root._meta,
6540
+ // Trivia classification describes this grammar's own active trivia
6541
+ // scope. A directly nested grammar may have classified trivia of its
6542
+ // own, but that must not advertise classification for this wrapper.
6543
+ triviaKindLabels: void 0,
6544
+ rootTriviaClassified: void 0,
6545
+ ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
6546
+ ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
6547
+ },
6548
+ _def: {
6549
+ tag: "grammar",
6550
+ parser: root,
6551
+ triviaParser: scopeTrivia,
6552
+ clearTrivia,
6553
+ ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
6554
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
6555
+ trackLines: opts.trackLines ?? false,
6556
+ constructionTrackLines: trackLinesPolicy,
6557
+ ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
6558
+ },
6559
+ _parseScalar: parseScalar,
6560
+ parse(input, pos, _ctx) {
6561
+ if (pos === void 0 && _ctx === void 0) {
6562
+ publicScalar ??= scalarRootOf(grammar) ?? null;
6563
+ if (publicScalar) {
6564
+ const ctx2 = createParseContext();
6565
+ const end = publicScalar(input, 0, ctx2);
6566
+ if (end < 0) {
6567
+ const at = ~end;
6568
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
6569
+ }
6570
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
6571
+ }
6572
+ }
6573
+ if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
6574
+ const trackLines = trackLinesOf(_ctx);
6575
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
6576
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
6577
+ const ctx = _ctx === void 0 ? createParseContext() : { ..._ctx };
6578
+ ctx.trackLines = trackLines;
6579
+ if (lineIndex) ctx._lineIndex = lineIndex;
6580
+ if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
6581
+ if (clearTrivia) {
6582
+ ctx.trivia = void 0;
6583
+ ctx.triviaKindLabels = void 0;
6584
+ } else if (scopeTrivia !== void 0) {
6585
+ ctx.trivia = scopeTrivia;
6586
+ if (scopeLabels) ctx.triviaKindLabels = scopeLabels;
6587
+ }
6588
+ if (forceCaptureTrivia || _ctx?.captureTrivia) ctx.captureTrivia = true;
6589
+ if (ownCaptureMask !== void 0) ctx._triviaCaptureMask = ownCaptureMask;
6590
+ else if (inheritCaptureMask) ctx._triviaCaptureMask = triviaKindMask(_ctx?.triviaKindLabels, captureKinds);
6591
+ if (opaqueRootCapture) ctx._rootTriviaCapture = false;
6592
+ const result = root.parse(input, pos ?? 0, ctx);
6593
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
6594
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
6595
+ }
6596
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
6597
+ }
6598
+ };
6599
+ return grammar;
6600
+ }
6601
+ function noTrivia(root) {
6602
+ return parser({ trivia: null }, root);
6603
+ }
6604
+ var _analyzed = /* @__PURE__ */ new WeakSet();
6605
+ function parse(combinator, input, opts = {}) {
6606
+ if (!_analyzed.has(combinator)) {
6607
+ _analyzed.add(combinator);
6608
+ markUnusedValues(combinator);
6609
+ }
6610
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
6611
+ return combinator.parse(input);
6612
+ }
6613
+ const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
6614
+ const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
6615
+ const lineIndex = lineContext?.lineIndex;
6616
+ const _errors = opts.recover ? [] : void 0;
6617
+ const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
6618
+ const grammarTrivia = combinator._meta.grammarTrivia;
6619
+ const grammarScanSkip = combinator._meta.grammarScanSkip;
6620
+ const ctx = createParseContext();
6621
+ ctx.trackLines = trackLines;
6622
+ if (lineIndex) ctx._lineIndex = lineIndex;
6623
+ if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
6624
+ if (grammarTrivia !== void 0) {
6625
+ ctx.trivia = grammarTrivia;
6626
+ if (grammarTrivia._meta.triviaKindLabels) ctx.triviaKindLabels = grammarTrivia._meta.triviaKindLabels;
6627
+ }
6628
+ if (grammarScanSkip !== void 0) ctx.scanSkip = grammarScanSkip;
6629
+ if (_errors !== void 0) ctx._errors = _errors;
6630
+ if (_probe !== void 0) ctx._probe = _probe;
6631
+ const result = combinator.parse(input, 0, ctx);
6632
+ if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
6633
+ const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
6634
+ return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
5665
6635
  }
5666
- function isConfirmableParam(part) {
5667
- const head = PARAM_HEAD_RE.exec(part);
5668
- if (!head) return false;
5669
- const rest = part.slice(head[0].length);
5670
- if (rest === "") return true;
5671
- if (rest[0] !== ":") return false;
5672
- return !hasDefaultAssign(rest.slice(1));
6636
+
6637
+ // src/combinators/attempt.ts
6638
+ function containOption(options) {
6639
+ if (options === void 0) return false;
6640
+ for (const key of Object.keys(options)) {
6641
+ if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
6642
+ }
6643
+ if (options.contain !== void 0 && typeof options.contain !== "boolean") {
6644
+ throw new TypeError("attempt(): `contain` must be a boolean");
6645
+ }
6646
+ return options.contain === true;
5673
6647
  }
5674
- function hasDefaultAssign(annotation) {
5675
- for (let i = 0; i < annotation.length; i++) {
5676
- if (annotation[i] !== "=") continue;
5677
- if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5678
- i++;
5679
- continue;
6648
+ function attempt(parser2, options) {
6649
+ const contain = containOption(options);
6650
+ const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
6651
+ let failExpected;
6652
+ return {
6653
+ _tag: "attempt",
6654
+ _meta: parser2._meta,
6655
+ _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
6656
+ parse(input, pos, ctx) {
6657
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
6658
+ if (failExpected === void 0) {
6659
+ const e = deriveExpected(parser2);
6660
+ failExpected = e.length > 0 ? e : [parser2._tag];
6661
+ }
6662
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
6663
+ }
6664
+ const mark = saveCstMark(ctx);
6665
+ const log = ctx._triviaLog?.length;
6666
+ const rootLog = ctx._rootTriviaLog?.length;
6667
+ const split = ctx._columnsSplit;
6668
+ const result = parser2.parse(input, pos, ctx);
6669
+ if (result.ok) return result;
6670
+ rollbackCstCapture(ctx, mark);
6671
+ ctx._columnsSplit = split;
6672
+ if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
6673
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
6674
+ if (result.committed && !contain) return result;
6675
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
5680
6676
  }
5681
- const prev = annotation[i - 1];
5682
- if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5683
- return true;
6677
+ };
6678
+ }
6679
+
6680
+ // src/table/factor-choice.ts
6681
+ var DERIVED = /* @__PURE__ */ new Set(["_tag", "_meta", "_def", "_parseScalar", "_stickyRegex", "parse"]);
6682
+ function isCombinator(v) {
6683
+ return typeof v === "object" && v !== null && "_def" in v && "_meta" in v;
6684
+ }
6685
+ function sameComb(a, b, depth) {
6686
+ if (a === b) return true;
6687
+ if (depth > 32 || a._tag !== b._tag) return false;
6688
+ for (const k of Object.keys(a)) if (!DERIVED.has(k)) return false;
6689
+ for (const k of Object.keys(b)) if (!DERIVED.has(k)) return false;
6690
+ return sameFields(a._def, b._def, depth, void 0);
6691
+ }
6692
+ function sameValue(u, v, depth) {
6693
+ if (u === v) return true;
6694
+ if (isCombinator(u) && isCombinator(v)) return sameComb(u, v, depth + 1);
6695
+ if (Array.isArray(u) && Array.isArray(v)) return u.length === v.length && u.every((x, i) => sameValue(x, v[i], depth));
6696
+ if (typeof u === "object" && u !== null && typeof v === "object" && v !== null && Object.getPrototypeOf(u) === Object.prototype && Object.getPrototypeOf(v) === Object.prototype) {
6697
+ return sameFields(u, v, depth, void 0);
5684
6698
  }
5685
6699
  return false;
5686
6700
  }
5687
- function buildAnalysisSrc(def) {
5688
- return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
5689
- }
5690
- var RESOLVER_REASONS = {
5691
- "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5692
- "arguments": "its body references `arguments`",
5693
- "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5694
- "not-a-function": "the binding it names is not a function declaration",
5695
- "unresolved-import": "its module could not be resolved or parsed",
5696
- "not-found": "the name did not resolve to any binding",
5697
- "computed": "it is a computed expression",
5698
- "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5699
- "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5700
- };
5701
- function unconfirmableReason(def, src) {
5702
- const declared = def.buildArityUnresolved;
5703
- if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5704
- const s = src.trim();
5705
- const params = s.slice(0, s.indexOf(")") + 1);
5706
- if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5707
- if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5708
- if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5709
- return "it names a binding this build could not resolve to a function declaration";
6701
+ function sameFields(x, y, depth, skip) {
6702
+ const kx = Object.keys(x).filter((k) => k !== skip && x[k] !== void 0);
6703
+ const ky = Object.keys(y).filter((k) => k !== skip && y[k] !== void 0);
6704
+ if (kx.length !== ky.length) return false;
6705
+ for (const k of kx) {
6706
+ if (!(k in y)) return false;
6707
+ const u = x[k];
6708
+ const v = y[k];
6709
+ if (k === "fn" && typeof u === "function" && typeof v === "function" && u !== v) {
6710
+ if (typeof x.fnSrc !== "string" || x.fnSrc === "" || x.fnSrc !== y.fnSrc) return false;
6711
+ continue;
6712
+ }
6713
+ if (!sameValue(u, v, depth)) return false;
5710
6714
  }
5711
- return "its parameter list could not be parsed";
5712
- }
5713
- function confirmedArityForDef(def) {
5714
- if (def.buildArity !== void 0) return def.buildArity;
5715
- const src = buildAnalysisSrc(def);
5716
- const arity = confirmedBuildArity(src);
5717
- if (arity !== null) return arity;
5718
- const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5719
- recordDegradation({
5720
- code: "build-arity-unconfirmed",
5721
- severity: "warn",
5722
- where: `node("${def.type ?? "<inferred>"}")`,
5723
- subject,
5724
- 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`,
5725
- 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"
5726
- });
5727
- return null;
5728
- }
5729
- function buildReadsRaw(def) {
5730
- if (!def.build) return true;
5731
- if (def.buildRawUnused === true) return false;
5732
- const arity = confirmedArityForDef(def);
5733
- if (arity === null) return true;
5734
- return arity >= 4;
5735
- }
5736
- function buildReadsTrivia(def) {
5737
- if (!def.build) return true;
5738
- const arity = confirmedArityForDef(def);
5739
- if (arity === null) return true;
5740
- return arity >= 5;
6715
+ return true;
5741
6716
  }
5742
- function buildReadsState(def) {
5743
- if (!def.build) return true;
5744
- const arity = confirmedArityForDef(def);
5745
- if (arity === null) return true;
5746
- return arity >= 6;
6717
+ function rewrap(w, body) {
6718
+ const d = w._def;
6719
+ let out;
6720
+ if (d.tag === "leaf") {
6721
+ out = d.cstValue === "source" ? sourceLeaf(body, d.fn) : leaf(body, d.fn);
6722
+ if (d.fnSrc !== void 0) out._def.fnSrc = d.fnSrc;
6723
+ } else if (d.tag === "grammar") {
6724
+ out = d.clearTrivia === true ? noTrivia(body) : parser({ trivia: d.triviaParser ?? null }, body);
6725
+ } else return void 0;
6726
+ return sameFields(d, out._def, 0, "parser") ? out : void 0;
6727
+ }
6728
+ function unusedOf(seq) {
6729
+ return seq._def.tag === "sequence" && seq._def.valueUnused === true;
6730
+ }
6731
+ function never(c) {
6732
+ const t2 = c._def.tag;
6733
+ return t2 === "optional" || t2 === "many";
6734
+ }
6735
+ function factorSharedEnds(d) {
6736
+ const arms = d.parsers;
6737
+ if (arms.length < 2) return void 0;
6738
+ if (d.strategy.tag !== "firstMatch" && d.strategy.tag !== "sharedPrefix") return void 0;
6739
+ if (d.gates.some((g) => g !== null) || d.autoNot.some((a) => a !== null)) return void 0;
6740
+ const shapes = [];
6741
+ for (const arm of arms) {
6742
+ const wrappers = [];
6743
+ let c = arm;
6744
+ while ((c._def.tag === "leaf" || c._def.tag === "grammar") && wrappers.length < 4) {
6745
+ wrappers.push(c);
6746
+ c = c._def.parser;
6747
+ }
6748
+ if (c._def.tag !== "sequence" || c._def.parsers.length < 2) return void 0;
6749
+ shapes.push({ wrappers, terms: c._def.parsers, seq: c });
6750
+ }
6751
+ const first = shapes[0];
6752
+ const n = first.terms.length;
6753
+ for (const s of shapes) {
6754
+ if (s.wrappers.length !== first.wrappers.length || s.terms.length !== n) return void 0;
6755
+ if (unusedOf(s.seq) !== unusedOf(first.seq)) return void 0;
6756
+ for (let j = 0; j < s.wrappers.length; j++) {
6757
+ const a = first.wrappers[j]._def;
6758
+ const b = s.wrappers[j]._def;
6759
+ if (a.tag !== b.tag || !sameFields(a, b, 0, "parser")) return void 0;
6760
+ }
6761
+ }
6762
+ let at = -1;
6763
+ for (let i = 0; i < n; i++) {
6764
+ if (shapes.every((s) => sameComb(s.terms[i], first.terms[i], 0))) continue;
6765
+ if (at >= 0) return void 0;
6766
+ at = i;
6767
+ }
6768
+ if (at < 0) return void 0;
6769
+ for (let i = at + 1; i < n; i++) if (!never(first.terms[i])) return void 0;
6770
+ if (arms.some((a) => mayCommitFailure(a))) return void 0;
6771
+ const middle = choice(...shapes.map((s) => s.terms[at]));
6772
+ if (middle._def.tag === "choice" && middle._def.autoNot.some((a) => a !== null)) return void 0;
6773
+ const st = middle._def.tag === "choice" ? middle._def.strategy : void 0;
6774
+ if (st === void 0 || st.tag !== "firstMatch" && st.tag !== "sharedPrefix" && !(st.tag === "literalsLongestFirst" && st.sortedIndices.every((x, i) => x === i))) return void 0;
6775
+ let out = sequence(
6776
+ ...[...first.terms.slice(0, at), middle, ...first.terms.slice(at + 1)]
6777
+ );
6778
+ if (unusedOf(first.seq)) {
6779
+ out._def.valueUnused = true;
6780
+ }
6781
+ for (let j = first.wrappers.length - 1; j >= 0 && out !== void 0; j--) out = rewrap(first.wrappers[j], out);
6782
+ return out === void 0 ? void 0 : attempt(out);
5747
6783
  }
5748
6784
 
5749
6785
  // src/compiler/fields.ts
@@ -5860,6 +6896,7 @@ var OP_SCOPE_PLAIN = 41;
5860
6896
  var OP_LEX_BODY = 42;
5861
6897
  var OP_LEX_PROGRAM = 43;
5862
6898
  var OP_SOURCE_LEAF = 44;
6899
+ var OP_RGATE = 45;
5863
6900
  var OP_DISPATCH = 25;
5864
6901
  var OP_ROUTED = 26;
5865
6902
  var OP_NAMES = {
@@ -5879,6 +6916,7 @@ var OP_NAMES = {
5879
6916
  [OP_PEEK]: "PEEK",
5880
6917
  [OP_LEAF]: "LEAF",
5881
6918
  [OP_SOURCE_LEAF]: "SOURCE_LEAF",
6919
+ [OP_RGATE]: "RGATE",
5882
6920
  [OP_EMPTY]: "EMPTY",
5883
6921
  [OP_LIT_TRACK]: "LIT_TRACK",
5884
6922
  [OP_RX_TRACK]: "RX_TRACK",
@@ -5909,71 +6947,6 @@ var OP_NAMES = {
5909
6947
  [OP_LEX_PROGRAM]: "LEX_PROGRAM"
5910
6948
  };
5911
6949
 
5912
- // src/combinators/adjacency.ts
5913
- function adjacencyOf(p) {
5914
- return p._def.tag === "adjacency" ? p._def : null;
5915
- }
5916
- function adjacencyExpected(def) {
5917
- if (def.polarity === "adjacent") return "adjacent";
5918
- return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5919
- }
5920
- function holdsAdjacency(input, cur, ctx, def) {
5921
- return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5922
- }
5923
- function adjacencyHolds(input, cur, ctx, negated, kinds) {
5924
- const end = probeTriviaEnd(input, cur, ctx);
5925
- if (!negated) return end === cur;
5926
- if (end === cur) return false;
5927
- if (kinds === void 0) return true;
5928
- const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
5929
- const spec = analyzeLabeledTrivia(ctx.trivia);
5930
- return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
5931
- }
5932
- function adjacencyFail(pos, def) {
5933
- return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5934
- }
5935
- 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.";
5936
- function adjacencyMisuse(polarity) {
5937
- return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
5938
- }
5939
- function adjacencyCombinator(def) {
5940
- const meta = {
5941
- // Zero-width and never leading (sequence() rejects index 0), so it contributes
5942
- // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
5943
- // rather than letting `any` poison the enclosing choice's dispatch.
5944
- firstSet: { kind: "any" },
5945
- canMatchNewline: false,
5946
- isTrivia: false
5947
- };
5948
- return {
5949
- _tag: "adjacency",
5950
- _meta: meta,
5951
- _def: def,
5952
- parse() {
5953
- throw adjacencyMisuse(def.polarity);
5954
- }
5955
- };
5956
- }
5957
- function adjacent() {
5958
- return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
5959
- }
5960
- function notAdjacent(options) {
5961
- const kinds = options?.kinds;
5962
- if (kinds !== void 0) {
5963
- if (!Array.isArray(kinds) || kinds.length === 0) {
5964
- throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
5965
- }
5966
- for (const k of kinds) {
5967
- if (typeof k !== "string" || k.length === 0) {
5968
- throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
5969
- }
5970
- }
5971
- }
5972
- return adjacencyCombinator(
5973
- kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
5974
- );
5975
- }
5976
-
5977
6950
  // src/combinators/node.ts
5978
6951
  function unwrapChild(child) {
5979
6952
  return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
@@ -6035,7 +7008,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
6035
7008
  }
6036
7009
  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;
6037
7010
  const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
6038
- const clonesState = build ? buildReadsState(def) : project === void 0;
7011
+ const readsState = build ? buildReadsState(def) : project === void 0;
6039
7012
  const hasOwnFields = parserHasOwnFields(combinator);
6040
7013
  const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
6041
7014
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
@@ -6076,12 +7049,11 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
6076
7049
  ctx._triviaCaptureMask = savedMask;
6077
7050
  const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
6078
7051
  if (!r.ok) return r;
6079
- const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
7052
+ const st = readsState ? ctx.state : void 0;
6080
7053
  const nodeType = def.type ?? missingInferredType();
6081
7054
  const cstOutput = cstOutputHost(ctx.build);
6082
7055
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
6083
- const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
6084
- 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 };
7056
+ 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 };
6085
7057
  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 };
6086
7058
  if (saved.buf !== void 0 || saved.ch !== void 0) {
6087
7059
  pushCstChild(ctx, built, rawEntry2);
@@ -6091,42 +7063,6 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
6091
7063
  };
6092
7064
  }
6093
7065
 
6094
- // src/combinators/trivia-boundary.ts
6095
- var MAX_DEPTH = 12;
6096
- function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
6097
- if (depth === 0) return true;
6098
- const d = p._def;
6099
- switch (d.tag) {
6100
- // Multi-term forms: the gaps BETWEEN terms are the ambient-trivia positions.
6101
- case "sequence":
6102
- return d.parsers.length > 1;
6103
- case "many":
6104
- case "oneOrMore":
6105
- case "sepBy":
6106
- return true;
6107
- // Transparent wrappers — they add no position, so ask what they wrap.
6108
- case "node":
6109
- case "transform":
6110
- case "leaf":
6111
- case "label":
6112
- case "field":
6113
- case "token":
6114
- case "attempt":
6115
- case "optional":
6116
- case "expect":
6117
- case "withCtx":
6118
- case "recover":
6119
- case "trivia":
6120
- return hasOwnTriviaBoundary(d.parser, depth - 1);
6121
- // An alternation adds no position either, but ONE arm that has one is enough
6122
- // to make the scope meaningful for this rule.
6123
- case "choice":
6124
- return d.parsers.some((a) => hasOwnTriviaBoundary(a, depth - 1));
6125
- default:
6126
- return false;
6127
- }
6128
- }
6129
-
6130
7066
  // src/compiler/direct-projection.ts
6131
7067
  function directArrayProjection(fn, fnSrc, arity) {
6132
7068
  let source = fnSrc;
@@ -6347,13 +7283,16 @@ var Encoder = class {
6347
7283
  }
6348
7284
  case "choice": {
6349
7285
  for (const arm of node2.arms) if (!emitNode(arm)) return false;
6350
- const op = node2.arms.length === 2 ? LEX_NODE_CHOICE2 : node2.arms.length === 4 ? LEX_NODE_CHOICE4 : node2.arms.length === 8 ? LEX_NODE_CHOICE8 : -1;
6351
- if (op < 0) return false;
6352
- words.push(op, this.expected(node2.expected));
7286
+ const final = classifyFinalChoice(
7287
+ node2.parsers,
7288
+ this.refResolver(),
7289
+ node2.cleared ? void 0 : this.activeTrivia
7290
+ );
7291
+ const classes = final.firstSets.map((first, i) => final.nullable[i] ? -1 : this.charClass(first));
7292
+ const exclusive = final.exclusive && classes.every((cls) => cls >= 0);
7293
+ words.push(LEX_NODE_CHOICE, node2.arms.length, exclusive ? 1 : 0, this.expected(node2.expected));
6353
7294
  for (let i = 0; i < node2.arms.length; i++) {
6354
- const first = node2.firstSets[i];
6355
- words.push(first.kind === "ranges" ? this.charClass(first) : -1);
6356
- words.push(this.expected(node2.armExpected[i]));
7295
+ words.push(classes[i], this.expected(node2.armExpected[i]));
6357
7296
  }
6358
7297
  return true;
6359
7298
  }
@@ -6365,6 +7304,10 @@ var Encoder = class {
6365
7304
  if (!emitNode(node2.body)) return false;
6366
7305
  words.push(LEX_NODE_OPTIONAL);
6367
7306
  return true;
7307
+ case "repeat":
7308
+ if (!emitNode(node2.body)) return false;
7309
+ words.push(LEX_NODE_REPEAT, node2.min, node2.max);
7310
+ return true;
6368
7311
  }
6369
7312
  };
6370
7313
  if (!emitNode(body.root)) return void 0;
@@ -6692,6 +7635,33 @@ var Encoder = class {
6692
7635
  return childrenOf(def);
6693
7636
  }
6694
7637
  }
7638
+ /**
7639
+ * THE FIRST-CHARACTER GATE OF AN `optional`, `not` OR `peek` CHILD.
7640
+ *
7641
+ * A non-nullable child cannot match at a character outside its first set, so
7642
+ * the wrapper's outcome there is already decided: `optional` yields `null`,
7643
+ * `not` succeeds, `peek` fails with its own set. The interpreter's `optional`
7644
+ * makes that test itself (`repeat.ts` `startsFirstSet`); the table entered the
7645
+ * child — a rollback mark, the call, the child's own failure — to learn it.
7646
+ *
7647
+ * The gate is an `OP_GATE` row around the child, so every engine runs it
7648
+ * unchanged, a probe or tolerant parse forwards through it as for a node's
7649
+ * gate, and the wrapper's row keeps its layout. The engines test the class
7650
+ * before taking the wrapper's mark. The first set is resolved through
7651
+ * `winners`, the analysis a choice arm's gate uses, so a composed rule's set
7652
+ * is the merged one. A scalar `not` child stays bare: `scalarTerminalNotChild`
7653
+ * already reduces it to one recognizer call.
7654
+ */
7655
+ lookaheadGate(p, child) {
7656
+ const op = this.code[child];
7657
+ 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;
7658
+ const rr = this.refResolver();
7659
+ if (matchesEmpty(p, /* @__PURE__ */ new Set(), rr)) return child;
7660
+ const cls = this.charClass(firstSetOf(p, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7661
+ if (cls < 0) return child;
7662
+ const e = deriveExpected(p);
7663
+ return this.emit(OP_GATE, cls, child, this.expected(e.length > 0 ? e : [p._tag]));
7664
+ }
6695
7665
  /** A first set becomes a char class string, or −1 for `any`. */
6696
7666
  charClass(fs) {
6697
7667
  if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
@@ -6703,12 +7673,19 @@ var Encoder = class {
6703
7673
  this.ccIndex.set(spec, i);
6704
7674
  return i;
6705
7675
  }
6706
- /** Bind a guard only when its class is already part of the program. Repeat
6707
- * gating must not grow the compact artifact merely to avoid a failed call. */
6708
- existingCharClass(fs) {
6709
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
6710
- const hit = this.ccIndex.get(encodeClassSpec(fs.ranges));
6711
- return hit !== void 0 && hit < 100 ? hit : -1;
7676
+ /**
7677
+ * The first set a node's or an attempt's fail-fast gate tests. A bare
7678
+ * cross-rule ref resolves through `winners` (a compose OVERRIDE may widen
7679
+ * it). Any other body keeps its construction-time `_meta.firstSet`, except
7680
+ * where that is `any`: under `compose()` a body that reaches a rule of
7681
+ * another piece is built before that rule exists, so its cached set is
7682
+ * `any` and the node got NO gate (jess's `CompoundSelector` was entered at
7683
+ * `{`, `Call` at `}`). The resolved set is the one a choice arm's gate uses,
7684
+ * over the final merged map.
7685
+ */
7686
+ gateFirstSet(p) {
7687
+ const cached = p._meta.firstSet;
7688
+ return p._def.tag === "lazy" || cached.kind === "any" ? firstSetOf(p, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : cached;
6712
7689
  }
6713
7690
  /**
6714
7691
  * Wrap one choice arm in its `autoNot` checks (`OP_REJECT`).
@@ -6836,6 +7813,50 @@ var Encoder = class {
6836
7813
  if (!hasOwnTriviaBoundary(target)) return ip;
6837
7814
  return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
6838
7815
  }
7816
+ /**
7817
+ * The `OP_RGATE` operands of a choice arm that opens with `routed()`, or
7818
+ * `undefined`. Through `node()`/scope wrappers and first sequence terms, the
7819
+ * arm's next term after the routed token is found; the gate is that term's
7820
+ * first characters, with the trivia in force at the boundary before it, so
7821
+ * the arm is entered only where it can get past the token. The term must be
7822
+ * unable to match empty or to commit, so a miss is exactly that term failing
7823
+ * at the token's end with its own set.
7824
+ */
7825
+ routedArmGate(arm) {
7826
+ const walk = (p, trivia2, depth) => {
7827
+ if (depth > 16) return void 0;
7828
+ const d = p._def;
7829
+ switch (d.tag) {
7830
+ case "routed":
7831
+ return "end";
7832
+ case "node":
7833
+ return walk(d.parser, trivia2, depth + 1);
7834
+ case "grammar":
7835
+ return walk(d.parser, d.clearTrivia === true ? void 0 : d.triviaParser ?? trivia2, depth + 1);
7836
+ case "sequence": {
7837
+ const head = d.parsers[0];
7838
+ if (head === void 0) return void 0;
7839
+ const r = walk(head, trivia2, depth + 1);
7840
+ if (r !== "end") return r;
7841
+ const next2 = d.parsers[1];
7842
+ return next2 === void 0 ? "end" : { next: next2, boundary: trivia2 };
7843
+ }
7844
+ default:
7845
+ return void 0;
7846
+ }
7847
+ };
7848
+ const follow = walk(arm, this.activeTrivia, 0);
7849
+ if (follow === void 0 || follow === "end") return void 0;
7850
+ const rr = this.refResolver();
7851
+ const { next, boundary } = follow;
7852
+ if (matchesEmpty(next, /* @__PURE__ */ new Set(), rr) || mayCommitFailure(next, rr, this.commitFailureMemo)) return void 0;
7853
+ const nextTag = next._def.tag;
7854
+ if (nextTag !== "literal" && nextTag !== "regex" && nextTag !== "keywords" && nextTag !== "label") return void 0;
7855
+ const first = firstSetOf(next, /* @__PURE__ */ new Set(), rr, boundary);
7856
+ const cls = this.charClass(boundary === void 0 ? first : union(first, firstSetOf(boundary, /* @__PURE__ */ new Set(), rr)));
7857
+ if (cls < 0) return void 0;
7858
+ return { cls, fx: this.expected(deriveExpected(next)) };
7859
+ }
6839
7860
  node(p) {
6840
7861
  const lazyRef = p._def.tag === "lazy";
6841
7862
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -6960,6 +7981,10 @@ var Encoder = class {
6960
7981
  return head;
6961
7982
  }
6962
7983
  case "choice": {
7984
+ if (this.plan === void 0) {
7985
+ const factored = factorSharedEnds(d);
7986
+ if (factored !== void 0) return this.node(factored).ip;
7987
+ }
6963
7988
  if (d.strategy.tag === "greedyClassify") {
6964
7989
  const superIndex = d.strategy.superIndex;
6965
7990
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -6983,9 +8008,12 @@ var Encoder = class {
6983
8008
  const kids = arms.map((c, k) => {
6984
8009
  const src = order[k];
6985
8010
  const checks = d.autoNot[src];
6986
- const inner = this.node(c).ip;
6987
- const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
6988
8011
  const gate = d.gates[src];
8012
+ const plain2 = (checks === null || checks === void 0 || checks.length === 0) && (gate === null || gate === void 0);
8013
+ const routedGate = plain2 ? this.routedArmGate(c) : void 0;
8014
+ const body = this.node(c).ip;
8015
+ const inner = routedGate === void 0 ? body : this.emit(OP_RGATE, routedGate.cls, body, routedGate.fx);
8016
+ const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
6989
8017
  const gated = gate === null || gate === void 0 ? ip : this.emit(OP_ARMGATE, this.fn(gate, d.gateSrcs?.[src] ?? null), ip, this.expected(deriveExpected(c)));
6990
8018
  return this.covWrap(gated, armCovIds?.[src], 1);
6991
8019
  });
@@ -7013,6 +8041,12 @@ var Encoder = class {
7013
8041
  if (transactionalFirst[i] !== void 0) classes[i] = -1;
7014
8042
  }
7015
8043
  }
8044
+ if (d.gates.some((g) => g !== null && g !== void 0) && !dispatchIsExclusive(classes, this.cc)) {
8045
+ for (let k = 0; k < classes.length; k++) {
8046
+ const gate = d.gates[order[k]];
8047
+ if (gate !== null && gate !== void 0) classes[k] = -1;
8048
+ }
8049
+ }
7016
8050
  const dispIdx = this.disp.length;
7017
8051
  this.disp.push(classes);
7018
8052
  let rollbackMask = kids.length > 31 ? -1 : 0;
@@ -7042,7 +8076,7 @@ var Encoder = class {
7042
8076
  case "oneOrMore": {
7043
8077
  const child = this.node(d.parser).ip;
7044
8078
  const rr = this.refResolver();
7045
- const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.existingCharClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
8079
+ const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.charClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7046
8080
  const op = d.valueUnused ? OP_REPV : OP_REP;
7047
8081
  const min = d.tag === "many" ? 0 : d.min;
7048
8082
  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);
@@ -7066,7 +8100,7 @@ var Encoder = class {
7066
8100
  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);
7067
8101
  }
7068
8102
  case "optional": {
7069
- const head = this.emit(OP_OPT, this.node(d.parser).ip);
8103
+ const head = this.emit(OP_OPT, this.lookaheadGate(d.parser, this.node(d.parser).ip));
7070
8104
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(head);
7071
8105
  return head;
7072
8106
  }
@@ -7114,8 +8148,8 @@ var Encoder = class {
7114
8148
  // every CST node, so this is load-bearing, not reflection trivia.
7115
8149
  d.tags === void 0 ? -1 : this.constant(d.tags)
7116
8150
  );
7117
- if (matchesEmpty(d.parser)) return body;
7118
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
8151
+ if (matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return body;
8152
+ const fs = this.gateFirstSet(d.parser);
7119
8153
  if (fs.kind === "any") return body;
7120
8154
  const cls = this.charClass(fs);
7121
8155
  if (cls < 0) return body;
@@ -7207,7 +8241,7 @@ var Encoder = class {
7207
8241
  // other engine reported `['not(literal)']`. It hid because `expected` is a
7208
8242
  // TOP-LEVEL field on `RunResult` and is NOT part of the identity digest.
7209
8243
  case "not":
7210
- return this.emit(OP_NOT, this.node(d.parser).ip, this.expected(assertionFailureExpected(false, d.parser._tag)));
8244
+ return this.emit(OP_NOT, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(false, d.parser._tag)));
7211
8245
  case "guard":
7212
8246
  return this.emit(OP_GUARD, this.fn(d.predicate, d.predSrc ?? null), this.expected(["gate"]));
7213
8247
  case "adjacency":
@@ -7228,14 +8262,14 @@ var Encoder = class {
7228
8262
  return this.emit(OP_WITHCTX, this.constant(d.extra), this.node(d.parser).ip);
7229
8263
  }
7230
8264
  case "peek":
7231
- return this.emit(OP_PEEK, this.node(d.parser).ip, this.expected(assertionFailureExpected(true, d.parser._tag)));
8265
+ return this.emit(OP_PEEK, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(true, d.parser._tag)));
7232
8266
  // A TRANSACTION IS A ROW. See `OP_ATTEMPT` for why the transparent
7233
8267
  // lowering was correct only for a choice arm.
7234
8268
  case "attempt": {
7235
8269
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip, d.contain === true ? 1 : 0);
7236
8270
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7237
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
7238
- if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
8271
+ const fs = this.gateFirstSet(d.parser);
8272
+ if (fs.kind === "any" || matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return inner;
7239
8273
  const cls = this.charClass(fs);
7240
8274
  if (cls < 0) return inner;
7241
8275
  const e = deriveExpected(d.parser);
@@ -7303,6 +8337,7 @@ var Encoder = class {
7303
8337
  const slots = (ip) => {
7304
8338
  switch (this.code[ip]) {
7305
8339
  case OP_GATE:
8340
+ case OP_RGATE:
7306
8341
  return [ip + 2];
7307
8342
  case OP_RULE:
7308
8343
  case OP_OPT:
@@ -8530,6 +9565,7 @@ function childSlots(code, ip, out) {
8530
9565
  case OP_LEAF:
8531
9566
  case OP_SOURCE_LEAF:
8532
9567
  case OP_ARMGATE:
9568
+ case OP_RGATE:
8533
9569
  out.push(code[ip + 2]);
8534
9570
  return true;
8535
9571
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -8613,6 +9649,42 @@ function reachableSites(code, roots) {
8613
9649
  }
8614
9650
  return seen;
8615
9651
  }
9652
+ function passCollapse(code, ip, hostCst) {
9653
+ const flags = code[ip + 3];
9654
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
9655
+ if (flags !== 32 && flags !== 34) return false;
9656
+ let at = code[ip + 2];
9657
+ for (let n = 0; n < 8; n++) {
9658
+ const op = code[at];
9659
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
9660
+ else if (op === OP_RULE) at = code[at + 1];
9661
+ else break;
9662
+ }
9663
+ return code[at] === OP_NODE;
9664
+ }
9665
+ function gatedPassCollapse(code, ip, hostCst) {
9666
+ const flags = code[ip + 3];
9667
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
9668
+ if (flags !== 32 && flags !== 34) return void 0;
9669
+ const seq = code[ip + 2];
9670
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
9671
+ const n = code[seq + 1];
9672
+ if (n < 2) return void 0;
9673
+ const leads = [];
9674
+ const lits = [];
9675
+ for (let i = 0; i < n - 1; i++) {
9676
+ const t2 = code[seq + 2 + i];
9677
+ if (code[t2] !== OP_OPT && code[t2] !== OP_NOT) return void 0;
9678
+ const g = code[t2 + 1];
9679
+ if (code[g] === OP_GATE) leads.push(g);
9680
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
9681
+ else return void 0;
9682
+ }
9683
+ const last = code[seq + 2 + n - 1];
9684
+ let at = last;
9685
+ 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];
9686
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
9687
+ }
8616
9688
  function transfer(code, ip, at, hostCst) {
8617
9689
  const op = code[ip];
8618
9690
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -8624,14 +9696,18 @@ function transfer(code, ip, at, hostCst) {
8624
9696
  }
8625
9697
  if (op === OP_NODE || op === OP_NODE_TRACK) {
8626
9698
  const flags = code[ip + 3];
9699
+ if (passCollapse(code, ip, hostCst)) return at;
9700
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
8627
9701
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
8628
9702
  if (directChildren) {
8629
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9703
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9704
+ return gated ? meet(at, framed2) : framed2;
8630
9705
  }
8631
9706
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
8632
9707
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
8633
9708
  if (at.buf && raw === at.raw && cap === at.cap) return at;
8634
- return { tri: at.tri, buf: true, raw, cap };
9709
+ const framed = { tri: at.tri, buf: true, raw, cap };
9710
+ return gated ? meet(at, framed) : framed;
8635
9711
  }
8636
9712
  if (op === OP_TOKEN) {
8637
9713
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -8669,6 +9745,40 @@ function computeSiteLabels(code, roots, hostCst) {
8669
9745
  }
8670
9746
  return { at: (ip) => labels.get(ip) ?? TOP };
8671
9747
  }
9748
+ function scopeIsIdentity(code, ip, at) {
9749
+ const op = code[ip];
9750
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
9751
+ const ki = code[ip + 1];
9752
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
9753
+ }
9754
+ function scanHandoffNeeded(code, ip, labels) {
9755
+ const seen = /* @__PURE__ */ new Set();
9756
+ const stack = [ip];
9757
+ const kids = [];
9758
+ while (stack.length > 0) {
9759
+ const at = stack.pop();
9760
+ if (seen.has(at)) continue;
9761
+ seen.add(at);
9762
+ const l = labels.at(at);
9763
+ if (l.tri === TRI_UNKNOWN) return true;
9764
+ const op = code[at];
9765
+ if (op === OP_SCAN) return true;
9766
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue;
9767
+ 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;
9768
+ kids.length = 0;
9769
+ if (!childSlots(code, at, kids)) return true;
9770
+ for (const c of kids) stack.push(c);
9771
+ }
9772
+ return false;
9773
+ }
9774
+ function triviaLeadRanges(tri, trivia2) {
9775
+ if (tri === TRI_NONE) return [];
9776
+ if (tri < 0) return void 0;
9777
+ const fs = trivia2[tri]?._meta.firstSet;
9778
+ if (fs === void 0) return void 0;
9779
+ if (fs.kind === "empty") return [];
9780
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
9781
+ }
8672
9782
 
8673
9783
  // src/table/scalar-terminal.ts
8674
9784
  function makeScalarRecognizer(op, spec) {
@@ -8706,6 +9816,12 @@ function scalarTerminalNotChild(code, ip) {
8706
9816
  const op = code[child];
8707
9817
  return op === OP_RX || op === OP_LIT ? child : -1;
8708
9818
  }
9819
+ function scalarTerminalPeekChild(code, ip) {
9820
+ if (code[ip] !== OP_PEEK) return -1;
9821
+ const child = code[ip + 1];
9822
+ const op = code[child];
9823
+ return op === OP_RX || op === OP_LIT ? child : -1;
9824
+ }
8709
9825
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
8710
9826
  const seen = /* @__PURE__ */ new Set();
8711
9827
  let at = ip;
@@ -8883,6 +9999,59 @@ function leadingTriviaFieldAt(code, k, ip) {
8883
9999
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
8884
10000
  }
8885
10001
 
10002
+ // src/table/hold-gap.ts
10003
+ var WRAPPERS = /* @__PURE__ */ new Set([
10004
+ OP_NODE,
10005
+ OP_XFORM,
10006
+ OP_LEAF,
10007
+ OP_SOURCE_LEAF,
10008
+ OP_TOKEN,
10009
+ OP_SCOPE,
10010
+ OP_SCOPE_CAP,
10011
+ OP_SCOPE_PLAIN,
10012
+ OP_FIELD,
10013
+ OP_LABEL,
10014
+ OP_EXPECT,
10015
+ OP_WITHCTX,
10016
+ OP_RULE,
10017
+ OP_ATTEMPT,
10018
+ OP_COV
10019
+ ]);
10020
+ function rowNullable(code, k, ip, memo) {
10021
+ const hit = memo.get(ip);
10022
+ if (hit !== void 0) return hit;
10023
+ memo.set(ip, true);
10024
+ const op = code[ip];
10025
+ const kids = [];
10026
+ let out = true;
10027
+ if (op === OP_GATE) out = false;
10028
+ else if (op === OP_LIT || op === OP_LIT_CI) out = k[code[ip + 1]].length === 0;
10029
+ else if (op === OP_RX) {
10030
+ const re = k[code[ip + 1]];
10031
+ out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
10032
+ } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
10033
+ childSlots(code, ip, kids);
10034
+ out = kids.every((c) => rowNullable(code, k, c, memo));
10035
+ } else if (op === OP_CHOICE) {
10036
+ childSlots(code, ip, kids);
10037
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
10038
+ } else if (op === OP_REP || op === OP_REPV) {
10039
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
10040
+ } else if (WRAPPERS.has(op)) {
10041
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
10042
+ }
10043
+ memo.set(ip, out);
10044
+ return out;
10045
+ }
10046
+ function holdsGap(code, k, base, n, i, memo) {
10047
+ if (i < 1 || i + 1 >= n) return false;
10048
+ const term = code[base + i];
10049
+ if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
10050
+ const next = code[base + i + 1];
10051
+ if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
10052
+ return !rowNullable(code, k, next, memo);
10053
+ }
10054
+
8886
10055
  // src/table/emit-assembly.ts
8887
10056
  var Unemittable = class extends Error {
8888
10057
  construct;
@@ -8960,7 +10129,13 @@ var EMITTED_PARAMS = [
8960
10129
  // Appended for trivia-attributing fields (`field(…, { leadingTrivia })`);
8961
10130
  // old factories ignore them.
8962
10131
  "LEAD",
8963
- "triviaFieldCapture"
10132
+ "triviaFieldCapture",
10133
+ // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
10134
+ // factories ignore it.
10135
+ "skipDeferredTrivia",
10136
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
10137
+ // ignore it.
10138
+ "collapseEmpty"
8964
10139
  ];
8965
10140
  var RUNTIME_PRELUDE = `
8966
10141
  let _pfScan=null
@@ -8981,7 +10156,7 @@ function _skipTrivia(input,cur,ctx){
8981
10156
  const s=_pfScan
8982
10157
  if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
8983
10158
  if(s!==null)return skipTriviaScanned(s,input,cur,ctx)
8984
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
10159
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
8985
10160
  return advanceTrivia(input,cur,ctx)
8986
10161
  }
8987
10162
  function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,{_tag:'leaf',value,span:{start:s,end:e}})}
@@ -9157,6 +10332,24 @@ ${fast}
9157
10332
  ${scanned}
9158
10333
  }`;
9159
10334
  }
10335
+ function emitHoldTerm(callee, dst, t2, l, skip) {
10336
+ const fast = `const ${t2}v=${callee}(input,cur,ctx)
10337
+ if(${t2}v===FAIL)return FAIL
10338
+ ${dst}=${t2}v
10339
+ cur=EC.e`;
10340
+ if (l.tri === TRI_NONE) return fast;
10341
+ const held = `const ${t2}s=${skip}(input,cur,ctx)
10342
+ const ${t2}v=${callee}(input,${t2}s,ctx)
10343
+ if(${t2}v===FAIL)return FAIL
10344
+ ${dst}=${t2}v
10345
+ cur=${t2}s`;
10346
+ if (l.tri !== TRI_UNKNOWN) return held;
10347
+ return `if(ctx.trivia===undefined){
10348
+ ${fast}
10349
+ }else{
10350
+ ${held}
10351
+ }`;
10352
+ }
9160
10353
  function leadSkip(hasTrivia, leadTrivia, skip) {
9161
10354
  if (hasTrivia === "false") return "{}";
9162
10355
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -9188,7 +10381,7 @@ function rebuildPools(cc, fx, disp, plan) {
9188
10381
  })
9189
10382
  };
9190
10383
  }
9191
- function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
10384
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select) {
9192
10385
  const { code, k, fx, disp, dsp, triviaLabelled } = t2;
9193
10386
  const swapLegal = !cfg.trackLines;
9194
10387
  const hostCst = cfg.hostCst;
@@ -9198,6 +10391,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9198
10391
  const reachable = [...reachableSites(code, roots)];
9199
10392
  const labels = computeSiteLabels(code, roots, hostCst);
9200
10393
  const scalarSpecs = /* @__PURE__ */ new Set();
10394
+ const nullable2 = /* @__PURE__ */ new Map();
9201
10395
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
9202
10396
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
9203
10397
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -9287,6 +10481,8 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9287
10481
  };
9288
10482
  const bodies = [];
9289
10483
  const byIp = /* @__PURE__ */ new Map();
10484
+ const externals = [];
10485
+ const siteBytes = /* @__PURE__ */ new Map();
9290
10486
  const reached = /* @__PURE__ */ new Set();
9291
10487
  const prelude = [];
9292
10488
  const skipDefs = [];
@@ -9422,6 +10618,18 @@ return 1
9422
10618
  tokenDecisionRefs.set(dispatchIp, made);
9423
10619
  return made;
9424
10620
  }
10621
+ function gateMissTest(gip) {
10622
+ const resolved = t2.cc[code[gip + 1]];
10623
+ const ci = classes.push([resolved]) - 1;
10624
+ classPlan.push([code[gip + 1]]);
10625
+ const cls = hoist("cl", `CLS[${ci}][0]`);
10626
+ return isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`;
10627
+ }
10628
+ function lookaheadMiss(child, miss) {
10629
+ if (code[child] !== OP_GATE || cfg.tolerant || cfg.probe) return "";
10630
+ return `if(${gateMissTest(child)}){${miss}}
10631
+ `;
10632
+ }
9425
10633
  function skipFor(l) {
9426
10634
  if (l.tri < 0) return "_skipTrivia";
9427
10635
  const ki = l.tri;
@@ -9432,8 +10640,8 @@ return 1
9432
10640
  const nm = `_sk${skipPool.size}`;
9433
10641
  skipPool.set(key, nm);
9434
10642
  if (!hasScan) {
9435
- skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return commitTriviaScan(scanTriviaCompact(input,cur,ctx))}` : `function ${nm}(input,cur,ctx){
9436
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
10643
+ skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10644
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
9437
10645
  return advanceTrivia(input,cur,ctx)}`);
9438
10646
  return nm;
9439
10647
  }
@@ -9478,9 +10686,17 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9478
10686
  const target = resolveAlias(ip);
9479
10687
  const done = byIp.get(target);
9480
10688
  if (done !== void 0) return done;
10689
+ if (select !== void 0 && !select.has(target)) {
10690
+ const ext = `_px${target}`;
10691
+ byIp.set(target, ext);
10692
+ externals.push(target);
10693
+ return ext;
10694
+ }
9481
10695
  const fname = `_pf${target}`;
9482
10696
  byIp.set(target, fname);
9483
- bodies.push(lower(target, fname));
10697
+ const body = lower(target, fname);
10698
+ siteBytes.set(target, body.length);
10699
+ bodies.push(body);
9484
10700
  return fname;
9485
10701
  }
9486
10702
  function resolveAlias(ip) {
@@ -9500,9 +10716,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9500
10716
  const op = code[ip];
9501
10717
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
9502
10718
  if (op === OP_RULE) return code[ip + 1];
9503
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
9504
- return code[ip + 2];
9505
- }
10719
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
9506
10720
  return void 0;
9507
10721
  }
9508
10722
  function lower(ip, fname) {
@@ -9620,14 +10834,44 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9620
10834
  return `${head}EC.e=pos;return ''}`;
9621
10835
  case OP_GATE: {
9622
10836
  const child = link(code[ip + 2]);
10837
+ const xf = fxRef(code[ip + 3]);
10838
+ return `${head}
10839
+ if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10840
+ return ${child}(input,pos,ctx)
10841
+ }`;
10842
+ }
10843
+ case OP_RGATE: {
10844
+ const child = link(code[ip + 2]);
10845
+ if (cfg.tolerant || cfg.probe) return `${head}
10846
+ return ${child}(input,pos,ctx)
10847
+ }`;
9623
10848
  const resolved = t2.cc[code[ip + 1]];
9624
10849
  const ci = classes.push([resolved]) - 1;
9625
10850
  classPlan.push([code[ip + 1]]);
9626
10851
  const cls = hoist("cl", `CLS[${ci}][0]`);
9627
10852
  const xf = fxRef(code[ip + 3]);
9628
10853
  return `${head}
9629
- if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10854
+ const it=ctx._routed
10855
+ if(it!==undefined&&it.span.start===pos&&!classHas(${cls},lead(input,it.span.end))){ctx._fe=it.span.end;ctx._fx=${xf};return FAIL}
10856
+ return ${child}(input,pos,ctx)
10857
+ }`;
10858
+ }
10859
+ case OP_ARMGATE: {
10860
+ const pred = fnRef(code[ip + 1]);
10861
+ const child = link(code[ip + 2]);
10862
+ const xf = fxRef(code[ip + 3]);
10863
+ return `${head}
10864
+ if(!${pred}(ctx.state)){ctx._fc=false;ctx._fe=-1;ctx._fx=${xf};return FAIL}
9630
10865
  return ${child}(input,pos,ctx)
10866
+ }`;
10867
+ }
10868
+ case OP_WITHCTX: {
10869
+ const ki = code[ip + 1];
10870
+ const child = link(code[ip + 2]);
10871
+ return `${head}
10872
+ const saved=ctx.state
10873
+ ctx.state=${ki < 0 ? `${fnRef(~ki)}(saved)` : kRef(ki)}
10874
+ try{return ${child}(input,pos,ctx)}finally{ctx.state=saved}
9631
10875
  }`;
9632
10876
  }
9633
10877
  case OP_XFORM: {
@@ -9883,24 +11127,34 @@ return FAIL
9883
11127
  const xf = fxRef(code[ip + 2]);
9884
11128
  const p = tmp();
9885
11129
  return `${head}
9886
- ${emitMark(p, L.buf, L.raw, sinks)}
9887
- const v=${child}(input,pos,ctx)
11130
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
11131
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
9888
11132
  ${emitRollback(p, L.buf, L.raw, sinks)}
9889
- if(v===FAIL){EC.e=pos;return null}
11133
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){EC.e=pos;return null}
9890
11134
  ctx._fe=pos
9891
11135
  ctx._fx=${xf}
9892
11136
  return FAIL
9893
11137
  }`;
9894
11138
  }
9895
11139
  case OP_PEEK: {
11140
+ const scalarChild = scalarTerminalPeekChild(code, ip);
11141
+ if (scalarChild >= 0) {
11142
+ const recognize = recognizerRef(code[scalarChild + 1]);
11143
+ const xf2 = fxRef(code[ip + 2]);
11144
+ return `${head}
11145
+ if(${recognize}(input,pos)<0){ctx._fe=pos;ctx._fx=${xf2};return FAIL}
11146
+ EC.e=pos
11147
+ return null
11148
+ }`;
11149
+ }
9896
11150
  const child = link(code[ip + 1]);
9897
11151
  const xf = fxRef(code[ip + 2]);
9898
11152
  const p = tmp();
9899
11153
  return `${head}
9900
- ${emitMark(p, L.buf, L.raw, sinks)}
9901
- const v=${child}(input,pos,ctx)
11154
+ ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
11155
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
9902
11156
  ${emitRollback(p, L.buf, L.raw, sinks)}
9903
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11157
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9904
11158
  EC.e=pos
9905
11159
  return null
9906
11160
  }`;
@@ -9910,7 +11164,7 @@ return null
9910
11164
  const clean = !REC && failureRollbackClean(prog, ip);
9911
11165
  const p = tmp();
9912
11166
  return `${head}
9913
- ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
11167
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
9914
11168
  ctx._fc=false
9915
11169
  const v=${child}(input,pos,ctx)
9916
11170
  if(v===FAIL){
@@ -9971,7 +11225,7 @@ return v
9971
11225
  );
9972
11226
  } else {
9973
11227
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
9974
- parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
11228
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
9975
11229
  }
9976
11230
  names.push(vn);
9977
11231
  }
@@ -9991,7 +11245,7 @@ return v
9991
11245
  const asc = hoist("as", `DISP[${di}].ascii`);
9992
11246
  const hiArr = table.hi;
9993
11247
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
9994
- const directAscii = staticBuild && table.hi.length === 0;
11248
+ const directAscii = table.hi.length === 0;
9995
11249
  return `${head}
9996
11250
  const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9997
11251
  let arm=-1
@@ -10018,7 +11272,7 @@ return FAIL
10018
11272
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10019
11273
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10020
11274
  const maskable = n <= 32;
10021
- const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
11275
+ const directAsciiMask = maskable && gates.every(isAsciiOnlyClass);
10022
11276
  const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10023
11277
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10024
11278
  const pretests = Array.from({ length: n }, (_, i) => {
@@ -10060,7 +11314,7 @@ return FAIL
10060
11314
  if (choiceCannotCommit(prog, ip) && !startFailureExact) {
10061
11315
  const deepAt = Array.from({ length: n }, () => tmp());
10062
11316
  const deepFx = Array.from({ length: n }, () => tmp());
10063
- const remember = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
11317
+ const remember2 = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
10064
11318
  const lazyArms = (ascii) => arms.map((arm, i) => {
10065
11319
  const pretest = pretests[i];
10066
11320
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
@@ -10072,13 +11326,13 @@ return FAIL
10072
11326
  if(${decision}===0){
10073
11327
  ctx._fc=false
10074
11328
  {const at=_pfTokEnd
10075
- ${remember(i, "at", pretest.token.expected)}}
11329
+ ${remember2(i, "at", pretest.token.expected)}}
10076
11330
  }`;
10077
11331
  const sequenceMiss = pretest?.sequence === void 0 ? "" : `
10078
11332
  else if(${ascii ? `(bits&${1 << i})!==0&&` : ""}${decision}<0){
10079
11333
  ctx._fc=false
10080
11334
  {const at=_pfSeqEnd
10081
- ${remember(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
11335
+ ${remember2(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
10082
11336
  }`;
10083
11337
  return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10084
11338
  `}if(${gate}){
@@ -10086,7 +11340,7 @@ ctx._fc=false
10086
11340
  {const v=${arm}(input,pos,ctx)
10087
11341
  if(v!==FAIL)return v}
10088
11342
  {const at=ctx._fe??pos
10089
- ${remember(i, "at", "ctx._fx")}}
11343
+ ${remember2(i, "at", "ctx._fx")}}
10090
11344
  ${rollbackFor(i)}
10091
11345
  }${routeMiss}${sequenceMiss}`;
10092
11346
  }).join("\n");
@@ -10199,7 +11453,7 @@ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10199
11453
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10200
11454
  ${startFailureExact ? "" : "let prev=0"}
10201
11455
  ${maskArms}
10202
- ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${n},prev,acc)`}
11456
+ ${startFailureExact ? "" : `if(best===pos&&prev!==0)acc=${catchName}(${n},prev,acc)`}
10203
11457
  ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
10204
11458
  return FAIL
10205
11459
  }
@@ -10298,7 +11552,7 @@ return [key,v]
10298
11552
  const ci = classes.push([resolved]) - 1;
10299
11553
  classPlan.push([itemClassIndex]);
10300
11554
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10301
- itemAscii = staticBuild && isAsciiOnlyClass(resolved);
11555
+ itemAscii = isAsciiOnlyClass(resolved);
10302
11556
  }
10303
11557
  }
10304
11558
  const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
@@ -10454,6 +11708,26 @@ return nd
10454
11708
  const trailingTrivia = (flags & 128) !== 0;
10455
11709
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
10456
11710
  const leanFlags = flags & ~128;
11711
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
11712
+ return `${head}
11713
+ const v=${child}(input,pos,ctx)
11714
+ if(v!==undefined)return v
11715
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11716
+ }`;
11717
+ }
11718
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
11719
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t2.trivia);
11720
+ const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
11721
+ if(!(${[
11722
+ ...gated.leads.map((g) => `!(${gateMissTest(g)})`),
11723
+ ...gated.lits.map((i) => `gc===${k[i].codePointAt(0)}`),
11724
+ ...triviaLead.map((r) => r.lo === r.hi ? `gc===${r.lo}` : `(gc>=${r.lo}&&gc<=${r.hi})`)
11725
+ ].join("||") || "false"})){
11726
+ const gv=${link(gated.last)}(input,pos,ctx)
11727
+ if(gv!==undefined)return gv
11728
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11729
+ }
11730
+ ` : "";
10457
11731
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
10458
11732
  const fields = flags === 18;
10459
11733
  const collapseChildren = flags === 34;
@@ -10488,7 +11762,7 @@ sCh.push(nd)
10488
11762
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
10489
11763
  }`;
10490
11764
  return `${head}
10491
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11765
+ ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10492
11766
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
10493
11767
  const flat=[]
10494
11768
  ctx._cstBuf=undefined
@@ -10524,7 +11798,7 @@ return nd
10524
11798
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
10525
11799
  const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
10526
11800
  const ty = q(type);
10527
- const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
11801
+ const stArg = "ctx.state";
10528
11802
  const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
10529
11803
  let value;
10530
11804
  if (proj >= 0) {
@@ -10563,7 +11837,7 @@ const hostKids=kids
10563
11837
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
10564
11838
  const tlog=buf.tl??EMPTY_TLOG`;
10565
11839
  return `${head}
10566
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11840
+ ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10567
11841
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
10568
11842
  ${openCapture}
10569
11843
  ctx.captureTrivia=${captureWide}
@@ -10585,7 +11859,7 @@ ctx.captureTrivia=sCap
10585
11859
  if(v===FAIL)return FAIL
10586
11860
  const end=EC.e
10587
11861
  const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
10588
- const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
11862
+ const st=${readsState ? "ctx.state" : "undefined"}
10589
11863
  let nd
10590
11864
  ${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]
10591
11865
  else ` : ""}{${value}}
@@ -10598,21 +11872,57 @@ return nd
10598
11872
  throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
10599
11873
  }
10600
11874
  }
11875
+ const served = (ip) => select === void 0 || select.has(resolveAlias(ip));
10601
11876
  const ruleEntries = [];
10602
11877
  for (const [rname, entryIp] of Object.entries(prog.rules)) {
11878
+ if (!served(entryIp)) continue;
10603
11879
  const target = link(entryIp);
10604
11880
  const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
10605
11881
  bodies.push(`const ${rn}=${target}`);
10606
11882
  ruleEntries.push(`${q(rname)}:${rn}`);
10607
11883
  }
10608
11884
  const extra = [];
10609
- for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
11885
+ const exported = /* @__PURE__ */ new Set();
11886
+ for (const ip of extraIps) {
11887
+ if (!served(ip)) continue;
11888
+ exported.add(ip);
11889
+ extra.push(`${ip}:${link(ip)}`);
11890
+ }
11891
+ if (select !== void 0) {
11892
+ const kids = [];
11893
+ for (const ip of reachable) {
11894
+ if (select.has(resolveAlias(ip))) continue;
11895
+ kids.length = 0;
11896
+ childSlots(code, ip, kids);
11897
+ for (const kid of kids) {
11898
+ const target = resolveAlias(kid);
11899
+ if (!select.has(target) || exported.has(target)) continue;
11900
+ exported.add(target);
11901
+ extra.push(`${target}:${link(target)}`);
11902
+ }
11903
+ }
11904
+ }
11905
+ const hybrid = select === void 0 ? "" : `,
11906
+ ext:[${externals.join(",")}],
11907
+ bind:function(xs,ps){_xScan=xs
11908
+ ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
11909
+ scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
11910
+ const scannerFor = (ip) => {
11911
+ const ki = labels.at(ip).tri;
11912
+ if (ki === TRI_UNKNOWN) return "_pfScan";
11913
+ if (ki === TRI_NONE) return "null";
11914
+ return swapLegal && !triviaLabelled[ki] && t2.triviaScan[ki] != null ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
11915
+ };
11916
+ const externalDefs = select === void 0 ? "" : `let _xScan
11917
+ ${externals.map((ip) => `let _xp${ip}
11918
+ function _px${ip}(input,pos,ctx){const o=_xScan(${scannerFor(ip)});const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
11919
+ `;
10610
11920
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10611
11921
  ${prelude.join("\n")}
10612
11922
  ${skipDefs.join("\n")}
10613
11923
  ${choiceDefs.join("\n")}
10614
11924
  ${bodies.join("\n")}
10615
- function _begin(ctx){
11925
+ ${externalDefs}function _begin(ctx){
10616
11926
  const host=ctx.build
10617
11927
  if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
10618
11928
  _pfDepth++
@@ -10639,7 +11949,7 @@ pieces:{${ruleEntries.join(",")}},
10639
11949
  byIp:{${extra.join(",")}},
10640
11950
  end:function(){return EC.e},
10641
11951
  begin:_begin,
10642
- finish:_finish
11952
+ finish:_finish${hybrid}
10643
11953
  }`;
10644
11954
  return {
10645
11955
  source,
@@ -10647,6 +11957,7 @@ finish:_finish
10647
11957
  masks,
10648
11958
  classes,
10649
11959
  armExpected,
11960
+ siteBytes,
10650
11961
  plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
10651
11962
  };
10652
11963
  }
@@ -10897,157 +12208,27 @@ function literal(value, opts = {}) {
10897
12208
  return { ok: true, value, span };
10898
12209
  }
10899
12210
  return failAt(ctx, expected, pos);
10900
- };
10901
- })() : function parse3(input, pos, ctx) {
10902
- const end = pos + value.length;
10903
- if (end > input.length) {
10904
- return failAt(ctx, expected, pos);
10905
- }
10906
- const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
10907
- if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
10908
- const span = { start: pos, end };
10909
- if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
10910
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
10911
- return { ok: true, value: matchedValue, span };
10912
- }
10913
- return failAt(ctx, expected, pos);
10914
- };
10915
- return {
10916
- _tag: "literal",
10917
- _meta: meta,
10918
- _def: { tag: "literal", value, caseInsensitive },
10919
- _parseScalar: parseScalar,
10920
- parse: parse2
10921
- };
10922
- }
10923
-
10924
- // src/combinators/sequence.ts
10925
- function sequence(...parsers) {
10926
- let adjacency = null;
10927
- for (let i = 0; i < parsers.length; i++) {
10928
- const a = adjacencyOf(parsers[i]);
10929
- if (a === null) continue;
10930
- if (i === 0) {
10931
- throw new TypeError(
10932
- `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
10933
- );
10934
- }
10935
- ;
10936
- (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
10937
- }
10938
- const hasAdjacency = adjacency !== null;
10939
- let leading = null;
10940
- for (let i = 1; i < parsers.length; i++) {
10941
- if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
10942
- }
10943
- const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
10944
- const meta = {
10945
- // Union through the nullable prefix — a leading optional()/many() lets a later
10946
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
10947
- firstSet: sequenceFirstSet(parsers),
10948
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
10949
- isTrivia: false
10950
- };
10951
- const def = { tag: "sequence", parsers };
10952
- const scalarParsers = parsers.map(scalarOf);
10953
- const parseScalar = (input, pos, ctx) => {
10954
- let cur = pos;
10955
- if (strictArity !== 0) {
10956
- cur = scalarParsers[0](input, cur, ctx);
10957
- if (cur < 0) return cur;
10958
- const first = ctx._sv;
10959
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10960
- cur = scalarParsers[1](input, cur, ctx);
10961
- if (cur < 0) return cur;
10962
- const second = ctx._sv;
10963
- if (strictArity === 2) {
10964
- ctx._sv = def.valueUnused ? void 0 : [first, second];
10965
- return cur;
10966
- }
10967
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10968
- cur = scalarParsers[2](input, cur, ctx);
10969
- if (cur < 0) return cur;
10970
- ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
10971
- return cur;
10972
- }
10973
- const values = def.valueUnused ? void 0 : [];
10974
- for (let i = 0; i < scalarParsers.length; i++) {
10975
- let termPos = cur;
10976
- if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
10977
- const end = scalarParsers[i](input, termPos, ctx);
10978
- if (end < 0) return end;
10979
- if (values !== void 0) values.push(ctx._sv);
10980
- if (end > termPos || termPos === cur) cur = end;
10981
- }
10982
- ctx._sv = values;
10983
- return cur;
10984
- };
10985
- let followSentinels;
10986
- return {
10987
- _tag: "sequence",
10988
- _meta: meta,
10989
- _def: def,
10990
- _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
10991
- parse(input, pos, ctx) {
10992
- const tolerant = ctx._tolerant === true;
10993
- if (tolerant) {
10994
- followSentinels ??= parsers.map((_, i) => firstSetSentinel(
10995
- parsers.slice(i + 1).reduce(
10996
- (set, parser2) => union(set, firstSetOf(parser2)),
10997
- { kind: "empty" }
10998
- )
10999
- ));
11000
- }
11001
- const inheritedSync = ctx._sync;
11002
- const deferredTrivia = needsDeferredTriviaCommit(ctx);
11003
- const values = def.valueUnused ? void 0 : [];
11004
- let cur = pos;
11005
- try {
11006
- for (let i = 0; i < parsers.length; i++) {
11007
- if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
11008
- const assertion = adjacency?.[i];
11009
- if (assertion) {
11010
- if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
11011
- if (values !== void 0) values.push(null);
11012
- continue;
11013
- }
11014
- let termPos = cur;
11015
- const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11016
- const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11017
- const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11018
- if (ctx.trivia && i > 0) {
11019
- termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
11020
- }
11021
- const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11022
- const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11023
- const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11024
- if (leading?.[i] === true) LEAD.at = cur;
11025
- const result = parsers[i].parse(input, termPos, ctx);
11026
- if (!result.ok) return result;
11027
- if (values !== void 0) values.push(result.value);
11028
- if (result.span.end > termPos || termPos === cur) cur = result.span.end;
11029
- else if (deferredTrivia) {
11030
- rollbackScannedTriviaAt(
11031
- ctx,
11032
- markTlog,
11033
- scanTlog,
11034
- markLog,
11035
- scanLog,
11036
- markRootLog,
11037
- scanRootLog
11038
- );
11039
- }
11040
- }
11041
- } finally {
11042
- if (tolerant) ctx._sync = inheritedSync;
11043
- }
11044
- return {
11045
- ok: true,
11046
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
11047
- value: values ?? void 0,
11048
- span: { start: pos, end: cur }
11049
- };
12211
+ };
12212
+ })() : function parse3(input, pos, ctx) {
12213
+ const end = pos + value.length;
12214
+ if (end > input.length) {
12215
+ return failAt(ctx, expected, pos);
12216
+ }
12217
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
12218
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
12219
+ const span = { start: pos, end };
12220
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
12221
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
12222
+ return { ok: true, value: matchedValue, span };
11050
12223
  }
12224
+ return failAt(ctx, expected, pos);
12225
+ };
12226
+ return {
12227
+ _tag: "literal",
12228
+ _meta: meta,
12229
+ _def: { tag: "literal", value, caseInsensitive },
12230
+ _parseScalar: parseScalar,
12231
+ parse: parse2
11051
12232
  };
11052
12233
  }
11053
12234
 
@@ -11118,124 +12299,6 @@ function ref() {
11118
12299
  return slot;
11119
12300
  }
11120
12301
 
11121
- // src/combinators/token.ts
11122
- function semanticLeafValue(_ctx, _input, _start, _end, value) {
11123
- return value;
11124
- }
11125
- function sourceLeafValue(ctx, input, start, end, value) {
11126
- return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
11127
- }
11128
- function token(root) {
11129
- const meta = {
11130
- firstSet: root._meta.firstSet,
11131
- canMatchNewline: root._meta.canMatchNewline,
11132
- isTrivia: false
11133
- };
11134
- return {
11135
- _tag: "token",
11136
- _meta: meta,
11137
- _def: { tag: "token", parser: root },
11138
- parse(input, pos, ctx) {
11139
- const savedTrivia = ctx.trivia;
11140
- const savedKinds = ctx.triviaKindLabels;
11141
- const savedBuf = ctx._cstBuf;
11142
- const savedChildren = ctx._cstChildren;
11143
- const savedLeaves = ctx._cstLeaves;
11144
- const savedRaw = ctx._cstRawChildren;
11145
- const savedTriviaLog = ctx._cstTriviaLog;
11146
- const savedOuterTriviaLog = ctx._triviaLog;
11147
- const savedRootTriviaLog = ctx._rootTriviaLog;
11148
- const wasCapturing = cstCaptureActive(ctx);
11149
- ctx.trivia = void 0;
11150
- ctx.triviaKindLabels = void 0;
11151
- ctx._cstBuf = void 0;
11152
- ctx._cstChildren = void 0;
11153
- ctx._cstLeaves = void 0;
11154
- ctx._cstRawChildren = void 0;
11155
- ctx._cstTriviaLog = void 0;
11156
- ctx._triviaLog = void 0;
11157
- ctx._rootTriviaLog = void 0;
11158
- let result;
11159
- try {
11160
- result = root.parse(input, pos, ctx);
11161
- } finally {
11162
- ctx.trivia = savedTrivia;
11163
- ctx.triviaKindLabels = savedKinds;
11164
- ctx._cstBuf = savedBuf;
11165
- ctx._cstChildren = savedChildren;
11166
- ctx._cstLeaves = savedLeaves;
11167
- ctx._cstRawChildren = savedRaw;
11168
- ctx._cstTriviaLog = savedTriviaLog;
11169
- ctx._triviaLog = savedOuterTriviaLog;
11170
- ctx._rootTriviaLog = savedRootTriviaLog;
11171
- }
11172
- if (!result.ok) return result;
11173
- const span = result.span;
11174
- const value = input.slice(pos, span.end);
11175
- if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11176
- return { ok: true, value, span };
11177
- }
11178
- };
11179
- }
11180
- function makeLeaf(root, fn, sourceCstValue) {
11181
- const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
11182
- const meta = {
11183
- firstSet: root._meta.firstSet,
11184
- canMatchNewline: root._meta.canMatchNewline,
11185
- isTrivia: false
11186
- };
11187
- return {
11188
- _tag: "leaf",
11189
- _meta: meta,
11190
- _def: {
11191
- tag: "leaf",
11192
- parser: root,
11193
- fn,
11194
- ...sourceCstValue ? { cstValue: "source" } : {}
11195
- },
11196
- parse(input, pos, ctx) {
11197
- const savedBuf = ctx._cstBuf;
11198
- const savedChildren = ctx._cstChildren;
11199
- const savedLeaves = ctx._cstLeaves;
11200
- const savedRaw = ctx._cstRawChildren;
11201
- const savedTriviaLog = ctx._cstTriviaLog;
11202
- const savedOuterTriviaLog = ctx._triviaLog;
11203
- const wasCapturing = cstCaptureActive(ctx);
11204
- ctx._cstBuf = void 0;
11205
- ctx._cstChildren = void 0;
11206
- ctx._cstLeaves = void 0;
11207
- ctx._cstRawChildren = void 0;
11208
- ctx._cstTriviaLog = void 0;
11209
- ctx._triviaLog = void 0;
11210
- let result;
11211
- try {
11212
- result = root.parse(input, pos, ctx);
11213
- } finally {
11214
- ctx._cstBuf = savedBuf;
11215
- ctx._cstChildren = savedChildren;
11216
- ctx._cstLeaves = savedLeaves;
11217
- ctx._cstRawChildren = savedRaw;
11218
- ctx._cstTriviaLog = savedTriviaLog;
11219
- ctx._triviaLog = savedOuterTriviaLog;
11220
- }
11221
- if (!result.ok) return result;
11222
- const value = fn(result.value, result.span);
11223
- if (wasCapturing) pushCstLeaf(ctx, {
11224
- _tag: "leaf",
11225
- value: cstValue(ctx, input, pos, result.span.end, value),
11226
- span: result.span
11227
- });
11228
- return { ok: true, value, span: result.span };
11229
- }
11230
- };
11231
- }
11232
- function leaf(root, fn) {
11233
- return makeLeaf(root, fn, false);
11234
- }
11235
- function sourceLeaf(root, fn) {
11236
- return makeLeaf(root, fn, true);
11237
- }
11238
-
11239
12302
  // src/combinators/scanTo.ts
11240
12303
  function resolveScanSkip(explicitSkip, raw, ctx) {
11241
12304
  if (raw) return [];
@@ -11480,37 +12543,184 @@ function escapeClassChar(ch2) {
11480
12543
  return ch2.replace(/[\\\]^-]/g, "\\$&");
11481
12544
  }
11482
12545
 
11483
- // src/table/run-support.ts
11484
- function lineCol(ctx, offset) {
11485
- const starts = ctx._lineStarts ?? [0];
11486
- let lo = 0, hi = starts.length - 1;
11487
- while (lo < hi) {
11488
- const mid = lo + hi + 1 >> 1;
11489
- if (starts[mid] <= offset) lo = mid;
11490
- else hi = mid - 1;
12546
+ // src/table/trivia-gap.ts
12547
+ function skipDeferredTrivia(input, cur, ctx) {
12548
+ const triviaP = ctx.trivia;
12549
+ const plain2 = ctx.trackLines !== true && ctx.captureTrivia !== true;
12550
+ const gap = ctx._gap;
12551
+ 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;
12552
+ const end = clearRunEnd(input, cur, ctx, triviaP, plain2);
12553
+ if (end >= 0) {
12554
+ remember(cur, end, ctx, input, triviaP);
12555
+ return end;
11491
12556
  }
11492
- return [lo + 1, offset - starts[lo] + 1];
12557
+ const scan = scanTriviaCompact(input, cur, ctx);
12558
+ if (typeof scan !== "number") return commitTriviaScan(scan);
12559
+ if (plain2) remember(cur, scan, ctx, input, triviaP);
12560
+ return scan;
11493
12561
  }
11494
- function spanLines(ctx, start, end) {
11495
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
11496
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
12562
+ function clearRunEnd(input, cur, ctx, triviaP, plain2) {
12563
+ const rootKinds = ctx._rootTriviaKindIndex;
12564
+ const spec = triviaP?._meta.labeledTriviaSpec;
12565
+ if (!plain2 || triviaP === void 0 || spec == null || rootKinds === void 0 || ctx._triviaLog !== void 0) return -1;
12566
+ if (spec.rootKinds !== rootKinds) prime(spec, triviaP, rootKinds);
12567
+ const fast = spec.rootScan;
12568
+ if (fast === null) return -1;
12569
+ const end = fast(input, cur);
12570
+ return ctx._rootTriviaCapture === false || clearOf(spec.rootLeaders, input, cur, end) ? end : -1;
12571
+ }
12572
+ function remember(cur, end, ctx, input, triviaP) {
12573
+ const gap = ctx._gap;
12574
+ if (gap === void 0) {
12575
+ ctx._gap = { at: cur, end, input, of: triviaP, root: ctx._rootTriviaCapture, rootKinds: ctx._rootTriviaKindIndex, log: ctx._triviaLog, state: ctx.state };
12576
+ return;
12577
+ }
12578
+ gap.at = cur;
12579
+ gap.end = end;
12580
+ gap.input = input;
12581
+ gap.of = triviaP;
12582
+ gap.root = ctx._rootTriviaCapture;
12583
+ gap.rootKinds = ctx._rootTriviaKindIndex;
12584
+ gap.log = ctx._triviaLog;
12585
+ gap.state = ctx.state;
11497
12586
  }
11498
- function rawEntry(v, input, s, e) {
11499
- if (typeof v === "object" && v !== null) {
11500
- const tg = v._tag;
11501
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
12587
+ function prime(spec, triviaP, rootKinds) {
12588
+ const ranges = [];
12589
+ let bounded = true;
12590
+ for (const arm of spec.arms) {
12591
+ if (rootKinds[arm.label] === void 0) continue;
12592
+ const fs = arm.parser._meta.firstSet;
12593
+ if (fs.kind === "any") bounded = false;
12594
+ else if (fs.kind === "ranges") ranges.push(...fs.ranges);
12595
+ }
12596
+ const classified = triviaP._meta.triviaScanner;
12597
+ spec.rootKinds = rootKinds;
12598
+ spec.rootLeaders = ranges;
12599
+ spec.rootScan = !bounded ? null : classified === void 0 ? fastTriviaScanner(triviaP) : classified;
12600
+ }
12601
+ function clearOf(ranges, input, from, to) {
12602
+ for (let i = from; i < to; i++) {
12603
+ const c = input.charCodeAt(i);
12604
+ if (c >= 55296 && c <= 57343) return false;
12605
+ for (const r of ranges) if (c >= r.lo && c <= r.hi) return false;
11502
12606
  }
11503
- return {
11504
- _tag: "leaf",
11505
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
11506
- span: { start: s, end: e }
11507
- };
12607
+ return true;
11508
12608
  }
11509
- function lead(input, pos) {
11510
- if (pos >= input.length) return -1;
11511
- const c = input.charCodeAt(pos);
11512
- if (c < 55296 || c > 56319) return c;
11513
- return input.codePointAt(pos) ?? c;
12609
+
12610
+ // src/table/fail-clean.ts
12611
+ function passChild(code, ip) {
12612
+ switch (code[ip]) {
12613
+ case OP_RULE:
12614
+ case OP_LABEL:
12615
+ case OP_COV:
12616
+ case OP_TOKEN:
12617
+ return code[ip + 1];
12618
+ case OP_GATE:
12619
+ case OP_NODE:
12620
+ case OP_NODE_TRACK:
12621
+ case OP_XFORM:
12622
+ case OP_FIELD:
12623
+ case OP_SCOPE:
12624
+ case OP_SCOPE_CAP:
12625
+ case OP_SCOPE_PLAIN:
12626
+ case OP_WITHCTX:
12627
+ case OP_LEAF:
12628
+ case OP_SOURCE_LEAF:
12629
+ return code[ip + 2];
12630
+ default:
12631
+ return -1;
12632
+ }
12633
+ }
12634
+ function seqCount(code, ip) {
12635
+ const op = code[ip];
12636
+ return op === OP_SEQ || op === OP_SEQV ? ip + 1 : op === OP_SEQX ? ip + 2 : -1;
12637
+ }
12638
+ function failCleanAnalysis(code) {
12639
+ const cleanAt = new Uint8Array(code.length);
12640
+ const neverAt = new Uint8Array(code.length);
12641
+ const neverFails = (ip) => {
12642
+ const hit = neverAt[ip];
12643
+ if (hit !== 0) return hit === 1;
12644
+ neverAt[ip] = 3;
12645
+ let out = false;
12646
+ const op = code[ip];
12647
+ if (op === OP_OPT || op === OP_EMPTY || op === OP_EXPECT) out = true;
12648
+ else if (op === OP_REP || op === OP_REPV) out = code[ip + 2] === 0;
12649
+ else {
12650
+ const at = seqCount(code, ip);
12651
+ if (at >= 0) {
12652
+ out = true;
12653
+ for (let i = 1, n = code[at]; out && i <= n; i++) out = neverFails(code[at + i]);
12654
+ } else if (op !== OP_GATE) {
12655
+ const c = passChild(code, ip);
12656
+ out = c >= 0 && neverFails(c);
12657
+ }
12658
+ }
12659
+ neverAt[ip] = out ? 1 : 2;
12660
+ return out;
12661
+ };
12662
+ const clean = (ip) => {
12663
+ const hit = cleanAt[ip];
12664
+ if (hit !== 0) return hit === 1;
12665
+ cleanAt[ip] = 3;
12666
+ let out = false;
12667
+ switch (code[ip]) {
12668
+ // A terminal pushes its leaf only on a match; NOT/PEEK/ATTEMPT restore
12669
+ // their own mark; OPT, EMPTY and EXPECT do not fail uncommitted.
12670
+ case OP_LIT:
12671
+ case OP_RX:
12672
+ case OP_LIT_TRACK:
12673
+ case OP_RX_TRACK:
12674
+ case OP_LIT_CI:
12675
+ case OP_LIT_CI_TRACK:
12676
+ case OP_GUARD:
12677
+ case OP_NOT:
12678
+ case OP_PEEK:
12679
+ case OP_ATTEMPT:
12680
+ case OP_EMPTY:
12681
+ case OP_OPT:
12682
+ case OP_EXPECT:
12683
+ out = true;
12684
+ break;
12685
+ // Min 0 does not fail uncommitted; min 1 fails only with no item kept, and
12686
+ // restores the failed item itself.
12687
+ case OP_REP:
12688
+ case OP_REPV:
12689
+ out = code[ip + 2] <= 1;
12690
+ break;
12691
+ // Only the first term may fail: a later one fails after the terms before it
12692
+ // wrote, and after the trivia scanned in front of it.
12693
+ case OP_SEQ:
12694
+ case OP_SEQV:
12695
+ case OP_SEQX: {
12696
+ const at = seqCount(code, ip);
12697
+ const n = code[at];
12698
+ out = n > 0 && clean(code[at + 1]);
12699
+ for (let i = 2; out && i <= n; i++) out = neverFails(code[at + i]);
12700
+ break;
12701
+ }
12702
+ case OP_CHOICE: {
12703
+ out = true;
12704
+ for (let i = 0, n = code[ip + 2]; out && i < n; i++) out = clean(code[ip + 4 + i]);
12705
+ break;
12706
+ }
12707
+ case OP_ROUTED:
12708
+ out = code[ip + 1] < 0 || clean(code[ip + 1]);
12709
+ break;
12710
+ // An arm's failure and the fallback's are committed; only the selector's is
12711
+ // not, and without a fallback an unknown key fails after the selector wrote.
12712
+ case OP_DISPATCH:
12713
+ out = code[ip + 3] >= 0 && clean(code[ip + 1]);
12714
+ break;
12715
+ default: {
12716
+ const c = passChild(code, ip);
12717
+ out = c >= 0 && clean(c);
12718
+ }
12719
+ }
12720
+ cleanAt[ip] = out ? 1 : 2;
12721
+ return out;
12722
+ };
12723
+ return clean;
11514
12724
  }
11515
12725
 
11516
12726
  // src/grammar-metadata.ts
@@ -11608,12 +12818,6 @@ function hasDirectBuilder(prog) {
11608
12818
  return false;
11609
12819
  }
11610
12820
 
11611
- // src/cst/root-trivia-scope.ts
11612
- var ROOT_TRIVIA_SCOPE_REFUSAL = "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.";
11613
- function refuseUnclassifiedRootScope(strict) {
11614
- if (strict === true) throw new TypeError(ROOT_TRIVIA_SCOPE_REFUSAL);
11615
- }
11616
-
11617
12821
  // src/table/cell.ts
11618
12822
  var FAIL = /* @__PURE__ */ Symbol("pm.fail");
11619
12823
  var newEndCell = () => ({ e: 0 });
@@ -11664,6 +12868,7 @@ function assemble(t2, prog, cfg) {
11664
12868
  const swapLegal = !cfg.trackLines;
11665
12869
  const hostCst = cfg.hostCst;
11666
12870
  const REC = prog.rec === 1 && cfg.tolerant;
12871
+ const PROBE = cfg.probe;
11667
12872
  const sentinels = /* @__PURE__ */ new Map();
11668
12873
  function sentinelFor(cls) {
11669
12874
  if (cls < 0) return void 0;
@@ -11678,6 +12883,9 @@ function assemble(t2, prog, cfg) {
11678
12883
  const EC = newEndCell();
11679
12884
  const scalarRecognizers = [];
11680
12885
  const rawScalarSpecs = /* @__PURE__ */ new Set();
12886
+ function lookaheadClass(child) {
12887
+ return code[child] === OP_GATE && !cfg.tolerant && !cfg.probe ? cc[code[child + 1]] : null;
12888
+ }
11681
12889
  function scalarFor(child) {
11682
12890
  const spec = code[child + 1];
11683
12891
  let recognize = scalarRecognizers[spec];
@@ -11687,17 +12895,27 @@ function assemble(t2, prog, cfg) {
11687
12895
  }
11688
12896
  return recognize;
11689
12897
  }
11690
- const labelExtraIps = [];
11691
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) labelExtraIps.push(r[0]);
11692
- for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0]);
12898
+ const labelExtraIps = assemblyExtraIps(prog);
11693
12899
  const closureLabels = computeSiteLabels(
11694
12900
  code,
11695
12901
  [...Object.values(prog.rules), ...labelExtraIps],
11696
12902
  hostCst
11697
12903
  );
11698
12904
  let SCAN = null;
12905
+ let HYBRID;
12906
+ function hybridPiece(piece) {
12907
+ const setScan = HYBRID.scan;
12908
+ return (input, pos, ctx) => {
12909
+ const saved = setScan(SCAN);
12910
+ const value = piece(input, pos, ctx);
12911
+ setScan(saved);
12912
+ return value;
12913
+ };
12914
+ }
11699
12915
  const memo = /* @__PURE__ */ new Map();
11700
12916
  const reached = /* @__PURE__ */ new Set();
12917
+ const NULLABLE = /* @__PURE__ */ new Map();
12918
+ const CLEAN = REC ? () => false : failCleanAnalysis(code);
11701
12919
  function pushLeaf(ctx, value, s, e) {
11702
12920
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
11703
12921
  pushCstLeaf(ctx, lf);
@@ -11896,6 +13114,22 @@ function assemble(t2, prog, cfg) {
11896
13114
  return node2;
11897
13115
  };
11898
13116
  }
13117
+ function passCollapseNode(child, build, readsRaw) {
13118
+ return (input, pos, ctx) => {
13119
+ const v = child(input, pos, ctx);
13120
+ if (v !== void 0) return v;
13121
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13122
+ };
13123
+ }
13124
+ function gatedPassCollapseNode(blockers, last, classic, build, readsRaw) {
13125
+ return (input, pos, ctx) => {
13126
+ const c = lead(input, pos);
13127
+ for (let i = 0; i < blockers.length; i++) if (classHas2(blockers[i], c)) return classic(input, pos, ctx);
13128
+ const v = last(input, pos, ctx);
13129
+ if (v !== void 0) return v;
13130
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13131
+ };
13132
+ }
11899
13133
  function plainProjectNode(child, projection, type) {
11900
13134
  return (input, pos, ctx) => {
11901
13135
  const sCh = ctx._cstChildren;
@@ -11987,9 +13221,7 @@ function assemble(t2, prog, cfg) {
11987
13221
  return s(input, cur);
11988
13222
  }
11989
13223
  if (s !== null) return skipTriviaScanned(s, input, cur, ctx);
11990
- if (needsDeferredTriviaCommit(ctx)) {
11991
- return commitTriviaScan(scanTriviaCompact(input, cur, ctx));
11992
- }
13224
+ if (needsDeferredTriviaCommit(ctx)) return skipDeferredTrivia(input, cur, ctx);
11993
13225
  return advanceTrivia(input, cur, ctx);
11994
13226
  }
11995
13227
  let TERMV;
@@ -12159,7 +13391,7 @@ function assemble(t2, prog, cfg) {
12159
13391
  if (next !== void 0) {
12160
13392
  return next(input, pos, ctx, bits, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12161
13393
  }
12162
- if (best === pos) acc = through(total, prev, acc);
13394
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12163
13395
  ctx._fe = pos;
12164
13396
  ctx._fx = acc ?? choiceFx;
12165
13397
  return FAIL;
@@ -12242,7 +13474,7 @@ function assemble(t2, prog, cfg) {
12242
13474
  if (next !== void 0) {
12243
13475
  return next(input, pos, ctx, c, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12244
13476
  }
12245
- if (best === pos) acc = through(total, prev, acc);
13477
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12246
13478
  ctx._fe = pos;
12247
13479
  ctx._fx = acc ?? choiceFx;
12248
13480
  return FAIL;
@@ -12268,21 +13500,27 @@ function assemble(t2, prog, cfg) {
12268
13500
  }
12269
13501
  function dispatchBranch(child, usesRouted) {
12270
13502
  if (!usesRouted) {
12271
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
12272
- const mark = saveTriviaMark(ctx);
13503
+ return (input, _pos, selEnd, key, ctx) => {
13504
+ const need = markCst(ctx);
13505
+ const mRaw = MRAW;
13506
+ const mTl = MTL;
13507
+ const mLv = MLV;
13508
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13509
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13510
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13511
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
12273
13512
  const v = child(input, selEnd, ctx);
12274
13513
  if (v === FAIL) {
12275
- rollbackTrivia(ctx, mark);
13514
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12276
13515
  ctx._fc = true;
12277
13516
  return FAIL;
12278
13517
  }
12279
13518
  return [key, v];
12280
13519
  };
12281
13520
  }
12282
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13521
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
12283
13522
  const savedRouted = ctx._routed;
12284
- rollbackTrivia(ctx, selectorMark);
12285
- const mark = saveTriviaMark(ctx);
13523
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12286
13524
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
12287
13525
  let v;
12288
13526
  try {
@@ -12291,7 +13529,7 @@ function assemble(t2, prog, cfg) {
12291
13529
  ctx._routed = savedRouted;
12292
13530
  }
12293
13531
  if (v === FAIL) {
12294
- rollbackTrivia(ctx, mark);
13532
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12295
13533
  ctx._fc = true;
12296
13534
  return FAIL;
12297
13535
  }
@@ -12299,12 +13537,12 @@ function assemble(t2, prog, cfg) {
12299
13537
  };
12300
13538
  }
12301
13539
  function dispatchArmBlock(start, a0, a1, a2, a3, next) {
12302
- return (arm, input, pos, selEnd, key, selectorMark, ctx) => {
12303
- if (arm === start) return a0(input, pos, selEnd, key, selectorMark, ctx);
12304
- if (arm === start + 1) return a1(input, pos, selEnd, key, selectorMark, ctx);
12305
- if (arm === start + 2) return a2(input, pos, selEnd, key, selectorMark, ctx);
12306
- if (arm === start + 3) return a3(input, pos, selEnd, key, selectorMark, ctx);
12307
- return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, selectorMark, ctx);
13540
+ return (arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
13541
+ if (arm === start) return a0(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13542
+ if (arm === start + 1) return a1(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13543
+ if (arm === start + 2) return a2(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13544
+ if (arm === start + 3) return a3(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13545
+ return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12308
13546
  };
12309
13547
  }
12310
13548
  function trackLinesInto(ctx, input, end) {
@@ -12321,20 +13559,68 @@ function assemble(t2, prog, cfg) {
12321
13559
  if (done !== void 0) return done;
12322
13560
  const flight = inFlight.get(ip);
12323
13561
  if (flight !== void 0) return flight.fwd;
13562
+ const selected = HYBRID?.byIp[ip];
13563
+ if (selected !== void 0) {
13564
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
13565
+ memo.set(ip, piece2);
13566
+ reached.add(ip);
13567
+ return piece2;
13568
+ }
12324
13569
  let target;
12325
13570
  const fwd = (input, pos, ctx) => target(input, pos, ctx);
12326
13571
  const holder = { fwd, set: (p) => {
12327
13572
  target = p;
12328
13573
  } };
12329
13574
  inFlight.set(ip, holder);
12330
- const op = code[ip];
12331
- 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);
13575
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
12332
13576
  inFlight.delete(ip);
12333
13577
  holder.set(piece);
12334
13578
  memo.set(ip, piece);
12335
13579
  reached.add(ip);
12336
13580
  return piece;
12337
13581
  }
13582
+ let FIRST_DECIDED;
13583
+ let NODE_BODY;
13584
+ const DECIDED = (_input, pos) => {
13585
+ EC.e = pos;
13586
+ return null;
13587
+ };
13588
+ function lookaheadLedNode(ip) {
13589
+ const op = code[ip];
13590
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
13591
+ if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
13592
+ const body = code[ip + 2];
13593
+ const bop = code[body];
13594
+ if (bop !== OP_SEQ && bop !== OP_SEQV && bop !== OP_SEQX) return void 0;
13595
+ const base = bop === OP_SEQX ? body + 3 : body + 2;
13596
+ if (code[bop === OP_SEQX ? body + 2 : body + 1] < 2) return void 0;
13597
+ const first = code[base];
13598
+ const negative = code[first] === OP_NOT;
13599
+ const terminal = negative ? scalarTerminalNotChild(code, first) : code[first] === OP_PEEK ? scalarTerminalPeekChild(code, first) : -1;
13600
+ if (terminal < 0) return void 0;
13601
+ const recognize = scalarFor(terminal);
13602
+ const xf = fx[code[first + 2]];
13603
+ FIRST_DECIDED = DECIDED;
13604
+ NODE_BODY = lower(body);
13605
+ const node2 = lower(ip);
13606
+ NODE_BODY = void 0;
13607
+ return negative ? (input, pos, ctx) => {
13608
+ if (recognize(input, pos) >= 0) {
13609
+ ctx._fe = pos;
13610
+ ctx._fx = xf;
13611
+ EC.e = pos;
13612
+ return FAIL;
13613
+ }
13614
+ return node2(input, pos, ctx);
13615
+ } : (input, pos, ctx) => {
13616
+ if (recognize(input, pos) < 0) {
13617
+ ctx._fe = pos;
13618
+ ctx._fx = xf;
13619
+ return FAIL;
13620
+ }
13621
+ return node2(input, pos, ctx);
13622
+ };
13623
+ }
12338
13624
  function lower(ip) {
12339
13625
  const op = code[ip];
12340
13626
  switch (op) {
@@ -12865,7 +14151,12 @@ function assemble(t2, prog, cfg) {
12865
14151
  }
12866
14152
  const child = link(code[ip + 1]);
12867
14153
  const xf = fx[code[ip + 2]];
14154
+ const gate = lookaheadClass(code[ip + 1]);
12868
14155
  return (input, pos, ctx) => {
14156
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14157
+ EC.e = pos;
14158
+ return null;
14159
+ }
12869
14160
  const need = markCst(ctx);
12870
14161
  const mRaw = MRAW;
12871
14162
  const mTl = MTL;
@@ -12874,8 +14165,10 @@ function assemble(t2, prog, cfg) {
12874
14165
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
12875
14166
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
12876
14167
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14168
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
12877
14169
  const v = child(input, pos, ctx);
12878
14170
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14171
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
12879
14172
  if (v === FAIL) {
12880
14173
  EC.e = pos;
12881
14174
  return null;
@@ -12886,9 +14179,29 @@ function assemble(t2, prog, cfg) {
12886
14179
  };
12887
14180
  }
12888
14181
  case OP_PEEK: {
14182
+ const scalarChild = scalarTerminalPeekChild(code, ip);
14183
+ if (scalarChild >= 0) {
14184
+ const recognize = scalarFor(scalarChild);
14185
+ const xf2 = fx[code[ip + 2]];
14186
+ return (input, pos, ctx) => {
14187
+ if (recognize(input, pos) < 0) {
14188
+ ctx._fe = pos;
14189
+ ctx._fx = xf2;
14190
+ return FAIL;
14191
+ }
14192
+ EC.e = pos;
14193
+ return null;
14194
+ };
14195
+ }
12889
14196
  const child = link(code[ip + 1]);
12890
14197
  const xf = fx[code[ip + 2]];
14198
+ const gate = lookaheadClass(code[ip + 1]);
12891
14199
  return (input, pos, ctx) => {
14200
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14201
+ ctx._fe = pos;
14202
+ ctx._fx = xf;
14203
+ return FAIL;
14204
+ }
12892
14205
  const need = markCst(ctx);
12893
14206
  const mRaw = MRAW;
12894
14207
  const mTl = MTL;
@@ -12897,8 +14210,10 @@ function assemble(t2, prog, cfg) {
12897
14210
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
12898
14211
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
12899
14212
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14213
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
12900
14214
  const v = child(input, pos, ctx);
12901
14215
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14216
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
12902
14217
  if (v === FAIL) {
12903
14218
  ctx._fe = pos;
12904
14219
  ctx._fx = xf;
@@ -12910,8 +14225,14 @@ function assemble(t2, prog, cfg) {
12910
14225
  }
12911
14226
  case OP_OPT: {
12912
14227
  const child = link(code[ip + 1]);
14228
+ const gate = lookaheadClass(code[ip + 1]);
14229
+ const childClean = CLEAN(code[ip + 1]);
12913
14230
  return (input, pos, ctx) => {
12914
- const need = markCst(ctx);
14231
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
14232
+ EC.e = pos;
14233
+ return null;
14234
+ }
14235
+ const need = !childClean && markCst(ctx);
12915
14236
  const mRaw = MRAW;
12916
14237
  const mTl = MTL;
12917
14238
  const mLv = MLV;
@@ -13109,6 +14430,9 @@ function assemble(t2, prog, cfg) {
13109
14430
  const projection = reducer < 0 ? ~reducer : -1;
13110
14431
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
13111
14432
  const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
14433
+ const decided = FIRST_DECIDED;
14434
+ FIRST_DECIDED = void 0;
14435
+ const linkFirst = () => decided ?? link(code[base]);
13112
14436
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
13113
14437
  if (count === 1) return (input, cur, ctx, values, inherited) => {
13114
14438
  cur = r0(input, cur, ctx, inherited);
@@ -13154,7 +14478,7 @@ function assemble(t2, prog, cfg) {
13154
14478
  };
13155
14479
  };
13156
14480
  if (REC) {
13157
- const first2 = link(code[base]);
14481
+ const first2 = linkFirst();
13158
14482
  const firstSync = sentinelFor(code[base + n]);
13159
14483
  const runnerAt = (i) => {
13160
14484
  const sync = sentinelFor(code[base + n + i]);
@@ -13190,13 +14514,13 @@ function assemble(t2, prog, cfg) {
13190
14514
  const bindRunners = (start) => {
13191
14515
  const count = Math.min(4, n - start);
13192
14516
  const at = (offset) => runnerAt(start + offset);
13193
- const never = () => -1;
14517
+ const never2 = () => -1;
13194
14518
  return runnerBlock(
13195
14519
  count,
13196
14520
  at(0),
13197
- count > 1 ? at(1) : never,
13198
- count > 2 ? at(2) : never,
13199
- count > 3 ? at(3) : never,
14521
+ count > 1 ? at(1) : never2,
14522
+ count > 2 ? at(2) : never2,
14523
+ count > 3 ? at(3) : never2,
13200
14524
  start + count < n ? bindRunners(start + count) : void 0
13201
14525
  );
13202
14526
  };
@@ -13246,15 +14570,31 @@ function assemble(t2, prog, cfg) {
13246
14570
  let hasAdj = false;
13247
14571
  for (let i = 1; i < n; i++) {
13248
14572
  const kidIp = code[base + i];
13249
- if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
14573
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp) || holdsGap(code, k, base, n, i, NULLABLE)) {
13250
14574
  hasAdj = true;
13251
14575
  break;
13252
14576
  }
13253
14577
  }
13254
14578
  if (hasAdj) {
13255
- const first2 = link(code[base]);
14579
+ const first2 = linkFirst();
13256
14580
  const runnerAt = (i) => {
13257
14581
  const kidIp = code[base + i];
14582
+ if (holdsGap(code, k, base, n, i, NULLABLE)) {
14583
+ const kid = link(kidIp);
14584
+ return (input, cur, ctx) => {
14585
+ if (ctx.trivia === void 0) {
14586
+ const v2 = kid(input, cur, ctx);
14587
+ if (v2 === FAIL) return -1;
14588
+ TERMV = v2;
14589
+ return EC.e;
14590
+ }
14591
+ const scanEnd = skipTrivia(input, cur, ctx);
14592
+ const v = kid(input, scanEnd, ctx);
14593
+ if (v === FAIL) return -1;
14594
+ TERMV = v;
14595
+ return scanEnd;
14596
+ };
14597
+ }
13258
14598
  if (code[kidIp] !== OP_ADJ) {
13259
14599
  const kid = link(kidIp);
13260
14600
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -13279,13 +14619,13 @@ function assemble(t2, prog, cfg) {
13279
14619
  const bindRunners = (start) => {
13280
14620
  const count = Math.min(4, n - start);
13281
14621
  const at = (offset) => runnerAt(start + offset);
13282
- const never = () => -1;
14622
+ const never2 = () => -1;
13283
14623
  return runnerBlock(
13284
14624
  count,
13285
14625
  at(0),
13286
- count > 1 ? at(1) : never,
13287
- count > 2 ? at(2) : never,
13288
- count > 3 ? at(3) : never,
14626
+ count > 1 ? at(1) : never2,
14627
+ count > 2 ? at(2) : never2,
14628
+ count > 3 ? at(3) : never2,
13289
14629
  start + count < n ? bindRunners(start + count) : void 0
13290
14630
  );
13291
14631
  };
@@ -13322,7 +14662,7 @@ function assemble(t2, prog, cfg) {
13322
14662
  };
13323
14663
  }
13324
14664
  if (n === 1) {
13325
- const k0 = link(code[base]);
14665
+ const k0 = linkFirst();
13326
14666
  if (fused) {
13327
14667
  return (input, pos, ctx) => {
13328
14668
  const v = k0(input, pos, ctx);
@@ -13344,7 +14684,7 @@ function assemble(t2, prog, cfg) {
13344
14684
  };
13345
14685
  }
13346
14686
  if (n === 2) {
13347
- const k0 = link(code[base]), k1 = link(code[base + 1]);
14687
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
13348
14688
  if (fused) {
13349
14689
  return (input, pos, ctx) => {
13350
14690
  const v0 = k0(input, pos, ctx);
@@ -13375,7 +14715,7 @@ function assemble(t2, prog, cfg) {
13375
14715
  };
13376
14716
  }
13377
14717
  if (n === 3) {
13378
- const k0 = link(code[base]), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
14718
+ const k0 = linkFirst(), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
13379
14719
  if (fused) {
13380
14720
  return (input, pos, ctx) => {
13381
14721
  const v0 = k0(input, pos, ctx);
@@ -13469,7 +14809,7 @@ function assemble(t2, prog, cfg) {
13469
14809
  start + count < n ? bind(start + count) : void 0
13470
14810
  );
13471
14811
  };
13472
- const first = link(code[base]);
14812
+ const first = linkFirst();
13473
14813
  const tail = bind(1);
13474
14814
  const runDirectTerms = (input, pos, ctx, values) => {
13475
14815
  const v0 = first(input, pos, ctx);
@@ -13508,6 +14848,8 @@ function assemble(t2, prog, cfg) {
13508
14848
  const n = code[ip + 2];
13509
14849
  const choiceFx = fx[code[ip + 3]];
13510
14850
  const base = ip + 4;
14851
+ for (let i = 0; i < n; i++) link(code[base + i]);
14852
+ const armsClean = CLEAN(ip);
13511
14853
  if (table.exclusive) {
13512
14854
  const ascii = table.ascii;
13513
14855
  const hi = table.hi;
@@ -13647,7 +14989,7 @@ function assemble(t2, prog, cfg) {
13647
14989
  if (n === 3) addGate(g2, 4);
13648
14990
  return (input, pos, ctx) => {
13649
14991
  const c = lead(input, pos);
13650
- const need = markCst(ctx);
14992
+ const need = !armsClean && markCst(ctx);
13651
14993
  const mRaw = MRAW;
13652
14994
  const mTl = MTL;
13653
14995
  const mLv = MLV;
@@ -13717,6 +15059,11 @@ function assemble(t2, prog, cfg) {
13717
15059
  }
13718
15060
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13719
15061
  }
15062
+ if (prev === 0) {
15063
+ ctx._fe = pos;
15064
+ ctx._fx = choiceFx;
15065
+ return FAIL;
15066
+ }
13720
15067
  if (best === pos && prev < 1) acc = accSet(e0, acc);
13721
15068
  if (best === pos && prev < 2) acc = accSet(e1, acc);
13722
15069
  if (best === pos && n === 3 && prev < 3) acc = accSet(e2, acc);
@@ -13859,7 +15206,7 @@ function assemble(t2, prog, cfg) {
13859
15206
  if (pn !== 0) {
13860
15207
  return (input, pos, ctx) => {
13861
15208
  const c = lead(input, pos);
13862
- const need = markCst(ctx);
15209
+ const need = !armsClean && markCst(ctx);
13863
15210
  const mRaw = MRAW;
13864
15211
  const mTl = MTL;
13865
15212
  const mLv = MLV;
@@ -13916,7 +15263,7 @@ function assemble(t2, prog, cfg) {
13916
15263
  }
13917
15264
  return (input, pos, ctx) => {
13918
15265
  const c = lead(input, pos);
13919
- const need = markCst(ctx);
15266
+ const need = !armsClean && markCst(ctx);
13920
15267
  const mRaw = MRAW;
13921
15268
  const mTl = MTL;
13922
15269
  const mLv = MLV;
@@ -13964,7 +15311,7 @@ function assemble(t2, prog, cfg) {
13964
15311
  }
13965
15312
  return (input, pos, ctx) => {
13966
15313
  const c = lead(input, pos);
13967
- const need = markCst(ctx);
15314
+ const need = !armsClean && markCst(ctx);
13968
15315
  const mRaw = MRAW;
13969
15316
  const mTl = MTL;
13970
15317
  const mLv = MLV;
@@ -14018,6 +15365,21 @@ function assemble(t2, prog, cfg) {
14018
15365
  return lit(input, pos, ctx);
14019
15366
  };
14020
15367
  }
15368
+ case OP_RGATE: {
15369
+ const cls = cc[code[ip + 1]];
15370
+ const xf = fx[code[ip + 3]];
15371
+ const child = link(code[ip + 2]);
15372
+ if (cfg.tolerant || cfg.probe) return child;
15373
+ return (input, pos, ctx) => {
15374
+ const item = ctx._routed;
15375
+ if (item !== void 0 && item.span.start === pos && !classHas2(cls, lead(input, item.span.end))) {
15376
+ ctx._fe = item.span.end;
15377
+ ctx._fx = xf;
15378
+ return FAIL;
15379
+ }
15380
+ return child(input, pos, ctx);
15381
+ };
15382
+ }
14021
15383
  case OP_ARMGATE: {
14022
15384
  const pred = fns[code[ip + 1]];
14023
15385
  const child = link(code[ip + 2]);
@@ -14025,7 +15387,7 @@ function assemble(t2, prog, cfg) {
14025
15387
  return (input, pos, ctx) => {
14026
15388
  if (!pred(ctx.state)) {
14027
15389
  ctx._fc = false;
14028
- ctx._fe = pos;
15390
+ ctx._fe = -1;
14029
15391
  ctx._fx = xf;
14030
15392
  return FAIL;
14031
15393
  }
@@ -14086,6 +15448,7 @@ function assemble(t2, prog, cfg) {
14086
15448
  const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
14087
15449
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
14088
15450
  const skipBeforeFirst = sepIp < 0 && min === 0;
15451
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
14089
15452
  if (REC) {
14090
15453
  const itemFx2 = fx[code[ip + 6]];
14091
15454
  const sepSent = sentinelFor(code[ip + 7]);
@@ -14182,6 +15545,8 @@ function assemble(t2, prog, cfg) {
14182
15545
  const out = collect ? [] : void 0;
14183
15546
  const hasTrivia = ctx.trivia !== void 0;
14184
15547
  const needMark = rollbackNeeded(ctx);
15548
+ const markLater = needMark && (!itemClean || hasTrivia);
15549
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
14185
15550
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
14186
15551
  let cur = pos;
14187
15552
  let count = 0;
@@ -14189,14 +15554,15 @@ function assemble(t2, prog, cfg) {
14189
15554
  if (max >= 0 && count >= max) break;
14190
15555
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
14191
15556
  if (count >= min && sep === void 0 && !hasTrivia && gateItems && !itemMayStart(input, cur)) break;
14192
- if (needMark) markCst(ctx);
14193
- const mRaw = needMark ? MRAW : 0;
14194
- const mTl = needMark ? MTL : 0;
14195
- const mLv = needMark ? MLV : 0;
14196
- const mFl = needMark ? ctx._fields?.length ?? 0 : 0;
14197
- const mEr = needMark ? ctx._errors?.length ?? 0 : 0;
14198
- const mLog = needMark ? ctx._triviaLog?.length ?? 0 : 0;
14199
- const mRoot = needMark ? ctx._rootTriviaLog?.length ?? 0 : 0;
15557
+ const markIt = count > 0 ? markLater : markFirst;
15558
+ if (markIt) markCst(ctx);
15559
+ const mRaw = markIt ? MRAW : 0;
15560
+ const mTl = markIt ? MTL : 0;
15561
+ const mLv = markIt ? MLV : 0;
15562
+ const mFl = markIt ? ctx._fields?.length ?? 0 : 0;
15563
+ const mEr = markIt ? ctx._errors?.length ?? 0 : 0;
15564
+ const mLog = markIt ? ctx._triviaLog?.length ?? 0 : 0;
15565
+ const mRoot = markIt ? ctx._rootTriviaLog?.length ?? 0 : 0;
14200
15566
  let itemStart = cur;
14201
15567
  let sepEnd = -1;
14202
15568
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -14208,7 +15574,7 @@ function assemble(t2, prog, cfg) {
14208
15574
  if (sepLeads) LEAD.at = cur;
14209
15575
  const sv = sep(input, sp, ctx);
14210
15576
  if (sv === FAIL) {
14211
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15577
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14212
15578
  if (committed3(ctx)) return FAIL;
14213
15579
  break;
14214
15580
  }
@@ -14219,25 +15585,25 @@ function assemble(t2, prog, cfg) {
14219
15585
  itemStart = skipTrivia(input, itemStart, ctx);
14220
15586
  }
14221
15587
  if (itemStart >= input.length && viaRepItem) {
14222
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15588
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14223
15589
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14224
15590
  break;
14225
15591
  }
14226
15592
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
14227
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15593
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14228
15594
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14229
15595
  break;
14230
15596
  }
14231
15597
  ctx._fc = false;
14232
15598
  const v = child(input, itemStart, ctx);
14233
15599
  if (v === FAIL) {
14234
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15600
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14235
15601
  if (committed3(ctx)) return FAIL;
14236
15602
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14237
15603
  break;
14238
15604
  }
14239
15605
  if (EC.e === itemStart && viaRepItem) {
14240
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15606
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14241
15607
  break;
14242
15608
  }
14243
15609
  if (out !== void 0) out.push(v);
@@ -14311,7 +15677,14 @@ function assemble(t2, prog, cfg) {
14311
15677
  const runArm = n === 0 ? void 0 : bindArms(0);
14312
15678
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
14313
15679
  return (input, pos, ctx) => {
14314
- const selectorMark = saveTriviaMark(ctx);
15680
+ const need = markCst(ctx);
15681
+ const mRaw = MRAW;
15682
+ const mTl = MTL;
15683
+ const mLv = MLV;
15684
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
15685
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
15686
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
15687
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14315
15688
  const selVal = selector(input, pos, ctx);
14316
15689
  if (selVal === FAIL) return FAIL;
14317
15690
  const selEnd = EC.e;
@@ -14323,9 +15696,9 @@ function assemble(t2, prog, cfg) {
14323
15696
  ctx._fx = expected;
14324
15697
  return FAIL;
14325
15698
  }
14326
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
15699
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14327
15700
  }
14328
- return runArm(arm, input, pos, selEnd, key, selectorMark, ctx);
15701
+ return runArm(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14329
15702
  };
14330
15703
  }
14331
15704
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -14361,7 +15734,8 @@ function assemble(t2, prog, cfg) {
14361
15734
  return nd;
14362
15735
  };
14363
15736
  }
14364
- const child = link(code[ip + 2]);
15737
+ const child = NODE_BODY ?? link(code[ip + 2]);
15738
+ NODE_BODY = void 0;
14365
15739
  const proj = code[ip + 4];
14366
15740
  const buildIdx = code[ip + 1];
14367
15741
  const type = k[code[ip + 5]];
@@ -14385,6 +15759,30 @@ function assemble(t2, prog, cfg) {
14385
15759
  if (build !== void 0 && proj < 0 && flags === 18) {
14386
15760
  return childrenOnlyFieldsBuildNode(child, build);
14387
15761
  }
15762
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
15763
+ return passCollapseNode(child, build, flags === 32);
15764
+ }
15765
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
15766
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(closureLabels.at(code[ip + 2]).tri, trivia2);
15767
+ if (build !== void 0 && gated !== void 0 && triviaLead !== void 0) {
15768
+ const classic = flags === 32 ? collapseBuildNode(child, build) : childrenOnlyCollapseBuildNode(child, build);
15769
+ return gatedPassCollapseNode(
15770
+ [
15771
+ ...gated.leads.map((g) => cc[code[g + 1]]),
15772
+ resolveClass(encodeClassSpec([
15773
+ ...triviaLead,
15774
+ ...gated.lits.map((i) => {
15775
+ const c = k[i].codePointAt(0);
15776
+ return { lo: c, hi: c };
15777
+ })
15778
+ ]))
15779
+ ],
15780
+ link(gated.last),
15781
+ classic,
15782
+ build,
15783
+ flags === 32
15784
+ );
15785
+ }
14388
15786
  if (build !== void 0 && proj < 0 && flags === 32) {
14389
15787
  return collapseBuildNode(child, build);
14390
15788
  }
@@ -14431,7 +15829,7 @@ function assemble(t2, prog, cfg) {
14431
15829
  if (v === FAIL) return FAIL;
14432
15830
  const end = EC.e;
14433
15831
  const span = tracked ? spanLines(ctx, pos, end) : { start: pos, end };
14434
- const st = readsState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
15832
+ const st = readsState ? ctx.state : void 0;
14435
15833
  let nd;
14436
15834
  if (unwrap && kids.length === 1) {
14437
15835
  nd = unwrapChild(kids[0]);
@@ -14444,10 +15842,10 @@ function assemble(t2, prog, cfg) {
14444
15842
  ) {
14445
15843
  nd = kids[0];
14446
15844
  } else if (proj >= 0) {
14447
- 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);
15845
+ nd = hostCst && host !== void 0 ? host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags) : projectChild(kids, proj, type);
14448
15846
  } else if (build !== void 0) {
14449
15847
  if (hostCst && host !== void 0) {
14450
- nd = host(type, kids, fieldMap, span, rawKids, tlog, readsState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0, tags);
15848
+ nd = host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags);
14451
15849
  } else {
14452
15850
  nd = build(kids, fieldMap, span, rawKids, captureWide ? tlog : EMPTY_TL2, st);
14453
15851
  }
@@ -14498,9 +15896,7 @@ function assemble(t2, prog, cfg) {
14498
15896
  let emitRefusal;
14499
15897
  let emitReached;
14500
15898
  {
14501
- const extraIps = [];
14502
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
14503
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
15899
+ const extraIps = assemblyExtraIps(prog);
14504
15900
  const roots = [...Object.values(prog.rules), ...extraIps];
14505
15901
  for (const ip of reachableSites(code, roots)) {
14506
15902
  if (code[ip] === OP_DISPATCH) {
@@ -14535,6 +15931,8 @@ function assemble(t2, prog, cfg) {
14535
15931
  }
14536
15932
  const notChild = scalarTerminalNotChild(code, ip);
14537
15933
  if (notChild >= 0) scalarFor(notChild);
15934
+ const peekChild = scalarTerminalPeekChild(code, ip);
15935
+ if (peekChild >= 0) scalarFor(peekChild);
14538
15936
  }
14539
15937
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
14540
15938
  if (pre !== void 0) {
@@ -14593,9 +15991,12 @@ function assemble(t2, prog, cfg) {
14593
15991
  adjacencyHolds,
14594
15992
  t2.lexPrograms,
14595
15993
  LEAD,
14596
- triviaFieldCapture
15994
+ triviaFieldCapture,
15995
+ skipDeferredTrivia,
15996
+ collapseEmpty
14597
15997
  );
14598
15998
  emitReached = new Set(pre.reached);
15999
+ if (emitted.ext !== void 0) HYBRID = emitted;
14599
16000
  }
14600
16001
  try {
14601
16002
  if (emitted !== void 0) throw new ServedByBuild();
@@ -14677,7 +16078,9 @@ function assemble(t2, prog, cfg) {
14677
16078
  adjacencyHolds,
14678
16079
  t2.lexPrograms,
14679
16080
  LEAD,
14680
- triviaFieldCapture
16081
+ triviaFieldCapture,
16082
+ skipDeferredTrivia,
16083
+ collapseEmpty
14681
16084
  );
14682
16085
  emitReached = em.reached;
14683
16086
  } catch (e) {
@@ -14688,7 +16091,7 @@ function assemble(t2, prog, cfg) {
14688
16091
  }
14689
16092
  function pieceAt(ip) {
14690
16093
  const em = emitted;
14691
- if (em !== void 0) {
16094
+ if (em !== void 0 && HYBRID === void 0) {
14692
16095
  const p = em.byIp[ip];
14693
16096
  if (p === void 0) throw new Error(`table emitter: no emitted body for site ${ip}`);
14694
16097
  return p;
@@ -14718,6 +16121,37 @@ function assemble(t2, prog, cfg) {
14718
16121
  }
14719
16122
  const scans = scansArr;
14720
16123
  const scanSkip = (prog.scanSkip ?? []).map((set) => set.map((r) => subtreeComb(r)));
16124
+ if (HYBRID !== void 0) {
16125
+ const em = HYBRID;
16126
+ em.bind(
16127
+ (s) => {
16128
+ const saved = SCAN;
16129
+ SCAN = s;
16130
+ return saved;
16131
+ },
16132
+ em.ext.map((ip) => link(ip))
16133
+ );
16134
+ const pieces2 = {};
16135
+ for (const [name, entryIp] of Object.entries(prog.rules)) {
16136
+ pieces2[name] = em.pieces[name] ?? link(entryIp);
16137
+ }
16138
+ for (const ip of emitReached) reached.add(ip);
16139
+ return {
16140
+ pieces: pieces2,
16141
+ end: () => EC.e,
16142
+ begin: (ctx) => {
16143
+ begin(ctx);
16144
+ em.begin(ctx);
16145
+ },
16146
+ finish: () => {
16147
+ em.finish();
16148
+ finish();
16149
+ },
16150
+ scanSkip,
16151
+ reached,
16152
+ emitRefusal: void 0
16153
+ };
16154
+ }
14721
16155
  if (emitted !== void 0) {
14722
16156
  const em = emitted;
14723
16157
  return {
@@ -14753,6 +16187,15 @@ function assemble(t2, prog, cfg) {
14753
16187
  }
14754
16188
  return { pieces, end: () => EC.e, begin, finish, scanSkip, reached, emitRefusal };
14755
16189
  }
16190
+ var SITE_COUNTS;
16191
+ function countedPiece(piece, ip) {
16192
+ const counts = SITE_COUNTS;
16193
+ if (counts === void 0) return piece;
16194
+ return (input, pos, ctx) => {
16195
+ counts[ip]++;
16196
+ return piece(input, pos, ctx);
16197
+ };
16198
+ }
14756
16199
  var AssemblyCache = class {
14757
16200
  t;
14758
16201
  prog;
@@ -14904,7 +16347,7 @@ function emitClassPool(classes) {
14904
16347
  if (classes.length < 2) return array;
14905
16348
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
14906
16349
  if (delimiter === void 0) return array;
14907
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16350
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
14908
16351
  return split.length < array.length ? split : array;
14909
16352
  }
14910
16353
  function emitConst(v) {
@@ -14955,9 +16398,7 @@ function emitDispatchSpec(d) {
14955
16398
  function emitAssemblies(prog, cfgs) {
14956
16399
  if (cfgs.length === 0) return ["a:[],"];
14957
16400
  const t2 = resolveTable(prog);
14958
- const extraIps = [];
14959
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
14960
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
16401
+ const extraIps = assemblyExtraIps(prog);
14961
16402
  const out = [];
14962
16403
  const seen = /* @__PURE__ */ new Set();
14963
16404
  for (const cfg of cfgs) {
@@ -14966,7 +16407,7 @@ function emitAssemblies(prog, cfgs) {
14966
16407
  seen.add(key);
14967
16408
  let em;
14968
16409
  try {
14969
- em = emitAssemblySource(t2, prog, cfg, extraIps, true);
16410
+ em = emitAssemblySource(t2, prog, cfg, extraIps, true, cfg.select);
14970
16411
  } catch (e) {
14971
16412
  if (e instanceof Unemittable) continue;
14972
16413
  throw e;
@@ -16513,339 +17954,85 @@ function reportDuplication(opt, analyze) {
16513
17954
  if (level === "error") throw new Error(`parseman: ${duplicationFindingCount(report)} duplication/overlap finding(s)
16514
17955
  ${lines2.join("\n")}`);
16515
17956
  for (const l of lines2) console.warn(l);
16516
- }
16517
- return report;
16518
- }
16519
- function runDuplicationDiagnostic(combinator, opt) {
16520
- return reportDuplication(opt, (o) => analyzeDuplication(combinator, o));
16521
- }
16522
- function runDuplicationDiagnosticRules(ruleMap, opt) {
16523
- return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
16524
- }
16525
-
16526
- // src/table/compile-rule-map.ts
16527
- function resolveHostMode(ruleMap, explicit) {
16528
- return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
16529
- }
16530
- function resolveTrackLines(ruleMap, explicit) {
16531
- return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
16532
- }
16533
- function withAmbient(ruleMap, opts) {
16534
- if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
16535
- const wrappers = /* @__PURE__ */ new Map();
16536
- return ruleMap.map(([name, rule2]) => {
16537
- if (rule2._meta.isTrivia) return [name, rule2];
16538
- const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
16539
- const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
16540
- if (!addTrivia && !addScanSkip) return [name, rule2];
16541
- let wrapped = wrappers.get(rule2);
16542
- if (wrapped === void 0) {
16543
- wrapped = {
16544
- ...rule2,
16545
- _meta: {
16546
- ...rule2._meta,
16547
- ...addTrivia ? { grammarTrivia: opts.trivia } : {},
16548
- ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
16549
- }
16550
- };
16551
- wrappers.set(rule2, wrapped);
16552
- }
16553
- return [name, wrapped];
16554
- });
16555
- }
16556
- function compileRuleMapRunnable(ruleMap, opts = {}) {
16557
- const encoded = encodeForRun(ruleMap, opts);
16558
- if (encoded === null) return null;
16559
- const { prog, hostMode, plan } = encoded;
16560
- const artifact = closureArtifact(prog);
16561
- const reflection = collectGrammarReflection(ruleMap);
16562
- return {
16563
- keys: ruleMap.map(([key]) => key),
16564
- hostMode,
16565
- hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule2]) => hasDirectBuildDef(rule2)),
16566
- reflection,
16567
- ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16568
- // Reflection rides on the map's metadata prototype from birth. Only `compile()`
16569
- // asks to specialise; every other caller runs the closure artifact.
16570
- rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
16571
- prog: artifact
16572
- };
16573
- }
16574
- function encodeForRun(ruleMap, opts) {
16575
- runDuplicationDiagnosticRules(ruleMap, opts.duplication);
16576
- const encodeMap = withAmbient(ruleMap, opts);
16577
- const plan = opts.coverage === true ? buildGrammarPlan(
16578
- encodeMap.map(([, rule2]) => rule2),
16579
- Object.fromEntries(encodeMap.filter(([, rule2]) => rule2._def.tag !== "lazy"))
16580
- ) : void 0;
16581
- const hostMode = resolveHostMode(ruleMap, opts.hostMode);
16582
- const settings = {
16583
- hostMode,
16584
- ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
16585
- ...opts.recovery === true ? { recovery: true } : {},
16586
- ...plan === void 0 ? {} : { coverage: plan }
16587
- };
16588
- try {
16589
- const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
16590
- return { prog, fnSrcs, hostMode, plan };
16591
- } catch (e) {
16592
- opts.refusals?.push(e instanceof Error ? e.message : String(e));
16593
- return null;
16594
- }
16595
- }
16596
-
16597
- // src/compiler/value-usage.ts
16598
- function markUnusedValues(root) {
16599
- const seenConsumed = /* @__PURE__ */ new WeakSet();
16600
- const seenUnconsumed = /* @__PURE__ */ new WeakSet();
16601
- const mark = (def, consumed) => {
16602
- if (consumed) def.valueUnused = false;
16603
- else if (def.valueUnused !== false) def.valueUnused = true;
16604
- };
16605
- const visit = (c, consumed) => {
16606
- const seen = consumed ? seenConsumed : seenUnconsumed;
16607
- if (seen.has(c)) return;
16608
- seen.add(c);
16609
- const def = c._def;
16610
- switch (def.tag) {
16611
- case "many":
16612
- case "oneOrMore":
16613
- mark(def, consumed);
16614
- visit(def.parser, consumed);
16615
- return;
16616
- case "optional":
16617
- visit(def.parser, consumed);
16618
- return;
16619
- case "sequence":
16620
- mark(def, consumed);
16621
- for (const p of def.parsers) visit(p, consumed);
16622
- return;
16623
- case "choice":
16624
- for (const p of def.parsers) visit(p, consumed);
16625
- return;
16626
- case "dispatch":
16627
- visit(def.selector, consumed);
16628
- for (const entry of def.cases) visit(entry.parser, consumed);
16629
- if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
16630
- if (def.otherwise) visit(def.otherwise, consumed);
16631
- return;
16632
- case "node":
16633
- visit(def.parser, false);
16634
- return;
16635
- case "transform":
16636
- visit(def.parser, true);
16637
- return;
16638
- case "field":
16639
- visit(def.parser, true);
16640
- return;
16641
- case "sepBy":
16642
- visit(def.parser, true);
16643
- visit(def.separator, false);
16644
- return;
16645
- case "not":
16646
- case "peek":
16647
- visit(def.parser, false);
16648
- return;
16649
- case "grammar":
16650
- visit(def.parser, consumed);
16651
- if (def.triviaParser) visit(def.triviaParser, false);
16652
- return;
16653
- case "recover":
16654
- visit(def.parser, consumed);
16655
- visit(def.sentinel, false);
16656
- return;
16657
- case "token":
16658
- visit(def.parser, false);
16659
- return;
16660
- case "label":
16661
- case "trivia":
16662
- case "attempt":
16663
- case "withCtx":
16664
- case "expect":
16665
- visit(def.parser, consumed);
16666
- return;
16667
- case "leaf":
16668
- visit(def.parser, true);
16669
- return;
16670
- case "lazy":
16671
- return;
16672
- default:
16673
- return;
16674
- }
16675
- };
16676
- const resolveRoot = (c) => {
16677
- const guard = /* @__PURE__ */ new Set();
16678
- let cur = c;
16679
- while (!guard.has(cur)) {
16680
- const d = cur._def;
16681
- if (d.tag === "grammar") {
16682
- guard.add(cur);
16683
- cur = d.parser;
16684
- continue;
16685
- }
16686
- if (d.tag !== "lazy") return cur;
16687
- guard.add(cur);
16688
- try {
16689
- cur = d.thunk();
16690
- } catch {
16691
- return c;
16692
- }
16693
- }
16694
- return cur;
16695
- };
16696
- visit(resolveRoot(root), true);
17957
+ }
17958
+ return report;
17959
+ }
17960
+ function runDuplicationDiagnostic(combinator, opt) {
17961
+ return reportDuplication(opt, (o) => analyzeDuplication(combinator, o));
17962
+ }
17963
+ function runDuplicationDiagnosticRules(ruleMap, opt) {
17964
+ return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
16697
17965
  }
16698
17966
 
16699
- // src/combinators/grammar.ts
16700
- function annotateResultLines(result, index) {
16701
- const annotated = { ...result, span: annotateSpan(result.span, index) };
16702
- const errors = annotated.errors;
16703
- if (errors) {
16704
- ;
16705
- annotated.errors = errors.map((error) => ({
16706
- ...error,
16707
- span: annotateSpan(error.span, index)
16708
- }));
16709
- }
16710
- return annotated;
17967
+ // src/table/compile-rule-map.ts
17968
+ function resolveHostMode(ruleMap, explicit) {
17969
+ return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
16711
17970
  }
16712
- function createParseLineContext(input, pos) {
16713
- const lineIndex = createLineIndex();
16714
- if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
16715
- return { lineIndex, lineScannedTo: pos };
17971
+ function resolveTrackLines(ruleMap, explicit) {
17972
+ return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
16716
17973
  }
16717
- var TRACK_LINES_ON = () => true;
16718
- var TRACK_LINES_OFF = () => false;
16719
- var TRACK_LINES_INHERIT = (ctx) => ctx?.trackLines === true;
16720
- function parser(opts, root) {
16721
- const clearTrivia = opts.trivia === null;
16722
- const opaqueRootCapture = opts.rootCapture === "opaque";
16723
- if (opaqueRootCapture && opts.trivia === void 0) {
16724
- throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
16725
- }
16726
- const scopeTrivia = clearTrivia ? void 0 : opts.trivia ?? void 0;
16727
- const scopeLabels = scopeTrivia?._meta?.triviaKindLabels;
16728
- const refuseUnclassified = scopeTrivia !== void 0 && !scopeTrivia._meta?.rootTriviaClassified && !opaqueRootCapture;
16729
- const forceCaptureTrivia = opts.captureTrivia === true;
16730
- const trackLinesPolicy = opts.trackLines === true ? "on" : opts.trackLines === false ? "off" : "inherit";
16731
- const trackLinesOf = trackLinesPolicy === "on" ? TRACK_LINES_ON : trackLinesPolicy === "off" ? TRACK_LINES_OFF : TRACK_LINES_INHERIT;
16732
- const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
16733
- const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
16734
- const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
16735
- const rootScalar = scalarOf(root);
16736
- const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
16737
- const parseScalar = scalarEligible ? (input, pos, ctx) => {
16738
- const savedTrivia = ctx.trivia;
16739
- const savedLabels = ctx.triviaKindLabels;
16740
- if (clearTrivia) {
16741
- ctx.trivia = void 0;
16742
- ctx.triviaKindLabels = void 0;
16743
- } else if (scopeTrivia !== void 0) {
16744
- ctx.trivia = scopeTrivia;
16745
- ctx.triviaKindLabels = scopeLabels;
16746
- }
16747
- const end = rootScalar(input, pos, ctx);
16748
- ctx.trivia = savedTrivia;
16749
- ctx.triviaKindLabels = savedLabels;
16750
- return end;
16751
- } : void 0;
16752
- let publicScalar;
16753
- const grammar = {
16754
- _tag: "grammar",
16755
- _meta: {
16756
- ...root._meta,
16757
- // Trivia classification describes this grammar's own active trivia
16758
- // scope. A directly nested grammar may have classified trivia of its
16759
- // own, but that must not advertise classification for this wrapper.
16760
- triviaKindLabels: void 0,
16761
- rootTriviaClassified: void 0,
16762
- ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
16763
- ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
16764
- },
16765
- _def: {
16766
- tag: "grammar",
16767
- parser: root,
16768
- triviaParser: scopeTrivia,
16769
- clearTrivia,
16770
- ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
16771
- ...opts.captureTrivia ? { captureTrivia: true } : {},
16772
- trackLines: opts.trackLines ?? false,
16773
- constructionTrackLines: trackLinesPolicy,
16774
- ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
16775
- },
16776
- _parseScalar: parseScalar,
16777
- parse(input, pos, _ctx) {
16778
- if (pos === void 0 && _ctx === void 0) {
16779
- publicScalar ??= scalarRootOf(grammar) ?? null;
16780
- if (publicScalar) {
16781
- const ctx2 = createParseContext();
16782
- const end = publicScalar(input, 0, ctx2);
16783
- if (end < 0) {
16784
- const at = ~end;
16785
- return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
16786
- }
16787
- return { ok: true, value: ctx2._sv, span: { start: 0, end } };
17974
+ function withAmbient(ruleMap, opts) {
17975
+ if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
17976
+ const wrappers = /* @__PURE__ */ new Map();
17977
+ return ruleMap.map(([name, rule2]) => {
17978
+ if (rule2._meta.isTrivia) return [name, rule2];
17979
+ const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
17980
+ const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
17981
+ if (!addTrivia && !addScanSkip) return [name, rule2];
17982
+ let wrapped = wrappers.get(rule2);
17983
+ if (wrapped === void 0) {
17984
+ wrapped = {
17985
+ ...rule2,
17986
+ _meta: {
17987
+ ...rule2._meta,
17988
+ ...addTrivia ? { grammarTrivia: opts.trivia } : {},
17989
+ ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
16788
17990
  }
16789
- }
16790
- if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
16791
- const trackLines = trackLinesOf(_ctx);
16792
- const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
16793
- const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
16794
- const ctx = _ctx === void 0 ? createParseContext() : { ..._ctx };
16795
- ctx.trackLines = trackLines;
16796
- if (lineIndex) ctx._lineIndex = lineIndex;
16797
- if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
16798
- if (clearTrivia) {
16799
- ctx.trivia = void 0;
16800
- ctx.triviaKindLabels = void 0;
16801
- } else if (scopeTrivia !== void 0) {
16802
- ctx.trivia = scopeTrivia;
16803
- if (scopeLabels) ctx.triviaKindLabels = scopeLabels;
16804
- }
16805
- if (forceCaptureTrivia || _ctx?.captureTrivia) ctx.captureTrivia = true;
16806
- if (ownCaptureMask !== void 0) ctx._triviaCaptureMask = ownCaptureMask;
16807
- else if (inheritCaptureMask) ctx._triviaCaptureMask = triviaKindMask(_ctx?.triviaKindLabels, captureKinds);
16808
- if (opaqueRootCapture) ctx._rootTriviaCapture = false;
16809
- const result = root.parse(input, pos ?? 0, ctx);
16810
- if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
16811
- _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
16812
- }
16813
- return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
17991
+ };
17992
+ wrappers.set(rule2, wrapped);
16814
17993
  }
17994
+ return [name, wrapped];
17995
+ });
17996
+ }
17997
+ function compileRuleMapRunnable(ruleMap, opts = {}) {
17998
+ const encoded = encodeForRun(ruleMap, opts);
17999
+ if (encoded === null) return null;
18000
+ const { prog, hostMode, plan } = encoded;
18001
+ const artifact = closureArtifact(prog);
18002
+ const reflection = collectGrammarReflection(ruleMap);
18003
+ return {
18004
+ keys: ruleMap.map(([key]) => key),
18005
+ hostMode,
18006
+ hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule2]) => hasDirectBuildDef(rule2)),
18007
+ reflection,
18008
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
18009
+ // Reflection rides on the map's metadata prototype from birth. Only `compile()`
18010
+ // asks to specialise; every other caller runs the closure artifact.
18011
+ rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
18012
+ prog: artifact
16815
18013
  };
16816
- return grammar;
16817
18014
  }
16818
- var _analyzed = /* @__PURE__ */ new WeakSet();
16819
- function parse(combinator, input, opts = {}) {
16820
- if (!_analyzed.has(combinator)) {
16821
- _analyzed.add(combinator);
16822
- markUnusedValues(combinator);
16823
- }
16824
- if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
16825
- return combinator.parse(input);
16826
- }
16827
- const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
16828
- const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
16829
- const lineIndex = lineContext?.lineIndex;
16830
- const _errors = opts.recover ? [] : void 0;
16831
- const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
16832
- const grammarTrivia = combinator._meta.grammarTrivia;
16833
- const grammarScanSkip = combinator._meta.grammarScanSkip;
16834
- const ctx = createParseContext();
16835
- ctx.trackLines = trackLines;
16836
- if (lineIndex) ctx._lineIndex = lineIndex;
16837
- if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
16838
- if (grammarTrivia !== void 0) {
16839
- ctx.trivia = grammarTrivia;
16840
- if (grammarTrivia._meta.triviaKindLabels) ctx.triviaKindLabels = grammarTrivia._meta.triviaKindLabels;
18015
+ function encodeForRun(ruleMap, opts) {
18016
+ runDuplicationDiagnosticRules(ruleMap, opts.duplication);
18017
+ const encodeMap = withAmbient(ruleMap, opts);
18018
+ const plan = opts.coverage === true ? buildGrammarPlan(
18019
+ encodeMap.map(([, rule2]) => rule2),
18020
+ Object.fromEntries(encodeMap.filter(([, rule2]) => rule2._def.tag !== "lazy"))
18021
+ ) : void 0;
18022
+ const hostMode = resolveHostMode(ruleMap, opts.hostMode);
18023
+ const settings = {
18024
+ hostMode,
18025
+ ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
18026
+ ...opts.recovery === true ? { recovery: true } : {},
18027
+ ...plan === void 0 ? {} : { coverage: plan }
18028
+ };
18029
+ try {
18030
+ const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
18031
+ return { prog, fnSrcs, hostMode, plan };
18032
+ } catch (e) {
18033
+ opts.refusals?.push(e instanceof Error ? e.message : String(e));
18034
+ return null;
16841
18035
  }
16842
- if (grammarScanSkip !== void 0) ctx.scanSkip = grammarScanSkip;
16843
- if (_errors !== void 0) ctx._errors = _errors;
16844
- if (_probe !== void 0) ctx._probe = _probe;
16845
- const result = combinator.parse(input, 0, ctx);
16846
- if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
16847
- const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
16848
- return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
16849
18036
  }
16850
18037
 
16851
18038
  // src/compiler/linker.ts
@@ -16945,7 +18132,7 @@ function analyzeGrammarGating(grammar, opts) {
16945
18132
  }
16946
18133
 
16947
18134
  // src/analysis/diagnose.ts
16948
- var isCombinator = (g) => typeof g === "object" && g !== null && "_def" in g;
18135
+ var isCombinator2 = (g) => typeof g === "object" && g !== null && "_def" in g;
16949
18136
  var isRuleEntries = (g) => Array.isArray(g);
16950
18137
  function diagnoseGrammar(grammar, opts) {
16951
18138
  const depth = degradationCaptureDepth();
@@ -16966,7 +18153,7 @@ function examinedNothing(d) {
16966
18153
  return d.summary.totalChoices === 0 && d.summary.unanalysable > 0;
16967
18154
  }
16968
18155
  function runAnalysis(grammar, opts) {
16969
- if (isCombinator(grammar)) return analyzeGating(grammar, opts);
18156
+ if (isCombinator2(grammar)) return analyzeGating(grammar, opts);
16970
18157
  if (isRuleEntries(grammar)) return analyzeGatingRules(grammar, opts);
16971
18158
  return analyzeGrammarGating(grammar, opts);
16972
18159
  }
@@ -17725,16 +18912,16 @@ function ownSource(fn) {
17725
18912
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
17726
18913
  }
17727
18914
  function compile(target, second, third) {
17728
- if (!isCombinator2(target)) return compileMap(target, second);
18915
+ if (!isCombinator3(target)) return compileMap(target, second);
17729
18916
  return compileRoot(target, second, third);
17730
18917
  }
17731
- function isCombinator2(x) {
18918
+ function isCombinator3(x) {
17732
18919
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
17733
18920
  }
17734
18921
  function compileMap(grammar, opts = {}) {
17735
18922
  const entries = [];
17736
18923
  for (const [key, value] of Object.entries(grammar)) {
17737
- if (!isCombinator2(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
18924
+ if (!isCombinator3(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
17738
18925
  if (value._def.tag === "lazy") {
17739
18926
  try {
17740
18927
  value._def.thunk();
@@ -18048,49 +19235,6 @@ function digestValue(value, prefix = "", options) {
18048
19235
  return sha.digest("hex");
18049
19236
  }
18050
19237
 
18051
- // src/combinators/attempt.ts
18052
- function containOption(options) {
18053
- if (options === void 0) return false;
18054
- for (const key of Object.keys(options)) {
18055
- if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
18056
- }
18057
- if (options.contain !== void 0 && typeof options.contain !== "boolean") {
18058
- throw new TypeError("attempt(): `contain` must be a boolean");
18059
- }
18060
- return options.contain === true;
18061
- }
18062
- function attempt(parser2, options) {
18063
- const contain = containOption(options);
18064
- const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
18065
- let failExpected;
18066
- return {
18067
- _tag: "attempt",
18068
- _meta: parser2._meta,
18069
- _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
18070
- parse(input, pos, ctx) {
18071
- if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
18072
- if (failExpected === void 0) {
18073
- const e = deriveExpected(parser2);
18074
- failExpected = e.length > 0 ? e : [parser2._tag];
18075
- }
18076
- return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
18077
- }
18078
- const mark = saveCstMark(ctx);
18079
- const log = ctx._triviaLog?.length;
18080
- const rootLog = ctx._rootTriviaLog?.length;
18081
- const split = ctx._columnsSplit;
18082
- const result = parser2.parse(input, pos, ctx);
18083
- if (result.ok) return result;
18084
- rollbackCstCapture(ctx, mark);
18085
- ctx._columnsSplit = split;
18086
- if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
18087
- if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
18088
- if (result.committed && !contain) return result;
18089
- return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
18090
- }
18091
- };
18092
- }
18093
-
18094
19238
  // src/combinators/not.ts
18095
19239
  function not(combinator) {
18096
19240
  const meta = {