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.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ GRAMMAR_COVERAGE_DEFINITIONS: () => GRAMMAR_COVERAGE_DEFINITIONS,
23
24
  OffsetIndex: () => OffsetIndex,
24
25
  absoluteSpanAt: () => absoluteSpanAt,
25
26
  absoluteSpanCST: () => absoluteSpanCST,
@@ -27,6 +28,7 @@ __export(index_exports, {
27
28
  absolutizeCST: () => absolutizeCST,
28
29
  annotateSpan: () => annotateSpan,
29
30
  applyEdit: () => applyEdit,
31
+ attempt: () => attempt,
30
32
  balanced: () => balanced,
31
33
  blankLinesIn: () => blankLinesIn,
32
34
  buildLineIndex: () => buildLineIndex,
@@ -36,20 +38,28 @@ __export(index_exports, {
36
38
  collectLeafSlots: () => collectLeafSlots,
37
39
  commentsIn: () => commentsIn,
38
40
  compile: () => compile,
41
+ compiledGrammarCoverageDefinitions: () => compiledGrammarCoverageDefinitions,
39
42
  completionsAt: () => completionsAt,
40
43
  compose: () => compose,
44
+ composeLeaf: () => composeLeaf,
45
+ composedGrammarCoverageDefinitions: () => composedGrammarCoverageDefinitions,
46
+ createGrammarCoverageCollector: () => createGrammarCoverageCollector,
47
+ createGrammarInstrumentationContext: () => createGrammarInstrumentationContext,
48
+ createGrammarTraceSink: () => createGrammarTraceSink,
41
49
  createVisitor: () => createVisitor,
42
50
  cstBuildHost: () => cstBuildHost,
43
51
  expect: () => expect,
44
52
  field: () => field,
45
53
  gapIsSignificant: () => gapIsSignificant,
46
54
  gapText: () => gapText,
55
+ grammarCoverageDefinitions: () => grammarCoverageDefinitions,
47
56
  guard: () => guard,
48
57
  indentMixed: () => indentMixed,
49
58
  indentWidth: () => indentWidth,
50
59
  isParseError: () => isParseError,
51
60
  keywords: () => keywords,
52
61
  label: () => label,
62
+ leaf: () => leaf,
53
63
  lineBreaksIn: () => lineBreaksIn,
54
64
  lineStartWithin: () => lineStartWithin,
55
65
  literal: () => literal,
@@ -70,6 +80,7 @@ __export(index_exports, {
70
80
  relativizeCST: () => relativizeCST,
71
81
  rules: () => rules,
72
82
  run: () => run,
83
+ runWithGrammarCoverage: () => runWithGrammarCoverage,
73
84
  scanTo: () => scanTo,
74
85
  sepBy: () => sepBy,
75
86
  sequence: () => sequence,
@@ -147,6 +158,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
147
158
  case "label":
148
159
  case "trivia":
149
160
  case "token":
161
+ case "leaf":
150
162
  case "expect":
151
163
  case "withCtx":
152
164
  case "node":
@@ -210,6 +222,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
210
222
  case "label":
211
223
  case "trivia":
212
224
  case "token":
225
+ case "leaf":
213
226
  case "node":
214
227
  case "grammar":
215
228
  case "expect":
@@ -278,10 +291,10 @@ function beginCstNodeCapture(ctx) {
278
291
  }
279
292
  function finishCstBuf(buf) {
280
293
  if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
281
- const children = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
294
+ const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
282
295
  const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
283
296
  const triviaLog = buf.tl ?? EMPTY_TL;
284
- return { children, rawChildren, triviaLog };
297
+ return { children: children2, rawChildren, triviaLog };
285
298
  }
286
299
  function endCstNodeCapture(ctx, saved) {
287
300
  const materialized = finishCstBuf(ctx._cstBuf);
@@ -293,8 +306,8 @@ function endCstNodeCapture(ctx, saved) {
293
306
  ctx.captureTrivia = saved.cap;
294
307
  return materialized;
295
308
  }
296
- function pushCstLeaf(ctx, leaf) {
297
- pushCstChild(ctx, leaf, leaf);
309
+ function pushCstLeaf(ctx, leaf2) {
310
+ pushCstChild(ctx, leaf2, leaf2);
298
311
  }
299
312
  function pushCstChild(ctx, built, rawEntry) {
300
313
  const b = ctx._cstBuf;
@@ -1028,10 +1041,13 @@ function deriveExpected(c) {
1028
1041
  return def.parsers.flatMap(deriveExpected);
1029
1042
  case "sequence":
1030
1043
  return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1044
+ case "attempt":
1045
+ return deriveExpected(def.parser);
1031
1046
  case "node":
1032
1047
  case "grammar":
1033
1048
  case "trivia":
1034
1049
  case "token":
1050
+ case "leaf":
1035
1051
  case "optional":
1036
1052
  case "many":
1037
1053
  case "oneOrMore":
@@ -1525,6 +1541,12 @@ function scanTrivia(input, cur, ctx) {
1525
1541
  const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1526
1542
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1527
1543
  }
1544
+ function consumeTrivia(input, cur, ctx) {
1545
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1546
+ const scan = scanTrivia(input, cur, ctx);
1547
+ scan.commit();
1548
+ return scan.end;
1549
+ }
1528
1550
  function fastTriviaScanner(trivia2) {
1529
1551
  const cached = fastTriviaCache.get(trivia2);
1530
1552
  if (cached !== void 0) return cached;
@@ -1803,6 +1825,24 @@ function sequence(...parsers) {
1803
1825
  };
1804
1826
  }
1805
1827
 
1828
+ // src/combinators/attempt.ts
1829
+ function attempt(parser2) {
1830
+ return {
1831
+ _tag: "attempt",
1832
+ _meta: parser2._meta,
1833
+ _def: { tag: "attempt", parser: parser2 },
1834
+ parse(input, pos, ctx) {
1835
+ const mark = saveCstMark(ctx);
1836
+ const log = ctx._triviaLog?.length;
1837
+ const result = parser2.parse(input, pos, ctx);
1838
+ if (result.ok) return result;
1839
+ rollbackCstCapture(ctx, mark);
1840
+ if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
1841
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
1842
+ }
1843
+ };
1844
+ }
1845
+
1806
1846
  // src/combinators/repeat.ts
1807
1847
  function repItem(combinator, input, cur, ctx) {
1808
1848
  const mark = saveTriviaMark(ctx);
@@ -2112,10 +2152,14 @@ function markUnusedValues(root) {
2112
2152
  case "label":
2113
2153
  case "trivia":
2114
2154
  case "token":
2155
+ case "attempt":
2115
2156
  case "withCtx":
2116
2157
  case "expect":
2117
2158
  visit(def.parser, consumed);
2118
2159
  return;
2160
+ case "leaf":
2161
+ visit(def.parser, true);
2162
+ return;
2119
2163
  case "lazy":
2120
2164
  return;
2121
2165
  default:
@@ -2238,6 +2282,20 @@ function confirmedBuildArity(src) {
2238
2282
  if (/\barguments\b/.test(s)) return null;
2239
2283
  return parts.length;
2240
2284
  }
2285
+ function buildReadsChildren(def) {
2286
+ if (!def.build) return true;
2287
+ const src = def.buildSrc ?? def.build.toString();
2288
+ const arity = confirmedBuildArity(src);
2289
+ if (arity === null) return true;
2290
+ return arity >= 1;
2291
+ }
2292
+ function buildReadsRaw(def) {
2293
+ if (!def.build) return true;
2294
+ const src = def.buildSrc ?? def.build.toString();
2295
+ const arity = confirmedBuildArity(src);
2296
+ if (arity === null) return true;
2297
+ return arity >= 4;
2298
+ }
2241
2299
  function buildReadsTrivia(def) {
2242
2300
  if (!def.build) return true;
2243
2301
  const src = def.buildSrc ?? def.build.toString();
@@ -2293,9 +2351,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
2293
2351
  case "many":
2294
2352
  case "oneOrMore":
2295
2353
  case "optional":
2354
+ case "attempt":
2296
2355
  case "transform":
2297
2356
  case "trivia":
2298
2357
  case "token":
2358
+ case "leaf":
2299
2359
  case "label":
2300
2360
  case "expect":
2301
2361
  case "withCtx":
@@ -2328,9 +2388,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
2328
2388
  case "keywords":
2329
2389
  case "guard":
2330
2390
  case "token":
2391
+ case "leaf":
2331
2392
  return false;
2332
2393
  // Transparent single-child wrappers: recurse.
2333
2394
  case "optional":
2395
+ case "attempt":
2334
2396
  case "transform":
2335
2397
  case "trivia":
2336
2398
  case "label":
@@ -2354,6 +2416,54 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
2354
2416
  return true;
2355
2417
  }
2356
2418
  }
2419
+ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
2420
+ if (seen.has(p)) return false;
2421
+ seen.add(p);
2422
+ const d = p._def;
2423
+ switch (d.tag) {
2424
+ case "grammar":
2425
+ return d.captureTrivia === true || parserEnablesTriviaCapture(d.parser, seen);
2426
+ case "node":
2427
+ return false;
2428
+ case "sequence":
2429
+ case "choice":
2430
+ return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
2431
+ case "sepBy":
2432
+ return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
2433
+ case "skip":
2434
+ return parserEnablesTriviaCapture(d.main, seen) || parserEnablesTriviaCapture(d.skipped, seen);
2435
+ case "scanTo":
2436
+ return parserEnablesTriviaCapture(d.sentinel, seen) || d.skip.some((x) => parserEnablesTriviaCapture(x, seen));
2437
+ case "recover":
2438
+ return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.sentinel, seen);
2439
+ case "many":
2440
+ case "oneOrMore":
2441
+ case "optional":
2442
+ case "attempt":
2443
+ case "transform":
2444
+ case "trivia":
2445
+ case "token":
2446
+ case "label":
2447
+ case "field":
2448
+ case "expect":
2449
+ case "withCtx":
2450
+ case "not":
2451
+ return parserEnablesTriviaCapture(d.parser, seen);
2452
+ // leaf() clears the inner CST/trivia collector and publishes only its own
2453
+ // terminal result. An inner parser() capture cannot reach this node.
2454
+ case "leaf":
2455
+ return false;
2456
+ case "lazy": {
2457
+ try {
2458
+ return parserEnablesTriviaCapture(d.thunk(), seen);
2459
+ } catch {
2460
+ return false;
2461
+ }
2462
+ }
2463
+ default:
2464
+ return false;
2465
+ }
2466
+ }
2357
2467
  function buildFieldMap(captures) {
2358
2468
  if (!captures?.length) return void 0;
2359
2469
  const out = {};
@@ -2391,11 +2501,13 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2391
2501
  };
2392
2502
  const unwrap = opts?.unwrap === true;
2393
2503
  const collapse = opts?.collapse === true;
2504
+ const captureTrivia = opts?.captureTrivia === true;
2505
+ const trailingTrivia = opts?.trailingTrivia === true;
2394
2506
  if (unwrap && collapse) {
2395
2507
  throw new Error("node() options cannot set both unwrap and collapse");
2396
2508
  }
2397
- const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
2398
- const capturesTrivia = build ? buildReadsTrivia(def) : true;
2509
+ const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
2510
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
2399
2511
  const clonesState = build ? buildReadsState(def) : true;
2400
2512
  const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
2401
2513
  return {
@@ -2411,16 +2523,21 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2411
2523
  ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
2412
2524
  }
2413
2525
  if (!capturesTrivia) ctx.captureTrivia = false;
2414
- const r = combinator.parse(input, pos, ctx);
2526
+ let r = combinator.parse(input, pos, ctx);
2527
+ if (r.ok && trailingTrivia && ctx.trivia) {
2528
+ const end = consumeTrivia(input, r.span.end, ctx);
2529
+ r = { ...r, span: { start: r.span.start, end } };
2530
+ }
2415
2531
  const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
2416
2532
  ctx._fields = savedFields;
2417
2533
  ctx._triviaCaptureMask = savedMask;
2418
- const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
2534
+ const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
2419
2535
  if (!r.ok) return r;
2420
2536
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2421
2537
  const nodeType = def.type ?? missingInferredType();
2422
- 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 };
2423
- const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
2538
+ const cstOutput = ctx.build?._parsemanCstOutput === true;
2539
+ 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 };
2540
+ 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 };
2424
2541
  if (saved.buf !== void 0 || saved.ch !== void 0) {
2425
2542
  pushCstChild(ctx, built, rawEntry);
2426
2543
  }
@@ -2537,6 +2654,7 @@ function parser(opts, root) {
2537
2654
  parser: root,
2538
2655
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2539
2656
  clearTrivia,
2657
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2540
2658
  trackLines: opts.trackLines ?? false
2541
2659
  },
2542
2660
  parse(input, pos, _ctx) {
@@ -2649,6 +2767,141 @@ function token(root) {
2649
2767
  }
2650
2768
  };
2651
2769
  }
2770
+ function leaf(root, fn) {
2771
+ const meta = {
2772
+ firstSet: root._meta.firstSet,
2773
+ canMatchNewline: root._meta.canMatchNewline,
2774
+ isTrivia: false
2775
+ };
2776
+ return {
2777
+ _tag: "leaf",
2778
+ _meta: meta,
2779
+ _def: { tag: "leaf", parser: root, fn },
2780
+ parse(input, pos, ctx) {
2781
+ const savedBuf = ctx._cstBuf;
2782
+ const savedChildren = ctx._cstChildren;
2783
+ const savedLeaves = ctx._cstLeaves;
2784
+ const savedRaw = ctx._cstRawChildren;
2785
+ const savedTriviaLog = ctx._cstTriviaLog;
2786
+ const savedOuterTriviaLog = ctx._triviaLog;
2787
+ const wasCapturing = cstCaptureActive(ctx);
2788
+ ctx._cstBuf = void 0;
2789
+ ctx._cstChildren = void 0;
2790
+ ctx._cstLeaves = void 0;
2791
+ ctx._cstRawChildren = void 0;
2792
+ ctx._cstTriviaLog = void 0;
2793
+ delete ctx._triviaLog;
2794
+ let result;
2795
+ try {
2796
+ result = root.parse(input, pos, ctx);
2797
+ } finally {
2798
+ ctx._cstBuf = savedBuf;
2799
+ ctx._cstChildren = savedChildren;
2800
+ ctx._cstLeaves = savedLeaves;
2801
+ ctx._cstRawChildren = savedRaw;
2802
+ ctx._cstTriviaLog = savedTriviaLog;
2803
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
2804
+ else ctx._triviaLog = savedOuterTriviaLog;
2805
+ }
2806
+ if (!result.ok) return result;
2807
+ const value = fn(result.value, result.span);
2808
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
2809
+ return { ok: true, value, span: result.span };
2810
+ }
2811
+ };
2812
+ }
2813
+
2814
+ // src/compiler/grammar-coverage-ids.ts
2815
+ function children(def, winners) {
2816
+ switch (def.tag) {
2817
+ case "sequence":
2818
+ case "choice":
2819
+ return def.parsers;
2820
+ case "many":
2821
+ case "oneOrMore":
2822
+ case "optional":
2823
+ case "attempt":
2824
+ case "transform":
2825
+ case "trivia":
2826
+ case "token":
2827
+ case "leaf":
2828
+ case "label":
2829
+ case "field":
2830
+ case "grammar":
2831
+ case "not":
2832
+ case "node":
2833
+ case "guard":
2834
+ case "withCtx":
2835
+ case "recover":
2836
+ case "expect":
2837
+ return "parser" in def ? [def.parser] : [];
2838
+ case "sepBy":
2839
+ return [def.parser, def.separator];
2840
+ case "skip":
2841
+ return [def.main, def.skipped];
2842
+ case "scanTo":
2843
+ return [def.sentinel, ...def.skip];
2844
+ case "lazy": {
2845
+ let resolved;
2846
+ try {
2847
+ resolved = def.thunk();
2848
+ } catch {
2849
+ return [];
2850
+ }
2851
+ const name = resolved._ruleName;
2852
+ return name && winners?.[name] ? [winners[name]] : [resolved];
2853
+ }
2854
+ default:
2855
+ return [];
2856
+ }
2857
+ }
2858
+ function buildGrammarPlan(entry, winners) {
2859
+ const definitions = /* @__PURE__ */ new Map();
2860
+ const choices = /* @__PURE__ */ new WeakMap();
2861
+ const attempts = /* @__PURE__ */ new WeakMap();
2862
+ const labels = /* @__PURE__ */ new WeakMap();
2863
+ const rules2 = /* @__PURE__ */ new WeakMap();
2864
+ const winnerNames = /* @__PURE__ */ new Map();
2865
+ if (winners) {
2866
+ for (const [name, winner] of Object.entries(winners)) {
2867
+ winnerNames.set(winner, name);
2868
+ if (winner._def.tag === "lazy") {
2869
+ try {
2870
+ winnerNames.set(winner._def.thunk(), name);
2871
+ } catch {
2872
+ }
2873
+ }
2874
+ }
2875
+ }
2876
+ const seen = /* @__PURE__ */ new Set();
2877
+ const visit = (parser2, path) => {
2878
+ if (seen.has(parser2)) return;
2879
+ seen.add(parser2);
2880
+ const rule = winnerNames.get(parser2) ?? parser2._ruleName;
2881
+ if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
2882
+ const id = `rule:${rule}`;
2883
+ definitions.set(id, { id, kind: "rule" });
2884
+ rules2.set(parser2, id);
2885
+ }
2886
+ if (parser2._def.tag === "choice") {
2887
+ const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
2888
+ choices.set(parser2, ids);
2889
+ ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
2890
+ }
2891
+ if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
2892
+ if (parser2._def.tag === "label") {
2893
+ const id = `label:${path}`;
2894
+ labels.set(parser2, [id]);
2895
+ definitions.set(id, { id, kind: "label" });
2896
+ }
2897
+ children(parser2._def, winners).forEach((child, index) => visit(child, `${path}/${parser2._def.tag}:${index}`));
2898
+ };
2899
+ const roots = Array.isArray(entry) ? entry : [entry];
2900
+ for (const root of roots) {
2901
+ visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
2902
+ }
2903
+ return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
2904
+ }
2652
2905
 
2653
2906
  // src/compiler/scannable-run.ts
2654
2907
  var BACKSLASH = 92;
@@ -3698,7 +3951,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
3698
3951
  ` if (${m.end} > _e) {`,
3699
3952
  ` if (_cap) {`,
3700
3953
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
3701
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
3954
+ ` 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})`,
3702
3955
  ` }`,
3703
3956
  ` _e = ${m.end}`,
3704
3957
  ` continue`,
@@ -3754,7 +4007,7 @@ function analyzeTriviaFastPath(trivia2) {
3754
4007
  var CAP_RECORD = [
3755
4008
  ` if (_cap && _e > _pos) {`,
3756
4009
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
3757
- ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
4010
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
3758
4011
  ` }`
3759
4012
  ].join("\n");
3760
4013
  function composeFastLoop(shapes) {
@@ -3814,7 +4067,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
3814
4067
  ` const _ce = _e + _m${i}[0].length`,
3815
4068
  ` if (_cap) {`,
3816
4069
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
3817
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
4070
+ ` 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})`,
3818
4071
  ` }`,
3819
4072
  ` _e = _ce`,
3820
4073
  ` _matched = true`,
@@ -3852,7 +4105,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
3852
4105
  ` const _ce = _r${i}.span.end`,
3853
4106
  ` if (_cap) {`,
3854
4107
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
3855
- ` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
4108
+ ` 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})`,
3856
4109
  ` }`,
3857
4110
  ` _e = _ce`,
3858
4111
  ` _matched = true`,
@@ -4033,21 +4286,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
4033
4286
  }
4034
4287
  function failBody(ctx, expected, posExpr) {
4035
4288
  const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
4289
+ const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
4036
4290
  if (ctx.failLabel) {
4037
- if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4038
- return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
4291
+ if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4292
+ return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
4039
4293
  }
4040
- return probe + failReturn(expected, posExpr);
4294
+ return probe + trace + failReturn(expected, posExpr);
4041
4295
  }
4042
4296
  function failArrBody(ctx, expectedArr, posExpr, constant = true) {
4043
4297
  const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
4298
+ const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
4044
4299
  if (ctx.failLabel) {
4045
- if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4300
+ if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
4046
4301
  const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
4047
- return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
4302
+ return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
4048
4303
  }
4049
- if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
4050
- return probe + failReturnArr(expectedArr, posExpr);
4304
+ if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
4305
+ return probe + trace + failReturnArr(expectedArr, posExpr);
4051
4306
  }
4052
4307
  function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
4053
4308
  return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
@@ -4082,7 +4337,7 @@ var NAMED_FN_END = "_pfEnd";
4082
4337
  function namedFnPrelude() {
4083
4338
  return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
4084
4339
  }
4085
- function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
4340
+ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
4086
4341
  ctx.namedFnDecls.push([
4087
4342
  `function ${fnName}(input, _pos, _ctx) {`,
4088
4343
  ` _pfail: {`,
@@ -4090,6 +4345,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
4090
4345
  ` ${NAMED_FN_END} = ${endVar}`,
4091
4346
  ` return ${valueVar}`,
4092
4347
  ` }`,
4348
+ ...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
4093
4349
  ` return ${NAMED_FN_FAIL}`,
4094
4350
  `}`
4095
4351
  ].join("\n"));
@@ -4195,7 +4451,7 @@ function ensureTriviaFn(ctx) {
4195
4451
  ` }`,
4196
4452
  ` if (_cap && _e > _pos) {`,
4197
4453
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
4198
- ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
4454
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
4199
4455
  ` }`,
4200
4456
  ` return _e`,
4201
4457
  `}`
@@ -4251,6 +4507,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
4251
4507
  case "not":
4252
4508
  case "trivia":
4253
4509
  case "token":
4510
+ case "leaf":
4254
4511
  case "scanTo":
4255
4512
  case "unknown":
4256
4513
  return false;
@@ -4262,6 +4519,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
4262
4519
  // nothing committed remains.
4263
4520
  case "choice":
4264
4521
  return false;
4522
+ case "attempt":
4523
+ return false;
4265
4524
  // optional never fails; many/oneOrMore only "fail" with zero captured items.
4266
4525
  case "optional":
4267
4526
  case "many":
@@ -4314,6 +4573,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
4314
4573
  case "keywords":
4315
4574
  case "node":
4316
4575
  case "token":
4576
+ case "leaf":
4317
4577
  return true;
4318
4578
  case "not":
4319
4579
  case "guard":
@@ -4328,6 +4588,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
4328
4588
  case "many":
4329
4589
  case "oneOrMore":
4330
4590
  case "optional":
4591
+ case "attempt":
4331
4592
  case "transform":
4332
4593
  case "label":
4333
4594
  case "field":
@@ -4669,35 +4930,55 @@ function needsFirstSetGuard(p) {
4669
4930
  const fs = p._meta.firstSet;
4670
4931
  return fs.kind !== "any" && !canMatchEmptyAtStart(p);
4671
4932
  }
4672
- function emitDisjointArm(p, ctx, pos, valV, endV) {
4673
- if (failsAtStart(p)) {
4933
+ function coverageHit(ctx, id, offset = "_pos", end) {
4934
+ return id === void 0 ? [] : [
4935
+ `${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
4936
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
4937
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
4938
+ ];
4939
+ }
4940
+ function coverageAttempt(ctx, id, offset) {
4941
+ return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
4942
+ }
4943
+ function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
4944
+ return id === void 0 ? [] : [
4945
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
4946
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
4947
+ ];
4948
+ }
4949
+ function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
4950
+ if (failsAtStart(p) && coverageId === void 0) {
4674
4951
  const r = emit(p, ctx, pos);
4675
- return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`];
4952
+ return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
4676
4953
  }
4677
4954
  const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
4678
4955
  return [
4956
+ ...coverageAttempt(ctx, coverageId, pos),
4679
4957
  ...stmts,
4680
- ...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
4958
+ ...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
4681
4959
  `${ind(ctx)}${valV} = ${valVar}`,
4682
- `${ind(ctx)}${endV} = ${endVar}`
4960
+ `${ind(ctx)}${endV} = ${endVar}`,
4961
+ ...coverageHit(ctx, coverageId, pos, endVar)
4683
4962
  ];
4684
4963
  }
4685
- function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
4964
+ function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
4686
4965
  const p = def.parsers[i];
4687
4966
  const gate = def.gates[i];
4688
- if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
4967
+ if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
4689
4968
  const gateIdx = ctx.mapFns.length;
4690
4969
  ctx.mapFns.push(gate);
4691
4970
  ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
4692
4971
  const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
4693
4972
  const stmts = [`${ind(ctx)}if (${gateCond}) {`];
4694
4973
  ctx.indent++;
4695
- stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4974
+ stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
4696
4975
  ctx.indent--;
4697
4976
  stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
4698
4977
  return stmts;
4699
4978
  }
4700
- function emitChoice(def, ctx, pos) {
4979
+ function emitChoice(parser2, def, ctx, pos) {
4980
+ const coverageIds = ctx.coverage?.plan.choices.get(parser2);
4981
+ const coverageBase = coverageIds?.[0]?.slice(0, -1);
4701
4982
  const allExpected = deriveExpectedArr(def.parsers);
4702
4983
  if (def.disjoint) {
4703
4984
  const codeV = v(ctx, "_code");
@@ -4716,7 +4997,7 @@ function emitChoice(def, ctx, pos) {
4716
4997
  stmts.push(`${ind(ctx)}{`);
4717
4998
  ctx.indent++;
4718
4999
  stmts.push(
4719
- ...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
5000
+ ...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
4720
5001
  `${ind(ctx)}break`
4721
5002
  );
4722
5003
  ctx.indent--;
@@ -4735,16 +5016,16 @@ function emitChoice(def, ctx, pos) {
4735
5016
  first = false;
4736
5017
  stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
4737
5018
  ctx.indent++;
4738
- stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
5019
+ stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
4739
5020
  ctx.indent--;
4740
5021
  stmts.push(`${ind(ctx)}}`);
4741
5022
  }
4742
5023
  stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
4743
5024
  return { stmts, valueVar: valV, endVar: endV };
4744
5025
  }
4745
- return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
5026
+ return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
4746
5027
  }
4747
- function emitGreedyClassify(def, superIndex, ctx, pos) {
5028
+ function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
4748
5029
  const superParser = def.parsers[superIndex];
4749
5030
  const regexDef = getCoreRegexDef(superParser);
4750
5031
  const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
@@ -4760,10 +5041,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4760
5041
  const endV = v(ctx, "_ge");
4761
5042
  const valV = v(ctx, "_gcv");
4762
5043
  const regexExpected = JSON.stringify(deriveExpected(superParser));
5044
+ const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
4763
5045
  const stmts = [
5046
+ ...coverageAttempt(ctx, superCoverageId, pos),
4764
5047
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
4765
5048
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
4766
- ...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
5049
+ ...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
4767
5050
  `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
4768
5051
  `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
4769
5052
  `${ind(ctx)}let ${valV}`
@@ -4779,8 +5062,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4779
5062
  stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
4780
5063
  ctx.indent++;
4781
5064
  const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
5065
+ stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
4782
5066
  stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
4783
- stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`);
5067
+ stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
4784
5068
  ctx.indent--;
4785
5069
  stmts.push(`${ind(ctx)}}`);
4786
5070
  }
