parseman 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +1 -1
  2. package/dist/combinators/attempt.d.ts +8 -0
  3. package/dist/combinators/attempt.d.ts.map +1 -0
  4. package/dist/combinators/expect.d.ts.map +1 -1
  5. package/dist/combinators/first-set.d.ts.map +1 -1
  6. package/dist/combinators/grammar.d.ts.map +1 -1
  7. package/dist/combinators/node.d.ts +8 -0
  8. package/dist/combinators/node.d.ts.map +1 -1
  9. package/dist/combinators/scanTo.d.ts.map +1 -1
  10. package/dist/combinators/token.d.ts +12 -0
  11. package/dist/combinators/token.d.ts.map +1 -1
  12. package/dist/compiler/build-arity.d.ts +8 -4
  13. package/dist/compiler/build-arity.d.ts.map +1 -1
  14. package/dist/compiler/codegen.d.ts +12 -0
  15. package/dist/compiler/codegen.d.ts.map +1 -1
  16. package/dist/compiler/fields.d.ts +7 -0
  17. package/dist/compiler/fields.d.ts.map +1 -1
  18. package/dist/compiler/grammar-coverage-ids.d.ts +19 -0
  19. package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -0
  20. package/dist/compiler/inline-callback.d.ts.map +1 -1
  21. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  22. package/dist/compiler/linker.d.ts +12 -1
  23. package/dist/compiler/linker.d.ts.map +1 -1
  24. package/dist/compiler/value-usage.d.ts.map +1 -1
  25. package/dist/coverage.d.ts +68 -0
  26. package/dist/coverage.d.ts.map +1 -0
  27. package/dist/cst/trivia-entries.d.ts +2 -0
  28. package/dist/cst/trivia-entries.d.ts.map +1 -1
  29. package/dist/functional/doc.d.ts.map +1 -1
  30. package/dist/functional/run.d.ts +13 -0
  31. package/dist/functional/run.d.ts.map +1 -1
  32. package/dist/index.cjs +936 -103
  33. package/dist/index.cjs.map +4 -4
  34. package/dist/index.d.ts +5 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +936 -103
  37. package/dist/index.js.map +4 -4
  38. package/dist/language-service/index.cjs +7 -2
  39. package/dist/language-service/index.cjs.map +2 -2
  40. package/dist/language-service/index.js +7 -2
  41. package/dist/language-service/index.js.map +2 -2
  42. package/dist/plugin/direct-builder-static.d.ts +8 -0
  43. package/dist/plugin/direct-builder-static.d.ts.map +1 -0
  44. package/dist/plugin/evaluator.d.ts.map +1 -1
  45. package/dist/plugin/index.cjs +1084 -145
  46. package/dist/plugin/index.cjs.map +4 -4
  47. package/dist/plugin/index.d.ts +4 -1
  48. package/dist/plugin/index.d.ts.map +1 -1
  49. package/dist/plugin/index.js +1084 -145
  50. package/dist/plugin/index.js.map +4 -4
  51. package/dist/spec/index.cjs +3 -0
  52. package/dist/spec/index.cjs.map +2 -2
  53. package/dist/spec/index.js +3 -0
  54. package/dist/spec/index.js.map +2 -2
  55. package/dist/spec/model.d.ts.map +1 -1
  56. package/dist/types.d.ts +16 -0
  57. package/dist/types.d.ts.map +1 -1
  58. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -59,6 +59,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
59
59
  case "label":
60
60
  case "trivia":
61
61
  case "token":
62
+ case "leaf":
62
63
  case "expect":
63
64
  case "withCtx":
64
65
  case "node":
@@ -122,6 +123,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
122
123
  case "label":
123
124
  case "trivia":
124
125
  case "token":
126
+ case "leaf":
125
127
  case "node":
126
128
  case "grammar":
127
129
  case "expect":
@@ -190,10 +192,10 @@ function beginCstNodeCapture(ctx) {
190
192
  }
191
193
  function finishCstBuf(buf) {
192
194
  if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
193
- const children = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
195
+ const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
194
196
  const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
195
197
  const triviaLog = buf.tl ?? EMPTY_TL;
196
- return { children, rawChildren, triviaLog };
198
+ return { children: children2, rawChildren, triviaLog };
197
199
  }
