parseman 0.57.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 (64) hide show
  1. package/dist/analysis/diagnostics.js +1799 -962
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +1928 -1091
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/dispatch.d.ts.map +1 -1
  6. package/dist/compiler/token-alphabet.d.ts +11 -1
  7. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  8. package/dist/compiler/token-capability.js +69 -16
  9. package/dist/compiler/token-capability.js.map +2 -2
  10. package/dist/cst/capture-buffer.d.ts +6 -0
  11. package/dist/cst/capture-buffer.d.ts.map +1 -1
  12. package/dist/index.js +1016 -177
  13. package/dist/index.js.map +3 -3
  14. package/dist/plugin/index.d.ts +25 -1
  15. package/dist/plugin/index.d.ts.map +1 -1
  16. package/dist/plugin/index.js +1209 -236
  17. package/dist/plugin/index.js.map +3 -3
  18. package/dist/table/assemble.d.ts.map +1 -1
  19. package/dist/table/compile-rule-map.d.ts.map +1 -1
  20. package/dist/table/emit-assembly.d.ts +1 -1
  21. package/dist/table/emit-assembly.d.ts.map +1 -1
  22. package/dist/table/emit.d.ts.map +1 -1
  23. package/dist/table/encode.d.ts.map +1 -1
  24. package/dist/table/exec.d.ts.map +1 -1
  25. package/dist/table/factor-choice.d.ts +42 -0
  26. package/dist/table/factor-choice.d.ts.map +1 -0
  27. package/dist/table/fail-clean.d.ts +3 -0
  28. package/dist/table/fail-clean.d.ts.map +1 -0
  29. package/dist/table/hold-gap.d.ts +8 -0
  30. package/dist/table/hold-gap.d.ts.map +1 -0
  31. package/dist/table/index.js +1369 -259
  32. package/dist/table/index.js.map +3 -3
  33. package/dist/table/lex-program.d.ts +7 -3
  34. package/dist/table/lex-program.d.ts.map +1 -1
  35. package/dist/table/ops.d.ts +8 -0
  36. package/dist/table/ops.d.ts.map +1 -1
  37. package/dist/table/run-support.d.ts +19 -0
  38. package/dist/table/run-support.d.ts.map +1 -1
  39. package/dist/table/scalar-terminal.d.ts +2 -0
  40. package/dist/table/scalar-terminal.d.ts.map +1 -1
  41. package/dist/table/site-labels.d.ts +66 -0
  42. package/dist/table/site-labels.d.ts.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/package.json +1 -1
  45. package/src/combinators/dispatch.ts +12 -3
  46. package/src/compiler/token-alphabet.ts +57 -17
  47. package/src/cst/capture-buffer.ts +25 -0
  48. package/src/plugin/index.ts +230 -35
  49. package/src/table/assemble.ts +252 -62
  50. package/src/table/child-slots.ts +2 -2
  51. package/src/table/compile-rule-map.ts +14 -5
  52. package/src/table/emit-assembly.ts +112 -23
  53. package/src/table/emit.ts +3 -1
  54. package/src/table/encode.ts +80 -14
  55. package/src/table/exec.ts +27 -8
  56. package/src/table/factor-choice.ts +173 -0
  57. package/src/table/fail-clean.ts +130 -0
  58. package/src/table/hold-gap.ts +68 -0
  59. package/src/table/lex-program.ts +197 -43
  60. package/src/table/ops.ts +9 -1
  61. package/src/table/run-support.ts +35 -0
  62. package/src/table/scalar-terminal.ts +8 -0
  63. package/src/table/site-labels.ts +135 -4
  64. 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) {
@@ -2395,10 +2420,16 @@ function branchUsesRouted(branch) {
2395
2420
  return branch.usesRouted === true || parserUsesRouted(branch.parser);
2396
2421
  }
2397
2422
  function asciiFoldKey(key) {
2398
- let out = "";
2399
- 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++) {
2400
2431
  const c = key.charCodeAt(i);
2401
- out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
2432
+ out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : key[i];
2402
2433
  }
2403
2434
  return out;
2404
2435
  }
@@ -2727,6 +2758,42 @@ function keywords(words, opts = {}) {
2727
2758
  };
2728
2759
  }
2729
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
+
2730
2797
  // src/compiler/token-alphabet.ts
2731
2798
  function optionalSuffixLexBody(ir) {
2732
2799
  if (ir.kind !== "sequence" || ir.parts.length !== 2) return void 0;
@@ -2746,7 +2813,10 @@ function selectOptionalSuffixLexBody(ir) {
2746
2813
  const token2 = { strategy: "token", estimatedOps: 2, body };
2747
2814
  return token2.estimatedOps < character.estimatedOps ? token2 : character;
2748
2815
  }
2749
- 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) {
2750
2820
  const outer = parser2._def;
2751
2821
  if (outer.tag !== "token") return void 0;
2752
2822
  let body = outer.parser;
@@ -2756,12 +2826,13 @@ function directTokenBodyParser(parser2, resolve2) {
2756
2826
  const wrapper = body._def;
2757
2827
  if (wrapper.tag === "grammar") {
2758
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;
2759
2830
  body = wrapper.parser;
2760
2831
  continue;
2761
2832
  }
2762
2833
  if (wrapper.tag === "lazy") {
2763
2834
  const target = resolvedLazyTarget(body, resolve2);
2764
- if (target === void 0) return void 0;
2835
+ if (target === void 0 || reinstallsRuleTrivia(body, target)) return void 0;
2765
2836
  body = target;
2766
2837
  continue;
2767
2838
  }
@@ -2933,7 +3004,7 @@ function directNot2TokenBody(parser2, resolve2) {
2933
3004
  terminal
2934
3005
  };
2935
3006
  }
2936
- function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
3007
+ function directFixedLexNode(parser2, resolve2, active, pureOnly = false, cleared = false) {
2937
3008
  let current = parser2;
2938
3009
  const wrappers = /* @__PURE__ */ new Set();
2939
3010
  while (!wrappers.has(current)) {
@@ -2941,7 +3012,7 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2941
3012
  const def = current._def;
2942
3013
  if (def.tag === "lazy") {
2943
3014
  const target = resolvedLazyTarget(current, resolve2);
2944
- if (target === void 0) return void 0;
3015
+ if (target === void 0 || reinstallsRuleTrivia(current, target)) return void 0;
2945
3016
  current = target;
2946
3017
  continue;
2947
3018
  }
@@ -2959,30 +3030,33 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2959
3030
  if (terminal !== void 0) return { kind: "terminal", terminal };
2960
3031
  const def = current._def;
2961
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
+ }
2962
3036
  if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
2963
- return directFixedLexNode(def.parser, resolve2, active, true);
3037
+ return directFixedLexNode(def.parser, resolve2, active, true, cleared);
2964
3038
  }
2965
3039
  if (def.tag === "sequence") {
2966
3040
  if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
2967
- const parts = def.parsers.map((part) => directFixedLexNode(part, resolve2, active, pureOnly));
3041
+ const parts = def.parsers.map((part) => directFixedLexNode(part, resolve2, active, pureOnly, cleared));
2968
3042
  if (parts.some((part) => part === void 0)) return void 0;
2969
3043
  return { kind: "sequence", parts };
2970
3044
  }
2971
3045
  if (def.tag === "choice") {
2972
- 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;
2973
- 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));
2974
3048
  if (arms.some((arm) => arm === void 0)) return void 0;
2975
- const final = classifyFinalChoice(def.parsers, resolve2);
2976
3049
  return {
2977
3050
  kind: "choice",
2978
3051
  arms,
2979
- firstSets: final.firstSets,
3052
+ parsers: def.parsers,
3053
+ cleared,
2980
3054
  armExpected: def.parsers.map(deriveExpected),
2981
3055
  expected: def.parsers.flatMap(deriveExpected)
2982
3056
  };
2983
3057
  }
2984
3058
  if (def.tag === "not") {
2985
- const body = directFixedLexNode(def.parser, resolve2, active, true);
3059
+ const body = directFixedLexNode(def.parser, resolve2, active, true, cleared);
2986
3060
  return body === void 0 ? void 0 : {
2987
3061
  kind: "not",
2988
3062
  body,
@@ -2990,18 +3064,28 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false) {
2990
3064
  };
2991
3065
  }
2992
3066
  if (def.tag === "optional") {
2993
- const body = directFixedLexNode(def.parser, resolve2, active, pureOnly);
3067
+ const body = directFixedLexNode(def.parser, resolve2, active, pureOnly, cleared);
2994
3068
  return body === void 0 ? void 0 : { kind: "optional", body };
2995
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
+ }
2996
3079
  return void 0;
2997
3080
  } finally {
2998
3081
  active.delete(current);
2999
3082
  }
3000
3083
  }
3001
3084
  function directFixedTokenBody(parser2, resolve2) {
3002
- const body = directTokenBodyParser(parser2, resolve2);
3085
+ const scope = { cleared: false };
3086
+ const body = directTokenBodyParser(parser2, resolve2, scope);
3003
3087
  if (body === void 0) return void 0;
3004
- const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set());
3088
+ const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set(), false, scope.cleared);
3005
3089
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
3006
3090
  }
3007
3091
  function directBalancedTokenBody(parser2, resolve2) {
@@ -4910,17 +4994,59 @@ function buildLexBodyRecognizer(spec, constants) {
4910
4994
  };
4911
4995
  }
4912
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
+
4913
5040
  // src/table/lex-program.ts
4914
5041
  var LEX_NODE_TERMINAL = 0;
4915
5042
  var LEX_NODE_SEQUENCE2 = 1;
4916
5043
  var LEX_NODE_SEQUENCE3 = 2;
4917
5044
  var LEX_NODE_SEQUENCE4 = 3;
4918
5045
  var LEX_NODE_SEQUENCE5 = 4;
4919
- var LEX_NODE_CHOICE2 = 5;
4920
- var LEX_NODE_CHOICE4 = 6;
4921
- var LEX_NODE_CHOICE8 = 7;
5046
+ var LEX_NODE_CHOICE = 5;
4922
5047
  var LEX_NODE_NOT = 8;
4923
5048
  var LEX_NODE_OPTIONAL = 9;