@@ -4788,12 +5072,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
4788
5072
  const regexKw = first ? "if" : "else";
4789
5073
  stmts.push(`${ind(ctx)}${regexKw} {`);
4790
5074
  ctx.indent++;
4791
- stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`);
5075
+ 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));
4792
5076
  ctx.indent--;
4793
5077
  stmts.push(`${ind(ctx)}}`);
4794
5078
  return { stmts, valueVar: valV, endVar: endV };
4795
5079
  }
4796
- function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
5080
+ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
4797
5081
  const valV = v(ctx, "_llv");
4798
5082
  const endV = v(ctx, "_lle");
4799
5083
  const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
@@ -4810,10 +5094,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
4810
5094
  ctx.indent++;
4811
5095
  const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
4812
5096
  stmts.push(
5097
+ ...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
4813
5098
  ...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
4814
5099
  ...tR.stmts,
4815
5100
  `${ind(ctx)}${valV} = ${tR.valueVar}`,
4816
- `${ind(ctx)}${endV} = ${litEnd}`
5101
+ `${ind(ctx)}${endV} = ${litEnd}`,
5102
+ ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
4817
5103
  );
4818
5104
  ctx.indent--;
4819
5105
  stmts.push(`${ind(ctx)}}`);
@@ -4821,16 +5107,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
4821
5107
  stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
4822
5108
  return { stmts, valueVar: valV, endVar: endV };
4823
5109
  }
4824
- function emitFirstMatch(def, ctx, pos) {
5110
+ function emitFirstMatch(def, ctx, pos, coverageBase) {
4825
5111
  const resValV = v(ctx, "_crv");
4826
5112
  const resEndV = v(ctx, "_cre");
4827
5113
  const resOkV = v(ctx, "_crok");
4828
5114
  const codeV = v(ctx, "_chcode");
4829
5115
  const slots = def.parsers.map(() => v(ctx, "_cfx"));
5116
+ const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
4830
5117
  const ind0 = ind(ctx);
4831
5118
  const stmts = [
4832
5119
  `${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
4833
5120
  `${ind0}let ${slots.join(", ")}`,
5121
+ ...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
4834
5122
  `${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
4835
5123
  ];
4836
5124
  for (let i = 0; i < def.parsers.length; i++) {
@@ -4866,6 +5154,7 @@ function emitFirstMatch(def, ctx, pos) {
4866
5154
  stmts.push(`${ind0}if (${skipCond}) {`);
4867
5155
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
4868
5156
  ctx.indent += fsGuard ? 2 : 1;
5157
+ if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
4869
5158
  if (markLeaves) {
4870
5159
  stmts.push(
4871
5160
  `${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
@@ -4888,13 +5177,21 @@ function emitFirstMatch(def, ctx, pos) {
4888
5177
  stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
4889
5178
  stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
4890
5179
  stmts.push(`${ind(ctx)} ${resOkV} = true`);
5180
+ if (autoRejectedV !== void 0) {
5181
+ 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} }) }`);
5182
+ }
5183
+ stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
4891
5184
  stmts.push(`${ind(ctx)} }`);
5185
+ if (autoRejectedV !== void 0) {
5186
+ stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
5187
+ }
4892
5188
  stmts.push(`${ind(ctx)}}`);
4893
- stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
5189
+ 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} });`} }`);
4894
5190
  if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
4895
5191
  } else {
4896
- stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
4897
- stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""} }`);
5192
+ 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} }) }`;
5193
+ 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} })`} }`);
5194
+ 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} })`} }`);
4898
5195
  }
4899
5196
  ctx.indent -= fsGuard ? 2 : 1;
4900
5197
  if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
@@ -4904,12 +5201,12 @@ function emitFirstMatch(def, ctx, pos) {
4904
5201
  stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
4905
5202
  return { stmts, valueVar: resValV, endVar: resEndV };
4906
5203
  }
4907
- function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
5204
+ function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
4908
5205
  if (strategy.tag === "greedyClassify")
4909
- return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
5206
+ return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
4910
5207
  if (strategy.tag === "literalsLongestFirst")
4911
- return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
4912
- return emitFirstMatch(def, ctx, pos);
5208
+ return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
5209
+ return emitFirstMatch(def, ctx, pos, coverageBase);
4913
5210
  }
4914
5211
  function pushMapFn(ctx, fn, src) {
4915
5212
  if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
@@ -5027,6 +5324,27 @@ function emitOptional(def, ctx, pos) {
5027
5324
  ];
5028
5325
  return { stmts, valueVar: valV, endVar: endV };
5029
5326
  }
5327
+ function emitAttempt(p, def, ctx, pos) {
5328
+ const inner = emitFallible(def.parser, ctx, pos);
5329
+ const leaves = v(ctx, "_atl");
5330
+ const raw = v(ctx, "_atr");
5331
+ const trivia2 = v(ctx, "_att");
5332
+ const log = v(ctx, "_atg");
5333
+ const fields = v(ctx, "_atf");
5334
+ const errors = v(ctx, "_ate");
5335
+ 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}`;
5336
+ const traceId = ctx.coverage?.plan.attempts.get(p);
5337
+ const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
5338
+ return {
5339
+ stmts: [
5340
+ `${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`,
5341
+ ...inner.stmts,
5342
+ ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
5343
+ ],
5344
+ valueVar: inner.valVar,
5345
+ endVar: inner.endVar
5346
+ };
5347
+ }
5030
5348
  function emitSepBy(_p, def, ctx, pos) {
5031
5349
  const arrV = v(ctx, "_arr");
5032
5350
  const curV = v(ctx, "_cur");
@@ -5317,6 +5635,36 @@ function emitToken(def, ctx, pos) {
5317
5635
  endVar: inner.endVar
5318
5636
  };
5319
5637
  }
