parseman 0.61.3 → 0.61.5

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 (45) hide show
  1. package/dist/analysis/diagnostics.js +844 -522
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +846 -522
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/cst/capture-buffer.d.ts +3 -2
  6. package/dist/cst/capture-buffer.d.ts.map +1 -1
  7. package/dist/index.js +846 -520
  8. package/dist/index.js.map +3 -3
  9. package/dist/plugin/index.d.ts +22 -3
  10. package/dist/plugin/index.d.ts.map +1 -1
  11. package/dist/plugin/index.js +872 -520
  12. package/dist/plugin/index.js.map +3 -3
  13. package/dist/table/assemble.d.ts.map +1 -1
  14. package/dist/table/child-slots.d.ts.map +1 -1
  15. package/dist/table/emit-assembly.d.ts +1 -1
  16. package/dist/table/emit-assembly.d.ts.map +1 -1
  17. package/dist/table/encode.d.ts.map +1 -1
  18. package/dist/table/exec.d.ts.map +1 -1
  19. package/dist/table/fail-clean.d.ts.map +1 -1
  20. package/dist/table/hold-gap.d.ts.map +1 -1
  21. package/dist/table/index.js +368 -42
  22. package/dist/table/index.js.map +3 -3
  23. package/dist/table/late-frame.d.ts +18 -0
  24. package/dist/table/late-frame.d.ts.map +1 -0
  25. package/dist/table/ops.d.ts +17 -0
  26. package/dist/table/ops.d.ts.map +1 -1
  27. package/dist/table/select-hot.d.ts.map +1 -1
  28. package/dist/table/site-labels.d.ts +5 -1
  29. package/dist/table/site-labels.d.ts.map +1 -1
  30. package/dist/version.d.ts +1 -1
  31. package/package.json +1 -1
  32. package/src/cst/capture-buffer.ts +20 -11
  33. package/src/plugin/index.ts +76 -23
  34. package/src/table/assemble.ts +124 -4
  35. package/src/table/child-slots.ts +9 -1
  36. package/src/table/emit-assembly.ts +101 -14
  37. package/src/table/encode.ts +69 -6
  38. package/src/table/exec.ts +7 -1
  39. package/src/table/fail-clean.ts +8 -1
  40. package/src/table/hold-gap.ts +5 -1
  41. package/src/table/late-frame.ts +54 -0
  42. package/src/table/ops.ts +19 -0
  43. package/src/table/select-hot.ts +7 -1
  44. package/src/table/site-labels.ts +38 -14
  45. package/src/version.ts +1 -1
