parseman 0.48.1 → 0.50.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 (83) hide show
  1. package/dist/analysis/commitment.d.ts +2 -1
  2. package/dist/analysis/commitment.d.ts.map +1 -1
  3. package/dist/analysis/diagnostics.js +1931 -861
  4. package/dist/analysis/diagnostics.js.map +3 -3
  5. package/dist/analysis/rebuild.d.ts.map +1 -1
  6. package/dist/cli/index.js +1236 -164
  7. package/dist/cli/index.js.map +3 -3
  8. package/dist/combinators/trivia-skip.d.ts +1 -1
  9. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  10. package/dist/compiler/build-arity.d.ts +16 -0
  11. package/dist/compiler/build-arity.d.ts.map +1 -1
  12. package/dist/compiler/degradation.d.ts +0 -2
  13. package/dist/compiler/degradation.d.ts.map +1 -1
  14. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  15. package/dist/compiler/linker.d.ts.map +1 -1
  16. package/dist/compiler/token-alphabet.d.ts +11 -0
  17. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  18. package/dist/compiler/token-capability.js +185 -20
  19. package/dist/compiler/token-capability.js.map +1 -1
  20. package/dist/cst/capture-buffer.d.ts +5 -1
  21. package/dist/cst/capture-buffer.d.ts.map +1 -1
  22. package/dist/index.js +1354 -278
  23. package/dist/index.js.map +3 -3
  24. package/dist/language-service/index.js +2 -1
  25. package/dist/language-service/index.js.map +1 -1
  26. package/dist/plugin/direct-builder-static.d.ts +20 -0
  27. package/dist/plugin/direct-builder-static.d.ts.map +1 -1
  28. package/dist/plugin/entry-supercompiler.d.ts +48 -0
  29. package/dist/plugin/entry-supercompiler.d.ts.map +1 -0
  30. package/dist/plugin/evaluator.d.ts +13 -0
  31. package/dist/plugin/evaluator.d.ts.map +1 -1
  32. package/dist/plugin/index.d.ts.map +1 -1
  33. package/dist/plugin/index.js +2118 -376
  34. package/dist/plugin/index.js.map +3 -3
  35. package/dist/run/index.js +2 -1
  36. package/dist/run/index.js.map +1 -1
  37. package/dist/spec/index.js +29 -7
  38. package/dist/spec/index.js.map +1 -1
  39. package/dist/table/assemble.d.ts.map +1 -1
  40. package/dist/table/compile-rule-map.d.ts +6 -5
  41. package/dist/table/compile-rule-map.d.ts.map +1 -1
  42. package/dist/table/emit-assembly.d.ts +6 -1
  43. package/dist/table/emit-assembly.d.ts.map +1 -1
  44. package/dist/table/encode.d.ts.map +1 -1
  45. package/dist/table/index.js +1298 -231
  46. package/dist/table/index.js.map +3 -3
  47. package/dist/table/ops.d.ts +3 -2
  48. package/dist/table/ops.d.ts.map +1 -1
  49. package/dist/table/program.d.ts +15 -1
  50. package/dist/table/program.d.ts.map +1 -1
  51. package/dist/table/scalar-terminal.d.ts +30 -0
  52. package/dist/table/scalar-terminal.d.ts.map +1 -1
  53. package/dist/table/site-labels.d.ts +8 -0
  54. package/dist/table/site-labels.d.ts.map +1 -1
  55. package/dist/types.d.ts +8 -2
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/version.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/src/analysis/commitment.ts +19 -8
  60. package/src/analysis/rebuild.ts +1 -0
  61. package/src/combinators/trivia-skip.ts +2 -2
  62. package/src/compiler/build-arity.ts +50 -0
  63. package/src/compiler/degradation.ts +0 -6
  64. package/src/compiler/ir-serialize.ts +17 -3
  65. package/src/compiler/linker.ts +14 -1
  66. package/src/compiler/token-alphabet.ts +322 -28
  67. package/src/cst/capture-buffer.ts +34 -11
  68. package/src/plugin/direct-builder-static.ts +116 -12
  69. package/src/plugin/entry-supercompiler.ts +567 -0
  70. package/src/plugin/evaluator.ts +60 -2
  71. package/src/plugin/index.ts +147 -4
  72. package/src/table/assemble.ts +125 -42
  73. package/src/table/compile-rule-map.ts +8 -7
  74. package/src/table/compile.ts +7 -8
  75. package/src/table/emit-assembly.ts +646 -126
  76. package/src/table/emit.ts +1 -1
  77. package/src/table/encode.ts +132 -7
  78. package/src/table/ops.ts +3 -2
  79. package/src/table/program.ts +44 -3
  80. package/src/table/scalar-terminal.ts +213 -1
  81. package/src/table/site-labels.ts +22 -9
  82. package/src/types.ts +1 -1
  83. package/src/version.ts +1 -1
@@ -405,7 +405,7 @@ function beginCstNodeCapture(ctx) {
405
405
  function finishCstBuf(buf) {
406
406
  if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
407
407
  const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
408
- const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
408
+ const rawChildren = buf.noRaw === true ? EMPTY : buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
409
409
  const triviaLog = buf.tl ?? EMPTY_TL;
410
410
  return { children: children2, rawChildren, triviaLog };
411
411
  }
@@ -437,7 +437,8 @@ function pushCstChild(ctx, built, rawEntry2) {
437
437
  b.single = void 0;
438
438
  } else b.single = built;
439
439
  }