5638
+ function emitLeaf(def, ctx, pos) {
5639
+ const inner = emitFallible(def.parser, ctx, pos);
5640
+ const i = ind(ctx);
5641
+ const sc = v(ctx, "_leafCh");
5642
+ const sl = v(ctx, "_leafLv");
5643
+ const sr = v(ctx, "_leafRaw");
5644
+ const stl = v(ctx, "_leafTl");
5645
+ const sol = v(ctx, "_leafLog");
5646
+ const sb = v(ctx, "_leafBuf");
5647
+ const rawV = v(ctx, "_leafRawValue");
5648
+ const valV = v(ctx, "_leaf");
5649
+ const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
5650
+ return {
5651
+ stmts: [
5652
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
5653
+ `${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
5654
+ `${i}try {`,
5655
+ ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
5656
+ `${i}} finally {`,
5657
+ `${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
5658
+ `${i}}`,
5659
+ ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
5660
+ `${i}const ${rawV} = ${inner.valVar}`,
5661
+ `${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
5662
+ ...emitLeafCapture(ctx, valV, pos, inner.endVar)
5663
+ ],
5664
+ valueVar: valV,
5665
+ endVar: inner.endVar
5666
+ };
5667
+ }
5320
5668
  function emitNode(def, ctx, pos) {
5321
5669
  if (def.type === void 0) {
5322
5670
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
@@ -5330,17 +5678,20 @@ function emitNode(def, ctx, pos) {
5330
5678
  ctx.buildSrcs.push(def.buildSrc ?? null);
5331
5679
  }
5332
5680
  const i = ind(ctx);
5333
- const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
5681
+ const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
5334
5682
  const clonesState = !structural && buildReadsState(def);
5683
+ const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
5684
+ const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
5335
5685
  const hasFields = parserHasOwnFields(def.parser);
5336
5686
  const capturesFields = hasFields && !structural && buildReadsFields(def);
5687
+ const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
5337
5688
  const chV = v(ctx, "_ch");
5338
5689
  const rawV = v(ctx, "_raw");
5339
- const capTLv = structural ? v(ctx, "_ctl") : null;
5690
+ const capTLv = structural || capturesTrivia ? v(ctx, "_ctl") : null;
5340
5691
  const capSTv = structural ? v(ctx, "_cst") : null;
5341
5692
  const capFv = structural && hasFields ? v(ctx, "_cf") : null;
5342
5693
  const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
5343
- if (!capturesTrivia) ctx.needsEmptyTl = true;
5694
+ if (!capturesTrivia || structural) ctx.needsEmptyTl = true;
5344
5695
  const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
5345
5696
  const smk = structural ? v(ctx, "_smk") : null;
5346
5697
  if (structural) ctx.needsHostReads = true;
@@ -5349,16 +5700,21 @@ function emitNode(def, ctx, pos) {
5349
5700
  const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
5350
5701
  const profileRecognizer = recV;
5351
5702
  const profileCapture = capV;
5352
- 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)))` : ""}
5353
- ${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 : []`;
5354
- const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
5703
+ const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
5704
+ const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
5705
+ const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
5706
+ 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)))` : ""}
5707
+ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
5708
+ ` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
5709
+ ` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
5710
+ const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
5355
5711
  const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
5356
5712
  const sf = hasFields ? v(ctx, "_sf") : null;
5357
5713
  const fArr = hasFields ? v(ctx, "_fa") : null;
5358
5714
  const fObj = hasFields ? v(ctx, "_fields") : "undefined";
5359
- const needsTriviaFrame = parserHasTriviaSite(def.parser);
5715
+ const needsTriviaFrame = def.trailingTrivia === true || parserHasTriviaSite(def.parser);
5360
5716
  const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
5361
- 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}` : ""}` : "";
5717
+ 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}` : ""}` : "";
5362
5718
  const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
5363
5719
  const stmts = [
5364
5720
  profHoist,
@@ -5366,8 +5722,13 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5366
5722
  `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
5367
5723
  `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
5368
5724
  ];
5369
- const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
5725
+ const { stmts: innerStmts, okVar, endVar: innerEndVar } = emitFallible(def.parser, ctx, pos);
5726
+ const endVar = def.trailingTrivia === true && ctx.activeTrivia ? v(ctx, "_trailend") : innerEndVar;
5370
5727
  stmts.push(...innerStmts);
5728
+ if (def.trailingTrivia === true && ctx.activeTrivia) {
5729
+ const triviaFn = ensureTriviaFn(ctx);
5730
+ stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
5731
+ }
5371
5732
  if (sf && fArr) {
5372
5733
  stmts.push(`${i}const ${fArr} = _ctx._fields`);
5373
5734
  }
@@ -5407,8 +5768,9 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5407
5768
  }
5408
5769
  const ndV = v(ctx, "_nd");
5409
5770
  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})`;
5410
- 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;
5411
- 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;
5771
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
5772
+ const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : `_ctx.build?._parsemanCstOutput === true ? (${hostBuildExpr}) : (${buildExpr})`;
5773
+ 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;
5412
5774
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
5413
5775
  const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
5414
5776
  const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
@@ -5416,7 +5778,7 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5416
5778
  `${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
5417
5779
  `${i}if (!(${profileRecognizer})) {`,
5418
5780
  `${i} if (${sc}) ${sc}.push(${ndV})`,
5419
- `${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} } })`,
5781
+ `${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} } })`,
5420
5782
  `${i}}`
5421
5783
  );