@@ -753,26 +753,34 @@ function popCstChild(ctx) {
753
753
  const b = ctx._cstBuf;
754
754
  if (b) {
755
755
  const ch2 = b.ch;
756
- if (b.rawOnly !== true && ch2) {
757
- ch2.pop();
758
- if (ch2.length === 1) {
759
- b.single = ch2[0];
760
- b.ch = void 0;
761
- }
756
+ if (b.rawOnly !== true) {
757
+ if (ch2) {
758
+ ch2.pop();
759
+ if (ch2.length === 1) {
760
+ b.single = ch2[0];
761
+ b.ch = void 0;
762
+ }
763
+ } else b.single = void 0;
762
764
  }
763
- if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1;
764
- else if (b.raw) {
765
- b.raw.pop();
765
+ if (b.noRaw === true) {
766
+ b.rawLen = (b.rawLen ?? 1) - 1;
767
+ return void 0;
768
+ }
769
+ if (b.raw) {
770
+ const entry2 = b.raw.pop();
766
771
  if (b.raw.length === 1) {
767
772
  b.rawSingle = b.raw[0];
768
773
  b.raw = void 0;
769
774
  }
770
- } else b.rawSingle = void 0;
771
- return;
775
+ return entry2;
776
+ }
777
+ const entry = b.rawSingle;
778
+ b.rawSingle = void 0;
779
+ return entry;
772
780
  }
773
781
  if (ctx._cstChildren) ctx._cstChildren.pop();
774
782
  else if (ctx._cstLeaves) ctx._cstLeaves.pop();
775
- if (ctx._cstRawChildren) ctx._cstRawChildren.pop();
783
+ return ctx._cstRawChildren?.pop();
776
784
  }
777
785
  function cstRawLen(ctx) {
778
786
  const b = ctx._cstBuf;
@@ -5622,7 +5630,7 @@ function sourceLeaf(root, fn) {
5622
5630
  }
5623
5631
 
5624
5632
  // src/version.ts
5625
- var PARSEMAN_VERSION = "0.61.3";
5633
+ var PARSEMAN_VERSION = "0.61.5";
5626
5634
 
5627
5635
  // src/table/lex-body.ts
5628
5636
  function buildLexBodyRecognizer(spec, constants) {
@@ -7201,6 +7209,8 @@ var OP_RGATE = 45;
7201
7209
  var OP_GAPGATE = 46;
7202
7210
  var OP_RGATE2 = 47;
7203
7211
  var OP_STRICT = 48;
7212
+ var OP_CONT = 49;
7213
+ var OP_SEED = 50;
7204
7214
  var OP_DISPATCH = 25;
7205
7215
  var OP_ROUTED = 26;
7206
7216
  var OP_NAMES = {
@@ -7251,7 +7261,9 @@ var OP_NAMES = {
7251
7261
  [OP_LEX_PROGRAM]: "LEX_PROGRAM",
7252
7262
  [OP_GAPGATE]: "GAPGATE",
7253
7263
  [OP_RGATE2]: "RGATE2",
7254
- [OP_STRICT]: "STRICT"
7264
+ [OP_STRICT]: "STRICT",
7265
+ [OP_CONT]: "CONT",
7266
+ [OP_SEED]: "SEED"
7255
7267
  };
7256
7268
 
7257
7269
  // src/compiler/direct-projection.ts
@@ -7633,81 +7645,432 @@ function balancedSpecOf(parser2) {
7633
7645
  return spec;
7634
7646
  }
7635
7647
 
7636
- // src/table/encode.ts
7637
- function emittableConst(v) {
7638
- const scalar = (x) => x === null || typeof x === "string" || typeof x === "number" || typeof x === "boolean";
7639
- if (scalar(v) || v instanceof RegExp) return true;
7640
- if (Array.isArray(v)) return v.every(scalar);
7641
- if (typeof v === "object" && v !== null) {
7642
- const proto = Object.getPrototypeOf(v);
7643
- if (proto !== Object.prototype && proto !== null) return false;
7644
- return Object.values(v).every((x) => scalar(x) || Array.isArray(x) && x.every(scalar));
7648
+ // src/table/child-slots.ts
7649
+ function childSlots(code, ip, out) {
7650
+ const from = out.length;
7651
+ if (!childSlotOffsets(code, ip, out)) return false;
7652
+ for (let i = from; i < out.length; i++) out[i] = code[out[i]];
7653
+ return true;
7654
+ }
7655
+ function childSlotOffsets(code, ip, out) {
7656
+ switch (code[ip]) {
7657
+ // ZERO-WIDTH / TERMINAL ROWS — no successor. `OP_GUARD` and `OP_ADJ` are both
7658
+ // childless tests. `OP_LIVE` holds a hand-written combinator in `prog.fns`; its
7659
+ // structure is a closure, so there is no successor row to reach.
7660
+ case OP_LIT:
7661
+ case OP_RX:
7662
+ case OP_LIT_TRACK:
7663
+ case OP_RX_TRACK:
7664
+ case OP_EMPTY:
7665
+ case OP_SCAN:
7666
+ case OP_LIT_CI:
7667
+ case OP_LIT_CI_TRACK:
7668
+ case OP_GUARD:
7669
+ case OP_ADJ:
7670
+ case OP_LIVE:
7671
+ case OP_LEX_BODY:
7672
+ case OP_LEX_PROGRAM:
7673
+ return true;
7674
+ // Single child at `ip + 1`. `OP_COV` is a wrapper on the same footing as the
7675
+ // rest — a coverage-encoded program is a program, and omitting it made
7676
+ // `opHistogram` throw on every table the coverage build produces.
7677
+ case OP_RULE:
7678
+ case OP_OPT:
7679
+ case OP_NOT:
7680
+ case OP_PEEK:
7681
+ case OP_EXPECT:
7682
+ case OP_TOKEN:
7683
+ case OP_ATTEMPT:
7684
+ case OP_LABEL:
7685
+ case OP_COV:
7686
+ case OP_REJECT:
7687
+ case OP_GAPGATE:
7688
+ out.push(ip + 1);
7689
+ return true;
7690
+ // Single child at `ip + 2`.
7691
+ case OP_GATE:
7692
+ case OP_SCOPE:
7693
+ case OP_SCOPE_CAP:
7694
+ case OP_SCOPE_PLAIN:
7695
+ case OP_WITHCTX:
7696
+ case OP_XFORM:
7697
+ case OP_NODE:
7698
+ case OP_NODE_TRACK:
7699
+ case OP_FIELD:
7700
+ case OP_LEAF:
7701
+ case OP_SOURCE_LEAF:
7702
+ case OP_ARMGATE:
7703
+ case OP_RGATE:
7704
+ case OP_RGATE2:
7705
+ out.push(ip + 2);
7706
+ return true;
7707
+ // `CONT corner wrapper tail`: `tail` is reached through `wrapper`.
7708
+ case OP_CONT:
7709
+ out.push(ip + 1, ip + 2);
7710
+ return true;
7711
+ case OP_SEED:
7712
+ out.push(ip + 1);
7713
+ return true;
7714
+ // `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
7715
+ case OP_STRICT:
7716
+ out.push(ip + 1, ip + 2);
7717
+ return true;
7718
+ // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
7719
+ // data the enclosing `dispatch()` already consumed, so the only edge is the
7720
+ // fallback.
7721
+ case OP_ROUTED:
7722
+ if (code[ip + 1] >= 0) out.push(ip + 1);
7723
+ return true;
7724
+ // `DISPATCH sel d other otherRouted n a1 … an` — the SELECTOR is a child on
7725
+ // exactly the same footing as the arms: it runs inside whatever node and scope
7726
+ // this site sits in.
7727
+ case OP_DISPATCH: {
7728
+ out.push(ip + 1);
7729
+ if (code[ip + 3] >= 0) out.push(ip + 3);
7730
+ const n = code[ip + 5];
7731
+ for (let i = 0; i < n; i++) out.push(ip + 6 + i);
7732
+ return true;
7733
+ }
7734
+ case OP_SEQ:
7735
+ case OP_SEQV: {
7736
+ const n = code[ip + 1];
7737
+ for (let i = 0; i < n; i++) out.push(ip + 2 + i);
7738
+ return true;
7739
+ }
7740
+ case OP_SEQX: {
7741
+ const n = code[ip + 2];
7742
+ for (let i = 0; i < n; i++) out.push(ip + 3 + i);
7743
+ return true;
7744
+ }
7745
+ case OP_CHOICE: {
7746
+ const n = code[ip + 2];
7747
+ for (let i = 0; i < n; i++) out.push(ip + 4 + i);
7748
+ return true;
7749
+ }
7750
+ // Arms are stride-2 from `ip + 4` — the gate word sits beside each arm offset.
7751
+ case OP_GREEDY: {
7752
+ out.push(ip + 1);
7753
+ const n = code[ip + 2];
7754
+ for (let i = 0; i < n; i++) out.push(ip + 4 + 2 * i);
7755
+ return true;
7756
+ }
7757
+ case OP_REP:
7758
+ case OP_REPV:
7759
+ out.push(ip + 1);
7760
+ if (code[ip + 4] >= 0) out.push(ip + 4);
7761
+ return true;
7762
+ default:
7763
+ return false;
7645
7764
  }
7646
- return false;
7647
7765
  }
7648
- var UnsupportedConstruct = class extends Error {
7649
- tag;
7650
- constructor(tag) {
7651
- super(`table lowering: no opcode for '${tag}'`);
7652
- this.tag = tag;
7766
+
7767
+ // src/table/site-labels.ts
7768
+ var TRI_UNKNOWN = -2;
7769
+ var TRI_NONE = -1;
7770
+ var CAP_UNKNOWN = 0;
7771
+ var CAP_OFF = 1;
7772
+ var CAP_ON = 2;
7773
+ var RAW_UNKNOWN = 0;
7774
+ var RAW_CAPTURE = 1;
7775
+ var RAW_OMIT = 2;
7776
+ var TOP = { tri: TRI_UNKNOWN, buf: false, raw: RAW_UNKNOWN, cap: CAP_UNKNOWN };
7777
+ function meet(a, b) {
7778
+ const tri = a.tri === b.tri ? a.tri : TRI_UNKNOWN;
7779
+ const buf = a.buf && b.buf;
7780
+ const raw = a.raw === b.raw ? a.raw : RAW_UNKNOWN;
7781
+ const cap = a.cap === b.cap ? a.cap : CAP_UNKNOWN;
7782
+ if (tri === a.tri && buf === a.buf && raw === a.raw && cap === a.cap) return a;
7783
+ return { tri, buf, raw, cap };
7784
+ }
7785
+ function reachableSites(code, roots) {
7786
+ const seen = /* @__PURE__ */ new Set();
7787
+ const stack = [...roots];
7788
+ const kids = [];
7789
+ while (stack.length > 0) {
7790
+ const ip = stack.pop();
7791
+ if (seen.has(ip)) continue;
7792
+ seen.add(ip);
7793
+ kids.length = 0;
7794
+ childSlots(code, ip, kids);
7795
+ for (const c of kids) stack.push(c);
7653
7796
  }
7654
- };
7655
- function firstTwo(p) {
7656
- const d = p._def;
7657
- if (d.tag === "label" || d.tag === "grammar") return firstTwo(d.parser);
7658
- let two;
7659
- if (d.tag === "literal" && d.value.length >= 2 && d.caseInsensitive !== true) {
7660
- const second = d.value.codePointAt(1);
7661
- two = { first: { kind: "ranges", ranges: [{ lo: d.value.charCodeAt(0), hi: d.value.charCodeAt(0) }] }, second: { kind: "ranges", ranges: [{ lo: second, hi: second }] } };
7662
- } else if (d.tag === "regex" && !d.flags.includes("i")) {
7663
- const units = regexFirstTwo(d.source, d.flags);
7664
- if (units !== void 0) two = units;
7797
+ return seen;
7798
+ }
7799
+ function passCollapse(code, ip, hostCst) {
7800
+ const flags = code[ip + 3];
7801
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
7802
+ if (flags !== 32 && flags !== 34) return false;
7803
+ let at = code[ip + 2];
7804
+ for (let n = 0; n < 8; n++) {
7805
+ const op = code[at];
7806
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
7807
+ else if (op === OP_RULE) at = code[at + 1];
7808
+ else break;
7665
7809
  }
7666
- if (two === void 0 || two.first.kind !== "ranges") return void 0;
7667
- return two.first.ranges.every((r) => r.hi < 55296 || r.lo > 57343 && r.hi <= 65535) ? two : void 0;
7810
+ return code[at] === OP_NODE || code[at] === OP_CONT;
7668
7811
  }
7669
- var GAP_CHARS = /* @__PURE__ */ new Set([9, 10, 12, 13, 32, 47]);
7670
- function isGap(p) {
7671
- if (matchesEmpty(p)) return true;
7672
- const fs3 = p._meta.firstSet;
7673
- return fs3.kind === "ranges" && fs3.ranges.every((r) => {
7674
- for (let c = r.lo; c <= r.hi; c++) if (!GAP_CHARS.has(c)) return false;
7675
- return true;
7676
- });
7812
+ function gatedPassCollapse(code, ip, hostCst) {
7813
+ const flags = code[ip + 3];
7814
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
7815
+ if (flags !== 32 && flags !== 34) return void 0;
7816
+ const seq = code[ip + 2];
7817
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
7818
+ const n = code[seq + 1];
7819
+ if (n < 2) return void 0;
7820
+ const leads = [];
7821
+ const lits = [];
7822
+ for (let i = 0; i < n - 1; i++) {
7823
+ const t = code[seq + 2 + i];
7824
+ if (code[t] !== OP_OPT && code[t] !== OP_NOT) return void 0;
7825
+ const g = code[t + 1];
7826
+ if (code[g] === OP_GATE) leads.push(g);
7827
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
7828
+ else return void 0;
7829
+ }
7830
+ const last = code[seq + 2 + n - 1];
7831
+ let at = last;
7832
+ for (let k = 0; k < 8 && (code[at] === OP_GATE || code[at] === OP_RULE); k++) at = code[at] === OP_RULE ? code[at + 1] : code[at + 2];
7833
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
7677
7834
  }
7678
- var Encoder = class {
7679
- code = [];
7680
- k = [];
7681
- fns = [];
7682
- /**
7683
- * SOURCE TEXT per `fns` entry, or `null` where the author's callback reached
7684
- * the encoder as a live closure with no source (the runtime path).
7685
- *
7686
- * Parallel to `fns`, in the same order, because that is the order the emitters
7687
- * print `f:[…]` in. Without it a macro build has no way to print an author
7688
- * reducer at all: `emitTableModule` falls back to `() => {}` per entry, which
7689
- * produces a module that LOADS and returns the wrong tree — the exact class of
7690
- * failure that a `null` return from `compileRuleMap` (its `mfCovered &&
7691
- * buildCovered` gate) exists to prevent on the source-lowering side. The table
7692
- * counterpart cannot honour that same all-or-nothing contract without this.
7693
- *
7694
- * NOT part of `TableProgram`: it is build-time metadata for the printer, never
7695
- * data the driver reads, and it must not travel in an emitted artifact.
7696
- */
7697
- fnSrcs = [];
7698
- cc = [];
7699
- fx = [];
7700
- disp = [];
7701
- dsp = [];
7702
- lex = [];
7703
- lexIndex = /* @__PURE__ */ new Map();
7704
- lexPrograms = [];
7705
- lexProgramIndex = /* @__PURE__ */ new Map();
7706
- choiceRollbackMasks = /* @__PURE__ */ new Map();
7707
- nonCommittingChoiceSites = /* @__PURE__ */ new Set();
7708
- failureRollbackCleanSites = /* @__PURE__ */ new Set();
7709
- /**
7710
- * THE TRIVIA LOGS A FAILED NODE LEAVES. A node drops its own capture frame when
7835
+ function transfer(code, ip, at, hostCst) {
7836
+ const op = code[ip];
7837
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
7838
+ const ki = code[ip + 1];
7839
+ const tri = ki === SCOPE_INHERIT ? at.tri : ki < 0 ? TRI_NONE : ki;
7840
+ const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
7841
+ if (tri === at.tri && cap === at.cap) return at;
7842
+ return { tri, buf: at.buf, raw: at.raw, cap };
7843
+ }
7844
+ if (op === OP_NODE || op === OP_NODE_TRACK) {
7845
+ const flags = code[ip + 3];
7846
+ if (passCollapse(code, ip, hostCst)) return at;
7847
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
7848
+ const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
7849
+ if (directChildren) {
7850
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
7851
+ return gated ? meet(at, framed2) : framed2;
7852
+ }
7853
+ const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
7854
+ const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
7855
+ if (at.buf && raw === at.raw && cap === at.cap) return at;
7856
+ const framed = { tri: at.tri, buf: true, raw, cap };
7857
+ return gated ? meet(at, framed) : framed;
7858
+ }
7859
+ if (op === OP_TOKEN) {
7860
+ if (at.tri === TRI_NONE && !at.buf) return at;
7861
+ return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
7862
+ }
7863
+ if (op === OP_LEAF || op === OP_SOURCE_LEAF) {
7864
+ if (!at.buf) return at;
7865
+ return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
7866
+ }
7867
+ return at;
7868
+ }
7869
+ function computeSiteLabels(code, roots, hostCst, late) {
7870
+ const labels = /* @__PURE__ */ new Map();
7871
+ const work = [];
7872
+ const push = (ip, l) => {
7873
+ const cur = labels.get(ip);
7874
+ if (cur === void 0) {
7875
+ labels.set(ip, l);
7876
+ work.push(ip);
7877
+ return;
7878
+ }
7879
+ const next = meet(cur, l);
7880
+ if (next === cur) return;
7881
+ labels.set(ip, next);
7882
+ work.push(ip);
7883
+ };
7884
+ const opened = /* @__PURE__ */ new Set();
7885
+ const kids = [];
7886
+ const lateIps = /* @__PURE__ */ new Set();
7887
+ for (const r of roots) push(r, TOP);
7888
+ for (let pass = 0; pass < 2; pass++) {
7889
+ while (work.length > 0) {
7890
+ const ip = work.pop();
7891
+ const down = transfer(code, ip, labels.get(ip), hostCst);
7892
+ kids.length = 0;
7893
+ if (late === void 0 || code[ip] !== OP_SEED || opened.has(ip)) childSlots(code, ip, kids);
7894
+ for (const c of kids) push(c, down);
7895
+ }
7896
+ if (late === void 0 || pass === 1) break;
7897
+ for (const [ip, l] of [...labels]) {
7898
+ if (code[ip] !== OP_CONT) continue;
7899
+ if (late(ip, l.tri)) lateIps.add(ip);
7900
+ else {
7901
+ const seed = seedOf(code, ip);
7902
+ opened.add(seed);
7903
+ work.push(seed);
7904
+ }
7905
+ }
7906
+ }
7907
+ return { at: (ip) => labels.get(ip) ?? TOP, late: lateIps };
7908
+ }
7909
+ function seedOf(code, cont) {
7910
+ return code[code[code[cont + 2] + 2] + 2];
7911
+ }
7912
+ function scopeIsIdentity(code, ip, at) {
7913
+ const op = code[ip];
7914
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
7915
+ const ki = code[ip + 1];
7916
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
7917
+ }
7918
+ function scanHandoffNeeded(code, ip, labels) {
7919
+ const seen = /* @__PURE__ */ new Set();
7920
+ const stack = [ip];
7921
+ const kids = [];
7922
+ while (stack.length > 0) {
7923
+ const at = stack.pop();
7924
+ if (seen.has(at)) continue;
7925
+ seen.add(at);
7926
+ const l = labels.at(at);
7927
+ if (l.tri === TRI_UNKNOWN) return true;
7928
+ const op = code[at];
7929
+ if (op === OP_SCAN) return true;
7930
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP && code[at + 1] !== SCOPE_INHERIT) continue;
7931
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1] >= 0 && l.tri === code[at + 1] && (op === OP_SCOPE_PLAIN || code[at + 3] === 0))) continue;
7932
+ kids.length = 0;
7933
+ if (!childSlots(code, at, kids)) return true;
7934
+ for (const c of kids) stack.push(c);
7935
+ }
7936
+ return false;
7937
+ }
7938
+ function triviaLeadRanges(tri, trivia2) {
7939
+ if (tri === TRI_NONE) return [];
7940
+ if (tri < 0) return void 0;
7941
+ const fs3 = trivia2[tri]?._meta.firstSet;
7942
+ if (fs3 === void 0) return void 0;
7943
+ if (fs3.kind === "empty") return [];
7944
+ return fs3.kind === "ranges" && fs3.ranges !== void 0 ? leadRanges(fs3.ranges) : void 0;
7945
+ }
7946
+
7947
+ // src/table/late-frame.ts
7948
+ function continuationGate(code, ip) {
7949
+ let at = ip;
7950
+ for (let n = 0; n < 8; n++) {
7951
+ const op2 = code[at];
7952
+ if (op2 === OP_RULE) at = code[at + 1];
7953
+ else if (op2 === OP_WITHCTX) at = code[at + 2];
7954
+ else break;
7955
+ }
7956
+ const op = code[at];
7957
+ if (op === OP_OPT) {
7958
+ const c = code[at + 1];
7959
+ return code[c] === OP_GATE ? { cls: code[c + 1], gapRow: -1, follow: -1, other: -1 } : void 0;
7960
+ }
7961
+ if (op !== OP_REP && op !== OP_REPV) return void 0;
7962
+ if (code[at + 2] !== 0 || code[at + 4] >= 0 || code[at + 7] < 0) return void 0;
7963
+ const item = code[at + 1];
7964
+ return code[item] === OP_GAPGATE ? { cls: code[at + 7], gapRow: code[item + 2], follow: code[item + 3], other: code[item + 4] } : { cls: code[at + 7], gapRow: -1, follow: -1, other: -1 };
7965
+ }
7966
+ function canDecide(code, ip, tri, triviaScan) {
7967
+ if (tri !== TRI_NONE && (tri < 0 || triviaScan[tri] == null)) return false;
7968
+ return continuationGate(code, code[ip + 3]) !== void 0;
7969
+ }
7970
+
7971
+ // src/table/encode.ts
7972
+ function emittableConst(v) {
7973
+ const scalar = (x) => x === null || typeof x === "string" || typeof x === "number" || typeof x === "boolean";
7974
+ if (scalar(v) || v instanceof RegExp) return true;
7975
+ if (Array.isArray(v)) return v.every(scalar);
7976
+ if (typeof v === "object" && v !== null) {
7977
+ const proto = Object.getPrototypeOf(v);
7978
+ if (proto !== Object.prototype && proto !== null) return false;
7979
+ return Object.values(v).every((x) => scalar(x) || Array.isArray(x) && x.every(scalar));
7980
+ }
7981
+ return false;
7982
+ }
7983
+ var UnsupportedConstruct = class extends Error {
7984
+ tag;
7985
+ constructor(tag) {
7986
+ super(`table lowering: no opcode for '${tag}'`);
7987
+ this.tag = tag;
7988
+ }
7989
+ };
7990
+ function firstTwo(p) {
7991
+ const d = p._def;
7992
+ if (d.tag === "label" || d.tag === "grammar") return firstTwo(d.parser);
7993
+ let two;
7994
+ if (d.tag === "literal" && d.value.length >= 2 && d.caseInsensitive !== true) {
7995
+ const second = d.value.codePointAt(1);
7996
+ two = { first: { kind: "ranges", ranges: [{ lo: d.value.charCodeAt(0), hi: d.value.charCodeAt(0) }] }, second: { kind: "ranges", ranges: [{ lo: second, hi: second }] } };
7997
+ } else if (d.tag === "regex" && !d.flags.includes("i")) {
7998
+ const units = regexFirstTwo(d.source, d.flags);
7999
+ if (units !== void 0) two = units;
8000
+ }
8001
+ if (two === void 0 || two.first.kind !== "ranges") return void 0;
8002
+ return two.first.ranges.every((r) => r.hi < 55296 || r.lo > 57343 && r.hi <= 65535) ? two : void 0;
8003
+ }
8004
+ var GAP_CHARS = /* @__PURE__ */ new Set([9, 10, 12, 13, 32, 47]);
8005
+ function isGap(p) {
8006
+ if (matchesEmpty(p)) return true;
8007
+ const fs3 = p._meta.firstSet;
8008
+ return fs3.kind === "ranges" && fs3.ranges.every((r) => {
8009
+ for (let c = r.lo; c <= r.hi; c++) if (!GAP_CHARS.has(c)) return false;
8010
+ return true;
8011
+ });
8012
+ }
8013
+ function publishesOneNode(p, rr, seen = /* @__PURE__ */ new Set()) {
8014
+ if (seen.has(p)) return true;
8015
+ seen.add(p);
8016
+ const d = p._def;
8017
+ switch (d.tag) {
8018
+ case "node":
8019
+ return true;
8020
+ case "lazy": {
8021
+ let target = winnerForRef(p, rr);
8022
+ if (target === void 0) {
8023
+ try {
8024
+ target = d.thunk();
8025
+ } catch {
8026
+ return false;
8027
+ }
8028
+ }
8029
+ return publishesOneNode(target, rr, seen);
8030
+ }
8031
+ case "choice":
8032
+ return d.parsers.every((a) => publishesOneNode(a, rr, seen));
8033
+ case "grammar":
8034
+ case "withCtx":
8035
+ case "label":
8036
+ return publishesOneNode(d.parser, rr, seen);
8037
+ default:
8038
+ return false;
8039
+ }
8040
+ }
8041
+ var Encoder = class {
8042
+ code = [];
8043
+ k = [];
8044
+ fns = [];
8045
+ /**
8046
+ * SOURCE TEXT per `fns` entry, or `null` where the author's callback reached
8047
+ * the encoder as a live closure with no source (the runtime path).
8048
+ *
8049
+ * Parallel to `fns`, in the same order, because that is the order the emitters
8050
+ * print `f:[…]` in. Without it a macro build has no way to print an author
8051
+ * reducer at all: `emitTableModule` falls back to `() => {}` per entry, which
8052
+ * produces a module that LOADS and returns the wrong tree — the exact class of
8053
+ * failure that a `null` return from `compileRuleMap` (its `mfCovered &&
8054
+ * buildCovered` gate) exists to prevent on the source-lowering side. The table
8055
+ * counterpart cannot honour that same all-or-nothing contract without this.
8056
+ *
8057
+ * NOT part of `TableProgram`: it is build-time metadata for the printer, never
8058
+ * data the driver reads, and it must not travel in an emitted artifact.
8059
+ */
8060
+ fnSrcs = [];
8061
+ cc = [];
8062
+ fx = [];
8063
+ disp = [];
8064
+ dsp = [];
8065
+ lex = [];
8066
+ lexIndex = /* @__PURE__ */ new Map();
8067
+ lexPrograms = [];
8068
+ lexProgramIndex = /* @__PURE__ */ new Map();
8069
+ choiceRollbackMasks = /* @__PURE__ */ new Map();
8070
+ nonCommittingChoiceSites = /* @__PURE__ */ new Set();
8071
+ failureRollbackCleanSites = /* @__PURE__ */ new Set();
8072
+ /**
8073
+ * THE TRIVIA LOGS A FAILED NODE LEAVES. A node drops its own capture frame when
7711
8074
  * it fails, but the trivia its body recorded into `_triviaLog`/`_rootTriviaLog`
7712
8075
  * is not part of that frame. So a child the census above counts as clean can
7713
8076
  * still leave trivia rows when it reaches a node whose body can fail after a
@@ -9028,7 +9391,8 @@ var Encoder = class {
9028
9391
  }
9029
9392
  case "node": {
9030
9393
  if (d.type === void 0) missingInferredType();
9031
- const child = this.node(d.parser).ip;
9394
+ const late = this.opensLate(d);
9395
+ const child = late ? this.lateBody(d.parser._def) : this.node(d.parser).ip;
9032
9396
  const cstOut = this.settings.hostMode === "cst";
9033
9397
  const noBuildCaptures = d.project === void 0;
9034
9398
  const derivedTrivia = d.build !== void 0 ? buildReadsTrivia(d) : noBuildCaptures;
@@ -9049,13 +9413,19 @@ var Encoder = class {
9049
9413
  // every CST node, so this is load-bearing, not reflection trivia.
9050
9414
  d.tags === void 0 ? -1 : this.constant(d.tags)
9051
9415
  );
9052
- if (matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return body;
9416
+ let run2 = body;
9417
+ if (late) {
9418
+ const corner = this.code[this.code[child + 2] + 1];
9419
+ if (continuationGate(this.code, this.code[child + 3]) === void 0) this.code[child + 2] = corner;
9420
+ else run2 = this.emit(OP_CONT, corner, body, this.code[child + 3]);
9421
+ }
9422
+ if (matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return run2;
9053
9423
  const fs3 = this.gateFirstSet(d.parser, d.guarded === true, false);
9054
- if (fs3.kind === "any") return body;
9424
+ if (fs3.kind === "any") return run2;
9055
9425
  const cls = this.charClass(fs3);
9056
- if (cls < 0) return body;
9426
+ if (cls < 0) return run2;
9057
9427
  const e = deriveExpected(d.parser);
9058
- return this.emit(OP_GATE, cls, body, this.expected(e.length > 0 ? e : [d.parser._tag]));
9428
+ return this.emit(OP_GATE, cls, run2, this.expected(e.length > 0 ? e : [d.parser._tag]));
9059
9429
  }
9060
9430
  case "token": {
9061
9431
  const saved = this.activeTrivia;
@@ -9237,6 +9607,29 @@ var Encoder = class {
9237
9607
  throw new UnsupportedConstruct(d.tag);
9238
9608
  }
9239
9609
  }
9610
+ /**
9611
+ * `node(sequence(corner, tail), build, { collapse: true })` with a tail that can take
9612
+ * nothing and a corner that is one node: the frame can open after the corner, only if
9613
+ * the tail can start. Any other node keeps its frame from the start, and so does one
9614
+ * with no reducer, whose host can scope the corner's trivia to its type.
9615
+ */
9616
+ opensLate(d) {
9617
+ if (this.plan !== void 0 || d.collapse !== true || d.build === void 0 || d.trailingTrivia === true) return false;
9618
+ const seq = d.parser._def;
9619
+ return seq.tag === "sequence" && seq.parsers.length === 2 && matchesEmpty(seq.parsers[1], /* @__PURE__ */ new Set(), this.refResolver()) && publishesOneNode(seq.parsers[0], this.refResolver());
9620
+ }
9621
+ /** The body of a late frame: the sequence as written, its corner behind `OP_SEED`. */
9622
+ lateBody(seq) {
9623
+ const seed = this.emit(OP_SEED, this.node(seq.parsers[0]).ip);
9624
+ const tailIp = this.node(seq.parsers[1]).ip;
9625
+ const head = this.emitHead(seq.valueUnused ? OP_SEQV : OP_SEQ, 5);
9626
+ this.code[head + 1] = 2;
9627
+ this.code[head + 2] = seed;
9628
+ this.code[head + 3] = tailIp;
9629
+ this.code[head + 4] = this.followClass(seq.parsers, 0);
9630
+ this.code[head + 5] = this.followClass(seq.parsers, 1);
9631
+ return head;
9632
+ }
9240
9633
  /**
9241
9634
  * Peephole: an `OP_RULE` row is pure indirection — a switch dispatch and a
9242
9635
  * call frame to do nothing but jump. Rewrite every child slot that points at
@@ -9302,6 +9695,10 @@ var Encoder = class {
9302
9695
  return this.code[ip + 4] >= 0 ? [ip + 1, ip + 4] : [ip + 1];
9303
9696
  case OP_STRICT:
9304
9697
  return [ip + 1, ip + 2];
9698
+ case OP_CONT:
9699
+ return [ip + 1, ip + 2, ip + 3];
9700
+ case OP_SEED:
9701
+ return [ip + 1];
9305
9702
  default:
9306
9703
  return [];
9307
9704
  }
@@ -10300,408 +10697,133 @@ function emitShapeMatch(shape, start, mint, ind, firstChar) {
10300
10697
  lines2.push(`${ind} if (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
10301
10698
  }
10302
10699
  } else if (p.part === "run") {
10303
- const s = mint("_s");
10304
- lines2.push(`${ind} const ${s} = ${endV2}`);
10305
- lines2.push(`${ind} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
10306
- if (p.min > 0) lines2.push(`${ind} if (${endV2} - ${s} < ${p.min}) break`);
10307
- } else {
10308
- const inner = emitShapeMatch(p.inner, endV2, mint, `${ind} `, first ? firstChar : void 0);
10309
- if (!p.unbounded) {
10310
- lines2.push(...inner.setup);
10311
- if (p.min === 1) {
10312
- lines2.push(`${ind} if (!(${inner.ok})) break`);
10313
- lines2.push(`${ind} ${endV2} = ${inner.end}`);
10314
- } else {
10315
- lines2.push(`${ind} if (${inner.ok}) ${endV2} = ${inner.end}`);
10316
- }
10317
- } else {
10318
- const progV = mint("_prog");
10319
- lines2.push(`${ind} let ${progV} = false`);
10320
- lines2.push(`${ind} while (true) {`);
10321
- lines2.push(...inner.setup);
10322
- lines2.push(`${ind} if (!(${inner.ok})) break`);
10323
- lines2.push(`${ind} ${endV2} = ${inner.end}`);
10324
- lines2.push(`${ind} ${progV} = true`);
10325
- lines2.push(`${ind} }`);
10326
- if (p.min === 1) lines2.push(`${ind} if (!${progV}) break`);
10327
- }
10328
- }
10329
- first = false;
10330
- }
10331
- lines2.push(`${ind} ${okV} = true`);
10332
- lines2.push(`${ind}} while (false)`);
10333
- lines2.push(`${ind}if (!${okV}) ${endV2} = ${start}`);
10334
- return { setup: lines2, ok: okV, end: endV2 };
10335
- }
10336
- if (shape.kind === "litFold") {
10337
- const openLen2 = shape.open.length;
10338
- const endV2 = mint("_end");
10339
- const checks = shape.open.map((cp, k) => {
10340
- const cVar = k === 0 && firstChar ? firstChar : `input.charCodeAt(${start} + ${k})`;
10341
- return foldEq(cVar, cp);
10342
- });
10343
- return {
10344
- setup: [
10345
- `${ind}let ${endV2} = ${start}`,
10346
- `${ind}if (${start} + ${openLen2} <= input.length && (${checks.join(" && ")})) ${endV2} = ${start} + ${openLen2}`
10347
- ],
10348
- ok: `${endV2} > ${start}`,
10349
- end: endV2
10350
- };
10351
- }
10352
- if (shape.kind === "until") {
10353
- const j2 = mint("_j");
10354
- const openLen2 = shape.open.length;
10355
- const openChk2 = openLen2 === 1 ? `${codeAt(start, firstChar)} === ${shape.open[0]}` : litCond(start, shape.open, firstChar);
10356
- const scanLine = `${ind} while (${j2} < input.length && !(${classCond(`input.charCodeAt(${j2})`, shape.stop)})) ${j2}++`;
10357
- return {
10358
- setup: [
10359
- `${ind}let ${j2} = ${start}`,
10360
- `${ind}if (${start} + ${openLen2} <= input.length && (${openChk2})) {`,
10361
- `${ind} ${j2} = ${start} + ${openLen2}`,
10362
- scanLine,
10363
- `${ind}}`
10364
- ],
10365
- // An open-until-terminator always completes (stop char or EOF), so a matched
10366
- // open literal is a full match; `end === start` iff the open didn't match.
10367
- ok: `${j2} > ${start}`,
10368
- end: j2
10369
- };
10370
- }
10371
- if (shape.kind === "string") {
10372
- const okV = mint("_ok");
10373
- const endV2 = mint("_end");
10374
- const i = mint("_i");
10375
- const c2 = mint("_c");
10376
- const hard = stringHardStop(shape);
10377
- const ltLines = shape.escLineTerm ? [] : (() => {
10378
- const c3 = mint("_c");
10379
- return [
10380
- `${ind} const ${c3} = input.charCodeAt(${i} + 1)`,
10381
- `${ind} if (${LINE_TERMINATORS.map((t) => `${c3} === ${t}`).join(" || ")}) break`
10382
- ];
10383
- })();
10384
- return {
10385
- setup: [
10386
- `${ind}let ${okV} = false`,
10387
- `${ind}let ${endV2} = ${start}`,
10388
- `${ind}if (${start} < input.length && (${codeAt(start, firstChar)}) === ${shape.quote}) {`,
10389
- `${ind} let ${i} = ${start} + 1`,
10390
- `${ind} while (${i} < input.length) {`,
10391
- `${ind} const ${c2} = input.charCodeAt(${i})`,
10392
- `${ind} if (${c2} === ${shape.quote}) { ${okV} = true; ${endV2} = ${i} + 1; break }`,
10393
- `${ind} if (${c2} === ${BACKSLASH}) {`,
10394
- `${ind} if (${i} + 1 >= input.length) break`,
10395
- ...ltLines,
10396
- `${ind} ${i} += 2`,
10397
- `${ind} continue`,
10398
- `${ind} }`,
10399
- ...hard.length ? [`${ind} if (${classCond(c2, hard)}) break`] : [],
10400
- `${ind} ${i}++`,
10401
- `${ind} }`,
10402
- `${ind}}`
10403
- ],
10404
- ok: okV,
10405
- end: endV2
10406
- };
10407
- }
10408
- const j = mint("_j");
10409
- const endV = mint("_end");
10410
- const openLen = shape.open.length;
10411
- const closeLen = shape.close.length;
10412
- const openChk = openLen === 1 ? `${codeAt(start, firstChar)} === ${shape.open[0]}` : litCond(start, shape.open, firstChar);
10413
- const closeChk = litCond(j, shape.close);
10414
- const scanLines = [
10415
- `${ind} while (${j} + ${closeLen - 1} < input.length && !(${closeChk})) ${j}++`,
10416
- `${ind} if (${j} + ${closeLen} <= input.length && (${closeChk})) ${endV} = ${j} + ${closeLen}`
10417
- ];
10418
- return {
10419
- setup: [
10420
- `${ind}let ${j} = ${start}`,
10421
- `${ind}let ${endV} = ${start}`,
10422
- `${ind}if (${start} + ${openLen} <= input.length && (${openChk})) {`,
10423
- `${ind} ${j} = ${start} + ${openLen}`,
10424
- ...scanLines,
10425
- `${ind}}`
10426
- ],
10427
- ok: `${endV} > ${start}`,
10428
- end: endV
10429
- };
10430
- }
10431
-
10432
- // src/table/child-slots.ts
10433
- function childSlots(code, ip, out) {
10434
- const from = out.length;
10435
- if (!childSlotOffsets(code, ip, out)) return false;
10436
- for (let i = from; i < out.length; i++) out[i] = code[out[i]];
10437
- return true;
10438
- }
10439
- function childSlotOffsets(code, ip, out) {
10440
- switch (code[ip]) {
10441
- // ZERO-WIDTH / TERMINAL ROWS — no successor. `OP_GUARD` and `OP_ADJ` are both
10442
- // childless tests. `OP_LIVE` holds a hand-written combinator in `prog.fns`; its
10443
- // structure is a closure, so there is no successor row to reach.
10444
- case OP_LIT:
10445
- case OP_RX:
10446
- case OP_LIT_TRACK:
10447
- case OP_RX_TRACK:
10448
- case OP_EMPTY:
10449
- case OP_SCAN:
10450
- case OP_LIT_CI:
10451
- case OP_LIT_CI_TRACK:
10452
- case OP_GUARD:
10453
- case OP_ADJ:
10454
- case OP_LIVE:
10455
- case OP_LEX_BODY:
10456
- case OP_LEX_PROGRAM:
10457
- return true;
10458
- // Single child at `ip + 1`. `OP_COV` is a wrapper on the same footing as the
10459
- // rest — a coverage-encoded program is a program, and omitting it made
10460
- // `opHistogram` throw on every table the coverage build produces.
10461
- case OP_RULE:
10462
- case OP_OPT:
10463
- case OP_NOT:
10464
- case OP_PEEK:
10465
- case OP_EXPECT:
10466
- case OP_TOKEN:
10467
- case OP_ATTEMPT:
10468
- case OP_LABEL:
10469
- case OP_COV:
10470
- case OP_REJECT:
10471
- case OP_GAPGATE:
10472
- out.push(ip + 1);
10473
- return true;
10474
- // Single child at `ip + 2`.
10475
- case OP_GATE:
10476
- case OP_SCOPE:
10477
- case OP_SCOPE_CAP:
10478
- case OP_SCOPE_PLAIN:
10479
- case OP_WITHCTX:
10480
- case OP_XFORM:
10481
- case OP_NODE:
10482
- case OP_NODE_TRACK:
10483
- case OP_FIELD:
10484
- case OP_LEAF:
10485
- case OP_SOURCE_LEAF:
10486
- case OP_ARMGATE:
10487
- case OP_RGATE:
10488
- case OP_RGATE2:
10489
- out.push(ip + 2);
10490
- return true;
10491
- // `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
10492
- case OP_STRICT:
10493
- out.push(ip + 1, ip + 2);
10494
- return true;
10495
- // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
10496
- // data the enclosing `dispatch()` already consumed, so the only edge is the
10497
- // fallback.
10498
- case OP_ROUTED:
10499
- if (code[ip + 1] >= 0) out.push(ip + 1);
10500
- return true;
10501
- // `DISPATCH sel d other otherRouted n a1 … an` — the SELECTOR is a child on
10502
- // exactly the same footing as the arms: it runs inside whatever node and scope
10503
- // this site sits in.
10504
- case OP_DISPATCH: {
10505
- out.push(ip + 1);
10506
- if (code[ip + 3] >= 0) out.push(ip + 3);
10507
- const n = code[ip + 5];
10508
- for (let i = 0; i < n; i++) out.push(ip + 6 + i);
10509
- return true;
10510
- }
10511
- case OP_SEQ:
10512
- case OP_SEQV: {
10513
- const n = code[ip + 1];
10514
- for (let i = 0; i < n; i++) out.push(ip + 2 + i);
10515
- return true;
10516
- }
10517
- case OP_SEQX: {
10518
- const n = code[ip + 2];
10519
- for (let i = 0; i < n; i++) out.push(ip + 3 + i);
10520
- return true;
10521
- }
10522
- case OP_CHOICE: {
10523
- const n = code[ip + 2];
10524
- for (let i = 0; i < n; i++) out.push(ip + 4 + i);
10525
- return true;
10526
- }
10527
- // Arms are stride-2 from `ip + 4` — the gate word sits beside each arm offset.
10528
- case OP_GREEDY: {
10529
- out.push(ip + 1);
10530
- const n = code[ip + 2];
10531
- for (let i = 0; i < n; i++) out.push(ip + 4 + 2 * i);
10532
- return true;
10533
- }
10534
- case OP_REP:
10535
- case OP_REPV:
10536
- out.push(ip + 1);
10537
- if (code[ip + 4] >= 0) out.push(ip + 4);
10538
- return true;
10539
- default:
10540
- return false;
10541
- }
10542
- }
10543
-
10544
- // src/table/site-labels.ts
10545
- var TRI_UNKNOWN = -2;
10546
- var TRI_NONE = -1;
10547
- var CAP_UNKNOWN = 0;
10548
- var CAP_OFF = 1;
10549
- var CAP_ON = 2;
10550
- var RAW_UNKNOWN = 0;
10551
- var RAW_CAPTURE = 1;
10552
- var RAW_OMIT = 2;
10553
- var TOP = { tri: TRI_UNKNOWN, buf: false, raw: RAW_UNKNOWN, cap: CAP_UNKNOWN };
10554
- function meet(a, b) {
10555
- const tri = a.tri === b.tri ? a.tri : TRI_UNKNOWN;
10556
- const buf = a.buf && b.buf;
10557
- const raw = a.raw === b.raw ? a.raw : RAW_UNKNOWN;
10558
- const cap = a.cap === b.cap ? a.cap : CAP_UNKNOWN;
10559
- if (tri === a.tri && buf === a.buf && raw === a.raw && cap === a.cap) return a;
10560
- return { tri, buf, raw, cap };
10561
- }
10562
- function reachableSites(code, roots) {
10563
- const seen = /* @__PURE__ */ new Set();
10564
- const stack = [...roots];
10565
- const kids = [];
10566
- while (stack.length > 0) {
10567
- const ip = stack.pop();
10568
- if (seen.has(ip)) continue;
10569
- seen.add(ip);
10570
- kids.length = 0;
10571
- childSlots(code, ip, kids);
10572
- for (const c of kids) stack.push(c);
10573
- }
10574
- return seen;
10575
- }
10576
- function passCollapse(code, ip, hostCst) {
10577
- const flags = code[ip + 3];
10578
- if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
10579
- if (flags !== 32 && flags !== 34) return false;
10580
- let at = code[ip + 2];
10581
- for (let n = 0; n < 8; n++) {
10582
- const op = code[at];
10583
- if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
10584
- else if (op === OP_RULE) at = code[at + 1];
10585
- else break;
10586
- }
10587
- return code[at] === OP_NODE;
10588
- }
10589
- function gatedPassCollapse(code, ip, hostCst) {
10590
- const flags = code[ip + 3];
10591
- if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
10592
- if (flags !== 32 && flags !== 34) return void 0;
10593
- const seq = code[ip + 2];
10594
- if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
10595
- const n = code[seq + 1];
10596
- if (n < 2) return void 0;
10597
- const leads = [];
10598
- const lits = [];
10599
- for (let i = 0; i < n - 1; i++) {
10600
- const t = code[seq + 2 + i];
10601
- if (code[t] !== OP_OPT && code[t] !== OP_NOT) return void 0;
10602
- const g = code[t + 1];
10603
- if (code[g] === OP_GATE) leads.push(g);
10604
- else if (code[g] === OP_LIT) lits.push(code[g + 1]);
10605
- else return void 0;
10606
- }
10607
- const last = code[seq + 2 + n - 1];
10608
- let at = last;
10609
- for (let k = 0; k < 8 && (code[at] === OP_GATE || code[at] === OP_RULE); k++) at = code[at] === OP_RULE ? code[at + 1] : code[at + 2];
10610
- return code[at] === OP_NODE ? { leads, lits, last } : void 0;
10611
- }
10612
- function transfer(code, ip, at, hostCst) {
10613
- const op = code[ip];
10614
- if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
10615
- const ki = code[ip + 1];
10616
- const tri = ki === SCOPE_INHERIT ? at.tri : ki < 0 ? TRI_NONE : ki;
10617
- const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
10618
- if (tri === at.tri && cap === at.cap) return at;
10619
- return { tri, buf: at.buf, raw: at.raw, cap };
10620
- }
10621
- if (op === OP_NODE || op === OP_NODE_TRACK) {
10622
- const flags = code[ip + 3];
10623
- if (passCollapse(code, ip, hostCst)) return at;
10624
- const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
10625
- const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
10626
- if (directChildren) {
10627
- const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
10628
- return gated ? meet(at, framed2) : framed2;
10700
+ const s = mint("_s");
10701
+ lines2.push(`${ind} const ${s} = ${endV2}`);
10702
+ lines2.push(`${ind} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
10703
+ if (p.min > 0) lines2.push(`${ind} if (${endV2} - ${s} < ${p.min}) break`);
10704
+ } else {
10705
+ const inner = emitShapeMatch(p.inner, endV2, mint, `${ind} `, first ? firstChar : void 0);
10706
+ if (!p.unbounded) {
10707
+ lines2.push(...inner.setup);
10708
+ if (p.min === 1) {
10709
+ lines2.push(`${ind} if (!(${inner.ok})) break`);
10710
+ lines2.push(`${ind} ${endV2} = ${inner.end}`);
10711
+ } else {
10712
+ lines2.push(`${ind} if (${inner.ok}) ${endV2} = ${inner.end}`);
10713
+ }
10714
+ } else {
10715
+ const progV = mint("_prog");
10716
+ lines2.push(`${ind} let ${progV} = false`);
10717
+ lines2.push(`${ind} while (true) {`);
10718
+ lines2.push(...inner.setup);
10719
+ lines2.push(`${ind} if (!(${inner.ok})) break`);
10720
+ lines2.push(`${ind} ${endV2} = ${inner.end}`);
10721
+ lines2.push(`${ind} ${progV} = true`);
10722
+ lines2.push(`${ind} }`);
10723
+ if (p.min === 1) lines2.push(`${ind} if (!${progV}) break`);
10724
+ }
10725
+ }
10726
+ first = false;
10629
10727
  }
10630
- const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
10631
- const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
10632
- if (at.buf && raw === at.raw && cap === at.cap) return at;
10633
- const framed = { tri: at.tri, buf: true, raw, cap };
10634
- return gated ? meet(at, framed) : framed;
10635
- }
10636
- if (op === OP_TOKEN) {
10637
- if (at.tri === TRI_NONE && !at.buf) return at;
10638
- return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
10728
+ lines2.push(`${ind} ${okV} = true`);
10729
+ lines2.push(`${ind}} while (false)`);
10730
+ lines2.push(`${ind}if (!${okV}) ${endV2} = ${start}`);
10731
+ return { setup: lines2, ok: okV, end: endV2 };
10639
10732
  }
10640
- if (op === OP_LEAF || op === OP_SOURCE_LEAF) {
10641
- if (!at.buf) return at;
10642
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
10733
+ if (shape.kind === "litFold") {
10734
+ const openLen2 = shape.open.length;
10735
+ const endV2 = mint("_end");
10736
+ const checks = shape.open.map((cp, k) => {
10737
+ const cVar = k === 0 && firstChar ? firstChar : `input.charCodeAt(${start} + ${k})`;
10738
+ return foldEq(cVar, cp);
10739
+ });
10740
+ return {
10741
+ setup: [
10742
+ `${ind}let ${endV2} = ${start}`,
10743
+ `${ind}if (${start} + ${openLen2} <= input.length && (${checks.join(" && ")})) ${endV2} = ${start} + ${openLen2}`
10744
+ ],
10745
+ ok: `${endV2} > ${start}`,
10746
+ end: endV2
10747
+ };
10643
10748
  }
10644
- return at;
10645
- }
10646
- function computeSiteLabels(code, roots, hostCst) {
10647
- const labels = /* @__PURE__ */ new Map();
10648
- const work = [];
10649
- const push = (ip, l) => {
10650
- const cur = labels.get(ip);
10651
- if (cur === void 0) {
10652
- labels.set(ip, l);
10653
- work.push(ip);
10654
- return;
10655
- }
10656
- const next = meet(cur, l);
10657
- if (next === cur) return;
10658
- labels.set(ip, next);
10659
- work.push(ip);
10660
- };
10661
- for (const r of roots) push(r, TOP);
10662
- const kids = [];
10663
- while (work.length > 0) {
10664
- const ip = work.pop();
10665
- const down = transfer(code, ip, labels.get(ip), hostCst);
10666
- kids.length = 0;
10667
- childSlots(code, ip, kids);
10668
- for (const c of kids) push(c, down);
10749
+ if (shape.kind === "until") {
10750
+ const j2 = mint("_j");
10751
+ const openLen2 = shape.open.length;
10752
+ const openChk2 = openLen2 === 1 ? `${codeAt(start, firstChar)} === ${shape.open[0]}` : litCond(start, shape.open, firstChar);
10753
+ const scanLine = `${ind} while (${j2} < input.length && !(${classCond(`input.charCodeAt(${j2})`, shape.stop)})) ${j2}++`;
10754
+ return {
10755
+ setup: [
10756
+ `${ind}let ${j2} = ${start}`,
10757
+ `${ind}if (${start} + ${openLen2} <= input.length && (${openChk2})) {`,
10758
+ `${ind} ${j2} = ${start} + ${openLen2}`,
10759
+ scanLine,
10760
+ `${ind}}`
10761
+ ],
10762
+ // An open-until-terminator always completes (stop char or EOF), so a matched
10763
+ // open literal is a full match; `end === start` iff the open didn't match.
10764
+ ok: `${j2} > ${start}`,
10765
+ end: j2
10766
+ };
10669
10767
  }
10670
- return { at: (ip) => labels.get(ip) ?? TOP };
10671
- }
10672
- function scopeIsIdentity(code, ip, at) {
10673
- const op = code[ip];
10674
- if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
10675
- const ki = code[ip + 1];
10676
- return at.tri === (ki < 0 ? TRI_NONE : ki);
10677
- }
10678
- function scanHandoffNeeded(code, ip, labels) {
10679
- const seen = /* @__PURE__ */ new Set();
10680
- const stack = [ip];
10681
- const kids = [];
10682
- while (stack.length > 0) {
10683
- const at = stack.pop();
10684
- if (seen.has(at)) continue;
10685
- seen.add(at);
10686
- const l = labels.at(at);
10687
- if (l.tri === TRI_UNKNOWN) return true;
10688
- const op = code[at];
10689
- if (op === OP_SCAN) return true;
10690
- if (op === OP_TOKEN || op === OP_SCOPE_CAP && code[at + 1] !== SCOPE_INHERIT) continue;
10691
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1] >= 0 && l.tri === code[at + 1] && (op === OP_SCOPE_PLAIN || code[at + 3] === 0))) continue;
10692
- kids.length = 0;
10693
- if (!childSlots(code, at, kids)) return true;
10694
- for (const c of kids) stack.push(c);
10768
+ if (shape.kind === "string") {
10769
+ const okV = mint("_ok");
10770
+ const endV2 = mint("_end");
10771
+ const i = mint("_i");
10772
+ const c2 = mint("_c");
10773
+ const hard = stringHardStop(shape);
10774
+ const ltLines = shape.escLineTerm ? [] : (() => {
10775
+ const c3 = mint("_c");
10776
+ return [
10777
+ `${ind} const ${c3} = input.charCodeAt(${i} + 1)`,
10778
+ `${ind} if (${LINE_TERMINATORS.map((t) => `${c3} === ${t}`).join(" || ")}) break`
10779
+ ];
10780
+ })();
10781
+ return {
10782
+ setup: [
10783
+ `${ind}let ${okV} = false`,
10784
+ `${ind}let ${endV2} = ${start}`,
10785
+ `${ind}if (${start} < input.length && (${codeAt(start, firstChar)}) === ${shape.quote}) {`,
10786
+ `${ind} let ${i} = ${start} + 1`,
10787
+ `${ind} while (${i} < input.length) {`,
10788
+ `${ind} const ${c2} = input.charCodeAt(${i})`,
10789
+ `${ind} if (${c2} === ${shape.quote}) { ${okV} = true; ${endV2} = ${i} + 1; break }`,
10790
+ `${ind} if (${c2} === ${BACKSLASH}) {`,
10791
+ `${ind} if (${i} + 1 >= input.length) break`,
10792
+ ...ltLines,
10793
+ `${ind} ${i} += 2`,
10794
+ `${ind} continue`,
10795
+ `${ind} }`,
10796
+ ...hard.length ? [`${ind} if (${classCond(c2, hard)}) break`] : [],
10797
+ `${ind} ${i}++`,
10798
+ `${ind} }`,
10799
+ `${ind}}`
10800
+ ],
10801
+ ok: okV,
10802
+ end: endV2
10803
+ };
10695
10804
  }
10696
- return false;
10697
- }
10698
- function triviaLeadRanges(tri, trivia2) {
10699
- if (tri === TRI_NONE) return [];
10700
- if (tri < 0) return void 0;
10701
- const fs3 = trivia2[tri]?._meta.firstSet;
10702
- if (fs3 === void 0) return void 0;
10703
- if (fs3.kind === "empty") return [];
10704
- return fs3.kind === "ranges" && fs3.ranges !== void 0 ? leadRanges(fs3.ranges) : void 0;
10805
+ const j = mint("_j");
10806
+ const endV = mint("_end");
10807
+ const openLen = shape.open.length;
10808
+ const closeLen = shape.close.length;
10809
+ const openChk = openLen === 1 ? `${codeAt(start, firstChar)} === ${shape.open[0]}` : litCond(start, shape.open, firstChar);
10810
+ const closeChk = litCond(j, shape.close);
10811
+ const scanLines = [
10812
+ `${ind} while (${j} + ${closeLen - 1} < input.length && !(${closeChk})) ${j}++`,
10813
+ `${ind} if (${j} + ${closeLen} <= input.length && (${closeChk})) ${endV} = ${j} + ${closeLen}`
10814
+ ];
10815
+ return {
10816
+ setup: [
10817
+ `${ind}let ${j} = ${start}`,
10818
+ `${ind}let ${endV} = ${start}`,
10819
+ `${ind}if (${start} + ${openLen} <= input.length && (${openChk})) {`,
10820
+ `${ind} ${j} = ${start} + ${openLen}`,
10821
+ ...scanLines,
10822
+ `${ind}}`
10823
+ ],
10824
+ ok: `${endV} > ${start}`,
10825
+ end: endV
10826
+ };
10705
10827
  }
10706
10828
 
10707
10829
  // src/table/scalar-terminal.ts
@@ -10962,6 +11084,10 @@ function rowNullable(code, k, ip, memo) {
10962
11084
  out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
10963
11085
  } else if (op === OP_REP || op === OP_REPV) {
10964
11086
  out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
11087
+ } else if (op === OP_SEED) {
11088
+ out = rowNullable(code, k, code[ip + 1], memo);
11089
+ } else if (op === OP_CONT) {
11090
+ out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
10965
11091
  } else if (WRAPPERS.has(op)) {
10966
11092
  if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
10967
11093
  }
@@ -11075,6 +11201,7 @@ var EMITTED_PARAMS = [
11075
11201
  "skipDeferredTrivia",
11076
11202
  // The pass-through collapse (`run-support.ts`).
11077
11203
  "collapseEmpty",
11204
+ "popCstChild",
11078
11205
  // Constructor-built tree objects (`cst/plain.d.ts`): a `new` call has no
11079
11206
  // allocation site, so V8 cannot pretenure them.
11080
11207
  "_SP",
@@ -11354,7 +11481,12 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false, se
11354
11481
  const roots = [...Object.values(prog.rules), ...extraIps];
11355
11482
  const reachable = [...reachableSites(code, roots)];
11356
11483
  const GAP_ROWS = gapNeutral ? /* @__PURE__ */ new Set() : new Set([...gapRows(code, roots)].filter((row) => !gapRegexLowers(k[code[row + 1]])));
11357
- const labels = computeSiteLabels(code, roots, hostCst);
11484
+ const labels = computeSiteLabels(
11485
+ code,
11486
+ roots,
11487
+ hostCst,
11488
+ cfg.tolerant || cfg.probe ? void 0 : (ip, tri) => canDecide(code, ip, tri, t.triviaScan)
11489
+ );
11358
11490
  const scalarSpecs = /* @__PURE__ */ new Set();
11359
11491
  const nullable2 = /* @__PURE__ */ new Map();
11360
11492
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
@@ -11601,6 +11733,14 @@ return 1
11601
11733
  if (leads.length === 0) return (c) => `${c}<55296`;
11602
11734
  return (c) => `${c}<55296&&!(${leads.map((r) => r.lo === r.hi ? `${c}===${r.lo}` : `(${c}>=${r.lo}&&${c}<=${r.hi})`).join("||")})`;
11603
11735
  }
11736
+ function skipCapturing(l) {
11737
+ if (l.tri < 0 || !swapLegal || triviaLabelled[l.tri] || t.triviaScan[l.tri] == null) return "true";
11738
+ return capturesHere(l);
11739
+ }
11740
+ function capturesHere(l) {
11741
+ const sink = l.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)";
11742
+ return l.cap === CAP_OFF ? "false" : l.cap === CAP_ON ? sink : `(ctx.captureTrivia===true&&${sink})`;
11743
+ }
11604
11744
  function skipFor(l) {
11605
11745
  if (l.tri < 0) return "_skipTrivia";
11606
11746
  const ki = l.tri;
@@ -11693,9 +11833,12 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
11693
11833
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
11694
11834
  if (op === OP_RULE || op === OP_GAPGATE) return code[ip + 1];
11695
11835
  if (op === OP_STRICT) return code[cfg.tolerant || cfg.probe ? ip + 2 : ip + 1];
11836
+ if (op === OP_CONT && !labels.late.has(ip)) return code[ip + 2];
11837
+ if (op === OP_SEED) return code[ip + 1];
11696
11838
  if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
11697
11839
  return void 0;
11698
11840
  }
11841
+ let LATE;
11699
11842
  function lower(ip, fname) {
11700
11843
  const op = code[ip];
11701
11844
  const head = `function ${fname}(input,pos,ctx){`;
@@ -11828,6 +11971,71 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
11828
11971
  }
11829
11972
  case OP_EMPTY:
11830
11973
  return `${head}EC.e=pos;return ''}`;
11974
+ case OP_CONT: {
11975
+ const tri = L.tri;
11976
+ const g = continuationGate(code, code[ip + 3]);
11977
+ const missAt = (idx, at2) => {
11978
+ const resolved = t.cc[idx];
11979
+ const ci = classes.push([resolved]) - 1;
11980
+ classPlan.push([idx]);
11981
+ const ref2 = hoist("cg", `CLS[${ci}][0]`);
11982
+ return isAsciiOnlyClass(resolved) ? `${ref2}.ascii[input.charCodeAt(${at2})]!==1` : `!classHas(${ref2},lead(input,${at2}))`;
11983
+ };
11984
+ let scanned = "";
11985
+ if (tri >= 0) {
11986
+ const scan = hoist("cs", `TRIVIASCAN[${tri}]`);
11987
+ const miss = triviaMiss(tri);
11988
+ scanned = miss === void 0 ? `const q0=${scan}(input,c1)
11989
+ ` : `const cc=input.charCodeAt(c1)
11990
+ const q0=${miss("cc")}?c1:${scan}(input,c1)
11991
+ `;
11992
+ }
11993
+ const at = tri >= 0 ? "q0" : "c1";
11994
+ let test;
11995
+ if (g.gapRow < 0) test = `if(c0!==undefined&&${missAt(g.cls, at)})return c0
11996
+ `;
11997
+ else {
11998
+ const re = hoist("cr", `K[${code[g.gapRow + 1]}]`);
11999
+ const other = g.other >= 0 ? missAt(g.other, at) : "true";
12000
+ test = `${re}.lastIndex=${at}
12001
+ const gq=${re}.test(input)?${re}.lastIndex:-1
12002
+ if(c0!==undefined&&(gq<0||${missAt(g.follow, "gq")})&&${other})return c0
12003
+ `;
12004
+ }
12005
+ const seq = code[code[ip + 2] + 2];
12006
+ const seqLabel = labels.at(seq);
12007
+ const tail = link(code[ip + 3]);
12008
+ const recorded = tri === TRI_NONE ? "" : `const tl0=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
12009
+ const lg0=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
12010
+ const rt0=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
12011
+ const s0=${skipFor(seqLabel)}(input,c1,ctx)
12012
+ const tl1=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
12013
+ const lg1=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
12014
+ const rt1=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
12015
+ v=${tail}(input,s0,ctx)
12016
+ if(v!==FAIL&&EC.e<=s0){rollbackScannedTriviaAt(ctx,tl0,tl1,lg0,lg1,rt0,rt1);EC.e=c1}`;
12017
+ const quiet = `v=${tail}(input,${at},ctx)
12018
+ if(v!==FAIL&&EC.e<=${at})EC.e=c1`;
12019
+ const capture = capturesHere(seqLabel);
12020
+ const body = `let v
12021
+ ${tri === TRI_NONE ? `v=${tail}(input,c1,ctx)` : `if(q0===c1)v=${tail}(input,c1,ctx)
12022
+ else ${capture === "true" ? `{
12023
+ ${recorded}
12024
+ }` : `if(ctx._triviaLog===undefined&&ctx._rootTriviaLog===undefined${capture === "false" ? "" : `&&!${capture}`}){
12025
+ ${quiet}
12026
+ }else{
12027
+ ${recorded}
12028
+ }`}`}`;
12029
+ const wrapperIp = code[ip + 2];
12030
+ LATE = {
12031
+ prefix: `const c0=${link(code[ip + 1])}(input,pos,ctx)
12032
+ if(c0===FAIL)return FAIL
12033
+ const c1=EC.e
12034
+ ${scanned}${test}`,
12035
+ body
12036
+ };
12037
+ return lower(wrapperIp, fname);
12038
+ }
11831
12039
  case OP_GATE: {
11832
12040
  const child = link(code[ip + 2]);
11833
12041
  const xf = fxRef(code[ip + 3]);
@@ -12790,7 +12998,9 @@ return out
12790
12998
  case OP_NODE:
12791
12999
  case OP_NODE_TRACK: {
12792
13000
  const flags = code[ip + 3];
12793
- const scalarChild = scalarTerminalNodeChild(code, ip);
13001
+ const late = LATE;
13002
+ LATE = void 0;
13003
+ const scalarChild = late === void 0 ? scalarTerminalNodeChild(code, ip) : -1;
12794
13004
  if (scalarChild >= 0 && scalarSpecs.has(code[scalarChild + 1])) {
12795
13005
  const recognize = recognizerRef(code[scalarChild + 1]);
12796
13006
  const spec = code[scalarChild] === OP_RX ? null : k[code[scalarChild + 1]];
@@ -12810,7 +13020,9 @@ EC.e=end
12810
13020
  return nd
12811
13021
  }`;
12812
13022
  }
12813
- const child = link(code[ip + 2]);
13023
+ const child = late === void 0 ? link(code[ip + 2]) : "";
13024
+ const runBody = late === void 0 ? `const v=${child}(input,pos,ctx)` : late.body;
13025
+ const takeBack = late === void 0 ? "" : "let c0Raw\nif(sBuf===undefined&&sRaw===undefined&&sCh!==undefined)sCh.pop()\nelse if(sBuf!==undefined||sCh!==undefined)c0Raw=popCstChild(ctx)\n";
12814
13026
  const proj = code[ip + 4];
12815
13027
  const buildIdx = code[ip + 1];
12816
13028
  const type = k[code[ip + 5]];
@@ -12825,14 +13037,14 @@ return nd
12825
13037
  const trailingTrivia = (flags & 128) !== 0;
12826
13038
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
12827
13039
  const leanFlags = flags & ~128;
12828
- if (build !== void 0 && passCollapse(code, ip, hostCst)) {
13040
+ if (late === void 0 && build !== void 0 && passCollapse(code, ip, hostCst)) {
12829
13041
  return `${head}
12830
13042
  const v=${child}(input,pos,ctx)
12831
13043
  if(v!==undefined)return v
12832
13044
  return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
12833
13045
  }`;
12834
13046
  }
12835
- const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
13047
+ const gated = late === void 0 && build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
12836
13048
  const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t.trivia);
12837
13049
  const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
12838
13050
  if(!(${[
@@ -12879,9 +13091,9 @@ sCh.push(nd)
12879
13091
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
12880
13092
  }`;
12881
13093
  return `${head}
12882
- ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
13094
+ ${late?.prefix ?? ""}${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12883
13095
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
12884
- const flat=[]
13096
+ ${takeBack}const flat=${late === void 0 ? "[]" : "[c0]"}
12885
13097
  ctx._cstBuf=undefined
12886
13098
  ctx._cstChildren=flat
12887
13099
  ctx._cstLeaves=flat
@@ -12889,7 +13101,7 @@ ctx._cstRawChildren=undefined
12889
13101
  ctx._cstTriviaLog=undefined
12890
13102
  ctx.captureTrivia=false
12891
13103
  ctx._fields=${fields ? "[]" : "undefined"}
12892
- const v=${child}(input,pos,ctx)
13104
+ ${runBody}
12893
13105
  ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
12894
13106
  ` : ""}const captured=_capturedFlatChildren(flat)
12895
13107
  ${fields ? "const fieldMap=buildFieldMap(ctx._fields)\n" : ""}ctx._fields=sFields
@@ -12953,16 +13165,17 @@ const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
12953
13165
  const hostKids=kids
12954
13166
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
12955
13167
  const tlog=buf.tl??EMPTY_TLOG`;
13168
+ const seedCapture = late === void 0 ? "" : omitsRaw ? "buf.single=c0\nbuf.rawLen=1\n" : "buf.single=c0\nbuf.rawSingle=c0Raw!==undefined?c0Raw:rawEntry(c0,input,pos,c1)\n";
12956
13169
  return `${head}
12957
- ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
13170
+ ${late?.prefix ?? ""}${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12958
13171
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
12959
- ${openCapture}
12960
- ctx.captureTrivia=${captureWide}
13172
+ ${takeBack}${openCapture}
13173
+ ${seedCapture}ctx.captureTrivia=${captureWide}
12961
13174
  const savedFields=ctx._fields
12962
13175
  ctx._fields=${wantFields ? "[]" : "undefined"}
12963
13176
  ${structural ? `const savedMask=ctx._triviaCaptureMask
12964
13177
  if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
12965
- ` : ""}const v=${child}(input,pos,ctx)
13178
+ ` : ""}${runBody}
12966
13179
  ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
12967
13180
  ` : ""}const fieldMap=${wantFields ? "buildFieldMap(ctx._fields)" : "undefined"}
12968
13181
  ctx._fields=savedFields
@@ -13683,6 +13896,13 @@ function failCleanAnalysis(code) {
13683
13896
  case OP_ROUTED:
13684
13897
  out = code[ip + 1] < 0 || clean(code[ip + 1]);
13685
13898
  break;
13899
+ case OP_SEED:
13900
+ out = clean(code[ip + 1]);
13901
+ break;
13902
+ // The corner may fail; the wrapper fails only through a tail that can.
13903
+ case OP_CONT:
13904
+ out = clean(code[ip + 1]) && neverFails(code[ip + 3]);
13905
+ break;
13686
13906
  // An arm's failure and the fallback's are committed; only the selector's is
13687
13907
  // not, and without a fallback an unknown key fails after the selector wrote.
13688
13908
  case OP_DISPATCH:
@@ -13901,7 +14121,8 @@ function assemble(t, prog, cfg) {
13901
14121
  const closureLabels = computeSiteLabels(
13902
14122
  code,
13903
14123
  [...Object.values(prog.rules), ...labelExtraIps],
13904
- hostCst
14124
+ hostCst,
14125
+ cfg.tolerant || cfg.probe ? void 0 : (ip, tri) => canDecide(code, ip, tri, t.triviaScan)
13905
14126
  );
13906
14127
  let SCAN = null;
13907
14128
  let HYBRID;
@@ -14298,6 +14519,32 @@ function assemble(t, prog, cfg) {
14298
14519
  if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
14299
14520
  return cur;
14300
14521
  }
14522
+ function startsTail(cls, input, at) {
14523
+ const c = input.charCodeAt(at);
14524
+ return c < 128 ? cls.ascii[c] === 1 : classHas2(cls, lead(input, at));
14525
+ }
14526
+ function lateTail(tail, input, end, at, ctx, frame) {
14527
+ if (at === end) return tail(input, end, ctx);
14528
+ if (ctx._triviaLog === void 0 && ctx._rootTriviaLog === void 0 && (frame.cap === CAP_OFF || !((frame.cap === CAP_ON || ctx.captureTrivia === true) && (frame.buf || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)))) {
14529
+ const v2 = tail(input, at, ctx);
14530
+ if (v2 !== FAIL && EC.e <= at) EC.e = end;
14531
+ return v2;
14532
+ }
14533
+ const need = rollbackNeeded(ctx);
14534
+ const mTl = need ? cstTlLen(ctx) : 0;
14535
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
14536
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14537
+ const scanEnd = skipTrivia(input, end, ctx);
14538
+ const scanTl = need ? cstTlLen(ctx) : 0;
14539
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
14540
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14541
+ const v = tail(input, scanEnd, ctx);
14542
+ if (v !== FAIL && EC.e <= scanEnd) {
14543
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
14544
+ EC.e = end;
14545
+ }
14546
+ return v;
14547
+ }
14301
14548
  function nextTermBuffered(child, input, cur, ctx) {
14302
14549
  const t2 = ctx.trivia;
14303
14550
  if (t2 === void 0 || cannotStartTrivia(input, cur, t2)) {
@@ -14913,6 +15160,79 @@ function assemble(t, prog, cfg) {
14913
15160
  EC.e = pos;
14914
15161
  return "";
14915
15162
  };
15163
+ case OP_SEED:
15164
+ return link(code[ip + 1]);
15165
+ case OP_CONT: {
15166
+ const wrapper = code[ip + 2];
15167
+ if (!closureLabels.late.has(ip)) return lower(wrapper);
15168
+ const corner = link(code[ip + 1]);
15169
+ const tail = link(code[ip + 3]);
15170
+ const g = continuationGate(code, code[ip + 3]);
15171
+ const tri = closureLabels.at(ip).tri;
15172
+ const scan = tri === TRI_NONE ? void 0 : t.triviaScan[tri];
15173
+ const leads = tri === TRI_NONE ? null : LEAD_TABLES[tri];
15174
+ const cls = cc[g.cls];
15175
+ const gapRe = g.gapRow < 0 ? void 0 : k[code[g.gapRow + 1]];
15176
+ const follow = g.follow < 0 ? void 0 : cc[g.follow];
15177
+ const other = g.other < 0 ? void 0 : cc[g.other];
15178
+ const mayStartPastGap = (input, at) => {
15179
+ gapRe.lastIndex = at;
15180
+ const q2 = gapRe.test(input) ? gapRe.lastIndex : -1;
15181
+ return q2 >= 0 && classHas2(follow, lead(input, q2)) || other !== void 0 && classHas2(other, lead(input, at));
15182
+ };
15183
+ const frame = closureLabels.at(code[wrapper + 2]);
15184
+ const flags = code[wrapper + 3];
15185
+ const buildIdx = code[wrapper + 1];
15186
+ let held;
15187
+ let heldRaw;
15188
+ let heldEnd = 0;
15189
+ let heldAt = 0;
15190
+ const omitsRaw = !hostCst && buildIdx >= 0 && code[wrapper + 4] < 0 && (flags & 2) !== 0;
15191
+ const body = omitsRaw ? (input, _pos, ctx) => {
15192
+ const b = ctx._cstBuf;
15193
+ if (b !== void 0) {
15194
+ b.single = held;
15195
+ b.rawLen = 1;
15196
+ } else ctx._cstChildren.push(held);
15197
+ held = void 0;
15198
+ heldRaw = void 0;
15199
+ return lateTail(tail, input, heldEnd, heldAt, ctx, frame);
15200
+ } : (input, pos, ctx) => {
15201
+ const b = ctx._cstBuf;
15202
+ if (b !== void 0) {
15203
+ b.single = held;
15204
+ b.rawSingle = heldRaw ?? rawEntry(held, input, pos, heldEnd);
15205
+ } else ctx._cstChildren.push(held);
15206
+ held = void 0;
15207
+ heldRaw = void 0;
15208
+ return lateTail(tail, input, heldEnd, heldAt, ctx, frame);
15209
+ };
15210
+ let open;
15211
+ if (!hostCst && !cfg.trackLines && code[wrapper] === OP_NODE && code[wrapper + 4] < 0 && (flags === 32 || flags === 34)) {
15212
+ const build = fns[buildIdx];
15213
+ open = flags === 34 ? childrenOnlyCollapseBuildNode(body, build) : collapseBuildNode(body, build);
15214
+ } else {
15215
+ NODE_BODY = body;
15216
+ open = lower(wrapper);
15217
+ }
15218
+ return (input, pos, ctx) => {
15219
+ const v = corner(input, pos, ctx);
15220
+ if (v === FAIL) return FAIL;
15221
+ const end = EC.e;
15222
+ let at = end;
15223
+ if (scan !== void 0) {
15224
+ const c = input.charCodeAt(end);
15225
+ if (leads === null || !(c < 128) || leads[c] !== 0) at = scan(input, end);
15226
+ }
15227
+ if (v !== void 0 && !(gapRe === void 0 ? startsTail(cls, input, at) : mayStartPastGap(input, at))) return v;
15228
+ if (ctx._cstBuf === void 0 && ctx._cstRawChildren === void 0 && ctx._cstChildren !== void 0) ctx._cstChildren.pop();
15229
+ else if (ctx._cstBuf !== void 0 || ctx._cstChildren !== void 0) heldRaw = popCstChild(ctx);
15230
+ held = v;
15231
+ heldEnd = end;
15232
+ heldAt = at;
15233
+ return open(input, pos, ctx);
15234
+ };
15235
+ }
14916
15236
  /* ── transparent / structural ────────────────────────────────────────── */
14917
15237
  case OP_GUARD: {
14918
15238
  const pred = fns[code[ip + 1]];
@@ -17129,6 +17449,7 @@ function assemble(t, prog, cfg) {
17129
17449
  triviaFieldCapture,
17130
17450
  skipDeferredTrivia,
17131
17451
  collapseEmpty,
17452
+ popCstChild,
17132
17453
  PlainSpan10,
17133
17454
  PlainLeaf9,
17134
17455
  PlainNode2,
@@ -17218,6 +17539,7 @@ function assemble(t, prog, cfg) {
17218
17539
  triviaFieldCapture,
17219
17540
  skipDeferredTrivia,
17220
17541
  collapseEmpty,
17542
+ popCstChild,
17221
17543
  PlainSpan10,
17222
17544
  PlainLeaf9,
17223
17545
  PlainNode2,
@@ -19176,6 +19498,10 @@ function staticWeights(code, entries) {
19176
19498
  kids.length = 0;
19177
19499
  childSlots(code, ip, kids);
19178
19500
  const op = code[ip];
19501
+ if (op === OP_CONT && continuationGate(code, code[ip + 3]) !== void 0) {
19502
+ kids.length = 0;
19503
+ kids.push(code[ip + 1], code[ip + 3]);
19504
+ }
19179
19505
  const scale = op === OP_REP || op === OP_REPV ? LOOP : op === OP_CHOICE || op === OP_DISPATCH ? 1 / Math.max(1, kids.length) : 1;
19180
19506
  for (const k of kids) {
19181
19507
  const kid = code[k] === OP_GAPGATE ? code[k + 1] : k;
@@ -23293,6 +23619,7 @@ async function emitCarriedSidecars(sinks, bundle) {
23293
23619
  var SIDECAR_FRAMEWORKS = /* @__PURE__ */ new Set(["rollup", "rolldown", "vite"]);
23294
23620
  var plugin_default = createUnplugin((opts = {}, meta) => {
23295
23621
  const sinks = SIDECAR_FRAMEWORKS.has(meta.framework) ? /* @__PURE__ */ new Map() : void 0;
23622
+ const profiled = /* @__PURE__ */ new Map();
23296
23623
  const generateBundle = sinks === void 0 ? void 0 : {
23297
23624
  generateBundle: {
23298
23625
  order: "post",
@@ -23311,8 +23638,15 @@ var plugin_default = createUnplugin((opts = {}, meta) => {
23311
23638
  transformInclude(id) {
23312
23639
  return /\.[jt]sx?$/.test(id) && !id.includes("node_modules");
23313
23640
  },
23641
+ buildEnd(error) {
23642
+ if (error) return;
23643
+ const ids = [...this.getModuleIds?.() ?? profiled.keys()].filter((id) => profiled.has(id));
23644
+ if (ids.length === 0 || ids.some((id) => profiled.get(id) === "ran")) return;
23645
+ throw new Error(`assemblyProfile: no grammar has rule "${opts.assemblyProfile?.entry}", so the corpus never ran (${ids.join(", ")})`);
23646
+ },
23314
23647
  transform(code, id) {
23315
23648
  sinks?.delete(id);
23649
+ profiled.delete(id);
23316
23650
  if (!code.includes("parseman")) return null;
23317
23651
  if (!code.includes("macro")) return null;
23318
23652
  for (const file of opts.assemblyProfile?.files ?? []) this?.addWatchFile?.(file);
@@ -23320,6 +23654,7 @@ var plugin_default = createUnplugin((opts = {}, meta) => {
23320
23654
  const sink = sinks && /* @__PURE__ */ new Map();
23321
23655
  const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true, opts.grammarCoverage === true, opts.assemblyProfile, opts.assemblyBudget, sink);
23322
23656
  if (sinks && sink && sink.size > 0) sinks.set(id, sink);
23657
+ if (result?.assemblyProfile !== void 0) profiled.set(id, result.assemblyProfile);
23323
23658
  if (result?.warnings.length) {
23324
23659
  for (const w of result.warnings) {
23325
23660
  if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
@@ -24384,8 +24719,14 @@ ${names.map((n) => ` - ${n}`).join("\n")}` : " (it is not a static combinator/v
24384
24719
  assemblySites.push(...sites);
24385
24720
  return sites;
24386
24721
  };
24722
+ let profileOutcome;
24387
24723
  const profileOf = (compiled) => {
24388
- if (assemblyProfile === void 0 || compiled.hostMode !== "ast" || compiled.prog.lines === 1 || !(assemblyProfile.entry in compiled.prog.rules)) return void 0;
24724
+ if (assemblyProfile === void 0 || compiled.hostMode !== "ast" || compiled.prog.lines === 1) return void 0;
24725
+ if (!(assemblyProfile.entry in compiled.prog.rules)) {
24726
+ profileOutcome ??= "no-entry";
24727
+ return void 0;
24728
+ }
24729
+ profileOutcome = "ran";
24389
24730
  const refuse = (why) => {
24390
24731
  throw new Error(`${id} \u2014 assemblyProfile: ${why}`);
24391
24732
  };
@@ -24405,26 +24746,36 @@ ${names.map((n) => ` - ${n}`).join("\n")}` : " (it is not a static combinator/v
24405
24746
  }
24406
24747
  });
24407
24748
  });
24408
- return countSiteVisits(compiled.prog, (rules3) => {
24409
- const entry = rules3[assemblyProfile.entry];
24410
- corpusTexts(assemblyProfile).forEach((text, i) => {
24411
- const file = assemblyProfile.files[i];
24412
- if (text.trim() === "") return;
24413
- let result2;
24414
- try {
24415
- result2 = run(entry, text);
24416
- } catch (e) {
24417
- const source = String(thrower).replace(/\s+/g, " ").slice(0, 200);
24418
- throw new Error(`${id} \u2014 assemblyProfile: ${thrower === void 0 ? "the parse" : `gate or reducer \`${source}\``} threw on ${file}: ${String(e)}`, { cause: e });
24419
- }
24420
- if (!result2.ok || result2.unconsumedFrom !== null) {
24421
- refuse(`${file} does not parse from rule "${assemblyProfile.entry}": it stops at offset ${result2.ok ? result2.unconsumedFrom : result2.span.end}`);
24422
- }
24423
- if (result2.errors.length > 0) {
24424
- refuse(`${file} parses only by recovering from ${result2.errors.length} error(s), first at offset ${result2.errors[0].span.start}`);
24425
- }
24426
- });
24427
- }, fns);
24749
+ const scope3 = assemblyProfile.scope ?? {};
24750
+ const names = Object.keys(scope3);
24751
+ for (const name of names) {
24752
+ if (name in globalThis) refuse(`\`scope\` name "${name}" is already a global; a callback couldn't tell which one it reads`);
24753
+ }
24754
+ try {
24755
+ for (const name of names) Object.defineProperty(globalThis, name, { value: scope3[name], configurable: true });
24756
+ return countSiteVisits(compiled.prog, (rules3) => {
24757
+ const entry = rules3[assemblyProfile.entry];
24758
+ corpusTexts(assemblyProfile).forEach((text, i) => {
24759
+ const file = assemblyProfile.files[i];
24760
+ if (text.trim() === "") return;
24761
+ let result2;
24762
+ try {
24763
+ result2 = run(entry, text);
24764
+ } catch (e) {
24765
+ const source = String(thrower).replace(/\s+/g, " ").slice(0, 200);
24766
+ throw new Error(`${id} \u2014 assemblyProfile: ${thrower === void 0 ? "the parse" : `gate or reducer \`${source}\``} threw on ${file}: ${String(e)}`, { cause: e });
24767
+ }
24768
+ if (!result2.ok || result2.unconsumedFrom !== null) {
24769
+ refuse(`${file} does not parse from rule "${assemblyProfile.entry}": it stops at offset ${result2.ok ? result2.unconsumedFrom : result2.span.end}`);
24770
+ }
24771
+ if (result2.errors.length > 0) {
24772
+ refuse(`${file} parses only by recovering from ${result2.errors.length} error(s), first at offset ${result2.errors[0].span.start}`);
24773
+ }
24774
+ });
24775
+ }, fns);
24776
+ } finally {
24777
+ for (const name of names) Reflect.deleteProperty(globalThis, name);
24778
+ }
24428
24779
  };
24429
24780
  const assembledReplacement = (compiled, metadata, select) => select.size === 0 ? compiled.replacementWithMetadata(metadata) : supercompileRuleMapReplacement(compiled.prog, compiled.replacementWithMetadata(metadata, { select }), select);
24430
24781
  const compileComposeLeafCall = (init) => {
@@ -24937,7 +25288,8 @@ ${lines2.join("\n")}`);
24937
25288
  assemblySites: applied.length > 0 ? assemblySites : [],
24938
25289
  code: ms.toString(),
24939
25290
  map: ms.generateMap({ hires: true }),
24940
- warnings
25291
+ warnings,
25292
+ ...profileOutcome === void 0 ? {} : { assemblyProfile: profileOutcome }
24941
25293
  };
24942
25294
  }
24943
25295
  export {