198
200
  function endCstNodeCapture(ctx, saved) {
199
201
  const materialized = finishCstBuf(ctx._cstBuf);
@@ -205,8 +207,8 @@ function endCstNodeCapture(ctx, saved) {
205
207
  ctx.captureTrivia = saved.cap;
206
208
  return materialized;
207
209
  }
208
- function pushCstLeaf(ctx, leaf) {
209
- pushCstChild(ctx, leaf, leaf);
210
+ function pushCstLeaf(ctx, leaf2) {
211
+ pushCstChild(ctx, leaf2, leaf2);
210
212
  }
211
213
  function pushCstChild(ctx, built, rawEntry) {
212
214
  const b = ctx._cstBuf;
@@ -940,10 +942,13 @@ function deriveExpected(c) {
940
942
  return def.parsers.flatMap(deriveExpected);
941
943
  case "sequence":
942
944
  return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
945
+ case "attempt":
946
+ return deriveExpected(def.parser);
943
947
  case "node":
944
948
  case "grammar":
945
949
  case "trivia":
946
950
  case "token":
951
+ case "leaf":
947
952
  case "optional":
948
953
  case "many":
949
954
  case "oneOrMore":
@@ -1437,6 +1442,12 @@ function scanTrivia(input, cur, ctx) {
1437
1442
  const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1438
1443
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1439
1444
  }
1445
+ function consumeTrivia(input, cur, ctx) {
1446
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1447
+ const scan = scanTrivia(input, cur, ctx);
1448
+ scan.commit();
1449
+ return scan.end;
1450
+ }
1440
1451
  function fastTriviaScanner(trivia2) {
1441
1452
  const cached = fastTriviaCache.get(trivia2);
1442
1453
  if (cached !== void 0) return cached;
@@ -1715,6 +1726,24 @@ function sequence(...parsers) {
1715
1726
  };
1716
1727
  }
1717
1728
 
1729
+ // src/combinators/attempt.ts
1730
+ function attempt(parser2) {
1731
+ return {
1732
+ _tag: "attempt",
1733
+ _meta: parser2._meta,
1734
+ _def: { tag: "attempt", parser: parser2 },
1735
+ parse(input, pos, ctx) {
1736
+ const mark = saveCstMark(ctx);
1737
+ const log = ctx._triviaLog?.length;
1738
+ const result = parser2.parse(input, pos, ctx);
1739
+ if (result.ok) return result;
1740
+ rollbackCstCapture(ctx, mark);
1741
+ if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
1742
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
1743
+ }
1744
+ };
1745
+ }
1746
+
1718
1747
  // src/combinators/repeat.ts
1719
1748
  function repItem(combinator, input, cur, ctx) {
1720
1749
  const mark = saveTriviaMark(ctx);
@@ -2024,10 +2053,14 @@ function markUnusedValues(root) {
2024
2053
  case "label":
2025
2054
  case "trivia":
2026
2055
  case "token":
2056
+ case "attempt":
2027
2057
  case "withCtx":
2028
2058
  case "expect":
2029
2059
  visit(def.parser, consumed);
2030
2060
  return;
2061
+ case "leaf":
2062
+ visit(def.parser, true);
2063
+ return;
2031
2064
  case "lazy":
2032
2065
  return;
2033
2066
  default:
@@ -2150,6 +2183,20 @@ function confirmedBuildArity(src) {
2150
2183
  if (/\barguments\b/.test(s)) return null;
2151
2184
  return parts.length;
2152
2185
  }
2186
+ function buildReadsChildren(def) {
2187
+ if (!def.build) return true;
2188
+ const src = def.buildSrc ?? def.build.toString();
2189
+ const arity = confirmedBuildArity(src);
2190
+ if (arity === null) return true;
2191
+ return arity >= 1;
2192
+ }
2193
+ function buildReadsRaw(def) {
2194
+ if (!def.build) return true;
2195
+ const src = def.buildSrc ?? def.build.toString();
2196
+ const arity = confirmedBuildArity(src);
2197
+ if (arity === null) return true;
2198
+ return arity >= 4;
2199
+ }
2153
2200
  function buildReadsTrivia(def) {
2154
2201
  if (!def.build) return true;
2155
2202
  const src = def.buildSrc ?? def.build.toString();
@@ -2205,9 +2252,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
2205
2252
  case "many":
2206
2253
  case "oneOrMore":
2207
2254
  case "optional":
2255
+ case "attempt":
2208
2256
  case "transform":
2209
2257
  case "trivia":
2210
2258
  case "token":
2259
+ case "leaf":
2211
2260
  case "label":
2212
2261
  case "expect":
2213
2262
  case "withCtx":
@@ -2240,9 +2289,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
2240
2289
  case "keywords":
2241
2290
  case "guard":
2242
2291
  case "token":
2292
+ case "leaf":
2243
2293
  return false;
2244
2294
  // Transparent single-child wrappers: recurse.
2245
2295
  case "optional":
2296
+ case "attempt":
2246
2297
  case "transform":
2247
2298
  case "trivia":
2248
2299
  case "label":
@@ -2266,6 +2317,54 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
2266
2317
  return true;
2267
2318
  }
2268
2319
  }
2320
+ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
2321
+ if (seen.has(p)) return false;
2322
+ seen.add(p);
2323
+ const d = p._def;
2324
+ switch (d.tag) {
2325
+ case "grammar":
2326
+ return d.captureTrivia === true || parserEnablesTriviaCapture(d.parser, seen);
2327
+ case "node":
2328
+ return false;
2329
+ case "sequence":
2330
+ case "choice":
2331
+ return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
2332
+ case "sepBy":
2333
+ return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
2334
+ case "skip":
2335
+ return parserEnablesTriviaCapture(d.main, seen) || parserEnablesTriviaCapture(d.skipped, seen);
2336
+ case "scanTo":
2337
+ return parserEnablesTriviaCapture(d.sentinel, seen) || d.skip.some((x) => parserEnablesTriviaCapture(x, seen));
2338
+ case "recover":
2339
+ return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.sentinel, seen);
2340
+ case "many":
2341
+ case "oneOrMore":
2342
+ case "optional":
2343
+ case "attempt":
2344
+ case "transform":
2345
+ case "trivia":
2346
+ case "token":
2347
+ case "label":
2348
+ case "field":
2349
+ case "expect":
2350
+ case "withCtx":
2351
+ case "not":
2352
+ return parserEnablesTriviaCapture(d.parser, seen);
2353
+ // leaf() clears the inner CST/trivia collector and publishes only its own
2354
+ // terminal result. An inner parser() capture cannot reach this node.
2355
+ case "leaf":
2356
+ return false;
2357
+ case "lazy": {
2358
+ try {
2359
+ return parserEnablesTriviaCapture(d.thunk(), seen);
2360
+ } catch {
2361
+ return false;
2362
+ }
2363
+ }
2364
+ default:
2365
+ return false;
2366
+ }
2367
+ }
2269
2368
  function buildFieldMap(captures) {
2270
2369
  if (!captures?.length) return void 0;
2271
2370
  const out = {};
@@ -2303,11 +2402,13 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2303
2402
  };
2304
2403
  const unwrap = opts?.unwrap === true;
2305
2404
  const collapse = opts?.collapse === true;
2405
+ const captureTrivia = opts?.captureTrivia === true;
2406
+ const trailingTrivia = opts?.trailingTrivia === true;
2306
2407
  if (unwrap && collapse) {
2307
2408
  throw new Error("node() options cannot set both unwrap and collapse");
2308
2409
  }
2309
- const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
2310
- const capturesTrivia = build ? buildReadsTrivia(def) : true;
2410
+ const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
2411
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
2311
2412
  const clonesState = build ? buildReadsState(def) : true;
2312
2413
  const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
2313
2414
  return {
@@ -2323,16 +2424,21 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2323
2424
  ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
2324
2425
  }
2325
2426
  if (!capturesTrivia) ctx.captureTrivia = false;
2326
- const r = combinator.parse(input, pos, ctx);
2427
+ let r = combinator.parse(input, pos, ctx);
2428
+ if (r.ok && trailingTrivia && ctx.trivia) {
2429
+ const end = consumeTrivia(input, r.span.end, ctx);
2430
+ r = { ...r, span: { start: r.span.start, end } };
2431
+ }
2327
2432
  const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
2328
2433
  ctx._fields = savedFields;
2329
2434
  ctx._triviaCaptureMask = savedMask;
2330
- const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
2435
+ const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
2331
2436
  if (!r.ok) return r;
2332
2437
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2333
2438
  const nodeType = def.type ?? missingInferredType();
2334
- const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : build ? build(children, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
2335
- const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
2439
+ const cstOutput = ctx.build?._parsemanCstOutput === true;
2440
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
2441
+ const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span: r.span };
2336
2442
  if (saved.buf !== void 0 || saved.ch !== void 0) {
2337
2443
  pushCstChild(ctx, built, rawEntry);
2338
2444
  }
@@ -2449,6 +2555,7 @@ function parser(opts, root) {
2449
2555
  parser: root,
2450
2556
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2451
2557
  clearTrivia,
2558
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2452
2559
  trackLines: opts.trackLines ?? false
2453
2560
  },
2454
2561
  parse(input, pos, _ctx) {
@@ -2561,6 +2668,141 @@ function token(root) {
2561
2668
  }
2562
2669
  };
2563
2670
  }
2671
+ function leaf(root, fn) {
2672
+ const meta = {
2673
+ firstSet: root._meta.firstSet,
2674
+ canMatchNewline: root._meta.canMatchNewline,
2675
+ isTrivia: false
2676
+ };
2677
+ return {
2678
+ _tag: "leaf",
2679
+ _meta: meta,
2680
+ _def: { tag: "leaf", parser: root, fn },
2681
+ parse(input, pos, ctx) {
2682
+ const savedBuf = ctx._cstBuf;
2683
+ const savedChildren = ctx._cstChildren;
2684
+ const savedLeaves = ctx._cstLeaves;
2685
+ const savedRaw = ctx._cstRawChildren;
2686
+ const savedTriviaLog = ctx._cstTriviaLog;
2687
+ const savedOuterTriviaLog = ctx._triviaLog;
2688
+ const wasCapturing = cstCaptureActive(ctx);
2689
+ ctx._cstBuf = void 0;
2690
+ ctx._cstChildren = void 0;
2691
+ ctx._cstLeaves = void 0;
2692
+ ctx._cstRawChildren = void 0;
2693
+ ctx._cstTriviaLog = void 0;
2694
+ delete ctx._triviaLog;
2695
+ let result;
2696
+ try {
2697
+ result = root.parse(input, pos, ctx);
2698
+ } finally {
2699
+ ctx._cstBuf = savedBuf;
2700
+ ctx._cstChildren = savedChildren;
2701
+ ctx._cstLeaves = savedLeaves;
2702
+ ctx._cstRawChildren = savedRaw;
2703
+ ctx._cstTriviaLog = savedTriviaLog;
2704
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
2705
+ else ctx._triviaLog = savedOuterTriviaLog;
2706
+ }
2707
+ if (!result.ok) return result;
2708
+ const value = fn(result.value, result.span);
2709
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
2710
+ return { ok: true, value, span: result.span };
2711
+ }
2712
+ };
2713
+ }
2714
+
2715
+ // src/compiler/grammar-coverage-ids.ts
2716
+ function children(def, winners) {
2717
+ switch (def.tag) {
2718
+ case "sequence":
2719
+ case "choice":
2720
+ return def.parsers;
2721
+ case "many":
2722
+ case "oneOrMore":
2723
+ case "optional":
2724
+ case "attempt":
2725
+ case "transform":
2726
+ case "trivia":
2727
+ case "token":
2728
+ case "leaf":
2729
+ case "label":
2730
+ case "field":
2731
+ case "grammar":
2732
+ case "not":
2733
+ case "node":
2734
+ case "guard":
2735
+ case "withCtx":
2736
+ case "recover":
2737
+ case "expect":
2738
+ return "parser" in def ? [def.parser] : [];
2739
+ case "sepBy":
2740
+ return [def.parser, def.separator];
2741
+ case "skip":
2742
+ return [def.main, def.skipped];
2743
+ case "scanTo":
2744
+ return [def.sentinel, ...def.skip];
2745
+ case "lazy": {
2746
+ let resolved;
2747
+ try {
2748
+ resolved = def.thunk();
2749
+ } catch {
2750
+ return [];
2751
+ }
2752
+ const name = resolved._ruleName;
2753
+ return name && winners?.[name] ? [winners[name]] : [resolved];
2754
+ }
2755
+ default:
2756
+ return [];
2757
+ }
2758
+ }
2759
+ function buildGrammarPlan(entry, winners) {
2760
+ const definitions = /* @__PURE__ */ new Map();
2761
+ const choices = /* @__PURE__ */ new WeakMap();
2762
+ const attempts = /* @__PURE__ */ new WeakMap();
2763
+ const labels = /* @__PURE__ */ new WeakMap();
2764
+ const rules2 = /* @__PURE__ */ new WeakMap();
2765
+ const winnerNames = /* @__PURE__ */ new Map();
2766
+ if (winners) {
2767
+ for (const [name, winner] of Object.entries(winners)) {
2768
+ winnerNames.set(winner, name);
2769
+ if (winner._def.tag === "lazy") {
2770
+ try {
2771
+ winnerNames.set(winner._def.thunk(), name);
2772
+ } catch {
2773
+ }
2774
+ }
2775
+ }
2776
+ }
2777
+ const seen = /* @__PURE__ */ new Set();
2778
+ const visit = (parser2, path) => {
2779
+ if (seen.has(parser2)) return;
2780
+ seen.add(parser2);
2781
+ const rule = winnerNames.get(parser2) ?? parser2._ruleName;
2782
+ if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
2783
+ const id = `rule:${rule}`;
2784
+ definitions.set(id, { id, kind: "rule" });
2785
+ rules2.set(parser2, id);
2786
+ }
2787
+ if (parser2._def.tag === "choice") {
2788
+ const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
2789
+ choices.set(parser2, ids);
2790
+ ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
2791
+ }
2792
+ if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
2793
+ if (parser2._def.tag === "label") {
2794
+ const id = `label:${path}`;
2795
+ labels.set(parser2, [id]);
2796
+ definitions.set(id, { id, kind: "label" });
2797
+ }
2798
+ children(parser2._def, winners).forEach((child, index) => visit(child, `${path}/${parser2._def.tag}:${index}`));
2799
+ };
2800
+ const roots = Array.isArray(entry) ? entry : [entry];
2801
+ for (const root of roots) {
2802
+ visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
2803
+ }
2804
+ return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
2805
+ }
2564
2806
 
2565
2807
  // src/compiler/scannable-run.ts
2566
2808
  var BACKSLASH = 92;
@@ -3610,7 +3852,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
3610
3852
  ` if (${m.end} > _e) {`,
3611
3853
  ` if (_cap) {`,
3612
3854
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
3613
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
3855
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
3614
3856
  ` }`,
3615
3857
  ` _e = ${m.end}`,
3616
3858
  ` continue`,
@@ -3666,7 +3908,7 @@ function analyzeTriviaFastPath(trivia2) {
3666
3908
  var CAP_RECORD = [
3667
3909
  ` if (_cap && _e > _pos) {`,
3668
3910
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
3669
- ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
3911
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
3670
3912
  ` }`
3671
3913
  ].join("\n");
3672
3914
  function composeFastLoop(shapes) {
@@ -3726,7 +3968,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
3726
3968
  ` const _ce = _e + _m${i}[0].length`,
3727
3969
  ` if (_cap) {`,
3728
3970
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
3729
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
3971
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
3730
3972
  ` }`,
3731
3973
  ` _e = _ce`,
3732
3974
  ` _matched = true`,
@@ -3764,7 +4006,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
3764
4006
  ` const _ce = _r${i}.span.end`,
3765
4007
  ` if (_cap) {`,
3766
4008
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
3767
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
4009
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
3768
4010
  ` }`,
3769
4011
  ` _e = _ce`,
3770
4012
  ` _matched = true`,
@@ -3945,21 +4187,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
3945
4187
  }
3946
4188
  function failBody(ctx, expected, posExpr) {
3947
4189
  const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
4190
+ const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
3948
4191
  if (ctx.failLabel) {
3949
- if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
3950
- return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
4192
+ if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4193
+ return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
3951
4194
  }
3952
- return probe + failReturn(expected, posExpr);
4195
+ return probe + trace + failReturn(expected, posExpr);
3953
4196
  }
3954
4197
  function failArrBody(ctx, expectedArr, posExpr, constant = true) {
3955
4198
  const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
4199
+ const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
3956
4200
  if (ctx.failLabel) {
3957
- if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4201
+ if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
3958
4202
  const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
3959
- return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
4203
+ return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
3960
4204
  }
3961
- if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
3962
- return probe + failReturnArr(expectedArr, posExpr);
4205
+ if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
4206
+ return probe + trace + failReturnArr(expectedArr, posExpr);
3963
4207
  }
3964
4208
  function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
3965
4209
  return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
@@ -3994,7 +4238,7 @@ var NAMED_FN_END = "_pfEnd";
3994
4238
  function namedFnPrelude() {
3995
4239
  return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
3996
4240
  }
3997
- function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
4241
+ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
3998
4242
  ctx.namedFnDecls.push([
3999
4243
  `function ${fnName}(input, _pos, _ctx) {`,
4000
4244
  ` _pfail: {`,
@@ -4002,6 +4246,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
4002
4246
  ` ${NAMED_FN_END} = ${endVar}`,
4003
4247
  ` return ${valueVar}`,
4004
4248
  ` }`,
4249
+ ...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
4005
4250
  ` return ${NAMED_FN_FAIL}`,
4006
4251
  `}`
4007
4252
  ].join("\n"));
@@ -4107,7 +4352,7 @@ function ensureTriviaFn(ctx) {
4107
4352
  ` }`,
4108
4353
  ` if (_cap && _e > _pos) {`,
4109
4354
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
4110
- ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
4355
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
4111
4356
  ` }`,
4112
4357
  ` return _e`,
4113
4358
  `}`
@@ -4163,6 +4408,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
4163
4408
  case "not":
4164
4409
  case "trivia":
4165
4410
  case "token":
4411
+ case "leaf":
4166
4412
  case "scanTo":
4167
4413
  case "unknown":
4168
4414
  return false;
@@ -4174,6 +4420,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
4174
4420
  // nothing committed remains.
4175
4421
  case "choice":
4176
4422
  return false;
4423
+ case "attempt":
4424
+ return false;
4177
4425
  // optional never fails; many/oneOrMore only "fail" with zero captured items.
4178
4426
  case "optional":
4179
4427
  case "many":
@@ -4226,6 +4474,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
4226
4474
  case "keywords":
4227
4475
  case "node":
4228
4476
  case "token":
4477
+ case "leaf":
4229
4478
  return true;
4230
4479
  case "not":
4231
4480
  case "guard":
@@ -4240,6 +4489,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
4240
4489
  case "many":
4241
4490
  case "oneOrMore":
4242
4491
  case "optional":
4492
+ case "attempt":
4243
4493
  case "transform":
4244
4494
  case "label":
4245
4495
  case "field":
@@ -4581,35 +4831,55 @@ function needsFirstSetGuard(p) {
4581
4831
  const fs = p._meta.firstSet;
4582
4832
  return fs.kind !== "any" && !canMatchEmptyAtStart(p);
4583
4833
  }
4584
- function emitDisjointArm(p, ctx, pos, valV, endV) {
4585
- if (failsAtStart(p)) {
4834
+ function coverageHit(ctx, id, offset = "_pos", end) {
4835
+ return id === void 0 ? [] : [
4836
+ `${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
4837
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
4838
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
4839
+ ];
4840
+ }
4841
+ function coverageAttempt(ctx, id, offset) {
4842
+ return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
4843
+ }
4844
+ function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
4845
+ return id === void 0 ? [] : [
4846
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
4847
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
4848
+ ];
4849
+ }
4850
+ function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
4851
+ if (failsAtStart(p) && coverageId === void 0) {
4586
4852
  const r = emit(p, ctx, pos);
4587
- return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`];
4853
+ return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
4588
4854
  }
4589
4855
  const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
4590
4856
  return [
4857
+ ...coverageAttempt(ctx, coverageId, pos),
4591
4858
  ...stmts,
4592
- ...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
4859
+ ...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
4593
4860
  `${ind(ctx)}${valV} = ${valVar}`,
4594
- `${ind(ctx)}${endV} = ${endVar}`
4861
+ `${ind(ctx)}${endV} = ${endVar}`,
4862
+ ...coverageHit(ctx, coverageId, pos, endVar)
4595
4863
  ];
4596
4864
  }
4597
- function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
4865
+ function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
4598
4866
  const p = def.parsers[i];
4599
4867
  const gate = def.gates[i];
4600
- if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
4868
+ if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
4601
4869
  const gateIdx = ctx.mapFns.length;
4602
4870
  ctx.mapFns.push(gate);
4603
4871
  ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
4604
4872
  const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
4605
4873
  const stmts = [`${ind(ctx)}if (${gateCond}) {`];
4606
4874
  ctx.indent++;
4607
- stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4875
+ stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
4608
4876
  ctx.indent--;
4609
4877
  stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
4610
4878
  return stmts;
4611
4879
  }
4612
- function emitChoice(def, ctx, pos) {
4880
+ function emitChoice(parser2, def, ctx, pos) {
4881
+ const coverageIds = ctx.coverage?.plan.choices.get(parser2);
4882
+ const coverageBase = coverageIds?.[0]?.slice(0, -1);
4613
4883
  const allExpected = deriveExpectedArr(def.parsers);
4614
4884
  if (def.disjoint) {
4615
4885
  const codeV = v(ctx, "_code");
@@ -4628,7 +4898,7 @@ function emitChoice(def, ctx, pos) {
4628
4898
  stmts.push(`${ind(ctx)}{`);
4629
4899
  ctx.indent++;
4630
4900
  stmts.push(
4631
- ...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
4901
+ ...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
4632
4902
  `${ind(ctx)}break`
4633
4903
  );
4634
4904
  ctx.indent--;
@@ -4647,16 +4917,16 @@ function emitChoice(def, ctx, pos) {
4647
4917
  first = false;
4648
4918
  stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
4649
4919
  ctx.indent++;
4650
- stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
4920
+ stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
4651
4921
  ctx.indent--;
4652
4922
  stmts.push(`${ind(ctx)}}`);
4653
4923
  }
4654
4924
  stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
4655
4925
  return { stmts, valueVar: valV, endVar: endV };
4656
4926
  }
4657
- return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
4927
+ return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
4658
4928
  }
4659
- function emitGreedyClassify(def, superIndex, ctx, pos) {
4929
+ function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
4660
4930
  const superParser = def.parsers[superIndex];
4661
4931
  const regexDef = getCoreRegexDef(superParser);
4662
4932
  const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
@@ -4672,10 +4942,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4672
4942
  const endV = v(ctx, "_ge");
4673
4943
  const valV = v(ctx, "_gcv");
4674
4944
  const regexExpected = JSON.stringify(deriveExpected(superParser));
4945
+ const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
4675
4946
  const stmts = [
4947
+ ...coverageAttempt(ctx, superCoverageId, pos),
4676
4948
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
4677
4949
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
4678
- ...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
4950
+ ...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
4679
4951
  `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
4680
4952
  `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
4681
4953
  `${ind(ctx)}let ${valV}`
@@ -4691,8 +4963,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4691
4963
  stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
4692
4964
  ctx.indent++;
4693
4965
  const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
4966
+ stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
4694
4967
  stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
4695
- stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`);
4968
+ stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
4696
4969
  ctx.indent--;
4697
4970
  stmts.push(`${ind(ctx)}}`);
4698
4971
  }
@@ -4700,12 +4973,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4700
4973
  const regexKw = first ? "if" : "else";
4701
4974
  stmts.push(`${ind(ctx)}${regexKw} {`);
4702
4975
  ctx.indent++;
4703
- stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`);
4976
+ stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`, pos, endV));
4704
4977
  ctx.indent--;
4705
4978
  stmts.push(`${ind(ctx)}}`);
4706
4979
  return { stmts, valueVar: valV, endVar: endV };
4707
4980
  }
4708
- function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
4981
+ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
4709
4982
  const valV = v(ctx, "_llv");
4710
4983
  const endV = v(ctx, "_lle");
4711
4984
  const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
@@ -4722,10 +4995,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
4722
4995
  ctx.indent++;
4723
4996
  const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
4724
4997
  stmts.push(
4998
+ ...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
4725
4999
  ...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
4726
5000
  ...tR.stmts,
4727
5001
  `${ind(ctx)}${valV} = ${tR.valueVar}`,
4728
- `${ind(ctx)}${endV} = ${litEnd}`
5002
+ `${ind(ctx)}${endV} = ${litEnd}`,
5003
+ ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
4729
5004
  );
4730
5005
  ctx.indent--;
4731
5006
  stmts.push(`${ind(ctx)}}`);
@@ -4733,16 +5008,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
4733
5008
  stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
4734
5009
  return { stmts, valueVar: valV, endVar: endV };
4735
5010
  }
4736
- function emitFirstMatch(def, ctx, pos) {
5011
+ function emitFirstMatch(def, ctx, pos, coverageBase) {
4737
5012
  const resValV = v(ctx, "_crv");
4738
5013
  const resEndV = v(ctx, "_cre");
4739
5014
  const resOkV = v(ctx, "_crok");
4740
5015
  const codeV = v(ctx, "_chcode");
4741
5016
  const slots = def.parsers.map(() => v(ctx, "_cfx"));
5017
+ const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
4742
5018
  const ind0 = ind(ctx);
4743
5019
  const stmts = [
4744
5020
  `${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
4745
5021
  `${ind0}let ${slots.join(", ")}`,
5022
+ ...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
4746
5023
  `${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
4747
5024
  ];
4748
5025
  for (let i = 0; i < def.parsers.length; i++) {
@@ -4778,6 +5055,7 @@ function emitFirstMatch(def, ctx, pos) {
4778
5055
  stmts.push(`${ind0}if (${skipCond}) {`);
4779
5056
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
4780
5057
  ctx.indent += fsGuard ? 2 : 1;
5058
+ if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
4781
5059
  if (markLeaves) {
4782
5060
  stmts.push(
4783
5061
  `${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
@@ -4800,13 +5078,21 @@ function emitFirstMatch(def, ctx, pos) {
4800
5078
  stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
4801
5079
  stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
4802
5080
  stmts.push(`${ind(ctx)} ${resOkV} = true`);
5081
+ if (autoRejectedV !== void 0) {
5082
+ stmts.push(`${ind(ctx)} for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`);
5083
+ }
5084
+ stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
4803
5085
  stmts.push(`${ind(ctx)} }`);
5086
+ if (autoRejectedV !== void 0) {
5087
+ stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
5088
+ }
4804
5089
  stmts.push(`${ind(ctx)}}`);
4805
- stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
5090
+ stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}; ${coverageBase === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} });`} }`);
4806
5091
  if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
4807
5092
  } else {
4808
- stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
4809
- stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""} }`);
5093
+ const rejectedFlush = autoRejectedV === void 0 ? "" : `; for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`;
5094
+ stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true${coverageBase === void 0 ? "" : `${rejectedFlush}; _ctx._grammarCoverage?.(${JSON.stringify(`${coverageBase}${i}`)}); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'selected', offset: ${pos}, end: ${endVar} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'success', offset: ${pos}, end: ${endVar} })`} }`);
5095
+ stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""}${coverageBase === void 0 ? "" : `; _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} })`} }`);
4810
5096
  }
4811
5097
  ctx.indent -= fsGuard ? 2 : 1;
4812
5098
  if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
@@ -4816,12 +5102,12 @@ function emitFirstMatch(def, ctx, pos) {
4816
5102
  stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
4817
5103
  return { stmts, valueVar: resValV, endVar: resEndV };
4818
5104
  }
4819
- function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
5105
+ function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
4820
5106
  if (strategy.tag === "greedyClassify")
4821
- return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
5107
+ return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
4822
5108
  if (strategy.tag === "literalsLongestFirst")
4823
- return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
4824
- return emitFirstMatch(def, ctx, pos);
5109
+ return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
5110
+ return emitFirstMatch(def, ctx, pos, coverageBase);
4825
5111
  }
4826
5112
  function pushMapFn(ctx, fn, src) {
4827
5113
  if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
@@ -4939,6 +5225,27 @@ function emitOptional(def, ctx, pos) {
4939
5225
  ];
4940
5226
  return { stmts, valueVar: valV, endVar: endV };
4941
5227
  }
5228
+ function emitAttempt(p, def, ctx, pos) {
5229
+ const inner = emitFallible(def.parser, ctx, pos);
5230
+ const leaves = v(ctx, "_atl");
5231
+ const raw = v(ctx, "_atr");
5232
+ const trivia2 = v(ctx, "_att");
5233
+ const log = v(ctx, "_atg");
5234
+ const fields = v(ctx, "_atf");
5235
+ const errors = v(ctx, "_ate");
5236
+ const rollback = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${log}; if (_ctx._fields) _ctx._fields.length = ${fields}; if (_ctx._errors) _ctx._errors.length = ${errors}`;
5237
+ const traceId = ctx.coverage?.plan.attempts.get(p);
5238
+ const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
5239
+ return {
5240
+ stmts: [
5241
+ `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
5242
+ ...inner.stmts,
5243
+ ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
5244
+ ],
5245
+ valueVar: inner.valVar,
5246
+ endVar: inner.endVar
5247
+ };
5248
+ }
4942
5249
  function emitSepBy(_p, def, ctx, pos) {
4943
5250
  const arrV = v(ctx, "_arr");
4944
5251
  const curV = v(ctx, "_cur");
@@ -5229,6 +5536,36 @@ function emitToken(def, ctx, pos) {
5229
5536
  endVar: inner.endVar
5230
5537
  };
5231
5538
  }
5539
+ function emitLeaf(def, ctx, pos) {
5540
+ const inner = emitFallible(def.parser, ctx, pos);
5541
+ const i = ind(ctx);
5542
+ const sc = v(ctx, "_leafCh");
5543
+ const sl = v(ctx, "_leafLv");
5544
+ const sr = v(ctx, "_leafRaw");
5545
+ const stl = v(ctx, "_leafTl");
5546
+ const sol = v(ctx, "_leafLog");
5547
+ const sb = v(ctx, "_leafBuf");
5548
+ const rawV = v(ctx, "_leafRawValue");
5549
+ const valV = v(ctx, "_leaf");
5550
+ const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
5551
+ return {
5552
+ stmts: [
5553
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
5554
+ `${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
5555
+ `${i}try {`,
5556
+ ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
5557
+ `${i}} finally {`,
5558
+ `${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
5559
+ `${i}}`,
5560
+ ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
5561
+ `${i}const ${rawV} = ${inner.valVar}`,
5562
+ `${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
5563
+ ...emitLeafCapture(ctx, valV, pos, inner.endVar)
5564
+ ],
5565
+ valueVar: valV,
5566
+ endVar: inner.endVar
5567
+ };
5568
+ }
5232
5569
  function emitNode(def, ctx, pos) {
5233
5570
  if (def.type === void 0) {
5234
5571
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
@@ -5242,17 +5579,20 @@ function emitNode(def, ctx, pos) {
5242
5579
  ctx.buildSrcs.push(def.buildSrc ?? null);
5243
5580
  }
5244
5581
  const i = ind(ctx);
5245
- const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
5582
+ const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
5246
5583
  const clonesState = !structural && buildReadsState(def);
5584
+ const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
5585
+ const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
5247
5586
  const hasFields = parserHasOwnFields(def.parser);
5248
5587
  const capturesFields = hasFields && !structural && buildReadsFields(def);
5588
+ const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
5249
5589
  const chV = v(ctx, "_ch");
5250
5590
  const rawV = v(ctx, "_raw");
5251
- const capTLv = structural ? v(ctx, "_ctl") : null;
5591
+ const capTLv = structural || capturesTrivia ? v(ctx, "_ctl") : null;
5252
5592
  const capSTv = structural ? v(ctx, "_cst") : null;
5253
5593
  const capFv = structural && hasFields ? v(ctx, "_cf") : null;
5254
5594
  const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
5255
- if (!capturesTrivia) ctx.needsEmptyTl = true;
5595
+ if (!capturesTrivia || structural) ctx.needsEmptyTl = true;
5256
5596
  const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
5257
5597
  const smk = structural ? v(ctx, "_smk") : null;
5258
5598
  if (structural) ctx.needsHostReads = true;
@@ -5261,16 +5601,21 @@ function emitNode(def, ctx, pos) {
5261
5601
  const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
5262
5602
  const profileRecognizer = recV;
5263
5603
  const profileCapture = capV;
5264
- const allocStmt = structural ? `${i}const ${capTLv} = !(${profileRecognizer}) && (${profileCapture} || ${hostTriviaGate}), ${capSTv} = !(${profileRecognizer} || ${profileCapture}) && (_ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6)))${capFv ? `, ${capFv} = !(${profileRecognizer}) && (${profileCapture} || (_ctx.build !== undefined && _hostReads(_ctx.build, 2)))` : ""}
5265
- ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capturesTrivia ? `${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : []` : `${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : []`;
5266
- const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
5604
+ const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
5605
+ const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
5606
+ const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
5607
+ const allocStmt = structural ? `${i}const ${capTLv} = !(${profileRecognizer}) && (${profileCapture} || ${structuralCapturesTrivia ? "true" : hostTriviaGate}), ${capSTv} = !(${profileRecognizer} || ${profileCapture}) && (_ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6)))${capFv ? `, ${capFv} = !(${profileRecognizer}) && (${profileCapture} || (_ctx.build !== undefined && _hostReads(_ctx.build, 2)))` : ""}
5608
+ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
5609
+ ` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
5610
+ ` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
5611
+ const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
5267
5612
  const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
5268
5613
  const sf = hasFields ? v(ctx, "_sf") : null;
5269
5614
  const fArr = hasFields ? v(ctx, "_fa") : null;
5270
5615
  const fObj = hasFields ? v(ctx, "_fields") : "undefined";
5271
- const needsTriviaFrame = parserHasTriviaSite(def.parser);
5616
+ const needsTriviaFrame = def.trailingTrivia === true || parserHasTriviaSite(def.parser);
5272
5617
  const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
5273
- const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
5618
+ const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${capTLv ?? "false"}; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build !== undefined && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
5274
5619
  const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
5275
5620
  const stmts = [
5276
5621
  profHoist,
@@ -5278,8 +5623,13 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5278
5623
  `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
5279
5624
  `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
5280
5625
  ];
5281
- const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
5626
+ const { stmts: innerStmts, okVar, endVar: innerEndVar } = emitFallible(def.parser, ctx, pos);
5627
+ const endVar = def.trailingTrivia === true && ctx.activeTrivia ? v(ctx, "_trailend") : innerEndVar;
5282
5628
  stmts.push(...innerStmts);
5629
+ if (def.trailingTrivia === true && ctx.activeTrivia) {
5630
+ const triviaFn = ensureTriviaFn(ctx);
5631
+ stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
5632
+ }
5283
5633
  if (sf && fArr) {
5284
5634
  stmts.push(`${i}const ${fArr} = _ctx._fields`);
5285
5635
  }
@@ -5319,8 +5669,9 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5319
5669
  }
5320
5670
  const ndV = v(ctx, "_nd");
5321
5671
  const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
5322
- const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? (_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})) : (${buildExpr})` : buildExpr;
5323
- const hostCollapseExpr = ctx.ns || structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
5672
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
5673
+ const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : `_ctx.build?._parsemanCstOutput === true ? (${hostBuildExpr}) : (${buildExpr})`;
5674
+ const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
5324
5675
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
5325
5676
  const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
5326
5677
  const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
@@ -5328,7 +5679,7 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5328
5679
  `${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
5329
5680
  `${i}if (!(${profileRecognizer})) {`,
5330
5681
  `${i} if (${sc}) ${sc}.push(${ndV})`,
5331
- `${i} if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`,
5682
+ `${i} if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : (typeof ${ndV} === 'object' && ${ndV} !== null ? input.slice(${pos}, ${endVar}) : ''), span: { start: ${pos}, end: ${endVar} } })`,
5332
5683
  `${i}}`
5333
5684
  );