5049
+ var LEX_NODE_REPEAT = 10;
4924
5050
  function lexProgramDigest(words) {
4925
5051
  let hash = 2166136261;
4926
5052
  for (const word of words) {
@@ -4949,85 +5075,114 @@ function trackLexLines(ctx, input, end) {
4949
5075
  ctx._lineScannedTo = end;
4950
5076
  }
4951
5077
  function terminalNode(matcher, failure, tracksLines) {
4952
- const match = (input, pos) => {
4953
- const result = matcher(input, pos);
4954
- return result < 0 ? -1 : result / 2;
4955
- };
4956
5078
  return {
4957
- match,
5079
+ match: (input, pos) => {
5080
+ const result = matcher(input, pos);
5081
+ return result < 0 ? -1 : result / 2;
5082
+ },
4958
5083
  run: (input, pos, ctx) => {
4959
- const end = match(input, pos);
4960
- if (end < 0) {
5084
+ const result = matcher(input, pos);
5085
+ if (result < 0) {
4961
5086
  ctx._fe = pos;
4962
5087
  ctx._fx = failure;
4963
5088
  if (ctx._probe !== void 0) failAt(ctx, ctx._fx, pos);
4964
5089
  return -1;
4965
5090
  }
5091
+ const end = result / 2;
4966
5092
  if (tracksLines) trackLexLines(ctx, input, end);
4967
5093
  return end;
4968
5094
  }
4969
5095
  };
4970
5096
  }
4971
5097
  function sequence2(a, b) {
5098
+ const am = a.match, bm = b.match, ar = a.run, br = b.run;
4972
5099
  return {
4973
5100
  match: (input, pos) => {
4974
- const e0 = a.match(input, pos);
4975
- return e0 < 0 ? -1 : b.match(input, e0);
5101
+ const e0 = am(input, pos);
5102
+ return e0 < 0 ? -1 : bm(input, e0);
4976
5103
  },
4977
5104
  run: (input, pos, ctx) => {
4978
- const e0 = a.run(input, pos, ctx);
5105
+ const e0 = ar(input, pos, ctx);
4979
5106
  if (e0 < 0) return -1;
4980
5107
  ctx._fc = false;
4981
- return b.run(input, e0, ctx);
5108
+ return br(input, e0, ctx);
4982
5109
  }
4983
5110
  };
4984
5111
  }
4985
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;
4986
5114
  return {
4987
5115
  match: (input, pos) => {
4988
- const e0 = a.match(input, pos);
5116
+ const e0 = am(input, pos);
4989
5117
  if (e0 < 0) return -1;
4990
- const e1 = b.match(input, e0);
4991
- return e1 < 0 ? -1 : c.match(input, e1);
5118
+ const e1 = bm(input, e0);
5119
+ return e1 < 0 ? -1 : cm(input, e1);
4992
5120
  },
4993
5121
  run: (input, pos, ctx) => {
4994
- const e0 = a.run(input, pos, ctx);
5122
+ const e0 = ar(input, pos, ctx);
4995
5123
  if (e0 < 0) return -1;
4996
5124
  ctx._fc = false;
4997
- const e1 = b.run(input, e0, ctx);
5125
+ const e1 = br(input, e0, ctx);
4998
5126
  if (e1 < 0) return -1;
4999
5127
  ctx._fc = false;
5000
- return c.run(input, e1, ctx);
5128
+ return cr(input, e1, ctx);
5001
5129
  }
5002
5130
  };
5003
5131
  }
5004
5132
  function sequence4(a, b, c, d) {
5005
- 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;
5006
5135
  return {
5007
5136
  match: (input, pos) => {
5008
- const end = abc.match(input, pos);
5009
- 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);
5010
5143
  },
5011
5144
  run: (input, pos, ctx) => {
5012
- const end = abc.run(input, pos, ctx);
5013
- 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;
5014
5150
  ctx._fc = false;
5015
- 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);
5016
5155
  }
5017
5156
  };
5018
5157
  }
5019
5158
  function sequence5(a, b, c, d, e) {
5020
- 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;
5021
5161
  return {
5022
5162
  match: (input, pos) => {
5023
- const end = abcd.match(input, pos);
5024
- 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);
5025
5171
  },
5026
5172
  run: (input, pos, ctx) => {
5027
- const end = abcd.run(input, pos, ctx);
5028
- 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;
5029
5184
  ctx._fc = false;
5030
- return e.run(input, end, ctx);
5185
+ return er(input, e3, ctx);
5031
5186
  }
5032
5187
  };
5033
5188
  }
@@ -5040,9 +5195,9 @@ function appendExpected(acc, values) {
5040
5195
  function choiceNode(arms, classes, armExpected, choiceExpected) {
5041
5196
  let matchTail = () => -1;
5042
5197
  for (let i = arms.length - 1; i >= 0; i--) {
5043
- const arm = arms[i], next = matchTail;
5198
+ const armMatch = arms[i].match, next = matchTail;
5044
5199
  matchTail = (input, pos) => {
5045
- const end = arm.match(input, pos);
5200
+ const end = armMatch(input, pos);
5046
5201
  return end < 0 ? next(input, pos) : end;
5047
5202
  };
5048
5203
  }
@@ -5052,7 +5207,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5052
5207
  return -1;
5053
5208
  };
5054
5209
  for (let i = arms.length - 1; i >= 0; i--) {
5055
- 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;
5056
5211
  tail = (input, pos, ctx, lead2, acc, best) => {
5057
5212
  if (cls !== void 0 && !classHas(cls, lead2)) {
5058
5213
  return next(
@@ -5065,7 +5220,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5065
5220
  );
5066
5221
  }
5067
5222
  ctx._fc = false;
5068
- const end = arm.run(input, pos, ctx);
5223
+ const end = armRun(input, pos, ctx);
5069
5224
  if (end >= 0) return end;
5070
5225
  const at = ctx._fe ?? pos;
5071
5226
  if (at > best) {
@@ -5092,11 +5247,58 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5092
5247
  )
5093
5248
  };
5094
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
+ }
5095
5296
  function notNode(body, failure) {
5297
+ const bodyMatch = body.match;
5096
5298
  return {
5097
- match: (input, pos) => body.match(input, pos) < 0 ? pos : -1,
5299
+ match: (input, pos) => bodyMatch(input, pos) < 0 ? pos : -1,
5098
5300
  run: (input, pos, ctx) => {
5099
- if (body.match(input, pos) < 0) return pos;
5301
+ if (bodyMatch(input, pos) < 0) return pos;
5100
5302
  ctx._fe = pos;
5101
5303
  ctx._fx = failure;
5102
5304
  return -1;
@@ -5104,18 +5306,57 @@ function notNode(body, failure) {
5104
5306
  };
5105
5307
  }
5106
5308
  function optionalNode(body) {
5309
+ const bodyMatch = body.match, bodyRun = body.run;
5107
5310
  return {
5108
5311
  match: (input, pos) => {
5109
- const end = body.match(input, pos);
5312
+ const end = bodyMatch(input, pos);
5110
5313
  return end < 0 ? pos : end;
5111
5314
  },
5112
5315
  run: (input, pos, ctx) => {
5113
5316
  ctx._fc = false;
5114
- const end = body.run(input, pos, ctx);
5317
+ const end = bodyRun(input, pos, ctx);
5115
5318
  return end < 0 && !committed(ctx) ? pos : end;
5116
5319
  }
5117
5320
  };
5118
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
+ }
5119
5360
  function fixedTreeRunner(words, matchers, classes, expected) {
5120
5361
  const stack = [];
5121
5362
  const pop = () => {
@@ -5143,9 +5384,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5143
5384
  else stack.push(sequence5(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4]));
5144
5385
  continue;
5145
5386
  }
5146
- if (op >= LEX_NODE_CHOICE2 && op <= LEX_NODE_CHOICE8) {
5147
- 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");
5148
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
+ }
5149
5395
  if (choiceFx === void 0) throw new TypeError("table lexical tree choice has an invalid expected set");
5150
5396
  const armClasses = [];
5151
5397
  const armFx = [];
@@ -5158,7 +5404,7 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5158
5404
  armFx.push(fx);
5159
5405
  }
5160
5406
  const arms = Array.from({ length: count }, pop).reverse();
5161
- stack.push(choiceNode(arms, armClasses, armFx, choiceFx));
5407
+ stack.push(exclusive === 1 ? exclusiveChoiceNode(arms, armClasses, choiceFx) : choiceNode(arms, armClasses, armFx, choiceFx));
5162
5408
  continue;
5163
5409
  }
5164
5410
  if (op === LEX_NODE_NOT) {
@@ -5171,6 +5417,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5171
5417
  stack.push(optionalNode(pop()));
5172
5418
  continue;
5173
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
+ }
5174
5428
  throw new TypeError("table lexical tree has an unknown fixed body");
5175
5429
  }
5176
5430
  if (stack.length !== 1) throw new TypeError("table lexical tree does not resolve to one root body");
@@ -5539,75 +5793,270 @@ function resolveTable(prog) {
5539
5793
  return built;
5540
5794
  }
5541
5795
 
5542
- // src/compiler/degradation.ts
5543
- function formatDegradation(d) {
5544
- return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
5796
+ // src/combinators/adjacency.ts
5797
+ function adjacencyOf(p) {
5798
+ return p._def.tag === "adjacency" ? p._def : null;
5545
5799
  }
5546
- var DETAIL_CAP = 8;
5547
- function formatDegradations(list) {
5548
- const byCode = /* @__PURE__ */ new Map();
5549
- for (const d of list) {
5550
- const bucket = byCode.get(d.code);
5551
- if (bucket) bucket.push(d);
5552
- else byCode.set(d.code, [d]);
5553
- }
5554
- const out = [];
5555
- for (const [code, items] of byCode) {
5556
- for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
5557
- if (items.length > DETAIL_CAP) {
5558
- out.push(
5559
- `[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.`
5560
- );
5561
- }
5562
- }
5563
- return out;
5800
+ function adjacencyExpected(def) {
5801
+ if (def.polarity === "adjacent") return "adjacent";
5802
+ return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5564
5803
  }
5565
- var _sinks = [];
5566
- function beginDegradationCapture() {
5567
- _sinks.push(/* @__PURE__ */ new Map());
5804
+ function holdsAdjacency(input, cur, ctx, def) {
5805
+ return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5568
5806
  }
5569
- function degradationCaptureDepth() {
5570
- return _sinks.length;
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;
5571
5815
  }
5572
- function unwindDegradationCapture(depth) {
5573
- const found = [];
5574
- while (_sinks.length > depth) {
5575
- const sink = _sinks.pop();
5576
- found.unshift(...sink.values());
5577
- }
5578
- return found;
5816
+ function adjacencyFail(pos, def) {
5817
+ return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5579
5818
  }
5580
- function resolveDegradationLevel(explicit) {
5581
- if (explicit !== void 0) return explicit;
5582
- const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
5583
- if (env === "off" || env === "warn" || env === "error") return env;
5584
- return "warn";
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}`);
5585
5822
  }
5586
- function degradationKey(d) {
5587
- return JSON.stringify([d.code, d.where, d.subject]);
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
+ };
5588
5840
  }
5589
- function recordDegradation(d) {
5590
- const level = resolveDegradationLevel();
5591
- if (level === "off") return;
5592
- const key = degradationKey(d);
5593
- const sink = _sinks[_sinks.length - 1];
5594
- if (sink) {
5595
- if (!sink.has(key)) sink.set(key, d);
5596
- return;
5597
- }
5598
- if (_immediate.has(key)) return;
5599
- _immediate.add(key);
5600
- if (level === "error") throw new Error(`parseman: degraded compilation path
5601
- ${formatDegradation(d)}`);
5602
- console.warn(formatDegradation(d));
5841
+ function adjacent() {
5842
+ return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
5603
5843
  }
5604
- var _immediate = /* @__PURE__ */ new Set();
5605
- function beginCompileDegradationDrain() {
5606
- if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
5607
- };
5608
- const depth = degradationCaptureDepth();
5609
- beginDegradationCapture();
5610
- return (report) => {
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)}`);
6051
+ console.warn(formatDegradation(d));
6052
+ }
6053
+ var _immediate = /* @__PURE__ */ new Set();
6054
+ function beginCompileDegradationDrain() {
6055
+ if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
6056
+ };
6057
+ const depth = degradationCaptureDepth();
6058
+ beginDegradationCapture();
6059
+ return (report) => {
5611
6060
  const found = unwindDegradationCapture(depth);
5612
6061
  if (!report || found.length === 0) return;
5613
6062
  const fresh = found.filter((d) => {
@@ -5717,91 +6166,620 @@ function splitTopLevel(inner) {
5717
6166
  last = i + 1;
5718
6167
  }
5719
6168
  }
5720
- if (depth !== 0 || angle !== 0) return null;
5721
- parts.push(inner.slice(last));
5722
- 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;
5723
6635
  }
5724
- function isConfirmableParam(part) {
5725
- const head = PARAM_HEAD_RE.exec(part);
5726
- if (!head) return false;
5727
- const rest = part.slice(head[0].length);
5728
- if (rest === "") return true;
5729
- if (rest[0] !== ":") return false;
5730
- 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;
5731
6647
  }
5732
- function hasDefaultAssign(annotation) {
5733
- for (let i = 0; i < annotation.length; i++) {
5734
- if (annotation[i] !== "=") continue;
5735
- if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5736
- i++;
5737
- 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 } };
5738
6676
  }
5739
- const prev = annotation[i - 1];
5740
- if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5741
- 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);
5742
6698
  }
