parseman 0.60.6 → 0.61.1

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 (60) hide show
  1. package/dist/analysis/backtrack.d.ts +50 -0
  2. package/dist/analysis/backtrack.d.ts.map +1 -0
  3. package/dist/analysis/diagnostics.d.ts +3 -0
  4. package/dist/analysis/diagnostics.d.ts.map +1 -1
  5. package/dist/analysis/diagnostics.js +1162 -158
  6. package/dist/analysis/diagnostics.js.map +3 -3
  7. package/dist/analysis/rebuild.d.ts +17 -1
  8. package/dist/analysis/rebuild.d.ts.map +1 -1
  9. package/dist/cli/index.js +353 -69
  10. package/dist/cli/index.js.map +3 -3
  11. package/dist/combinators/choice.d.ts.map +1 -1
  12. package/dist/combinators/dispatch.d.ts +2 -0
  13. package/dist/combinators/dispatch.d.ts.map +1 -1
  14. package/dist/combinators/expect.d.ts.map +1 -1
  15. package/dist/combinators/link-scope.d.ts +7 -0
  16. package/dist/combinators/link-scope.d.ts.map +1 -0
  17. package/dist/combinators/node.d.ts.map +1 -1
  18. package/dist/combinators/parser.d.ts.map +1 -1
  19. package/dist/compiler/token-capability.js +1 -0
  20. package/dist/compiler/token-capability.js.map +1 -1
  21. package/dist/compiler/value-usage.d.ts.map +1 -1
  22. package/dist/coverage.d.ts.map +1 -1
  23. package/dist/functional/run.d.ts.map +1 -1
  24. package/dist/index.js +121 -90
  25. package/dist/index.js.map +3 -3
  26. package/dist/language-service/index.js +1 -1
  27. package/dist/language-service/index.js.map +1 -1
  28. package/dist/plugin/index.js +274 -243
  29. package/dist/plugin/index.js.map +3 -3
  30. package/dist/run/index.js +1 -1
  31. package/dist/run/index.js.map +1 -1
  32. package/dist/spec/index.js.map +1 -1
  33. package/dist/table/backtrack-probe.d.ts +41 -0
  34. package/dist/table/backtrack-probe.d.ts.map +1 -0
  35. package/dist/table/child-slots.d.ts +10 -0
  36. package/dist/table/child-slots.d.ts.map +1 -1
  37. package/dist/table/emit.d.ts.map +1 -1
  38. package/dist/table/index.js +31 -20
  39. package/dist/table/index.js.map +3 -3
  40. package/dist/table/program.d.ts +3 -1
  41. package/dist/table/program.d.ts.map +1 -1
  42. package/dist/version.d.ts +1 -1
  43. package/package.json +5 -1
  44. package/src/analysis/backtrack.ts +249 -0
  45. package/src/analysis/diagnostics.ts +4 -0
  46. package/src/analysis/rebuild.ts +63 -11
  47. package/src/combinators/choice.ts +3 -1
  48. package/src/combinators/dispatch.ts +9 -0
  49. package/src/combinators/expect.ts +1 -0
  50. package/src/combinators/link-scope.ts +19 -0
  51. package/src/combinators/node.ts +11 -2
  52. package/src/combinators/parser.ts +37 -31
  53. package/src/compiler/value-usage.ts +16 -29
  54. package/src/coverage.ts +2 -14
  55. package/src/functional/run.ts +3 -1
  56. package/src/table/backtrack-probe.ts +326 -0
  57. package/src/table/child-slots.ts +30 -14
  58. package/src/table/emit.ts +5 -1
  59. package/src/table/program.ts +8 -2
  60. package/src/version.ts +1 -1