5334
5685
  return { stmts, valueVar: ndV, endVar };
@@ -5373,14 +5724,23 @@ function emitLazy(p, def, ctx, pos) {
5373
5724
  const savedIndent = ctx.indent;
5374
5725
  const savedFailLabel = ctx.failLabel;
5375
5726
  const savedRecord = ctx.recordFail;
5727
+ const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
5728
+ const savedActiveRule = ctx.activeCoverageRuleId;
5729
+ const savedSuppressFailure = ctx.suppressCoverageFailure;
5376
5730
  ctx.indent = 1;
5377
5731
  ctx.failLabel = "_pfail";
5378
5732
  ctx.recordFail = true;
5733
+ if (failureRuleId !== void 0) {
5734
+ ctx.activeCoverageRuleId = void 0;
5735
+ ctx.suppressCoverageFailure = true;
5736
+ }
5379
5737
  const r = emit(resolved, ctx, "_pos");
5380
5738
  ctx.indent = savedIndent;
5381
5739
  ctx.failLabel = savedFailLabel;
5382
5740
  ctx.recordFail = savedRecord;
5383
- pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar);
5741
+ ctx.activeCoverageRuleId = savedActiveRule;
5742
+ ctx.suppressCoverageFailure = savedSuppressFailure;
5743
+ pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
5384
5744
  }