5743
6699
  return false;
5744
6700
  }
5745
- function buildAnalysisSrc(def) {
5746
- return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
5747
- }
5748
- var RESOLVER_REASONS = {
5749
- "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5750
- "arguments": "its body references `arguments`",
5751
- "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5752
- "not-a-function": "the binding it names is not a function declaration",
5753
- "unresolved-import": "its module could not be resolved or parsed",
5754
- "not-found": "the name did not resolve to any binding",
5755
- "computed": "it is a computed expression",
5756
- "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5757
- "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5758
- };
5759
- function unconfirmableReason(def, src) {
5760
- const declared = def.buildArityUnresolved;
5761
- if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5762
- const s = src.trim();
5763
- const params = s.slice(0, s.indexOf(")") + 1);
5764
- if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5765
- if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5766
- if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5767
- 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;
5768
6714
  }
5769
- return "its parameter list could not be parsed";
5770
- }
5771
- function confirmedArityForDef(def) {
5772
- if (def.buildArity !== void 0) return def.buildArity;
5773
- const src = buildAnalysisSrc(def);
5774
- const arity = confirmedBuildArity(src);
5775
- if (arity !== null) return arity;
5776
- const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5777
- recordDegradation({
5778
- code: "build-arity-unconfirmed",
5779
- severity: "warn",
5780
- where: `node("${def.type ?? "<inferred>"}")`,
5781
- subject,
5782
- 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`,
5783
- 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"
5784
- });
5785
- return null;
5786
- }
5787
- function buildReadsRaw(def) {
5788
- if (!def.build) return true;
5789
- if (def.buildRawUnused === true) return false;
5790
- const arity = confirmedArityForDef(def);
5791
- if (arity === null) return true;
5792
- return arity >= 4;
5793
- }
5794
- function buildReadsTrivia(def) {
5795
- if (!def.build) return true;
5796
- const arity = confirmedArityForDef(def);
5797
- if (arity === null) return true;
5798
- return arity >= 5;
6715
+ return true;
5799
6716
  }
5800
- function buildReadsState(def) {
5801
- if (!def.build) return true;
5802
- const arity = confirmedArityForDef(def);
5803
- if (arity === null) return true;
5804
- 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);
5805
6783
  }
5806
6784
 
5807
6785
  // src/compiler/fields.ts
@@ -5918,6 +6896,7 @@ var OP_SCOPE_PLAIN = 41;
5918
6896
  var OP_LEX_BODY = 42;
5919
6897
  var OP_LEX_PROGRAM = 43;
5920
6898
  var OP_SOURCE_LEAF = 44;
6899
+ var OP_RGATE = 45;
5921
6900
  var OP_DISPATCH = 25;
5922
6901
  var OP_ROUTED = 26;
5923
6902
  var OP_NAMES = {
@@ -5937,6 +6916,7 @@ var OP_NAMES = {
5937
6916
  [OP_PEEK]: "PEEK",
5938
6917
  [OP_LEAF]: "LEAF",
5939
6918
  [OP_SOURCE_LEAF]: "SOURCE_LEAF",
6919
+ [OP_RGATE]: "RGATE",
5940
6920
  [OP_EMPTY]: "EMPTY",
5941
6921
  [OP_LIT_TRACK]: "LIT_TRACK",
5942
6922
  [OP_RX_TRACK]: "RX_TRACK",
@@ -5967,71 +6947,6 @@ var OP_NAMES = {
5967
6947
  [OP_LEX_PROGRAM]: "LEX_PROGRAM"
5968
6948
  };
5969
6949
 
5970
- // src/combinators/adjacency.ts
5971
- function adjacencyOf(p) {
5972
- return p._def.tag === "adjacency" ? p._def : null;
5973
- }
5974
- function adjacencyExpected(def) {
5975
- if (def.polarity === "adjacent") return "adjacent";
5976
- return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5977
- }
5978
- function holdsAdjacency(input, cur, ctx, def) {
5979
- return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5980
- }
5981
- function adjacencyHolds(input, cur, ctx, negated, kinds) {
5982
- const end = probeTriviaEnd(input, cur, ctx);
5983
- if (!negated) return end === cur;
5984
- if (end === cur) return false;
5985
- if (kinds === void 0) return true;
5986
- const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
5987
- const spec = analyzeLabeledTrivia(ctx.trivia);
5988
- return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
5989
- }
5990
- function adjacencyFail(pos, def) {
5991
- return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5992
- }
5993
- 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.";
5994
- function adjacencyMisuse(polarity) {
5995
- return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
5996
- }
5997
- function adjacencyCombinator(def) {
5998
- const meta = {
5999
- // Zero-width and never leading (sequence() rejects index 0), so it contributes
6000
- // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
6001
- // rather than letting `any` poison the enclosing choice's dispatch.
6002
- firstSet: { kind: "any" },
6003
- canMatchNewline: false,
6004
- isTrivia: false
6005
- };
6006
- return {
6007
- _tag: "adjacency",
6008
- _meta: meta,
6009
- _def: def,
6010
- parse() {
6011
- throw adjacencyMisuse(def.polarity);
6012
- }
6013
- };
6014
- }
6015
- function adjacent() {
6016
- return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
6017
- }
6018
- function notAdjacent(options) {
6019
- const kinds = options?.kinds;
6020
- if (kinds !== void 0) {
6021
- if (!Array.isArray(kinds) || kinds.length === 0) {
6022
- throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
6023
- }
6024
- for (const k of kinds) {
6025
- if (typeof k !== "string" || k.length === 0) {
6026
- throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
6027
- }
6028
- }
6029
- }
6030
- return adjacencyCombinator(
6031
- kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
6032
- );
6033
- }
6034
-
6035
6950
  // src/combinators/node.ts
6036
6951
  function unwrapChild(child) {
6037
6952
  return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
@@ -6148,42 +7063,6 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
6148
7063
  };
6149
7064
  }
6150
7065
 
6151
- // src/combinators/trivia-boundary.ts
6152
- var MAX_DEPTH = 12;
6153
- function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
6154
- if (depth === 0) return true;
6155
- const d = p._def;
6156
- switch (d.tag) {
6157
- // Multi-term forms: the gaps BETWEEN terms are the ambient-trivia positions.
6158
- case "sequence":
6159
- return d.parsers.length > 1;
6160
- case "many":
6161
- case "oneOrMore":
6162
- case "sepBy":
6163
- return true;
6164
- // Transparent wrappers — they add no position, so ask what they wrap.
6165
- case "node":
6166
- case "transform":
6167
- case "leaf":
6168
- case "label":
6169
- case "field":
6170
- case "token":
6171
- case "attempt":
6172
- case "optional":
6173
- case "expect":
6174
- case "withCtx":
6175
- case "recover":
6176
- case "trivia":
6177
- return hasOwnTriviaBoundary(d.parser, depth - 1);
6178
- // An alternation adds no position either, but ONE arm that has one is enough
6179
- // to make the scope meaningful for this rule.
6180
- case "choice":
6181
- return d.parsers.some((a) => hasOwnTriviaBoundary(a, depth - 1));
6182
- default:
6183
- return false;
6184
- }
6185
- }
6186
-
6187
7066
  // src/compiler/direct-projection.ts
6188
7067
  function directArrayProjection(fn, fnSrc, arity) {
6189
7068
  let source = fnSrc;
@@ -6404,13 +7283,16 @@ var Encoder = class {
6404
7283
  }
6405
7284
  case "choice": {
6406
7285
  for (const arm of node2.arms) if (!emitNode(arm)) return false;
6407
- const op = node2.arms.length === 2 ? LEX_NODE_CHOICE2 : node2.arms.length === 4 ? LEX_NODE_CHOICE4 : node2.arms.length === 8 ? LEX_NODE_CHOICE8 : -1;
6408
- if (op < 0) return false;
6409
- 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));
6410
7294
  for (let i = 0; i < node2.arms.length; i++) {
6411
- const first = node2.firstSets[i];
6412
- words.push(first.kind === "ranges" ? this.charClass(first) : -1);
6413
- words.push(this.expected(node2.armExpected[i]));
7295
+ words.push(classes[i], this.expected(node2.armExpected[i]));
6414
7296
  }
6415
7297
  return true;
6416
7298
  }
@@ -6422,6 +7304,10 @@ var Encoder = class {
6422
7304
  if (!emitNode(node2.body)) return false;
6423
7305
  words.push(LEX_NODE_OPTIONAL);
6424
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;
6425
7311
  }
6426
7312
  };
6427
7313
  if (!emitNode(body.root)) return void 0;
@@ -6927,6 +7813,50 @@ var Encoder = class {
6927
7813
  if (!hasOwnTriviaBoundary(target)) return ip;
6928
7814
  return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
6929
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
+ }
6930
7860
  node(p) {
6931
7861
  const lazyRef = p._def.tag === "lazy";
6932
7862
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -7051,6 +7981,10 @@ var Encoder = class {
7051
7981
  return head;
7052
7982
  }
7053
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
+ }
7054
7988
  if (d.strategy.tag === "greedyClassify") {
7055
7989
  const superIndex = d.strategy.superIndex;
7056
7990
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -7074,9 +8008,12 @@ var Encoder = class {
7074
8008
  const kids = arms.map((c, k) => {
7075
8009
  const src = order[k];
7076
8010
  const checks = d.autoNot[src];
7077
- const inner = this.node(c).ip;
7078
- const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
7079
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);
7080
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)));
7081
8018
  return this.covWrap(gated, armCovIds?.[src], 1);
7082
8019
  });
@@ -7400,6 +8337,7 @@ var Encoder = class {
7400
8337
  const slots = (ip) => {
7401
8338
  switch (this.code[ip]) {
7402
8339
  case OP_GATE:
8340
+ case OP_RGATE:
7403
8341
  return [ip + 2];
7404
8342
  case OP_RULE:
7405
8343
  case OP_OPT:
@@ -8627,6 +9565,7 @@ function childSlots(code, ip, out) {
8627
9565
  case OP_LEAF:
8628
9566
  case OP_SOURCE_LEAF:
8629
9567
  case OP_ARMGATE:
9568
+ case OP_RGATE:
8630
9569
  out.push(code[ip + 2]);
8631
9570
  return true;
8632
9571
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -8710,6 +9649,42 @@ function reachableSites(code, roots) {
8710
9649
  }
8711
9650
  return seen;
8712
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
+ }
8713
9688
  function transfer(code, ip, at, hostCst) {
8714
9689
  const op = code[ip];
8715
9690
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -8721,14 +9696,18 @@ function transfer(code, ip, at, hostCst) {
8721
9696
  }
8722
9697
  if (op === OP_NODE || op === OP_NODE_TRACK) {
8723
9698
  const flags = code[ip + 3];
9699
+ if (passCollapse(code, ip, hostCst)) return at;
9700
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
8724
9701
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
8725
9702
  if (directChildren) {
8726
- 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;
8727
9705
  }
8728
9706
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
8729
9707
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
8730
9708
  if (at.buf && raw === at.raw && cap === at.cap) return at;
8731
- 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;
8732
9711
  }
8733
9712
  if (op === OP_TOKEN) {
8734
9713
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -8766,6 +9745,40 @@ function computeSiteLabels(code, roots, hostCst) {
8766
9745
  }
8767
9746
  return { at: (ip) => labels.get(ip) ?? TOP };
8768
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
+ }
8769
9782
 
8770
9783
  // src/table/scalar-terminal.ts
8771
9784
  function makeScalarRecognizer(op, spec) {
@@ -8803,6 +9816,12 @@ function scalarTerminalNotChild(code, ip) {
8803
9816
  const op = code[child];
8804
9817
  return op === OP_RX || op === OP_LIT ? child : -1;
8805
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
+ }
8806
9825
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
8807
9826
  const seen = /* @__PURE__ */ new Set();
8808
9827
  let at = ip;
@@ -8980,6 +9999,59 @@ function leadingTriviaFieldAt(code, k, ip) {
8980
9999
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
8981
10000
  }
8982
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
+
8983
10055
  // src/table/emit-assembly.ts
8984
10056
  var Unemittable = class extends Error {
8985
10057
  construct;
@@ -9060,7 +10132,10 @@ var EMITTED_PARAMS = [
9060
10132
  "triviaFieldCapture",
9061
10133
  // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
9062
10134
  // factories ignore it.
9063
- "skipDeferredTrivia"
10135
+ "skipDeferredTrivia",
10136
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
10137
+ // ignore it.
10138
+ "collapseEmpty"
9064
10139
  ];
9065
10140
  var RUNTIME_PRELUDE = `
9066
10141
  let _pfScan=null
@@ -9257,6 +10332,24 @@ ${fast}
9257
10332
  ${scanned}
9258
10333
  }`;
9259
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
+ }
9260
10353
  function leadSkip(hasTrivia, leadTrivia, skip) {
9261
10354
  if (hasTrivia === "false") return "{}";
9262
10355
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -9298,6 +10391,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
9298
10391
  const reachable = [...reachableSites(code, roots)];
9299
10392
  const labels = computeSiteLabels(code, roots, hostCst);
9300
10393
  const scalarSpecs = /* @__PURE__ */ new Set();
10394
+ const nullable2 = /* @__PURE__ */ new Map();
9301
10395
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
9302
10396
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
9303
10397
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -9622,9 +10716,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9622
10716
  const op = code[ip];
9623
10717
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
9624
10718
  if (op === OP_RULE) return code[ip + 1];
9625
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
9626
- return code[ip + 2];
9627
- }
10719
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
9628
10720
  return void 0;
9629
10721
  }
9630
10722
  function lower(ip, fname) {
@@ -9746,6 +10838,22 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9746
10838
  return `${head}
9747
10839
  if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9748
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
+ }`;
10848
+ const resolved = t2.cc[code[ip + 1]];
10849
+ const ci = classes.push([resolved]) - 1;
10850
+ classPlan.push([code[ip + 1]]);
10851
+ const cls = hoist("cl", `CLS[${ci}][0]`);
10852
+ const xf = fxRef(code[ip + 3]);
10853
+ return `${head}
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)
9749
10857
  }`;
9750
10858
  }
9751
10859
  case OP_ARMGATE: {
@@ -10020,23 +11128,33 @@ return FAIL
10020
11128
  const p = tmp();
10021
11129
  return `${head}