440
- if (b.raw) b.raw.push(rawEntry2);
440
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 0) + 1;
441
+ else if (b.raw) b.raw.push(rawEntry2);
441
442
  else if (b.rawSingle !== void 0) {
442
443
  b.raw = [b.rawSingle, rawEntry2];
443
444
  b.rawSingle = void 0;
@@ -451,6 +452,7 @@ function pushCstChild(ctx, built, rawEntry2) {
451
452
  function cstRawLen(ctx) {
452
453
  const b = ctx._cstBuf;
453
454
  if (b) {
455
+ if (b.noRaw === true) return b.rawLen ?? 0;
454
456
  if (b.raw) return b.raw.length;
455
457
  return b.rawSingle !== void 0 ? 1 : 0;
456
458
  }
@@ -510,19 +512,37 @@ function rollbackCstCaptureAt(ctx, raw, tlog, leaves, fields, errors) {
510
512
  if (ctx._errors && errors !== void 0 && ctx._errors.length !== errors) ctx._errors.length = errors;
511
513
  const b = ctx._cstBuf;
512
514
  if (b) {
513
- rollbackBufList(b, "raw", "rawSingle", raw);
514
- rollbackBufList(b, "ch", "single", leaves);
515
+ if (b.noRaw === true) {
516
+ if (b.rawLen !== raw) b.rawLen = raw;
517
+ } else {
518
+ const rawList = b.raw;
519
+ if (rawList) {
520
+ if (raw === 0) b.raw = void 0;
521
+ else if (raw === 1) {
522
+ b.rawSingle = rawList[0];
523
+ b.raw = void 0;
524
+ } else if (rawList.length !== raw) rawList.length = raw;
525
+ } else if (raw === 0) b.rawSingle = void 0;
526
+ }
527
+ const childList = b.ch;
528
+ if (childList) {
529
+ if (leaves === 0) b.ch = void 0;
530
+ else if (leaves === 1) {
531
+ b.single = childList[0];
532
+ b.ch = void 0;
533
+ } else if (childList.length !== leaves) childList.length = leaves;
534
+ } else if (leaves === 0) b.single = void 0;
515
535
  if (b.tl) {
516
536
  if (tlog === 0) b.tl = void 0;
517
537
  else if (b.tl.length !== tlog) b.tl.length = tlog;
518
538
  }
519
- if (ctx._fields && ctx._fields.length !== fields) ctx._fields.length = fields;
539
+ if (ctx._fields && fields !== void 0 && ctx._fields.length !== fields) ctx._fields.length = fields;
520
540
  return;
521
541
  }
522
542
  if (ctx._cstRawChildren && ctx._cstRawChildren.length !== raw) ctx._cstRawChildren.length = raw;
523
543
  if (ctx._cstTriviaLog && ctx._cstTriviaLog.length !== tlog) ctx._cstTriviaLog.length = tlog;
524
544
  if (ctx._cstLeaves && ctx._cstLeaves.length !== leaves) ctx._cstLeaves.length = leaves;
525
- if (ctx._fields && ctx._fields.length !== fields) ctx._fields.length = fields;
545
+ if (ctx._fields && fields !== void 0 && ctx._fields.length !== fields) ctx._fields.length = fields;
526
546
  }
527
547
  function pushCstTriviaEntry(ctx, start, end, kindIndex) {
528
548
  const insertIdx = cstRawLen(ctx);
@@ -2620,222 +2640,780 @@ function analyzeChoice(p, d, rule2, resolve) {
2620
2640
  };
2621
2641
  }
2622
2642
 
2623
- // src/recovery/scan.ts
2624
- function probeAt(sentinel, input, pos, ctx) {
2625
- const s = {
2626
- _probe: ctx._probe,
2627
- _errors: ctx._errors,
2628
- _cstLeaves: ctx._cstLeaves,
2629
- _cstChildren: ctx._cstChildren,
2630
- _cstRawChildren: ctx._cstRawChildren,
2631
- _cstTriviaLog: ctx._cstTriviaLog,
2632
- _triviaLog: ctx._triviaLog,
2633
- _rootTriviaLog: ctx._rootTriviaLog,
2634
- _fields: ctx._fields,
2635
- _cstBuf: ctx._cstBuf,
2636
- _tolerant: ctx._tolerant,
2637
- _sync: ctx._sync
2638
- };
2639
- ctx._probe = void 0;
2640
- ctx._errors = void 0;
2641
- ctx._cstLeaves = void 0;
2642
- ctx._cstChildren = void 0;
2643
- ctx._cstRawChildren = void 0;
2644
- ctx._cstTriviaLog = void 0;
2645
- ctx._triviaLog = void 0;
2646
- ctx._rootTriviaLog = void 0;
2647
- ctx._fields = void 0;
2648
- ctx._cstBuf = void 0;
2649
- ctx._tolerant = void 0;
2650
- ctx._sync = void 0;
2651
- try {
2652
- return sentinel.parse(input, pos, ctx).ok;
2653
- } finally {
2654
- ctx._probe = s._probe;
2655
- ctx._errors = s._errors;
2656
- ctx._cstLeaves = s._cstLeaves;
2657
- ctx._cstChildren = s._cstChildren;
2658
- ctx._cstRawChildren = s._cstRawChildren;
2659
- ctx._cstTriviaLog = s._cstTriviaLog;
2660
- ctx._triviaLog = s._triviaLog;
2661
- ctx._rootTriviaLog = s._rootTriviaLog;
2662
- ctx._fields = s._fields;
2663
- ctx._cstBuf = s._cstBuf;
2664
- ctx._tolerant = s._tolerant;
2665
- ctx._sync = s._sync;
2666
- }
2667
- }
2668
- function orSentinel(a, b) {
2669
- if (b === void 0) return a;
2670
- return {
2671
- _tag: "orSentinel",
2672
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
2673
- _def: { tag: "unknown" },
2674
- parse(input, pos, ctx) {
2675
- const ra = a.parse(input, pos, ctx);
2676
- if (ra.ok) return ra;
2677
- return b.parse(input, pos, ctx);
2678
- }
2679
- };
2680
- }
2681
- function firstSetSentinel(fs) {
2682
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
2683
- const ranges = fs.ranges;
2684
- return {
2685
- _tag: "firstSetSentinel",
2686
- _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
2687
- _def: { tag: "unknown" },
2688
- parse(input, pos) {
2689
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
2690
- if (code !== void 0) {
2691
- for (const r of ranges) {
2692
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
2693
- }
2694
- }
2695
- return { ok: false, expected: [], span: { start: pos, end: pos } };
2696
- }
2697
- };
2698
- }
2699
- function recoverScan(input, from, ctx, sync, expected) {
2700
- let scanPos = from;
2701
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
2702
- const span = { start: from, end: scanPos };
2703
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
2704
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
2705
- ctx._errors?.push(error);
2706
- return { error, end: scanPos };
2707
- }
2708
- function matchesAt(sentinel, input, pos, ctx) {
2709
- return probeAt(sentinel, input, pos, ctx);
2643
+ // src/regex/first-set.ts
2644
+ var ANY = { t: "any" };
2645
+ var EMPTY2 = { t: "empty" };
2646
+ function charNode(set, nl) {
2647
+ return { t: "char", set, nl };
2710
2648
  }
2711
- function captureError(ctx, error) {
2712
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
2649
+ function rangesToSet(ranges) {
2650
+ let fs = empty();
2651
+ for (const [lo, hi] of ranges) fs = union(fs, fromRange(lo, hi));
2652
+ return fs;
2713
2653
  }
2714
-
2715
- // src/combinators/expect.ts
2716
- function deriveExpected(c) {
2717
- return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
2654
+ function rangesHaveNewline(ranges) {
2655
+ return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
2718
2656
  }
2719
- function derive(c, seen) {
2720
- const deriveExpected2 = (p) => derive(p, seen);
2721
- const def = c._def;
2722
- switch (def.tag) {
2723
- case "literal":
2724
- return [JSON.stringify(def.value)];
2725
- case "regex":
2726
- return [`/${def.source}/`];
2727
- case "keywords":
2728
- return def.words.map((w) => JSON.stringify(w));
2729
- case "label":
2730
- return [def.label];
2731
- case "choice":
2732
- return def.parsers.flatMap(deriveExpected2);
2733
- case "dispatch":
2734
- return deriveExpected2(def.selector);
2735
- // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
2736
- // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
2737
- // able to fail first — deriving from term 0 alone named a token the parse
2738
- // never actually required. A leading `not(…)` is zero-width and contributes
2739
- // nothing (its own expectation is about what must NOT be here), but it is
2740
- // nullable, so keep scanning past it. Stop at the first term that must match.
2741
- case "sequence": {
2742
- const out = [];
2743
- for (const term of def.parsers) {
2744
- if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
2745
- if (!matchesEmpty(term)) break;
2746
- }
2747
- return out;
2748
- }
2749
- case "attempt":
2750
- return deriveExpected2(def.parser);
2751
- // Delegating wrappers whose first-token failure is their inner parser's — must
2752
- // pass through so a start-failure (and the first-set-miss fast-path in attempt/
2753
- // node, which reads this) names the real expected token, not the wrapper tag.
2754
- case "field":
2755
- case "withCtx":
2756
- case "recover":
2757
- return deriveExpected2(def.parser);
2758
- case "expect":
2759
- return def.expected;
2760
- case "node":
2761
- case "grammar":
2762
- case "trivia":
2763
- case "token":
2764
- case "leaf":
2765
- case "optional":
2766
- case "many":
2767
- case "oneOrMore":
2768
- case "transform":
2769
- case "not":
2770
- case "peek":
2771
- return deriveExpected2(def.parser);
2772
- // A bare routed() can only fail as "there is no routed token here". With a
2773
- // fallback, THAT is the branch that can fail, so its expectations are the useful
2774
- // ones — the routed path either succeeds or is not taken.
2775
- case "routed":
2776
- return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
2777
- // A bare adjacency assertion names the JOIN it requires. Inside a sequence it is
2778
- // skipped entirely (isZeroWidthAssertion, above), which is the normal path.
2779
- case "adjacency":
2780
- return [def.polarity];
2781
- case "lazy": {
2782
- const name = c._ruleName;
2783
- if (seen.has(c)) return name ? [name] : [];
2784
- seen.add(c);
2785
- try {
2786
- return deriveExpected2(def.thunk());
2787
- } catch {
2788
- return name ? [name] : [];
2789
- } finally {
2790
- seen.delete(c);
2791
- }
2657
+ var BAIL = /* @__PURE__ */ Symbol("regex-bail");
2658
+ function parseRegex(src) {
2659
+ let i = 0;
2660
+ const parseAlt = () => {
2661
+ const arms = [parseSeq()];
2662
+ while (src[i] === "|") {
2663
+ i++;
2664
+ arms.push(parseSeq());
2792
2665
  }
2793
- default:
2794
- return [];
2795
- }
2796
- }
2797
- function expect(combinator, label2) {
2798
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
2799
- const meta = {
2800
- firstSet: combinator._meta.firstSet,
2801
- canMatchNewline: combinator._meta.canMatchNewline,
2802
- isTrivia: false
2666
+ return arms.length === 1 ? arms[0] : { t: "alt", arms };
2803
2667
  };
2804
- return {
2805
- _tag: "expect",
2806
- _meta: meta,
2807
- _def: { tag: "expect", parser: combinator, label: label2, expected },
2808
- parse(input, pos, ctx) {
2809
- const result = combinator.parse(input, pos, ctx);
2810
- if (result.ok) return result;
2811
- const span = { start: pos, end: pos };
2812
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
2813
- ctx._errors?.push(error);
2814
- if (ctx._tolerant) captureError(ctx, error);
2815
- return { ok: true, value: error, span: { start: pos, end: pos } };
2668
+ const parseSeq = () => {
2669
+ const parts = [];
2670
+ while (i < src.length) {
2671
+ const ch2 = src[i];
2672
+ if (ch2 === "|" || ch2 === ")") break;
2673
+ parts.push(parseQuantified());
2816
2674
  }
2675
+ if (parts.length === 0) return EMPTY2;
2676
+ return parts.length === 1 ? parts[0] : { t: "seq", parts };
2817
2677
  };
2818
- }
2819
-
2820
- // src/combinators/choice.ts
2821
- function choice(...args) {
2822
- const parsers = args.map((a) => "gate" in a ? a.combinator : a);
2823
- const gates = args.map((a) => "gate" in a ? a.gate : null);
2824
- const hasGates = gates.some((g) => g !== null);
2825
- const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
2826
- let combined = { kind: "empty" };
2827
- for (const p of parsers) combined = union(combined, p._meta.firstSet);
2828
- const meta = {
2829
- firstSet: combined,
2830
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2831
- isTrivia: false,
2832
- disjoint
2678
+ const parseQuantified = () => {
2679
+ const atom = parseAtom();
2680
+ const ch2 = src[i];
2681
+ let min = null;
2682
+ if (ch2 === "*") {
2683
+ min = 0;
2684
+ i++;
2685
+ } else if (ch2 === "+") {
2686
+ min = 1;
2687
+ i++;
2688
+ } else if (ch2 === "?") {
2689
+ min = 0;
2690
+ i++;
2691
+ } else if (ch2 === "{") {
2692
+ min = parseBraceQuantifier();
2693
+ }
2694
+ if (min === null) return atom;
2695
+ if (src[i] === "?") i++;
2696
+ return { t: "rep", node: atom, min };
2833
2697
  };
2834
- const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
2835
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
2836
- let greedyLitMap = null;
2837
- let sortedParsers = null;
2838
- const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
2698
+ const parseBraceQuantifier = () => {
2699
+ const close = src.indexOf("}", i);
2700
+ if (close === -1) return null;
2701
+ const m = /^(\d+)(?:,(\d*))?$/.exec(src.slice(i + 1, close));
2702
+ if (!m) return null;
2703
+ i = close + 1;
2704
+ return Number.parseInt(m[1], 10);
2705
+ };
2706
+ const parseAtom = () => {
2707
+ const ch2 = src[i];
2708
+ switch (ch2) {
2709
+ case "(":
2710
+ return parseGroup();
2711
+ case "[":
2712
+ return parseClass();
2713
+ case ".":
2714
+ i++;
2715
+ return charNode(any(), false);
2716
+ // `.` matches any char except line terminators
2717
+ case "\\":
2718
+ return parseEscape();
2719
+ case "^":
2720
+ case "$":
2721
+ i++;
2722
+ return EMPTY2;
2723
+ // anchors are zero-width
2724
+ case "{":
2725
+ i++;
2726
+ return charNode(fromRange(123, 123), false);
2727
+ // a `{` with nothing to quantify is a literal brace
2728
+ default:
2729
+ i += ch2.length;
2730
+ return charNode(fromRange(ch2.codePointAt(0), ch2.codePointAt(0)), ch2 === "\n");
2731
+ }
2732
+ };
2733
+ const parseGroup = () => {
2734
+ i++;
2735
+ let lookaround = false;
2736
+ if (src[i] === "?") {
2737
+ const c1 = src[i + 1];
2738
+ if (c1 === ":") i += 2;
2739
+ else if (c1 === "=" || c1 === "!") {
2740
+ i += 2;
2741
+ lookaround = true;
2742
+ } else if (c1 === "<") {
2743
+ const c2 = src[i + 2];
2744
+ if (c2 === "=" || c2 === "!") {
2745
+ i += 3;
2746
+ lookaround = true;
2747
+ } else {
2748
+ const gt = src.indexOf(">", i);
2749
+ if (gt === -1) throw BAIL;
2750
+ i = gt + 1;
2751
+ }
2752
+ } else throw BAIL;
2753
+ }
2754
+ const inner = parseAlt();
2755
+ if (src[i] !== ")") throw BAIL;
2756
+ i++;
2757
+ return lookaround ? EMPTY2 : inner;
2758
+ };
2759
+ const parseClass = () => {
2760
+ let k = i + 1;
2761
+ const negated = src[k] === "^";
2762
+ if (negated) k++;
2763
+ let body = "";
2764
+ while (k < src.length && src[k] !== "]") {
2765
+ if (src[k] === "\\") {
2766
+ body += src[k] + (src[k + 1] ?? "");
2767
+ k += 2;
2768
+ } else {
2769
+ body += src[k];
2770
+ k++;
2771
+ }
2772
+ }
2773
+ if (src[k] !== "]") throw BAIL;
2774
+ i = k + 1;
2775
+ const ranges = parseClassRanges(body);
2776
+ if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
2777
+ if (!ranges) return charNode(any(), true);
2778
+ return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
2779
+ };
2780
+ const parseEscape = () => {
2781
+ const e = src[i + 1];
2782
+ if (e === void 0) throw BAIL;
2783
+ if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
2784
+ const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
2785
+ i += 6;
2786
+ return charNode(fromRange(cp, cp), cp === 10);
2787
+ }
2788
+ if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
2789
+ const cp = Number.parseInt(src.slice(i + 2, i + 4), 16);
2790
+ i += 4;
2791
+ return charNode(fromRange(cp, cp), cp === 10);
2792
+ }
2793
+ i += 2;
2794
+ switch (e) {
2795
+ case "d":
2796
+ return charNode(rangesToSet(shorthandRanges("d")), false);
2797
+ case "w":
2798
+ return charNode(rangesToSet(shorthandRanges("w")), false);
2799
+ case "s":
2800
+ return charNode(rangesToSet(shorthandRanges("s")), true);
2801
+ case "D":
2802
+ case "W":
2803
+ case "S":
2804
+ return charNode(any(), true);
2805
+ // negated shorthand → widen
2806
+ case "b":
2807
+ case "B":
2808
+ return EMPTY2;
2809
+ // word boundary: zero-width
2810
+ case "n":
2811
+ return charNode(fromRange(10, 10), true);
2812
+ case "r":
2813
+ return charNode(fromRange(13, 13), false);
2814
+ case "t":
2815
+ return charNode(fromRange(9, 9), false);
2816
+ case "f":
2817
+ return charNode(fromRange(12, 12), false);
2818
+ case "v":
2819
+ return charNode(fromRange(11, 11), false);
2820
+ case "0":
2821
+ return charNode(fromRange(0, 0), false);
2822
+ default:
2823
+ if (e >= "1" && e <= "9") return ANY;
2824
+ return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
2825
+ }
2826
+ };
2827
+ const node2 = parseAlt();
2828
+ if (i < src.length) throw BAIL;
2829
+ return node2;
2830
+ }
2831
+ function nullable(n) {
2832
+ switch (n.t) {
2833
+ case "char":
2834
+ return false;
2835
+ case "any":
2836
+ return true;
2837
+ case "empty":
2838
+ return true;
2839
+ case "seq":
2840
+ return n.parts.every(nullable);
2841
+ case "alt":
2842
+ return n.arms.some(nullable);
2843
+ case "rep":
2844
+ return n.min === 0 || nullable(n.node);
2845
+ }
2846
+ }
2847
+ function firstSet(n) {
2848
+ switch (n.t) {
2849
+ case "char":
2850
+ return n.set;
2851
+ case "any":
2852
+ return any();
2853
+ case "empty":
2854
+ return empty();
2855
+ case "rep":
2856
+ return firstSet(n.node);
2857
+ case "alt": {
2858
+ let fs = empty();
2859
+ for (const arm of n.arms) fs = union(fs, firstSet(arm));
2860
+ return fs;
2861
+ }
2862
+ case "seq": {
2863
+ let fs = empty();
2864
+ for (const part of n.parts) {
2865
+ fs = union(fs, firstSet(part));
2866
+ if (!nullable(part)) break;
2867
+ }
2868
+ return fs;
2869
+ }
2870
+ }
2871
+ }
2872
+ function canConsumeNewline(n) {
2873
+ switch (n.t) {
2874
+ case "char":
2875
+ return n.nl;
2876
+ case "any":
2877
+ return true;
2878
+ case "empty":
2879
+ return false;
2880
+ case "rep":
2881
+ return canConsumeNewline(n.node);
2882
+ case "alt":
2883
+ return n.arms.some(canConsumeNewline);
2884
+ case "seq":
2885
+ return n.parts.some(canConsumeNewline);
2886
+ }
2887
+ }
2888
+ function regexCanMatchEmpty(source) {
2889
+ try {
2890
+ return nullable(parseRegex(source));
2891
+ } catch {
2892
+ return true;
2893
+ }
2894
+ }
2895
+ function firstSetFromRegex(source) {
2896
+ let ast;
2897
+ try {
2898
+ ast = parseRegex(source);
2899
+ } catch {
2900
+ return { firstSet: any(), canMatchNewline: true };
2901
+ }
2902
+ if (nullable(ast)) return { firstSet: any(), canMatchNewline: canConsumeNewline(ast) };
2903
+ return { firstSet: firstSet(ast), canMatchNewline: canConsumeNewline(ast) };
2904
+ }
2905
+
2906
+ // src/analysis/commitment.ts
2907
+ function mayFail(p, seen = /* @__PURE__ */ new Set()) {
2908
+ if (seen.has(p)) return true;
2909
+ seen.add(p);
2910
+ const d = p._def;
2911
+ switch (d.tag) {
2912
+ case "literal":
2913
+ return d.value.length > 0;
2914
+ case "trivia":
2915
+ return false;
2916
+ // `optional`/`many`/a min-0 `sepBy` swallow an ORDINARY failure — zero
2917
+ // repetitions is a match. They do NOT swallow a COMMITTED one: a dispatch
2918
+ // that has selected an arm and then failed inside it breaks out past every
2919
+ // enclosing repeat, straight to the fallible boundary. So these are total
2920
+ // exactly when their body cannot commit. (Measured: treating them as
2921
+ // unconditionally total left an extra zero-width leaf in
2922
+ // `BareInterpolatedSelector` on benchmark.less — a rollback the legacy
2923
+ // build fired and this one had deleted.)
2924
+ case "optional":
2925
+ case "many":
2926
+ return mayCommitFailure(d.parser);
2927
+ case "sepBy":
2928
+ return d.min >= 1 ? mayFail(d.parser, seen) : mayCommitFailure(d.parser) || mayCommitFailure(d.separator);
2929
+ case "oneOrMore":
2930
+ return mayFail(d.parser, seen);
2931
+ case "sequence":
2932
+ return d.parsers.some((x) => mayFail(x, seen));
2933
+ // Delegating wrappers: as fallible as what they wrap.
2934
+ case "node":
2935
+ case "transform":
2936
+ case "label":
2937
+ case "field":
2938
+ case "expect":
2939
+ case "withCtx":
2940
+ case "grammar":
2941
+ case "token":
2942
+ case "leaf":
2943
+ return mayFail(d.parser, seen);
2944
+ case "lazy": {
2945
+ try {
2946
+ return mayFail(d.thunk(), seen);
2947
+ } catch {
2948
+ return true;
2949
+ }
2950
+ }
2951
+ // An adjacency assertion is a TEST — failing is its whole job.
2952
+ case "adjacency":
2953
+ return true;
2954
+ default:
2955
+ return true;
2956
+ }
2957
+ }
2958
+ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set(), triviaActive = true) {
2959
+ if (seen.has(p)) return false;
2960
+ seen.add(p);
2961
+ const d = p._def;
2962
+ switch (d.tag) {
2963
+ // Atomic / non-capturing-then-failing: a failure happens before any push.
2964
+ case "literal":
2965
+ case "regex":
2966
+ case "keywords":
2967
+ case "guard":
2968
+ // Adjacency probes with `_cap = 0` / no `commit()`: it cannot push anything.
2969
+ case "adjacency":
2970
+ case "not":
2971
+ // peek(): emitted under a non-capturing probe ctx and zero-width on both
2972
+ // outcomes, so it can never leave a partial capture behind.
2973
+ case "peek":
2974
+ case "trivia":
2975
+ case "token":
2976
+ case "leaf":
2977
+ case "scanTo":
2978
+ case "unknown":
2979
+ return false;
2980
+ // node() captures into its own private buffers and rolls them back on
2981
+ // failure (emitNode restores _ctx.* and never pushes on the !ok path).
2982
+ case "node":
2983
+ return false;
2984
+ // choice/firstMatch already roll back each failed arm; on overall failure
2985
+ // nothing committed remains.
2986
+ case "choice":
2987
+ return false;
2988
+ case "dispatch":
2989
+ return capturesLeaf(d.selector, new Set(seen)) || d.cases.some((x) => mayLeavePartialCapture(x.parser, new Set(seen), triviaActive) || capturesLeaf(x.parser, new Set(seen))) || (d.matchers ? d.matchers.some((x) => mayLeavePartialCapture(x.parser, new Set(seen), triviaActive) || capturesLeaf(x.parser, new Set(seen))) : false) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, new Set(seen), triviaActive) || capturesLeaf(d.otherwise, new Set(seen)) : false);
2990
+ case "attempt":
2991
+ return false;
2992
+ // optional never fails; many/oneOrMore only "fail" with zero captured items.
2993
+ case "optional":
2994
+ case "many":
2995
+ case "oneOrMore":
2996
+ return false;
2997
+ // sepBy emits its own per-iteration rollback in emitSepBy.
2998
+ case "sepBy":
2999
+ return false;
3000
+ // A sequence is the real case: an earlier capturing term followed by a term
3001
+ // that can fail leaves the earlier captures buffered.
3002
+ //
3003
+ // BOTH halves of that sentence are load-bearing, and the second half is what
3004
+ // this walk exists to exploit. "Some earlier term captures" alone was the old
3005
+ // test, and it is true of very nearly every sequence in a real grammar — a
3006
+ // sequence almost always opens with a literal or a node. The rollback is only
3007
+ // reachable if something AFTER the capture can still fail; once the remainder
3008
+ // is total (`optional`/`many`/trivia/a min-0 `sepBy`), the sequence has no
3009
+ // failure path left to roll back from, and the save+restore is dead code.
3010
+ //
3011
+ // `captured` tracks whether anything is in the buffers yet as the scan moves
3012
+ // left to right. Two things put it there:
3013
+ // - a term that captures (`capturesLeaf`/`hasNodeDef`), and
3014
+ // - the inter-term TRIVIA scan, which under `capturing` pushes into
3015
+ // `_cstRawChildren`/`_cstTriviaLog` BEFORE the term at each boundary
3016
+ // i >= 1. `emitSeqValues` only rewinds that push on the term's SUCCESS
3017
+ // path (the "matched empty, so leave the whitespace out of the span"
3018
+ // branch); a term that FAILS breaks straight out with the trivia still
3019
+ // buffered, so from boundary 1 onward the buffers are dirty regardless of
3020
+ // what the earlier terms did.
3021
+ // Each term is also asked about itself: a nested sequence can leave its own
3022
+ // partial capture behind, and its terms are emitted inline into this same
3023
+ // block with no boundary of their own to roll them back.
3024
+ case "sequence": {
3025
+ const parts = d.parsers;
3026
+ let captured = false;
3027
+ for (let i = 0; i < parts.length; i++) {
3028
+ const part = parts[i];
3029
+ if (i > 0 && triviaActive) captured = true;
3030
+ if (captured && mayFail(part)) return true;
3031
+ if (mayLeavePartialCapture(part, seen, triviaActive)) return true;
3032
+ if (capturesLeaf(part) || hasNodeDef(part)) captured = true;
3033
+ }
3034
+ return false;
3035
+ }
3036
+ // Delegating wrappers: defer to the wrapped parser.
3037
+ case "transform":
3038
+ case "label":
3039
+ case "field":
3040
+ case "expect":
3041
+ case "withCtx":
3042
+ case "grammar":
3043
+ return mayLeavePartialCapture(d.parser, seen, triviaActive);
3044
+ case "recover":
3045
+ return mayLeavePartialCapture(d.parser, seen, triviaActive);
3046
+ case "lazy": {
3047
+ try {
3048
+ return mayLeavePartialCapture(d.thunk(), seen, triviaActive);
3049
+ } catch {
3050
+ return true;
3051
+ }
3052
+ }
3053
+ // Unknown shapes: be safe and keep the rollback.
3054
+ default:
3055
+ return true;
3056
+ }
3057
+ }
3058
+ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
3059
+ if (seen.has(p)) return false;
3060
+ seen.add(p);
3061
+ const d = p._def;
3062
+ switch (d.tag) {
3063
+ case "literal":
3064
+ case "regex":
3065
+ case "keywords":
3066
+ case "node":
3067
+ case "token":
3068
+ case "routed":
3069
+ case "leaf":
3070
+ return true;
3071
+ case "not":
3072
+ case "peek":
3073
+ case "guard":
3074
+ case "adjacency":
3075
+ case "trivia":
3076
+ case "unknown":
3077
+ return false;
3078
+ case "sequence":
3079
+ case "choice":
3080
+ return d.parsers.some((x) => capturesLeaf(x, seen));
3081
+ case "dispatch":
3082
+ return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => capturesLeaf(entry.parser, seen)) : false) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
3083
+ case "sepBy":
3084
+ return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
3085
+ case "many":
3086
+ case "oneOrMore":
3087
+ case "optional":
3088
+ case "attempt":
3089
+ case "transform":
3090
+ case "label":
3091
+ case "field":
3092
+ case "expect":
3093
+ case "withCtx":
3094
+ case "grammar":
3095
+ case "recover":
3096
+ return capturesLeaf(d.parser, seen);
3097
+ case "scanTo":
3098
+ return true;
3099
+ case "lazy": {
3100
+ try {
3101
+ return capturesLeaf(d.thunk(), seen);
3102
+ } catch {
3103
+ return true;
3104
+ }
3105
+ }
3106
+ default:
3107
+ return true;
3108
+ }
3109
+ }
3110
+ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
3111
+ if (seen.has(p)) return false;
3112
+ seen.add(p);
3113
+ const d = p._def;
3114
+ switch (d.tag) {
3115
+ case "node":
3116
+ return true;
3117
+ case "lazy": {
3118
+ try {
3119
+ return hasNodeDef(d.thunk(), seen);
3120
+ } catch {
3121
+ return false;
3122
+ }
3123
+ }
3124
+ case "grammar":
3125
+ case "trivia":
3126
+ case "token":
3127
+ case "leaf":
3128
+ case "label":
3129
+ case "field":
3130
+ case "optional":
3131
+ case "many":
3132
+ case "oneOrMore":
3133
+ case "not":
3134
+ case "peek":
3135
+ case "transform":
3136
+ return hasNodeDef(d.parser, seen);
3137
+ case "sequence":
3138
+ case "choice":
3139
+ return d.parsers.some((x) => hasNodeDef(x, seen));
3140
+ case "dispatch":
3141
+ return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => hasNodeDef(entry.parser, seen)) : false) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
3142
+ case "sepBy":
3143
+ return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
3144
+ case "scanTo":
3145
+ return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
3146
+ case "recover":
3147
+ return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
3148
+ case "expect":
3149
+ return hasNodeDef(d.parser, seen);
3150
+ case "withCtx":
3151
+ return hasNodeDef(d.parser, seen);
3152
+ default:
3153
+ return false;
3154
+ }
3155
+ }
3156
+ function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
3157
+ if (seen.has(p)) return false;
3158
+ seen.add(p);
3159
+ const d = p._def;
3160
+ switch (d.tag) {
3161
+ case "dispatch":
3162
+ return true;
3163
+ case "choice":
3164
+ case "sequence":
3165
+ return d.parsers.some((x) => mayCommitFailure(x, seen, resolve));
3166
+ case "many":
3167
+ case "oneOrMore":
3168
+ case "optional":
3169
+ case "attempt":
3170
+ case "transform":
3171
+ case "label":
3172
+ case "field":
3173
+ case "grammar":
3174
+ case "node":
3175
+ return mayCommitFailure(d.parser, seen, resolve);
3176
+ case "sepBy":
3177
+ return mayCommitFailure(d.parser, seen, resolve) || mayCommitFailure(d.separator, seen, resolve);
3178
+ case "token":
3179
+ case "leaf":
3180
+ return mayCommitFailure(d.parser, seen, resolve);
3181
+ case "withCtx":
3182
+ return mayCommitFailure(d.parser, seen, resolve);
3183
+ case "scanTo":
3184
+ return mayCommitFailure(d.sentinel, seen, resolve) || d.skip.some((x) => mayCommitFailure(x, seen, resolve));
3185
+ case "lazy": {
3186
+ try {
3187
+ return mayCommitFailure(d.thunk(), seen, resolve);
3188
+ } catch {
3189
+ const name = p._ruleName;
3190
+ const target = name === void 0 ? void 0 : resolve?.(name);
3191
+ return target === void 0 ? true : mayCommitFailure(target, seen, resolve);
3192
+ }
3193
+ }
3194
+ case "unknown":
3195
+ return true;
3196
+ default:
3197
+ return false;
3198
+ }
3199
+ }
3200
+
3201
+ // src/recovery/scan.ts
3202
+ function probeAt(sentinel, input, pos, ctx) {
3203
+ const s = {
3204
+ _probe: ctx._probe,
3205
+ _errors: ctx._errors,
3206
+ _cstLeaves: ctx._cstLeaves,
3207
+ _cstChildren: ctx._cstChildren,
3208
+ _cstRawChildren: ctx._cstRawChildren,
3209
+ _cstTriviaLog: ctx._cstTriviaLog,
3210
+ _triviaLog: ctx._triviaLog,
3211
+ _rootTriviaLog: ctx._rootTriviaLog,
3212
+ _fields: ctx._fields,
3213
+ _cstBuf: ctx._cstBuf,
3214
+ _tolerant: ctx._tolerant,
3215
+ _sync: ctx._sync
3216
+ };
3217
+ ctx._probe = void 0;
3218
+ ctx._errors = void 0;
3219
+ ctx._cstLeaves = void 0;
3220
+ ctx._cstChildren = void 0;
3221
+ ctx._cstRawChildren = void 0;
3222
+ ctx._cstTriviaLog = void 0;
3223
+ ctx._triviaLog = void 0;
3224
+ ctx._rootTriviaLog = void 0;
3225
+ ctx._fields = void 0;
3226
+ ctx._cstBuf = void 0;
3227
+ ctx._tolerant = void 0;
3228
+ ctx._sync = void 0;
3229
+ try {
3230
+ return sentinel.parse(input, pos, ctx).ok;
3231
+ } finally {
3232
+ ctx._probe = s._probe;
3233
+ ctx._errors = s._errors;
3234
+ ctx._cstLeaves = s._cstLeaves;
3235
+ ctx._cstChildren = s._cstChildren;
3236
+ ctx._cstRawChildren = s._cstRawChildren;
3237
+ ctx._cstTriviaLog = s._cstTriviaLog;
3238
+ ctx._triviaLog = s._triviaLog;
3239
+ ctx._rootTriviaLog = s._rootTriviaLog;
3240
+ ctx._fields = s._fields;
3241
+ ctx._cstBuf = s._cstBuf;
3242
+ ctx._tolerant = s._tolerant;
3243
+ ctx._sync = s._sync;
3244
+ }
3245
+ }
3246
+ function orSentinel(a, b) {
3247
+ if (b === void 0) return a;
3248
+ return {
3249
+ _tag: "orSentinel",
3250
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
3251
+ _def: { tag: "unknown" },
3252
+ parse(input, pos, ctx) {
3253
+ const ra = a.parse(input, pos, ctx);
3254
+ if (ra.ok) return ra;
3255
+ return b.parse(input, pos, ctx);
3256
+ }
3257
+ };
3258
+ }
3259
+ function firstSetSentinel(fs) {
3260
+ if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
3261
+ const ranges = fs.ranges;
3262
+ return {
3263
+ _tag: "firstSetSentinel",
3264
+ _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
3265
+ _def: { tag: "unknown" },
3266
+ parse(input, pos) {
3267
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
3268
+ if (code !== void 0) {
3269
+ for (const r of ranges) {
3270
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
3271
+ }
3272
+ }
3273
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
3274
+ }
3275
+ };
3276
+ }
3277
+ function recoverScan(input, from, ctx, sync, expected) {
3278
+ let scanPos = from;
3279
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
3280
+ const span = { start: from, end: scanPos };
3281
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
3282
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
3283
+ ctx._errors?.push(error);
3284
+ return { error, end: scanPos };
3285
+ }
3286
+ function matchesAt(sentinel, input, pos, ctx) {
3287
+ return probeAt(sentinel, input, pos, ctx);
3288
+ }
3289
+ function captureError(ctx, error) {
3290
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
3291
+ }
3292
+
3293
+ // src/combinators/expect.ts
3294
+ function deriveExpected(c) {
3295
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
3296
+ }
3297
+ function derive(c, seen) {
3298
+ const deriveExpected2 = (p) => derive(p, seen);
3299
+ const def = c._def;
3300
+ switch (def.tag) {
3301
+ case "literal":
3302
+ return [JSON.stringify(def.value)];
3303
+ case "regex":
3304
+ return [`/${def.source}/`];
3305
+ case "keywords":
3306
+ return def.words.map((w) => JSON.stringify(w));
3307
+ case "label":
3308
+ return [def.label];
3309
+ case "choice":
3310
+ return def.parsers.flatMap(deriveExpected2);
3311
+ case "dispatch":
3312
+ return deriveExpected2(def.selector);
3313
+ // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
3314
+ // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
3315
+ // able to fail first — deriving from term 0 alone named a token the parse
3316
+ // never actually required. A leading `not(…)` is zero-width and contributes
3317
+ // nothing (its own expectation is about what must NOT be here), but it is
3318
+ // nullable, so keep scanning past it. Stop at the first term that must match.
3319
+ case "sequence": {
3320
+ const out = [];
3321
+ for (const term of def.parsers) {
3322
+ if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
3323
+ if (!matchesEmpty(term)) break;
3324
+ }
3325
+ return out;
3326
+ }
3327
+ case "attempt":
3328
+ return deriveExpected2(def.parser);
3329
+ // Delegating wrappers whose first-token failure is their inner parser's — must
3330
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
3331
+ // node, which reads this) names the real expected token, not the wrapper tag.
3332
+ case "field":
3333
+ case "withCtx":
3334
+ case "recover":
3335
+ return deriveExpected2(def.parser);
3336
+ case "expect":
3337
+ return def.expected;
3338
+ case "node":
3339
+ case "grammar":
3340
+ case "trivia":
3341
+ case "token":
3342
+ case "leaf":
3343
+ case "optional":
3344
+ case "many":
3345
+ case "oneOrMore":
3346
+ case "transform":
3347
+ case "not":
3348
+ case "peek":
3349
+ return deriveExpected2(def.parser);
3350
+ // A bare routed() can only fail as "there is no routed token here". With a
3351
+ // fallback, THAT is the branch that can fail, so its expectations are the useful
3352
+ // ones — the routed path either succeeds or is not taken.
3353
+ case "routed":
3354
+ return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
3355
+ // A bare adjacency assertion names the JOIN it requires. Inside a sequence it is
3356
+ // skipped entirely (isZeroWidthAssertion, above), which is the normal path.
3357
+ case "adjacency":
3358
+ return [def.polarity];
3359
+ case "lazy": {
3360
+ const name = c._ruleName;
3361
+ if (seen.has(c)) return name ? [name] : [];
3362
+ seen.add(c);
3363
+ try {
3364
+ return deriveExpected2(def.thunk());
3365
+ } catch {
3366
+ return name ? [name] : [];
3367
+ } finally {
3368
+ seen.delete(c);
3369
+ }
3370
+ }
3371
+ default:
3372
+ return [];
3373
+ }
3374
+ }
3375
+ function expect(combinator, label2) {
3376
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
3377
+ const meta = {
3378
+ firstSet: combinator._meta.firstSet,
3379
+ canMatchNewline: combinator._meta.canMatchNewline,
3380
+ isTrivia: false
3381
+ };
3382
+ return {
3383
+ _tag: "expect",
3384
+ _meta: meta,
3385
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
3386
+ parse(input, pos, ctx) {
3387
+ const result = combinator.parse(input, pos, ctx);
3388
+ if (result.ok) return result;
3389
+ const span = { start: pos, end: pos };
3390
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
3391
+ ctx._errors?.push(error);
3392
+ if (ctx._tolerant) captureError(ctx, error);
3393
+ return { ok: true, value: error, span: { start: pos, end: pos } };
3394
+ }
3395
+ };
3396
+ }
3397
+
3398
+ // src/combinators/choice.ts
3399
+ function choice(...args) {
3400
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
3401
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
3402
+ const hasGates = gates.some((g) => g !== null);
3403
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
3404
+ let combined = { kind: "empty" };
3405
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
3406
+ const meta = {
3407
+ firstSet: combined,
3408
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
3409
+ isTrivia: false,
3410
+ disjoint
3411
+ };
3412
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3413
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3414
+ let greedyLitMap = null;
3415
+ let sortedParsers = null;
3416
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
2839
3417
  if (strategy?.tag === "greedyClassify") {
2840
3418
  greedyLitMap = /* @__PURE__ */ new Map();
2841
3419
  for (let i = 0; i < parsers.length; i++) {
@@ -3363,6 +3941,7 @@ function confirmedArityForDef(def) {
3363
3941
  }
3364
3942
  function buildReadsRaw(def) {
3365
3943
  if (!def.build) return true;
3944
+ if (def.buildRawUnused === true) return false;
3366
3945
  const arity = confirmedArityForDef(def);
3367
3946
  if (arity === null) return true;
3368
3947
  return arity >= 4;
@@ -4276,525 +4855,269 @@ function many(combinator, opts = {}) {
4276
4855
  count++;
4277
4856
  cur = item.end;
4278
4857
  }
4279
- return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4280
- }
4281
- };
4282
- }
4283
- function oneOrMore(combinator, opts = {}) {
4284
- return many(combinator, { ...opts, min: opts.min ?? 1 });
4285
- }
4286
- function atLeast(combinator, min, max) {
4287
- const meta = {
4288
- firstSet: combinator._meta.firstSet,
4289
- canMatchNewline: combinator._meta.canMatchNewline,
4290
- isTrivia: false
4291
- };
4292
- const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4293
- let expected;
4294
- const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4295
- return {
4296
- _tag: "oneOrMore",
4297
- _meta: meta,
4298
- _def: def,
4299
- parse(input, pos, ctx) {
4300
- const first = combinator.parse(input, pos, ctx);
4301
- if (!first.ok) return first;
4302
- const values = def.valueUnused ? void 0 : [first.value];
4303
- let cur = first.span.end;
4304
- let count = 1;
4305
- while (count < min) {
4306
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4307
- if (item === "stop" || "fail" in item) {
4308
- if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4309
- expected ??= deriveExpected(combinator);
4310
- return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4311
- }
4312
- if (values !== void 0) values.push(item.value);
4313
- cur = item.end;
4314
- count++;
4315
- }
4316
- while (cur < input.length) {
4317
- if (count >= max) break;
4318
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4319
- if (item === "stop") break;
4320
- if ("fail" in item) {
4321
- if (!item.fail.ok && item.fail.committed) return item.fail;
4322
- const sync = ctx._tolerant ? ctx._sync : void 0;
4323
- if (sync === void 0) break;
4324
- if (matchesAt(sync, input, item.failPos, ctx)) break;
4325
- expected ??= deriveExpected(combinator);
4326
- const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
4327
- if (values !== void 0) values.push(error);
4328
- captureError(ctx, error);
4329
- count++;
4330
- cur = end;
4331
- continue;
4332
- }
4333
- if (values !== void 0) values.push(item.value);
4334
- count++;
4335
- cur = item.end;
4336
- }
4337
- return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4338
- }
4339
- };
4340
- }
4341
- function optional(combinator) {
4342
- const meta = {
4343
- firstSet: combinator._meta.firstSet,
4344
- canMatchNewline: combinator._meta.canMatchNewline,
4345
- isTrivia: false
4346
- };
4347
- const firstSetSkippable = !matchesEmpty(combinator);
4348
- return {
4349
- _tag: "optional",
4350
- _meta: meta,
4351
- _def: { tag: "optional", parser: combinator },
4352
- parse(input, pos, ctx) {
4353
- if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4354
- return { ok: true, value: null, span: { start: pos, end: pos } };
4355
- }
4356
- const mark = saveTriviaMark(ctx);
4357
- const result = combinator.parse(input, pos, ctx);
4358
- if (result.ok) return result;
4359
- rollbackTrivia(ctx, mark);
4360
- if (result.committed) return result;
4361
- return { ok: true, value: null, span: { start: pos, end: pos } };
4362
- }
4363
- };
4364
- }
4365
- function unwrapSeparator(separator) {
4366
- return "_keepSeparator" in separator ? { sep: separator._keepSeparator, keep: true } : { sep: separator, keep: false };
4367
- }
4368
- function sepBy(combinator, separatorArg, opts = {}) {
4369
- const { sep: separator, keep: keepSeparators } = unwrapSeparator(separatorArg);
4370
- const { min, max } = resolveBounds("sepBy()", opts);
4371
- const trailing = opts.trailing ?? "forbid";
4372
- const meta = {
4373
- firstSet: combinator._meta.firstSet,
4374
- canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
4375
- isTrivia: false
4376
- };
4377
- let expected;
4378
- const failAt2 = (at) => {
4379
- expected ??= deriveExpected(combinator);
4380
- return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4381
- };
4382
- return {
4383
- _tag: "sepBy",
4384
- _meta: meta,
4385
- _def: {
4386
- tag: "sepBy",
4387
- parser: combinator,
4388
- separator,
4389
- min,
4390
- ...max === Infinity ? {} : { max },
4391
- ...trailing === "forbid" ? {} : { trailing },
4392
- // Carried into the IR so the COMPILED engine demotes exactly where the
4393
- // interpreter does. The two engines have drifted three separate ways across
4394
- // this option surface already; parity is held by test/parity, not by hope.
4395
- ...keepSeparators ? { keepSeparators: true } : {}
4396
- },
4397
- parse(input, pos, ctx) {
4398
- const first = combinator.parse(input, pos, ctx);
4399
- const values = [];
4400
- let cur;
4401
- if (first.ok) {
4402
- values.push(first.value);
4403
- cur = first.span.end;
4404
- } else {
4405
- if (first.committed) return first;
4406
- const term = ctx._tolerant ? ctx._sync : void 0;
4407
- if (term === void 0 || matchesAt(term, input, pos, ctx)) {
4408
- if (min >= 1) return failAt2(pos);
4409
- return { ok: true, value: [], span: { start: pos, end: pos } };
4410
- }
4411
- expected ??= deriveExpected(combinator);
4412
- const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
4413
- values.push(rec.error);
4414
- captureError(ctx, rec.error);
4415
- cur = rec.end;
4416
- }
4417
- while (cur < input.length || values.length < min) {
4418
- if (values.length >= max) break;
4419
- const loopMark = saveTriviaMark(ctx);
4420
- let sepPos = cur;
4421
- if (ctx.trivia) {
4422
- if (needsDeferredTriviaCommit(ctx)) {
4423
- sepPos = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
4424
- } else {
4425
- sepPos = advanceTrivia(input, cur, ctx);
4426
- }
4427
- }
4428
- const sep = separator.parse(input, sepPos, ctx);
4429
- if (!sep.ok) {
4430
- rollbackTrivia(ctx, loopMark);
4431
- if (sep.committed) return sep;
4432
- break;
4433
- }
4434
- if (!keepSeparators) demoteCapturedToRaw(ctx, loopMark.leaves);
4435
- const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
4436
- let nextPos = sep.span.end;
4437
- if (ctx.trivia) {
4438
- if (needsDeferredTriviaCommit(ctx)) {
4439
- nextPos = commitTriviaScan(scanTriviaCompact(input, sep.span.end, ctx));
4440
- } else {
4441
- nextPos = advanceTrivia(input, sep.span.end, ctx);
4442
- }
4443
- }
4444
- const next = combinator.parse(input, nextPos, ctx);
4445
- if (!next.ok) {
4446
- if (next.committed) return next;
4447
- const term = ctx._tolerant ? ctx._sync : void 0;
4448
- if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
4449
- expected ??= deriveExpected(combinator);
4450
- const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
4451
- values.push(rec.error);
4452
- captureError(ctx, rec.error);
4453
- cur = rec.end;
4454
- continue;
4455
- }
4456
- if (sepMark !== void 0) {
4457
- rollbackTrivia(ctx, sepMark);
4458
- cur = sep.span.end;
4459
- break;
4460
- }
4461
- rollbackTrivia(ctx, loopMark);
4462
- break;
4463
- }
4464
- values.push(next.value);
4465
- cur = next.span.end;
4466
- }
4467
- if (values.length < min) return failAt2(cur);
4468
- return { ok: true, value: values, span: { start: pos, end: cur } };
4469
- }
4470
- };
4471
- }
4472
-
4473
- // src/combinators/map.ts
4474
- function transform(combinator, fn) {
4475
- return {
4476
- _tag: "transform",
4477
- _meta: combinator._meta,
4478
- _def: { tag: "transform", parser: combinator, fn },
4479
- parse(input, pos, ctx) {
4480
- const result = combinator.parse(input, pos, ctx);
4481
- if (!result.ok) return result;
4482
- return { ok: true, value: fn(result.value, result.span), span: result.span };
4483
- }
4484
- };
4485
- }
4486
- function trivia(combinator) {
4487
- const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
4488
- return {
4489
- _tag: combinator._tag,
4490
- _meta: {
4491
- ...combinator._meta,
4492
- isTrivia: true,
4493
- ...kindLabels ? { triviaKindLabels: kindLabels } : {}
4494
- },
4495
- _def: { tag: "trivia", parser: combinator },
4496
- parse: combinator.parse.bind(combinator)
4858
+ return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4859
+ }
4497
4860
  };