5422
5784
  return { stmts, valueVar: ndV, endVar };
@@ -5461,14 +5823,23 @@ function emitLazy(p, def, ctx, pos) {
5461
5823
  const savedIndent = ctx.indent;
5462
5824
  const savedFailLabel = ctx.failLabel;
5463
5825
  const savedRecord = ctx.recordFail;
5826
+ const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
5827
+ const savedActiveRule = ctx.activeCoverageRuleId;
5828
+ const savedSuppressFailure = ctx.suppressCoverageFailure;
5464
5829
  ctx.indent = 1;
5465
5830
  ctx.failLabel = "_pfail";
5466
5831
  ctx.recordFail = true;
5832
+ if (failureRuleId !== void 0) {
5833
+ ctx.activeCoverageRuleId = void 0;
5834
+ ctx.suppressCoverageFailure = true;
5835
+ }
5467
5836
  const r = emit(resolved, ctx, "_pos");
5468
5837
  ctx.indent = savedIndent;
5469
5838
  ctx.failLabel = savedFailLabel;
5470
5839
  ctx.recordFail = savedRecord;
5471
- pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar);
5840
+ ctx.activeCoverageRuleId = savedActiveRule;
5841
+ ctx.suppressCoverageFailure = savedSuppressFailure;
5842
+ pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
5472
5843
  }