@@ -424,13 +424,13 @@ function caseFoldVariants(cp) {
424
424
  // src/combinators/probe.ts
425
425
  function failAt(ctx, expected, pos) {
426
426
  const r = { ok: false, expected, span: { start: pos, end: pos } };
427
- const probe = ctx._probe;
428
- if (probe !== void 0 && pos <= probe.offset) {
429
- const best = probe.best;
427
+ const probe2 = ctx._probe;
428
+ if (probe2 !== void 0 && pos <= probe2.offset) {
429
+ const best = probe2.best;
430
430
  if (best === null || pos > best.span.start) {
431
- probe.best = r;
431
+ probe2.best = r;
432
432
  } else if (pos === best.span.start) {
433
- probe.best = { ...best, expected: [...best.expected, ...expected] };
433
+ probe2.best = { ...best, expected: [...best.expected, ...expected] };
434
434
  }
435
435
  }
436
436
  return r;
@@ -2258,15 +2258,20 @@ function markUnusedValues(root) {
2258
2258
  case "many":
2259
2259
  case "oneOrMore":
2260
2260
  mark(def, consumed);
2261
- visit(def.parser, consumed);
2262
- return;
2263
2261
  case "optional":
2262
+ // `optional` returns `inner | null` — no aggregate array/tuple to elide, so
2263
+ // it carries no valueUnused flag. Still descend so an inner many/sequence
2264
+ // under a node() is analyzed (it benefits even when its optional wrapper
2265
+ // doesn't).
2266
+ case "label":
2267
+ case "trivia":
2268
+ case "attempt":
2269
+ case "withCtx":
2270
+ case "expect":
2264
2271
  visit(def.parser, consumed);
2265
2272
  return;
2266
2273
  case "sequence":
2267
2274
  mark(def, consumed);
2268
- for (const p of def.parsers) visit(p, consumed);
2269
- return;
2270
2275
  case "choice":
2271
2276
  for (const p of def.parsers) visit(p, consumed);
2272
2277
  return;
@@ -2277,22 +2282,24 @@ function markUnusedValues(root) {
2277
2282
  if (def.otherwise) visit(def.otherwise, consumed);
2278
2283
  return;
2279
2284
  case "node":
2285
+ // builds from captured children, NOT the inner parser value.
2286
+ case "not":
2287
+ case "peek":
2288
+ // lookahead — value never observed
2289
+ case "token":
2280
2290
  visit(def.parser, false);
2281
2291
  return;
2282
2292
  case "transform":
2283
- visit(def.parser, true);
2284
- return;
2293
+ // the map fn reads the value → always consumed.
2285
2294
  case "field":
2295
+ // the field capture records the parsed value → always consumed.
2296
+ case "leaf":
2286
2297
  visit(def.parser, true);
2287
2298
  return;
2288
2299
  case "sepBy":
2289
2300
  visit(def.parser, true);
2290
2301
  visit(def.separator, false);
2291
2302
  return;
2292
- case "not":
2293
- case "peek":
2294
- visit(def.parser, false);
2295
- return;
2296
2303
  case "grammar":
2297
2304
  visit(def.parser, consumed);
2298
2305
  if (def.triviaParser) visit(def.triviaParser, false);
@@ -2301,19 +2308,6 @@ function markUnusedValues(root) {
2301
2308
  visit(def.parser, consumed);
2302
2309
  visit(def.sentinel, false);
2303
2310
  return;
2304
- case "token":
2305
- visit(def.parser, false);
2306
- return;
2307
- case "label":
2308
- case "trivia":
2309
- case "attempt":
2310
- case "withCtx":
2311
- case "expect":
2312
- visit(def.parser, consumed);
2313
- return;
2314
- case "leaf":
2315
- visit(def.parser, true);
2316
- return;
2317
2311
  case "lazy":
2318
2312
  return;
2319
2313
  default:
@@ -2616,6 +2610,7 @@ function matchesAt(sentinel, input, pos, ctx) {
2616
2610
  function captureError(ctx, error) {
2617
2611
  if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
2618
2612
  }
2613
+ var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
2619
2614
 
2620
2615
  // src/combinators/expect.ts
2621
2616
  function deriveExpected(c) {
@@ -2676,6 +2671,7 @@ function derive(c, seen) {
2676
2671
  case "optional":
2677
2672
  case "many":
2678
2673
  case "oneOrMore":
2674
+ case "sepBy":
2679
2675
  case "transform":
2680
2676
  case "not":
2681
2677
  case "peek":
@@ -2823,7 +2819,7 @@ function choice(...args) {
2823
2819
  const result = parsers[idx].parse(input, pos, ctx);
2824
2820
  if (result.ok) return result;
2825
2821
  expected.push(...result.expected);
2826
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
2822
+ if (result.committed) return { ok: false, expected, span: result.span, committed: true };
2827
2823
  return { ok: false, expected, span: { start: pos, end: pos } };
2828
2824
  }
2829
2825
  if (ctx._probe !== void 0 || ctx._tolerant) for (const p of parsers) p.parse(input, pos, ctx);
@@ -4067,6 +4063,9 @@ function regex(pattern, flags = "") {
4067
4063
  };
4068
4064
  }
4069
4065
 
4066
+ // src/version.ts
4067
+ var PARSEMAN_VERSION = "0.61.1";
4068
+
4070
4069
  // src/table/lex-body.ts
4071
4070
  function buildLexBodyRecognizer(spec, constants) {
4072
4071
  const raw = constants[spec[0]];
@@ -4535,7 +4534,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
4535
4534
  if (!Number.isInteger(spec[2]) || spec[2] < 0) {
4536
4535
  throw new TypeError("table balanced lexical program has an invalid scan reference");
4537
4536
  }
4538
- const run = (_input, _pos, ctx, scan) => {
4537
+ const run2 = (_input, _pos, ctx, scan) => {
4539
4538
  if (scan === void 0) throw new TypeError("table balanced lexical program lost its scan body");
4540
4539
  const result = scan.parse(_input, _pos, ctx);
4541
4540
  if (!result.ok) {
@@ -4545,7 +4544,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
4545
4544
  }
4546
4545
  return result.span.end;
4547
4546
  };
4548
- return Object.assign(run, { scan: spec[2] });
4547
+ return Object.assign(run2, { scan: spec[2] });
4549
4548
  }
4550
4549
  if (spec[0] === 2) return fixedTreeRunner(spec.slice(2), matchers, classes, expected);
4551
4550
  if (spec[0] === 1) {
@@ -4682,11 +4681,12 @@ function assemblyExtraIps(prog) {
4682
4681
  }
4683
4682
  function expandCompact(p) {
4684
4683
  if ("code" in p) return p;
4684
+ if (p.es === void 0) throw new Error(`parseman: this parser was printed by an earlier parseman; reprint it with parseman ${PARSEMAN_VERSION}`);
4685
4685
  return ownTableProgram({
4686
4686
  code: p.c,
4687
4687
  k: p.k,
4688
4688
  cc: p.x,
4689
- fx: p.e,
4689
+ fx: p.e.map((set) => set.map((i) => p.es[i])),
4690
4690
  disp: p.d,
4691
4691
  rules: p.r,
4692
4692
  fns: p.f,
@@ -6591,6 +6591,206 @@ function asciiFoldKey(key) {
6591
6591
  }
6592
6592
  return out;
6593
6593
  }
6594
+ function matchesDispatchMatcher(value, matcher) {
6595
+ const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
6596
+ const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
6597
+ switch (matcher.kind) {
6598
+ case "startsWith":
6599
+ return candidate.startsWith(expected);
6600
+ case "endsWith":
6601
+ return candidate.endsWith(expected);
6602
+ case "matches": {
6603
+ const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
6604
+ return new RegExp(matcher.value, flags).test(value);
6605
+ }
6606
+ }
6607
+ }
6608
+ function isStringMatcher(value) {
6609
+ if (typeof value !== "object" || value === null) return false;
6610
+ const kind = value.kind;
6611
+ return kind === "startsWith" || kind === "endsWith" || kind === "matches";
6612
+ }
6613
+ function fixedMatcher(kind, value) {
6614
+ if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
6615
+ if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
6616
+ return { kind, value };
6617
+ }
6618
+ function startsWith(prefix) {
6619
+ return fixedMatcher("startsWith", prefix);
6620
+ }
6621
+ function endsWith(suffix) {
6622
+ return fixedMatcher("endsWith", suffix);
6623
+ }
6624
+ function matches(pattern) {
6625
+ if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
6626
+ if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
6627
+ throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
6628
+ }
6629
+ return { kind: "matches", value: pattern.source, flags: pattern.flags };
6630
+ }
6631
+ function dispatchMatcher(entry) {
6632
+ switch (entry.kind) {
6633
+ case "startsWith":
6634
+ return startsWith(entry.value);
6635
+ case "endsWith":
6636
+ return endsWith(entry.value);
6637
+ case "matches":
6638
+ return matches(new RegExp(entry.value, entry.flags));
6639
+ }
6640
+ }
6641
+ function when(key, parser2, opts = {}) {
6642
+ const usesRouted = parserUsesRouted(parser2);
6643
+ if (isStringMatcher(key)) {
6644
+ return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
6645
+ }
6646
+ const keys = Array.isArray(key) ? [...key] : [key];
6647
+ if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
6648
+ for (const item of keys) {
6649
+ if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
6650
+ }
6651
+ return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
6652
+ }
6653
+ function otherwise(parser2, opts = {}) {
6654
+ const usesRouted = parserUsesRouted(parser2);
6655
+ return opts.commit === false ? { kind: "otherwise", parser: parser2, usesRouted, commit: false } : { kind: "otherwise", parser: parser2, usesRouted };
6656
+ }
6657
+ function routed(fallback) {
6658
+ return {
6659
+ _tag: "routed",
6660
+ _meta: {
6661
+ // The routed token is whatever the selector matched, so the first set stays
6662
+ // `any` even with a fallback — `any` already subsumes the fallback's.
6663
+ firstSet: { kind: "any" },
6664
+ canMatchNewline: fallback?._meta.canMatchNewline ?? false,
6665
+ isTrivia: false
6666
+ },
6667
+ _def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
6668
+ parse(_input, pos, ctx) {
6669
+ const item = ctx._routed;
6670
+ if (item === void 0 || pos !== item.span.start) {
6671
+ if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
6672
+ return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
6673
+ }
6674
+ if (cstCaptureActive(ctx)) {
6675
+ pushCstLeaf(ctx, new PlainLeaf6(item.value, item.span));
6676
+ }
6677
+ return { ok: true, value: item.value, span: item.span };
6678
+ }
6679
+ };
6680
+ }
6681
+ function dispatch(selector, ...arms) {
6682
+ if (parserUsesRouted(selector)) {
6683
+ throw new Error("parseman: routed() can only appear inside a dispatch() branch");
6684
+ }
6685
+ let fallback;
6686
+ let fallbackUsesRouted = false;
6687
+ let fallbackCommits = true;
6688
+ const matchers = [];
6689
+ const cases = [];
6690
+ const seen = [];
6691
+ for (let i = 0; i < arms.length; i++) {
6692
+ const arm = arms[i];
6693
+ if (arm.kind === "otherwise") {
6694
+ if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
6695
+ if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
6696
+ fallback = arm.parser;
6697
+ fallbackUsesRouted = arm.usesRouted === true;
6698
+ fallbackCommits = arm.commit !== false;
6699
+ continue;
6700
+ }
6701
+ if (arm.kind === "whenMatcher") {
6702
+ const matcher = arm.matcher;
6703
+ matchers.push({
6704
+ kind: matcher.kind,
6705
+ value: matcher.value,
6706
+ ...matcher.kind === "matches" ? { flags: matcher.flags } : {},
6707
+ parser: arm.parser,
6708
+ caseInsensitive: arm.caseInsensitive,
6709
+ ...arm.usesRouted === true ? { usesRouted: true } : {}
6710
+ });
6711
+ continue;
6712
+ }
6713
+ for (const key of arm.keys) {
6714
+ const folded = asciiFoldKey(key);
6715
+ for (const prior of seen) {
6716
+ const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
6717
+ if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
6718
+ }
6719
+ seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
6720
+ }
6721
+ cases.push({
6722
+ keys: arm.keys,
6723
+ parser: arm.parser,
6724
+ caseInsensitive: arm.caseInsensitive,
6725
+ ...arm.usesRouted === true ? { usesRouted: true } : {}
6726
+ });
6727
+ }
6728
+ const meta = {
6729
+ firstSet: selector._meta.firstSet,
6730
+ canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
6731
+ isTrivia: false
6732
+ };
6733
+ const byKey = /* @__PURE__ */ new Map();
6734
+ const byFoldedKey = /* @__PURE__ */ new Map();
6735
+ for (const entry of cases) {
6736
+ for (const key of entry.keys) {
6737
+ if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
6738
+ else byKey.set(key, entry);
6739
+ }
6740
+ }
6741
+ return {
6742
+ _tag: "dispatch",
6743
+ _meta: meta,
6744
+ _def: {
6745
+ tag: "dispatch",
6746
+ selector,
6747
+ cases,
6748
+ ...matchers.length === 0 ? {} : { matchers },
6749
+ ...fallback === void 0 ? {} : {
6750
+ otherwise: fallback,
6751
+ ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {},
6752
+ ...fallbackCommits ? {} : { otherwiseCommit: false }
6753
+ }
6754
+ },
6755
+ parse(input, pos, ctx) {
6756
+ if (parserUsesRouted(selector)) {
6757
+ throw new Error("parseman: routed() can only appear inside a dispatch() branch");
6758
+ }
6759
+ const selectorMark = saveTriviaMark(ctx);
6760
+ const selected = selector.parse(input, pos, ctx);
6761
+ if (!selected.ok) return selected;
6762
+ const chosen = byKey.get(selected.value) ?? (byFoldedKey.size === 0 ? void 0 : byFoldedKey.get(asciiFoldKey(selected.value))) ?? matchers.find((matcher) => matchesDispatchMatcher(selected.value, matcher));
6763
+ const branch = chosen ?? (fallback === void 0 ? void 0 : { keys: [], parser: fallback, caseInsensitive: false, usesRouted: fallbackUsesRouted });
6764
+ if (branch === void 0) {
6765
+ const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
6766
+ return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
6767
+ }
6768
+ const savedRouted = ctx._routed;
6769
+ const usesRouted = branchUsesRouted(branch);
6770
+ let mark = saveTriviaMark(ctx);
6771
+ if (usesRouted) {
6772
+ rollbackTrivia(ctx, selectorMark);
6773
+ mark = saveTriviaMark(ctx);
6774
+ ctx._routed = { value: selected.value, span: selected.span };
6775
+ }
6776
+ let result;
6777
+ try {
6778
+ result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
6779
+ } finally {
6780
+ if (usesRouted) ctx._routed = savedRouted;
6781
+ }
6782
+ if (!result.ok) {
6783
+ rollbackTrivia(ctx, mark);
6784
+ return chosen === void 0 && !fallbackCommits ? result : { ...result, committed: true };
6785
+ }
6786
+ return {
6787
+ ok: true,
6788
+ value: [selected.value, result.value],
6789
+ span: { start: pos, end: result.span.end }
6790
+ };
6791
+ }
6792
+ };
6793
+ }
6594
6794
 
6595
6795
  // src/table/ops.ts
6596
6796
  var OP_LIT = 1;
@@ -6693,6 +6893,12 @@ var OP_NAMES = {
6693
6893
  [OP_STRICT]: "STRICT"
6694
6894
  };
6695
6895
 
6896
+ // src/combinators/link-scope.ts
6897
+ var scope;
6898
+ function afterLink(settle) {
6899
+ scope?.push(settle);
6900
+ }
6901
+
6696
6902
  // src/combinators/node.ts
6697
6903
  import { PlainNode, PlainSpan as PlainSpan7 } from "../cst/plain.js";
6698
6904
  function unwrapChild(child) {
@@ -6756,8 +6962,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
6756
6962
  const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
6757
6963
  const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
6758
6964
  const readsState = build ? buildReadsState(def) : project === void 0;
6759
- const hasOwnFields = parserHasOwnFields(combinator);
6760
- const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
6965
+ let hasOwnFields = parserHasOwnFields(combinator);
6966
+ let capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
6967
+ if (!hasOwnFields) {
6968
+ afterLink(() => {
6969
+ hasOwnFields = parserHasOwnFields(combinator);
6970
+ capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
6971
+ });
6972
+ }
6761
6973
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
6762
6974
  let failExpected;
6763
6975
  return {
@@ -6863,7 +7075,7 @@ function selectOptionalSuffixLexBody(ir) {
6863
7075
  function reinstallsRuleTrivia(reference, target) {
6864
7076
  return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
6865
7077
  }
6866
- function directTokenBodyParser(parser2, resolve, scope) {
7078
+ function directTokenBodyParser(parser2, resolve, scope2) {
6867
7079
  const outer = parser2._def;
6868
7080
  if (outer.tag !== "token") return void 0;
6869
7081
  let body = outer.parser;
@@ -6873,7 +7085,7 @@ function directTokenBodyParser(parser2, resolve, scope) {
6873
7085
  const wrapper = body._def;
6874
7086
  if (wrapper.tag === "grammar") {
6875
7087
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
6876
- if (scope !== void 0) scope.cleared = true;
7088
+ if (scope2 !== void 0) scope2.cleared = true;
6877
7089
  body = wrapper.parser;
6878
7090
  continue;
6879
7091
  }
@@ -7130,10 +7342,10 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared
7130
7342
  }
7131
7343
  }
7132
7344
  function directFixedTokenBody(parser2, resolve) {
7133
- const scope = { cleared: false };
7134
- const body = directTokenBodyParser(parser2, resolve, scope);
7345
+ const scope2 = { cleared: false };
7346
+ const body = directTokenBodyParser(parser2, resolve, scope2);
7135
7347
  if (body === void 0) return void 0;
7136
- const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope.cleared);
7348
+ const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope2.cleared);
7137
7349
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
7138
7350
  }
7139
7351
  function directBalancedTokenBody(parser2, resolve) {
@@ -8633,7 +8845,7 @@ var Encoder = class {
8633
8845
  const dispCovIds = this.plan?.dispatches.get(p);
8634
8846
  let dispCov = 0;
8635
8847
  const arms = [];
8636
- const routed = [];
8848
+ const routed2 = [];
8637
8849
  const key = [], keyArm = [];
8638
8850
  const fold = [], foldArm = [];
8639
8851
  const match = [];
@@ -8641,7 +8853,7 @@ var Encoder = class {
8641
8853
  for (const c of d.cases) {
8642
8854
  const arm = arms.length;
8643
8855
  arms.push(this.covWrap(this.node(c.parser).ip, dispCovIds?.[dispCov++], 1));
8644
- routed.push(branchUsesRouted(c) ? 1 : 0);
8856
+ routed2.push(branchUsesRouted(c) ? 1 : 0);
8645
8857
  for (const kk of c.keys) {
8646
8858
  expected.push(JSON.stringify(kk));
8647
8859
  if (c.caseInsensitive) {
@@ -8657,7 +8869,7 @@ var Encoder = class {
8657
8869
  for (const m of d.matchers ?? []) {
8658
8870
  const arm = arms.length;
8659
8871
  arms.push(this.covWrap(this.node(m.parser).ip, dispCovIds?.[dispCov++], 1));
8660
- routed.push(branchUsesRouted(m) ? 1 : 0);
8872
+ routed2.push(branchUsesRouted(m) ? 1 : 0);
8661
8873
  if (!m.caseInsensitive) {
8662
8874
  match.push([KIND[m.kind], m.value, m.flags ?? "", arm]);
8663
8875
  continue;
@@ -8671,7 +8883,7 @@ var Encoder = class {
8671
8883
  }
8672
8884
  const other = d.otherwise === void 0 ? -1 : this.covWrap(this.node(d.otherwise).ip, dispCovIds?.[dispCov++], 1);
8673
8885
  const dspIdx = this.dsp.length;
8674
- this.dsp.push({ key, keyArm, fold, foldArm, match, routed, expected });
8886
+ this.dsp.push({ key, keyArm, fold, foldArm, match, routed: routed2, expected });
8675
8887
  const head = this.emitHead(OP_DISPATCH, 5 + arms.length);
8676
8888
  this.code[head + 1] = sel;
8677
8889
  this.code[head + 2] = dspIdx;
@@ -9987,6 +10199,12 @@ function emitShapeMatch(shape, start, mint, ind, firstChar) {
9987
10199
 
9988
10200
  // src/table/child-slots.ts
9989
10201
  function childSlots(code, ip, out) {
10202
+ const from = out.length;
10203
+ if (!childSlotOffsets(code, ip, out)) return false;
10204
+ for (let i = from; i < out.length; i++) out[i] = code[out[i]];
10205
+ return true;
10206
+ }
10207
+ function childSlotOffsets(code, ip, out) {
9990
10208
  switch (code[ip]) {
9991
10209
  // ZERO-WIDTH / TERMINAL ROWS — no successor. `OP_GUARD` and `OP_ADJ` are both
9992
10210
  // childless tests. `OP_LIVE` holds a hand-written combinator in `prog.fns`; its
@@ -10019,7 +10237,7 @@ function childSlots(code, ip, out) {
10019
10237
  case OP_COV:
10020
10238
  case OP_REJECT:
10021
10239
  case OP_GAPGATE:
10022
- out.push(code[ip + 1]);
10240
+ out.push(ip + 1);
10023
10241
  return true;
10024
10242
  // Single child at `ip + 2`.
10025
10243
  case OP_GATE:
@@ -10036,55 +10254,55 @@ function childSlots(code, ip, out) {
10036
10254
  case OP_ARMGATE:
10037
10255
  case OP_RGATE:
10038
10256
  case OP_RGATE2:
10039
- out.push(code[ip + 2]);
10257
+ out.push(ip + 2);
10040
10258
  return true;
10041
10259
  // `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
10042
10260
  case OP_STRICT:
10043
- out.push(code[ip + 1], code[ip + 2]);
10261
+ out.push(ip + 1, ip + 2);
10044
10262
  return true;
10045
10263
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
10046
10264
  // data the enclosing `dispatch()` already consumed, so the only edge is the
10047
10265
  // fallback.
10048
10266
  case OP_ROUTED:
10049
- if (code[ip + 1] >= 0) out.push(code[ip + 1]);
10267
+ if (code[ip + 1] >= 0) out.push(ip + 1);
10050
10268
  return true;
10051
10269
  // `DISPATCH sel d other otherRouted n a1 … an` — the SELECTOR is a child on
10052
10270
  // exactly the same footing as the arms: it runs inside whatever node and scope
10053
10271
  // this site sits in.
10054
10272
  case OP_DISPATCH: {
10055
- out.push(code[ip + 1]);
10056
- if (code[ip + 3] >= 0) out.push(code[ip + 3]);
10273
+ out.push(ip + 1);
10274
+ if (code[ip + 3] >= 0) out.push(ip + 3);
10057
10275
  const n = code[ip + 5];
10058
- for (let i = 0; i < n; i++) out.push(code[ip + 6 + i]);
10276
+ for (let i = 0; i < n; i++) out.push(ip + 6 + i);
10059
10277
  return true;
10060
10278
  }
10061
10279
  case OP_SEQ:
10062
10280
  case OP_SEQV: {
10063
10281
  const n = code[ip + 1];
10064
- for (let i = 0; i < n; i++) out.push(code[ip + 2 + i]);
10282
+ for (let i = 0; i < n; i++) out.push(ip + 2 + i);
10065
10283
  return true;
10066
10284
  }
10067
10285
  case OP_SEQX: {
10068
10286
  const n = code[ip + 2];
10069
- for (let i = 0; i < n; i++) out.push(code[ip + 3 + i]);
10287
+ for (let i = 0; i < n; i++) out.push(ip + 3 + i);
10070
10288
  return true;
10071
10289
  }
10072
10290
  case OP_CHOICE: {
10073
10291
  const n = code[ip + 2];
10074
- for (let i = 0; i < n; i++) out.push(code[ip + 4 + i]);
10292
+ for (let i = 0; i < n; i++) out.push(ip + 4 + i);
10075
10293
  return true;
10076
10294
  }
10077
10295
  // Arms are stride-2 from `ip + 4` — the gate word sits beside each arm offset.
10078
10296
  case OP_GREEDY: {
10079
- out.push(code[ip + 1]);
10297
+ out.push(ip + 1);
10080
10298
  const n = code[ip + 2];
10081
- for (let i = 0; i < n; i++) out.push(code[ip + 4 + 2 * i]);
10299
+ for (let i = 0; i < n; i++) out.push(ip + 4 + 2 * i);
10082
10300
  return true;
10083
10301
  }
10084
10302
  case OP_REP:
10085
10303
  case OP_REPV:
10086
- out.push(code[ip + 1]);
10087
- if (code[ip + 4] >= 0) out.push(code[ip + 4]);
10304
+ out.push(ip + 1);
10305
+ if (code[ip + 4] >= 0) out.push(ip + 4);
10088
10306
  return true;
10089
10307
  default:
10090
10308
  return false;
@@ -10899,7 +11117,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
10899
11117
  const swapLegal = !cfg.trackLines;
10900
11118
  const hostCst = cfg.hostCst;
10901
11119
  const LOGS = (prog.triviaSpecs?.length ?? 0) > 0 || cfg.inheritedTrivia === true;
10902
- const REC = prog.rec === 1 && cfg.tolerant;
11120
+ const REC2 = prog.rec === 1 && cfg.tolerant;
10903
11121
  if (cfg.coverage) throw new Unemittable("a coverage assembly");
10904
11122
  const roots = [...Object.values(prog.rules), ...extraIps];
10905
11123
  const reachable = [...reachableSites(code, roots)];
@@ -10972,7 +11190,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
10972
11190
  const op = code[ip];
10973
11191
  sinkBits.set(
10974
11192
  ip,
10975
- op === OP_SCAN || !scanSinkNeutral && op === OP_LEX_PROGRAM && t2.lexPrograms[code[ip + 1]].scan !== void 0 ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
11193
+ op === OP_SCAN || !scanSinkNeutral && op === OP_LEX_PROGRAM && t2.lexPrograms[code[ip + 1]].scan !== void 0 ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC2 && (op === OP_REP || op === OP_REPV) ? 2 : 0)
10976
11194
  );
10977
11195
  }
10978
11196
  const sinkKids = [];
@@ -11497,7 +11715,7 @@ if(v!==FAIL)return v
11497
11715
  const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "new _SP(pos,pos)"},expected:${xf}}
11498
11716
  const es=ctx._errors
11499
11717
  if(es!==undefined)es.push(err)
11500
- ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
11718
+ ${REC2 ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
11501
11719
  EC.e=pos
11502
11720
  return err
11503
11721
  }`;
@@ -11627,7 +11845,7 @@ return v
11627
11845
  }
11628
11846
  case OP_LEX_PROGRAM: {
11629
11847
  const programId = code[ip + 1];
11630
- const run = hoist("lexProgram", `LEXPROG[${programId}]`);
11848
+ const run2 = hoist("lexProgram", `LEXPROG[${programId}]`);
11631
11849
  const scanId = t2.lexPrograms[programId].scan;
11632
11850
  if (scanId !== void 0) return `${head}
11633
11851
  const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan
@@ -11645,7 +11863,7 @@ ctx._cstTriviaLog=undefined
11645
11863
  ctx._triviaLog=undefined
11646
11864
  ctx._rootTriviaLog=undefined
11647
11865
  let e
11648
- try{e=${run}(input,pos,ctx,SCANS[${scanId}])}finally{
11866
+ try{e=${run2}(input,pos,ctx,SCANS[${scanId}])}finally{
11649
11867
  _pfScan=sScan
11650
11868
  ctx.trivia=sTri
11651
11869
  ctx.triviaKindLabels=sKinds
@@ -11664,7 +11882,7 @@ EC.e=e
11664
11882
  return v
11665
11883
  }`;
11666
11884
  return `${head}
11667
- const e=${run}(input,pos,ctx)
11885
+ const e=${run2}(input,pos,ctx)
11668
11886
  if(e<0)return FAIL
11669
11887
  const v=input.slice(pos,e)
11670
11888
  if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,new _LF(v,new _SP(pos,e)))
@@ -11675,7 +11893,7 @@ return v
11675
11893
  /* ── transaction ─────────────────────────────────────────────────────── */
11676
11894
  case OP_ATTEMPT: {
11677
11895
  const child = link(code[ip + 1]);
11678
- const clean = !REC && failureRollbackClean(prog, ip);
11896
+ const clean = !REC2 && failureRollbackClean(prog, ip);
11679
11897
  const logs = clean && LOGS && failureLogRollback(prog, ip);
11680
11898
  const p = tmp();
11681
11899
  return `${head}
@@ -11741,7 +11959,7 @@ return null
11741
11959
  }
11742
11960
  case OP_OPT: {
11743
11961
  const child = link(code[ip + 1]);
11744
- const clean = !REC && failureRollbackClean(prog, ip);
11962
+ const clean = !REC2 && failureRollbackClean(prog, ip);
11745
11963
  const logs = clean && LOGS && failureLogRollback(prog, ip);
11746
11964
  const p = tmp();
11747
11965
  return `${head}
@@ -11772,15 +11990,15 @@ return v
11772
11990
  const childIp = code[base + i];
11773
11991
  kids.push(code[childIp] === OP_ADJ ? "" : link(childIp));
11774
11992
  }
11775
- const sy = REC ? `${tmp()}sy` : "";
11993
+ const sy = REC2 ? `${tmp()}sy` : "";
11776
11994
  const pub = (i) => {
11777
11995
  const s = sentRef(code[base + n + i]);
11778
11996
  return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
11779
11997
  };
11780
11998
  const parts = [head];
11781
- if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
11999
+ if (REC2) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
11782
12000
  parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
11783
- const close = () => REC ? `${parts.join("\n")}
12001
+ const close = () => REC2 ? `${parts.join("\n")}
11784
12002
  }finally{ctx._sync=${sy}}
11785
12003
  }` : `${parts.join("\n")}
11786
12004
  }`;
@@ -11793,7 +12011,7 @@ return v
11793
12011
  for (let i = 1; i < n; i++) {
11794
12012
  const vn = `v${i}`;
11795
12013
  parts.push(`let ${vn}`);
11796
- if (REC) parts.push(pub(i));
12014
+ if (REC2) parts.push(pub(i));
11797
12015
  const childIp = code[base + i];
11798
12016
  if (code[childIp] === OP_ADJ) {
11799
12017
  const negated = code[childIp + 1] === 1;
@@ -11898,7 +12116,7 @@ return FAIL
11898
12116
  if (maskable) maskPlan.push(~di);
11899
12117
  const p = tmp();
11900
12118
  const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
11901
- const rollbackMask = REC ? -1 : encodedRollbackMask;
12119
+ const rollbackMask = REC2 ? -1 : encodedRollbackMask;
11902
12120
  const hasRollback = rollbackMask !== 0;
11903
12121
  const logMask = rollbackMask === -1 || !LOGS ? 0 : choiceLogRollbackMask(prog, ip);
11904
12122
  const choiceMark = hasRollback ? emitMark(p, L.buf, L.raw, sinks) : "";
@@ -12151,7 +12369,7 @@ return [key,v]
12151
12369
  const collect = op === OP_REP;
12152
12370
  let itemCls;
12153
12371
  let itemAscii = false;
12154
- if (!REC) {
12372
+ if (!REC2) {
12155
12373
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
12156
12374
  if (itemClassIndex >= 0) {
12157
12375
  const resolved = t2.cc[itemClassIndex];
@@ -12164,14 +12382,14 @@ return [key,v]
12164
12382
  const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
12165
12383
  let sepCls;
12166
12384
  let sepAscii = false;
12167
- if (!REC && sepIp >= 0 && (code[ip + 5] & 8) !== 0 && !leadingTriviaFieldAt(code, k, sepIp) && !rowNullable(code, k, sepIp, nullable2)) {
12385
+ if (!REC2 && sepIp >= 0 && (code[ip + 5] & 8) !== 0 && !leadingTriviaFieldAt(code, k, sepIp) && !rowNullable(code, k, sepIp, nullable2)) {
12168
12386
  const resolved = t2.cc[code[ip + 8]];
12169
12387
  const ci = classes.push([resolved]) - 1;
12170
12388
  classPlan.push([code[ip + 8]]);
12171
12389
  sepCls = hoist("rs", `CLS[${ci}][0]`);
12172
12390
  sepAscii = isAsciiOnlyClass(resolved);
12173
12391
  }
12174
- const gapIp = !gapNeutral && sepIp < 0 && min === 0 && !REC && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
12392
+ const gapIp = !gapNeutral && sepIp < 0 && min === 0 && !REC2 && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
12175
12393
  let gapCode = (_rb) => "";
12176
12394
  if (gapIp >= 0) {
12177
12395
  const row = code[gapIp + 2];
@@ -12256,11 +12474,11 @@ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
12256
12474
  ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
12257
12475
  }`;
12258
12476
  const my = `${p}my`;
12259
- const recFx = !REC ? "" : (flags & 16) !== 0 ? "[]" : fxRef(code[ip + 6]);
12260
- const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
12477
+ const recFx = !REC2 ? "" : (flags & 16) !== 0 ? "[]" : fxRef(code[ip + 6]);
12478
+ const sepSent = REC2 ? sentRef(code[ip + 7]) : "undefined";
12261
12479
  const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
12262
12480
  const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
12263
- const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
12481
+ const recBranch = !REC2 ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
12264
12482
  ${sep === void 0 ? `${rb}
12265
12483
  ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
12266
12484
  ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
@@ -12271,7 +12489,7 @@ continue
12271
12489
  `;
12272
12490
  return `${head}
12273
12491
  const out=${collect ? "[]" : "undefined"}
12274
- ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
12492
+ ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC2 ? `const ${my}=ctx._sync
12275
12493
  ` : ""}${itemCls === void 0 && sepCls === void 0 ? "" : `const ${p}gate=ctx._probe===undefined
12276
12494
  `}let cur=pos
12277
12495
  let count=0
@@ -12314,7 +12532,7 @@ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
12314
12532
  `}${gapCode(rb)}ctx._fc=false
12315
12533
  const v=${child}(input,itemStart,ctx)
12316
12534
  ${gapIp >= 0 ? "if(gapped)GAP.at=-1\n" : ""}if(v===FAIL){
12317
- ${REC ? `if(ctx._fc===true){
12535
+ ${REC2 ? `if(ctx._fc===true){
12318
12536
  ${rb}
12319
12537
  return FAIL
12320
12538
  }
@@ -12540,13 +12758,13 @@ return nd
12540
12758
  }
12541
12759
  }
12542
12760
  const served = (ip) => select === void 0 || select.has(resolveAlias(ip));
12543
- const ruleEntries = [];
12761
+ const ruleEntries2 = [];
12544
12762
  for (const [rname, entryIp] of Object.entries(prog.rules)) {
12545
12763
  if (!served(entryIp)) continue;
12546
12764
  const target = link(entryIp);
12547
12765
  const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
12548
12766
  bodies.push(`const ${rn}=${target}`);
12549
- ruleEntries.push(`${q(rname)}:${rn}`);
12767
+ ruleEntries2.push(`${q(rname)}:${rn}`);
12550
12768
  }
12551
12769
  const extra = [];
12552
12770
  const exported = /* @__PURE__ */ new Set();
@@ -12612,7 +12830,7 @@ _pfHost=prior[1]
12612
12830
  EC.e=prior[2]
12613
12831
  }
12614
12832
  return{
12615
- pieces:{${ruleEntries.join(",")}},
12833
+ pieces:{${ruleEntries2.join(",")}},
12616
12834
  byIp:{${extra.join(",")}},
12617
12835
  end:function(){return EC.e},
12618
12836
  begin:_begin,
@@ -12721,31 +12939,31 @@ function lines(prefix, body, options = {}) {
12721
12939
  _def: { tag: "lines", prefix, body, ...first === void 0 ? {} : { first }, ...lazy === void 0 ? {} : { lazy } },
12722
12940
  parse(input, pos, ctx) {
12723
12941
  const c = ctx;
12724
- const probe = createDetachedParseContext(false, ctx.state);
12725
- probe.lineView = c.lineView;
12726
- const run = [];
12942
+ const probe2 = createDetachedParseContext(false, ctx.state);
12943
+ probe2.lineView = c.lineView;
12944
+ const run2 = [];
12727
12945
  const parts = [];
12728
12946
  let offset = 0;
12729
12947
  for (let start = pos; start < input.length || start === pos; ) {
12730
12948
  let end2 = input.indexOf("\n", start);
12731
12949
  if (end2 < 0) end2 = input.length;
12732
- probe._columnsSplit = void 0;
12733
- const head = (run.length === 0 ? opening : prefix).parse(input, start, probe);
12950
+ probe2._columnsSplit = void 0;
12951
+ const head = (run2.length === 0 ? opening : prefix).parse(input, start, probe2);
12734
12952
  let content;
12735
12953
  let joined;
12736
12954
  if (head.ok && head.span.end <= end2) {
12737
12955
  content = head.span.end;
12738
12956
  joined = "prefix";
12739
- } else if (run.length === 0) {
12957
+ } else if (run2.length === 0) {
12740
12958
  return { ok: false, expected: head.ok ? ["line prefix"] : head.expected, span: { start, end: start } };
12741
- } else if (lazy !== void 0 && lazy.parse(input, start, probe).ok) {
12959
+ } else if (lazy !== void 0 && lazy.parse(input, start, probe2).ok) {
12742
12960
  content = start;
12743
12961
  joined = "lazy";
12744
12962
  } else break;
12745
- const mark = probe._columnsSplit;
12963
+ const mark = probe2._columnsSplit;
12746
12964
  const here = columnAt(input, content, c);
12747
12965
  const split = joined === "prefix" && mark !== void 0 && mark.at === content ? mark.split : here.split;
12748
- run.push({ offset, source: content, end: end2, column: here.column + (split - here.split), split, lazy: joined === "lazy" });
12966
+ run2.push({ offset, source: content, end: end2, column: here.column + (split - here.split), split, lazy: joined === "lazy" });
12749
12967
  const text = input.slice(content, end2);
12750
12968
  const newline = end2 < input.length;
12751
12969
  parts.push(newline ? `${text}
@@ -12754,11 +12972,11 @@ function lines(prefix, body, options = {}) {
12754
12972
  start = end2 + 1;
12755
12973
  if (!newline) break;
12756
12974
  }
12757
- const view = { lines: run, parent: c.lineView };
12975
+ const view = { lines: run2, parent: c.lineView };
12758
12976
  const saved = c.lineView, starts = c._lineStarts, lineIndex = c._lineIndex, scanned = c._lineScannedTo, probing = c._probe;
12759
12977
  const errors = c._errors?.length ?? 0;
12760
12978
  let cursor = -1;
12761
- if (probing !== void 0) for (const line2 of run) {
12979
+ if (probing !== void 0) for (const line2 of run2) {
12762
12980
  if (probing.offset >= line2.source && probing.offset <= line2.end) {
12763
12981
  cursor = line2.offset + probing.offset - line2.source;
12764
12982
  break;
@@ -12791,8 +13009,8 @@ function lines(prefix, body, options = {}) {
12791
13009
  }
12792
13010
  const stop = result.span.end;
12793
13011
  const index = lineIndexAt(view, stop);
12794
- const line = run[index];
12795
- const end = stop === line.offset && index > 0 ? run[index - 1].end + 1 : stop - line.offset > line.end - line.source ? line.end + 1 : line.source + (stop - line.offset);
13012
+ const line = run2[index];
13013
+ const end = stop === line.offset && index > 0 ? run2[index - 1].end + 1 : stop - line.offset > line.end - line.source ? line.end + 1 : line.source + (stop - line.offset);
12796
13014
  recordLineRangeFromContext(c, input, pos, end);
12797
13015
  return { ok: true, value: result.value, span: { start: pos, end } };
12798
13016
  }
@@ -12901,12 +13119,12 @@ function literal(value, opts = {}) {
12901
13119
  }
12902
13120
 
12903
13121
  // src/combinators/ref.ts
12904
- function withRuleTrivia(trivia2, ctx, run) {
13122
+ function withRuleTrivia(trivia2, ctx, run2) {
12905
13123
  const savedLabels = ctx.triviaKindLabels;
12906
13124
  ctx.trivia = trivia2;
12907
13125
  ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
12908
13126
  try {
12909
- return run();
13127
+ return run2();
12910
13128
  } finally {
12911
13129
  ctx.trivia = void 0;
12912
13130
  ctx.triviaKindLabels = savedLabels;
@@ -13285,9 +13503,6 @@ function clearOf(ranges, input, from, to) {
13285
13503
  return true;
13286
13504
  }
13287
13505
 
13288
- // src/version.ts
13289
- var PARSEMAN_VERSION = "0.60.6";
13290
-
13291
13506
  // src/table/assemble.ts
13292
13507
  import { PlainBuf as PlainBuf2, PlainField, PlainLeaf as PlainLeaf9, PlainNode as PlainNode2, PlainSpan as PlainSpan10 } from "../cst/plain.js";
13293
13508
 
@@ -13411,6 +13626,19 @@ function failCleanAnalysis(code) {
13411
13626
  // src/cst/host-mode.ts
13412
13627
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
13413
13628
  var FUSED_HOST_ELIDED = /* @__PURE__ */ Symbol.for("parseman.fusedHostElided");
13629
+ function assertHostModeCompatible(mode, build, hostBranchElided = true) {
13630
+ const isCstHost = build?._parsemanCstOutput === true;
13631
+ if (mode === "ast" && isCstHost && hostBranchElided) {
13632
+ throw new Error(
13633
+ "parseman: this parser was compiled for host mode \"ast\" (the default), so its nodes build through their own `build` callbacks and no positioned-CST branch was emitted. It cannot be driven with a positioned-CST host (cstBuildHost / a language-service host). Compile a second artifact from the SAME grammar with `compile(grammar, { hostMode: 'cst' })` \u2014 or, under the macro, a second `rules({ hostMode: 'cst' }, factory)` call site \u2014 and drive that one instead."
13634
+ );
13635
+ }
13636
+ if (mode === "cst" && !isCstHost) {
13637
+ throw new Error(
13638
+ 'parseman: this parser was compiled for host mode "cst", so every node builds through a positioned-CST `ctx.build` host. Pass one (e.g. `{ build: cstBuildHost }`), or use an artifact compiled with the default `hostMode: "ast"` to get the grammar\'s own AST.'
13639
+ );
13640
+ }
13641
+ }
13414
13642
 
13415
13643
  // src/grammar-metadata.ts
13416
13644
  var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
@@ -13545,8 +13773,8 @@ function linkMatcher(m) {
13545
13773
  }
13546
13774
  var NO_COVERAGE = (_id) => {
13547
13775
  };
13548
- function cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe, hostReadsChildren = true, inheritedTrivia = false) {
13549
- return (hostCst ? 1 : 0) | (trackLines ? 2 : 0) | (tolerant ? 4 : 0) | (coverage ? 8 : 0) | (probe ? 16 : 0) | (hostReadsChildren ? 0 : 32) | (inheritedTrivia ? 64 : 0);
13776
+ function cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe2, hostReadsChildren = true, inheritedTrivia = false) {
13777
+ return (hostCst ? 1 : 0) | (trackLines ? 2 : 0) | (tolerant ? 4 : 0) | (coverage ? 8 : 0) | (probe2 ? 16 : 0) | (hostReadsChildren ? 0 : 32) | (inheritedTrivia ? 64 : 0);
13550
13778
  }
13551
13779
  function cfgKey(c) {
13552
13780
  return cfgKeyOf(c.hostCst, c.trackLines, c.tolerant, c.coverage, c.probe, c.hostReadsChildren, c.inheritedTrivia);
@@ -13563,7 +13791,7 @@ function assemble(t2, prog, cfg) {
13563
13791
  const triviaScan = t2.triviaScan;
13564
13792
  const swapLegal = !cfg.trackLines;
13565
13793
  const hostCst = cfg.hostCst;
13566
- const REC = prog.rec === 1 && cfg.tolerant;
13794
+ const REC2 = prog.rec === 1 && cfg.tolerant;
13567
13795
  const PROBE = cfg.probe;
13568
13796
  const sentinels = /* @__PURE__ */ new Map();
13569
13797
  function sentinelFor(cls) {
@@ -13613,7 +13841,7 @@ function assemble(t2, prog, cfg) {
13613
13841
  const memo = /* @__PURE__ */ new Map();
13614
13842
  const reached = /* @__PURE__ */ new Set();
13615
13843
  const NULLABLE = /* @__PURE__ */ new Map();
13616
- const CLEAN = REC ? () => false : failCleanAnalysis(code);
13844
+ const CLEAN = REC2 ? () => false : failCleanAnalysis(code);
13617
13845
  function pushLeaf(ctx, value, s, e) {
13618
13846
  const lf = new PlainLeaf9(value, new PlainSpan10(s, e));
13619
13847
  pushCstLeaf(ctx, lf);
@@ -14324,7 +14552,7 @@ function assemble(t2, prog, cfg) {
14324
14552
  };
14325
14553
  function lookaheadLedNode(ip) {
14326
14554
  const op = code[ip];
14327
- if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
14555
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC2 || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
14328
14556
  if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
14329
14557
  const body = code[ip + 2];
14330
14558
  const bop = code[body];
@@ -14700,7 +14928,7 @@ function assemble(t2, prog, cfg) {
14700
14928
  const child = link(code[ip + 1]);
14701
14929
  const xf = fx[code[ip + 2]];
14702
14930
  const expectSpan = (ctx, pos) => prog.lines === 1 ? spanLines(ctx, pos, pos) : new PlainSpan10(pos, pos);
14703
- if (REC) {
14931
+ if (REC2) {
14704
14932
  return (input, pos, ctx) => {
14705
14933
  const v = child(input, pos, ctx);
14706
14934
  if (v !== FAIL) return v;
@@ -15097,8 +15325,8 @@ function assemble(t2, prog, cfg) {
15097
15325
  };
15098
15326
  }
15099
15327
  case OP_LEX_PROGRAM: {
15100
- const run = t2.lexPrograms[code[ip + 1]];
15101
- const scanId = run.scan;
15328
+ const run2 = t2.lexPrograms[code[ip + 1]];
15329
+ const scanId = run2.scan;
15102
15330
  if (scanId !== void 0) {
15103
15331
  return (input, pos, ctx) => {
15104
15332
  const sTrivia = ctx.trivia, sKinds = ctx.triviaKindLabels;
@@ -15119,7 +15347,7 @@ function assemble(t2, prog, cfg) {
15119
15347
  ctx._rootTriviaLog = void 0;
15120
15348
  let end;
15121
15349
  try {
15122
- end = run(input, pos, ctx, scans[scanId]);
15350
+ end = run2(input, pos, ctx, scans[scanId]);
15123
15351
  } finally {
15124
15352
  SCAN = sScan;
15125
15353
  ctx.trivia = sTrivia;
@@ -15140,7 +15368,7 @@ function assemble(t2, prog, cfg) {
15140
15368
  };
15141
15369
  }
15142
15370
  return (input, pos, ctx) => {
15143
- const end = run(input, pos, ctx);
15371
+ const end = run2(input, pos, ctx);
15144
15372
  if (end < 0) return FAIL;
15145
15373
  const value = input.slice(pos, end);
15146
15374
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, new PlainLeaf9(value, new PlainSpan10(pos, end)));
@@ -15241,7 +15469,7 @@ function assemble(t2, prog, cfg) {
15241
15469
  return next === void 0 ? cur : next(input, cur, ctx, values, inherited);
15242
15470
  };
15243
15471
  };
15244
- if (REC) {
15472
+ if (REC2) {
15245
15473
  const first2 = linkFirst();
15246
15474
  const firstSync = sentinelFor(code[base + n]);
15247
15475
  const runnerAt = (i) => {
@@ -15730,7 +15958,7 @@ function assemble(t2, prog, cfg) {
15730
15958
  if (n === 2 || n === 3) {
15731
15959
  const a0 = link(code[base]), a1 = link(code[base + 1]);
15732
15960
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
15733
- const predecide = !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
15961
+ const predecide = !REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines;
15734
15962
  const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
15735
15963
  const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
15736
15964
  const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
@@ -15960,7 +16188,7 @@ function assemble(t2, prog, cfg) {
15960
16188
  const masked = bindMasked(0, EMPTY_EXPECTED_PREFIX);
15961
16189
  const pBit = [];
15962
16190
  const pRec = [];
15963
- if (!REC && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
16191
+ if (!REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
15964
16192
  for (let i = 0; i < n; i++) {
15965
16193
  for (const terminal of largeChoiceLiteralPretest(code, k, code[base + i]) ?? []) {
15966
16194
  pBit.push(1 << i);
@@ -16248,18 +16476,18 @@ function assemble(t2, prog, cfg) {
16248
16476
  const itemFx = reportItem ? fx[code[ip + 6]] : EMPTY_FX2;
16249
16477
  const collect = op === OP_REP;
16250
16478
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
16251
- const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
16479
+ const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
16252
16480
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
16253
16481
  const sepClassIndex = sepIp >= 0 && !sepLeads && (flags & 8) !== 0 ? code[ip + 8] : -1;
16254
- const sepClass = !REC && sepClassIndex >= 0 && !rowNullable(code, k, sepIp, NULLABLE) ? cc[sepClassIndex] : void 0;
16255
- const gapIp = sepIp < 0 && min === 0 && !REC && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
16482
+ const sepClass = !REC2 && sepClassIndex >= 0 && !rowNullable(code, k, sepIp, NULLABLE) ? cc[sepClassIndex] : void 0;
16483
+ const gapIp = sepIp < 0 && min === 0 && !REC2 && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
16256
16484
  const gapRow = gapIp >= 0 ? code[gapIp + 2] : -1;
16257
16485
  const gapRe = gapIp >= 0 ? k[code[gapRow + 1]] : void 0;
16258
16486
  const gapFollow = gapIp >= 0 ? cc[code[gapIp + 3]] : void 0;
16259
16487
  const gapOther = gapIp >= 0 && code[gapIp + 4] >= 0 ? cc[code[gapIp + 4]] : void 0;
16260
16488
  const skipBeforeFirst = sepIp < 0 && min === 0;
16261
16489
  const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
16262
- if (REC) {
16490
+ if (REC2) {
16263
16491
  const itemFx2 = fx[code[ip + 6]];
16264
16492
  const recFx = (flags & 16) !== 0 ? EMPTY_FX2 : itemFx2;
16265
16493
  const sepSent = sentinelFor(code[ip + 7]);
@@ -16469,10 +16697,10 @@ function assemble(t2, prog, cfg) {
16469
16697
  const hasFold = spec.byFold.size > 0;
16470
16698
  const match = spec.match;
16471
16699
  const matchN = match.length;
16472
- const routed = spec.routed;
16700
+ const routed2 = spec.routed;
16473
16701
  const expected = spec.expected;
16474
16702
  const validArm = (arm) => Number.isInteger(arm) && arm >= 0 && arm < n;
16475
- if (routed.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
16703
+ if (routed2.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
16476
16704
  for (const arm of byKey.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch exact arm");
16477
16705
  for (const arm of byFold.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch folded arm");
16478
16706
  for (const m of match) if (!validArm(m[3])) throw new TypeError("table assembler: malformed dispatch matcher arm");
@@ -16497,7 +16725,7 @@ function assemble(t2, prog, cfg) {
16497
16725
  const classify = hasFold ? matchBlock === void 0 ? (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) : (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) ?? matchBlock(key) : matchBlock === void 0 ? (key) => byKey.get(key) : (key) => byKey.get(key) ?? matchBlock(key);
16498
16726
  const neverBranch = () => FAIL;
16499
16727
  const bindArms = (start) => {
16500
- const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed[i] === 1) : neverBranch;
16728
+ const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed2[i] === 1) : neverBranch;
16501
16729
  const next = start + 4 < n ? bindArms(start + 4) : void 0;
16502
16730
  return dispatchArmBlock(
16503
16731
  start,
@@ -16812,7 +17040,7 @@ function assemble(t2, prog, cfg) {
16812
17040
  lead,
16813
17041
  asciiFoldKey,
16814
17042
  ROUTED_FX,
16815
- REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
17043
+ REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
16816
17044
  matchesAt,
16817
17045
  recoverScan,
16818
17046
  orSentinel,
@@ -16901,7 +17129,7 @@ function assemble(t2, prog, cfg) {
16901
17129
  // — a strict one emits no reader — and through the SAME `sentinelFor` memo
16902
17130
  // the closure pieces use, so both engines resync to the same combinator
16903
17131
  // object rather than to two separately constructed ones.
16904
- REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
17132
+ REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
16905
17133
  matchesAt,
16906
17134
  recoverScan,
16907
17135
  orSentinel,
@@ -17116,9 +17344,9 @@ var AssemblyCache = class {
17116
17344
  const trackLines = ctx.trackLines === true;
17117
17345
  const tolerant = ctx._tolerant === true;
17118
17346
  const coverage = ctx._grammarCoverage !== void 0;
17119
- const probe = ctx._probe !== void 0;
17347
+ const probe2 = ctx._probe !== void 0;
17120
17348
  const inheritedTrivia = this.noOwnTrivia && ctx.trivia !== void 0;
17121
- const key = cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe, hostReadsChildren, inheritedTrivia);
17349
+ const key = cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe2, hostReadsChildren, inheritedTrivia);
17122
17350
  let cache = this.byCfg;
17123
17351
  if (hostCaptureTrivia !== void 0) {
17124
17352
  if (this.hostPredicate === hostCaptureTrivia) {
@@ -17138,7 +17366,7 @@ var AssemblyCache = class {
17138
17366
  trackLines,
17139
17367
  tolerant,
17140
17368
  coverage,
17141
- probe,
17369
+ probe: probe2,
17142
17370
  inheritedTrivia
17143
17371
  });
17144
17372
  cache[key] = made;
@@ -17271,12 +17499,15 @@ function assertPrintable(prog, who) {
17271
17499
  }
17272
17500
  }
17273
17501
  function programFields(prog, fns, opts = {}) {
17502
+ const tokens = [...new Set(prog.fx.flat())];
17503
+ const tokenAt = new Map(tokens.map((token2, i) => [token2, i]));
17274
17504
  return [
17275
17505
  ...emitAssemblies(prog, opts.assemblies ?? []),
17276
17506
  `c:[${prog.code.join(",")}],`,
17277
17507
  `k:[${prog.k.map(emitConst).join(",")}],`,
17278
17508
  `x:${emitClassPool(prog.cc)},`,
17279
- `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
17509
+ `e:[${prog.fx.map((f) => `[${f.map((token2) => tokenAt.get(token2)).join(",")}]`).join(",")}],`,
17510
+ `es:[${tokens.map(jsString).join(",")}],`,
17280
17511
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
17281
17512
  `r:${JSON.stringify(prog.rules)},`,
17282
17513
  ...prog.lines === 1 ? ["l:1,"] : [],
@@ -18047,36 +18278,36 @@ function findRegexFragments(visited) {
18047
18278
  if (branches.length >= 2) runs.add(branches.join("|"));
18048
18279
  for (let i = 0; i < branches.length; i++) {
18049
18280
  for (let n = 2; n <= Math.min(MAX_RUN, branches.length - i); n++) {
18050
- const run = branches.slice(i, i + n).join("|");
18051
- if (run.length < 4) continue;
18052
- runs.add(run);
18281
+ const run2 = branches.slice(i, i + n).join("|");
18282
+ if (run2.length < 4) continue;
18283
+ runs.add(run2);
18053
18284
  }
18054
18285
  }
18055
18286
  }
18056
- for (const run of runs) {
18057
- let e = byRun.get(run);
18287
+ for (const run2 of runs) {
18288
+ let e = byRun.get(run2);
18058
18289
  if (e === void 0) {
18059
- e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run.split("|").length };
18060
- byRun.set(run, e);
18290
+ e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run2.split("|").length };
18291
+ byRun.set(run2, e);
18061
18292
  }
18062
18293
  if (e.nodes.has(v.p)) continue;
18063
18294
  e.nodes.add(v.p);
18064
18295
  e.occ.push({ site: v.site, source: d.source });
18065
18296
  }
18066
18297
  }
18067
- const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([run, e]) => ({ run, e, savings: (e.occ.length - 1) * run.length })).sort((a, b) => b.e.occ.length - a.e.occ.length || b.savings - a.savings || b.run.length - a.run.length);
18298
+ const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([run2, e]) => ({ run: run2, e, savings: (e.occ.length - 1) * run2.length })).sort((a, b) => b.e.occ.length - a.e.occ.length || b.savings - a.savings || b.run.length - a.run.length);
18068
18299
  const kept = [];
18069
18300
  for (const c of candidates) {
18070
18301
  if (kept.some((k) => k.e.occ.length >= c.e.occ.length && `|${k.run}|`.includes(`|${c.run}|`))) continue;
18071
18302
  kept.push(c);
18072
18303
  }
18073
- return kept.map(({ run, e }) => ({
18304
+ return kept.map(({ run: run2, e }) => ({
18074
18305
  kind: "regex-fragment",
18075
- id: `regex-fragment:${run}`,
18076
- fragment: run,
18306
+ id: `regex-fragment:${run2}`,
18307
+ fragment: run2,
18077
18308
  branches: e.branches,
18078
18309
  count: e.occ.length,
18079
- savings: (e.occ.length - 1) * run.length,
18310
+ savings: (e.occ.length - 1) * run2.length,
18080
18311
  sources: e.occ.map((o) => `/${o.source}/`),
18081
18312
  sites: e.occ.map((o) => o.site),
18082
18313
  suggestion: `this ${e.branches}-branch alternation is re-spelled in ${e.occ.length} DISTINCT regex() terminals. Hoist it to one shared source string and interpolate it (\`new RegExp(\\\`\u2026\\\${OP}\u2026\\\`)\`) or lift the shared part into its own terminal \u2014 an edit to the operator set currently has to land in ${e.occ.length} places, and the analysis cannot tell you when one of them drifts.`
@@ -18930,9 +19161,9 @@ function withAmbient(ruleMap, opts) {
18930
19161
  const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
18931
19162
  const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
18932
19163
  if (!addTrivia && !addScanSkip) return [name, rule2];
18933
- let wrapped = wrappers.get(rule2);
18934
- if (wrapped === void 0) {
18935
- wrapped = {
19164
+ let wrapped2 = wrappers.get(rule2);
19165
+ if (wrapped2 === void 0) {
19166
+ wrapped2 = {
18936
19167
  ...rule2,
18937
19168
  _meta: {
18938
19169
  ...rule2._meta,
@@ -18940,9 +19171,9 @@ function withAmbient(ruleMap, opts) {
18940
19171
  ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
18941
19172
  }
18942
19173
  };
18943
- wrappers.set(rule2, wrapped);
19174
+ wrappers.set(rule2, wrapped2);
18944
19175
  }
18945
- return [name, wrapped];
19176
+ return [name, wrapped2];
18946
19177
  });
18947
19178
  }
18948
19179
  function compileRuleMapRunnable(ruleMap, opts = {}) {
@@ -19124,7 +19355,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
19124
19355
  const emitOpts = { fnSources: sources };
19125
19356
  const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
19126
19357
  const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
19127
- const runOnce = (input, pos, ctx) => entry(input, pos, ctx);
19358
+ const runOnce2 = (input, pos, ctx) => entry(input, pos, ctx);
19128
19359
  return {
19129
19360
  source,
19130
19361
  inlineExpression,
@@ -19138,10 +19369,10 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
19138
19369
  // parser runs where a combinator does. A caller probing many positions
19139
19370
  // passes one context and pays for none per call.
19140
19371
  parse(input, pos = 0, ctx) {
19141
- return runOnce(input, pos, ctx ?? createParseContext());
19372
+ return runOnce2(input, pos, ctx ?? createParseContext());
19142
19373
  },
19143
19374
  parseWithContext(input, parseCtx, pos = 0) {
19144
- return runOnce(input, pos, parseCtx);
19375
+ return runOnce2(input, pos, parseCtx);
19145
19376
  },
19146
19377
  /**
19147
19378
  * NO LONGER REFUSES. It used to throw unless the caller passed
@@ -19157,7 +19388,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
19157
19388
  const errors = [];
19158
19389
  ctx._errors = errors;
19159
19390
  ctx._tolerant = true;
19160
- const r = runOnce(input, pos, ctx);
19391
+ const r = runOnce2(input, pos, ctx);
19161
19392
  return { ...r, errors };
19162
19393
  }
19163
19394
  };
@@ -19402,6 +19633,38 @@ function not(combinator) {
19402
19633
  };
19403
19634
  }
19404
19635
 
19636
+ // src/combinators/withCtx.ts
19637
+ function withCtx(extra, combinator) {
19638
+ const meta = {
19639
+ firstSet: combinator._meta.firstSet,
19640
+ canMatchNewline: combinator._meta.canMatchNewline,
19641
+ isTrivia: false
19642
+ };
19643
+ const parse2 = typeof extra === "function" ? (input, pos, ctx) => {
19644
+ const saved = ctx.state;
19645
+ ctx.state = extra(saved);
19646
+ try {
19647
+ return combinator.parse(input, pos, ctx);
19648
+ } finally {
19649
+ ctx.state = saved;
19650
+ }
19651
+ } : (input, pos, ctx) => {
19652
+ const saved = ctx.state;
19653
+ ctx.state = extra;
19654
+ try {
19655
+ return combinator.parse(input, pos, ctx);
19656
+ } finally {
19657
+ ctx.state = saved;
19658
+ }
19659
+ };
19660
+ return {
19661
+ _tag: "withCtx",
19662
+ _meta: meta,
19663
+ _def: { tag: "withCtx", extra, parser: combinator },
19664
+ parse: parse2
19665
+ };
19666
+ }
19667
+
19405
19668
  // src/analysis/rebuild.ts
19406
19669
  var FROZEN_TAGS = /* @__PURE__ */ new Set([
19407
19670
  "dispatch",
@@ -19415,6 +19678,7 @@ var FROZEN_TAGS = /* @__PURE__ */ new Set([
19415
19678
  "lines",
19416
19679
  "columns"
19417
19680
  ]);
19681
+ var THAWED_TAGS = /* @__PURE__ */ new Set(["dispatch", "withCtx", "routed", "guard"]);
19418
19682
  var CARRIED_META = [
19419
19683
  "grammarTrivia",
19420
19684
  "grammarScanSkip",
@@ -19453,7 +19717,9 @@ function subtreeContains(p, targets) {
19453
19717
  walk(p);
19454
19718
  return hit;
19455
19719
  }
19456
- function rebuildCombinator(root, replacements) {
19720
+ function rebuildCombinator(root, replacements, options = {}) {
19721
+ const thaw = options.thaw === true;
19722
+ const after = options.after ?? ((_p, out) => out);
19457
19723
  const memo = /* @__PURE__ */ new Map();
19458
19724
  const frozenKeys = /* @__PURE__ */ new Set();
19459
19725
  const frozen = [];
@@ -19473,15 +19739,16 @@ function rebuildCombinator(root, replacements) {
19473
19739
  return p;
19474
19740
  }
19475
19741
  const here = p._ruleName ?? rule2;
19476
- if (FROZEN_TAGS.has(d.tag)) {
19742
+ if (FROZEN_TAGS.has(d.tag) && !(thaw && THAWED_TAGS.has(d.tag))) {
19477
19743
  const key = JSON.stringify([here, d.tag]);
19478
19744
  if (!frozenKeys.has(key)) {
19479
19745
  frozenKeys.add(key);
19480
19746
  frozen.push({ tag: d.tag, rule: here });
19481
19747
  }
19482
19748
  for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
19483
- memo.set(p, p);
19484
- return p;
19749
+ const kept = after(p, p);
19750
+ memo.set(p, kept);
19751
+ return kept;
19485
19752
  }
19486
19753
  if (d.tag === "lazy") {
19487
19754
  let target;
@@ -19518,6 +19785,14 @@ function rebuildCombinator(root, replacements) {
19518
19785
  break;
19519
19786
  }
19520
19787
  case "choice": {
19788
+ if (d.gates.some((g) => g !== null) && thaw) {
19789
+ const unsafeChoice = choice;
19790
+ out = unsafeChoice(...d.parsers.map((arm, i) => {
19791
+ const gate = d.gates[i];
19792
+ return gate ? { combinator: one(arm), gate } : one(arm);
19793
+ }));
19794
+ break;
19795
+ }
19521
19796
  if (d.gates.some((g) => g !== null)) {
19522
19797
  const key = JSON.stringify([here, "choice(gated)"]);
19523
19798
  if (!frozenKeys.has(key)) {
@@ -19525,8 +19800,9 @@ function rebuildCombinator(root, replacements) {
19525
19800
  frozen.push({ tag: "choice(gated)", rule: here });
19526
19801
  }
19527
19802
  for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
19528
- memo.set(p, p);
19529
- return p;
19803
+ const kept = after(p, p);
19804
+ memo.set(p, kept);
19805
+ return kept;
19530
19806
  }
19531
19807
  const kids = d.parsers.map(one);
19532
19808
  out = choice(...kids);
@@ -19604,13 +19880,33 @@ function rebuildCombinator(root, replacements) {
19604
19880
  frozen.push({ tag: "node(untyped+build+opts)", rule: here });
19605
19881
  }
19606
19882
  for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
19607
- memo.set(p, p);
19608
- return p;
19883
+ const kept = after(p, p);
19884
+ memo.set(p, kept);
19885
+ return kept;
19609
19886
  }
19610
19887
  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);
19611
19888
  if (d.buildRawUnused === true && out._def.tag === "node") out._def.buildRawUnused = true;
19612
19889
  break;
19613
19890
  }
19891
+ case "dispatch": {
19892
+ const arms = d.cases.map((e) => when(e.keys, one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
19893
+ for (const e of d.matchers ?? []) {
19894
+ arms.push(when(dispatchMatcher(e), one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
19895
+ }
19896
+ if (d.otherwise) arms.push(otherwise(one(d.otherwise), d.otherwiseCommit === false ? { commit: false } : void 0));
19897
+ const unsafeDispatch = dispatch;
19898
+ out = unsafeDispatch(one(d.selector), ...arms);
19899
+ break;
19900
+ }
19901
+ case "withCtx":
19902
+ out = withCtx(d.extra, one(d.parser));
19903
+ break;
19904
+ case "routed":
19905
+ out = d.fallback === void 0 ? routed() : routed(one(d.fallback));
19906
+ break;
19907
+ case "guard":
19908
+ out = p;
19909
+ break;
19614
19910
  case "grammar": {
19615
19911
  const inner = one(d.parser);
19616
19912
  out = parser({
@@ -19628,13 +19924,15 @@ function rebuildCombinator(root, replacements) {
19628
19924
  frozen.push({ tag: d.tag, rule: here });
19629
19925
  }
19630
19926
  for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
19631
- memo.set(p, p);
19632
- return p;
19927
+ const kept = after(p, p);
19928
+ memo.set(p, kept);
19929
+ return kept;
19633
19930
  }
19634
19931
  }
19635
19932
  carryStamps(p, out);
19636
- memo.set(p, out);
19637
- return out;
19933
+ const done = after(p, out);
19934
+ memo.set(p, done);
19935
+ return done;
19638
19936
  };
19639
19937
  const rebuilt = go(root, root._ruleName ?? "<entry>");
19640
19938
  frozen.sort((a, b) => a.rule < b.rule ? -1 : a.rule > b.rule ? 1 : a.tag < b.tag ? -1 : a.tag > b.tag ? 1 : 0);
@@ -20871,9 +21169,715 @@ function measureChoiceCost(c, samples, arms) {
20871
21169
  function armFirstSets(choiceArms2) {
20872
21170
  return choiceArms2.map((a) => ({ firstSet: firstSetOf(a) }));
20873
21171
  }
21172
+
21173
+ // src/cst/trivia-entries.ts
21174
+ var EMPTY_INDICES = Object.freeze([]);
21175
+ var EMPTY_GAPS = Object.freeze([]);
21176
+ var SELECTED_ROOT_STRIDE = 5;
21177
+ function buildRootTriviaIndex(log, labels) {
21178
+ const length = Math.floor(log.length / SELECTED_ROOT_STRIDE);
21179
+ const markerOffset = (i) => i * SELECTED_ROOT_STRIDE;
21180
+ const ownedRangeStart = (i) => log[markerOffset(i)];
21181
+ const ownedRangeEnd = (i) => log[markerOffset(i) + 1];
21182
+ const markerStart = (i) => log[markerOffset(i) + 2];
21183
+ const markerEnd = (i) => log[markerOffset(i) + 3];
21184
+ const markerKind = (i) => log[markerOffset(i) + 4];
21185
+ const entries = {
21186
+ length,
21187
+ labels,
21188
+ stride: SELECTED_ROOT_STRIDE,
21189
+ start: markerStart,
21190
+ end: markerEnd,
21191
+ insertIndex: () => void 0,
21192
+ kindIndex: markerKind,
21193
+ kind(i) {
21194
+ return labels[markerKind(i)];
21195
+ },
21196
+ text(i, input) {
21197
+ return input.slice(markerStart(i), markerEnd(i));
21198
+ }
21199
+ };
21200
+ const lowerBound = (offset, by) => {
21201
+ let lo = 0;
21202
+ let hi = length;
21203
+ while (lo < hi) {
21204
+ const mid = lo + hi >>> 1;
21205
+ if (by(mid) < offset) lo = mid + 1;
21206
+ else hi = mid;
21207
+ }
21208
+ return lo;
21209
+ };
21210
+ const gapRowsAt = (offset, direction) => {
21211
+ const edge = direction === "before" ? ownedRangeEnd : ownedRangeStart;
21212
+ let first = lowerBound(offset, edge);
21213
+ if (first === length || edge(first) !== offset) return void 0;
21214
+ const start = ownedRangeStart(first);
21215
+ const end = ownedRangeEnd(first);
21216
+ while (first > 0 && ownedRangeStart(first - 1) === start && ownedRangeEnd(first - 1) === end) first--;
21217
+ let last = first + 1;
21218
+ while (last < length && ownedRangeStart(last) === start && ownedRangeEnd(last) === end) last++;
21219
+ return [first, last];
21220
+ };
21221
+ const indices = (first, last) => {
21222
+ const out = [];
21223
+ for (let i = first; i < last; i++) out.push(i);
21224
+ return out;
21225
+ };
21226
+ const makeGap = (first, last) => {
21227
+ const start = ownedRangeStart(first);
21228
+ const end = ownedRangeEnd(first);
21229
+ let entryIndices;
21230
+ return {
21231
+ start,
21232
+ end,
21233
+ get entryIndices() {
21234
+ return entryIndices ??= indices(first, last);
21235
+ },
21236
+ hasKind(kind) {
21237
+ for (let i = first; i < last; i++) {
21238
+ if (labels[markerKind(i)] === kind) return true;
21239
+ }
21240
+ return false;
21241
+ },
21242
+ text(input) {
21243
+ return input.slice(start, end);
21244
+ }
21245
+ };
21246
+ };
21247
+ let maps;
21248
+ const getMaps = () => {
21249
+ if (maps !== void 0) return maps;
21250
+ const before = /* @__PURE__ */ new Map();
21251
+ const after = /* @__PURE__ */ new Map();
21252
+ const beforeGaps = /* @__PURE__ */ new Map();
21253
+ const afterGaps = /* @__PURE__ */ new Map();
21254
+ const gaps = [];
21255
+ for (let first = 0; first < length; ) {
21256
+ let last = first + 1;
21257
+ while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
21258
+ const gap = makeGap(first, last);
21259
+ gaps.push(gap);
21260
+ afterGaps.set(gap.start, gap);
21261
+ beforeGaps.set(gap.end, gap);
21262
+ after.set(gap.start, [...gap.entryIndices]);
21263
+ before.set(gap.end, [...gap.entryIndices]);
21264
+ first = last;
21265
+ }
21266
+ maps = { before, after, beforeGaps, afterGaps, gaps };
21267
+ return maps;
21268
+ };
21269
+ return {
21270
+ entries,
21271
+ labels,
21272
+ get before() {
21273
+ return getMaps().before;
21274
+ },
21275
+ get after() {
21276
+ return getMaps().after;
21277
+ },
21278
+ entryIndicesBefore(offset) {
21279
+ const rows = gapRowsAt(offset, "before");
21280
+ return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
21281
+ },
21282
+ entryIndicesAfter(offset) {
21283
+ const rows = gapRowsAt(offset, "after");
21284
+ return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
21285
+ },
21286
+ gapBefore(offset) {
21287
+ const rows = gapRowsAt(offset, "before");
21288
+ return rows ? makeGap(rows[0], rows[1]) : void 0;
21289
+ },
21290
+ gapAfter(offset) {
21291
+ const rows = gapRowsAt(offset, "after");
21292
+ return rows ? makeGap(rows[0], rows[1]) : void 0;
21293
+ },
21294
+ gaps() {
21295
+ return getMaps().gaps;
21296
+ },
21297
+ gapsWithKind(kind) {
21298
+ const kinds = typeof kind === "string" ? [kind] : kind;
21299
+ const matches2 = [];
21300
+ for (let first = 0; first < length; ) {
21301
+ let last = first + 1;
21302
+ while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
21303
+ let matched = false;
21304
+ for (let i = first; i < last && !matched; i++) {
21305
+ const label2 = labels[markerKind(i)];
21306
+ for (const kind2 of kinds) {
21307
+ if (label2 === kind2) {
21308
+ matched = true;
21309
+ break;
21310
+ }
21311
+ }
21312
+ }
21313
+ if (matched) matches2.push(makeGap(first, last));
21314
+ first = last;
21315
+ }
21316
+ return matches2.length === 0 ? EMPTY_GAPS : matches2;
21317
+ }
21318
+ };
21319
+ }
21320
+
21321
+ // src/functional/run.ts
21322
+ var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
21323
+ var REMOVED_RUN_RESULT_FIELDS = [
21324
+ [
21325
+ "triviaMap",
21326
+ `It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
21327
+ ],
21328
+ [
21329
+ "triviaLog",
21330
+ `It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
21331
+ ],
21332
+ [
21333
+ "triviaKindLabels",
21334
+ `It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
21335
+ ]
21336
+ ];
21337
+ var RunResultRecord = class {
21338
+ constructor(ok, value, span, expected, errors, unconsumedFrom) {
21339
+ this.ok = ok;
21340
+ this.value = value;
21341
+ this.span = span;
21342
+ this.expected = expected;
21343
+ this.errors = errors;
21344
+ this.unconsumedFrom = unconsumedFrom;
21345
+ }
21346
+ };
21347
+ var RunResultWithRootTrivia = class {
21348
+ constructor(ok, value, span, expected, errors, rootTrivia, unconsumedFrom) {
21349
+ this.ok = ok;
21350
+ this.value = value;
21351
+ this.span = span;
21352
+ this.expected = expected;
21353
+ this.errors = errors;
21354
+ this.rootTrivia = rootTrivia;
21355
+ this.unconsumedFrom = unconsumedFrom;
21356
+ }
21357
+ };
21358
+ for (const proto of [RunResultRecord.prototype, RunResultWithRootTrivia.prototype]) {
21359
+ for (const [name, detail] of REMOVED_RUN_RESULT_FIELDS) {
21360
+ Object.defineProperty(proto, name, {
21361
+ configurable: true,
21362
+ enumerable: false,
21363
+ get() {
21364
+ throw new TypeError(
21365
+ `RunResult.${name} was REMOVED in parseman 0.44.0 and has no default replacement. ${detail}`
21366
+ );
21367
+ }
21368
+ });
21369
+ }
21370
+ }
21371
+ var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
21372
+ function ambientTriviaFromRunnable(r) {
21373
+ if (!r) return void 0;
21374
+ if (typeof r === "function") return r._meta?.grammarTrivia;
21375
+ if (r._meta.isTrivia) return void 0;
21376
+ return r._meta.grammarTrivia ?? (r._def.tag === "grammar" ? r._def.triviaParser : void 0);
21377
+ }
21378
+ function triviaKindLabelsFromRunnable(r) {
21379
+ if (!r) return void 0;
21380
+ if (typeof r === "function") return r._meta?.triviaKindLabels;
21381
+ const grammarTrivia = r._meta.grammarTrivia;
21382
+ return grammarTrivia?._meta.triviaKindLabels ?? r._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
21383
+ }
21384
+ function rootTriviaClassifiedFromRunnable(r) {
21385
+ if (!r) return false;
21386
+ if (typeof r === "function") return r._meta?.rootTriviaClassified === true;
21387
+ const grammarTrivia = r._meta.grammarTrivia;
21388
+ return grammarTrivia?._meta.rootTriviaClassified === true || r._meta.rootTriviaClassified === true;
21389
+ }
21390
+ function makeSelectedRootLabelIndex(labels) {
21391
+ const index = /* @__PURE__ */ Object.create(null);
21392
+ for (let i = 0; i < labels.length; i++) {
21393
+ if (index[labels[i]] === void 0) index[labels[i]] = i;
21394
+ }
21395
+ return index;
21396
+ }
21397
+ function growSpanEnd(span, input, end) {
21398
+ if (span.endLine === void 0 || span.endColumn === void 0) {
21399
+ return { start: span.start, end };
21400
+ }
21401
+ let line = span.endLine;
21402
+ let column = span.endColumn;
21403
+ for (let i = span.end; i < end; i++) {
21404
+ if (input.charCodeAt(i) === 10) {
21405
+ line++;
21406
+ column = 1;
21407
+ } else {
21408
+ column++;
21409
+ }
21410
+ }
21411
+ return { ...span, end, endLine: line, endColumn: column };
21412
+ }
21413
+ function runOnce(entry, input, options) {
21414
+ if (typeof entry !== "function" && typeof entry?.parse !== "function") {
21415
+ throw new TypeError(
21416
+ `run(): start production is ${entry === null ? "null" : typeof entry}, not a rule \u2014 the requested grammar rule does not exist (check the rule name).`
21417
+ );
21418
+ }
21419
+ const rootTriviaSelection = options.rootTrivia?.select;
21420
+ const captureRootTrivia = rootTriviaSelection !== void 0 && rootTriviaSelection.length > 0;
21421
+ const selectedRootLog = captureRootTrivia ? [] : void 0;
21422
+ const selectedRootLabelIndex = captureRootTrivia ? makeSelectedRootLabelIndex(rootTriviaSelection) : void 0;
21423
+ const errors = [];
21424
+ const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
21425
+ const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
21426
+ const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
21427
+ if (captureRootTrivia && triviaKindLabels === void 0) {
21428
+ throw new TypeError("run(): rootTrivia.select requires labeled grammar trivia.");
21429
+ }
21430
+ if (captureRootTrivia) {
21431
+ for (const label2 of rootTriviaSelection) {
21432
+ if (!triviaKindLabels.includes(label2)) {
21433
+ throw new TypeError(`run(): rootTrivia.select contains unknown trivia label ${JSON.stringify(label2)}.`);
21434
+ }
21435
+ }
21436
+ }
21437
+ if (captureRootTrivia && !rootTriviaClassifiedFromRunnable(entry) && !rootTriviaClassifiedFromRunnable(options.trivia)) {
21438
+ throw new TypeError(
21439
+ "run(): rootTrivia.select requires classifiedTrivia() at the root."
21440
+ );
21441
+ }
21442
+ const stamped = entry;
21443
+ assertHostModeCompatible(
21444
+ typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
21445
+ options.build,
21446
+ typeof entry === "function" && stamped[FUSED_HOST_ELIDED] === true
21447
+ );
21448
+ const ctx = createParseContext();
21449
+ if (captureRootTrivia) {
21450
+ ctx._rootTriviaLog = selectedRootLog;
21451
+ ctx._rootTriviaKindIndex = selectedRootLabelIndex;
21452
+ ctx._rootTriviaStrictScopes = true;
21453
+ }
21454
+ ctx._errors = errors;
21455
+ ctx.build = options.build;
21456
+ ctx.state = options.state;
21457
+ if (grammarTrivia !== void 0) ctx.trivia = grammarTrivia;
21458
+ if (triviaKindLabels) ctx.triviaKindLabels = triviaKindLabels;
21459
+ if (grammarScanSkip !== void 0) ctx.scanSkip = grammarScanSkip;
21460
+ if (options.triviaCaptureMask !== void 0) ctx._triviaCaptureMask = options.triviaCaptureMask;
21461
+ if (options.tolerant) {
21462
+ ctx._tolerant = true;
21463
+ ctx._rec = REC;
21464
+ }
21465
+ if (options.instrumentation !== void 0) {
21466
+ ctx._grammarCoverage = options.instrumentation._grammarCoverage;
21467
+ ctx._grammarTrace = options.instrumentation._grammarTrace;
21468
+ }
21469
+ const r = invoke(entry, input, 0, ctx);
21470
+ const value = r.ok ? r.value : void 0;
21471
+ let span = r.span ?? { start: 0, end: 0 };
21472
+ const expected = r.ok ? [] : [...new Set(r.expected ?? [])];
21473
+ let unconsumedFrom = null;
21474
+ if (r.ok) {
21475
+ let pos = span.end;
21476
+ const tail = options.trivia ?? ambientTriviaFromRunnable(entry);
21477
+ if (tail !== void 0 && pos < input.length) {
21478
+ const t2 = invoke(tail, input, pos, createParseContext());
21479
+ if (t2.ok && t2.span.end > pos) {
21480
+ span = growSpanEnd(span, input, t2.span.end);
21481
+ pos = t2.span.end;
21482
+ }
21483
+ }
21484
+ unconsumedFrom = pos < input.length ? pos : null;
21485
+ }
21486
+ return selectedRootLog !== void 0 && selectedRootLog.length > 0 ? new RunResultWithRootTrivia(
21487
+ r.ok,
21488
+ value,
21489
+ span,
21490
+ expected,
21491
+ errors,
21492
+ {
21493
+ rows: selectedRootLog,
21494
+ select: rootTriviaSelection,
21495
+ index: buildRootTriviaIndex(selectedRootLog, rootTriviaSelection)
21496
+ },
21497
+ unconsumedFrom
21498
+ ) : new RunResultRecord(r.ok, value, span, expected, errors, unconsumedFrom);
21499
+ }
21500
+ function run(entry, input, options = {}) {
21501
+ return runOnce(entry, input, options);
21502
+ }
21503
+
21504
+ // src/table/backtrack-probe.ts
21505
+ var LOOKAROUND = /(?<!\\)\(\?<?[=!]/;
21506
+ function hasLookaround(re) {
21507
+ return LOOKAROUND.test(re.source);
21508
+ }
21509
+ function lookaroundExtent(re, input, start, end) {
21510
+ const probe2 = new RegExp(re.source, re.flags.includes("y") ? re.flags : `${re.flags}y`);
21511
+ const same = (n) => {
21512
+ probe2.lastIndex = start;
21513
+ return probe2.test(input.slice(0, end + n)) && probe2.lastIndex === end;
21514
+ };
21515
+ let lo = 0;
21516
+ let hi = input.length - end;
21517
+ while (lo < hi) {
21518
+ const mid = lo + hi >>> 1;
21519
+ if (same(mid)) hi = mid;
21520
+ else lo = mid + 1;
21521
+ }
21522
+ return lo;
21523
+ }
21524
+ var BacktrackRecorder = class {
21525
+ input = "";
21526
+ counts = zeroCounts();
21527
+ look = 0;
21528
+ opaque = 0;
21529
+ last = 0;
21530
+ furthest = 0;
21531
+ begin(input) {
21532
+ this.input = input;
21533
+ this.counts = zeroCounts();
21534
+ this.look = 0;
21535
+ this.opaque = 0;
21536
+ this.last = 0;
21537
+ this.furthest = 0;
21538
+ }
21539
+ /** The counts for the parse `begin` opened. Throws if a region was left open. */
21540
+ end() {
21541
+ if (this.look !== 0 || this.opaque !== 0) {
21542
+ throw new Error(`backtrack probe: unbalanced region (lookahead ${this.look}, opaque ${this.opaque})`);
21543
+ }
21544
+ return this.counts;
21545
+ }
21546
+ consume(start, end) {
21547
+ if (this.opaque > 0 || end <= start) return;
21548
+ const c = this.counts;
21549
+ if (this.look > 0) {
21550
+ c.lookaheadBytes += end - start;
21551
+ return;
21552
+ }
21553
+ if (start < this.last) c.rewinds++;
21554
+ if (start < this.furthest) c.bytesReread += Math.min(end, this.furthest) - start;
21555
+ this.last = end;
21556
+ if (end > this.furthest) this.furthest = end;
21557
+ }
21558
+ enterLookahead() {
21559
+ if (this.opaque === 0) this.counts.lookaheads++;
21560
+ this.look++;
21561
+ }
21562
+ exitLookahead() {
21563
+ this.look--;
21564
+ }
21565
+ regexAttempt() {
21566
+ if (this.opaque === 0) this.counts.regexLookarounds++;
21567
+ }
21568
+ regexMatch(re, start, end) {
21569
+ if (this.opaque === 0) this.counts.regexLookaroundBytes += lookaroundExtent(re, this.input, start, end);
21570
+ this.consume(start, end);
21571
+ }
21572
+ /** A read whose inner steps are not the grammar's (the interpreter's scans). */
21573
+ enterOpaque() {
21574
+ this.opaque++;
21575
+ }
21576
+ exitOpaque() {
21577
+ this.opaque--;
21578
+ }
21579
+ };
21580
+ function zeroCounts() {
21581
+ return { rewinds: 0, bytesReread: 0, lookaheads: 0, lookaheadBytes: 0, regexLookarounds: 0, regexLookaroundBytes: 0 };
21582
+ }
21583
+ function rowStarts(code, roots) {
21584
+ const seen = /* @__PURE__ */ new Set();
21585
+ const stack = [...roots];
21586
+ const kids = [];
21587
+ while (stack.length > 0) {
21588
+ const ip = stack.pop();
21589
+ if (seen.has(ip)) continue;
21590
+ seen.add(ip);
21591
+ kids.length = 0;
21592
+ childSlots(code, ip, kids);
21593
+ for (const c of kids) stack.push(c);
21594
+ }
21595
+ return [...seen, code.length].sort((a, b) => a - b);
21596
+ }
21597
+ function probeProgram(source, rec) {
21598
+ const prog = expandCompact(source);
21599
+ const code = [...prog.code];
21600
+ const fns = [...prog.fns];
21601
+ const fx = [...prog.fx, []];
21602
+ const noFx = fx.length - 1;
21603
+ const row = (...words) => {
21604
+ const ip = code.length;
21605
+ code.push(...words);
21606
+ return ip;
21607
+ };
21608
+ const fn = (f) => fns.push(f) - 1;
21609
+ const slots = [];
21610
+ const extraIps = assemblyExtraIps(prog);
21611
+ const starts = rowStarts(prog.code, [...Object.values(prog.rules), ...extraIps]);
21612
+ const copies = /* @__PURE__ */ new Map();
21613
+ function copyOf(ip) {
21614
+ const hit = copies.get(ip);
21615
+ if (hit !== void 0) return hit;
21616
+ slots.length = 0;
21617
+ childSlotOffsets(prog.code, ip, slots);
21618
+ if (slots.length === 0) {
21619
+ copies.set(ip, ip);
21620
+ return ip;
21621
+ }
21622
+ const next = starts[starts.findIndex((s) => s > ip)];
21623
+ const at = code.length;
21624
+ copies.set(ip, at);
21625
+ for (let i = ip; i < next; i++) code.push(prog.code[i]);
21626
+ const own = slots.map((s) => s - ip);
21627
+ for (const o of own) code[at + o] = copyOf(prog.code[ip + o]);
21628
+ return at;
21629
+ }
21630
+ const ref2 = (r) => [copyOf(r[0]), r[1]];
21631
+ const scans = prog.scans?.map((s) => ({
21632
+ ...s,
21633
+ skip: s.skip.map(ref2),
21634
+ ...s.sentinel === void 0 ? {} : { sentinel: ref2(s.sentinel) },
21635
+ ...s.recoverAt === void 0 ? {} : { recoverAt: ref2(s.recoverAt) },
21636
+ ...s.stopAt === void 0 ? {} : { stopAt: ref2(s.stopAt) },
21637
+ ...s.prefix === void 0 ? {} : { prefix: ref2(s.prefix) },
21638
+ ...s.body === void 0 ? {} : { body: ref2(s.body) },
21639
+ ...s.first === void 0 ? {} : { first: ref2(s.first) },
21640
+ ...s.lazy === void 0 ? {} : { lazy: ref2(s.lazy) }
21641
+ }));
21642
+ const scanSkip = prog.scanSkip?.map((set) => set.map(ref2));
21643
+ const report = fn((v, span) => {
21644
+ rec.consume(span.start, span.end);
21645
+ return v;
21646
+ });
21647
+ const lookIn = fn(() => {
21648
+ rec.enterLookahead();
21649
+ return true;
21650
+ });
21651
+ const lookOut = fn((v) => {
21652
+ rec.exitLookahead();
21653
+ return v;
21654
+ });
21655
+ const regexTry = fn(() => {
21656
+ rec.regexAttempt();
21657
+ return true;
21658
+ });
21659
+ const lookahead = (child, fxi) => row(
21660
+ OP_ARMGATE,
21661
+ lookIn,
21662
+ row(OP_XFORM, lookOut, row(OP_NOT, row(OP_XFORM, lookOut, replacement(child) ?? child), fxi)),
21663
+ noFx
21664
+ );
21665
+ const replaced = /* @__PURE__ */ new Map();
21666
+ function replacement(c) {
21667
+ const hit = replaced.get(c);
21668
+ if (hit !== void 0) return hit;
21669
+ let r;
21670
+ switch (code[c]) {
21671
+ case OP_LIT:
21672
+ case OP_LIT_TRACK:
21673
+ case OP_LIT_CI:
21674
+ case OP_LIT_CI_TRACK:
21675
+ case OP_LEX_BODY:
21676
+ case OP_LEX_PROGRAM:
21677
+ case OP_SCAN:
21678
+ case OP_LIVE:
21679
+ r = row(OP_XFORM, report, c);
21680
+ break;
21681
+ case OP_RX:
21682
+ case OP_RX_TRACK: {
21683
+ const re = prog.k[code[c + 1]];
21684
+ r = hasLookaround(re) ? row(
21685
+ OP_ARMGATE,
21686
+ regexTry,
21687
+ row(OP_XFORM, fn((v, span) => {
21688
+ rec.regexMatch(re, span.start, span.end);
21689
+ return v;
21690
+ }), c),
21691
+ noFx
21692
+ ) : row(OP_XFORM, report, c);
21693
+ break;
21694
+ }
21695
+ case OP_NOT:
21696
+ r = lookahead(code[c + 1], code[c + 2]);
21697
+ break;
21698
+ case OP_PEEK:
21699
+ r = row(OP_NOT, lookahead(code[c + 1], code[c + 2]), code[c + 2]);
21700
+ break;
21701
+ }
21702
+ if (r !== void 0) replaced.set(c, r);
21703
+ return r;
21704
+ }
21705
+ const rules = {};
21706
+ const stack = [];
21707
+ for (const [name, ip] of Object.entries(prog.rules)) {
21708
+ rules[name] = replacement(ip) ?? ip;
21709
+ stack.push(ip);
21710
+ }
21711
+ const seen = /* @__PURE__ */ new Set();
21712
+ while (stack.length > 0) {
21713
+ const ip = stack.pop();
21714
+ if (seen.has(ip)) continue;
21715
+ seen.add(ip);
21716
+ slots.length = 0;
21717
+ if (!childSlotOffsets(code, ip, slots)) throw new Error(`backtrack probe: unknown opcode ${String(code[ip])} at ${ip}`);
21718
+ for (let i = 0; i < slots.length; i++) {
21719
+ const s = slots[i];
21720
+ const c = code[s];
21721
+ stack.push(c);
21722
+ if (code[ip] === OP_GREEDY && i > 0) continue;
21723
+ const r = replacement(c);
21724
+ if (r !== void 0) code[s] = r;
21725
+ }
21726
+ }
21727
+ const out = Object.fromEntries(Object.entries(prog));
21728
+ return {
21729
+ ...out,
21730
+ code,
21731
+ fns,
21732
+ fx,
21733
+ rules,
21734
+ asm: [],
21735
+ ...scans === void 0 ? {} : { scans },
21736
+ ...scanSkip === void 0 ? {} : { scanSkip }
21737
+ };
21738
+ }
21739
+
21740
+ // src/analysis/backtrack.ts
21741
+ function isCombinator3(x) {
21742
+ return typeof x === "object" && x !== null && "_def" in x && typeof x.parse === "function";
21743
+ }
21744
+ function isProgram(x) {
21745
+ return Array.isArray(x.code) || Array.isArray(x.c);
21746
+ }
21747
+ function ruleEntries(grammar) {
21748
+ const out = [];
21749
+ for (const [name, value] of Object.entries(grammar)) {
21750
+ if (!isCombinator3(value)) continue;
21751
+ if (value._def.tag === "lazy") {
21752
+ try {
21753
+ value._def.thunk();
21754
+ } catch {
21755
+ continue;
21756
+ }
21757
+ }
21758
+ out.push([name, value]);
21759
+ }
21760
+ return out;
21761
+ }
21762
+ function outcome(r) {
21763
+ return digestValue({ ok: r.ok, value: r.value, span: r.span, unconsumedFrom: r.unconsumedFrom });
21764
+ }
21765
+ function tableOf(grammar) {
21766
+ if (isProgram(grammar)) return expandCompact(grammar);
21767
+ const refusals = [];
21768
+ const compiled = compileRuleMapRunnable(ruleEntries(grammar), { refusals });
21769
+ if (compiled === null) throw new Error(`backtrackProbe: this grammar could not be encoded to a table: ${refusals.join("; ")}`);
21770
+ return compiled.prog;
21771
+ }
21772
+ function backtrackProbe(grammar, engine = "closure") {
21773
+ const rec = new BacktrackRecorder();
21774
+ if (engine === "interpreter") {
21775
+ if (isProgram(grammar)) throw new TypeError("backtrackProbe: the interpreter runs a rule map of combinators, not a table program");
21776
+ const rules2 = Object.fromEntries(ruleEntries(grammar));
21777
+ const built = /* @__PURE__ */ new Map();
21778
+ const instrument = instrumentFor(rec);
21779
+ return probe(rec, "interpreter", (entry) => ruleOf(rules2, entry), (entry) => {
21780
+ let hit = built.get(entry);
21781
+ if (hit === void 0) {
21782
+ hit = rebuildCombinator(ruleOf(rules2, entry), /* @__PURE__ */ new Map(), { thaw: true, after: instrument }).root;
21783
+ built.set(entry, hit);
21784
+ }
21785
+ return hit;
21786
+ });
21787
+ }
21788
+ if (engine !== "closure") throw new TypeError(`backtrackProbe: no engine ${JSON.stringify(engine)}; it runs 'closure' or 'interpreter'`);
21789
+ const prog = tableOf(grammar);
21790
+ const base = tableRules({ ...prog, asm: [] });
21791
+ const rules = tableRules(probeProgram(prog, rec));
21792
+ return probe(rec, "closure", (entry) => ruleOf(base, entry), (entry) => ruleOf(rules, entry));
21793
+ }
21794
+ function probe(rec, ran, plain2, probed) {
21795
+ return {
21796
+ engine: { ran },
21797
+ measure(entry, input, options = {}) {
21798
+ const result = run(plain2(entry), input, options);
21799
+ rec.begin(input);
21800
+ const probedResult = run(probed(entry), input, options);
21801
+ const counts = rec.end();
21802
+ if (outcome(probedResult) !== outcome(result)) {
21803
+ throw new Error(`backtrackProbe: the probed ${ran} parse of rule ${JSON.stringify(entry)} differs from the plain one; its counts would describe another parse`);
21804
+ }
21805
+ return { result, counts };
21806
+ }
21807
+ };
21808
+ }
21809
+ function ruleOf(rules, entry) {
21810
+ if (!Object.hasOwn(rules, entry)) throw new Error(`backtrackProbe: the grammar has no rule ${JSON.stringify(entry)}`);
21811
+ return rules[entry];
21812
+ }
21813
+ function wrapped(out, parse2) {
21814
+ const w = { _tag: out._tag, _meta: out._meta, _def: out._def, parse: parse2 };
21815
+ const name = out._ruleName;
21816
+ if (name !== void 0) w._ruleName = name;
21817
+ return w;
21818
+ }
21819
+ function instrumentFor(rec) {
21820
+ return (_original, out) => {
21821
+ const d = out._def;
21822
+ switch (d.tag) {
21823
+ case "literal":
21824
+ case "keywords":
21825
+ return wrapped(out, (input, pos, ctx) => {
21826
+ const r = out.parse(input, pos, ctx);
21827
+ if (r.ok) rec.consume(r.span.start, r.span.end);
21828
+ return r;
21829
+ });
21830
+ case "regex": {
21831
+ const re = new RegExp(d.source, d.flags);
21832
+ if (!hasLookaround(re)) {
21833
+ return wrapped(out, (input, pos, ctx) => {
21834
+ const r = out.parse(input, pos, ctx);
21835
+ if (r.ok) rec.consume(r.span.start, r.span.end);
21836
+ return r;
21837
+ });
21838
+ }
21839
+ return wrapped(out, (input, pos, ctx) => {
21840
+ rec.regexAttempt();
21841
+ const r = out.parse(input, pos, ctx);
21842
+ if (r.ok) rec.regexMatch(re, r.span.start, r.span.end);
21843
+ return r;
21844
+ });
21845
+ }
21846
+ case "scanTo":
21847
+ case "lines":
21848
+ case "columns":
21849
+ case "recover":
21850
+ case "unknown":
21851
+ return wrapped(out, (input, pos, ctx) => {
21852
+ rec.enterOpaque();
21853
+ let r;
21854
+ try {
21855
+ r = out.parse(input, pos, ctx);
21856
+ } finally {
21857
+ rec.exitOpaque();
21858
+ }
21859
+ if (r.ok) rec.consume(r.span.start, r.span.end);
21860
+ return r;
21861
+ });
21862
+ case "not":
21863
+ case "peek":
21864
+ return wrapped(out, (input, pos, ctx) => {
21865
+ rec.enterLookahead();
21866
+ try {
21867
+ return out.parse(input, pos, ctx);
21868
+ } finally {
21869
+ rec.exitLookahead();
21870
+ }
21871
+ });
21872
+ default:
21873
+ return out;
21874
+ }
21875
+ };
21876
+ }
20874
21877
  export {
20875
21878
  applyFixEdits,
20876
21879
  armFirstSets,
21880
+ backtrackProbe,
20877
21881
  diagnosisLines,
20878
21882
  fixReportLines,
20879
21883
  groupDigits,