4498
4861
  }
4499
- function classifiedTrivia(arms) {
4500
- const entries = Object.entries(arms);
4501
- if (entries.length === 0) {
4502
- throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
4503
- }
4504
- for (let i = 0; i < entries.length; i++) {
4505
- const [name, arm] = entries[i];
4506
- const first = arm._meta.firstSet;
4507
- if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
4508
- throw new TypeError(
4509
- `classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
4510
- );
4511
- }
4512
- }
4513
- const labeledArms = entries.map(([name, arm]) => label(name, arm));
4514
- const result = trivia(oneOrMore(choice(...labeledArms)));
4515
- result._meta.rootTriviaClassified = true;
4516
- return result;
4862
+ function oneOrMore(combinator, opts = {}) {
4863
+ return many(combinator, { ...opts, min: opts.min ?? 1 });
4517
4864
  }
4518
- function label(name, combinator) {
4865
+ function atLeast(combinator, min, max) {
4866
+ const meta = {
4867
+ firstSet: combinator._meta.firstSet,
4868
+ canMatchNewline: combinator._meta.canMatchNewline,
4869
+ isTrivia: false
4870
+ };
4871
+ const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4872
+ let expected;
4873
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4519
4874
  return {
4520
- _tag: combinator._tag,
4521
- _meta: combinator._meta,
4522
- _def: { tag: "label", label: name, parser: combinator },
4875
+ _tag: "oneOrMore",
4876
+ _meta: meta,
4877
+ _def: def,
4523
4878
  parse(input, pos, ctx) {
4524
- const result = combinator.parse(input, pos, ctx);
4525
- if (!result.ok) return { ok: false, expected: [name], span: result.span };
4526
- return result;
4879
+ const first = combinator.parse(input, pos, ctx);
4880
+ if (!first.ok) return first;
4881
+ const values = def.valueUnused ? void 0 : [first.value];
4882
+ let cur = first.span.end;
4883
+ let count = 1;
4884
+ while (count < min) {
4885
+ const item = repItem(combinator, input, cur, ctx, guardable, true);
4886
+ if (item === "stop" || "fail" in item) {
4887
+ if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4888
+ expected ??= deriveExpected(combinator);
4889
+ return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4890
+ }
4891
+ if (values !== void 0) values.push(item.value);
4892
+ cur = item.end;
4893
+ count++;
4894
+ }
4895
+ while (cur < input.length) {
4896
+ if (count >= max) break;
4897
+ const item = repItem(combinator, input, cur, ctx, guardable, false);
4898
+ if (item === "stop") break;
4899
+ if ("fail" in item) {
4900
+ if (!item.fail.ok && item.fail.committed) return item.fail;
4901
+ const sync = ctx._tolerant ? ctx._sync : void 0;
4902
+ if (sync === void 0) break;
4903
+ if (matchesAt(sync, input, item.failPos, ctx)) break;
4904
+ expected ??= deriveExpected(combinator);
4905
+ const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
4906
+ if (values !== void 0) values.push(error);
4907
+ captureError(ctx, error);
4908
+ count++;
4909
+ cur = end;
4910
+ continue;
4911
+ }
4912
+ if (values !== void 0) values.push(item.value);
4913
+ count++;
4914
+ cur = item.end;
4915
+ }
4916
+ return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4527
4917
  }
4528
4918
  };
4529
4919
  }
4530
- function field(name, combinator) {
4920
+ function optional(combinator) {
4921
+ const meta = {
4922
+ firstSet: combinator._meta.firstSet,
4923
+ canMatchNewline: combinator._meta.canMatchNewline,
4924
+ isTrivia: false
4925
+ };
4926
+ const firstSetSkippable = !matchesEmpty(combinator);
4531
4927
  return {
4532
- _tag: combinator._tag,
4533
- _meta: combinator._meta,
4534
- _def: { tag: "field", name, parser: combinator },
4928
+ _tag: "optional",
4929
+ _meta: meta,
4930
+ _def: { tag: "optional", parser: combinator },
4535
4931
  parse(input, pos, ctx) {
4932
+ if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4933
+ return { ok: true, value: null, span: { start: pos, end: pos } };
4934
+ }
4935
+ const mark = saveTriviaMark(ctx);
4536
4936
  const result = combinator.parse(input, pos, ctx);
4537
- if (!result.ok) return result;
4538
- ctx._fields?.push({ name, value: result.value, span: result.span });
4539
- return result;
4937
+ if (result.ok) return result;
4938
+ rollbackTrivia(ctx, mark);
4939
+ if (result.committed) return result;
4940
+ return { ok: true, value: null, span: { start: pos, end: pos } };
4540
4941
  }
4541
4942
  };
4542
4943
  }
4543
-
4544
- // src/regex/first-set.ts
4545
- var ANY = { t: "any" };
4546
- var EMPTY2 = { t: "empty" };
4547
- function charNode(set, nl) {
4548
- return { t: "char", set, nl };
4549
- }
4550
- function rangesToSet(ranges) {
4551
- let fs = empty();
4552
- for (const [lo, hi] of ranges) fs = union(fs, fromRange(lo, hi));
4553
- return fs;
4554
- }
4555
- function rangesHaveNewline(ranges) {
4556
- return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
4944
+ function unwrapSeparator(separator) {
4945
+ return "_keepSeparator" in separator ? { sep: separator._keepSeparator, keep: true } : { sep: separator, keep: false };
4557
4946
  }
4558
- var BAIL = /* @__PURE__ */ Symbol("regex-bail");
4559
- function parseRegex(src) {
4560
- let i = 0;
4561
- const parseAlt = () => {
4562
- const arms = [parseSeq()];
4563
- while (src[i] === "|") {
4564
- i++;
4565
- arms.push(parseSeq());
4566
- }
4567
- return arms.length === 1 ? arms[0] : { t: "alt", arms };
4568
- };
4569
- const parseSeq = () => {
4570
- const parts = [];
4571
- while (i < src.length) {
4572
- const ch2 = src[i];
4573
- if (ch2 === "|" || ch2 === ")") break;
4574
- parts.push(parseQuantified());
4575
- }
4576
- if (parts.length === 0) return EMPTY2;
4577
- return parts.length === 1 ? parts[0] : { t: "seq", parts };
4578
- };
4579
- const parseQuantified = () => {
4580
- const atom = parseAtom();
4581
- const ch2 = src[i];
4582
- let min = null;
4583
- if (ch2 === "*") {
4584
- min = 0;
4585
- i++;
4586
- } else if (ch2 === "+") {
4587
- min = 1;
4588
- i++;
4589
- } else if (ch2 === "?") {
4590
- min = 0;
4591
- i++;
4592
- } else if (ch2 === "{") {
4593
- min = parseBraceQuantifier();
4594
- }
4595
- if (min === null) return atom;
4596
- if (src[i] === "?") i++;
4597
- return { t: "rep", node: atom, min };
4598
- };
4599
- const parseBraceQuantifier = () => {
4600
- const close = src.indexOf("}", i);
4601
- if (close === -1) return null;
4602
- const m = /^(\d+)(?:,(\d*))?$/.exec(src.slice(i + 1, close));
4603
- if (!m) return null;
4604
- i = close + 1;
4605
- return Number.parseInt(m[1], 10);
4606
- };
4607
- const parseAtom = () => {
4608
- const ch2 = src[i];
4609
- switch (ch2) {
4610
- case "(":
4611
- return parseGroup();
4612
- case "[":
4613
- return parseClass();
4614
- case ".":
4615
- i++;
4616
- return charNode(any(), false);
4617
- // `.` matches any char except line terminators
4618
- case "\\":
4619
- return parseEscape();
4620
- case "^":
4621
- case "$":
4622
- i++;
4623
- return EMPTY2;
4624
- // anchors are zero-width
4625
- case "{":
4626
- i++;
4627
- return charNode(fromRange(123, 123), false);
4628
- // a `{` with nothing to quantify is a literal brace
4629
- default:
4630
- i += ch2.length;
4631
- return charNode(fromRange(ch2.codePointAt(0), ch2.codePointAt(0)), ch2 === "\n");
4632
- }
4947
+ function sepBy(combinator, separatorArg, opts = {}) {
4948
+ const { sep: separator, keep: keepSeparators } = unwrapSeparator(separatorArg);
4949
+ const { min, max } = resolveBounds("sepBy()", opts);
4950
+ const trailing = opts.trailing ?? "forbid";
4951
+ const meta = {
4952
+ firstSet: combinator._meta.firstSet,
4953
+ canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
4954
+ isTrivia: false
4633
4955
  };
4634
- const parseGroup = () => {
4635
- i++;
4636
- let lookaround = false;
4637
- if (src[i] === "?") {
4638
- const c1 = src[i + 1];
4639
- if (c1 === ":") i += 2;
4640
- else if (c1 === "=" || c1 === "!") {
4641
- i += 2;
4642
- lookaround = true;
4643
- } else if (c1 === "<") {
4644
- const c2 = src[i + 2];
4645
- if (c2 === "=" || c2 === "!") {
4646
- i += 3;
4647
- lookaround = true;
4648
- } else {
4649
- const gt = src.indexOf(">", i);
4650
- if (gt === -1) throw BAIL;
4651
- i = gt + 1;
4652
- }
4653
- } else throw BAIL;
4654
- }
4655
- const inner = parseAlt();
4656
- if (src[i] !== ")") throw BAIL;
4657
- i++;
4658
- return lookaround ? EMPTY2 : inner;
4956
+ let expected;
4957
+ const failAt2 = (at) => {
4958
+ expected ??= deriveExpected(combinator);
4959
+ return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4659
4960
  };
4660
- const parseClass = () => {
4661
- let k = i + 1;
4662
- const negated = src[k] === "^";
4663
- if (negated) k++;
4664
- let body = "";
4665
- while (k < src.length && src[k] !== "]") {
4666
- if (src[k] === "\\") {
4667
- body += src[k] + (src[k + 1] ?? "");
4668
- k += 2;
4961
+ return {
4962
+ _tag: "sepBy",
4963
+ _meta: meta,
4964
+ _def: {
4965
+ tag: "sepBy",
4966
+ parser: combinator,
4967
+ separator,
4968
+ min,
4969
+ ...max === Infinity ? {} : { max },
4970
+ ...trailing === "forbid" ? {} : { trailing },
4971
+ // Carried into the IR so the COMPILED engine demotes exactly where the
4972
+ // interpreter does. The two engines have drifted three separate ways across
4973
+ // this option surface already; parity is held by test/parity, not by hope.
4974
+ ...keepSeparators ? { keepSeparators: true } : {}
4975
+ },
4976
+ parse(input, pos, ctx) {
4977
+ const first = combinator.parse(input, pos, ctx);
4978
+ const values = [];
4979
+ let cur;
4980
+ if (first.ok) {
4981
+ values.push(first.value);
4982
+ cur = first.span.end;
4669
4983
  } else {
4670
- body += src[k];
4671
- k++;
4984
+ if (first.committed) return first;
4985
+ const term = ctx._tolerant ? ctx._sync : void 0;
4986
+ if (term === void 0 || matchesAt(term, input, pos, ctx)) {
4987
+ if (min >= 1) return failAt2(pos);
4988
+ return { ok: true, value: [], span: { start: pos, end: pos } };
4989
+ }
4990
+ expected ??= deriveExpected(combinator);
4991
+ const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
4992
+ values.push(rec.error);
4993
+ captureError(ctx, rec.error);
4994
+ cur = rec.end;
4995
+ }
4996
+ while (cur < input.length || values.length < min) {
4997
+ if (values.length >= max) break;
4998
+ const loopMark = saveTriviaMark(ctx);
4999
+ let sepPos = cur;
5000
+ if (ctx.trivia) {
5001
+ if (needsDeferredTriviaCommit(ctx)) {
5002
+ sepPos = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
5003
+ } else {
5004
+ sepPos = advanceTrivia(input, cur, ctx);
5005
+ }
5006
+ }
5007
+ const sep = separator.parse(input, sepPos, ctx);
5008
+ if (!sep.ok) {
5009
+ rollbackTrivia(ctx, loopMark);
5010
+ if (sep.committed) return sep;
5011
+ break;
5012
+ }
5013
+ if (!keepSeparators) demoteCapturedToRaw(ctx, loopMark.leaves);
5014
+ const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
5015
+ let nextPos = sep.span.end;
5016
+ if (ctx.trivia) {
5017
+ if (needsDeferredTriviaCommit(ctx)) {
5018
+ nextPos = commitTriviaScan(scanTriviaCompact(input, sep.span.end, ctx));
5019
+ } else {
5020
+ nextPos = advanceTrivia(input, sep.span.end, ctx);
5021
+ }
5022
+ }
5023
+ const next = combinator.parse(input, nextPos, ctx);
5024
+ if (!next.ok) {
5025
+ if (next.committed) return next;
5026
+ const term = ctx._tolerant ? ctx._sync : void 0;
5027
+ if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
5028
+ expected ??= deriveExpected(combinator);
5029
+ const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
5030
+ values.push(rec.error);
5031
+ captureError(ctx, rec.error);
5032
+ cur = rec.end;
5033
+ continue;
5034
+ }
5035
+ if (sepMark !== void 0) {
5036
+ rollbackTrivia(ctx, sepMark);
5037
+ cur = sep.span.end;
5038
+ break;
5039
+ }
5040
+ rollbackTrivia(ctx, loopMark);
5041
+ break;
5042
+ }
5043
+ values.push(next.value);
5044
+ cur = next.span.end;
4672
5045
  }
5046
+ if (values.length < min) return failAt2(cur);
5047
+ return { ok: true, value: values, span: { start: pos, end: cur } };
4673
5048
  }
4674
- if (src[k] !== "]") throw BAIL;
4675
- i = k + 1;
4676
- const ranges = parseClassRanges(body);
4677
- if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
4678
- if (!ranges) return charNode(any(), true);
4679
- return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
4680
5049
  };
4681
- const parseEscape = () => {
4682
- const e = src[i + 1];
4683
- if (e === void 0) throw BAIL;
4684
- if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
4685
- const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
4686
- i += 6;
4687
- return charNode(fromRange(cp, cp), cp === 10);
4688
- }
4689
- if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
4690
- const cp = Number.parseInt(src.slice(i + 2, i + 4), 16);
4691
- i += 4;
4692
- return charNode(fromRange(cp, cp), cp === 10);
4693
- }
4694
- i += 2;
4695
- switch (e) {
4696
- case "d":
4697
- return charNode(rangesToSet(shorthandRanges("d")), false);
4698
- case "w":
4699
- return charNode(rangesToSet(shorthandRanges("w")), false);
4700
- case "s":
4701
- return charNode(rangesToSet(shorthandRanges("s")), true);
4702
- case "D":
4703
- case "W":
4704
- case "S":
4705
- return charNode(any(), true);
4706
- // negated shorthand → widen
4707
- case "b":
4708
- case "B":
4709
- return EMPTY2;
4710
- // word boundary: zero-width
4711
- case "n":
4712
- return charNode(fromRange(10, 10), true);
4713
- case "r":
4714
- return charNode(fromRange(13, 13), false);
4715
- case "t":
4716
- return charNode(fromRange(9, 9), false);
4717
- case "f":
4718
- return charNode(fromRange(12, 12), false);
4719
- case "v":
4720
- return charNode(fromRange(11, 11), false);
4721
- case "0":
4722
- return charNode(fromRange(0, 0), false);
4723
- default:
4724
- if (e >= "1" && e <= "9") return ANY;
4725
- return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
5050
+ }
5051
+
5052
+ // src/combinators/map.ts
5053
+ function transform(combinator, fn) {
5054
+ return {
5055
+ _tag: "transform",
5056
+ _meta: combinator._meta,
5057
+ _def: { tag: "transform", parser: combinator, fn },
5058
+ parse(input, pos, ctx) {
5059
+ const result = combinator.parse(input, pos, ctx);
5060
+ if (!result.ok) return result;
5061
+ return { ok: true, value: fn(result.value, result.span), span: result.span };
4726
5062
  }
4727
5063
  };
4728
- const node2 = parseAlt();
4729
- if (i < src.length) throw BAIL;
4730
- return node2;
4731
5064
  }
4732
- function nullable(n) {
4733
- switch (n.t) {
4734
- case "char":
4735
- return false;
4736
- case "any":
4737
- return true;
4738
- case "empty":
4739
- return true;
4740
- case "seq":
4741
- return n.parts.every(nullable);
4742
- case "alt":
4743
- return n.arms.some(nullable);
4744
- case "rep":
4745
- return n.min === 0 || nullable(n.node);
4746
- }
5065
+ function trivia(combinator) {
5066
+ const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
5067
+ return {
5068
+ _tag: combinator._tag,
5069
+ _meta: {
5070
+ ...combinator._meta,
5071
+ isTrivia: true,
5072
+ ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5073
+ },
5074
+ _def: { tag: "trivia", parser: combinator },
5075
+ parse: combinator.parse.bind(combinator)
5076
+ };
4747
5077
  }
4748
- function firstSet(n) {
4749
- switch (n.t) {
4750
- case "char":
4751
- return n.set;
4752
- case "any":
4753
- return any();
4754
- case "empty":
4755
- return empty();
4756
- case "rep":
4757
- return firstSet(n.node);
4758
- case "alt": {
4759
- let fs = empty();
4760
- for (const arm of n.arms) fs = union(fs, firstSet(arm));
4761
- return fs;
4762
- }
4763
- case "seq": {
4764
- let fs = empty();
4765
- for (const part of n.parts) {
4766
- fs = union(fs, firstSet(part));
4767
- if (!nullable(part)) break;
4768
- }
4769
- return fs;
5078
+ function classifiedTrivia(arms) {
5079
+ const entries = Object.entries(arms);
5080
+ if (entries.length === 0) {
5081
+ throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
5082
+ }
5083
+ for (let i = 0; i < entries.length; i++) {
5084
+ const [name, arm] = entries[i];
5085
+ const first = arm._meta.firstSet;
5086
+ if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
5087
+ throw new TypeError(
5088
+ `classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
5089
+ );
4770
5090
  }
4771
5091
  }
5092
+ const labeledArms = entries.map(([name, arm]) => label(name, arm));
5093
+ const result = trivia(oneOrMore(choice(...labeledArms)));
5094
+ result._meta.rootTriviaClassified = true;
5095
+ return result;
4772
5096
  }