5473
5844
  const fnName = ctx.namedParsers.get(p);
5474
5845
  return emitNamedFnCall(ctx, fnName, pos);
@@ -5519,6 +5890,30 @@ function emitExpect(def, ctx, pos) {
5519
5890
  return { stmts, valueVar: valVar, endVar };
5520
5891
  }
5521
5892
  function emit(p, ctx, pos) {
5893
+ const dispatch = (emissionPos = pos) => {
5894
+ const savedRule = ctx.activeCoverageRuleId;
5895
+ const rule = ctx.coverage?.plan.rules.get(p);
5896
+ if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
5897
+ const result = emitDispatch(p, ctx, emissionPos);
5898
+ ctx.activeCoverageRuleId = savedRule;
5899
+ return result;
5900
+ };
5901
+ const instrument = (r) => {
5902
+ const ruleId = ctx.coverage?.plan.rules.get(p);
5903
+ const labelIds = ctx.coverage?.plan.labels.get(p);
5904
+ if (!ruleId && !labelIds) return r;
5905
+ return {
5906
+ ...r,
5907
+ stmts: [
5908
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
5909
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
5910
+ ...r.stmts,
5911
+ ...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
5912
+ ...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
5913
+ ...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
5914
+ ]
5915
+ };
5916
+ };
5522
5917
  const usage = ctx.lazyUsage;
5523
5918
  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
5524
5919
  // overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
@@ -5535,14 +5930,14 @@ function emit(p, ctx, pos) {
5535
5930
  ctx.indent = 1;
5536
5931
  ctx.failLabel = "_pfail";
5537
5932
  ctx.recordFail = true;
5538
- const r = emitDispatch(p, ctx, "_pos");
5933
+ const r = dispatch("_pos");
5539
5934
  ctx.indent = savedIndent;
5540
5935
  ctx.failLabel = savedFailLabel;
5541
5936
  ctx.recordFail = savedRecord;
5542
5937
  pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
5543
- return emitNamedFnCall(ctx, fnName, pos);
5938
+ return instrument(emitNamedFnCall(ctx, fnName, pos));
5544
5939
  }
5545
- return emitDispatch(p, ctx, pos);
5940
+ return instrument(dispatch());
5546
5941
  }