10022
11130
  ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
10023
- const v=${child}(input,pos,ctx)
11131
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10024
11132
  ${emitRollback(p, L.buf, L.raw, sinks)}
10025
- 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}
10026
11134
  ctx._fe=pos
10027
11135
  ctx._fx=${xf}
10028
11136
  return FAIL
10029
11137
  }`;
10030
11138
  }
10031
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
+ }
10032
11150
  const child = link(code[ip + 1]);
10033
11151
  const xf = fxRef(code[ip + 2]);
10034
11152
  const p = tmp();
10035
11153
  return `${head}
10036
11154
  ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
10037
- const v=${child}(input,pos,ctx)
11155
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10038
11156
  ${emitRollback(p, L.buf, L.raw, sinks)}
10039
- 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}
10040
11158
  EC.e=pos
10041
11159
  return null
10042
11160
  }`;
@@ -10107,7 +11225,7 @@ return v
10107
11225
  );
10108
11226
  } else {
10109
11227
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
10110
- 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)));
10111
11229
  }
10112
11230
  names.push(vn);
10113
11231
  }
@@ -10590,6 +11708,26 @@ return nd
10590
11708
  const trailingTrivia = (flags & 128) !== 0;
10591
11709
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
10592
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
+ ` : "";
10593
11731
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
10594
11732
  const fields = flags === 18;
10595
11733
  const collapseChildren = flags === 34;
@@ -10624,7 +11762,7 @@ sCh.push(nd)
10624
11762
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
10625
11763
  }`;
10626
11764
  return `${head}
10627
- 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
10628
11766
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
10629
11767
  const flat=[]
10630
11768
  ctx._cstBuf=undefined
@@ -10699,7 +11837,7 @@ const hostKids=kids
10699
11837
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
10700
11838
  const tlog=buf.tl??EMPTY_TLOG`;
10701
11839
  return `${head}
10702
- 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
10703
11841
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
10704
11842
  ${openCapture}
10705
11843
  ctx.captureTrivia=${captureWide}
@@ -10769,9 +11907,15 @@ ext:[${externals.join(",")}],
10769
11907
  bind:function(xs,ps){_xScan=xs
10770
11908
  ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
10771
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
+ };
10772
11916
  const externalDefs = select === void 0 ? "" : `let _xScan
10773
11917
  ${externals.map((ip) => `let _xp${ip}
10774
- function _px${ip}(input,pos,ctx){const o=_xScan(_pfScan);const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
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")}
10775
11919
  `;
10776
11920
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10777
11921
  ${prelude.join("\n")}
@@ -11023,198 +12167,68 @@ function literal(value, opts = {}) {
11023
12167
  const canMatchNewline = meta.canMatchNewline;
11024
12168
  const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
11025
12169
  const code = value.charCodeAt(0);
11026
- return (input, pos, ctx) => {
11027
- if (input.charCodeAt(pos) === code) {
11028
- ctx._sv = value;
11029
- return pos + 1;
11030
- }
11031
- ctx._fx = expected;
11032
- return ~pos;
11033
- };
11034
- })() : (input, pos, ctx) => {
11035
- const end = pos + value.length;
11036
- if (end <= input.length) {
11037
- const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
11038
- if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
11039
- ctx._sv = matchedValue;
11040
- return end;
11041
- }
11042
- }
11043
- ctx._fx = expected;
11044
- return ~pos;
11045
- };
11046
- if (caseInsensitive) {
11047
- const upper = value.toUpperCase();
11048
- const lower = value.toLowerCase();
11049
- const firstUpper = upper.codePointAt(0);
11050
- const firstLower = lower.codePointAt(0);
11051
- meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
11052
- { lo: firstLower, hi: firstLower },
11053
- { lo: firstUpper, hi: firstUpper }
11054
- ] } : firstSet2;
11055
- }
11056
- const expected = directTerminalFailureExpected({ tag: "literal", value, caseInsensitive });
11057
- const parse2 = !caseInsensitive && value.length === 1 ? (() => {
11058
- const code = value.charCodeAt(0);
11059
- return function parse3(input, pos, ctx) {
11060
- if (input.charCodeAt(pos) === code) {
11061
- const span = { start: pos, end: pos + 1 };
11062
- if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
11063
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11064
- return { ok: true, value, span };
11065
- }
11066
- return failAt(ctx, expected, pos);
11067
- };
11068
- })() : function parse3(input, pos, ctx) {
11069
- const end = pos + value.length;
11070
- if (end > input.length) {
11071
- return failAt(ctx, expected, pos);
11072
- }
11073
- const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
11074
- if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
11075
- const span = { start: pos, end };
11076
- if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
11077
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
11078
- return { ok: true, value: matchedValue, span };
11079
- }
11080
- return failAt(ctx, expected, pos);
11081
- };
11082
- return {
11083
- _tag: "literal",
11084
- _meta: meta,
11085
- _def: { tag: "literal", value, caseInsensitive },
11086
- _parseScalar: parseScalar,
11087
- parse: parse2
11088
- };
11089
- }
11090
-
11091
- // src/combinators/sequence.ts
11092
- function sequence(...parsers) {
11093
- let adjacency = null;
11094
- for (let i = 0; i < parsers.length; i++) {
11095
- const a = adjacencyOf(parsers[i]);
11096
- if (a === null) continue;
11097
- if (i === 0) {
11098
- throw new TypeError(
11099
- `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
11100
- );
11101
- }
11102
- ;
11103
- (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
11104
- }
11105
- const hasAdjacency = adjacency !== null;
11106
- let leading = null;
11107
- for (let i = 1; i < parsers.length; i++) {
11108
- if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
11109
- }
11110
- const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
11111
- const meta = {
11112
- // Union through the nullable prefix — a leading optional()/many() lets a later
11113
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
11114
- firstSet: sequenceFirstSet(parsers),
11115
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
11116
- isTrivia: false
11117
- };
11118
- const def = { tag: "sequence", parsers };
11119
- const scalarParsers = parsers.map(scalarOf);
11120
- const parseScalar = (input, pos, ctx) => {
11121
- let cur = pos;
11122
- if (strictArity !== 0) {
11123
- cur = scalarParsers[0](input, cur, ctx);
11124
- if (cur < 0) return cur;
11125
- const first = ctx._sv;
11126
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11127
- cur = scalarParsers[1](input, cur, ctx);
11128
- if (cur < 0) return cur;
11129
- const second = ctx._sv;
11130
- if (strictArity === 2) {
11131
- ctx._sv = def.valueUnused ? void 0 : [first, second];
11132
- return cur;
11133
- }
11134
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11135
- cur = scalarParsers[2](input, cur, ctx);
11136
- if (cur < 0) return cur;
11137
- ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
11138
- return cur;
11139
- }
11140
- const values = def.valueUnused ? void 0 : [];
11141
- for (let i = 0; i < scalarParsers.length; i++) {
11142
- let termPos = cur;
11143
- if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
11144
- const end = scalarParsers[i](input, termPos, ctx);
11145
- if (end < 0) return end;
11146
- if (values !== void 0) values.push(ctx._sv);
11147
- if (end > termPos || termPos === cur) cur = end;
11148
- }
11149
- ctx._sv = values;
11150
- return cur;
11151
- };
11152
- let followSentinels;
11153
- return {
11154
- _tag: "sequence",
11155
- _meta: meta,
11156
- _def: def,
11157
- _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
11158
- parse(input, pos, ctx) {
11159
- const tolerant = ctx._tolerant === true;
11160
- if (tolerant) {
11161
- followSentinels ??= parsers.map((_, i) => firstSetSentinel(
11162
- parsers.slice(i + 1).reduce(
11163
- (set, parser2) => union(set, firstSetOf(parser2)),
11164
- { kind: "empty" }
11165
- )
11166
- ));
11167
- }
11168
- const inheritedSync = ctx._sync;
11169
- const deferredTrivia = needsDeferredTriviaCommit(ctx);
11170
- const values = def.valueUnused ? void 0 : [];
11171
- let cur = pos;
11172
- try {
11173
- for (let i = 0; i < parsers.length; i++) {
11174
- if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
11175
- const assertion = adjacency?.[i];
11176
- if (assertion) {
11177
- if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
11178
- if (values !== void 0) values.push(null);
11179
- continue;
11180
- }
11181
- let termPos = cur;
11182
- const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11183
- const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11184
- const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11185
- if (ctx.trivia && i > 0) {
11186
- termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
11187
- }
11188
- const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11189
- const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11190
- const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11191
- if (leading?.[i] === true) LEAD.at = cur;
11192
- const result = parsers[i].parse(input, termPos, ctx);
11193
- if (!result.ok) return result;
11194
- if (values !== void 0) values.push(result.value);
11195
- if (result.span.end > termPos || termPos === cur) cur = result.span.end;
11196
- else if (deferredTrivia) {
11197
- rollbackScannedTriviaAt(
11198
- ctx,
11199
- markTlog,
11200
- scanTlog,
11201
- markLog,
11202
- scanLog,
11203
- markRootLog,
11204
- scanRootLog
11205
- );
11206
- }
11207
- }
11208
- } finally {
11209
- if (tolerant) ctx._sync = inheritedSync;
12170
+ return (input, pos, ctx) => {
12171
+ if (input.charCodeAt(pos) === code) {
12172
+ ctx._sv = value;
12173
+ return pos + 1;
11210
12174
  }
11211
- return {
11212
- ok: true,
11213
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
11214
- value: values ?? void 0,
11215
- span: { start: pos, end: cur }
11216
- };
12175
+ ctx._fx = expected;
12176
+ return ~pos;
12177
+ };
12178
+ })() : (input, pos, ctx) => {
12179
+ const end = pos + value.length;
12180
+ if (end <= input.length) {
12181
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
12182
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
12183
+ ctx._sv = matchedValue;
12184
+ return end;
12185
+ }
12186
+ }
12187
+ ctx._fx = expected;
12188
+ return ~pos;
12189
+ };
12190
+ if (caseInsensitive) {
12191
+ const upper = value.toUpperCase();
12192
+ const lower = value.toLowerCase();
12193
+ const firstUpper = upper.codePointAt(0);
12194
+ const firstLower = lower.codePointAt(0);
12195
+ meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
12196
+ { lo: firstLower, hi: firstLower },
12197
+ { lo: firstUpper, hi: firstUpper }
12198
+ ] } : firstSet2;
12199
+ }
12200
+ const expected = directTerminalFailureExpected({ tag: "literal", value, caseInsensitive });
12201
+ const parse2 = !caseInsensitive && value.length === 1 ? (() => {
12202
+ const code = value.charCodeAt(0);
12203
+ return function parse3(input, pos, ctx) {
12204
+ if (input.charCodeAt(pos) === code) {
12205
+ const span = { start: pos, end: pos + 1 };
12206
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
12207
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
12208
+ return { ok: true, value, span };
12209
+ }
12210
+ return failAt(ctx, expected, pos);
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 };
11217
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
11218
12232
  };
11219
12233
  }