4773
- function canConsumeNewline(n) {
4774
- switch (n.t) {
4775
- case "char":
4776
- return n.nl;
4777
- case "any":
4778
- return true;
4779
- case "empty":
4780
- return false;
4781
- case "rep":
4782
- return canConsumeNewline(n.node);
4783
- case "alt":
4784
- return n.arms.some(canConsumeNewline);
4785
- case "seq":
4786
- return n.parts.some(canConsumeNewline);
4787
- }
5097
+ function label(name, combinator) {
5098
+ return {
5099
+ _tag: combinator._tag,
5100
+ _meta: combinator._meta,
5101
+ _def: { tag: "label", label: name, parser: combinator },
5102
+ parse(input, pos, ctx) {
5103
+ const result = combinator.parse(input, pos, ctx);
5104
+ if (!result.ok) return { ok: false, expected: [name], span: result.span };
5105
+ return result;
5106
+ }
5107
+ };
4788
5108
  }
4789
- function firstSetFromRegex(source) {
4790
- let ast;
4791
- try {
4792
- ast = parseRegex(source);
4793
- } catch {
4794
- return { firstSet: any(), canMatchNewline: true };
4795
- }
4796
- if (nullable(ast)) return { firstSet: any(), canMatchNewline: canConsumeNewline(ast) };
4797
- return { firstSet: firstSet(ast), canMatchNewline: canConsumeNewline(ast) };
5109
+ function field(name, combinator) {
5110
+ return {
5111
+ _tag: combinator._tag,
5112
+ _meta: combinator._meta,
5113
+ _def: { tag: "field", name, parser: combinator },
5114
+ parse(input, pos, ctx) {
5115
+ const result = combinator.parse(input, pos, ctx);
5116
+ if (!result.ok) return result;
5117
+ ctx._fields?.push({ name, value: result.value, span: result.span });
5118
+ return result;
5119
+ }
5120
+ };
4798
5121
  }
4799
5122
 
4800
5123
  // src/combinators/regex.ts
@@ -4983,8 +5306,26 @@ function validateDispatchSpec(spec, arity, fallbackRouted) {
4983
5306
  }
4984
5307
  }
4985
5308
  var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
4986
- function ownTableProgram(prog, resolved) {
4987
- return { ...prog, [TABLE_RUNTIME]: { resolved } };
5309
+ function ownTableProgram(prog, resolved, caches = {}) {
5310
+ const runtime = prog[TABLE_RUNTIME];
5311
+ return {
5312
+ ...prog,
5313
+ [TABLE_RUNTIME]: {
5314
+ resolved,
5315
+ choiceRollbackMasks: caches.choiceRollbackMasks ?? runtime?.choiceRollbackMasks,
5316
+ nonCommittingChoiceSites: caches.nonCommittingChoiceSites ?? runtime?.nonCommittingChoiceSites,
5317
+ failureRollbackCleanSites: caches.failureRollbackCleanSites ?? runtime?.failureRollbackCleanSites
5318
+ }
5319
+ };
5320
+ }
5321
+ function choiceRollbackMask(prog, ip) {
5322
+ return prog[TABLE_RUNTIME]?.choiceRollbackMasks?.get(ip);
5323
+ }
5324
+ function choiceCannotCommit(prog, ip) {
5325
+ return prog[TABLE_RUNTIME]?.nonCommittingChoiceSites?.has(ip) === true;
5326
+ }
5327
+ function failureRollbackClean(prog, ip) {
5328
+ return prog[TABLE_RUNTIME]?.failureRollbackCleanSites?.has(ip) === true;
4988
5329
  }
4989
5330
  var WIDE_CLASS_PREFIX_LO = 65535;
4990
5331
  var WIDE_CLASS_PREFIX_HI = 0;
@@ -5159,7 +5500,6 @@ function directArrayProjection(fn, fnSrc, arity) {
5159
5500
 
5160
5501
  // src/table/encode.ts
5161
5502
  import {
5162
- assertLexicalCapabilityClosure,
5163
5503
  collectLexicalCapabilities,
5164
5504
  winnerWrapsReference as winnerWrapsReference2
5165
5505
  } from "../compiler/token-capability.js";
@@ -5541,6 +5881,9 @@ var Encoder = class {
5541
5881
  lexIndex = /* @__PURE__ */ new Map();
5542
5882
  lexPrograms = [];
5543
5883
  lexProgramIndex = /* @__PURE__ */ new Map();
5884
+ choiceRollbackMasks = /* @__PURE__ */ new Map();
5885
+ nonCommittingChoiceSites = /* @__PURE__ */ new Set();
5886
+ failureRollbackCleanSites = /* @__PURE__ */ new Set();
5544
5887
  labels = void 0;
5545
5888
  /** Trivia table in scope at the row being encoded — codegen's `ctx.activeTrivia`. */
5546
5889
  activeTrivia = void 0;
@@ -5951,6 +6294,71 @@ var Encoder = class {
5951
6294
  const w = this.winners;
5952
6295
  return w === void 0 ? void 0 : (name) => w[name];
5953
6296
  }
6297
+ /**
6298
+ * Whether a failed ordered-choice arm can leave state that the enclosing
6299
+ * choice must restore before trying its successor.
6300
+ *
6301
+ * `mayLeavePartialCapture` is the existing sound CST/trivia proof. The extra
6302
+ * writer census covers the side sinks that proof deliberately does not model:
6303
+ * fields, recovered errors, and interpreted scanners. Strict assemblies do
6304
+ * not run repeat recovery, but these rows can still publish through a caller's
6305
+ * context. Cycles are safe to stop: revisiting the same combinator cannot
6306
+ * discover a writer the first traversal did not already reach.
6307
+ */
6308
+ failureNeedsRollback(p, autoNot) {
6309
+ const refName = p._ruleName;
6310
+ const winner = refName === void 0 ? void 0 : this.winners?.[refName];
6311
+ const root = winner !== void 0 && !winnerWrapsReference2(winner, p) ? winner : p;
6312
+ const sideWriterMemo = /* @__PURE__ */ new Map();
6313
+ const hasSideWriter = (current, seen = /* @__PURE__ */ new Set()) => {
6314
+ const cached = sideWriterMemo.get(current);
6315
+ if (cached !== void 0) return { found: cached, complete: true };
6316
+ if (seen.has(current)) return { found: false, complete: false };
6317
+ const next = new Set(seen);
6318
+ next.add(current);
6319
+ const def = current._def;
6320
+ let result;
6321
+ switch (def.tag) {
6322
+ case "field":
6323
+ case "expect":
6324
+ case "recover":
6325
+ case "scanTo":
6326
+ case "unknown":
6327
+ result = { found: true, complete: true };
6328
+ break;
6329
+ case "lazy": {
6330
+ const name = current._ruleName;
6331
+ const resolvedWinner = name === void 0 ? void 0 : this.winners?.[name];
6332
+ if (resolvedWinner !== void 0 && !winnerWrapsReference2(resolvedWinner, current)) {
6333
+ result = hasSideWriter(resolvedWinner, next);
6334
+ break;
6335
+ }
6336
+ try {
6337
+ result = hasSideWriter(def.thunk(), next);
6338
+ } catch {
6339
+ result = { found: true, complete: true };
6340
+ }
6341
+ break;
6342
+ }
6343
+ default: {
6344
+ let complete = true;
6345
+ result = { found: false, complete: true };
6346
+ for (const child of childrenOf(def)) {
6347
+ const childResult = hasSideWriter(child, next);
6348
+ if (childResult.found) {
6349
+ result = { found: true, complete: true };
6350
+ break;
6351
+ }
6352
+ complete &&= childResult.complete;
6353
+ }
6354
+ if (!result.found) result = { found: false, complete };
6355
+ }
6356
+ }
6357
+ if (result.found || result.complete) sideWriterMemo.set(current, result.found);
6358
+ return result;
6359
+ };
6360
+ return mayLeavePartialCapture(root, /* @__PURE__ */ new Set(), true) || hasSideWriter(root).found || (autoNot?.length ?? 0) > 0 && capturesLeaf(root);
6361
+ }
5954
6362
  /** A first set becomes a char class string, or −1 for `any`. */
5955
6363
  charClass(fs) {
5956
6364
  if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
@@ -6236,9 +6644,39 @@ var Encoder = class {
6236
6644
  });
6237
6645
  const rr = this.refResolver();
6238
6646
  const finalChoice = classifyFinalChoice(arms, rr);
6239
- const classes = arms.map((_, i) => finalChoice.nullable[i] ? -1 : this.charClass(finalChoice.firstSets[i]));
6647
+ const transactionalFirst = arms.map((arm, i) => {
6648
+ if (!finalChoice.nullable[i]) return void 0;
6649
+ const def = arm._def;
6650
+ if (def.tag !== "attempt" || matchesEmpty(def.parser, /* @__PURE__ */ new Set(), rr)) return void 0;
6651
+ return firstSetOf(def.parser, /* @__PURE__ */ new Set(), rr);
6652
+ });
6653
+ const gateFirst = finalChoice.firstSets.map((first, i) => transactionalFirst[i] ?? first);
6654
+ const classes = gateFirst.map((first, i) => finalChoice.nullable[i] && transactionalFirst[i] === void 0 ? -1 : this.charClass(first));
6655
+ if (transactionalFirst.some((first) => first !== void 0) && classes.every((cls) => cls >= 0)) {
6656
+ let overlap = false;
6657
+ for (let i = 0; i < gateFirst.length && !overlap; i++) {
6658
+ for (let j = i + 1; j < gateFirst.length; j++) {
6659
+ if (intersects(gateFirst[i], gateFirst[j])) {
6660
+ overlap = true;
6661
+ break;
6662
+ }
6663
+ }
6664
+ }
6665
+ if (!overlap) for (let i = 0; i < classes.length; i++) {
6666
+ if (transactionalFirst[i] !== void 0) classes[i] = -1;
6667
+ }
6668
+ }
6240
6669
  const dispIdx = this.disp.length;
6241
6670
  this.disp.push(classes);
6671
+ let rollbackMask = kids.length > 31 ? -1 : 0;
6672
+ if (rollbackMask === 0) {
6673
+ for (let i = 0; i < arms.length; i++) {
6674
+ const src = order[i];
6675
+ if (this.failureNeedsRollback(arms[i], d.autoNot[src])) {
6676
+ rollbackMask |= 1 << i;
6677
+ }
6678
+ }
6679
+ }
6242
6680
  const head = this.emitHead(OP_CHOICE, 3 + 2 * kids.length);
6243
6681
  this.code[head + 1] = dispIdx;
6244
6682
  this.code[head + 2] = kids.length;
@@ -6247,6 +6685,10 @@ var Encoder = class {
6247
6685
  this.code[head + 4 + i] = kids[i];
6248
6686
  this.code[head + 4 + kids.length + i] = this.expected(deriveExpected(arms[i]));
6249
6687
  }
6688
+ this.choiceRollbackMasks.set(head, rollbackMask);
6689
+ if (arms.every((arm) => !mayCommitFailure(arm, /* @__PURE__ */ new Set(), rr))) {
6690
+ this.nonCommittingChoiceSites.add(head);
6691
+ }
6250
6692
  return head;
6251
6693
  }
6252
6694
  case "many":
@@ -6276,8 +6718,11 @@ var Encoder = class {
6276
6718
  }
6277
6719
  return d.min >= 2 ? this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags, this.expected(deriveExpected(d.parser))) : this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags);
6278
6720
  }