5385
5745
  const fnName = ctx.namedParsers.get(p);
5386
5746
  return emitNamedFnCall(ctx, fnName, pos);
@@ -5431,6 +5791,30 @@ function emitExpect(def, ctx, pos) {
5431
5791
  return { stmts, valueVar: valVar, endVar };
5432
5792
  }
5433
5793
  function emit(p, ctx, pos) {
5794
+ const dispatch = (emissionPos = pos) => {
5795
+ const savedRule = ctx.activeCoverageRuleId;
5796
+ const rule = ctx.coverage?.plan.rules.get(p);
5797
+ if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
5798
+ const result = emitDispatch(p, ctx, emissionPos);
5799
+ ctx.activeCoverageRuleId = savedRule;
5800
+ return result;
5801
+ };
5802
+ const instrument = (r) => {
5803
+ const ruleId = ctx.coverage?.plan.rules.get(p);
5804
+ const labelIds = ctx.coverage?.plan.labels.get(p);
5805
+ if (!ruleId && !labelIds) return r;
5806
+ return {
5807
+ ...r,
5808
+ stmts: [
5809
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
5810
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
5811
+ ...r.stmts,
5812
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
5813
+ ...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
5814
+ ...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
5815
+ ]
5816
+ };
5817
+ };
5434
5818
  const usage = ctx.lazyUsage;
5435
5819
  if (usage && !ctx.noHoist && !ctx.capAsTrivia && !ctx.ruleNames?.has(p) && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && // Only hoist subtrees big enough that de-duplicating them beats the call
5436
5820
  // overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
@@ -5447,14 +5831,14 @@ function emit(p, ctx, pos) {
5447
5831
  ctx.indent = 1;
5448
5832
  ctx.failLabel = "_pfail";
5449
5833
  ctx.recordFail = true;
5450
- const r = emitDispatch(p, ctx, "_pos");
5834
+ const r = dispatch("_pos");
5451
5835
  ctx.indent = savedIndent;
5452
5836
  ctx.failLabel = savedFailLabel;
5453
5837
  ctx.recordFail = savedRecord;
5454
5838
  pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
5455
- return emitNamedFnCall(ctx, fnName, pos);
5839
+ return instrument(emitNamedFnCall(ctx, fnName, pos));
5456
5840
  }
5457
- return emitDispatch(p, ctx, pos);
5841
+ return instrument(dispatch());
5458
5842
  }
5459
5843
  function emitDispatch(p, ctx, pos) {
5460
5844
  const def = p._def;
@@ -5468,7 +5852,9 @@ function emitDispatch(p, ctx, pos) {
5468
5852
  case "sequence":
5469
5853
  return emitSeq(def, ctx, pos);
5470
5854
  case "choice":
5471
- return emitChoice(def, ctx, pos);
5855
+ return emitChoice(p, def, ctx, pos);
5856
+ case "attempt":
5857
+ return emitAttempt(p, def, ctx, pos);
5472
5858
  case "many":
5473
5859
  case "oneOrMore":
5474
5860
  return emitMany(def, ctx, pos);
@@ -5537,6 +5923,8 @@ function emitDispatch(p, ctx, pos) {
5537
5923
  return emit(def.parser, ctx, pos);
5538
5924
  case "token":
5539
5925
  return emitToken(def, ctx, pos);
5926
+ case "leaf":
5927
+ return emitLeaf(def, ctx, pos);
5540
5928
  case "label": {
5541
5929
  const inner = emitFallible(def.parser, ctx, pos);
5542
5930
  return {
@@ -5571,10 +5959,19 @@ function emitDispatch(p, ctx, pos) {
5571
5959
  ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
5572
5960
  }
5573
5961
  }
5962
+ const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
5574
5963
  const r = emit(def.parser, ctx, pos);
5575
5964
  ctx.activeTrivia = savedTrivia;
5576
5965
  ctx.triviaKindLabels = savedKindLabels;
5577
- return r;
5966
+ if (!savedCapture) return r;
5967
+ return {
5968
+ ...r,
5969
+ stmts: [
5970
+ `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
5971
+ ...r.stmts,
5972
+ `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
5973
+ ]
5974
+ };
5578
5975
  }
5579
5976
  case "not":
5580
5977
  return emitNot(def, ctx, pos);
@@ -5659,6 +6056,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
5659
6056
  case "grammar":
5660
6057
  case "trivia":
5661
6058
  case "token":
6059
+ case "leaf":
5662
6060
  case "label":
5663
6061
  case "field":
5664
6062
  case "optional":
@@ -5686,16 +6084,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
5686
6084
  return false;
5687
6085
  }
5688
6086
  }
6087
+ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
6088
+ if (seen.has(p)) return false;
6089
+ seen.add(p);
6090
+ const d = p._def;
6091
+ if (d.tag === "node" && d.build !== void 0) return true;
6092
+ if (d.tag === "lazy") {
6093
+ try {
6094
+ return hasDirectBuildDef(d.thunk(), seen);
6095
+ } catch {
6096
+ return false;
6097
+ }
6098
+ }
6099
+ return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
6100
+ }
5689
6101
  function childrenOf(def) {
5690
6102
  switch (def.tag) {
5691
6103
  case "sequence":
5692
6104
  case "choice":
5693
6105
  return def.parsers;
5694
6106
  case "many":
6107
+ case "attempt":
5695
6108
  case "optional":
5696
6109
  case "transform":
5697
6110
  case "trivia":
5698
6111
  case "token":
6112
+ case "leaf":
5699
6113
  case "label":
5700
6114
  case "field":
5701
6115
  case "grammar":
@@ -5870,10 +6284,25 @@ function compile(combinator, mapFnSources, opts) {
5870
6284
  namedFnDecls: [],
5871
6285
  capturing: hasNodeDef(combinator),
5872
6286
  recovery: opts?.recovery ?? false,
6287
+ ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
5873
6288
  lazyUsage: analyzeLazyUsage(combinator),
5874
6289
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
5875
6290
  };
5876
6291
  const r = emit(combinator, ctx, "_pos");
6292
+ const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
6293
+ const resultBody = coverageRootRuleId === void 0 ? [
6294
+ ` let pos = _pos`,
6295
+ ...r.stmts,
6296
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6297
+ ] : [
6298
+ ` const _coverageResult = (() => {`,
6299
+ ` let pos = _pos`,
6300
+ ...r.stmts,
6301
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6302
+ ` })()`,
6303
+ ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6304
+ ` return _coverageResult`
6305
+ ];
5877
6306
  const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
5878
6307
  const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
5879
6308
  const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
@@ -5886,9 +6315,7 @@ function compile(combinator, mapFnSources, opts) {
5886
6315
  ...namedPrelude,
5887
6316
  ctx.namedFnDecls.join("\n\n"),
5888
6317
  `function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
5889
- ` let pos = _pos`,
5890
- ...r.stmts,
5891
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6318
+ ...resultBody,
5892
6319
  `}`
5893
6320
  ].join("\n");
5894
6321
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
@@ -5898,9 +6325,15 @@ function compile(combinator, mapFnSources, opts) {
5898
6325
  ...ctx.expectedDecls,
5899
6326
  ...namedPrelude,
5900
6327
  ...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
5901
- `let pos = _pos`,
5902
- ...r.stmts,
5903
- `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6328
+ ...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
6329
+ `const _coverageResult = (() => {`,
6330
+ ` let pos = _pos`,
6331
+ ...r.stmts,
6332
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6333
+ `})()`,
6334
+ `if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6335
+ `return _coverageResult`
6336
+ ]
5904
6337
  ].join("\n"));
5905
6338
  const defaultCtx = {
5906
6339
  trackLines: false,
@@ -5912,10 +6345,11 @@ function compile(combinator, mapFnSources, opts) {
5912
6345
  const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
5913
6346
  const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
5914
6347
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
5915
- const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
6348
+ const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
5916
6349
  return {
5917
6350
  source,
5918
6351
  inlineExpression,
6352
+ ...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
5919
6353
  parse(input, pos = 0) {
5920
6354
  return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
5921
6355
  },
@@ -5978,8 +6412,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
5978
6412
  triviaCaptureNames: /* @__PURE__ */ new Map(),
5979
6413
  triviaFnNames: /* @__PURE__ */ new Map(),
5980
6414
  namedFnDecls: [],
5981
- capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
6415
+ // A recognition-only fragment normally has no node collector of its own.
6416
+ // Leaf composition can re-lower it beneath a local semantic node, though;
6417
+ // in that case its terminals must feed the caller's collector rather than
6418
+ // merely returning their scalar parse values.
6419
+ capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
5982
6420
  recovery: opts?.recovery ?? false,
6421
+ ...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
5983
6422
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
5984
6423
  ns,
5985
6424
  deferFirstSetRefs: true,
@@ -6053,7 +6492,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
6053
6492
  ctx.indent = savedIndent;
6054
6493
  ctx.failLabel = savedFail;
6055
6494
  ctx.recordFail = savedRec;
6056
- pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
6495
+ const ruleId = ctx.coverage?.plan.rules.get(rule);
6496
+ const stmts = ruleId === void 0 ? body.stmts : [
6497
+ `${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
6498
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
6499
+ ...body.stmts,
6500
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
6501
+ ];
6502
+ pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
6057
6503
  }
6058
6504
  perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
6059
6505
  }
@@ -6110,15 +6556,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
6110
6556
  deps: ruleDependencies(ruleMap),
6111
6557
  needsEmptyTl: !!ctx.needsEmptyTl,
6112
6558
  needsHostReads: !!ctx.needsHostReads,
6559
+ hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
6560
+ isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
6113
6561
  mfFns: mfSrcs ? [] : ctx.mapFns,
6114
6562
  buildFns: buildSrcs ? [] : ctx.buildFns
6115
6563
  };