11220
12234
 
@@ -11285,124 +12299,6 @@ function ref() {
11285
12299
  return slot;
11286
12300
  }
11287
12301
 
11288
- // src/combinators/token.ts
11289
- function semanticLeafValue(_ctx, _input, _start, _end, value) {
11290
- return value;
11291
- }
11292
- function sourceLeafValue(ctx, input, start, end, value) {
11293
- return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
11294
- }
11295
- function token(root) {
11296
- const meta = {
11297
- firstSet: root._meta.firstSet,
11298
- canMatchNewline: root._meta.canMatchNewline,
11299
- isTrivia: false
11300
- };
11301
- return {
11302
- _tag: "token",
11303
- _meta: meta,
11304
- _def: { tag: "token", parser: root },
11305
- parse(input, pos, ctx) {
11306
- const savedTrivia = ctx.trivia;
11307
- const savedKinds = ctx.triviaKindLabels;
11308
- const savedBuf = ctx._cstBuf;
11309
- const savedChildren = ctx._cstChildren;
11310
- const savedLeaves = ctx._cstLeaves;
11311
- const savedRaw = ctx._cstRawChildren;
11312
- const savedTriviaLog = ctx._cstTriviaLog;
11313
- const savedOuterTriviaLog = ctx._triviaLog;
11314
- const savedRootTriviaLog = ctx._rootTriviaLog;
11315
- const wasCapturing = cstCaptureActive(ctx);
11316
- ctx.trivia = void 0;
11317
- ctx.triviaKindLabels = void 0;
11318
- ctx._cstBuf = void 0;
11319
- ctx._cstChildren = void 0;
11320
- ctx._cstLeaves = void 0;
11321
- ctx._cstRawChildren = void 0;
11322
- ctx._cstTriviaLog = void 0;
11323
- ctx._triviaLog = void 0;
11324
- ctx._rootTriviaLog = void 0;
11325
- let result;
11326
- try {
11327
- result = root.parse(input, pos, ctx);
11328
- } finally {
11329
- ctx.trivia = savedTrivia;
11330
- ctx.triviaKindLabels = savedKinds;
11331
- ctx._cstBuf = savedBuf;
11332
- ctx._cstChildren = savedChildren;
11333
- ctx._cstLeaves = savedLeaves;
11334
- ctx._cstRawChildren = savedRaw;
11335
- ctx._cstTriviaLog = savedTriviaLog;
11336
- ctx._triviaLog = savedOuterTriviaLog;
11337
- ctx._rootTriviaLog = savedRootTriviaLog;
11338
- }
11339
- if (!result.ok) return result;
11340
- const span = result.span;
11341
- const value = input.slice(pos, span.end);
11342
- if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11343
- return { ok: true, value, span };
11344
- }
11345
- };
11346
- }
11347
- function makeLeaf(root, fn, sourceCstValue) {
11348
- const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
11349
- const meta = {
11350
- firstSet: root._meta.firstSet,
11351
- canMatchNewline: root._meta.canMatchNewline,
11352
- isTrivia: false
11353
- };
11354
- return {
11355
- _tag: "leaf",
11356
- _meta: meta,
11357
- _def: {
11358
- tag: "leaf",
11359
- parser: root,
11360
- fn,
11361
- ...sourceCstValue ? { cstValue: "source" } : {}
11362
- },
11363
- parse(input, pos, ctx) {
11364
- const savedBuf = ctx._cstBuf;
11365
- const savedChildren = ctx._cstChildren;
11366
- const savedLeaves = ctx._cstLeaves;
11367
- const savedRaw = ctx._cstRawChildren;
11368
- const savedTriviaLog = ctx._cstTriviaLog;
11369
- const savedOuterTriviaLog = ctx._triviaLog;
11370
- const wasCapturing = cstCaptureActive(ctx);
11371
- ctx._cstBuf = void 0;
11372
- ctx._cstChildren = void 0;
11373
- ctx._cstLeaves = void 0;
11374
- ctx._cstRawChildren = void 0;
11375
- ctx._cstTriviaLog = void 0;
11376
- ctx._triviaLog = void 0;
11377
- let result;
11378
- try {
11379
- result = root.parse(input, pos, ctx);
11380
- } finally {
11381
- ctx._cstBuf = savedBuf;
11382
- ctx._cstChildren = savedChildren;
11383
- ctx._cstLeaves = savedLeaves;
11384
- ctx._cstRawChildren = savedRaw;
11385
- ctx._cstTriviaLog = savedTriviaLog;
11386
- ctx._triviaLog = savedOuterTriviaLog;
11387
- }
11388
- if (!result.ok) return result;
11389
- const value = fn(result.value, result.span);
11390
- if (wasCapturing) pushCstLeaf(ctx, {
11391
- _tag: "leaf",
11392
- value: cstValue(ctx, input, pos, result.span.end, value),
11393
- span: result.span
11394
- });
11395
- return { ok: true, value, span: result.span };
11396
- }
11397
- };
11398
- }
11399
- function leaf(root, fn) {
11400
- return makeLeaf(root, fn, false);
11401
- }
11402
- function sourceLeaf(root, fn) {
11403
- return makeLeaf(root, fn, true);
11404
- }
11405
-
11406
12302
  // src/combinators/scanTo.ts