6279
- case "optional":
6280
- return this.emit(OP_OPT, this.node(d.parser).ip);
6721
+ case "optional": {
6722
+ const head = this.emit(OP_OPT, this.node(d.parser).ip);
6723
+ if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(head);
6724
+ return head;
6725
+ }
6281
6726
  case "transform": {
6282
6727
  const inner = d.parser._def;
6283
6728
  if (inner.tag === "sequence" && !this.memo.has(d.parser) && !this.pending.has(d.parser)) {
@@ -6436,6 +6881,7 @@ var Encoder = class {
6436
6881
  // lowering was correct only for a choice arm.
6437
6882
  case "attempt": {
6438
6883
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
6884
+ if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
6439
6885
  const fs = d.parser._meta.firstSet;
6440
6886
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
6441
6887
  const cls = this.charClass(fs);
@@ -6604,6 +7050,10 @@ var Encoder = class {
6604
7050
  ...this.rec ? { rec: 1 } : {},
6605
7051
  ...this.cov === void 0 ? {} : { cov: this.cov },
6606
7052
  lines: this.track ? 1 : 0
7053
+ }, void 0, {
7054
+ choiceRollbackMasks: this.choiceRollbackMasks,
7055
+ failureRollbackCleanSites: this.failureRollbackCleanSites,
7056
+ nonCommittingChoiceSites: this.nonCommittingChoiceSites
6607
7057
  });
6608
7058
  }
6609
7059
  };
@@ -6648,7 +7098,6 @@ function encodeTableProgram(ruleMap, settings = {}) {
6648
7098
  const lexicalRoots = [...names].sort().map((name) => ruleMap[name]);
6649
7099
  const resolveLexical = (name) => ruleMap[name];
6650
7100
  const capabilities = collectLexicalCapabilities(lexicalRoots, resolveLexical);
6651
- assertLexicalCapabilityClosure(lexicalRoots, capabilities, resolveLexical);
6652
7101
  const enc = new Encoder(resolvedSettings, capabilities.capabilityComplete);
6653
7102
  enc.winners = ruleMap;
6654
7103
  for (const name of names) enc.encodeRule(name, ruleMap[name]);
@@ -7781,13 +8230,17 @@ var TRI_NONE = -1;
7781
8230
  var CAP_UNKNOWN = 0;
7782
8231
  var CAP_OFF = 1;
7783
8232
  var CAP_ON = 2;
7784
- var TOP = { tri: TRI_UNKNOWN, buf: false, cap: CAP_UNKNOWN };
8233
+ var RAW_UNKNOWN = 0;
8234
+ var RAW_CAPTURE = 1;
8235
+ var RAW_OMIT = 2;
8236
+ var TOP = { tri: TRI_UNKNOWN, buf: false, raw: RAW_UNKNOWN, cap: CAP_UNKNOWN };
7785
8237
  function meet(a, b) {
7786
8238
  const tri = a.tri === b.tri ? a.tri : TRI_UNKNOWN;
7787
8239
  const buf = a.buf && b.buf;
8240
+ const raw = a.raw === b.raw ? a.raw : RAW_UNKNOWN;
7788
8241
  const cap = a.cap === b.cap ? a.cap : CAP_UNKNOWN;
7789
- if (tri === a.tri && buf === a.buf && cap === a.cap) return a;
7790
- return { tri, buf, cap };
8242
+ if (tri === a.tri && buf === a.buf && raw === a.raw && cap === a.cap) return a;
8243
+ return { tri, buf, raw, cap };
7791
8244
  }
7792
8245
  function reachableSites(code, roots) {
7793
8246
  const seen = /* @__PURE__ */ new Set();
@@ -7810,25 +8263,26 @@ function transfer(code, ip, at, hostCst) {
7810
8263
  const tri = ki < 0 ? TRI_NONE : ki;
7811
8264
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
7812
8265
  if (tri === at.tri && cap === at.cap) return at;
7813
- return { tri, buf: at.buf, cap };
8266
+ return { tri, buf: at.buf, raw: at.raw, cap };
7814
8267
  }
7815
8268
  if (op === OP_NODE || op === OP_NODE_TRACK) {
7816
8269
  const flags = code[ip + 3];
7817
8270
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags === 2 || flags === 18 || flags === 34);
7818
8271
  if (directChildren) {
7819
- return { tri: at.tri, buf: false, cap: CAP_OFF };
8272
+ return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
7820
8273
  }
7821
8274
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
7822
- if (at.buf && cap === at.cap) return at;
7823
- return { tri: at.tri, buf: true, cap };
8275
+ const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
8276
+ if (at.buf && raw === at.raw && cap === at.cap) return at;
8277
+ return { tri: at.tri, buf: true, raw, cap };
7824
8278
  }
7825
8279
  if (op === OP_TOKEN) {
7826
8280
  if (at.tri === TRI_NONE && !at.buf) return at;
7827
- return { tri: TRI_NONE, buf: false, cap: at.cap };
8281
+ return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
7828
8282
  }
7829
8283
  if (op === OP_LEAF) {
7830
8284
  if (!at.buf) return at;
7831
- return { tri: at.tri, buf: false, cap: at.cap };
8285
+ return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
7832
8286
  }
7833
8287
  return at;
7834
8288
  }
@@ -7895,6 +8349,162 @@ function scalarTerminalNotChild(code, ip) {
7895
8349
  const op = code[child];
7896
8350
  return op === OP_RX || op === OP_LIT ? child : -1;
7897
8351
  }
8352
+ function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
8353
+ const seen = /* @__PURE__ */ new Set();
8354
+ let at = ip;
8355
+ let depth = 0;
8356
+ while (!seen.has(at)) {
8357
+ seen.add(at);
8358
+ const op = code[at];
8359
+ if (op === OP_LIT || op === OP_RX) return depth >= minDepth ? at : -1;
8360
+ if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || throughAttempt && op === OP_ATTEMPT) {
8361
+ at = code[at + 1];
8362
+ depth++;
8363
+ continue;
8364
+ }
8365
+ if (throughPeek && op === OP_PEEK) {
8366
+ at = code[at + 1];
8367
+ depth++;
8368
+ continue;
8369
+ }
8370
+ if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
8371
+ at = code[at + 2];
8372
+ depth++;
8373
+ continue;
8374
+ }
8375
+ if (op === OP_SEQ || op === OP_SEQV) {
8376
+ if (code[at + 1] < 1) return -1;
8377
+ at = code[at + 2];
8378
+ depth++;
8379
+ continue;
8380
+ }
8381
+ if (op === OP_SEQX) {
8382
+ if (code[at + 2] < 1) return -1;
8383
+ at = code[at + 3];
8384
+ depth++;
8385
+ continue;
8386
+ }
8387
+ return -1;
8388
+ }
8389
+ return -1;
8390
+ }
8391
+ function leadingScalarSequence(code, ip) {
8392
+ const wholeScalar = (start) => {
8393
+ const seen2 = /* @__PURE__ */ new Set();
8394
+ let at2 = start;
8395
+ while (!seen2.has(at2)) {
8396
+ seen2.add(at2);
8397
+ const op = code[at2];
8398
+ if (op === OP_LIT || op === OP_RX) return at2;
8399
+ if (op === OP_RULE || op === OP_TOKEN || op === OP_ATTEMPT) {
8400
+ at2 = code[at2 + 1];
8401
+ continue;
8402
+ }
8403
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
8404
+ at2 = code[at2 + 2];
8405
+ continue;
8406
+ }
8407
+ if (op === OP_SEQ || op === OP_SEQV) {
8408
+ if (code[at2 + 1] !== 1) return -1;
8409
+ at2 = code[at2 + 2];
8410
+ continue;
8411
+ }
8412
+ if (op === OP_SEQX) {
8413
+ if (code[at2 + 2] !== 1) return -1;
8414
+ at2 = code[at2 + 3];
8415
+ continue;
8416
+ }
8417
+ return -1;
8418
+ }
8419
+ return -1;
8420
+ };
8421
+ const seen = /* @__PURE__ */ new Set();
8422
+ let at = ip;
8423
+ let ambientTrivia;
8424
+ while (!seen.has(at)) {
8425
+ seen.add(at);
8426
+ const op = code[at];
8427
+ if (op === OP_RULE) {
8428
+ at = code[at + 1];
8429
+ continue;
8430
+ }
8431
+ if (op === OP_SCOPE_PLAIN) {
8432
+ ambientTrivia = code[at + 1];
8433
+ at = code[at + 2];
8434
+ continue;
8435
+ }
8436
+ if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
8437
+ at = code[at + 2];
8438
+ continue;
8439
+ }
8440
+ const n = op === OP_SEQ || op === OP_SEQV ? code[at + 1] : op === OP_SEQX ? code[at + 2] : 0;
8441
+ if (n < 3 || ambientTrivia === void 0) return void 0;
8442
+ const base = op === OP_SEQX ? at + 3 : at + 2;
8443
+ const terminals = [
8444
+ wholeScalar(code[base]),
8445
+ wholeScalar(code[base + 1]),
8446
+ wholeScalar(code[base + 2])
8447
+ ];
8448
+ return terminals.every((terminal) => terminal >= 0) ? { terminals, trivia: ambientTrivia } : void 0;
8449
+ }
8450
+ return void 0;
8451
+ }
8452
+ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
8453
+ const active = /* @__PURE__ */ new Set();
8454
+ const walk = (at, depth) => {
8455
+ if (active.has(at)) return void 0;
8456
+ active.add(at);
8457
+ try {
8458
+ const op = code[at];
8459
+ if (op === OP_LIT) {
8460
+ const value = constants[code[at + 1]];
8461
+ return depth >= minDepth && typeof value === "string" && value.length > 0 ? [at] : void 0;
8462
+ }
8463
+ if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || op === OP_ATTEMPT || op === OP_PEEK) {
8464
+ return walk(code[at + 1], depth + 1);
8465
+ }
8466
+ if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
8467
+ return walk(code[at + 2], depth + 1);
8468
+ }
8469
+ if (op === OP_SEQ || op === OP_SEQV) {
8470
+ return code[at + 1] < 1 ? void 0 : walk(code[at + 2], depth + 1);
8471
+ }
8472
+ if (op === OP_SEQX) {
8473
+ return code[at + 2] < 1 ? void 0 : walk(code[at + 3], depth + 1);
8474
+ }
8475
+ if (op !== OP_CHOICE) return void 0;
8476
+ const n = code[at + 2];
8477
+ if (n < 1) return void 0;
8478
+ const out = [];
8479
+ for (let i = 0; i < n; i++) {
8480
+ const branch = walk(code[at + 4 + i], depth + 1);
8481
+ if (branch === void 0) return void 0;
8482
+ for (const terminal of branch) {
8483
+ const value = constants[code[terminal + 1]];
8484
+ let covered = false;
8485
+ for (let j = 0; j < out.length; j++) {
8486
+ const prior = constants[code[out[j] + 1]];
8487
+ if (value.startsWith(prior)) {
8488
+ covered = true;
8489
+ break;
8490
+ }
8491
+ }
8492
+ if (covered) continue;
8493
+ for (let j = out.length - 1; j >= 0; j--) {
8494
+ const prior = constants[code[out[j] + 1]];
8495
+ if (prior.startsWith(value)) out.splice(j, 1);
8496
+ }
8497
+ out.push(terminal);
8498
+ if (out.length > limit) return void 0;
8499
+ }
8500
+ }
8501
+ return out;
8502
+ } finally {
8503
+ active.delete(at);
8504
+ }
8505
+ };
8506
+ return walk(ip, 0);
8507
+ }
7898
8508
 
7899
8509
  // src/table/emit-assembly.ts
7900
8510
  var Unemittable = class extends Error {
@@ -7976,6 +8586,16 @@ let _pfScan=null
7976
8586
  let _pfHost
7977
8587
  let _pfDepth=0
7978
8588
  const _pfFrames=[]
8589
+ let _pfTokInput
8590
+ let _pfTokPos=-1
8591
+ let _pfTokBody=-1
8592
+ let _pfTokPacked=-1
8593
+ let _pfTokValue
8594
+ let _pfTokDispatch=-1
8595
+ let _pfTokArm=-1
8596
+ let _pfTokEnd=-1
8597
+ let _pfSeqEnd=-1
8598
+ function _asciiFoldCode(c){return c>=65&&c<=90?c+32:c}
7979
8599
  function _skipTrivia(input,cur,ctx){
7980
8600
  const s=_pfScan
7981
8601
  if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
@@ -8041,6 +8661,40 @@ if(ctx._triviaLog!==undefined&&ctx._triviaLog.length!==lg)ctx._triviaLog.length=
8041
8661
  if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTriviaLog.length=rt
8042
8662
  }
8043
8663
  `;
8664
+ var NO_RAW_RUNTIME_PRELUDE = `
8665
+ function _pushLeafNoRawBuf(ctx,value,s,e){
8666
+ const l={_tag:'leaf',value,span:{start:s,end:e}}
8667
+ const b=ctx._cstBuf
8668
+ if(b.ch!==undefined)b.ch.push(l)
8669
+ else if(b.single!==undefined){b.ch=[b.single,l];b.single=undefined}
8670
+ else b.single=l
8671
+ b.rawLen++
8672
+ }
8673
+ function _pushNodeNoRawBuf(ctx,value){
8674
+ const b=ctx._cstBuf
8675
+ if(b.ch!==undefined)b.ch.push(value)
8676
+ else if(b.single!==undefined){b.ch=[b.single,value];b.single=undefined}
8677
+ else b.single=value
8678
+ b.rawLen++
8679
+ }
8680
+ function _rbNoRawBuf(ctx,raw,tl,lv,lg,rt){
8681
+ const b=ctx._cstBuf
8682
+ if(b.rawLen!==raw)b.rawLen=raw
8683
+ const ch=b.ch
8684
+ if(ch!==undefined){
8685
+ if(lv===0)b.ch=undefined
8686
+ else if(lv===1){b.single=ch[0];b.ch=undefined}
8687
+ else if(ch.length!==lv)ch.length=lv
8688
+ }else if(lv===0)b.single=undefined
8689
+ const bt=b.tl
8690
+ if(bt!==undefined){
8691
+ if(tl===0)b.tl=undefined
8692
+ else if(bt.length!==tl)bt.length=tl
8693
+ }
8694
+ if(ctx._triviaLog!==undefined&&ctx._triviaLog.length!==lg)ctx._triviaLog.length=lg
8695
+ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTriviaLog.length=rt
8696
+ }
8697
+ `;
8044
8698
  function q(s) {
8045
8699
  return JSON.stringify(s);
8046
8700
  }
@@ -8053,11 +8707,12 @@ function sinkReads(t2, s) {
8053
8707
  ${t2}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${s.er ? `
8054
8708
  ${t2}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
8055
8709
  }