6116
6564
  }
6117
- function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
6118
- const bodyLines = [
6565
+ function hasSemanticReduction(roots) {
6566
+ const seen = /* @__PURE__ */ new Set();
6567
+ const visit = (parser2) => {
6568
+ if (seen.has(parser2)) return false;
6569
+ seen.add(parser2);
6570
+ const def = parser2._def;
6571
+ if (def.tag === "transform" && !def.recognitionOnly) return true;
6572
+ if (def.tag === "choice" && def.gates.some(Boolean)) return true;
6573
+ if (def.tag === "guard" || def.tag === "withCtx") return true;
6574
+ if (def.tag === "node" && def.build !== void 0) return true;
6575
+ if (def.tag === "lazy") {
6576
+ try {
6577
+ return visit(def.thunk());
6578
+ } catch {
6579
+ return true;
6580
+ }
6581
+ }
6582
+ return childrenOf(def).some(visit);
6583
+ };
6584
+ return roots.some(visit);
6585
+ }
6586
+ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
6587
+ const bodyLines = coverageRootRuleId === void 0 ? [
6119
6588
  ` let pos = _pos`,
6120
6589
  ...r.stmts,
6121
6590
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6591
+ ] : [
6592
+ ` const _coverageResult = (() => {`,
6593
+ ` let pos = _pos`,
6594
+ ...r.stmts,
6595
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6596
+ ` })()`,
6597
+ ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6598
+ ` return _coverageResult`
6122
6599
  ];
6123
6600
  const innerFn = [
6124
6601
  `function(input, _pos, _ctx) {`,
@@ -6173,8 +6650,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
6173
6650
  };
6174
6651
  const emit2 = (end) => {
6175
6652
  if (end > pos && cstCaptureActive(ctx)) {
6176
- const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
6177
- pushCstLeaf(ctx, leaf);
6653
+ const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
6654
+ pushCstLeaf(ctx, leaf2);
6178
6655
  }
6179
6656
  };
6180
6657
  while (cur < input.length) {
@@ -6228,6 +6705,7 @@ function balanced(open, close, options = {}) {
6228
6705
  );
6229
6706
  if (combi._def.tag === "transform") {
6230
6707
  combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
6708
+ combi._def.recognitionOnly = true;
6231
6709
  }
6232
6710
  self.define(combi);
6233
6711
  return combi;
@@ -6273,9 +6751,11 @@ function childrenOf2(def) {
6273
6751
  case "many":
6274
6752
  case "oneOrMore":
6275
6753
  case "optional":
6754
+ case "attempt":
6276
6755
  case "transform":
6277
6756
  case "trivia":
6278
6757
  case "token":
6758
+ case "leaf":
6279
6759
  case "label":
6280
6760
  case "field":
6281
6761
  case "not":
@@ -6324,7 +6804,7 @@ function serializeRuleMap(ruleMap) {
6324
6804
  }
6325
6805
  }
6326
6806
  function evalRuleMapIR(ir) {
6327
- const _tf = (child, src) => {
6807
+ const _tf = (child, src, recognitionOnly = false) => {
6328
6808
  let fn2;
6329
6809
  try {
6330
6810
  fn2 = (0, eval)(`(${src})`);
@@ -6335,11 +6815,31 @@ function evalRuleMapIR(ir) {
6335
6815
  }
6336
6816
  const t = transform(child, fn2);
6337
6817
  t._def.fnSrc = src;
6818
+ if (recognitionOnly) t._def.recognitionOnly = true;
6338
6819
  return t;
6339
6820
  };
6340
- const _nd = (type, child, src, opts) => {
6341
- const n = node(type, child, void 0, opts);
6821
+ const _lf = (child, src) => {
6822
+ let fn2;
6823
+ try {
6824
+ fn2 = (0, eval)(`(${src})`);
6825
+ } catch {
6826
+ fn2 = () => {
6827
+ throw new Error("IR leaf fn not materialized");
6828
+ };
6829
+ }
6830
+ const l = leaf(child, fn2);
6831
+ l._def.fnSrc = src;
6832
+ return l;
6833
+ };
6834
+ const _nd = (type, child, src, opts, staticError) => {
6835
+ if (staticError !== void 0 && staticError.length > 0) {
6836
+ throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
6837
+ }
6838
+ const n = node(type, child, (() => {
6839
+ throw new Error("IR node build requires static re-lowering");
6840
+ }), opts);
6342
6841
  n._def.buildSrc = src;
6842
+ if (staticError !== void 0) n._def.buildStaticError = staticError;
6343
6843
  return n;
6344
6844
  };
6345
6845
  const _gch = (items) => {
@@ -6389,6 +6889,7 @@ function evalRuleMapIR(ir) {
6389
6889
  "keywords",
6390
6890
  "sequence",
6391
6891
  "choice",
6892
+ "attempt",
6392
6893
  "many",
6393
6894
  "oneOrMore",
6394
6895
  "optional",
@@ -6398,6 +6899,7 @@ function evalRuleMapIR(ir) {
6398
6899
  "parser",
6399
6900
  "scanTo",
6400
6901
  "token",
6902
+ "leaf",
6401
6903
  "transform",
6402
6904
  "skip",
6403
6905
  "trivia",
@@ -6405,6 +6907,7 @@ function evalRuleMapIR(ir) {
6405
6907
  "field",
6406
6908
  "expect",
6407
6909
  "_tf",
6910
+ "_lf",
6408
6911
  "_nd",
6409
6912
  "_gch",
6410
6913
  "_wc",
@@ -6418,6 +6921,7 @@ function evalRuleMapIR(ir) {
6418
6921
  keywords,
6419
6922
  sequence,
6420
6923
  choice,
6924
+ attempt,
6421
6925
  many,
6422
6926
  oneOrMore,
6423
6927
  optional,
@@ -6427,6 +6931,7 @@ function evalRuleMapIR(ir) {
6427
6931
  parser,
6428
6932
  scanTo,
6429
6933
  token,
6934
+ leaf,
6430
6935
  transform,
6431
6936
  skip,
6432
6937
  trivia,
@@ -6434,6 +6939,7 @@ function evalRuleMapIR(ir) {
6434
6939
  field,
6435
6940
  expect,
6436
6941
  _tf,
6942
+ _lf,
6437
6943
  _nd,
6438
6944
  _gch,
6439
6945
  _wc
@@ -6565,6 +7071,8 @@ ${body}
6565
7071
  return `oneOrMore(${kid(def.parser)})`;
6566
7072
  case "optional":
6567
7073
  return `optional(${kid(def.parser)})`;
7074
+ case "attempt":
7075
+ return `attempt(${kid(def.parser)})`;
6568
7076
  case "sepBy":
6569
7077
  return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
6570
7078
  case "not":
@@ -6573,6 +7081,10 @@ ${body}
6573
7081
  return `trivia(${kid(def.parser)})`;
6574
7082
  case "token":
6575
7083
  return `token(${kid(def.parser)})`;
7084
+ case "leaf": {
7085
+ if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
7086
+ return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
7087
+ }
6576
7088
  case "label":
6577
7089
  return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
6578
7090
  case "field":
@@ -6585,21 +7097,30 @@ ${body}
6585
7097
  return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
6586
7098
  case "transform": {
6587
7099
  if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
6588
- return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
7100
+ return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
6589
7101
  }
6590
7102
  case "node": {
6591
7103
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
6592
- const opts = def.unwrap || def.collapse ? `, { ${def.unwrap ? "unwrap: true" : "collapse: true"} }` : "";
7104
+ const optEntries = [
7105
+ ...def.unwrap ? ["unwrap: true"] : [],
7106
+ ...def.collapse ? ["collapse: true"] : [],
7107
+ ...def.captureTrivia ? ["captureTrivia: true"] : [],
7108
+ ...def.trailingTrivia ? ["trailingTrivia: true"] : []
7109
+ ];
7110
+ const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
6593
7111
  if (def.type === void 0) {
6594
7112
  if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
6595
7113
  return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
6596
7114
  }
6597
- if (def.buildSrc !== void 0) return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts})`;
7115
+ if (def.buildSrc !== void 0) {
7116
+ const staticError = def.buildStaticError === void 0 ? "" : `${opts ? "" : ", undefined"}, ${JSON.stringify(def.buildStaticError)}`;
7117
+ return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${staticError})`;
7118
+ }
6598
7119
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
6599
7120
  }
6600
7121
  case "grammar": {
6601
7122
  const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
6602
- return `parser({ trivia: ${trivia2}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
7123
+ return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
6603
7124
  }
6604
7125
  case "withCtx": {
6605
7126
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -6628,18 +7149,20 @@ function normalizeCstCollapse(collapse) {
6628
7149
  }
6629
7150
  return typeof collapse === "function" ? collapse : void 0;
6630
7151
  }
6631
- function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
6632
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
7152
+ function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
7153
+ return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
6633
7154
  }
6634
- function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
7155
+ function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
6635
7156
  if (typeof typeOrOptions === "string") {
6636
- return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
7157
+ return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
6637
7158
  }
6638
7159
  const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
6639
- const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children2, fields, span2, rawChildren2, triviaLog2, state2);
7160
+ const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
7161
+ host._parsemanCstOutput = true;
6640
7162
  if (collapse) host._parsemanCstCollapse = collapse;
6641
7163
  return host;
6642
7164
  }
7165
+ cstBuildHost._parsemanCstOutput = true;
6643
7166
  function fusedBody(pieces) {
6644
7167
  const winner = /* @__PURE__ */ new Map();
6645
7168
  for (const p of pieces) for (const k of p.keys) winner.set(k, p);
@@ -6693,13 +7216,39 @@ function fuseRules(pieces) {
6693
7216
  return new Function("_env", body)(env);
6694
7217
  }
6695
7218
  var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
7219
+ var LEAF_COMPOSED = /* @__PURE__ */ Symbol.for("parseman.leafComposed");
6696
7220
  var COMPOSED_TRIVIA = /* @__PURE__ */ Symbol.for("parseman.composedTrivia");
7221
+ var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCoverageRules");
6697
7222
  function isIRPiece(p) {
6698
7223
  return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
6699
7224
  }
6700
- function materializePiece(p, trivia2) {
7225
+ function coverageRulesOf(carried) {
7226
+ const winners = {};
7227
+ for (const piece of carried) {
7228
+ if (!isIRPiece(piece)) return void 0;
7229
+ const map = evalRuleMapIR(piece.ir);
7230
+ for (const [name, rule] of map) {
7231
+ if (rule._def.tag === "lazy") {
7232
+ try {
7233
+ rule._def.thunk();
7234
+ } catch {
7235
+ continue;
7236
+ }
7237
+ }
7238
+ winners[name] = rule;
7239
+ }
7240
+ }
7241
+ return winners;
7242
+ }
7243
+ function composedCoverageRules(grammar) {
7244
+ return grammar[COMPOSED_COVERAGE_RULES];
7245
+ }
7246
+ function materializePiece(p, trivia2, captureTerminals = false) {
6701
7247
  if (!isIRPiece(p)) return p;
6702
- const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, trivia2 ? { trivia: trivia2 } : void 0);
7248
+ const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
7249
+ ...trivia2 ? { trivia: trivia2 } : {},
7250
+ ...captureTerminals ? { captureTerminals: true } : {}
7251
+ });
6703
7252
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
6704
7253
  return pieces;
6705
7254
  }
@@ -6750,6 +7299,9 @@ function composingTriviaOf(items) {
6750
7299
  return void 0;
6751
7300
  }
6752
7301
  function compose(items) {
7302
+ if (items.some((item) => item[LEAF_COMPOSED] === true)) {
7303
+ throw new Error("compose: a composeLeaf() result is terminal and cannot be composed again");
7304
+ }
6753
7305
  const used = /* @__PURE__ */ new Set();
6754
7306
  const trivia2 = composingTriviaOf(items);
6755
7307
  const carried = items.flatMap((item) => itemCarried(item, used, trivia2));
@@ -6757,8 +7309,13 @@ function compose(items) {
6757
7309
  const map = fuseRules(pieces);
6758
7310
  Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
6759
7311
  if (trivia2) Object.defineProperty(map, COMPOSED_TRIVIA, { value: trivia2, enumerable: false });
7312
+ const coverageRules = coverageRulesOf(carried);
7313
+ if (coverageRules) Object.defineProperty(map, COMPOSED_COVERAGE_RULES, { value: coverageRules, enumerable: false });
6760
7314
  return map;
6761
7315
  }
7316
+ function composeLeaf(_items) {
7317
+ throw new Error("composeLeaf(): requires Parseman macro lowering; runtime composition is forbidden");
7318
+ }
6762
7319
 
6763
7320
  // src/combinators/guard.ts
6764
7321
  function guard(predicate) {
@@ -6922,7 +7479,9 @@ function producesRepetition(def, depth = 0) {
6922
7479
  // Transparent wrappers — look through to the inner parser.
6923
7480
  case "node":
6924
7481
  case "transform":
7482
+ case "attempt":
6925
7483
  case "token":
7484
+ case "leaf":
6926
7485
  case "label":
6927
7486
  case "field":
6928
7487
  case "expect":
@@ -6974,8 +7533,8 @@ function replaceAtPath(rebuild, root, path, newNode) {
6974
7533
  newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
6975
7534
  return rebuild(root, newChildren);
6976
7535
  }
6977
- function defaultRebuild(node2, children) {
6978
- return { ...node2, children };
7536
+ function defaultRebuild(node2, children2) {
7537
+ return { ...node2, children: children2 };
6979
7538
  }
6980
7539
  function shiftRelStart(child, delta) {
6981
7540
  const c = child;
@@ -7315,7 +7874,8 @@ function runOnce(entry, input, options, phase, profileState) {
7315
7874
  state: options.state,
7316
7875
  ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
7317
7876
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
7318
- ...options.tolerant ? { _tolerant: true, _rec: REC } : {}
7877
+ ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
7878
+ ...options.instrumentation === void 0 ? {} : options.instrumentation
7319
7879
  };
7320
7880
  const r = invoke(entry, input, 0, ctx);
7321
7881
  let unconsumedFrom = null;
@@ -7370,6 +7930,265 @@ function run(entry, input, options = {}) {
7370
7930
  };
7371
7931
  }
7372
7932
 
7933
+ // src/coverage.ts
7934
+ var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
7935
+ function compiledGrammarCoverageDefinitions(grammar) {
7936
+ const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
7937
+ if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "label"))) {
7938
+ throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
7939
+ }
7940
+ return definitions;
7941
+ }
7942
+ function createGrammarInstrumentationContext(options = {}) {
7943
+ return {
7944
+ trackLines: options.trackLines ?? false,
7945
+ ...options.state === void 0 ? {} : { state: options.state },
7946
+ ...options.collector === void 0 ? {} : { _grammarCoverage: (id) => options.collector.hit(id) },
7947
+ ...options.trace === void 0 ? {} : { _grammarTrace: options.trace }
7948
+ };
7949
+ }
7950
+ function createGrammarTraceSink(options) {
7951
+ if (!Number.isInteger(options.capacity) || options.capacity < 0) throw new TypeError("trace capacity must be a finite non-negative integer");
7952
+ const events = [];
7953
+ let detached = false;
7954
+ let truncated = false;
7955
+ let dropped = 0;
7956
+ return {
7957
+ write(event) {
7958
+ if (detached || events.length >= options.capacity) {
7959
+ detached = true;
7960
+ truncated = true;
7961
+ dropped++;
7962
+ return;
7963
+ }
7964
+ events.push(Object.freeze({ ...event }));
7965
+ try {
7966
+ if (options.write?.(event) === false) {
7967
+ detached = true;
7968
+ truncated = true;
7969
+ }
7970
+ } catch {
7971
+ detached = true;
7972
+ truncated = true;
7973
+ }
7974
+ },
7975
+ snapshot() {
7976
+ return Object.freeze({ events: Object.freeze([...events]), truncated, dropped });
7977
+ }
7978
+ };
7979
+ }
7980
+ function createGrammarCoverageCollector(definitions) {
7981
+ const ordered = [...definitions].sort((a, b) => a.id.localeCompare(b.id));
7982
+ const known = new Set(ordered.map((definition) => definition.id));
7983
+ const hits = /* @__PURE__ */ new Set();
7984
+ return {
7985
+ hit(id) {
7986
+ if (known.has(id)) hits.add(id);
7987
+ },
7988
+ snapshot() {
7989
+ const hitList = [...hits].sort();
7990
+ const unhit = ordered.map((definition) => definition.id).filter((id) => !hits.has(id));
7991
+ return { definitions: ordered, hits: hitList, unhit, ratio: ordered.length === 0 ? 1 : hitList.length / ordered.length };
7992
+ },
7993
+ reset() {
7994
+ hits.clear();
7995
+ }
7996
+ };
7997
+ }
7998
+ function grammarCoverageDefinitions(entry, winners) {
7999
+ return buildGrammarPlan(entry, winners).definitions;
8000
+ }
8001
+ function composedGrammarCoverageDefinitions(grammar, startRule) {
8002
+ const winners = composedCoverageRules(grammar);
8003
+ if (!winners) throw new TypeError("semantic coverage needs re-lowerable composed IR; this composition contains an opaque artifact");
8004
+ const entry = winners[startRule];
8005
+ if (!entry) throw new TypeError(`semantic coverage start rule ${JSON.stringify(startRule)} is not a final winner`);
8006
+ return grammarCoverageDefinitions(entry, winners);
8007
+ }
8008
+ function coverageEntry(entry, collector, maps, trace) {
8009
+ const cache = /* @__PURE__ */ new WeakMap();
8010
+ const build = (parser2) => {
8011
+ const existing = cache.get(parser2);
8012
+ if (existing) return existing;
8013
+ const rule = maps.rules.get(parser2);
8014
+ const wrap = (parse2) => {
8015
+ const wrapped = {
8016
+ _tag: parser2._tag,
8017
+ _meta: parser2._meta,
8018
+ _def: parser2._def,
8019
+ parse(input, pos, ctx) {
8020
+ if (rule) {
8021
+ collector.hit(rule);
8022
+ trace?.write({ id: rule, phase: "enter", offset: pos });
8023
+ }
8024
+ const result = parse2(input, pos, ctx);
8025
+ if (rule) trace?.write(result.ok ? { id: rule, phase: "success", offset: pos, end: result.span.end } : { id: rule, phase: "failure", offset: result.span.end });
8026
+ return result;
8027
+ }
8028
+ };
8029
+ cache.set(parser2, wrapped);
8030
+ return wrapped;
8031
+ };
8032
+ const def = parser2._def;
8033
+ if (def.tag === "lazy") {
8034
+ return wrap((input, pos, ctx) => build(def.thunk()).parse(input, pos, ctx));
8035
+ }
8036
+ if (def.tag === "label") {
8037
+ const base2 = label(def.label, build(def.parser));
8038
+ return wrap((input, pos, ctx) => {
8039
+ const result = base2.parse(input, pos, ctx);
8040
+ if (result.ok) for (const id of maps.labels.get(parser2) ?? []) {
8041
+ collector.hit(id);
8042
+ trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
8043
+ }
8044
+ return result;
8045
+ });
8046
+ }
8047
+ if (def.tag === "choice") {
8048
+ const ids = maps.choices.get(parser2) ?? [];
8049
+ const invocations = [];
8050
+ const arms = def.parsers.map((arm, index) => {
8051
+ const child = build(arm);
8052
+ return {
8053
+ _tag: child._tag,
8054
+ _meta: child._meta,
8055
+ _def: child._def,
8056
+ parse(input, pos, ctx) {
8057
+ const id = ids[index];
8058
+ if (id) trace?.write({ id, phase: "attempt", offset: pos });
8059
+ const result = child.parse(input, pos, ctx);
8060
+ if (result.ok) {
8061
+ if (def.strategy.tag !== "greedyClassify") collector.hit(ids[index]);
8062
+ const invocation = invocations[invocations.length - 1];
8063
+ if (invocation) {
8064
+ invocation.lastSuccessfulArm = index;
8065
+ invocation.successfulArms.push(index);
8066
+ }
8067
+ } else if (id) {
8068
+ trace?.write({ id, phase: "failure", offset: result.span.end });
8069
+ trace?.write({ id, phase: "backtrack", offset: pos });
8070
+ }
8071
+ return result;
8072
+ }
8073
+ };
8074
+ });
8075
+ const args = arms.map((arm, index) => def.gates[index] ? { combinator: arm, gate: def.gates[index] } : arm);
8076
+ const unsafeChoice = choice;
8077
+ const baseChoice = unsafeChoice(...args);
8078
+ return wrap((input, pos, ctx) => {
8079
+ const invocation = { lastSuccessfulArm: void 0, successfulArms: [] };
8080
+ invocations.push(invocation);
8081
+ const result = baseChoice.parse(input, pos, ctx);
8082
+ const strategy = def.strategy;
8083
+ if (result.ok && strategy.tag === "greedyClassify") {
8084
+ const text = input.slice(pos, result.span.end);
8085
+ const classified = def.parsers.findIndex((arm, index) => index !== strategy.superIndex && getCoreLiteralValue(arm) === text);
8086
+ if (classified !== -1) invocation.lastSuccessfulArm = classified;
8087
+ else invocation.lastSuccessfulArm = strategy.superIndex;
8088
+ }
8089
+ if (result.ok && invocation.lastSuccessfulArm !== void 0) {
8090
+ const id = ids[invocation.lastSuccessfulArm];
8091
+ for (const rejected of invocation.successfulArms) {
8092
+ if (rejected !== invocation.lastSuccessfulArm) {
8093
+ const rejectedId = ids[rejected];
8094
+ if (rejectedId) {
8095
+ trace?.write({ id: rejectedId, phase: "failure", offset: pos });
8096
+ trace?.write({ id: rejectedId, phase: "backtrack", offset: pos });
8097
+ }
8098
+ }
8099
+ }
8100
+ if (id) {
8101
+ collector.hit(id);
8102
+ trace?.write({ id, phase: "selected", offset: pos, end: result.span.end });
8103
+ trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
8104
+ }
8105
+ }
8106
+ invocations.pop();
8107
+ return result;
8108
+ });
8109
+ }
8110
+ const base = (() => {
8111
+ switch (def.tag) {
8112
+ case "sequence": {
8113
+ const unsafeSequence = sequence;
8114
+ return unsafeSequence(...def.parsers.map(build));
8115
+ }
8116
+ case "many":
8117
+ return many(build(def.parser));
8118
+ case "oneOrMore":
8119
+ return oneOrMore(build(def.parser));
8120
+ case "optional":
8121
+ return optional(build(def.parser));
8122
+ case "attempt": {
8123
+ const base2 = attempt(build(def.parser));
8124
+ const id = maps.attempts.get(parser2);
8125
+ return id === void 0 ? base2 : {
8126
+ ...base2,
8127
+ parse(input, pos, ctx) {
8128
+ const result = base2.parse(input, pos, ctx);
8129
+ if (!result.ok) trace?.write({ id, phase: "rollback", offset: pos });
8130
+ return result;
8131
+ }
8132
+ };
8133
+ }
8134
+ case "sepBy":
8135
+ return sepBy(build(def.parser), build(def.separator));
8136
+ case "transform":
8137
+ return transform(build(def.parser), def.fn);
8138
+ case "skip":
8139
+ return skip(build(def.main), build(def.skipped));
8140
+ case "trivia":
8141
+ return trivia(build(def.parser));
8142
+ case "token":
8143
+ return token(build(def.parser));
8144
+ case "leaf":
8145
+ return leaf(build(def.parser), def.fn);
8146
+ case "field":
8147
+ return field(def.name, build(def.parser));
8148
+ case "grammar":
8149
+ return parser({
8150
+ ...def.triviaParser === void 0 ? def.clearTrivia ? { trivia: null } : {} : { trivia: build(def.triviaParser) },
8151
+ ...def.captureTrivia ? { captureTrivia: true } : {},
8152
+ ...def.trackLines ? { trackLines: true } : {}
8153
+ }, build(def.parser));
8154
+ case "not":
8155
+ return not(build(def.parser));
8156
+ case "node": {
8157
+ const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
8158
+ return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
8159
+ }
8160
+ case "guard":
8161
+ return guard(def.predicate);
8162
+ case "withCtx":
8163
+ return withCtx(def.extra, build(def.parser));
8164
+ case "expect":
8165
+ return expect(build(def.parser), def.label);
8166
+ case "scanTo":
8167
+ return scanTo(build(def.sentinel), { skip: def.skip.map(build), orEOF: def.orEOF });
8168
+ case "literal":
8169
+ case "regex":
8170
+ case "keywords":
8171
+ return parser2;
8172
+ case "recover":
8173
+ case "unknown":
8174
+ throw new TypeError(`runWithGrammarCoverage does not yet support ${def.tag}`);
8175
+ default:
8176
+ return parser2;
8177
+ }
8178
+ })();
8179
+ return wrap((input, pos, ctx) => base.parse(input, pos, ctx));
8180
+ };
8181
+ return build(entry);
8182
+ }
8183
+ function runWithGrammarCoverage(entry, input, options = {}) {
8184
+ if (typeof entry === "function") throw new TypeError("runWithGrammarCoverage currently requires an interpreter combinator entry");
8185
+ const plan = buildGrammarPlan(entry);
8186
+ const definitions = plan.definitions;
8187
+ const collector = options.collector ?? createGrammarCoverageCollector(definitions);
8188
+ const { collector: _collector, trace, ...runOptions } = options;
8189
+ return { result: run(coverageEntry(entry, collector, plan, trace), input, runOptions), coverage: collector.snapshot() };
8190
+ }
8191
+
7373
8192
  // src/cst/trivia-index.ts
7374
8193
  function merge(map, key, run2) {
7375
8194
  if (run2.length === 0) return;
@@ -7440,9 +8259,9 @@ function buildTriviaIndex(root, input = "", opts) {
7440
8259
  function walk(root, visitor, ctx = void 0) {
7441
8260
  const go = (node2, parent) => {
7442
8261
  const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
7443
- const children = node2.children;
7444
- if (descend !== false && Array.isArray(children)) {
7445
- for (const child of children) go(child, node2);
8262
+ const children2 = node2.children;
8263
+ if (descend !== false && Array.isArray(children2)) {
8264
+ for (const child of children2) go(child, node2);
7446
8265
  }
7447
8266
  visitor.leave?.(node2, parent, ctx);
7448
8267
  };
@@ -7458,9 +8277,9 @@ function createVisitor(handlers) {
7458
8277
  },
7459
8278
  visitChildren(node2) {
7460
8279
  const out = [];
7461
- const children = node2.children;
7462
- if (Array.isArray(children)) {
7463
- for (const child of children) {
8280
+ const children2 = node2.children;
8281
+ if (Array.isArray(children2)) {
8282
+ for (const child of children2) {
7464
8283
  const r = api.visit(child);
7465
8284
  if (r !== void 0) out.push(r);
7466
8285
  }
@@ -7489,6 +8308,9 @@ function triviaEntries(log, labels, opts) {
7489
8308
  end(i) {
7490
8309
  return log[entryOffset(i, stride) + 1];
7491
8310
  },
8311
+ insertIndex(i) {
8312
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
8313
+ },
7492
8314
  kindIndex(i) {
7493
8315
  if (!labels) return void 0;
7494
8316
  return log[entryOffset(i, stride) + baseStride];
@@ -7698,6 +8520,7 @@ function buildOffsetIndex(root, input = "") {
7698
8520
  // src/index.ts
7699
8521
  registerRegexAnalyzer(firstSetFromRegex);
7700
8522
  export {
8523
+ GRAMMAR_COVERAGE_DEFINITIONS,
7701
8524
  OffsetIndex,
7702
8525
  absoluteSpanAt,
7703
8526
  absoluteSpanCST,
@@ -7705,6 +8528,7 @@ export {
7705
8528
  absolutizeCST,
7706
8529
  annotateSpan,
7707
8530
  applyEdit,
8531
+ attempt,
7708
8532
  balanced,
7709
8533
  blankLinesIn,
7710
8534
  buildLineIndex,
@@ -7714,20 +8538,28 @@ export {
7714
8538
  collectLeafSlots,
7715
8539
  commentsIn,
7716
8540
  compile,
8541
+ compiledGrammarCoverageDefinitions,
7717
8542
  completionsAt,
7718
8543
  compose,
8544
+ composeLeaf,
8545
+ composedGrammarCoverageDefinitions,
8546
+ createGrammarCoverageCollector,
8547
+ createGrammarInstrumentationContext,
8548
+ createGrammarTraceSink,
7719
8549
  createVisitor,
7720
8550
  cstBuildHost,
7721
8551
  expect,
7722
8552
  field,
7723
8553
  gapIsSignificant,
7724
8554
  gapText,
8555
+ grammarCoverageDefinitions,
7725
8556
  guard,
7726
8557
  indentMixed,
7727
8558
  indentWidth,
7728
8559
  isParseError,
7729
8560
  keywords,
7730
8561
  label,
8562
+ leaf,
7731
8563
  lineBreaksIn,
7732
8564
  lineStartWithin,
7733
8565
  literal,
@@ -7748,6 +8580,7 @@ export {
7748
8580
  relativizeCST,
7749
8581
  rules,
7750
8582
  run,
8583
+ runWithGrammarCoverage,
7751
8584
  scanTo,
7752
8585
  sepBy,
7753
8586
  sequence,