11407
12303
  function resolveScanSkip(explicitSkip, raw, ctx) {
11408
12304
  if (raw) return [];
@@ -11711,37 +12607,120 @@ function clearOf(ranges, input, from, to) {
11711
12607
  return true;
11712
12608
  }
11713
12609
 
11714
- // src/table/run-support.ts
11715
- function lineCol(ctx, offset) {
11716
- const starts = ctx._lineStarts ?? [0];
11717
- let lo = 0, hi = starts.length - 1;
11718
- while (lo < hi) {
11719
- const mid = lo + hi + 1 >> 1;
11720
- if (starts[mid] <= offset) lo = mid;
11721
- else hi = mid - 1;
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;
11722
12632
  }
11723
- return [lo + 1, offset - starts[lo] + 1];
11724
- }
11725
- function spanLines(ctx, start, end) {
11726
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
11727
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
11728
12633
  }
11729
- function rawEntry(v, input, s, e) {
11730
- if (typeof v === "object" && v !== null) {
11731
- const tg = v._tag;
11732
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
11733
- }
11734
- return {
11735
- _tag: "leaf",
11736
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
11737
- span: { start: s, end: e }
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;
11738
12661
  };
11739
- }
11740
- function lead(input, pos) {
11741
- if (pos >= input.length) return -1;
11742
- const c = input.charCodeAt(pos);
11743
- if (c < 55296 || c > 56319) return c;
11744
- return input.codePointAt(pos) ?? c;
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;
11745
12724
  }
11746
12725
 
11747
12726
  // src/grammar-metadata.ts
@@ -11839,12 +12818,6 @@ function hasDirectBuilder(prog) {
11839
12818
  return false;
11840
12819
  }
11841
12820
 
11842
- // src/cst/root-trivia-scope.ts
11843
- var ROOT_TRIVIA_SCOPE_REFUSAL = "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.";
11844
- function refuseUnclassifiedRootScope(strict) {
11845
- if (strict === true) throw new TypeError(ROOT_TRIVIA_SCOPE_REFUSAL);
11846
- }
11847
-
11848
12821
  // src/table/cell.ts
11849
12822
  var FAIL = /* @__PURE__ */ Symbol("pm.fail");
11850
12823
  var newEndCell = () => ({ e: 0 });
@@ -11895,6 +12868,7 @@ function assemble(t2, prog, cfg) {
11895
12868
  const swapLegal = !cfg.trackLines;
11896
12869
  const hostCst = cfg.hostCst;
11897
12870
  const REC = prog.rec === 1 && cfg.tolerant;
12871
+ const PROBE = cfg.probe;
11898
12872
  const sentinels = /* @__PURE__ */ new Map();
11899
12873
  function sentinelFor(cls) {
11900
12874
  if (cls < 0) return void 0;
@@ -11940,6 +12914,8 @@ function assemble(t2, prog, cfg) {
11940
12914
  }
11941
12915
  const memo = /* @__PURE__ */ new Map();
11942
12916
  const reached = /* @__PURE__ */ new Set();
12917
+ const NULLABLE = /* @__PURE__ */ new Map();
12918
+ const CLEAN = REC ? () => false : failCleanAnalysis(code);
11943
12919
  function pushLeaf(ctx, value, s, e) {
11944
12920
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
11945
12921
  pushCstLeaf(ctx, lf);
@@ -12138,6 +13114,22 @@ function assemble(t2, prog, cfg) {
12138
13114
  return node2;
12139
13115
  };
12140
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
+ }
12141
13133
  function plainProjectNode(child, projection, type) {
12142
13134
  return (input, pos, ctx) => {
12143
13135
  const sCh = ctx._cstChildren;
@@ -12508,21 +13500,27 @@ function assemble(t2, prog, cfg) {
12508
13500
  }
12509
13501
  function dispatchBranch(child, usesRouted) {
12510
13502
  if (!usesRouted) {
12511
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
12512
- 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;
12513
13512
  const v = child(input, selEnd, ctx);
12514
13513
  if (v === FAIL) {
12515
- rollbackTrivia(ctx, mark);
13514
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12516
13515
  ctx._fc = true;
12517
13516
  return FAIL;
12518
13517
  }
12519
13518
  return [key, v];
12520
13519
  };
12521
13520
  }
12522
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13521
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
12523
13522
  const savedRouted = ctx._routed;
12524
- rollbackTrivia(ctx, selectorMark);
12525
- const mark = saveTriviaMark(ctx);
13523
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12526
13524
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
12527
13525
  let v;
12528
13526
  try {
@@ -12531,7 +13529,7 @@ function assemble(t2, prog, cfg) {
12531
13529
  ctx._routed = savedRouted;
12532
13530
  }
12533
13531
  if (v === FAIL) {
12534
- rollbackTrivia(ctx, mark);
13532
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12535
13533
  ctx._fc = true;
12536
13534
  return FAIL;
12537
13535
  }
@@ -12539,12 +13537,12 @@ function assemble(t2, prog, cfg) {
12539
13537
  };
12540
13538
  }
12541
13539
  function dispatchArmBlock(start, a0, a1, a2, a3, next) {
12542
- return (arm, input, pos, selEnd, key, selectorMark, ctx) => {
12543
- if (arm === start) return a0(input, pos, selEnd, key, selectorMark, ctx);
12544
- if (arm === start + 1) return a1(input, pos, selEnd, key, selectorMark, ctx);
12545
- if (arm === start + 2) return a2(input, pos, selEnd, key, selectorMark, ctx);
12546
- if (arm === start + 3) return a3(input, pos, selEnd, key, selectorMark, ctx);
12547
- 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);
12548
13546
  };
12549
13547
  }
12550
13548
  function trackLinesInto(ctx, input, end) {
@@ -12563,7 +13561,7 @@ function assemble(t2, prog, cfg) {
12563
13561
  if (flight !== void 0) return flight.fwd;
12564
13562
  const selected = HYBRID?.byIp[ip];
12565
13563
  if (selected !== void 0) {
12566
- const piece2 = hybridPiece(selected);
13564
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
12567
13565
  memo.set(ip, piece2);
12568
13566
  reached.add(ip);
12569
13567
  return piece2;
@@ -12574,14 +13572,55 @@ function assemble(t2, prog, cfg) {
12574
13572
  target = p;
12575
13573
  } };
12576
13574
  inFlight.set(ip, holder);
12577
- const op = code[ip];
12578
- 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]) : countedPiece(lower(ip), ip);
13575
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
12579
13576
  inFlight.delete(ip);
12580
13577
  holder.set(piece);
12581
13578
  memo.set(ip, piece);
12582
13579
  reached.add(ip);
12583
13580
  return piece;
12584
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
+ }
12585
13624
  function lower(ip) {
12586
13625
  const op = code[ip];
12587
13626
  switch (op) {
@@ -13126,8 +14165,10 @@ function assemble(t2, prog, cfg) {
13126
14165
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13127
14166
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13128
14167
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14168
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13129
14169
  const v = child(input, pos, ctx);
13130
14170
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14171
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13131
14172
  if (v === FAIL) {
13132
14173
  EC.e = pos;
13133
14174
  return null;
@@ -13138,6 +14179,20 @@ function assemble(t2, prog, cfg) {
13138
14179
  };
13139
14180
  }
13140
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
+ }
13141
14196
  const child = link(code[ip + 1]);
13142
14197
  const xf = fx[code[ip + 2]];
13143
14198
  const gate = lookaheadClass(code[ip + 1]);
@@ -13155,8 +14210,10 @@ function assemble(t2, prog, cfg) {
13155
14210
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13156
14211
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13157
14212
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14213
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13158
14214
  const v = child(input, pos, ctx);
13159
14215
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14216
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13160
14217
  if (v === FAIL) {
13161
14218
  ctx._fe = pos;
13162
14219
  ctx._fx = xf;
@@ -13169,12 +14226,13 @@ function assemble(t2, prog, cfg) {
13169
14226
  case OP_OPT: {
13170
14227
  const child = link(code[ip + 1]);
13171
14228
  const gate = lookaheadClass(code[ip + 1]);
14229
+ const childClean = CLEAN(code[ip + 1]);
13172
14230
  return (input, pos, ctx) => {
13173
14231
  if (gate !== null && !classHas2(gate, lead(input, pos))) {
13174
14232
  EC.e = pos;
13175
14233
  return null;
13176
14234
  }
13177
- const need = markCst(ctx);
14235
+ const need = !childClean && markCst(ctx);
13178
14236
  const mRaw = MRAW;
13179
14237
  const mTl = MTL;
13180
14238
  const mLv = MLV;
@@ -13372,6 +14430,9 @@ function assemble(t2, prog, cfg) {
13372
14430
  const projection = reducer < 0 ? ~reducer : -1;
13373
14431
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
13374
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]);
13375
14436
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
13376
14437
  if (count === 1) return (input, cur, ctx, values, inherited) => {
13377
14438
  cur = r0(input, cur, ctx, inherited);
@@ -13417,7 +14478,7 @@ function assemble(t2, prog, cfg) {
13417
14478
  };
13418
14479
  };
13419
14480
  if (REC) {
13420
- const first2 = link(code[base]);
14481
+ const first2 = linkFirst();
13421
14482
  const firstSync = sentinelFor(code[base + n]);
13422
14483
  const runnerAt = (i) => {
13423
14484
  const sync = sentinelFor(code[base + n + i]);
@@ -13453,13 +14514,13 @@ function assemble(t2, prog, cfg) {
13453
14514
  const bindRunners = (start) => {
13454
14515
  const count = Math.min(4, n - start);
13455
14516
  const at = (offset) => runnerAt(start + offset);
13456
- const never = () => -1;
14517
+ const never2 = () => -1;
13457
14518
  return runnerBlock(
13458
14519
  count,
13459
14520
  at(0),
13460
- count > 1 ? at(1) : never,
13461
- count > 2 ? at(2) : never,
13462
- count > 3 ? at(3) : never,
14521
+ count > 1 ? at(1) : never2,
14522
+ count > 2 ? at(2) : never2,
14523
+ count > 3 ? at(3) : never2,
13463
14524
  start + count < n ? bindRunners(start + count) : void 0
13464
14525
  );
13465
14526
  };
@@ -13509,15 +14570,31 @@ function assemble(t2, prog, cfg) {
13509
14570
  let hasAdj = false;
13510
14571
  for (let i = 1; i < n; i++) {
13511
14572
  const kidIp = code[base + i];
13512
- 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)) {
13513
14574
  hasAdj = true;
13514
14575
  break;
13515
14576
  }
13516
14577
  }
13517
14578
  if (hasAdj) {
13518
- const first2 = link(code[base]);
14579
+ const first2 = linkFirst();
13519
14580
  const runnerAt = (i) => {
13520
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
+ }
13521
14598
  if (code[kidIp] !== OP_ADJ) {
13522
14599
  const kid = link(kidIp);
13523
14600
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -13542,13 +14619,13 @@ function assemble(t2, prog, cfg) {
13542
14619
  const bindRunners = (start) => {
13543
14620
  const count = Math.min(4, n - start);
13544
14621
  const at = (offset) => runnerAt(start + offset);
13545
- const never = () => -1;
14622
+ const never2 = () => -1;
13546
14623
  return runnerBlock(
13547
14624
  count,
13548
14625
  at(0),
13549
- count > 1 ? at(1) : never,
13550
- count > 2 ? at(2) : never,
13551
- count > 3 ? at(3) : never,
14626
+ count > 1 ? at(1) : never2,
14627
+ count > 2 ? at(2) : never2,
14628
+ count > 3 ? at(3) : never2,
13552
14629
  start + count < n ? bindRunners(start + count) : void 0
13553
14630
  );
13554
14631
  };
@@ -13585,7 +14662,7 @@ function assemble(t2, prog, cfg) {
13585
14662
  };
13586
14663
  }
13587
14664
  if (n === 1) {
13588
- const k0 = link(code[base]);
14665
+ const k0 = linkFirst();
13589
14666
  if (fused) {
13590
14667
  return (input, pos, ctx) => {
13591
14668
  const v = k0(input, pos, ctx);
@@ -13607,7 +14684,7 @@ function assemble(t2, prog, cfg) {
13607
14684
  };
13608
14685
  }
13609
14686
  if (n === 2) {
13610
- const k0 = link(code[base]), k1 = link(code[base + 1]);
14687
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
13611
14688
  if (fused) {
13612
14689
  return (input, pos, ctx) => {
13613
14690
  const v0 = k0(input, pos, ctx);
@@ -13638,7 +14715,7 @@ function assemble(t2, prog, cfg) {
13638
14715
  };
13639
14716
  }
13640
14717
  if (n === 3) {
13641
- 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]);
13642
14719
  if (fused) {
13643
14720
  return (input, pos, ctx) => {
13644
14721
  const v0 = k0(input, pos, ctx);
@@ -13732,7 +14809,7 @@ function assemble(t2, prog, cfg) {
13732
14809
  start + count < n ? bind(start + count) : void 0
13733
14810
  );
13734
14811
  };
13735
- const first = link(code[base]);
14812
+ const first = linkFirst();
13736
14813
  const tail = bind(1);
13737
14814
  const runDirectTerms = (input, pos, ctx, values) => {
13738
14815
  const v0 = first(input, pos, ctx);
@@ -13771,6 +14848,8 @@ function assemble(t2, prog, cfg) {
13771
14848
  const n = code[ip + 2];
13772
14849
  const choiceFx = fx[code[ip + 3]];
13773
14850
  const base = ip + 4;
14851
+ for (let i = 0; i < n; i++) link(code[base + i]);
14852
+ const armsClean = CLEAN(ip);
13774
14853
  if (table.exclusive) {
13775
14854
  const ascii = table.ascii;
13776
14855
  const hi = table.hi;
@@ -13910,7 +14989,7 @@ function assemble(t2, prog, cfg) {
13910
14989
  if (n === 3) addGate(g2, 4);
13911
14990
  return (input, pos, ctx) => {
13912
14991
  const c = lead(input, pos);
13913
- const need = markCst(ctx);
14992
+ const need = !armsClean && markCst(ctx);
13914
14993
  const mRaw = MRAW;
13915
14994
  const mTl = MTL;
13916
14995
  const mLv = MLV;
@@ -14127,7 +15206,7 @@ function assemble(t2, prog, cfg) {
14127
15206
  if (pn !== 0) {
14128
15207
  return (input, pos, ctx) => {
14129
15208
  const c = lead(input, pos);
14130
- const need = markCst(ctx);
15209
+ const need = !armsClean && markCst(ctx);
14131
15210
  const mRaw = MRAW;
14132
15211
  const mTl = MTL;
14133
15212
  const mLv = MLV;
@@ -14184,7 +15263,7 @@ function assemble(t2, prog, cfg) {
14184
15263
  }
14185
15264
  return (input, pos, ctx) => {
14186
15265
  const c = lead(input, pos);
14187
- const need = markCst(ctx);
15266
+ const need = !armsClean && markCst(ctx);
14188
15267
  const mRaw = MRAW;
14189
15268
  const mTl = MTL;
14190
15269
  const mLv = MLV;
@@ -14232,7 +15311,7 @@ function assemble(t2, prog, cfg) {
14232
15311
  }
14233
15312
  return (input, pos, ctx) => {
14234
15313
  const c = lead(input, pos);
14235
- const need = markCst(ctx);
15314
+ const need = !armsClean && markCst(ctx);
14236
15315
  const mRaw = MRAW;
14237
15316
  const mTl = MTL;
14238
15317
  const mLv = MLV;
@@ -14286,6 +15365,21 @@ function assemble(t2, prog, cfg) {
14286
15365
  return lit(input, pos, ctx);
14287
15366
  };
14288
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
+ }
14289
15383
  case OP_ARMGATE: {
14290
15384
  const pred = fns[code[ip + 1]];
14291
15385
  const child = link(code[ip + 2]);
@@ -14354,6 +15448,7 @@ function assemble(t2, prog, cfg) {
14354
15448
  const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
14355
15449
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
14356
15450
  const skipBeforeFirst = sepIp < 0 && min === 0;
15451
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
14357
15452
  if (REC) {
14358
15453
  const itemFx2 = fx[code[ip + 6]];
14359
15454
  const sepSent = sentinelFor(code[ip + 7]);
@@ -14450,6 +15545,8 @@ function assemble(t2, prog, cfg) {
14450
15545
  const out = collect ? [] : void 0;
14451
15546
  const hasTrivia = ctx.trivia !== void 0;
14452
15547
  const needMark = rollbackNeeded(ctx);
15548
+ const markLater = needMark && (!itemClean || hasTrivia);
15549
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
14453
15550
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
14454
15551
  let cur = pos;
14455
15552
  let count = 0;
@@ -14457,14 +15554,15 @@ function assemble(t2, prog, cfg) {
14457
15554
  if (max >= 0 && count >= max) break;
14458
15555
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
14459
15556
  if (count >= min && sep === void 0 && !hasTrivia && gateItems && !itemMayStart(input, cur)) break;
14460
- if (needMark) markCst(ctx);
14461
- const mRaw = needMark ? MRAW : 0;
14462
- const mTl = needMark ? MTL : 0;
14463
- const mLv = needMark ? MLV : 0;
14464
- const mFl = needMark ? ctx._fields?.length ?? 0 : 0;
14465
- const mEr = needMark ? ctx._errors?.length ?? 0 : 0;
14466
- const mLog = needMark ? ctx._triviaLog?.length ?? 0 : 0;
14467
- 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;
14468
15566
  let itemStart = cur;
14469
15567
  let sepEnd = -1;
14470
15568
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -14476,7 +15574,7 @@ function assemble(t2, prog, cfg) {
14476
15574
  if (sepLeads) LEAD.at = cur;
14477
15575
  const sv = sep(input, sp, ctx);
14478
15576
  if (sv === FAIL) {
14479
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15577
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14480
15578
  if (committed3(ctx)) return FAIL;
14481
15579
  break;
14482
15580
  }
@@ -14487,25 +15585,25 @@ function assemble(t2, prog, cfg) {
14487
15585
  itemStart = skipTrivia(input, itemStart, ctx);
14488
15586
  }
14489
15587
  if (itemStart >= input.length && viaRepItem) {
14490
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15588
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14491
15589
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14492
15590
  break;
14493
15591
  }
14494
15592
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
14495
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15593
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14496
15594
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14497
15595
  break;
14498
15596
  }
14499
15597
  ctx._fc = false;
14500
15598
  const v = child(input, itemStart, ctx);
14501
15599
  if (v === FAIL) {
14502
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15600
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14503
15601
  if (committed3(ctx)) return FAIL;
14504
15602
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14505
15603
  break;
14506
15604
  }
14507
15605
  if (EC.e === itemStart && viaRepItem) {
14508
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15606
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14509
15607
  break;
14510
15608
  }
14511
15609
  if (out !== void 0) out.push(v);
@@ -14579,7 +15677,14 @@ function assemble(t2, prog, cfg) {
14579
15677
  const runArm = n === 0 ? void 0 : bindArms(0);
14580
15678
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
14581
15679
  return (input, pos, ctx) => {
14582
- 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;
14583
15688
  const selVal = selector(input, pos, ctx);
14584
15689
  if (selVal === FAIL) return FAIL;
14585
15690
  const selEnd = EC.e;
@@ -14591,9 +15696,9 @@ function assemble(t2, prog, cfg) {
14591
15696
  ctx._fx = expected;
14592
15697
  return FAIL;
14593
15698
  }
14594
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
15699
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14595
15700
  }
14596
- 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);
14597
15702
  };
14598
15703
  }
14599
15704
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -14629,7 +15734,8 @@ function assemble(t2, prog, cfg) {
14629
15734
  return nd;
14630
15735
  };
14631
15736
  }
14632
- const child = link(code[ip + 2]);
15737
+ const child = NODE_BODY ?? link(code[ip + 2]);
15738
+ NODE_BODY = void 0;
14633
15739
  const proj = code[ip + 4];
14634
15740
  const buildIdx = code[ip + 1];
14635
15741
  const type = k[code[ip + 5]];
@@ -14653,6 +15759,30 @@ function assemble(t2, prog, cfg) {
14653
15759
  if (build !== void 0 && proj < 0 && flags === 18) {
14654
15760
  return childrenOnlyFieldsBuildNode(child, build);
14655
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
+ }
14656
15786
  if (build !== void 0 && proj < 0 && flags === 32) {
14657
15787
  return collapseBuildNode(child, build);
14658
15788
  }
@@ -14801,6 +15931,8 @@ function assemble(t2, prog, cfg) {
14801
15931
  }
14802
15932
  const notChild = scalarTerminalNotChild(code, ip);
14803
15933
  if (notChild >= 0) scalarFor(notChild);
15934
+ const peekChild = scalarTerminalPeekChild(code, ip);
15935
+ if (peekChild >= 0) scalarFor(peekChild);
14804
15936
  }
14805
15937
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
14806
15938
  if (pre !== void 0) {
@@ -14860,7 +15992,8 @@ function assemble(t2, prog, cfg) {
14860
15992
  t2.lexPrograms,
14861
15993
  LEAD,
14862
15994
  triviaFieldCapture,
14863
- skipDeferredTrivia
15995
+ skipDeferredTrivia,
15996
+ collapseEmpty
14864
15997
  );
14865
15998
  emitReached = new Set(pre.reached);
14866
15999
  if (emitted.ext !== void 0) HYBRID = emitted;
@@ -14946,7 +16079,8 @@ function assemble(t2, prog, cfg) {
14946
16079
  t2.lexPrograms,
14947
16080
  LEAD,
14948
16081
  triviaFieldCapture,
14949
- skipDeferredTrivia
16082
+ skipDeferredTrivia,
16083
+ collapseEmpty
14950
16084
  );
14951
16085
  emitReached = em.reached;
14952
16086
  } catch (e) {
@@ -15213,7 +16347,7 @@ function emitClassPool(classes) {
15213
16347
  if (classes.length < 2) return array;
15214
16348
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
15215
16349
  if (delimiter === void 0) return array;
15216
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16350
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
15217
16351
  return split.length < array.length ? split : array;
15218
16352
  }
15219
16353
  function emitConst(v) {
@@ -16820,339 +17954,85 @@ function reportDuplication(opt, analyze) {
16820
17954
  if (level === "error") throw new Error(`parseman: ${duplicationFindingCount(report)} duplication/overlap finding(s)
16821
17955
  ${lines2.join("\n")}`);
16822
17956
  for (const l of lines2) console.warn(l);
16823
- }
16824
- return report;
16825
- }
16826
- function runDuplicationDiagnostic(combinator, opt) {
16827
- return reportDuplication(opt, (o) => analyzeDuplication(combinator, o));
16828
- }
16829
- function runDuplicationDiagnosticRules(ruleMap, opt) {
16830
- return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
16831
- }
16832
-
16833
- // src/table/compile-rule-map.ts
16834
- function resolveHostMode(ruleMap, explicit) {
16835
- return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
16836
- }
16837
- function resolveTrackLines(ruleMap, explicit) {
16838
- return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
16839
- }
16840
- function withAmbient(ruleMap, opts) {
16841
- if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
16842
- const wrappers = /* @__PURE__ */ new Map();
16843
- return ruleMap.map(([name, rule2]) => {
16844
- if (rule2._meta.isTrivia) return [name, rule2];
16845
- const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
16846
- const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
16847
- if (!addTrivia && !addScanSkip) return [name, rule2];
16848
- let wrapped = wrappers.get(rule2);
16849
- if (wrapped === void 0) {
16850
- wrapped = {
16851
- ...rule2,
16852
- _meta: {
16853
- ...rule2._meta,
16854
- ...addTrivia ? { grammarTrivia: opts.trivia } : {},
16855
- ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
16856
- }
16857
- };
16858
- wrappers.set(rule2, wrapped);
16859
- }
16860
- return [name, wrapped];
16861
- });
16862
- }
16863
- function compileRuleMapRunnable(ruleMap, opts = {}) {
16864
- const encoded = encodeForRun(ruleMap, opts);
16865
- if (encoded === null) return null;
16866
- const { prog, hostMode, plan } = encoded;
16867
- const artifact = closureArtifact(prog);
16868
- const reflection = collectGrammarReflection(ruleMap);
16869
- return {
16870
- keys: ruleMap.map(([key]) => key),
16871
- hostMode,
16872
- hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule2]) => hasDirectBuildDef(rule2)),
16873
- reflection,
16874
- ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16875
- // Reflection rides on the map's metadata prototype from birth. Only `compile()`
16876
- // asks to specialise; every other caller runs the closure artifact.
16877
- rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
16878
- prog: artifact
16879
- };
16880
- }
16881
- function encodeForRun(ruleMap, opts) {
16882
- runDuplicationDiagnosticRules(ruleMap, opts.duplication);
16883
- const encodeMap = withAmbient(ruleMap, opts);
16884
- const plan = opts.coverage === true ? buildGrammarPlan(
16885
- encodeMap.map(([, rule2]) => rule2),
16886
- Object.fromEntries(encodeMap.filter(([, rule2]) => rule2._def.tag !== "lazy"))
16887
- ) : void 0;
16888
- const hostMode = resolveHostMode(ruleMap, opts.hostMode);
16889
- const settings = {
16890
- hostMode,
16891
- ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
16892
- ...opts.recovery === true ? { recovery: true } : {},
16893
- ...plan === void 0 ? {} : { coverage: plan }
16894
- };
16895
- try {
16896
- const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
16897
- return { prog, fnSrcs, hostMode, plan };
16898
- } catch (e) {
16899
- opts.refusals?.push(e instanceof Error ? e.message : String(e));
16900
- return null;
16901
- }
16902
- }
16903
-
16904
- // src/compiler/value-usage.ts
16905
- function markUnusedValues(root) {
16906
- const seenConsumed = /* @__PURE__ */ new WeakSet();
16907
- const seenUnconsumed = /* @__PURE__ */ new WeakSet();
16908
- const mark = (def, consumed) => {
16909
- if (consumed) def.valueUnused = false;
16910
- else if (def.valueUnused !== false) def.valueUnused = true;
16911
- };
16912
- const visit = (c, consumed) => {
16913
- const seen = consumed ? seenConsumed : seenUnconsumed;
16914
- if (seen.has(c)) return;
16915
- seen.add(c);
16916
- const def = c._def;
16917
- switch (def.tag) {
16918
- case "many":
16919
- case "oneOrMore":
16920
- mark(def, consumed);
16921
- visit(def.parser, consumed);
16922
- return;
16923
- case "optional":
16924
- visit(def.parser, consumed);
16925
- return;
16926
- case "sequence":
16927
- mark(def, consumed);
16928
- for (const p of def.parsers) visit(p, consumed);
16929
- return;
16930
- case "choice":
16931
- for (const p of def.parsers) visit(p, consumed);
16932
- return;
16933
- case "dispatch":
16934
- visit(def.selector, consumed);
16935
- for (const entry of def.cases) visit(entry.parser, consumed);
16936
- if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
16937
- if (def.otherwise) visit(def.otherwise, consumed);
16938
- return;
16939
- case "node":
16940
- visit(def.parser, false);
16941
- return;
16942
- case "transform":
16943
- visit(def.parser, true);
16944
- return;
16945
- case "field":
16946
- visit(def.parser, true);
16947
- return;
16948
- case "sepBy":
16949
- visit(def.parser, true);
16950
- visit(def.separator, false);
16951
- return;
16952
- case "not":
16953
- case "peek":
16954
- visit(def.parser, false);
16955
- return;
16956
- case "grammar":
16957
- visit(def.parser, consumed);
16958
- if (def.triviaParser) visit(def.triviaParser, false);
16959
- return;
16960
- case "recover":
16961
- visit(def.parser, consumed);
16962
- visit(def.sentinel, false);
16963
- return;
16964
- case "token":
16965
- visit(def.parser, false);
16966
- return;
16967
- case "label":
16968
- case "trivia":
16969
- case "attempt":
16970
- case "withCtx":
16971
- case "expect":
16972
- visit(def.parser, consumed);
16973
- return;
16974
- case "leaf":
16975
- visit(def.parser, true);
16976
- return;
16977
- case "lazy":
16978
- return;
16979
- default:
16980
- return;
16981
- }
16982
- };
16983
- const resolveRoot = (c) => {
16984
- const guard = /* @__PURE__ */ new Set();
16985
- let cur = c;
16986
- while (!guard.has(cur)) {
16987
- const d = cur._def;
16988
- if (d.tag === "grammar") {
16989
- guard.add(cur);
16990
- cur = d.parser;
16991
- continue;
16992
- }
16993
- if (d.tag !== "lazy") return cur;
16994
- guard.add(cur);
16995
- try {
16996
- cur = d.thunk();
16997
- } catch {
16998
- return c;
16999
- }
17000
- }
17001
- return cur;
17002
- };
17003
- 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));
17004
17965
  }
17005
17966
 
17006
- // src/combinators/grammar.ts
17007
- function annotateResultLines(result, index) {
17008
- const annotated = { ...result, span: annotateSpan(result.span, index) };
17009
- const errors = annotated.errors;
17010
- if (errors) {
17011
- ;
17012
- annotated.errors = errors.map((error) => ({
17013
- ...error,
17014
- span: annotateSpan(error.span, index)
17015
- }));
17016
- }
17017
- 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";
17018
17970
  }
17019
- function createParseLineContext(input, pos) {
17020
- const lineIndex = createLineIndex();
17021
- if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
17022
- return { lineIndex, lineScannedTo: pos };
17971
+ function resolveTrackLines(ruleMap, explicit) {
17972
+ return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
17023
17973
  }
17024
- var TRACK_LINES_ON = () => true;
17025
- var TRACK_LINES_OFF = () => false;
17026
- var TRACK_LINES_INHERIT = (ctx) => ctx?.trackLines === true;
17027
- function parser(opts, root) {
17028
- const clearTrivia = opts.trivia === null;
17029
- const opaqueRootCapture = opts.rootCapture === "opaque";
17030
- if (opaqueRootCapture && opts.trivia === void 0) {
17031
- throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
17032
- }
17033
- const scopeTrivia = clearTrivia ? void 0 : opts.trivia ?? void 0;
17034
- const scopeLabels = scopeTrivia?._meta?.triviaKindLabels;
17035
- const refuseUnclassified = scopeTrivia !== void 0 && !scopeTrivia._meta?.rootTriviaClassified && !opaqueRootCapture;
17036
- const forceCaptureTrivia = opts.captureTrivia === true;
17037
- const trackLinesPolicy = opts.trackLines === true ? "on" : opts.trackLines === false ? "off" : "inherit";
17038
- const trackLinesOf = trackLinesPolicy === "on" ? TRACK_LINES_ON : trackLinesPolicy === "off" ? TRACK_LINES_OFF : TRACK_LINES_INHERIT;
17039
- const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
17040
- const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
17041
- const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
17042
- const rootScalar = scalarOf(root);
17043
- const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
17044
- const parseScalar = scalarEligible ? (input, pos, ctx) => {
17045
- const savedTrivia = ctx.trivia;
17046
- const savedLabels = ctx.triviaKindLabels;
17047
- if (clearTrivia) {
17048
- ctx.trivia = void 0;
17049
- ctx.triviaKindLabels = void 0;
17050
- } else if (scopeTrivia !== void 0) {
17051
- ctx.trivia = scopeTrivia;
17052
- ctx.triviaKindLabels = scopeLabels;
17053
- }
17054
- const end = rootScalar(input, pos, ctx);
17055
- ctx.trivia = savedTrivia;
17056
- ctx.triviaKindLabels = savedLabels;
17057
- return end;
17058
- } : void 0;
17059
- let publicScalar;
17060
- const grammar = {
17061
- _tag: "grammar",
17062
- _meta: {
17063
- ...root._meta,
17064
- // Trivia classification describes this grammar's own active trivia
17065
- // scope. A directly nested grammar may have classified trivia of its
17066
- // own, but that must not advertise classification for this wrapper.
17067
- triviaKindLabels: void 0,
17068
- rootTriviaClassified: void 0,
17069
- ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
17070
- ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
17071
- },
17072
- _def: {
17073
- tag: "grammar",
17074
- parser: root,
17075
- triviaParser: scopeTrivia,
17076
- clearTrivia,
17077
- ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
17078
- ...opts.captureTrivia ? { captureTrivia: true } : {},
17079
- trackLines: opts.trackLines ?? false,
17080
- constructionTrackLines: trackLinesPolicy,
17081
- ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
17082
- },
17083
- _parseScalar: parseScalar,
17084
- parse(input, pos, _ctx) {
17085
- if (pos === void 0 && _ctx === void 0) {
17086
- publicScalar ??= scalarRootOf(grammar) ?? null;
17087
- if (publicScalar) {
17088
- const ctx2 = createParseContext();
17089
- const end = publicScalar(input, 0, ctx2);
17090
- if (end < 0) {
17091
- const at = ~end;
17092
- return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
17093
- }
17094
- 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 } : {}
17095
17990
  }
17096
- }
17097
- if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
17098
- const trackLines = trackLinesOf(_ctx);
17099
- const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
17100
- const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
17101
- const ctx = _ctx === void 0 ? createParseContext() : { ..._ctx };
17102
- ctx.trackLines = trackLines;
17103
- if (lineIndex) ctx._lineIndex = lineIndex;
17104
- if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
17105
- if (clearTrivia) {
17106
- ctx.trivia = void 0;
17107
- ctx.triviaKindLabels = void 0;
17108
- } else if (scopeTrivia !== void 0) {
17109
- ctx.trivia = scopeTrivia;
17110
- if (scopeLabels) ctx.triviaKindLabels = scopeLabels;
17111
- }
17112
- if (forceCaptureTrivia || _ctx?.captureTrivia) ctx.captureTrivia = true;
17113
- if (ownCaptureMask !== void 0) ctx._triviaCaptureMask = ownCaptureMask;
17114
- else if (inheritCaptureMask) ctx._triviaCaptureMask = triviaKindMask(_ctx?.triviaKindLabels, captureKinds);
17115
- if (opaqueRootCapture) ctx._rootTriviaCapture = false;
17116
- const result = root.parse(input, pos ?? 0, ctx);
17117
- if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
17118
- _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
17119
- }
17120
- return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
17991
+ };
17992
+ wrappers.set(rule2, wrapped);
17121
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
17122
18013
  };
17123
- return grammar;
17124
18014
  }
17125
- var _analyzed = /* @__PURE__ */ new WeakSet();
17126
- function parse(combinator, input, opts = {}) {
17127
- if (!_analyzed.has(combinator)) {
17128
- _analyzed.add(combinator);
17129
- markUnusedValues(combinator);
17130
- }
17131
- if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
17132
- return combinator.parse(input);
17133
- }
17134
- const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
17135
- const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
17136
- const lineIndex = lineContext?.lineIndex;
17137
- const _errors = opts.recover ? [] : void 0;
17138
- const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
17139
- const grammarTrivia = combinator._meta.grammarTrivia;
17140
- const grammarScanSkip = combinator._meta.grammarScanSkip;
17141
- const ctx = createParseContext();
17142
- ctx.trackLines = trackLines;
17143
- if (lineIndex) ctx._lineIndex = lineIndex;
17144
- if (lineContext) ctx._lineScannedTo = lineContext.lineScannedTo;
17145
- if (grammarTrivia !== void 0) {
17146
- ctx.trivia = grammarTrivia;
17147
- 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;
17148
18035
  }
17149
- if (grammarScanSkip !== void 0) ctx.scanSkip = grammarScanSkip;
17150
- if (_errors !== void 0) ctx._errors = _errors;
17151
- if (_probe !== void 0) ctx._probe = _probe;
17152
- const result = combinator.parse(input, 0, ctx);
17153
- if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
17154
- const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
17155
- return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
17156
18036
  }
17157
18037
 
17158
18038
  // src/compiler/linker.ts
@@ -17252,7 +18132,7 @@ function analyzeGrammarGating(grammar, opts) {
17252
18132
  }
17253
18133
 
17254
18134
  // src/analysis/diagnose.ts
17255
- var isCombinator = (g) => typeof g === "object" && g !== null && "_def" in g;
18135
+ var isCombinator2 = (g) => typeof g === "object" && g !== null && "_def" in g;
17256
18136
  var isRuleEntries = (g) => Array.isArray(g);
17257
18137
  function diagnoseGrammar(grammar, opts) {
17258
18138
  const depth = degradationCaptureDepth();
@@ -17273,7 +18153,7 @@ function examinedNothing(d) {
17273
18153
  return d.summary.totalChoices === 0 && d.summary.unanalysable > 0;
17274
18154
  }
17275
18155
  function runAnalysis(grammar, opts) {
17276
- if (isCombinator(grammar)) return analyzeGating(grammar, opts);
18156
+ if (isCombinator2(grammar)) return analyzeGating(grammar, opts);
17277
18157
  if (isRuleEntries(grammar)) return analyzeGatingRules(grammar, opts);
17278
18158
  return analyzeGrammarGating(grammar, opts);
17279
18159
  }
@@ -18032,16 +18912,16 @@ function ownSource(fn) {
18032
18912
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
18033
18913
  }
18034
18914
  function compile(target, second, third) {
18035
- if (!isCombinator2(target)) return compileMap(target, second);
18915
+ if (!isCombinator3(target)) return compileMap(target, second);
18036
18916
  return compileRoot(target, second, third);
18037
18917
  }
18038
- function isCombinator2(x) {
18918
+ function isCombinator3(x) {
18039
18919
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
18040
18920
  }
18041
18921
  function compileMap(grammar, opts = {}) {
18042
18922
  const entries = [];
18043
18923
  for (const [key, value] of Object.entries(grammar)) {
18044
- 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`);
18045
18925
  if (value._def.tag === "lazy") {
18046
18926
  try {
18047
18927
  value._def.thunk();
@@ -18355,49 +19235,6 @@ function digestValue(value, prefix = "", options) {
18355
19235
  return sha.digest("hex");
18356
19236
  }
18357
19237
 
18358
- // src/combinators/attempt.ts
18359
- function containOption(options) {
18360
- if (options === void 0) return false;
18361
- for (const key of Object.keys(options)) {
18362
- if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
18363
- }
18364
- if (options.contain !== void 0 && typeof options.contain !== "boolean") {
18365
- throw new TypeError("attempt(): `contain` must be a boolean");
18366
- }
18367
- return options.contain === true;
18368
- }
18369
- function attempt(parser2, options) {
18370
- const contain = containOption(options);
18371
- const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
18372
- let failExpected;
18373
- return {
18374
- _tag: "attempt",
18375
- _meta: parser2._meta,
18376
- _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
18377
- parse(input, pos, ctx) {
18378
- if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
18379
- if (failExpected === void 0) {
18380
- const e = deriveExpected(parser2);
18381
- failExpected = e.length > 0 ? e : [parser2._tag];
18382
- }
18383
- return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
18384
- }
18385
- const mark = saveCstMark(ctx);
18386
- const log = ctx._triviaLog?.length;
18387
- const rootLog = ctx._rootTriviaLog?.length;
18388
- const split = ctx._columnsSplit;
18389
- const result = parser2.parse(input, pos, ctx);
18390
- if (result.ok) return result;
18391
- rollbackCstCapture(ctx, mark);
18392
- ctx._columnsSplit = split;
18393
- if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
18394
- if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
18395
- if (result.committed && !contain) return result;
18396
- return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
18397
- }
18398
- };
18399
- }
18400
-
18401
19238
  // src/combinators/not.ts
18402
19239
  function not(combinator) {
18403
19240
  const meta = {