8056
- function emitMark(t2, buf, s = NO_SINKS, decl = true) {
8710
+ function emitMark(t2, buf, rawMode, s = NO_SINKS, decl = true) {
8057
8711
  if (buf) {
8712
+ const raw = rawMode === RAW_OMIT ? `${t2}raw=b.rawLen` : rawMode === RAW_CAPTURE ? `const r=b.raw;${t2}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0` : `const r=b.raw;${t2}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)`;
8058
8713
  return `${decl ? `let ${t2}raw=0,${t2}tl=0,${t2}lv=0,${t2}lg=0,${t2}rt=0${sinkSlots(t2, s)}
8059
8714
  ` : ""}{const b=ctx._cstBuf
8060
- const r=b.raw;${t2}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
8715
+ ${raw}
8061
8716
  const h=b.ch;${t2}lv=h!==undefined?h.length:b.single!==undefined?1:0
8062
8717
  const l=b.tl;${t2}tl=l!==undefined?l.length:0
8063
8718
  ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
@@ -8067,7 +8722,7 @@ ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${sinkReads(t2
8067
8722
  ` : `${t2}n=false
8068
8723
  `}{const b=ctx._cstBuf
8069
8724
  if(b!==undefined){
8070
- const r=b.raw;${t2}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
8725
+ const r=b.raw;${t2}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)
8071
8726
  const h=b.ch;${t2}lv=h!==undefined?h.length:b.single!==undefined?1:0
8072
8727
  const l=b.tl;${t2}tl=l!==undefined?l.length:0
8073
8728
  ${t2}n=true
@@ -8082,14 +8737,16 @@ ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
8082
8737
  ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${sinkReads(t2, s)}
8083
8738
  }}`;
8084
8739
  }
8085
- function emitRollback(t2, buf, s = NO_SINKS) {
8740
+ function emitRollback(t2, buf, rawMode, s = NO_SINKS) {
8086
8741
  const fd = s.fd ? `
8087
8742
  if(ctx._fields!==undefined&&ctx._fields.length!==${t2}fd)ctx._fields.length=${t2}fd` : "";
8088
8743
  const er = s.er ? `
8089
8744
  if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2}er` : "";
8090
- if (buf) return `_rbBuf(ctx,${t2}raw,${t2}tl,${t2}lv,${t2}lg,${t2}rt)${fd}${er}`;
8091
- if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,0,undefined,${t2}lg,${t2}rt)`;
8092
- return `if(${t2}n){rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,${s.fd ? `${t2}fd` : "0"},${s.er ? `${t2}er` : "undefined"},${t2}lg,${t2}rt)}`;
8745
+ if (buf && rawMode === RAW_OMIT) return `_rbNoRawBuf(ctx,${t2}raw,${t2}tl,${t2}lv,${t2}lg,${t2}rt)${fd}${er}`;
8746
+ if (buf && rawMode === RAW_CAPTURE) return `_rbBuf(ctx,${t2}raw,${t2}tl,${t2}lv,${t2}lg,${t2}rt)${fd}${er}`;
8747
+ if (buf) return `rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,${s.fd ? `${t2}fd` : "undefined"},${s.er ? `${t2}er` : "undefined"},${t2}lg,${t2}rt)`;
8748
+ if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,undefined,undefined,${t2}lg,${t2}rt)`;
8749
+ return `if(${t2}n){rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,${s.fd ? `${t2}fd` : "undefined"},${s.er ? `${t2}er` : "undefined"},${t2}lg,${t2}rt)}`;
8093
8750
  }
8094
8751
  function emitTerm(callee, dst, t2, l, skip) {
8095
8752
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
@@ -8147,37 +8804,111 @@ function rebuildPools(cc, fx, disp, plan) {
8147
8804
  })
8148
8805
  };
8149
8806
  }
8150
- function emitAssemblySource(t2, prog, cfg, extraIps = []) {
8151
- const { code, k, disp, dsp, triviaLabelled } = t2;
8807
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
8808
+ const { code, k, fx, disp, dsp, triviaLabelled } = t2;
8152
8809
  const swapLegal = !cfg.trackLines;
8153
8810
  const hostCst = cfg.hostCst;
8154
8811
  const REC = prog.rec === 1 && cfg.tolerant;
8155
8812
  if (cfg.coverage) throw new Unemittable("a coverage assembly");
8156
8813
  const roots = [...Object.values(prog.rules), ...extraIps];
8814
+ const reachable = [...reachableSites(code, roots)];
8157
8815
  const labels = computeSiteLabels(code, roots, hostCst);
8158
8816
  const scalarSpecs = /* @__PURE__ */ new Set();
8817
+ const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
8818
+ const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
8819
+ const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
8820
+ const tokenChoiceCandidates = /* @__PURE__ */ new Map();
8821
+ const tokenChoiceDispatches = /* @__PURE__ */ new Set();
8822
+ const tokenChoiceBodies = /* @__PURE__ */ new Set();
8159
8823
  if (!hostCst && !cfg.tolerant && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
8160
- for (const ip of reachableSites(code, roots)) {
8161
- if (code[ip] !== OP_NODE) continue;
8162
- const child = scalarTerminalNodeChild(code, ip);
8163
- if (child >= 0) scalarSpecs.add(code[child + 1]);
8824
+ for (const ip of reachable) {
8825
+ if (code[ip] === OP_NODE) {
8826
+ const child = scalarTerminalNodeChild(code, ip);
8827
+ if (child >= 0) scalarSpecs.add(code[child + 1]);
8828
+ continue;
8829
+ }
8830
+ if (code[ip] !== OP_CHOICE || disp[code[ip + 1]].exclusive) continue;
8831
+ const n = code[ip + 2];
8832
+ for (let i = 0; i < n; i++) {
8833
+ const armIp = code[ip + 4 + i];
8834
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
8835
+ if (n === 2 || n === 3) {
8836
+ if (child >= 0) scalarSpecs.add(code[child + 1]);
8837
+ continue;
8838
+ }
8839
+ if (child >= 0) {
8840
+ const spec = k[code[child + 1]];
8841
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
8842
+ largeChoiceScalarSpecs.add(code[child + 1]);
8843
+ continue;
8844
+ }
8845
+ }
8846
+ const family = leadingLiteralFamily(code, k, armIp);
8847
+ if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
8848
+ const value = k[code[terminal + 1]];
8849
+ return typeof value === "string" && value.length >= 2;
8850
+ })) {
8851
+ largeChoiceLiteralFamilies.set(armIp, family);
8852
+ }
8853
+ const sequence6 = leadingScalarSequence(code, armIp);
8854
+ if (sequence6 !== void 0 && (sequence6.trivia < 0 || swapLegal && t2.triviaScan[sequence6.trivia] != null)) {
8855
+ largeChoiceScalarSequences.set(armIp, sequence6);
8856
+ }
8857
+ }
8858
+ let candidate;
8859
+ let ambiguous = false;
8860
+ for (let i = 0; i < n; i++) {
8861
+ const armIp = code[ip + 4 + i];
8862
+ if (code[armIp] !== OP_XFORM) continue;
8863
+ const dispatchIp = code[armIp + 2];
8864
+ if (code[dispatchIp] !== OP_DISPATCH) continue;
8865
+ const selectorIp = code[dispatchIp + 1];
8866
+ if (code[selectorIp] !== OP_LEX_BODY) continue;
8867
+ if (candidate !== void 0) {
8868
+ ambiguous = true;
8869
+ break;
8870
+ }
8871
+ candidate = { arm: i, dispatchIp };
8872
+ }
8873
+ if (!ambiguous && candidate !== void 0) {
8874
+ tokenChoiceCandidates.set(ip, candidate);
8875
+ tokenChoiceDispatches.add(candidate.dispatchIp);
8876
+ tokenChoiceBodies.add(code[code[candidate.dispatchIp + 1] + 1]);
8877
+ }
8164
8878
  }
8165
8879
  }
8166
- const sinks = (() => {
8167
- let fd = false;
8168
- let er = REC;
8169
- for (const ip of reachableSites(code, roots)) {
8170
- const op = code[ip];
8171
- if (op === OP_SCAN) {
8172
- fd = true;
8173
- er = true;
8174
- break;
8880
+ const needsNoRawPrelude = !hostCst && reachable.some((ip) => {
8881
+ const op = code[ip];
8882
+ return (op === OP_NODE || op === OP_NODE_TRACK) && code[ip + 1] >= 0 && code[ip + 4] < 0 && (code[ip + 3] & 2) !== 0;
8883
+ });
8884
+ const sinkSites = reachable;
8885
+ const sinkBits = /* @__PURE__ */ new Map();
8886
+ for (const ip of sinkSites) {
8887
+ const op = code[ip];
8888
+ sinkBits.set(
8889
+ ip,
8890
+ op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
8891
+ );
8892
+ }
8893
+ const sinkKids = [];
8894
+ let sinkChanged = true;
8895
+ while (sinkChanged) {
8896
+ sinkChanged = false;
8897
+ for (const ip of sinkSites) {
8898
+ let bits = sinkBits.get(ip) ?? 0;
8899
+ sinkKids.length = 0;
8900
+ childSlots(code, ip, sinkKids);
8901
+ for (let i = 0; i < sinkKids.length; i++) bits |= sinkBits.get(sinkKids[i]) ?? 0;
8902
+ if (bits !== sinkBits.get(ip)) {
8903
+ sinkBits.set(ip, bits);
8904
+ sinkChanged = true;
8175
8905
  }
8176
- if (op === OP_FIELD) fd = true;
8177
- else if (op === OP_EXPECT) er = true;
8178
8906
  }
8179
- return { fd, er };
8180
- })();
8907
+ }
8908
+ const sinksAt = (ip) => {
8909
+ const bits = sinkBits.get(ip) ?? 0;
8910
+ return bits === 0 ? NO_SINKS : { fd: (bits & 1) !== 0, er: (bits & 2) !== 0 };
8911
+ };
8181
8912
  const bodies = [];
8182
8913
  const byIp = /* @__PURE__ */ new Map();
8183
8914
  const reached = /* @__PURE__ */ new Set();
@@ -8204,9 +8935,117 @@ function emitAssemblySource(t2, prog, cfg, extraIps = []) {
8204
8935
  const fxRef = (i) => hoist("fx", `FX[${i}]`);
8205
8936
  const fnRef = (i) => hoist("fn", `FNS[${i}]`);
8206
8937
  const recognizerRef = (i) => hoist("rec", `RECOG[${i}]`);
8938
+ const scalarSequenceRefs = /* @__PURE__ */ new Map();
8939
+ const scalarSequenceRef = (sequence6) => {
8940
+ const key = `${sequence6.trivia}:${sequence6.terminals.map((terminal) => code[terminal + 1]).join(",")}`;
8941
+ const prior = scalarSequenceRefs.get(key);
8942
+ if (prior !== void 0) return prior;
8943
+ const recognizers = sequence6.terminals.map((terminal) => recognizerRef(code[terminal + 1]));
8944
+ const expected = sequence6.terminals.map((terminal) => fxRef(code[terminal + 2]));
8945
+ const scan = sequence6.trivia < 0 ? void 0 : hoist("ts", `TRIVIASCAN[${sequence6.trivia}]`);
8946
+ const name = `_sd${scalarSequenceRefs.size}_`;
8947
+ const steps = recognizers.map((recognize, i) => `${i === 0 ? "let " : ""}at=${i === 0 ? "pos" : scan === void 0 ? "cur" : `${scan}(input,cur)`}
8948
+ ${i === 0 ? "let " : ""}cur=${recognize}(input,at)
8949
+ if(cur<0){_pfSeqEnd=at;return ${~i}}`).join("\n");
8950
+ choiceDefs.push(`function ${name}(input,pos){
8951
+ ${steps}
8952
+ return cur
8953
+ }`);
8954
+ const made = { name, expected };
8955
+ scalarSequenceRefs.set(key, made);
8956
+ return made;
8957
+ };
8207
8958
  const sentRef = (cls) => cls < 0 ? "undefined" : hoist("sent", `SENTS[${cls}]`);
8208
8959
  let uid = 0;
8209
8960
  const tmp = () => `_t${uid++}_`;
8961
+ const dispatchClaim = (m) => {
8962
+ switch (m[0]) {
8963
+ case 0:
8964
+ return `key.startsWith(${q(m[1])})`;
8965
+ case 1:
8966
+ return `key.endsWith(${q(m[1])})`;
8967
+ case 3:
8968
+ return `asciiFoldKey(key).startsWith(${q(m[1])})`;
8969
+ case 4:
8970
+ return `asciiFoldKey(key).endsWith(${q(m[1])})`;
8971
+ default: {
8972
+ if (!m[2].includes("g") && !m[2].includes("y")) {
8973
+ try {
8974
+ new RegExp(m[1], m[2]);
8975
+ return `${hoist("dm", `new RegExp(${q(m[1])},${q(m[2])})`)}.test(key)`;
8976
+ } catch {
8977
+ }
8978
+ }
8979
+ return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
8980
+ }
8981
+ }
8982
+ };
8983
+ const tokenDecisionRefs = /* @__PURE__ */ new Map();
8984
+ function tokenDecisionFor(dispatchIp) {
8985
+ const prior = tokenDecisionRefs.get(dispatchIp);
8986
+ if (prior !== void 0) return prior;
8987
+ const selectorIp = code[dispatchIp + 1];
8988
+ const body = code[selectorIp + 1];
8989
+ const lineFlags = code[selectorIp + 4];
8990
+ const hasSuffix = (lineFlags & 4) !== 0;
8991
+ const di = code[dispatchIp + 2];
8992
+ const spec = dsp[di];
8993
+ const n = code[dispatchIp + 5];
8994
+ validateDispatchSpec(spec, n, code[dispatchIp + 4]);
8995
+ const recognize = hoist("lex", `LEX[${body}]`);
8996
+ const bk = hoist("bk", `DSP[${di}].byKey`);
8997
+ const expected = hoist("dx", `DSP[${di}].expected`);
8998
+ const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
8999
+ ` : "";
9000
+ const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
9001
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${dispatchClaim(m)})arm=${m[3]}`).join("\n")}
9002
+ }
9003
+ `;
9004
+ const foldedEntries = [...spec.byFold.entries()];
9005
+ const fixedFunctionChoice = spec.byKey.size === 0 && foldedEntries.length === 1 && spec.match.length === 1 && spec.match[0][0] === 2 && spec.match[0][1] === "^(?!(?:url|calc)\\($).+\\($" && spec.match[0][2] === "i" && code[dispatchIp + 3] < 0;
9006
+ const foldedRangeEquals = (value) => {
9007
+ const folded = value.replace(/[A-Z]/g, (c) => c.toLowerCase());
9008
+ return `e-pos===${folded.length}&&${[...folded].map((c, i) => {
9009
+ const cc = c.charCodeAt(0);
9010
+ return `_asciiFoldCode(input.charCodeAt(pos+${i}))===${cc}`;
9011
+ }).join("&&")}`;
9012
+ };
9013
+ const classify = fixedFunctionChoice ? (() => {
9014
+ const [exact, exactArm] = foldedEntries[0];
9015
+ const genericArm = spec.match[0][3];
9016
+ return `let arm
9017
+ if(${foldedRangeEquals(exact)})arm=${exactArm}
9018
+ else if(sm&&e>pos+1){
9019
+ let clean=true
9020
+ for(let i=pos;i<e;i++){const c=input.charCodeAt(i);if(c===10||c===13||c===0x2028||c===0x2029){clean=false;break}}
9021
+ if(clean&&!(${foldedRangeEquals("url(")})&&!(${foldedRangeEquals("calc(")}))arm=${genericArm}
9022
+ }`;
9023
+ })() : `const key=input.slice(pos,e)
9024
+ let arm=${bk}.get(key)
9025
+ ${fold}${chain}`;
9026
+ const name = `_td${tokenDecisionRefs.size}_`;
9027
+ choiceDefs.push(`function ${name}(input,pos){
9028
+ const r=${recognize}(input,pos)
9029
+ if(r<0)return -1
9030
+ const sm=${hasSuffix ? "r%2===1" : "false"},e=(r-(sm?1:0))/2
9031
+ ${classify}
9032
+ if(arm===undefined){
9033
+ ${code[dispatchIp + 3] < 0 ? "_pfTokEnd=e;return 0" : `arm=${n}`}
9034
+ }
9035
+ ${fixedFunctionChoice ? "const key=input.slice(pos,e)" : ""}
9036
+ _pfTokInput=input
9037
+ _pfTokPos=pos
9038
+ _pfTokBody=${body}
9039
+ _pfTokPacked=r
9040
+ _pfTokValue=key
9041
+ _pfTokDispatch=${dispatchIp}
9042
+ _pfTokArm=arm
9043
+ return 1
9044
+ }`);
9045
+ const made = { name, expected };
9046
+ tokenDecisionRefs.set(dispatchIp, made);
9047
+ return made;
9048
+ }
8210
9049
  function skipFor(l) {
8211
9050
  if (l.tri < 0) return "_skipTrivia";
8212
9051
  const ki = l.tri;
@@ -8294,7 +9133,8 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
8294
9133
  const op = code[ip];
8295
9134
  const head = `function ${fname}(input,pos,ctx){`;
8296
9135
  const L = labels.at(ip);
8297
- const pushLeaf = L.buf && !cfg.trackLines ? "_pushLeafBuf" : "_pushLeaf";
9136
+ const sinks = sinksAt(ip);
9137
+ const pushLeaf = L.buf && !cfg.trackLines ? L.raw === RAW_OMIT ? "_pushLeafNoRawBuf" : L.raw === RAW_CAPTURE ? "_pushLeafBuf" : "_pushLeaf" : "_pushLeaf";
8298
9138
  const captureLeaf = (value) => {
8299
9139
  const call = `${pushLeaf}(ctx,${value},pos,e)`;
8300
9140
  return L.buf ? call : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${call}`;
@@ -8545,20 +9385,24 @@ return out
8545
9385
  }`;
8546
9386
  }
8547
9387
  case OP_LEX_BODY: {
8548
- const recognize = hoist("lex", `LEX[${code[ip + 1]}]`);
9388
+ const body = code[ip + 1];
9389
+ const recognize = hoist("lex", `LEX[${body}]`);
8549
9390
  const expected = fxRef(code[ip + 2]);
8550
9391
  const suffixExpected = fxRef(code[ip + 3]);
8551
9392
  const lineFlags = code[ip + 4];
8552
9393
  const hasSuffix = (lineFlags & 4) !== 0;
9394
+ const pending = tokenChoiceBodies.has(body);
8553
9395
  return `${head}
8554
- const r=${recognize}(input,pos)
9396
+ ${pending ? `const tp=_pfTokBody===${body}&&_pfTokInput===input&&_pfTokPos===pos
9397
+ const r=tp?_pfTokPacked:${recognize}(input,pos)` : `const r=${recognize}(input,pos)`}
8555
9398
  if(r<0){ctx._fe=pos;ctx._fx=${expected};if(ctx._probe!==undefined)failAt(ctx,${expected},pos);return FAIL}
8556
9399
  const sm=${hasSuffix ? "r%2===1" : "false"},e=(r-(sm?1:0))/2
8557
9400
  ${(lineFlags & 1) !== 0 ? "_trackLines(ctx,input,sm?e-1:e)" : ""}
8558
9401
  ${hasSuffix ? "ctx._fc=false" : ""}
8559
9402
  ${hasSuffix && (lineFlags & 2) !== 0 ? "if(sm)_trackLines(ctx,input,e)" : ""}
8560
9403
  ${hasSuffix ? `if(!sm){ctx._fe=e;ctx._fx=${suffixExpected};if(ctx._probe!==undefined)failAt(ctx,${suffixExpected},e)}` : ""}
8561
- const v=input.slice(pos,e)
9404
+ const v=${pending ? "tp?_pfTokValue:" : ""}input.slice(pos,e)
9405
+ ${pending ? "if(tp){_pfTokBody=-1;_pfTokValue=undefined}" : ""}
8562
9406
  if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
8563
9407
  EC.e=e
8564
9408
  return v
@@ -8614,12 +9458,13 @@ return v
8614
9458
  /* ── transaction ─────────────────────────────────────────────────────── */
8615
9459
  case OP_ATTEMPT: {
8616
9460
  const child = link(code[ip + 1]);
9461
+ const clean = !REC && failureRollbackClean(prog, ip);
8617
9462
  const p = tmp();
8618
9463
  return `${head}
8619
- ${emitMark(p, L.buf, sinks)}
9464
+ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
8620
9465
  const v=${child}(input,pos,ctx)
8621
9466
  if(v!==FAIL)return v
8622
- ${emitRollback(p, L.buf, sinks)}
9467
+ ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
8623
9468
  if(ctx._fc===true)return FAIL
8624
9469
  ctx._fe=pos
8625
9470
  return FAIL
@@ -8642,9 +9487,9 @@ return FAIL
8642
9487
  const xf = fxRef(code[ip + 2]);
8643
9488
  const p = tmp();
8644
9489
  return `${head}
8645
- ${emitMark(p, L.buf, sinks)}
9490
+ ${emitMark(p, L.buf, L.raw, sinks)}
8646
9491
  const v=${child}(input,pos,ctx)
8647
- ${emitRollback(p, L.buf, sinks)}
9492
+ ${emitRollback(p, L.buf, L.raw, sinks)}
8648
9493
  if(v===FAIL){EC.e=pos;return null}
8649
9494
  ctx._fe=pos
8650
9495
  ctx._fx=${xf}
@@ -8656,9 +9501,9 @@ return FAIL
8656
9501
  const xf = fxRef(code[ip + 2]);
8657
9502
  const p = tmp();
8658
9503
  return `${head}
8659
- ${emitMark(p, L.buf, sinks)}
9504
+ ${emitMark(p, L.buf, L.raw, sinks)}
8660
9505
  const v=${child}(input,pos,ctx)
8661
- ${emitRollback(p, L.buf, sinks)}
9506
+ ${emitRollback(p, L.buf, L.raw, sinks)}
8662
9507
  if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
8663
9508
  EC.e=pos
8664
9509
  return null
@@ -8666,14 +9511,15 @@ return null
8666
9511
  }
8667
9512
  case OP_OPT: {
8668
9513
  const child = link(code[ip + 1]);
9514
+ const clean = !REC && failureRollbackClean(prog, ip);
8669
9515
  const p = tmp();
8670
9516
  return `${head}
8671
- ${emitMark(p, L.buf, sinks)}
9517
+ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
8672
9518
  ctx._fc=false
8673
9519
  const v=${child}(input,pos,ctx)
8674
9520
  if(v===FAIL){
8675
9521
  if(ctx._fc===true)return FAIL
8676
- ${emitRollback(p, L.buf, sinks)}
9522
+ ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
8677
9523
  EC.e=pos
8678
9524
  return null
8679
9525
  }
@@ -8772,57 +9618,193 @@ return FAIL
8772
9618
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
8773
9619
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
8774
9620
  const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
9621
+ const tokenCandidate = tokenChoiceCandidates.get(ip);
9622
+ const pretests = Array.from({ length: n }, (_, i) => {
9623
+ if (tokenCandidate?.arm === i) {
9624
+ return { token: tokenDecisionFor(tokenCandidate.dispatchIp) };
9625
+ }
9626
+ const terminal = leadingScalarTerminal(code, code[base + i], 2, true, true);
9627
+ if (terminal >= 0) {
9628
+ const spec = code[terminal + 1];
9629
+ if ((n === 2 || n === 3 ? scalarSpecs : largeChoiceScalarSpecs).has(spec)) {
9630
+ return { scalar: [recognizerRef(spec)] };
9631
+ }
9632
+ }
9633
+ const family = largeChoiceLiteralFamilies.get(code[base + i]);
9634
+ if (family !== void 0) {
9635
+ return { scalar: family.map((member) => recognizerRef(code[member + 1])) };
9636
+ }
9637
+ const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
9638
+ return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
9639
+ });
8775
9640
  const maskable = n <= 32;
8776
9641
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
8777
9642
  if (maskable) maskPlan.push(~di);
8778
9643
  const p = tmp();
8779
- const catchName = maskable ? `_cx${uid++}_` : "";
8780
- if (maskable) {
9644
+ const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
9645
+ const rollbackMask = REC ? -1 : encodedRollbackMask;
9646
+ const hasRollback = rollbackMask !== 0;
9647
+ const startFailureExact = arms.every((_arm, i) => {
9648
+ const terminal = leadingScalarTerminal(code, code[base + i], 0, false);
9649
+ if (terminal < 0) return false;
9650
+ const op2 = code[terminal];
9651
+ const spec = k[code[terminal + 1]];
9652
+ const terminalFx = fx[code[terminal + 2]];
9653
+ const armFx = fx[code[base + n + i]];
9654
+ if (terminalFx.length !== armFx.length || terminalFx.some((expected2, at) => expected2 !== armFx[at])) return false;
9655
+ if (op2 === OP_LIT) return typeof spec === "string" && spec.length > 0;
9656
+ return op2 === OP_RX && spec instanceof RegExp && !regexCanMatchEmpty(spec.source);
9657
+ });
9658
+ const rollbackFor = (i) => rollbackMask === -1 || (rollbackMask & 1 << i) !== 0 ? emitRollback(p, L.buf, L.raw, sinks) : "";
9659
+ if (choiceCannotCommit(prog, ip) && !startFailureExact) {
9660
+ const deepAt = Array.from({ length: n }, () => tmp());
9661
+ const deepFx = Array.from({ length: n }, () => tmp());
9662
+ const remember = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
9663
+ const lazyArms = (ascii) => arms.map((arm, i) => {
9664
+ const pretest = pretests[i];
9665
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
9666
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
9667
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
9668
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
9669
+ const gate = ascii ? `(bits&${1 << i})!==0${condition}` : `(${gateRefs[i]}===null||classHas(${gateRefs[i]},c))${condition}`;
9670
+ const routeMiss = pretest?.token === void 0 ? "" : `
9671
+ if(${decision}===0){
9672
+ ctx._fc=false
9673
+ {const at=_pfTokEnd
9674
+ ${remember(i, "at", pretest.token.expected)}}
9675
+ }`;
9676
+ const sequenceMiss = pretest?.sequence === void 0 ? "" : `
9677
+ else if(${ascii ? `(bits&${1 << i})!==0&&` : ""}${decision}<0){
9678
+ ctx._fc=false
9679
+ {const at=_pfSeqEnd
9680
+ ${remember(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
9681
+ }`;
9682
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
9683
+ `}if(${gate}){
9684
+ ctx._fc=false
9685
+ {const v=${arm}(input,pos,ctx)
9686
+ if(v!==FAIL)return v}
9687
+ {const at=ctx._fe??pos
9688
+ ${remember(i, "at", "ctx._fx")}}
9689
+ ${rollbackFor(i)}
9690
+ }${routeMiss}${sequenceMiss}`;
9691
+ }).join("\n");
9692
+ const merge = deepAt.map((at, i) => `{const at=${at}??pos
9693
+ const ex=${at}===undefined?${expected[i]}:${deepFx[i]}
9694
+ if(at>best){best=at;acc=_accSet(ex,undefined)}
9695
+ else if(at===best)acc=_accSet(ex,acc)
9696
+ }`).join("\n");
9697
+ const finish = `let best=pos,acc
9698
+ ${merge}
9699
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
9700
+ return FAIL`;
9701
+ return `${head}
9702
+ const c=lead(input,pos)
9703
+ ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9704
+ ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
9705
+ ${maskable ? `if(c<128){
9706
+ const bits=${maskName}[c<0?128:c]
9707
+ if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9708
+ ${lazyArms(true)}
9709
+ }else{
9710
+ ${lazyArms(false)}
9711
+ }
9712
+ ` : lazyArms(false)}
9713
+ ${finish}
9714
+ }`;
9715
+ }
9716
+ const needsCatch = maskable || startFailureExact;
9717
+ const catchName = needsCatch ? `_cx${uid++}_` : "";
9718
+ if (needsCatch) {
8781
9719
  const catchCases = expected.map((e, i) => `case ${i}:if(target<=${i})return acc;acc=_accSet(${e},acc)`).join("\n");
8782
9720
  choiceDefs.push(`function ${catchName}(target,prev,acc){switch(prev){
8783
9721
  ${catchCases}
8784
9722
  }return acc}`);
8785
9723
  }
8786
9724
  const maskArms = maskable ? arms.map((arm, i) => {
8787
- return `if((bits&${1 << i})!==0){
9725
+ const pretest = pretests[i];
9726
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
9727
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
9728
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
9729
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
9730
+ const routeMiss = pretest?.token === void 0 ? "" : `
9731
+ if(${decision}===0){
9732
+ ctx._fc=false
9733
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
9734
+ prev=${i + 1}`}
9735
+ {const at=_pfTokEnd
9736
+ if(at>best){best=at;acc=undefined}
9737
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.token.expected},acc)}
9738
+ }`;
9739
+ const sequenceMiss = pretest?.sequence === void 0 ? "" : `
9740
+ else if((bits&${1 << i})!==0&&${decision}<0){
9741
+ ctx._fc=false
9742
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
9743
+ prev=${i + 1}`}
9744
+ {const at=_pfSeqEnd
9745
+ if(at>best){best=at;acc=undefined}
9746
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("")}${pretest.sequence.expected.at(-1)},acc)}
9747
+ }`;
9748
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
9749
+ `}if((bits&${1 << i})!==0${condition}){
8788
9750
  ctx._fc=false
8789
9751
  {const v=${arm}(input,pos,ctx)
8790
9752
  if(v!==FAIL)return v}
8791
- if(best===pos)acc=${catchName}(${i},prev,acc)
8792
- prev=${i + 1}
9753
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
9754
+ prev=${i + 1}`}
8793
9755
  {const at=ctx._fe??pos
8794
9756
  if(at>best){best=at;acc=undefined}
8795
- if(at===best)acc=_accSet(ctx._fx,acc)}
8796
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
8797
- ${emitRollback(p, L.buf, sinks)}
8798
- }`;
9757
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(ctx._fx,acc)}
9758
+ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0,undefined);acc=_accSet(ctx._fx,acc)}` : ""}if(acc!==undefined)ctx._fx=acc;return FAIL}
9759
+ ${rollbackFor(i)}
9760
+ }${routeMiss}${sequenceMiss}`;
8799
9761
  }).join("\n") : "";
8800
- const generalArms = arms.map((arm, i) => `if(${gateRefs[i]}===null||classHas(${gateRefs[i]},c)){
9762
+ const generalArms = arms.map((arm, i) => {
9763
+ const pretest = pretests[i];
9764
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
9765
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
9766
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
9767
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
9768
+ const miss = pretest?.sequence !== void 0 ? `else if(${decision}<0){
9769
+ ctx._fc=false
9770
+ const at=_pfSeqEnd
9771
+ if(at>best){best=at;acc=undefined}
9772
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("")}${pretest.sequence.expected.at(-1)},acc)
9773
+ }${startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)`}` : pretest?.token === void 0 ? startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)` : `else if(${decision}===0){
9774
+ ctx._fc=false
9775
+ const at=_pfTokEnd
9776
+ if(at>best){best=at;acc=undefined}
9777
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.token.expected},acc)
9778
+ }${startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)`}`;
9779
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
9780
+ `}if((${gateRefs[i]}===null||classHas(${gateRefs[i]},c))${condition}){
8801
9781
  ctx._fc=false
8802
9782
  {const v=${arm}(input,pos,ctx)
8803
9783
  if(v!==FAIL)return v}
8804
9784
  {const at=ctx._fe??pos
8805
9785
  if(at>best){best=at;acc=undefined}
8806
- if(at===best)acc=_accSet(ctx._fx,acc)}
8807
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
8808
- ${emitRollback(p, L.buf, sinks)}
8809
- }else if(best===pos)acc=_accSet(${expected[i]},acc)`).join("\n");
9786
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(ctx._fx,acc)}
9787
+ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0,undefined);acc=_accSet(ctx._fx,acc)}` : ""}if(acc!==undefined)ctx._fx=acc;return FAIL}
9788
+ ${rollbackFor(i)}
9789
+ }${miss}`;
9790
+ }).join("\n");
8810
9791
  return `${head}