5547
5942
  function emitDispatch(p, ctx, pos) {
5548
5943
  const def = p._def;
@@ -5556,7 +5951,9 @@ function emitDispatch(p, ctx, pos) {
5556
5951
  case "sequence":
5557
5952
  return emitSeq(def, ctx, pos);
5558
5953
  case "choice":
5559
- return emitChoice(def, ctx, pos);
5954
+ return emitChoice(p, def, ctx, pos);
5955
+ case "attempt":
5956
+ return emitAttempt(p, def, ctx, pos);
5560
5957
  case "many":
5561
5958
  case "oneOrMore":
5562
5959
  return emitMany(def, ctx, pos);
@@ -5625,6 +6022,8 @@ function emitDispatch(p, ctx, pos) {
5625
6022
  return emit(def.parser, ctx, pos);
5626
6023
  case "token":
5627
6024
  return emitToken(def, ctx, pos);
6025
+ case "leaf":
6026
+ return emitLeaf(def, ctx, pos);
5628
6027
  case "label": {
5629
6028
  const inner = emitFallible(def.parser, ctx, pos);
5630
6029
  return {
@@ -5659,10 +6058,19 @@ function emitDispatch(p, ctx, pos) {
5659
6058
  ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
5660
6059
  }
5661
6060
  }
6061
+ const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
5662
6062
  const r = emit(def.parser, ctx, pos);
5663
6063
  ctx.activeTrivia = savedTrivia;
5664
6064
  ctx.triviaKindLabels = savedKindLabels;
5665
- return r;
6065
+ if (!savedCapture) return r;
6066
+ return {
6067
+ ...r,
6068
+ stmts: [
6069
+ `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
6070
+ ...r.stmts,
6071
+ `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
6072
+ ]
6073
+ };
5666
6074
  }
5667
6075
  case "not":
5668
6076
  return emitNot(def, ctx, pos);
@@ -5747,6 +6155,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
5747
6155
  case "grammar":
5748
6156
  case "trivia":
5749
6157
  case "token":
6158
+ case "leaf":
5750
6159
  case "label":
5751
6160
  case "field":
5752
6161
  case "optional":
@@ -5774,16 +6183,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
5774
6183
  return false;
5775
6184
  }
5776
6185
  }
6186
+ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
6187
+ if (seen.has(p)) return false;
6188
+ seen.add(p);
6189
+ const d = p._def;
6190
+ if (d.tag === "node" && d.build !== void 0) return true;
6191
+ if (d.tag === "lazy") {
6192
+ try {
6193
+ return hasDirectBuildDef(d.thunk(), seen);
6194
+ } catch {
6195
+ return false;
6196
+ }
6197
+ }
6198
+ return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
6199
+ }
5777
6200
  function childrenOf(def) {
5778
6201
  switch (def.tag) {
5779
6202
  case "sequence":
5780
6203
  case "choice":
5781
6204
  return def.parsers;
5782
6205
  case "many":
6206
+ case "attempt":
5783
6207
  case "optional":
5784
6208
  case "transform":
5785
6209
  case "trivia":
5786
6210
  case "token":
6211
+ case "leaf":
5787
6212
  case "label":
5788
6213
  case "field":
5789
6214
  case "grammar":
@@ -5958,10 +6383,25 @@ function compile(combinator, mapFnSources, opts) {
5958
6383
  namedFnDecls: [],
5959
6384
  capturing: hasNodeDef(combinator),
5960
6385
  recovery: opts?.recovery ?? false,
6386
+ ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
5961
6387
  lazyUsage: analyzeLazyUsage(combinator),
5962
6388
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
5963
6389
  };
5964
6390
  const r = emit(combinator, ctx, "_pos");
6391
+ const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
6392
+ const resultBody = coverageRootRuleId === void 0 ? [
6393
+ ` let pos = _pos`,
6394
+ ...r.stmts,
6395
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6396
+ ] : [
6397
+ ` const _coverageResult = (() => {`,
6398
+ ` let pos = _pos`,
6399
+ ...r.stmts,
6400
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6401
+ ` })()`,
6402
+ ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6403
+ ` return _coverageResult`
6404
+ ];
5965
6405
  const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
5966
6406
  const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
5967
6407
  const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
@@ -5974,9 +6414,7 @@ function compile(combinator, mapFnSources, opts) {
5974
6414
  ...namedPrelude,
5975
6415
  ctx.namedFnDecls.join("\n\n"),
5976
6416
  `function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
5977
- ` let pos = _pos`,
5978
- ...r.stmts,
5979
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6417
+ ...resultBody,
5980
6418
  `}`
5981
6419
  ].join("\n");
5982
6420
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
@@ -5986,9 +6424,15 @@ function compile(combinator, mapFnSources, opts) {
5986
6424
  ...ctx.expectedDecls,
5987
6425
  ...namedPrelude,
5988
6426
  ...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
5989
- `let pos = _pos`,
5990
- ...r.stmts,
5991
- `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6427
+ ...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
6428
+ `const _coverageResult = (() => {`,
6429
+ ` let pos = _pos`,
6430
+ ...r.stmts,
6431
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6432
+ `})()`,
6433
+ `if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6434
+ `return _coverageResult`
6435
+ ]
5992
6436
  ].join("\n"));
5993
6437
  const defaultCtx = {
5994
6438
  trackLines: false,
@@ -6000,10 +6444,11 @@ function compile(combinator, mapFnSources, opts) {
6000
6444
  const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
6001
6445
  const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
6002
6446
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
6003
- const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
6447
+ const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
6004
6448
  return {
6005
6449
  source,
6006
6450
  inlineExpression,
6451
+ ...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
6007
6452
  parse(input, pos = 0) {
6008
6453
  return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
6009
6454
  },
@@ -6066,8 +6511,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
6066
6511
  triviaCaptureNames: /* @__PURE__ */ new Map(),
6067
6512
  triviaFnNames: /* @__PURE__ */ new Map(),
6068
6513
  namedFnDecls: [],
6069
- capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
6514
+ // A recognition-only fragment normally has no node collector of its own.
6515
+ // Leaf composition can re-lower it beneath a local semantic node, though;
6516
+ // in that case its terminals must feed the caller's collector rather than
6517
+ // merely returning their scalar parse values.
6518
+ capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
6070
6519
  recovery: opts?.recovery ?? false,
6520
+ ...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
6071
6521
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
6072
6522
  ns,
6073
6523
  deferFirstSetRefs: true,
@@ -6141,7 +6591,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
6141
6591
  ctx.indent = savedIndent;
6142
6592
  ctx.failLabel = savedFail;
6143
6593
  ctx.recordFail = savedRec;
6144
- pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
6594
+ const ruleId = ctx.coverage?.plan.rules.get(rule);
6595
+ const stmts = ruleId === void 0 ? body.stmts : [
6596
+ `${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
6597
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
6598
+ ...body.stmts,
6599
+ `${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
6600
+ ];
6601
+ pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
6145
6602
  }
6146
6603
  perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
6147
6604
  }
@@ -6198,15 +6655,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
6198
6655
  deps: ruleDependencies(ruleMap),
6199
6656
  needsEmptyTl: !!ctx.needsEmptyTl,
6200
6657
  needsHostReads: !!ctx.needsHostReads,
6658
+ hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
6659
+ isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
6201
6660
  mfFns: mfSrcs ? [] : ctx.mapFns,
6202
6661
  buildFns: buildSrcs ? [] : ctx.buildFns
6203
6662
  };
6204
6663
  }
6205
- function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
6206
- const bodyLines = [
6664
+ function hasSemanticReduction(roots) {
6665
+ const seen = /* @__PURE__ */ new Set();
6666
+ const visit = (parser2) => {
6667
+ if (seen.has(parser2)) return false;
6668
+ seen.add(parser2);
6669
+ const def = parser2._def;
6670
+ if (def.tag === "transform" && !def.recognitionOnly) return true;
6671
+ if (def.tag === "choice" && def.gates.some(Boolean)) return true;
6672
+ if (def.tag === "guard" || def.tag === "withCtx") return true;
6673
+ if (def.tag === "node" && def.build !== void 0) return true;
6674
+ if (def.tag === "lazy") {
6675
+ try {
6676
+ return visit(def.thunk());
6677
+ } catch {
6678
+ return true;
6679
+ }
6680
+ }
6681
+ return childrenOf(def).some(visit);
6682
+ };
6683
+ return roots.some(visit);
6684
+ }
6685
+ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
6686
+ const bodyLines = coverageRootRuleId === void 0 ? [
6207
6687
  ` let pos = _pos`,
6208
6688
  ...r.stmts,
6209
6689
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
6690
+ ] : [
6691
+ ` const _coverageResult = (() => {`,
6692
+ ` let pos = _pos`,
6693
+ ...r.stmts,
6694
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
6695
+ ` })()`,
6696
+ ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
6697
+ ` return _coverageResult`
6210
6698
  ];
6211
6699
  const innerFn = [
6212
6700
  `function(input, _pos, _ctx) {`,
@@ -6261,8 +6749,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
6261
6749
  };
6262
6750
  const emit2 = (end) => {
6263
6751
  if (end > pos && cstCaptureActive(ctx)) {
6264
- const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
6265
- pushCstLeaf(ctx, leaf);
6752
+ const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
6753
+ pushCstLeaf(ctx, leaf2);
6266
6754
  }
6267
6755
  };
6268
6756
  while (cur < input.length) {
@@ -6316,6 +6804,7 @@ function balanced(open, close, options = {}) {
6316
6804
  );
6317
6805
  if (combi._def.tag === "transform") {
6318
6806
  combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
6807
+ combi._def.recognitionOnly = true;
6319
6808
  }
6320
6809
  self.define(combi);
6321
6810
  return combi;
@@ -6361,9 +6850,11 @@ function childrenOf2(def) {
6361
6850
  case "many":
6362
6851
  case "oneOrMore":
6363
6852
  case "optional":
6853
+ case "attempt":
6364
6854
  case "transform":
6365
6855
  case "trivia":
6366
6856
  case "token":
6857
+ case "leaf":
6367
6858
  case "label":
6368
6859
  case "field":
6369
6860
  case "not":
@@ -6412,7 +6903,7 @@ function serializeRuleMap(ruleMap) {
6412
6903
  }
6413
6904
  }
6414
6905
  function evalRuleMapIR(ir) {
6415
- const _tf = (child, src) => {
6906
+ const _tf = (child, src, recognitionOnly = false) => {
6416
6907
  let fn2;
6417
6908
  try {
6418
6909
  fn2 = (0, eval)(`(${src})`);
@@ -6423,11 +6914,31 @@ function evalRuleMapIR(ir) {
6423
6914
  }
6424
6915
  const t = transform(child, fn2);
6425
6916
  t._def.fnSrc = src;
6917
+ if (recognitionOnly) t._def.recognitionOnly = true;
6426
6918
  return t;
6427
6919
  };
6428
- const _nd = (type, child, src, opts) => {
6429
- const n = node(type, child, void 0, opts);
6920
+ const _lf = (child, src) => {
6921
+ let fn2;
6922
+ try {
6923
+ fn2 = (0, eval)(`(${src})`);
6924
+ } catch {
6925
+ fn2 = () => {
6926
+ throw new Error("IR leaf fn not materialized");
6927
+ };
6928
+ }
6929
+ const l = leaf(child, fn2);
6930
+ l._def.fnSrc = src;
6931
+ return l;
6932
+ };
6933
+ const _nd = (type, child, src, opts, staticError) => {
6934
+ if (staticError !== void 0 && staticError.length > 0) {
6935
+ throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
6936
+ }
6937
+ const n = node(type, child, (() => {
6938
+ throw new Error("IR node build requires static re-lowering");
6939
+ }), opts);
6430
6940
  n._def.buildSrc = src;
6941
+ if (staticError !== void 0) n._def.buildStaticError = staticError;
6431
6942
  return n;
6432
6943
  };
6433
6944
  const _gch = (items) => {
@@ -6477,6 +6988,7 @@ function evalRuleMapIR(ir) {
6477
6988
  "keywords",
6478
6989
  "sequence",
6479
6990
  "choice",
6991
+ "attempt",
6480
6992
  "many",
6481
6993
  "oneOrMore",
6482
6994
  "optional",
@@ -6486,6 +6998,7 @@ function evalRuleMapIR(ir) {
6486
6998
  "parser",
6487
6999
  "scanTo",
6488
7000
  "token",
7001
+ "leaf",
6489
7002
  "transform",
6490
7003
  "skip",
6491
7004
  "trivia",
@@ -6493,6 +7006,7 @@ function evalRuleMapIR(ir) {
6493
7006
  "field",
6494
7007
  "expect",
6495
7008
  "_tf",
7009
+ "_lf",
6496
7010
  "_nd",
6497
7011
  "_gch",
6498
7012
  "_wc",
@@ -6506,6 +7020,7 @@ function evalRuleMapIR(ir) {
6506
7020
  keywords,
6507
7021
  sequence,
6508
7022
  choice,
7023
+ attempt,
6509
7024
  many,
6510
7025
  oneOrMore,
6511
7026
  optional,
@@ -6515,6 +7030,7 @@ function evalRuleMapIR(ir) {
6515
7030
  parser,
6516
7031
  scanTo,
6517
7032
  token,
7033
+ leaf,
6518
7034
  transform,
6519
7035
  skip,
6520
7036
  trivia,
@@ -6522,6 +7038,7 @@ function evalRuleMapIR(ir) {
6522
7038
  field,
6523
7039
  expect,
6524
7040
  _tf,
7041
+ _lf,
6525
7042
  _nd,
6526
7043
  _gch,
6527
7044
  _wc
@@ -6653,6 +7170,8 @@ ${body}
6653
7170
  return `oneOrMore(${kid(def.parser)})`;
6654
7171
  case "optional":
6655
7172
  return `optional(${kid(def.parser)})`;
7173
+ case "attempt":
7174
+ return `attempt(${kid(def.parser)})`;
6656
7175
  case "sepBy":
6657
7176
  return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
6658
7177
  case "not":
@@ -6661,6 +7180,10 @@ ${body}
6661
7180
  return `trivia(${kid(def.parser)})`;
6662
7181
  case "token":
6663
7182
  return `token(${kid(def.parser)})`;
7183
+ case "leaf": {
7184
+ if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
7185
+ return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
7186
+ }
6664
7187
  case "label":
6665
7188
  return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
6666
7189
  case "field":
@@ -6673,21 +7196,30 @@ ${body}
6673
7196
  return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
6674
7197
  case "transform": {
6675
7198
  if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
6676
- return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
7199
+ return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
6677
7200
  }
6678
7201
  case "node": {
6679
7202
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
6680
- const opts = def.unwrap || def.collapse ? `, { ${def.unwrap ? "unwrap: true" : "collapse: true"} }` : "";
7203
+ const optEntries = [
7204
+ ...def.unwrap ? ["unwrap: true"] : [],
7205
+ ...def.collapse ? ["collapse: true"] : [],
7206
+ ...def.captureTrivia ? ["captureTrivia: true"] : [],
7207
+ ...def.trailingTrivia ? ["trailingTrivia: true"] : []
7208
+ ];
7209
+ const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
6681
7210
  if (def.type === void 0) {
6682
7211
  if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
6683
7212
  return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
6684
7213
  }
6685
- if (def.buildSrc !== void 0) return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts})`;
7214
+ if (def.buildSrc !== void 0) {
7215
+ const staticError = def.buildStaticError === void 0 ? "" : `${opts ? "" : ", undefined"}, ${JSON.stringify(def.buildStaticError)}`;
7216
+ return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${staticError})`;
7217
+ }
6686
7218
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
6687
7219
  }
6688
7220
  case "grammar": {
6689
7221
  const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
6690
- return `parser({ trivia: ${trivia2}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
7222
+ return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
6691
7223
  }
6692
7224
  case "withCtx": {
6693
7225
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -6716,18 +7248,20 @@ function normalizeCstCollapse(collapse) {
6716
7248
  }
6717
7249
  return typeof collapse === "function" ? collapse : void 0;
6718
7250
  }
6719
- function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
6720
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
7251
+ function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
7252
+ return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
6721
7253
  }
6722
- function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
7254
+ function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
6723
7255
  if (typeof typeOrOptions === "string") {
6724
- return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
7256
+ return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
6725
7257
  }
6726
7258
  const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
6727
- const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children2, fields, span2, rawChildren2, triviaLog2, state2);
7259
+ const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
7260
+ host._parsemanCstOutput = true;
6728
7261
  if (collapse) host._parsemanCstCollapse = collapse;
6729
7262
  return host;
6730
7263
  }
7264
+ cstBuildHost._parsemanCstOutput = true;
6731
7265
  function fusedBody(pieces) {
6732
7266
  const winner = /* @__PURE__ */ new Map();
6733
7267
  for (const p of pieces) for (const k of p.keys) winner.set(k, p);
@@ -6781,13 +7315,39 @@ function fuseRules(pieces) {
6781
7315
  return new Function("_env", body)(env);
6782
7316
  }
6783
7317
  var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
7318
+ var LEAF_COMPOSED = /* @__PURE__ */ Symbol.for("parseman.leafComposed");
6784
7319
  var COMPOSED_TRIVIA = /* @__PURE__ */ Symbol.for("parseman.composedTrivia");
7320
+ var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCoverageRules");
6785
7321
  function isIRPiece(p) {
6786
7322
  return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
6787
7323
  }
6788
- function materializePiece(p, trivia2) {
7324
+ function coverageRulesOf(carried) {
7325
+ const winners = {};
7326
+ for (const piece of carried) {
7327
+ if (!isIRPiece(piece)) return void 0;
7328
+ const map = evalRuleMapIR(piece.ir);
7329
+ for (const [name, rule] of map) {
7330
+ if (rule._def.tag === "lazy") {
7331
+ try {
7332
+ rule._def.thunk();
7333
+ } catch {
7334
+ continue;
7335
+ }
7336
+ }
7337
+ winners[name] = rule;
7338
+ }
7339
+ }
7340
+ return winners;
7341
+ }
7342
+ function composedCoverageRules(grammar) {
7343
+ return grammar[COMPOSED_COVERAGE_RULES];
7344
+ }
7345
+ function materializePiece(p, trivia2, captureTerminals = false) {
6789
7346
  if (!isIRPiece(p)) return p;
6790
- const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, trivia2 ? { trivia: trivia2 } : void 0);
7347
+ const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
7348
+ ...trivia2 ? { trivia: trivia2 } : {},
7349
+ ...captureTerminals ? { captureTerminals: true } : {}
7350
+ });
6791
7351
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
6792
7352
  return pieces;
6793
7353
  }
@@ -6838,6 +7398,9 @@ function composingTriviaOf(items) {
6838
7398
  return void 0;
6839
7399
  }
6840
7400
  function compose(items) {
7401
+ if (items.some((item) => item[LEAF_COMPOSED] === true)) {
7402
+ throw new Error("compose: a composeLeaf() result is terminal and cannot be composed again");
7403
+ }
6841
7404
  const used = /* @__PURE__ */ new Set();
6842
7405
  const trivia2 = composingTriviaOf(items);
6843
7406
  const carried = items.flatMap((item) => itemCarried(item, used, trivia2));
@@ -6845,8 +7408,13 @@ function compose(items) {
6845
7408
  const map = fuseRules(pieces);
6846
7409
  Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
6847
7410
  if (trivia2) Object.defineProperty(map, COMPOSED_TRIVIA, { value: trivia2, enumerable: false });
7411
+ const coverageRules = coverageRulesOf(carried);
7412
+ if (coverageRules) Object.defineProperty(map, COMPOSED_COVERAGE_RULES, { value: coverageRules, enumerable: false });
6848
7413
  return map;
6849
7414
  }
7415
+ function composeLeaf(_items) {
7416
+ throw new Error("composeLeaf(): requires Parseman macro lowering; runtime composition is forbidden");
7417
+ }
6850
7418
 
6851
7419
  // src/combinators/guard.ts
6852
7420
  function guard(predicate) {
@@ -7010,7 +7578,9 @@ function producesRepetition(def, depth = 0) {
7010
7578
  // Transparent wrappers — look through to the inner parser.
7011
7579
  case "node":
7012
7580
  case "transform":
7581
+ case "attempt":
7013
7582
  case "token":
7583
+ case "leaf":
7014
7584
  case "label":
7015
7585
  case "field":
7016
7586
  case "expect":
@@ -7062,8 +7632,8 @@ function replaceAtPath(rebuild, root, path, newNode) {
7062
7632
  newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
7063
7633
  return rebuild(root, newChildren);
7064
7634
  }
7065
- function defaultRebuild(node2, children) {
7066
- return { ...node2, children };
7635
+ function defaultRebuild(node2, children2) {
7636
+ return { ...node2, children: children2 };
7067
7637
  }
7068
7638
  function shiftRelStart(child, delta) {
7069
7639
  const c = child;
@@ -7403,7 +7973,8 @@ function runOnce(entry, input, options, phase, profileState) {
7403
7973
  state: options.state,
7404
7974
  ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
7405
7975
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
7406
- ...options.tolerant ? { _tolerant: true, _rec: REC } : {}
7976
+ ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
7977
+ ...options.instrumentation === void 0 ? {} : options.instrumentation
7407
7978
  };
7408
7979
  const r = invoke(entry, input, 0, ctx);
7409
7980
  let unconsumedFrom = null;
@@ -7458,6 +8029,265 @@ function run(entry, input, options = {}) {
7458
8029
  };
7459
8030
  }
7460
8031
 
8032
+ // src/coverage.ts
8033
+ var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
8034
+ function compiledGrammarCoverageDefinitions(grammar) {
8035
+ const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
8036
+ 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"))) {
8037
+ throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
8038
+ }
8039
+ return definitions;
8040
+ }
8041
+ function createGrammarInstrumentationContext(options = {}) {
8042
+ return {
8043
+ trackLines: options.trackLines ?? false,
8044
+ ...options.state === void 0 ? {} : { state: options.state },
8045
+ ...options.collector === void 0 ? {} : { _grammarCoverage: (id) => options.collector.hit(id) },
8046
+ ...options.trace === void 0 ? {} : { _grammarTrace: options.trace }
8047
+ };
8048
+ }
8049
+ function createGrammarTraceSink(options) {
8050
+ if (!Number.isInteger(options.capacity) || options.capacity < 0) throw new TypeError("trace capacity must be a finite non-negative integer");
8051
+ const events = [];
8052
+ let detached = false;
8053
+ let truncated = false;
8054
+ let dropped = 0;
8055
+ return {
8056
+ write(event) {
8057
+ if (detached || events.length >= options.capacity) {
8058
+ detached = true;
8059
+ truncated = true;
8060
+ dropped++;
8061
+ return;
8062
+ }
8063
+ events.push(Object.freeze({ ...event }));
8064
+ try {
8065
+ if (options.write?.(event) === false) {
8066
+ detached = true;
8067
+ truncated = true;
8068
+ }
8069
+ } catch {
8070
+ detached = true;
8071
+ truncated = true;
8072
+ }
8073
+ },
8074
+ snapshot() {
8075
+ return Object.freeze({ events: Object.freeze([...events]), truncated, dropped });
8076
+ }
8077
+ };
8078
+ }
8079
+ function createGrammarCoverageCollector(definitions) {
8080
+ const ordered = [...definitions].sort((a, b) => a.id.localeCompare(b.id));
8081
+ const known = new Set(ordered.map((definition) => definition.id));
8082
+ const hits = /* @__PURE__ */ new Set();
8083
+ return {
8084
+ hit(id) {
8085
+ if (known.has(id)) hits.add(id);
8086
+ },
8087
+ snapshot() {
8088
+ const hitList = [...hits].sort();
8089
+ const unhit = ordered.map((definition) => definition.id).filter((id) => !hits.has(id));
8090
+ return { definitions: ordered, hits: hitList, unhit, ratio: ordered.length === 0 ? 1 : hitList.length / ordered.length };
8091
+ },
8092
+ reset() {
8093
+ hits.clear();
8094
+ }
8095
+ };
8096
+ }
8097
+ function grammarCoverageDefinitions(entry, winners) {
8098
+ return buildGrammarPlan(entry, winners).definitions;
8099
+ }
8100
+ function composedGrammarCoverageDefinitions(grammar, startRule) {
8101
+ const winners = composedCoverageRules(grammar);
8102
+ if (!winners) throw new TypeError("semantic coverage needs re-lowerable composed IR; this composition contains an opaque artifact");
8103
+ const entry = winners[startRule];
8104
+ if (!entry) throw new TypeError(`semantic coverage start rule ${JSON.stringify(startRule)} is not a final winner`);
8105
+ return grammarCoverageDefinitions(entry, winners);
8106
+ }
8107
+ function coverageEntry(entry, collector, maps, trace) {
8108
+ const cache = /* @__PURE__ */ new WeakMap();
8109
+ const build = (parser2) => {
8110
+ const existing = cache.get(parser2);
8111
+ if (existing) return existing;
8112
+ const rule = maps.rules.get(parser2);
8113
+ const wrap = (parse2) => {
8114
+ const wrapped = {
8115
+ _tag: parser2._tag,
8116
+ _meta: parser2._meta,
8117
+ _def: parser2._def,
8118
+ parse(input, pos, ctx) {
8119
+ if (rule) {
8120
+ collector.hit(rule);
8121
+ trace?.write({ id: rule, phase: "enter", offset: pos });
8122
+ }
8123
+ const result = parse2(input, pos, ctx);
8124
+ if (rule) trace?.write(result.ok ? { id: rule, phase: "success", offset: pos, end: result.span.end } : { id: rule, phase: "failure", offset: result.span.end });
8125
+ return result;
8126
+ }
8127
+ };
8128
+ cache.set(parser2, wrapped);
8129
+ return wrapped;
8130
+ };
8131
+ const def = parser2._def;
8132
+ if (def.tag === "lazy") {
8133
+ return wrap((input, pos, ctx) => build(def.thunk()).parse(input, pos, ctx));
8134
+ }
8135
+ if (def.tag === "label") {
8136
+ const base2 = label(def.label, build(def.parser));
8137
+ return wrap((input, pos, ctx) => {
8138
+ const result = base2.parse(input, pos, ctx);
8139
+ if (result.ok) for (const id of maps.labels.get(parser2) ?? []) {
8140
+ collector.hit(id);
8141
+ trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
8142
+ }
8143
+ return result;
8144
+ });
8145
+ }
8146
+ if (def.tag === "choice") {
8147
+ const ids = maps.choices.get(parser2) ?? [];
8148
+ const invocations = [];
8149
+ const arms = def.parsers.map((arm, index) => {
8150
+ const child = build(arm);
8151
+ return {
8152
+ _tag: child._tag,
8153
+ _meta: child._meta,
8154
+ _def: child._def,
8155
+ parse(input, pos, ctx) {
8156
+ const id = ids[index];
8157
+ if (id) trace?.write({ id, phase: "attempt", offset: pos });
8158
+ const result = child.parse(input, pos, ctx);
8159
+ if (result.ok) {
8160
+ if (def.strategy.tag !== "greedyClassify") collector.hit(ids[index]);
8161
+ const invocation = invocations[invocations.length - 1];
8162
+ if (invocation) {
8163
+ invocation.lastSuccessfulArm = index;
8164
+ invocation.successfulArms.push(index);
8165
+ }
8166
+ } else if (id) {
8167
+ trace?.write({ id, phase: "failure", offset: result.span.end });
8168
+ trace?.write({ id, phase: "backtrack", offset: pos });
8169
+ }
8170
+ return result;
8171
+ }
8172
+ };
8173
+ });
8174
+ const args = arms.map((arm, index) => def.gates[index] ? { combinator: arm, gate: def.gates[index] } : arm);
8175
+ const unsafeChoice = choice;
8176
+ const baseChoice = unsafeChoice(...args);
8177
+ return wrap((input, pos, ctx) => {
8178
+ const invocation = { lastSuccessfulArm: void 0, successfulArms: [] };
8179
+ invocations.push(invocation);
8180
+ const result = baseChoice.parse(input, pos, ctx);
8181
+ const strategy = def.strategy;
8182
+ if (result.ok && strategy.tag === "greedyClassify") {
8183
+ const text = input.slice(pos, result.span.end);
8184
+ const classified = def.parsers.findIndex((arm, index) => index !== strategy.superIndex && getCoreLiteralValue(arm) === text);
8185
+ if (classified !== -1) invocation.lastSuccessfulArm = classified;
8186
+ else invocation.lastSuccessfulArm = strategy.superIndex;
8187
+ }
8188
+ if (result.ok && invocation.lastSuccessfulArm !== void 0) {
8189
+ const id = ids[invocation.lastSuccessfulArm];
8190
+ for (const rejected of invocation.successfulArms) {
8191
+ if (rejected !== invocation.lastSuccessfulArm) {
8192
+ const rejectedId = ids[rejected];
8193
+ if (rejectedId) {
8194
+ trace?.write({ id: rejectedId, phase: "failure", offset: pos });
8195
+ trace?.write({ id: rejectedId, phase: "backtrack", offset: pos });
8196
+ }
8197
+ }
8198
+ }
8199
+ if (id) {
8200
+ collector.hit(id);
8201
+ trace?.write({ id, phase: "selected", offset: pos, end: result.span.end });
8202
+ trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
8203
+ }
8204
+ }
8205
+ invocations.pop();
8206
+ return result;
8207
+ });
8208
+ }
8209
+ const base = (() => {
8210
+ switch (def.tag) {
8211
+ case "sequence": {
8212
+ const unsafeSequence = sequence;
8213
+ return unsafeSequence(...def.parsers.map(build));
8214
+ }
8215
+ case "many":
8216
+ return many(build(def.parser));
8217
+ case "oneOrMore":
8218
+ return oneOrMore(build(def.parser));
8219
+ case "optional":
8220
+ return optional(build(def.parser));
8221
+ case "attempt": {
8222
+ const base2 = attempt(build(def.parser));
8223
+ const id = maps.attempts.get(parser2);
8224
+ return id === void 0 ? base2 : {
8225
+ ...base2,
8226
+ parse(input, pos, ctx) {
8227
+ const result = base2.parse(input, pos, ctx);
8228
+ if (!result.ok) trace?.write({ id, phase: "rollback", offset: pos });
8229
+ return result;
8230
+ }
8231
+ };
8232
+ }
8233
+ case "sepBy":
8234
+ return sepBy(build(def.parser), build(def.separator));
8235
+ case "transform":
8236
+ return transform(build(def.parser), def.fn);
8237
+ case "skip":
8238
+ return skip(build(def.main), build(def.skipped));
8239
+ case "trivia":
8240
+ return trivia(build(def.parser));
8241
+ case "token":
8242
+ return token(build(def.parser));
8243
+ case "leaf":
8244
+ return leaf(build(def.parser), def.fn);
8245
+ case "field":
8246
+ return field(def.name, build(def.parser));
8247
+ case "grammar":
8248
+ return parser({
8249
+ ...def.triviaParser === void 0 ? def.clearTrivia ? { trivia: null } : {} : { trivia: build(def.triviaParser) },
8250
+ ...def.captureTrivia ? { captureTrivia: true } : {},
8251
+ ...def.trackLines ? { trackLines: true } : {}
8252
+ }, build(def.parser));
8253
+ case "not":
8254
+ return not(build(def.parser));
8255
+ case "node": {
8256
+ const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
8257
+ return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
8258
+ }
8259
+ case "guard":
8260
+ return guard(def.predicate);
8261
+ case "withCtx":
8262
+ return withCtx(def.extra, build(def.parser));
8263
+ case "expect":
8264
+ return expect(build(def.parser), def.label);
8265
+ case "scanTo":
8266
+ return scanTo(build(def.sentinel), { skip: def.skip.map(build), orEOF: def.orEOF });
8267
+ case "literal":
8268
+ case "regex":
8269
+ case "keywords":
8270
+ return parser2;
8271
+ case "recover":
8272
+ case "unknown":
8273
+ throw new TypeError(`runWithGrammarCoverage does not yet support ${def.tag}`);
8274
+ default:
8275
+ return parser2;
8276
+ }
8277
+ })();
8278
+ return wrap((input, pos, ctx) => base.parse(input, pos, ctx));
8279
+ };
8280
+ return build(entry);
8281
+ }
8282
+ function runWithGrammarCoverage(entry, input, options = {}) {
8283
+ if (typeof entry === "function") throw new TypeError("runWithGrammarCoverage currently requires an interpreter combinator entry");
8284
+ const plan = buildGrammarPlan(entry);
8285
+ const definitions = plan.definitions;
8286
+ const collector = options.collector ?? createGrammarCoverageCollector(definitions);
8287
+ const { collector: _collector, trace, ...runOptions } = options;
8288
+ return { result: run(coverageEntry(entry, collector, plan, trace), input, runOptions), coverage: collector.snapshot() };
8289
+ }
8290
+
7461
8291
  // src/cst/trivia-index.ts
7462
8292
  function merge(map, key, run2) {
7463
8293
  if (run2.length === 0) return;
@@ -7528,9 +8358,9 @@ function buildTriviaIndex(root, input = "", opts) {
7528
8358
  function walk(root, visitor, ctx = void 0) {
7529
8359
  const go = (node2, parent) => {
7530
8360
  const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
7531
- const children = node2.children;
7532
- if (descend !== false && Array.isArray(children)) {
7533
- for (const child of children) go(child, node2);
8361
+ const children2 = node2.children;
8362
+ if (descend !== false && Array.isArray(children2)) {
8363
+ for (const child of children2) go(child, node2);
7534
8364
  }
7535
8365
  visitor.leave?.(node2, parent, ctx);
7536
8366
  };
@@ -7546,9 +8376,9 @@ function createVisitor(handlers) {
7546
8376
  },
7547
8377
  visitChildren(node2) {
7548
8378
  const out = [];
7549
- const children = node2.children;
7550
- if (Array.isArray(children)) {
7551
- for (const child of children) {
8379
+ const children2 = node2.children;
8380
+ if (Array.isArray(children2)) {
8381
+ for (const child of children2) {
7552
8382
  const r = api.visit(child);
7553
8383
  if (r !== void 0) out.push(r);
7554
8384
  }
@@ -7577,6 +8407,9 @@ function triviaEntries(log, labels, opts) {
7577
8407
  end(i) {
7578
8408
  return log[entryOffset(i, stride) + 1];
7579
8409
  },
8410
+ insertIndex(i) {
8411
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
8412
+ },
7580
8413
  kindIndex(i) {
7581
8414
  if (!labels) return void 0;
7582
8415
  return log[entryOffset(i, stride) + baseStride];