8811
9792
  const c=lead(input,pos)
8812
- ${emitMark(p, L.buf, sinks)}
9793
+ ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
8813
9794
  let acc
8814
9795
  let best=pos
8815
9796
  ${maskable ? `if(c<128){
8816
9797
  const bits=${maskName}[c<0?128:c]
8817
- let prev=0
9798
+ if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9799
+ ${startFailureExact ? "" : "let prev=0"}
8818
9800
  ${maskArms}
8819
- if(best===pos)acc=${catchName}(${n},prev,acc)
8820
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
9801
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${n},prev,acc)`}
9802
+ ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
8821
9803
  return FAIL
8822
9804
  }
8823
9805
  ` : ""}
8824
9806
  ${generalArms}
8825
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
9807
+ ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
8826
9808
  return FAIL
8827
9809
  }`;
8828
9810
  }
@@ -8841,30 +9823,8 @@ return FAIL
8841
9823
  for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
8842
9824
  const bk = hoist("bk", `DSP[${di}].byKey`);
8843
9825
  const dx = hoist("dx", `DSP[${di}].expected`);
8844
- const claims = (m) => {
8845
- switch (m[0]) {
8846
- case 0:
8847
- return `key.startsWith(${q(m[1])})`;
8848
- case 1:
8849
- return `key.endsWith(${q(m[1])})`;
8850
- case 3:
8851
- return `asciiFoldKey(key).startsWith(${q(m[1])})`;
8852
- case 4:
8853
- return `asciiFoldKey(key).endsWith(${q(m[1])})`;
8854
- default: {
8855
- if (!m[2].includes("g") && !m[2].includes("y")) {
8856
- try {
8857
- new RegExp(m[1], m[2]);
8858
- return `${hoist("dm", `new RegExp(${q(m[1])},${q(m[2])})`)}.test(key)`;
8859
- } catch {
8860
- }
8861
- }
8862
- return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
8863
- }
8864
- }
8865
- };
8866
9826
  const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
8867
- ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
9827
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${dispatchClaim(m)})arm=${m[3]}`).join("\n")}
8868
9828
  }
8869
9829
  `;
8870
9830
  const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
@@ -8872,33 +9832,43 @@ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}
8872
9832
  const m1 = tmp();
8873
9833
  const m2 = tmp();
8874
9834
  const routedCall = (target) => `{const savedRouted=ctx._routed
8875
- ${emitRollback(m1, L.buf, sinks)}
8876
- ${emitMark(m2, L.buf, sinks, false)}
9835
+ ${emitRollback(m1, L.buf, L.raw, sinks)}
9836
+ ${emitMark(m2, L.buf, L.raw, sinks, false)}
8877
9837
  ctx._routed={value:key,span:{start:pos,end:selEnd}}
8878
9838
  try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
8879
9839
  break}`;
8880
9840
  const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
8881
9841
  const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
8882
9842
  const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
9843
+ const armSelection = tokenChoiceDispatches.has(ip) ? `const tp=_pfTokDispatch===${ip}&&_pfTokInput===input&&_pfTokPos===pos
9844
+ let arm
9845
+ if(tp){
9846
+ arm=_pfTokArm
9847
+ _pfTokDispatch=-1
9848
+ _pfTokInput=undefined
9849
+ if(arm===${n})arm=undefined
9850
+ }else{
9851
+ arm=${bk}.get(key)
9852
+ ${fold}${chain}}` : `let arm=${bk}.get(key)
9853
+ ${fold}${chain}`;
8883
9854
  return `${head}
8884
- ${emitMark(m1, L.buf, sinks)}
9855
+ ${emitMark(m1, L.buf, L.raw, sinks)}
8885
9856
  const sv=${selector}(input,pos,ctx)
8886
9857
  if(sv===FAIL)return FAIL
8887
9858
  const selEnd=EC.e
8888
9859
  const key=sv
8889
- let arm=${bk}.get(key)
8890
- ${fold}${chain}
9860
+ ${armSelection}
8891
9861
  if(arm===undefined){
8892
9862
  ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
8893
9863
  }
8894
- ${emitMark(m2, L.buf, sinks)}
9864
+ ${emitMark(m2, L.buf, L.raw, sinks)}
8895
9865
  let v
8896
9866
  switch(arm){
8897
9867
  ${armCases}
8898
9868
  ${fallbackCase}
8899
9869
  }
8900
9870
  if(v===FAIL){
8901
- ${emitRollback(m2, L.buf, sinks)}
9871
+ ${emitRollback(m2, L.buf, L.raw, sinks)}
8902
9872
  ctx._fc=true
8903
9873
  return FAIL
8904
9874
  }
@@ -8934,23 +9904,25 @@ return [key,v]
8934
9904
  const skip = skipFor(L);
8935
9905
  const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
8936
9906
  const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
8937
- const pfd = sinks.fd ? `${p}fd` : "0";
9907
+ const pfd = sinks.fd ? `${p}fd` : "undefined";
8938
9908
  const per = sinks.er ? `${p}er` : "undefined";
8939
- const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
9909
+ const rbHelper = L.raw === RAW_OMIT ? "_rbNoRawBuf" : "_rbBuf";
9910
+ const rb = L.buf && L.raw !== 0 ? `${rbHelper}(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
8940
9911
  if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
8941
- if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
9912
+ if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : L.buf ? `rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
8942
9913
  const markSinks = `${sinks.fd ? `
8943
9914
  ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
8944
9915
  ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
9916
+ const markRaw = L.raw === RAW_OMIT ? `${p}raw=b.rawLen` : L.raw === RAW_CAPTURE ? `const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0` : `const r=b.raw;${p}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)`;
8945
9917
  const markBody = L.buf ? `const b=ctx._cstBuf
8946
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
9918
+ ${markRaw}
8947
9919
  const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
8948
9920
  const l=b.tl;${p}tl=l!==undefined?l.length:0
8949
9921
  ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
8950
9922
  ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
8951
9923
  const b=ctx._cstBuf
8952
9924
  if(b!==undefined){
8953
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
9925
+ const r=b.raw;${p}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)
8954
9926
  const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
8955
9927
  const l=b.tl;${p}tl=l!==undefined?l.length:0
8956
9928
  }else{
@@ -9057,7 +10029,7 @@ const leaf={_tag:'leaf',value,span:{start:pos,end}}
9057
10029
  const kids=[leaf],rawKids=[leaf],span={start:pos,end}
9058
10030
  EC.e=end
9059
10031
  const nd=${build2}(kids,undefined,span,rawKids,EMPTY_TL,undefined)
9060
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
10032
+ ${L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : staticBuild ? "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,ctx._cstBuf!==undefined&&ctx._cstBuf.noRaw===true?undefined:ctx._cstBuf!==undefined||ctx._cstRawChildren!==undefined?rawEntry(nd,input,pos,end):undefined)" : "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
9061
10033
  EC.e=end
9062
10034
  return nd
9063
10035
  }`;
@@ -9079,7 +10051,22 @@ return nd
9079
10051
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (flags === 2 || flags === 18 || flags === 34)) {
9080
10052
  const fields = flags === 18;
9081
10053
  const collapseChildren = flags === 34;
9082
- const publish = `if(sBuf!==undefined){
10054
+ const publish = L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? `if(sBuf!==undefined){
10055
+ if(sBuf.rawOnly!==true){
10056
+ if(sBuf.ch!==undefined)sBuf.ch.push(nd)
10057
+ else if(sBuf.single!==undefined){sBuf.ch=[sBuf.single,nd];sBuf.single=undefined}
10058
+ else sBuf.single=nd
10059
+ }
10060
+ const rawNd=rawEntry(nd,input,pos,end)
10061
+ if(sBuf.raw!==undefined)sBuf.raw.push(rawNd)
10062
+ else if(sBuf.rawSingle!==undefined){sBuf.raw=[sBuf.rawSingle,rawNd];sBuf.rawSingle=undefined}
10063
+ else sBuf.rawSingle=rawNd
10064
+ }else if(sCh!==undefined){
10065
+ sCh.push(nd)
10066
+ if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
10067
+ }` : `if(sBuf!==undefined){
10068
+ if(sBuf.noRaw===true)_pushNodeNoRawBuf(ctx,nd)
10069
+ else{
9083
10070
  if(sBuf.rawOnly!==true){
9084
10071
  if(sBuf.ch!==undefined)sBuf.ch.push(nd)
9085
10072
  else if(sBuf.single!==undefined){sBuf.ch=[sBuf.single,nd];sBuf.single=undefined}
@@ -9089,6 +10076,7 @@ const rawNd=rawEntry(nd,input,pos,end)
9089
10076
  if(sBuf.raw!==undefined)sBuf.raw.push(rawNd)
9090
10077
  else if(sBuf.rawSingle!==undefined){sBuf.raw=[sBuf.rawSingle,rawNd];sBuf.rawSingle=undefined}
9091
10078
  else sBuf.rawSingle=rawNd
10079
+ }
9092
10080
  }else if(sCh!==undefined){
9093
10081
  sCh.push(nd)
9094
10082
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
@@ -9127,6 +10115,7 @@ return nd
9127
10115
  const wantFields = hasFields || hostCst;
9128
10116
  const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
9129
10117
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
10118
+ const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
9130
10119
  const ty = q(type);
9131
10120
  const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
9132
10121
  const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
@@ -9140,7 +10129,12 @@ return nd
9140
10129
  value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
9141
10130
  }
9142
10131
  const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
9143
- const openCapture = keepChildren ? `const buf={}
10132
+ const openCapture = omitsRaw ? `const buf={noRaw:true,rawLen:0}
10133
+ ctx._cstBuf=buf
10134
+ ctx._cstChildren=undefined
10135
+ ctx._cstLeaves=undefined
10136
+ ctx._cstRawChildren=undefined
10137
+ ctx._cstTriviaLog=undefined` : keepChildren ? `const buf={}
9144
10138
  ctx._cstBuf=buf
9145
10139
  ctx._cstChildren=undefined
9146
10140
  ctx._cstLeaves=undefined
@@ -9151,7 +10145,10 @@ ctx._cstChildren=undefined
9151
10145
  ctx._cstLeaves=undefined
9152
10146
  ctx._cstRawChildren=undefined
9153
10147
  ctx._cstTriviaLog=undefined`;
9154
- const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
10148
+ const finishCapture = omitsRaw ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
10149
+ const hostKids=kids
10150
+ const rawKids=EMPTY_CH
10151
+ const tlog=buf.tl??EMPTY_TLOG` : keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
9155
10152
  const hostKids=kids
9156
10153
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
9157
10154
  const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
@@ -9185,7 +10182,7 @@ const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):unde
9185
10182
  let nd
9186
10183
  ${unwrap ? "if(kids.length===1)nd=unwrapChild(kids[0])\nelse " : ""}${collapse ? "if(kids.length===1)nd=kids[0]\nelse " : ""}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
9187
10184
  else ` : ""}{${value}}
9188
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
10185
+ ${L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : staticBuild ? "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,sBuf!==undefined?(sBuf.noRaw===true?undefined:rawEntry(nd,input,pos,end)):sRaw!==undefined?rawEntry(nd,input,pos,end):undefined)" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
9189
10186
  EC.e=end
9190
10187
  return nd
9191
10188
  }`;
@@ -9203,7 +10200,7 @@ return nd
9203
10200
  }
9204
10201
  const extra = [];
9205
10202
  for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
9206
- const source = `${RUNTIME_PRELUDE}
10203
+ const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
9207
10204
  ${prelude.join("\n")}
9208
10205
  ${skipDefs.join("\n")}
9209
10206
  ${choiceDefs.join("\n")}
@@ -9218,7 +10215,13 @@ _pfHost=host
9218
10215
  function _finish(){
9219
10216
  if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
9220
10217
  _pfDepth--
9221
- if(_pfDepth===0)return
10218
+ if(_pfDepth===0){
10219
+ _pfTokInput=undefined
10220
+ _pfTokBody=-1
10221
+ _pfTokValue=undefined
10222
+ _pfTokDispatch=-1
10223
+ return
10224
+ }
9222
10225
  const prior=_pfFrames.pop()
9223
10226
  _pfScan=prior[0]
9224
10227
  _pfHost=prior[1]
@@ -9985,6 +10988,17 @@ function assemble(t2, prog, cfg) {
9985
10988
  }
9986
10989
  return recognize;
9987
10990
  }
10991
+ const labelExtraIps = [];
10992
+ for (const s of prog.scans ?? []) {
10993
+ for (const r of s.skip) labelExtraIps.push(r[0]);
10994
+ if (s.sentinel !== void 0) labelExtraIps.push(s.sentinel[0]);
10995
+ }
10996
+ for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0]);
10997
+ const closureLabels = computeSiteLabels(
10998
+ code,
10999
+ [...Object.values(prog.rules), ...labelExtraIps],
11000
+ hostCst
11001
+ );
9988
11002
  let SCAN = null;
9989
11003
  const memo = /* @__PURE__ */ new Map();
9990
11004
  const reached = /* @__PURE__ */ new Set();
@@ -10230,7 +11244,7 @@ function assemble(t2, prog, cfg) {
10230
11244
  const b = ctx._cstBuf;
10231
11245
  if (b !== void 0) {
10232
11246
  const raw = b.raw;
10233
- MRAW = raw !== void 0 ? raw.length : b.rawSingle !== void 0 ? 1 : 0;
11247
+ MRAW = b.noRaw === true ? b.rawLen ?? 0 : raw !== void 0 ? raw.length : b.rawSingle !== void 0 ? 1 : 0;
10234
11248
  const ch2 = b.ch;
10235
11249
  MLV = ch2 !== void 0 ? ch2.length : b.single !== void 0 ? 1 : 0;
10236
11250
  const tl = b.tl;
@@ -10314,6 +11328,31 @@ function assemble(t2, prog, cfg) {
10314
11328
  if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
10315
11329
  return cur;
10316
11330
  }
11331
+ function nextTermBuffered(child, input, cur, ctx) {
11332
+ if (ctx.trivia === void 0) {
11333
+ const v2 = child(input, cur, ctx);
11334
+ if (v2 === FAIL) return -1;
11335
+ TERMV = v2;
11336
+ return EC.e;
11337
+ }
11338
+ const before = ctx._cstBuf;
11339
+ const beforeTl = before.tl;
11340
+ const mTl = beforeTl === void 0 ? 0 : beforeTl.length;
11341
+ const mLog = ctx._triviaLog?.length ?? 0;
11342
+ const mRoot = ctx._rootTriviaLog?.length ?? 0;
11343
+ const scanEnd = skipTrivia(input, cur, ctx);
11344
+ const scanned = ctx._cstBuf;
11345
+ const scannedTl = scanned.tl;
11346
+ const scanTl = scannedTl === void 0 ? 0 : scannedTl.length;
11347
+ const scanLog = ctx._triviaLog?.length ?? 0;
11348
+ const scanRoot = ctx._rootTriviaLog?.length ?? 0;
11349
+ const v = child(input, scanEnd, ctx);
11350
+ if (v === FAIL) return -1;
11351
+ TERMV = v;
11352
+ if (EC.e > scanEnd) return EC.e;
11353
+ rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
11354
+ return cur;
11355
+ }
10317
11356
  function committed3(c) {
10318
11357
  return c._fc === true;
10319
11358
  }
@@ -10584,7 +11623,8 @@ function assemble(t2, prog, cfg) {
10584
11623
  target = p;
10585
11624
  } };
10586
11625
  inFlight.set(ip, holder);
10587
- const piece = lower(ip);
11626
+ const op = code[ip];
11627
+ const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : lower(ip);
10588
11628
  inFlight.delete(ip);
10589
11629
  holder.set(piece);
10590
11630
  memo.set(ip, piece);
@@ -11327,6 +12367,7 @@ function assemble(t2, prog, cfg) {
11327
12367
  const reducer = fused ? code[ip + 1] : -1;
11328
12368
  const projection = reducer < 0 ? ~reducer : -1;
11329
12369
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
12370
+ const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
11330
12371
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
11331
12372
  if (count === 1) return (input, cur, ctx, values, inherited) => {
11332
12373
  cur = r0(input, cur, ctx, inherited);
@@ -11381,7 +12422,7 @@ function assemble(t2, prog, cfg) {
11381
12422
  const kid = link(kidIp);
11382
12423
  return (input, cur, ctx, inherited) => {
11383
12424
  ctx._sync = sync ?? inherited;
11384
- return nextTerm(kid, input, cur, ctx);
12425
+ return step(kid, input, cur, ctx);
11385
12426
  };
11386
12427
  }
11387
12428
  const negated = code[kidIp + 1] === 1;
@@ -11466,7 +12507,7 @@ function assemble(t2, prog, cfg) {
11466
12507
  const kidIp = code[base + i];
11467
12508
  if (code[kidIp] !== OP_ADJ) {
11468
12509
  const kid = link(kidIp);
11469
- return (input, cur, ctx) => nextTerm(kid, input, cur, ctx);
12510
+ return (input, cur, ctx) => step(kid, input, cur, ctx);
11470
12511
  }
11471
12512
  const negated = code[kidIp + 1] === 1;
11472
12513
  const ki = code[kidIp + 2];
@@ -11555,7 +12596,7 @@ function assemble(t2, prog, cfg) {
11555
12596
  return (input, pos, ctx) => {
11556
12597
  const v0 = k0(input, pos, ctx);
11557
12598
  if (v0 === FAIL) return FAIL;
11558
- const cur = nextTerm(k1, input, EC.e, ctx);
12599
+ const cur = step(k1, input, EC.e, ctx);
11559
12600
  if (cur < 0) return FAIL;
11560
12601
  EC.e = cur;
11561
12602
  return projection === 0 ? v0 : projection === 1 ? TERMV : fn([v0, TERMV], { start: pos, end: cur });
@@ -11565,7 +12606,7 @@ function assemble(t2, prog, cfg) {
11565
12606
  return (input, pos, ctx) => {
11566
12607
  const v0 = k0(input, pos, ctx);
11567
12608
  if (v0 === FAIL) return FAIL;
11568
- const cur = nextTerm(k1, input, EC.e, ctx);
12609
+ const cur = step(k1, input, EC.e, ctx);
11569
12610
  if (cur < 0) return FAIL;
11570
12611
  EC.e = cur;
11571
12612
  return [v0, TERMV];
@@ -11574,7 +12615,7 @@ function assemble(t2, prog, cfg) {
11574
12615
  return (input, pos, ctx) => {
11575
12616
  const v0 = k0(input, pos, ctx);
11576
12617
  if (v0 === FAIL) return FAIL;
11577
- const cur = nextTerm(k1, input, EC.e, ctx);
12618
+ const cur = step(k1, input, EC.e, ctx);
11578
12619
  if (cur < 0) return FAIL;
11579
12620
  EC.e = cur;
11580
12621
  return void 0;
@@ -11586,10 +12627,10 @@ function assemble(t2, prog, cfg) {
11586
12627
  return (input, pos, ctx) => {
11587
12628
  const v0 = k0(input, pos, ctx);
11588
12629
  if (v0 === FAIL) return FAIL;
11589
- let cur = nextTerm(k1, input, EC.e, ctx);
12630
+ let cur = step(k1, input, EC.e, ctx);
11590
12631
  if (cur < 0) return FAIL;
11591
12632
  const v1 = TERMV;
11592
- cur = nextTerm(k2, input, cur, ctx);
12633
+ cur = step(k2, input, cur, ctx);
11593
12634
  if (cur < 0) return FAIL;
11594
12635
  EC.e = cur;
11595
12636
  return projection === 0 ? v0 : projection === 1 ? v1 : projection === 2 ? TERMV : fn([v0, v1, TERMV], { start: pos, end: cur });
@@ -11599,10 +12640,10 @@ function assemble(t2, prog, cfg) {
11599
12640
  return (input, pos, ctx) => {
11600
12641
  const v0 = k0(input, pos, ctx);
11601
12642
  if (v0 === FAIL) return FAIL;
11602
- let cur = nextTerm(k1, input, EC.e, ctx);
12643
+ let cur = step(k1, input, EC.e, ctx);
11603
12644
  if (cur < 0) return FAIL;
11604
12645
  const v1 = TERMV;
11605
- cur = nextTerm(k2, input, cur, ctx);
12646
+ cur = step(k2, input, cur, ctx);
11606
12647
  if (cur < 0) return FAIL;
11607
12648
  EC.e = cur;
11608
12649
  return [v0, v1, TERMV];
@@ -11611,9 +12652,9 @@ function assemble(t2, prog, cfg) {
11611
12652
  return (input, pos, ctx) => {
11612
12653
  const v0 = k0(input, pos, ctx);
11613
12654
  if (v0 === FAIL) return FAIL;
11614
- let cur = nextTerm(k1, input, EC.e, ctx);
12655
+ let cur = step(k1, input, EC.e, ctx);
11615
12656
  if (cur < 0) return FAIL;
11616
- cur = nextTerm(k2, input, cur, ctx);
12657
+ cur = step(k2, input, cur, ctx);
11617
12658
  if (cur < 0) return FAIL;
11618
12659
  EC.e = cur;
11619
12660
  return void 0;
@@ -11621,43 +12662,43 @@ function assemble(t2, prog, cfg) {
11621
12662
  }
11622
12663
  const block = (count, k0, k1, k2, k3, next) => {
11623
12664
  if (count === 1) return (input, cur, ctx, values) => {
11624
- cur = nextTerm(k0, input, cur, ctx);
12665
+ cur = step(k0, input, cur, ctx);
11625
12666
  if (cur < 0) return -1;
11626
12667
  if (values !== void 0) values.push(TERMV);
11627
12668
  return next === void 0 ? cur : next(input, cur, ctx, values);
11628
12669
  };
11629
12670
  if (count === 2) return (input, cur, ctx, values) => {
11630
- cur = nextTerm(k0, input, cur, ctx);
12671
+ cur = step(k0, input, cur, ctx);
11631
12672
  if (cur < 0) return -1;
11632
12673
  if (values !== void 0) values.push(TERMV);
11633
- cur = nextTerm(k1, input, cur, ctx);
12674
+ cur = step(k1, input, cur, ctx);
11634
12675
  if (cur < 0) return -1;
11635
12676
  if (values !== void 0) values.push(TERMV);
11636
12677
  return next === void 0 ? cur : next(input, cur, ctx, values);
11637
12678
  };
11638
12679
  if (count === 3) return (input, cur, ctx, values) => {
11639
- cur = nextTerm(k0, input, cur, ctx);
12680
+ cur = step(k0, input, cur, ctx);
11640
12681
  if (cur < 0) return -1;
11641
12682
  if (values !== void 0) values.push(TERMV);
11642
- cur = nextTerm(k1, input, cur, ctx);
12683
+ cur = step(k1, input, cur, ctx);
11643
12684
  if (cur < 0) return -1;
11644
12685
  if (values !== void 0) values.push(TERMV);
11645
- cur = nextTerm(k2, input, cur, ctx);
12686
+ cur = step(k2, input, cur, ctx);
11646
12687
  if (cur < 0) return -1;
11647
12688
  if (values !== void 0) values.push(TERMV);
11648
12689
  return next === void 0 ? cur : next(input, cur, ctx, values);
11649
12690
  };
11650
12691
  return (input, cur, ctx, values) => {
11651
- cur = nextTerm(k0, input, cur, ctx);
12692
+ cur = step(k0, input, cur, ctx);
11652
12693
  if (cur < 0) return -1;
11653
12694
  if (values !== void 0) values.push(TERMV);
11654
- cur = nextTerm(k1, input, cur, ctx);
12695
+ cur = step(k1, input, cur, ctx);
11655
12696
  if (cur < 0) return -1;
11656
12697
  if (values !== void 0) values.push(TERMV);
11657
- cur = nextTerm(k2, input, cur, ctx);
12698
+ cur = step(k2, input, cur, ctx);
11658
12699
  if (cur < 0) return -1;
11659
12700
  if (values !== void 0) values.push(TERMV);
11660
- cur = nextTerm(k3, input, cur, ctx);
12701
+ cur = step(k3, input, cur, ctx);
11661
12702
  if (cur < 0) return -1;
11662
12703
  if (values !== void 0) values.push(TERMV);
11663
12704
  return next === void 0 ? cur : next(input, cur, ctx, values);
@@ -11828,6 +12869,13 @@ function assemble(t2, prog, cfg) {
11828
12869
  if (n === 2 || n === 3) {
11829
12870
  const a0 = link(code[base]), a1 = link(code[base + 1]);
11830
12871
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
12872
+ const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
12873
+ const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
12874
+ const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
12875
+ const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
12876
+ const p0 = p0ip < 0 ? void 0 : scalarFor(p0ip);
12877
+ const p1 = p1ip < 0 ? void 0 : scalarFor(p1ip);
12878
+ const p2 = p2ip < 0 ? void 0 : scalarFor(p2ip);
11831
12879
  const e0 = fx[code[base + n]];
11832
12880
  const e1 = fx[code[base + n + 1]];
11833
12881
  const e2 = n === 3 ? fx[code[base + n + 2]] : void 0;
@@ -11857,7 +12905,10 @@ function assemble(t2, prog, cfg) {
11857
12905
  let acc;
11858
12906
  let best = pos;
11859
12907
  if (c < 128) {
11860
- const bits = mask[c < 0 ? 128 : c];
12908
+ let bits = mask[c < 0 ? 128 : c];
12909
+ if ((bits & 1) !== 0 && p0 !== void 0 && p0(input, pos) < 0) bits &= ~1;
12910
+ if ((bits & 2) !== 0 && p1 !== void 0 && p1(input, pos) < 0) bits &= ~2;
12911
+ if ((bits & 4) !== 0 && p2 !== void 0 && p2(input, pos) < 0) bits &= ~4;
11861
12912
  let prev = 0;
11862
12913
  if ((bits & 1) !== 0) {
11863
12914
  ctx._fc = false;
@@ -11920,7 +12971,7 @@ function assemble(t2, prog, cfg) {
11920
12971
  ctx._fx = acc ?? choiceFx;
11921
12972
  return FAIL;
11922
12973
  }
11923
- if (g0 === null || classHas2(g0, c)) {
12974
+ if ((g0 === null || classHas2(g0, c)) && (p0 === void 0 || p0(input, pos) >= 0)) {
11924
12975
  ctx._fc = false;
11925
12976
  const v = a0(input, pos, ctx);
11926
12977
  if (v !== FAIL) return v;
@@ -11936,7 +12987,7 @@ function assemble(t2, prog, cfg) {
11936
12987
  }
11937
12988
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
11938
12989
  } else if (best === pos) acc = accSet(e0, acc);
11939
- if (g1 === null || classHas2(g1, c)) {
12990
+ if ((g1 === null || classHas2(g1, c)) && (p1 === void 0 || p1(input, pos) >= 0)) {
11940
12991
  ctx._fc = false;
11941
12992
  const v = a1(input, pos, ctx);
11942
12993
  if (v !== FAIL) return v;
@@ -11953,7 +13004,7 @@ function assemble(t2, prog, cfg) {
11953
13004
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
11954
13005
  } else if (best === pos) acc = accSet(e1, acc);
11955
13006
  if (n === 3) {
11956
- if (g2 === null || classHas2(g2, c)) {
13007
+ if ((g2 === null || classHas2(g2, c)) && (p2 === void 0 || p2(input, pos) >= 0)) {
11957
13008
  ctx._fc = false;
11958
13009
  const v = a2(input, pos, ctx);
11959
13010
  if (v !== FAIL) return v;
@@ -12526,20 +13577,14 @@ function assemble(t2, prog, cfg) {
12526
13577
  const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
12527
13578
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
12528
13579
  const rawOnly = !keepChildren;
13580
+ const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
12529
13581
  return (input, pos, ctx) => {
12530
13582
  const host = HOST;
12531
13583
  const sCh = ctx._cstChildren;
12532
- const sLv = ctx._cstLeaves;
12533
- const sRaw = ctx._cstRawChildren;
12534
- const sTl = ctx._cstTriviaLog;
12535
13584
  const sCap = ctx.captureTrivia;
12536
13585
  const sBuf = ctx._cstBuf;
12537
- const buf = rawOnly ? { rawOnly: true } : {};
13586
+ const buf = rawOnly ? { rawOnly: true } : omitsRaw ? { noRaw: true, rawLen: 0 } : {};
12538
13587
  ctx._cstBuf = buf;
12539
- ctx._cstChildren = void 0;
12540
- ctx._cstLeaves = void 0;
12541
- ctx._cstRawChildren = void 0;
12542
- ctx._cstTriviaLog = void 0;
12543
13588
  ctx.captureTrivia = captureWide;
12544
13589
  const savedFields = ctx._fields;
12545
13590
  ctx._fields = wantFields ? [] : void 0;
@@ -12554,13 +13599,9 @@ function assemble(t2, prog, cfg) {
12554
13599
  if (structural) ctx._triviaCaptureMask = savedMask;
12555
13600
  const kids = rawOnly ? EMPTY_CH : buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY_CH);
12556
13601
  const hostKids = kids;
12557
- const rawKids = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
13602
+ const rawKids = omitsRaw ? EMPTY_CH : buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
12558
13603
  const tlog = buf.tl ?? EMPTY_TLOG;
12559
13604
  ctx._cstBuf = sBuf;
12560
- ctx._cstChildren = sCh;
12561
- ctx._cstLeaves = sLv;
12562
- ctx._cstRawChildren = sRaw;
12563
- ctx._cstTriviaLog = sTl;
12564
13605
  ctx.captureTrivia = sCap;
12565
13606
  if (v === FAIL) return FAIL;
12566
13607
  const end = EC.e;
@@ -12651,6 +13692,34 @@ function assemble(t2, prog, cfg) {
12651
13692
  rawScalarSpecs.add(code[child + 1]);
12652
13693
  scalarFor(child);
12653
13694
  }
13695
+ } else if (code[ip] === OP_CHOICE && !disp[code[ip + 1]].exclusive) {
13696
+ const n = code[ip + 2];
13697
+ for (let i = 0; i < n; i++) {
13698
+ const armIp = code[ip + 4 + i];
13699
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
13700
+ if (n === 2 || n === 3) {
13701
+ if (child >= 0) scalarFor(child);
13702
+ continue;
13703
+ }
13704
+ if (child >= 0) {
13705
+ const spec = k[code[child + 1]];
13706
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
13707
+ scalarFor(child);
13708
+ continue;
13709
+ }
13710
+ }
13711
+ const family = leadingLiteralFamily(code, k, armIp);
13712
+ if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
13713
+ const value = k[code[terminal + 1]];
13714
+ return typeof value === "string" && value.length >= 2;
13715
+ })) {
13716
+ for (const terminal of family) scalarFor(terminal);
13717
+ }
13718
+ const sequence6 = leadingScalarSequence(code, armIp);
13719
+ if (sequence6 !== void 0 && (sequence6.trivia < 0 || triviaScan[sequence6.trivia] != null)) {
13720
+ for (const terminal of sequence6.terminals) scalarFor(terminal);
13721
+ }
13722
+ }
12654
13723
  }
12655
13724
  }
12656
13725
  const notChild = scalarTerminalNotChild(code, ip);
@@ -13061,7 +14130,7 @@ function emitAssemblies(prog, cfgs) {
13061
14130
  seen.add(key);
13062
14131
  let em;
13063
14132
  try {
13064
- em = emitAssemblySource(t2, prog, cfg, extraIps);
14133
+ em = emitAssemblySource(t2, prog, cfg, extraIps, true);
13065
14134
  } catch (e) {
13066
14135
  if (e instanceof Unemittable) continue;
13067
14136
  throw e;
@@ -14594,7 +15663,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
14594
15663
  };
14595
15664
  const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
14596
15665
  const artifact = closureArtifact(prog);
14597
- const entry = tableRules(artifact)[ENTRY];
15666
+ const entry = tableRules(prog)[ENTRY];
14598
15667
  const offered = opts.fnSources ?? mapFnSources;
14599
15668
  const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
14600
15669
  const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
@@ -15116,6 +16185,7 @@ function rebuildCombinator(root, replacements) {
15116
16185
  return p;
15117
16186
  }
15118
16187
  out = d.type === void 0 ? d.build === void 0 ? node(one(d.parser), opts) : node(one(d.parser), d.build) : node(d.type, one(d.parser), d.build, opts);
16188
+ if (d.buildRawUnused === true && out._def.tag === "node") out._def.buildRawUnused = true;
15119
16189
  break;
15120
16190
  }
15121
16191
  case "grammar": {