parseman 0.40.0 → 0.42.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 (54) hide show
  1. package/README.md +7 -6
  2. package/dist/combinators/expect.d.ts.map +1 -1
  3. package/dist/combinators/grammar.d.ts.map +1 -1
  4. package/dist/combinators/literal.d.ts.map +1 -1
  5. package/dist/combinators/node.d.ts.map +1 -1
  6. package/dist/combinators/regex.d.ts.map +1 -1
  7. package/dist/combinators/scanTo.d.ts.map +1 -1
  8. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  9. package/dist/compiler/codegen.d.ts +3 -0
  10. package/dist/compiler/codegen.d.ts.map +1 -1
  11. package/dist/compiler/inline-build.d.ts +1 -1
  12. package/dist/compiler/inline-build.d.ts.map +1 -1
  13. package/dist/compiler/inline-callback.d.ts +9 -0
  14. package/dist/compiler/inline-callback.d.ts.map +1 -1
  15. package/dist/compiler/line-index.d.ts +1 -15
  16. package/dist/compiler/line-index.d.ts.map +1 -1
  17. package/dist/compiler/value-usage.d.ts.map +1 -1
  18. package/dist/cst/capture-buffer.d.ts.map +1 -1
  19. package/dist/cst/trivia-entries.d.ts +52 -0
  20. package/dist/cst/trivia-entries.d.ts.map +1 -1
  21. package/dist/functional/run.d.ts +11 -2
  22. package/dist/functional/run.d.ts.map +1 -1
  23. package/dist/index.cjs +634 -169
  24. package/dist/index.cjs.map +4 -4
  25. package/dist/index.d.ts +4 -4
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +634 -169
  28. package/dist/index.js.map +4 -4
  29. package/dist/language-service/index.cjs +203 -4
  30. package/dist/language-service/index.cjs.map +4 -4
  31. package/dist/language-service/index.js +203 -4
  32. package/dist/language-service/index.js.map +4 -4
  33. package/dist/line-index.d.ts +41 -0
  34. package/dist/line-index.d.ts.map +1 -0
  35. package/dist/plugin/index.cjs +454 -126
  36. package/dist/plugin/index.cjs.map +4 -4
  37. package/dist/plugin/index.js +454 -126
  38. package/dist/plugin/index.js.map +4 -4
  39. package/dist/recovery/scan.d.ts.map +1 -1
  40. package/dist/regex/first-set.d.ts.map +1 -1
  41. package/dist/run/index.cjs +202 -2
  42. package/dist/run/index.cjs.map +4 -4
  43. package/dist/run/index.d.ts +8 -4
  44. package/dist/run/index.d.ts.map +1 -1
  45. package/dist/run/index.js +202 -2
  46. package/dist/run/index.js.map +4 -4
  47. package/dist/spec/index.cjs +174 -52
  48. package/dist/spec/index.cjs.map +4 -4
  49. package/dist/spec/index.js +174 -52
  50. package/dist/spec/index.js.map +4 -4
  51. package/dist/types.d.ts +12 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/version.d.ts +1 -1
  54. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -33,12 +33,14 @@ __export(index_exports, {
33
33
  analyzeGatingRules: () => analyzeGatingRules,
34
34
  analyzeGrammarGating: () => analyzeGrammarGating,
35
35
  annotateSpan: () => annotateSpan,
36
+ annotateTreeSpans: () => annotateTreeSpans,
36
37
  applyEdit: () => applyEdit,
37
38
  attempt: () => attempt,
38
39
  balanced: () => balanced,
39
40
  blankLinesIn: () => blankLinesIn,
40
41
  buildLineIndex: () => buildLineIndex,
41
42
  buildOffsetIndex: () => buildOffsetIndex,
43
+ buildRootTriviaIndex: () => buildRootTriviaIndex,
42
44
  buildTriviaIndex: () => buildTriviaIndex,
43
45
  charClassMembers: () => charClassMembers,
44
46
  choice: () => choice,
@@ -53,6 +55,7 @@ __export(index_exports, {
53
55
  createGrammarCoverageCollector: () => createGrammarCoverageCollector,
54
56
  createGrammarInstrumentationContext: () => createGrammarInstrumentationContext,
55
57
  createGrammarTraceSink: () => createGrammarTraceSink,
58
+ createLineIndex: () => createLineIndex,
56
59
  createVisitor: () => createVisitor,
57
60
  cstBuildHost: () => cstBuildHost,
58
61
  dispatch: () => dispatch,
@@ -86,6 +89,7 @@ __export(index_exports, {
86
89
  matches: () => matches,
87
90
  noTrivia: () => noTrivia,
88
91
  node: () => node,
92
+ normalizeLineIndex: () => normalizeLineIndex,
89
93
  not: () => not,
90
94
  offsetToLineCol: () => offsetToLineCol,
91
95
  oneOrMore: () => oneOrMore,
@@ -96,6 +100,7 @@ __export(index_exports, {
96
100
  parseDoc: () => parseDoc,
97
101
  parser: () => parser,
98
102
  peek: () => peek,
103
+ recordLineRange: () => recordLineRange,
99
104
  ref: () => ref,
100
105
  regex: () => regex,
101
106
  relativize: () => relativize,
@@ -362,6 +367,87 @@ function failAt(ctx, expected, pos) {
362
367
  return r;
363
368
  }
364
369
 
370
+ // src/line-index.ts
371
+ function createLineIndex() {
372
+ return { lineStarts: [0] };
373
+ }
374
+ function buildLineIndex(input) {
375
+ const lineStarts = [0];
376
+ for (let i = 0; i < input.length; i++) {
377
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
378
+ }
379
+ return { lineStarts };
380
+ }
381
+ function recordLineRange(index, input, start, end) {
382
+ const lineStarts = index.lineStarts;
383
+ for (let i = start; i < end; i++) {
384
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
385
+ }
386
+ }
387
+ function recordLineRangeFromContext(ctx, input, _startHint, end) {
388
+ if (!ctx.trackLines) return;
389
+ const from = ctx._lineScannedTo ?? 0;
390
+ if (end <= from) return;
391
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
392
+ if (!index) return;
393
+ recordLineRange(index, input, from, end);
394
+ ctx._lineScannedTo = end;
395
+ }
396
+ function normalizeLineIndex(index) {
397
+ const starts = index.lineStarts;
398
+ starts.sort((a, b) => a - b);
399
+ let write = 0;
400
+ for (let read = 0; read < starts.length; read++) {
401
+ const value = starts[read];
402
+ if (write === 0 || starts[write - 1] !== value) starts[write++] = value;
403
+ }
404
+ starts.length = write;
405
+ if (starts.length === 0 || starts[0] !== 0) starts.unshift(0);
406
+ return index;
407
+ }
408
+ function offsetToLineCol(index, offset) {
409
+ const { lineStarts } = index;
410
+ let lo = 0;
411
+ let hi = lineStarts.length - 1;
412
+ while (lo < hi) {
413
+ const mid = lo + hi + 1 >> 1;
414
+ if (lineStarts[mid] <= offset) lo = mid;
415
+ else hi = mid - 1;
416
+ }
417
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
418
+ }
419
+ function annotateSpan(span, index) {
420
+ const s = offsetToLineCol(index, span.start);
421
+ const e = offsetToLineCol(index, span.end);
422
+ return {
423
+ ...span,
424
+ startLine: s.line,
425
+ startColumn: s.col,
426
+ endLine: e.line,
427
+ endColumn: e.col
428
+ };
429
+ }
430
+ function annotateSpanFromLineContext(span, ctx) {
431
+ if (!ctx.trackLines) return span;
432
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
433
+ return index ? annotateSpan(span, index) : span;
434
+ }
435
+ function isSpan(value) {
436
+ return !!value && typeof value === "object" && typeof value.start === "number" && typeof value.end === "number";
437
+ }
438
+ function annotateTreeSpans(value, index, seen = /* @__PURE__ */ new WeakSet()) {
439
+ if (!value || typeof value !== "object") return value;
440
+ if (seen.has(value)) return value;
441
+ seen.add(value);
442
+ const obj = value;
443
+ if (isSpan(obj.span)) obj.span = annotateSpan(obj.span, index);
444
+ for (const key of Object.keys(obj)) {
445
+ const child = obj[key];
446
+ if (child && typeof child === "object") annotateTreeSpans(child, index, seen);
447
+ }
448
+ return value;
449
+ }
450
+
365
451
  // src/cst/capture-buffer.ts
366
452
  var EMPTY = [];
367
453
  var EMPTY_TL = [];
@@ -403,7 +489,12 @@ function endCstNodeCapture(ctx, saved) {
403
489
  return materialized;
404
490
  }
405
491
  function pushCstLeaf(ctx, leaf2) {
406
- pushCstChild(ctx, leaf2, leaf2);
492
+ if (!ctx.trackLines) {
493
+ pushCstChild(ctx, leaf2, leaf2);
494
+ return;
495
+ }
496
+ const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
497
+ pushCstChild(ctx, annotated, annotated);
407
498
  }
408
499
  function pushCstChild(ctx, built, rawEntry) {
409
500
  const b = ctx._cstBuf;
@@ -537,6 +628,7 @@ function literal(value, opts = {}) {
537
628
  canMatchNewline: value.includes("\n"),
538
629
  isTrivia: false
539
630
  };
631
+ const canMatchNewline = meta.canMatchNewline;
540
632
  if (caseInsensitive) {
541
633
  const upper = value.toUpperCase();
542
634
  const lower = value.toLowerCase();
@@ -553,6 +645,7 @@ function literal(value, opts = {}) {
553
645
  return function parse3(input, pos, ctx) {
554
646
  if (input.charCodeAt(pos) === code) {
555
647
  const span = { start: pos, end: pos + 1 };
648
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
556
649
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
557
650
  return { ok: true, value, span };
558
651
  }
@@ -566,6 +659,7 @@ function literal(value, opts = {}) {
566
659
  const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
567
660
  if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
568
661
  const span = { start: pos, end };
662
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
569
663
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
570
664
  return { ok: true, value: matchedValue, span };
571
665
  }
@@ -733,6 +827,7 @@ function regex(pattern, flags = "") {
733
827
  if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
734
828
  const value = input.slice(pos, scanEnd);
735
829
  const span2 = { start: pos, end: scanEnd };
830
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
736
831
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
737
832
  return { ok: true, value, span: span2 };
738
833
  }
@@ -742,6 +837,7 @@ function regex(pattern, flags = "") {
742
837
  return failAt(ctx, [`/${source}/`], pos);
743
838
  }
744
839
  const span = { start: pos, end: pos + m[0].length };
840
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
745
841
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
746
842
  return { ok: true, value: m[0], span };
747
843
  }
@@ -880,8 +976,8 @@ function parseRegex(src) {
880
976
  }
881
977
  if (src[k] !== "]") throw BAIL;
882
978
  i = k + 1;
883
- if (negated) return charNode(any(), true);
884
979
  const ranges = parseClassRanges(body);
980
+ if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
885
981
  if (!ranges) return charNode(any(), true);
886
982
  return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
887
983
  };
@@ -977,7 +1073,7 @@ function firstSet(n) {
977
1073
  }
978
1074
  }
979
1075
  }
980
- function firstCanBeNewline(n) {
1076
+ function canConsumeNewline(n) {
981
1077
  switch (n.t) {
982
1078
  case "char":
983
1079
  return n.nl;
@@ -986,16 +1082,11 @@ function firstCanBeNewline(n) {
986
1082
  case "empty":
987
1083
  return false;
988
1084
  case "rep":
989
- return firstCanBeNewline(n.node);
1085
+ return canConsumeNewline(n.node);
990
1086
  case "alt":
991
- return n.arms.some(firstCanBeNewline);
992
- case "seq": {
993
- for (const part of n.parts) {
994
- if (firstCanBeNewline(part)) return true;
995
- if (!nullable(part)) break;
996
- }
997
- return false;
998
- }
1087
+ return n.arms.some(canConsumeNewline);
1088
+ case "seq":
1089
+ return n.parts.some(canConsumeNewline);
999
1090
  }
1000
1091
  }
1001
1092
  function firstSetFromRegex(source) {
@@ -1005,8 +1096,8 @@ function firstSetFromRegex(source) {
1005
1096
  } catch {
1006
1097
  return { firstSet: any(), canMatchNewline: true };
1007
1098
  }
1008
- if (nullable(ast)) return { firstSet: any(), canMatchNewline: true };
1009
- return { firstSet: firstSet(ast), canMatchNewline: firstCanBeNewline(ast) };
1099
+ if (nullable(ast)) return { firstSet: any(), canMatchNewline: canConsumeNewline(ast) };
1100
+ return { firstSet: firstSet(ast), canMatchNewline: canConsumeNewline(ast) };
1010
1101
  }
1011
1102
 
1012
1103
  // src/combinators/case-fold.ts
@@ -1168,7 +1259,9 @@ function firstSetSentinel(fs) {
1168
1259
  function recoverScan(input, from, ctx, sync, expected) {
1169
1260
  let scanPos = from;
1170
1261
  while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1171
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
1262
+ const span = { start: from, end: scanPos };
1263
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1264
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1172
1265
  ctx._errors?.push(error);
1173
1266
  return { error, end: scanPos };
1174
1267
  }
@@ -1271,7 +1364,8 @@ function expect(combinator, label2) {
1271
1364
  parse(input, pos, ctx) {
1272
1365
  const result = combinator.parse(input, pos, ctx);
1273
1366
  if (result.ok) return result;
1274
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
1367
+ const span = { start: pos, end: pos };
1368
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1275
1369
  ctx._errors?.push(error);
1276
1370
  if (ctx._tolerant) captureError(ctx, error);
1277
1371
  return { ok: true, value: error, span: { start: pos, end: pos } };
@@ -1719,6 +1813,18 @@ function rollbackTrivia(ctx, mark) {
1719
1813
  rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1720
1814
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1721
1815
  }
1816
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1817
+ const probeCtx = {
1818
+ trackLines: ctx.trackLines,
1819
+ state: ctx.state,
1820
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1821
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1822
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1823
+ };
1824
+ const result = triviaP.parse(input, cur, probeCtx);
1825
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1826
+ return result;
1827
+ }
1722
1828
  function saveLookaheadMark(ctx) {
1723
1829
  return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1724
1830
  }
@@ -1741,13 +1847,29 @@ function scanWithLabels(input, cur, ctx) {
1741
1847
  function advanceTrivia(input, cur, ctx) {
1742
1848
  const triviaP = ctx.trivia;
1743
1849
  if (!triviaP) return cur;
1850
+ if (!ctx.trackLines) {
1851
+ const fast2 = fastTriviaScanner(triviaP);
1852
+ if (fast2) return fast2(input, cur);
1853
+ if (ctx.triviaKindLabels) {
1854
+ const scan = scanWithLabels(input, cur, ctx);
1855
+ return scan.end;
1856
+ }
1857
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1858
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1859
+ }
1860
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1744
1861
  const fast = fastTriviaScanner(triviaP);
1745
- if (fast) return fast(input, cur);
1862
+ if (fast) {
1863
+ const end = fast(input, cur);
1864
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1865
+ return end;
1866
+ }
1746
1867
  if (ctx.triviaKindLabels) {
1747
1868
  const scan = scanWithLabels(input, cur, ctx);
1869
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1748
1870
  return scan.end;
1749
1871
  }
1750
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1872
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1751
1873
  return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1752
1874
  }
1753
1875
  function scanTrivia(input, cur, ctx) {
@@ -1755,18 +1877,46 @@ function scanTrivia(input, cur, ctx) {
1755
1877
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1756
1878
  const log = ctx._triviaLog;
1757
1879
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1880
+ if (!ctx.trackLines) {
1881
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1882
+ if (fast2 && log === void 0 && !captureTl) {
1883
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1884
+ }
1885
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1886
+ return scanWithLabels(input, cur, ctx);
1887
+ }
1888
+ if (log !== void 0 || captureTl) {
1889
+ const tr3 = triviaP.parse(input, cur, {
1890
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1891
+ state: ctx.state
1892
+ });
1893
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1894
+ const end = tr3.span.end;
1895
+ return {
1896
+ end,
1897
+ commit: () => {
1898
+ pushTriviaLogEntry(ctx, cur, end);
1899
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1900
+ }
1901
+ };
1902
+ }
1903
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1904
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1905
+ }
1906
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1758
1907
  const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1759
1908
  if (fast && log === void 0 && !captureTl) {
1760
- return { end: fast(input, cur), commit: NOOP_COMMIT };
1909
+ const end = fast(input, cur);
1910
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1911
+ return { end, commit: NOOP_COMMIT };
1761
1912
  }
1762
1913
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1763
- return scanWithLabels(input, cur, ctx);
1914
+ const scan = scanWithLabels(input, cur, ctx);
1915
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1916
+ return scan;
1764
1917
  }
1765
1918
  if (log !== void 0 || captureTl) {
1766
- const tr2 = triviaP.parse(input, cur, {
1767
- trackLines: log !== void 0 ? false : ctx.trackLines,
1768
- state: ctx.state
1769
- });
1919
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1770
1920
  if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1771
1921
  const end = tr2.span.end;
1772
1922
  return {
@@ -1777,7 +1927,7 @@ function scanTrivia(input, cur, ctx) {
1777
1927
  }
1778
1928
  };
1779
1929
  }
1780
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1930
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1781
1931
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1782
1932
  }
1783
1933
  function consumeTrivia(input, cur, ctx) {
@@ -2711,9 +2861,11 @@ function markUnusedValues(root) {
2711
2861
  visit(def.parser, consumed);
2712
2862
  visit(def.sentinel, false);
2713
2863
  return;
2864
+ case "token":
2865
+ visit(def.parser, false);
2866
+ return;
2714
2867
  case "label":
2715
2868
  case "trivia":
2716
- case "token":
2717
2869
  case "attempt":
2718
2870
  case "withCtx":
2719
2871
  case "expect":
@@ -3199,13 +3351,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3199
3351
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3200
3352
  const nodeType = def.type ?? missingInferredType();
3201
3353
  const cstOutput = cstOutputHost(ctx.build);
3354
+ const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
3202
3355
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3203
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : 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 };
3204
- 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 };
3356
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3357
+ 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 };
3205
3358
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3206
3359
  pushCstChild(ctx, built, rawEntry);
3207
3360
  }
3208
- return { ok: true, value: built, span: r.span };
3361
+ return { ok: true, value: built, span };
3209
3362
  }
3210
3363
  };
3211
3364
  }
@@ -3276,38 +3429,24 @@ function field(name, combinator) {
3276
3429
  };
3277
3430
  }
3278
3431
 
3279
- // src/compiler/line-index.ts
3280
- function buildLineIndex(input) {
3281
- const lineStarts = [0];
3282
- for (let i = 0; i < input.length; i++) {
3283
- if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
3284
- }
3285
- return { lineStarts };
3286
- }
3287
- function offsetToLineCol(index, offset) {
3288
- const { lineStarts } = index;
3289
- let lo = 0;
3290
- let hi = lineStarts.length - 1;
3291
- while (lo < hi) {
3292
- const mid = lo + hi + 1 >> 1;
3293
- if (lineStarts[mid] <= offset) lo = mid;
3294
- else hi = mid - 1;
3432
+ // src/combinators/grammar.ts
3433
+ function annotateResultLines(result, index) {
3434
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
3435
+ const errors = annotated.errors;
3436
+ if (errors) {
3437
+ ;
3438
+ annotated.errors = errors.map((error) => ({
3439
+ ...error,
3440
+ span: annotateSpan(error.span, index)
3441
+ }));
3295
3442
  }
3296
- return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
3443
+ return annotated;
3297
3444
  }
3298
- function annotateSpan(span, index) {
3299
- const s = offsetToLineCol(index, span.start);
3300
- const e = offsetToLineCol(index, span.end);
3301
- return {
3302
- ...span,
3303
- startLine: s.line,
3304
- startColumn: s.col,
3305
- endLine: e.line,
3306
- endColumn: e.col
3307
- };
3445
+ function createParseLineContext(input, pos) {
3446
+ const lineIndex = createLineIndex();
3447
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3448
+ return { lineIndex, lineScannedTo: pos };
3308
3449
  }
3309
-
3310
- // src/combinators/grammar.ts
3311
3450
  function parser(opts, root) {
3312
3451
  const clearTrivia = opts.trivia === null;
3313
3452
  return {
@@ -3323,9 +3462,13 @@ function parser(opts, root) {
3323
3462
  },
3324
3463
  parse(input, pos, _ctx) {
3325
3464
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3465
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3466
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
3326
3467
  const ctx = {
3327
3468
  ..._ctx,
3328
3469
  trackLines,
3470
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
3471
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3329
3472
  // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
3330
3473
  ...clearTrivia ? {
3331
3474
  trivia: void 0,
@@ -3343,11 +3486,10 @@ function parser(opts, root) {
3343
3486
  ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3344
3487
  };
3345
3488
  const result = root.parse(input, pos ?? 0, ctx);
3346
- if (trackLines) {
3347
- const idx = buildLineIndex(input);
3348
- return { ...result, span: annotateSpan(result.span, idx) };
3489
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3490
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
3349
3491
  }
3350
- return result;
3492
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3351
3493
  }
3352
3494
  };
3353
3495
  }
@@ -3361,25 +3503,25 @@ function parse(combinator, input, opts = {}) {
3361
3503
  markUnusedValues(combinator);
3362
3504
  }
3363
3505
  const trackLines = opts.trackLines ?? false;
3506
+ const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
3507
+ const lineIndex = lineContext?.lineIndex;
3364
3508
  const _errors = opts.recover ? [] : void 0;
3365
3509
  const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
3366
3510
  const grammarTrivia = combinator._meta.grammarTrivia;
3367
3511
  const grammarScanSkip = combinator._meta.grammarScanSkip;
3368
3512
  const ctx = {
3369
3513
  trackLines,
3514
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
3515
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3370
3516
  ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
3371
3517
  ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
3372
3518
  ..._errors !== void 0 ? { _errors } : {},
3373
3519
  ..._probe !== void 0 ? { _probe } : {}
3374
3520
  };
3375
3521
  const result = combinator.parse(input, 0, ctx);
3376
- if (!result.ok) return result;
3522
+ if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3377
3523
  const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
3378
- if (trackLines) {
3379
- const idx = buildLineIndex(input);
3380
- return { ...withErrors, span: annotateSpan(withErrors.span, idx) };
3381
- }
3382
- return withErrors;
3524
+ return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
3383
3525
  }
3384
3526
 
3385
3527
  // src/combinators/token.ts
@@ -3478,7 +3620,7 @@ function leaf(root, fn) {
3478
3620
  }
3479
3621
 
3480
3622
  // src/version.ts
3481
- var PARSEMAN_VERSION = "0.40.0";
3623
+ var PARSEMAN_VERSION = "0.42.0";
3482
3624
 
3483
3625
  // src/cst/host-mode.ts
3484
3626
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -5162,7 +5304,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5162
5304
  let cur = pos;
5163
5305
  const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
5164
5306
  const probeCtx = {
5165
- trackLines: ctx.trackLines,
5307
+ trackLines: false,
5166
5308
  state: ctx.state,
5167
5309
  ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
5168
5310
  };
@@ -5175,6 +5317,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5175
5317
  while (cur < input.length) {
5176
5318
  const s = sentinel.parse(input, cur, probeCtx);
5177
5319
  if (s.ok) {
5320
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5178
5321
  emit2(cur);
5179
5322
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5180
5323
  }
@@ -5190,6 +5333,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5190
5333
  if (!advanced) cur++;
5191
5334
  }
5192
5335
  if (orEOF) {
5336
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5193
5337
  emit2(cur);
5194
5338
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5195
5339
  }
@@ -6422,7 +6566,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6422
6566
  ` if (${m.end} > _e) {`,
6423
6567
  ` if (_cap) {`,
6424
6568
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6425
- ` 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})`,
6569
+ ` if (_cap === 1 && _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})`,
6426
6570
  ` }`,
6427
6571
  ` _e = ${m.end}`,
6428
6572
  ` continue`,
@@ -6478,7 +6622,7 @@ function analyzeTriviaFastPath(trivia2) {
6478
6622
  var CAP_RECORD = [
6479
6623
  ` if (_cap && _e > _pos) {`,
6480
6624
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6481
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6625
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6482
6626
  ` }`
6483
6627
  ].join("\n");
6484
6628
  function composeFastLoop(shapes) {
@@ -6538,7 +6682,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6538
6682
  ` const _ce = _e + _m${i}[0].length`,
6539
6683
  ` if (_cap) {`,
6540
6684
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6541
- ` 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})`,
6685
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6542
6686
  ` }`,
6543
6687
  ` _e = _ce`,
6544
6688
  ` _matched = true`,
@@ -6576,7 +6720,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6576
6720
  ` const _ce = _r${i}.span.end`,
6577
6721
  ` if (_cap) {`,
6578
6722
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6579
- ` 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})`,
6723
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6580
6724
  ` }`,
6581
6725
  ` _e = _ce`,
6582
6726
  ` _matched = true`,
@@ -6628,8 +6772,8 @@ function analyzeMkInlineBuild(def) {
6628
6772
  if (looseMkBuildRe(def.type).test(src)) return def.type;
6629
6773
  return null;
6630
6774
  }
6631
- function emitInlineMkNodeExpr(type, chV, rawV, pos, endVar, tlV) {
6632
- return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: { start: ${pos}, end: ${endVar} }, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
6775
+ function emitInlineMkNodeExpr(type, chV, rawV, spanExpr, tlV) {
6776
+ return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: ${spanExpr}, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
6633
6777
  }
6634
6778
 
6635
6779
  // src/compiler/inline-callback.ts
@@ -6662,6 +6806,9 @@ function transformFnSource(fn, fnSrc) {
6662
6806
  function replaceParam(body, param, valueVar) {
6663
6807
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6664
6808
  }
6809
+ function hasExplicitObjectKey(body, param) {
6810
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6811
+ }
6665
6812
  function stripForIdCheck(body) {
6666
6813
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6667
6814
  }
@@ -6704,10 +6851,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6704
6851
  const allowed = new Set(valueVars);
6705
6852
  for (let i = 0; i < slots.length; i++) {
6706
6853
  const name = slots[i];
6707
- if (name) body = replaceParam(body, name, valueVars[i]);
6854
+ if (!name) continue;
6855
+ if (hasExplicitObjectKey(body, name)) return null;
6856
+ body = replaceParam(body, name, valueVars[i]);
6708
6857
  }
6709
6858
  return hasFreeIdentifiers(body, allowed) ? null : body;
6710
6859
  }
6860
+ function isDispatchTailOnlyTransform(src) {
6861
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
6862
+ if (!m) return false;
6863
+ const slots = parseArrayDestructure(m[1], 2);
6864
+ const tail = slots[1];
6865
+ return tail !== null && m[2].trim() === tail;
6866
+ }
6711
6867
 
6712
6868
  // src/compiler/codegen.ts
6713
6869
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6799,6 +6955,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
6799
6955
  }
6800
6956
  }
6801
6957
  var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) return false; let s; try { s = Function.prototype.toString.call(b) } catch (e) { return true } if (/\\barguments\\b/.test(s)) return true; const m = /^[^(]*\\(([\\s\\S]*?)\\)/.exec(s); if (m && /\\.\\.\\.|=/.test(m[1])) return true; return b.length > n }";
6958
+ var LINE_TRACK_DECL = "const _trackLines = (_ctx, input, start, end) => { const from = _ctx._lineScannedTo ?? 0; if (end <= from) return; for (let i = from; i < end; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1); _ctx._lineScannedTo = end }";
6959
+ var LINE_SPAN_DECL = "const _lineCol = (_ctx, offset) => { const starts = _ctx._lineStarts; let lo = 0, hi = starts.length - 1; while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (starts[mid] <= offset) lo = mid; else hi = mid - 1 } return [lo + 1, offset - starts[lo] + 1] }\nconst _spanLines = (_ctx, start, end) => { const s = _lineCol(_ctx, start), e = _lineCol(_ctx, end); return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] } }";
6802
6960
  var _loweringSink = null;
6803
6961
  function v(ctx, prefix = "_v") {
6804
6962
  return `${prefix}${ctx.vars++}`;
@@ -6939,14 +7097,46 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
6939
7097
  if (ctx.capAsTrivia) return [];
6940
7098
  const i = ind(ctx);
6941
7099
  const lf = v(ctx, "_lf");
7100
+ const spanExpr = emitSpanExpr(ctx, startExpr, endExpr);
6942
7101
  return [
6943
7102
  `${i}if (_ctx._cstLeaves || _ctx._cstRawChildren) {`,
6944
- `${i} const ${lf} = { _tag: 'leaf', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } }`,
7103
+ `${i} const ${lf} = { _tag: 'leaf', value: ${valExpr}, span: ${spanExpr} }`,
6945
7104
  `${i} if (_ctx._cstLeaves) _ctx._cstLeaves.push(${lf})`,
6946
7105
  `${i} if (_ctx._cstRawChildren) _ctx._cstRawChildren.push(${lf})`,
6947
7106
  `${i}}`
6948
7107
  ];
6949
7108
  }
7109
+ function emitSpanExpr(ctx, startExpr, endExpr) {
7110
+ if (!ctx.lineTracking) return `{ start: ${startExpr}, end: ${endExpr} }`;
7111
+ ctx.needsLineSpan = true;
7112
+ return `_spanLines(_ctx, ${startExpr}, ${endExpr})`;
7113
+ }
7114
+ function emitLineTrack(ctx, startExpr, endExpr) {
7115
+ if (!ctx.lineTracking) return [];
7116
+ ctx.needsLineTrack = true;
7117
+ return [`${ind(ctx)}_trackLines(_ctx, input, ${startExpr}, ${endExpr})`];
7118
+ }
7119
+ function emitLiteralLineTrack(ctx, startExpr, value) {
7120
+ if (!ctx.lineTracking) return [];
7121
+ const lineDeltas = [];
7122
+ for (let i = 0; i < value.length; i++) {
7123
+ if (value.charCodeAt(i) === 10) lineDeltas.push(i + 1);
7124
+ }
7125
+ if (lineDeltas.length === 0) return [];
7126
+ const fromV = v(ctx, "_ltFrom");
7127
+ const endExpr = value.length === 0 ? startExpr : `${startExpr} + ${value.length}`;
7128
+ return [
7129
+ `${ind(ctx)}const ${fromV} = _ctx._lineScannedTo ?? 0`,
7130
+ `${ind(ctx)}if (${endExpr} > ${fromV}) {`,
7131
+ `${ind(ctx)} for (let i = ${fromV}; i < ${startExpr}; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1)`,
7132
+ ...lineDeltas.map((delta) => {
7133
+ const lineStart = `${startExpr} + ${delta}`;
7134
+ return `${ind(ctx)} if (${lineStart} > ${fromV}) _ctx._lineStarts.push(${lineStart})`;
7135
+ }),
7136
+ `${ind(ctx)} _ctx._lineScannedTo = ${endExpr}`,
7137
+ `${ind(ctx)}}`
7138
+ ];
7139
+ }
6950
7140
  function ensureRegexDecl(ctx, source, flags) {
6951
7141
  const f = "y" + flags.replace(/[gy]/g, "");
6952
7142
  const key = `${source}/${f}`;
@@ -6958,6 +7148,17 @@ function ensureRegexDecl(ctx, source, flags) {
6958
7148
  }
6959
7149
  return rName;
6960
7150
  }
7151
+ function ensurePlainRegexDecl(ctx, source, flags) {
7152
+ const f = flags.replace(/[gy]/g, "");
7153
+ const key = `${source}/${f}`;
7154
+ let rName = ctx.regexMap.get(key);
7155
+ if (rName === void 0) {
7156
+ rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
7157
+ ctx.regexDecls.push(`const ${rName} = ${new RegExp(source, f).toString()}`);
7158
+ ctx.regexMap.set(key, rName);
7159
+ }
7160
+ return rName;
7161
+ }
6961
7162
  function ensureTriviaFn(ctx) {
6962
7163
  const trivia2 = ctx.activeTrivia;
6963
7164
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -7023,7 +7224,7 @@ function ensureTriviaFn(ctx) {
7023
7224
  ` }`,
7024
7225
  ` if (_cap && _e > _pos) {`,
7025
7226
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
7026
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
7227
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
7027
7228
  ` }`,
7028
7229
  ` return _e`,
7029
7230
  `}`
@@ -7320,6 +7521,7 @@ function emitLit(def, ctx, pos) {
7320
7521
  );
7321
7522
  }
7322
7523
  const endVar = len === 0 ? pos : `${pos} + ${len}`;
7524
+ stmts.push(...emitLiteralLineTrack(ctx, pos, value));
7323
7525
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7324
7526
  return { stmts, valueVar: vv, endVar };
7325
7527
  }
@@ -7399,7 +7601,7 @@ function emitKeywords(def, ctx, pos) {
7399
7601
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7400
7602
  return { stmts, valueVar: vv, endVar };
7401
7603
  }
7402
- function emitRegex(def, ctx, pos) {
7604
+ function emitRegex(def, ctx, pos, canMatchNewline = true) {
7403
7605
  const expectedStr = JSON.stringify(`/${def.source}/`);
7404
7606
  const shape = scanShapeFromRegex(def.source, def.flags);
7405
7607
  if (shape) {
@@ -7412,7 +7614,11 @@ function emitRegex(def, ctx, pos) {
7412
7614
  fresh: (prefix) => v(ctx, prefix)
7413
7615
  });
7414
7616
  if (scanned) {
7415
- const stmts2 = [...scanned.stmts, ...emitLeafCapture(ctx, vv2, pos, scanned.endVar)];
7617
+ const stmts2 = [
7618
+ ...scanned.stmts,
7619
+ ...canMatchNewline ? emitLineTrack(ctx, pos, scanned.endVar) : [],
7620
+ ...emitLeafCapture(ctx, vv2, pos, scanned.endVar)
7621
+ ];
7416
7622
  return { stmts: stmts2, valueVar: vv2, endVar: scanned.endVar };
7417
7623
  }
7418
7624
  }
@@ -7434,6 +7640,7 @@ function emitRegex(def, ctx, pos) {
7434
7640
  `${ind(ctx)}const ${vv} = ${mv}[0]`
7435
7641
  ];
7436
7642
  const endVar = `${pos} + ${vv}.length`;
7643
+ if (canMatchNewline) stmts.push(...emitLineTrack(ctx, pos, endVar));
7437
7644
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7438
7645
  return { stmts, valueVar: vv, endVar };
7439
7646
  }
@@ -7471,7 +7678,8 @@ function emitSeqValues(def, ctx, pos) {
7471
7678
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7472
7679
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7473
7680
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7474
- `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`
7681
+ `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7682
+ ...emitLineTrack(ctx, curV, scanEndV)
7475
7683
  );
7476
7684
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7477
7685
  stmts.push(...r2.stmts);
@@ -7484,14 +7692,20 @@ function emitSeqValues(def, ctx, pos) {
7484
7692
  continue;
7485
7693
  } else {
7486
7694
  const trivFn = ensureTriviaFn(ctx);
7695
+ const markLog = v(ctx, "_mklg");
7487
7696
  const scanEndV = v(ctx, "_sne");
7488
- stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
7697
+ const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7698
+ stmts.push(
7699
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7700
+ `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7701
+ ...emitLineTrack(ctx, curV, scanEndV)
7702
+ );
7489
7703
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7490
7704
  stmts.push(...r2.stmts);
7491
7705
  const endAfterV = v(ctx, "_sea");
7492
7706
  stmts.push(
7493
7707
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7494
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
7708
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7495
7709
  );
7496
7710
  valueVars.push(r2.valueVar);
7497
7711
  continue;
@@ -7721,19 +7935,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7721
7935
  return false;
7722
7936
  }
7723
7937
  }
7724
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7938
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7725
7939
  if (parserUsesRouted2(def.selector)) {
7726
7940
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7727
7941
  }
7728
7942
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7729
7943
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7730
7944
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7731
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7732
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7733
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7734
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7735
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7736
- const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
7945
+ const selectorNeedsRollback = hasRoutedBranch && (ctx.capturing === true && capturesLeaf(def.selector) || ctx.activeTrivia !== void 0 && parserHasTriviaSite(def.selector) || parserEnablesTriviaCapture(def.selector) || parserHasOwnFields(def.selector) || mayRecordRecoveryError(def.selector, !!ctx.recovery));
7946
+ const selectorLeafMark = selectorNeedsRollback ? v(ctx, "_dsl") : null;
7947
+ const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7948
+ const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7949
+ const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
7950
+ const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7951
+ const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7737
7952
  const selector = emit(def.selector, ctx, pos);
7738
7953
  const outV = v(ctx, "_dval");
7739
7954
  const outE = v(ctx, "_dend");
@@ -7758,13 +7973,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7758
7973
  stmts.push(head);
7759
7974
  ctx.indent++;
7760
7975
  const usesRouted = branchUsesRouted2(entry);
7761
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7976
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7977
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7762
7978
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7763
7979
  const errMark = mayError ? v(ctx, "_derr") : null;
7764
7980
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7765
- if (routedV) {
7981
+ if (usesRouted) {
7766
7982
  stmts.push(
7767
- `${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
7983
+ ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7768
7984
  ...selectorLeafMark ? [
7769
7985
  `${ind(ctx)}if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${selectorLeafMark}) _ctx._cstLeaves.length = ${selectorLeafMark}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${selectorRawMark}) _ctx._cstRawChildren.length = ${selectorRawMark}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${selectorTriviaMark}) _ctx._cstTriviaLog.length = ${selectorTriviaMark}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${selectorLogMark}) _ctx._triviaLog.length = ${selectorLogMark}; if (_ctx._fields && _ctx._fields.length !== ${selectorFieldMark}) _ctx._fields.length = ${selectorFieldMark}; if (_ctx._errors && _ctx._errors.length !== ${selectorErrorMark}) _ctx._errors.length = ${selectorErrorMark}`
7770
7986
  ] : []
@@ -7772,7 +7988,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7772
7988
  }
7773
7989
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7774
7990
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
7991
+ const savedRoutedLocal = ctx.routedLocal;
7992
+ const savedNoHoist = ctx.noHoist;
7993
+ if (usesRouted && !needsRoutedContext) {
7994
+ ctx.routedLocal = { valueVar: selector.valueVar, startVar: pos, endVar: selector.endVar };
7995
+ ctx.noHoist = true;
7996
+ } else if (usesRouted) {
7997
+ ctx.routedLocal = void 0;
7998
+ }
7775
7999
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
8000
+ ctx.routedLocal = savedRoutedLocal;
8001
+ ctx.noHoist = savedNoHoist;
7776
8002
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7777
8003
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7778
8004
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7782,7 +8008,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7782
8008
  ...tail.stmts,
7783
8009
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7784
8010
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7785
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
8011
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7786
8012
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7787
8013
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7788
8014
  );
@@ -7797,7 +8023,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7797
8023
  }
7798
8024
  const emitMatcherTails = () => {
7799
8025
  for (const matcher of def.matchers ?? []) {
7800
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
8026
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7801
8027
  wroteBranch = true;
7802
8028
  }
7803
8029
  };
@@ -7822,10 +8048,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7822
8048
  }
7823
8049
  return parts.join(" && ");
7824
8050
  }
7825
- function emitDispatchMatcherCondition(valueVar, matcher) {
8051
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7826
8052
  if (matcher.kind === "matches") {
7827
8053
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7828
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
8054
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7829
8055
  }
7830
8056
  const text = matcher.value;
7831
8057
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -8028,6 +8254,28 @@ function emitsAsNamedFn(p, ctx) {
8028
8254
  const usage = ctx.lazyUsage;
8029
8255
  return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
8030
8256
  }
8257
+ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8258
+ if (seen.has(p)) return false;
8259
+ seen.add(p);
8260
+ if (p._def.tag === "lazy") {
8261
+ if (ctx.ruleNames?.has(p) || ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8262
+ const usage = ctx.lazyUsage;
8263
+ if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
8264
+ try {
8265
+ return routedNeedsContextBridge(p._def.thunk(), ctx, seen);
8266
+ } catch {
8267
+ return parserUsesRouted2(p);
8268
+ }
8269
+ }
8270
+ return parserUsesRouted2(p);
8271
+ }
8272
+ if (ctx.ruleNames?.has(p)) return parserUsesRouted2(p);
8273
+ if (ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8274
+ const d = p._def;
8275
+ if (d.tag === "dispatch") return false;
8276
+ if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8277
+ return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8278
+ }
8031
8279
  function armReplayInScope(arm, ctx) {
8032
8280
  let p = arm;
8033
8281
  for (; ; ) {
@@ -8150,14 +8398,15 @@ function emitMany(def, ctx, pos) {
8150
8398
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8151
8399
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8152
8400
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8153
- `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`
8401
+ `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8402
+ ...emitLineTrack(ctx, curV, npV)
8154
8403
  );
8155
8404
  itemPos = npV;
8156
8405
  rollback = `if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; `;
8157
8406
  } else {
8158
8407
  const trivFn = ensureTriviaFn(ctx);
8159
8408
  const npV = v(ctx, "_np");
8160
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`);
8409
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, npV));
8161
8410
  itemPos = npV;
8162
8411
  }
8163
8412
  }
@@ -8278,15 +8527,16 @@ function emitSepBy(_p, def, ctx, pos) {
8278
8527
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8279
8528
  const postSepMarks = () => {
8280
8529
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8281
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg");
8530
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8282
8531
  return {
8283
8532
  decl: [
8284
8533
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8285
8534
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8286
8535
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8287
- `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`
8536
+ `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8537
+ `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8288
8538
  ],
8289
- rb: `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${lv}) _ctx._cstLeaves.length = ${lv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${rw}) _ctx._cstRawChildren.length = ${rw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${lg}) _ctx._triviaLog.length = ${lg}; `
8539
+ rb: `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${lv}) _ctx._cstLeaves.length = ${lv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${rw}) _ctx._cstRawChildren.length = ${rw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${lg}) _ctx._triviaLog.length = ${lg}; if (_ctx._fields && _ctx._fields.length !== ${fl}) _ctx._fields.length = ${fl}; `
8290
8540
  };
8291
8541
  };
8292
8542
  if (rec) {
@@ -8325,23 +8575,26 @@ function emitSepBy(_p, def, ctx, pos) {
8325
8575
  const markTl = v(ctx, "_mktl");
8326
8576
  const markLog = v(ctx, "_mklg");
8327
8577
  const markLv = v(ctx, "_mklv");
8578
+ const markFld = v(ctx, "_mkf");
8328
8579
  const spV = v(ctx, "_sp");
8329
8580
  stmts.push(
8330
8581
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8331
8582
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8332
8583
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8333
8584
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8334
- `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8585
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8586
+ `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8587
+ ...emitLineTrack(ctx, curV, spV)
8335
8588
  );
8336
8589
  sepAtPos = spV;
8337
- const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; `;
8590
+ const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; `;
8338
8591
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8339
8592
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8340
8593
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8341
8594
  const post = postSepMarks();
8342
8595
  stmts.push(...post.decl);
8343
8596
  const npV = v(ctx, "_np");
8344
- stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
8597
+ stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`, ...emitLineTrack(ctx, sepEnd, npV));
8345
8598
  const next = emitFallible(def.parser, ctx, npV, true);
8346
8599
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8347
8600
  stmts.push(
@@ -8353,13 +8606,13 @@ function emitSepBy(_p, def, ctx, pos) {
8353
8606
  } else {
8354
8607
  const trivFn = ensureTriviaFn(ctx);
8355
8608
  const spV = v(ctx, "_sp");
8356
- stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
8609
+ stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, spV));
8357
8610
  sepAtPos = spV;
8358
8611
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8359
8612
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8360
8613
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8361
8614
  const npV = v(ctx, "_np");
8362
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
8615
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`, ...emitLineTrack(ctx, sepEnd, npV));
8363
8616
  const next = emitFallible(def.parser, ctx, npV, true);
8364
8617
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8365
8618
  stmts.push(
@@ -8372,16 +8625,18 @@ function emitSepBy(_p, def, ctx, pos) {
8372
8625
  } else {
8373
8626
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8374
8627
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8628
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8375
8629
  if (markLv) {
8376
8630
  stmts.push(
8377
8631
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8378
- `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
8632
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8633
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`
8379
8634
  );
8380
8635
  }
8381
8636
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8382
8637
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8383
8638
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8384
- const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; ` : "";
8639
+ const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; ` : "";
8385
8640
  const post = postSepMarks();
8386
8641
  stmts.push(...post.decl);
8387
8642
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8444,6 +8699,7 @@ function emitScanTo(def, ctx, pos) {
8444
8699
  }
8445
8700
  const valV = v(ctx);
8446
8701
  stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
8702
+ stmts.push(...emitLineTrack(ctx, pos, curV));
8447
8703
  if (ctx.capturing) {
8448
8704
  const cap = reindentStmts(emitLeafCapture(ctx, valV, pos, curV), ctx.indent + 1);
8449
8705
  stmts.push(`${ind(ctx)}if (${curV} > ${pos}) {`, ...cap, `${ind(ctx)}}`);
@@ -8451,7 +8707,7 @@ function emitScanTo(def, ctx, pos) {
8451
8707
  return { stmts, valueVar: valV, endVar: curV };
8452
8708
  }
8453
8709
  function emitNot(def, ctx, pos) {
8454
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8710
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8455
8711
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8456
8712
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8457
8713
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8490,6 +8746,17 @@ function emitPeek(def, ctx, pos) {
8490
8746
  };
8491
8747
  }
8492
8748
  function emitRouted(ctx, pos) {
8749
+ const local = ctx.routedLocal;
8750
+ if (local !== void 0) {
8751
+ return {
8752
+ stmts: [
8753
+ ...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
8754
+ ...emitLeafCapture(ctx, local.valueVar, local.startVar, local.endVar)
8755
+ ],
8756
+ valueVar: local.valueVar,
8757
+ endVar: local.endVar
8758
+ };
8759
+ }
8493
8760
  const item = v(ctx, "_rt");
8494
8761
  return {
8495
8762
  stmts: [
@@ -8576,7 +8843,7 @@ function tokenNullableRegex(def) {
8576
8843
  }
8577
8844
  function emitToken(def, ctx, pos) {
8578
8845
  const lowered = tokenNullableRegex(def);
8579
- if (lowered) return emitRegex(lowered, ctx, pos);
8846
+ if (lowered) return emitRegex(lowered, ctx, pos, def.parser._meta.canMatchNewline);
8580
8847
  const savedTrivia = ctx.activeTrivia;
8581
8848
  const savedKindLabels = ctx.triviaKindLabels;
8582
8849
  ctx.activeTrivia = void 0;
@@ -8726,7 +8993,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8726
8993
  stmts.push(...innerStmts);
8727
8994
  if (def.trailingTrivia === true && ctx.activeTrivia) {
8728
8995
  const triviaFn = ensureTriviaFn(ctx);
8729
- stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
8996
+ stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`, ...emitLineTrack(ctx, innerEndVar, endVar));
8730
8997
  }
8731
8998
  if (sf && fArr) {
8732
8999
  stmts.push(`${i}const ${fArr} = _ctx._fields`);
@@ -8766,8 +9033,11 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8766
9033
  );
8767
9034
  }
8768
9035
  const ndV = v(ctx, "_nd");
8769
- 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) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8770
- const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
9036
+ const nodeSpanExpr = emitSpanExpr(ctx, pos, endVar);
9037
+ const nodeSpanV = ctx.lineTracking ? v(ctx, "_nspan") : nodeSpanExpr;
9038
+ if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
9039
+ const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: ${nodeSpanV}, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, nodeSpanV, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
9040
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
8771
9041
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8772
9042
  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;
8773
9043
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
@@ -8777,7 +9047,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8777
9047
  `${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
8778
9048
  `${i}if (!(${profileRecognizer})) {`,
8779
9049
  `${i} if (${sc}) ${sc}.push(${ndV})`,
8780
- `${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} } })`,
9050
+ `${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: ${nodeSpanV} })`,
8781
9051
  `${i}}`
8782
9052
  );
8783
9053
  return { stmts, valueVar: ndV, endVar };
@@ -8793,7 +9063,8 @@ function emitRuntimeFallback(parser2, ctx, pos) {
8793
9063
  `${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
8794
9064
  ...emitIfFail(ctx, `!${rv}.ok`, failStmt),
8795
9065
  `${ind(ctx)}const ${vv} = ${rv}.value`,
8796
- `${ind(ctx)}const ${ev} = ${rv}.span.end`
9066
+ `${ind(ctx)}const ${ev} = ${rv}.span.end`,
9067
+ ...parser2._meta.canMatchNewline ? emitLineTrack(ctx, pos, ev) : []
8797
9068
  ];
8798
9069
  return { stmts, valueVar: vv, endVar: ev };
8799
9070
  }
@@ -8859,7 +9130,8 @@ function emitRecover(def, ctx, pos) {
8859
9130
  `${ind0} if (${sentOk}) break`,
8860
9131
  `${ind0} ${scanV}++`,
8861
9132
  `${ind0} }`,
8862
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
9133
+ ...emitLineTrack(ctx, pos, scanV).map((s) => `${ind0} ${s.trim()}`),
9134
+ `${ind0} const ${errV} = { _tag: 'parseError', span: ${emitSpanExpr(ctx, pos, scanV)}, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
8863
9135
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
8864
9136
  `${ind0} ${valVar} = ${errV}`,
8865
9137
  `${ind0} ${endVar} = ${scanV}`,
@@ -8875,7 +9147,7 @@ function emitExpect(def, ctx, pos) {
8875
9147
  const stmts = [
8876
9148
  ...innerStmts,
8877
9149
  `${ind0}if (!${okVar}) {`,
8878
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
9150
+ `${ind0} const ${errV} = { _tag: 'parseError', span: ${emitSpanExpr(ctx, pos, pos)}, expected: ${JSON.stringify(def.expected)} }`,
8879
9151
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
8880
9152
  // Embed the missing-token error as a `parseError` CST child, mirroring the
8881
9153
  // interpreter (expect.ts) and the list-recovery emit sites — guarded on
@@ -8965,7 +9237,7 @@ function emitDispatch(p, ctx, pos) {
8965
9237
  case "literal":
8966
9238
  return emitLit(def, ctx, pos);
8967
9239
  case "regex":
8968
- return emitRegex(def, ctx, pos);
9240
+ return emitRegex(def, ctx, pos, p._meta.canMatchNewline);
8969
9241
  case "keywords":
8970
9242
  return emitKeywords(def, ctx, pos);
8971
9243
  case "sequence":
@@ -8985,6 +9257,9 @@ function emitDispatch(p, ctx, pos) {
8985
9257
  return emitSepBy(p, def, ctx, pos);
8986
9258
  case "transform": {
8987
9259
  const fnSrc = transformFnSource(def.fn, def.fnSrc);
9260
+ if (fnSrc && def.parser._def.tag === "dispatch" && isDispatchTailOnlyTransform(fnSrc)) {
9261
+ return emitDispatchCombinator(def.parser, def.parser._def, ctx, pos, "tail");
9262
+ }
8988
9263
  if (fnSrc && def.parser._def.tag === "sequence") {
8989
9264
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8990
9265
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9212,6 +9487,20 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
9212
9487
  return false;
9213
9488
  }
9214
9489
  }
9490
+ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9491
+ if (seen.has(p)) return false;
9492
+ seen.add(p);
9493
+ const d = p._def;
9494
+ if (d.tag === "grammar" && d.trackLines) return true;
9495
+ if (d.tag === "lazy") {
9496
+ try {
9497
+ return hasLineTrackingDef(d.thunk(), seen);
9498
+ } catch {
9499
+ return false;
9500
+ }
9501
+ }
9502
+ return childrenOf2(d).some((child) => hasLineTrackingDef(child, seen));
9503
+ }
9215
9504
  function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9216
9505
  if (seen.has(p)) return false;
9217
9506
  seen.add(p);
@@ -9579,6 +9868,7 @@ function compile(combinator, mapFnSources, opts) {
9579
9868
  capturing: hasNodeDef(combinator),
9580
9869
  recovery: opts?.recovery ?? false,
9581
9870
  hostMode: opts?.hostMode ?? grammarHostMode ?? "ast",
9871
+ lineTracking: opts?.trackLines === true || hasLineTrackingDef(combinator),
9582
9872
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9583
9873
  lazyUsage: analyzeLazyUsage(combinator),
9584
9874
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9602,9 +9892,13 @@ function compile(combinator, mapFnSources, opts) {
9602
9892
  const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
9603
9893
  const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
9604
9894
  const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
9895
+ const lineTrackDecls = ctx.needsLineTrack ? [LINE_TRACK_DECL] : [];
9896
+ const lineSpanDecls = ctx.needsLineSpan ? [LINE_SPAN_DECL] : [];
9605
9897
  const source = [
9606
9898
  ...emptyTlDecls,
9607
9899
  ...hostReadsDecls,
9900
+ ...lineTrackDecls,
9901
+ ...lineSpanDecls,
9608
9902
  ...ctx.regexDecls,
9609
9903
  ...ctx.expectedDecls,
9610
9904
  "",
@@ -9617,6 +9911,8 @@ function compile(combinator, mapFnSources, opts) {
9617
9911
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
9618
9912
  ...emptyTlDecls,
9619
9913
  ...hostReadsDecls,
9914
+ ...lineTrackDecls,
9915
+ ...lineSpanDecls,
9620
9916
  ...ctx.regexDecls,
9621
9917
  ...ctx.expectedDecls,
9622
9918
  ...namedPrelude,
@@ -9635,6 +9931,25 @@ function compile(combinator, mapFnSources, opts) {
9635
9931
  trackLines: false,
9636
9932
  ...ctx.triviaKindLabels ? { triviaKindLabels: ctx.triviaKindLabels } : {}
9637
9933
  };
9934
+ const annotateWithTrackedLines = (result, lineStarts) => {
9935
+ const index = normalizeLineIndex({ lineStarts });
9936
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
9937
+ const errors = annotated.errors;
9938
+ if (errors) {
9939
+ ;
9940
+ annotated.errors = errors.map((error) => ({
9941
+ ...error,
9942
+ span: annotateSpan(error.span, index)
9943
+ }));
9944
+ }
9945
+ return annotated;
9946
+ };
9947
+ const trackedCtx = (base, input, pos) => {
9948
+ if (!ctx.lineTracking) return base;
9949
+ const lineIndex = { lineStarts: [0] };
9950
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
9951
+ return { ...base, trackLines: true, _lineStarts: lineIndex.lineStarts, _lineScannedTo: pos };
9952
+ };
9638
9953
  const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
9639
9954
  const effectiveSources = mapFnSources ?? derivedSrcs;
9640
9955
  const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
@@ -9642,17 +9957,46 @@ function compile(combinator, mapFnSources, opts) {
9642
9957
  const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
9643
9958
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
9644
9959
  const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
9645
- return {
9960
+ const compiledMeta = {
9646
9961
  source,
9647
9962
  inlineExpression,
9648
9963
  ...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
9649
- ...gatingReport === void 0 ? {} : { gating: gatingReport },
9964
+ ...gatingReport === void 0 ? {} : { gating: gatingReport }
9965
+ };
9966
+ if (!ctx.lineTracking) {
9967
+ return {
9968
+ ...compiledMeta,
9969
+ parse(input, pos = 0) {
9970
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
9971
+ },
9972
+ parseWithContext(input, parseCtx, pos = 0) {
9973
+ assertHostModeCompatible(ctx.hostMode ?? "ast", parseCtx.build, !!ctx.hostBranchElided);
9974
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9975
+ },
9976
+ // Note: collects expect() errors via _errors. Unlike interpreter
9977
+ // parse({recover:true}) it does NOT populate furthestFail — the compiled path
9978
+ // inlines failures for throughput and deliberately skips _probe bookkeeping.
9979
+ // Callers wanting a furthest-position diagnostic detect unconsumed input
9980
+ // (span.end < input.length) instead, which is mode-agnostic.
9981
+ parseWithErrors(input, pos = 0) {
9982
+ const errors = [];
9983
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
9984
+ return { ...result, errors };
9985
+ }
9986
+ };
9987
+ }
9988
+ return {
9989
+ ...compiledMeta,
9650
9990
  parse(input, pos = 0) {
9651
- return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
9991
+ const parseCtx = trackedCtx(defaultCtx, input, pos);
9992
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9993
+ return annotateWithTrackedLines(result, parseCtx._lineStarts);
9652
9994
  },
9653
9995
  parseWithContext(input, parseCtx, pos = 0) {
9654
9996
  assertHostModeCompatible(ctx.hostMode ?? "ast", parseCtx.build, !!ctx.hostBranchElided);
9655
- return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9997
+ const activeCtx = trackedCtx(parseCtx, input, pos);
9998
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, activeCtx);
9999
+ return activeCtx.trackLines ? annotateWithTrackedLines(result, activeCtx._lineStarts) : result;
9656
10000
  },
9657
10001
  // Note: collects expect() errors via _errors. Unlike interpreter
9658
10002
  // parse({recover:true}) it does NOT populate furthestFail — the compiled path
@@ -9661,8 +10005,9 @@ function compile(combinator, mapFnSources, opts) {
9661
10005
  // (span.end < input.length) instead, which is mode-agnostic.
9662
10006
  parseWithErrors(input, pos = 0) {
9663
10007
  const errors = [];
9664
- const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
9665
- return { ...result, errors };
10008
+ const parseCtx = trackedCtx({ ...defaultCtx, _errors: errors }, input, pos);
10009
+ const result = { ...fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx), errors };
10010
+ return annotateWithTrackedLines(result, parseCtx._lineStarts);
9666
10011
  }
9667
10012
  };
9668
10013
  }
@@ -9674,8 +10019,8 @@ function assertRuleName(name) {
9674
10019
  );
9675
10020
  }
9676
10021
  }
9677
- function publicRuleWrapperSource(rule, fnSource) {
9678
- const labels = rule._meta.triviaKindLabels;
10022
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
10023
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9679
10024
  if (labels === void 0) return fnSource;
9680
10025
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9681
10026
  }
@@ -9844,7 +10189,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9844
10189
  ...r.stmts,
9845
10190
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9846
10191
  `}`
9847
- ].join("\n")));
10192
+ ].join("\n"), ctx.triviaKindLabels));
9848
10193
  }
9849
10194
  const firstSets = /* @__PURE__ */ new Map();
9850
10195
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -9949,12 +10294,16 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootR
9949
10294
  const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
9950
10295
  const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
9951
10296
  const hostReadsDecl = ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "";
9952
- const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl;
10297
+ const lineTrackDecl = ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "";
10298
+ const lineSpanDecl = ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "";
10299
+ const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!lineTrackDecl || !!lineSpanDecl;
9953
10300
  if (!needsWrapper) return innerFn;
9954
10301
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
9955
10302
  const hoistedDecls = [
9956
10303
  emptyTlDecl,
9957
10304
  hostReadsDecl,
10305
+ lineTrackDecl,
10306
+ lineSpanDecl,
9958
10307
  ...ctx.regexDecls.map((d) => ` ${d}`),
9959
10308
  ...ctx.expectedDecls.map((d) => ` ${d}`),
9960
10309
  mfDecl,
@@ -10503,7 +10852,7 @@ function normalizeCstCollapse(collapse) {
10503
10852
  return typeof collapse === "function" ? collapse : void 0;
10504
10853
  }
10505
10854
  function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
10506
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
10855
+ return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
10507
10856
  }
10508
10857
  function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
10509
10858
  if (typeof typeOrOptions === "string") {
@@ -11362,8 +11711,158 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11362
11711
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11363
11712
  }
11364
11713
 
11714
+ // src/cst/trivia-entries.ts
11715
+ var EMPTY_INDICES = Object.freeze([]);
11716
+ var EMPTY_GAPS = Object.freeze([]);
11717
+ function entryOffset(i, stride) {
11718
+ return i * stride;
11719
+ }
11720
+ function triviaEntries(log, labels, opts) {
11721
+ const baseStride = opts?.nodeLog ? 3 : 2;
11722
+ const stride = labels ? baseStride + 1 : baseStride;
11723
+ const length = Math.floor(log.length / stride);
11724
+ return {
11725
+ length,
11726
+ labels,
11727
+ stride,
11728
+ start(i) {
11729
+ return log[entryOffset(i, stride)];
11730
+ },
11731
+ end(i) {
11732
+ return log[entryOffset(i, stride) + 1];
11733
+ },
11734
+ insertIndex(i) {
11735
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11736
+ },
11737
+ kindIndex(i) {
11738
+ if (!labels) return void 0;
11739
+ return log[entryOffset(i, stride) + baseStride];
11740
+ },
11741
+ kind(i) {
11742
+ const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11743
+ return ki !== void 0 ? labels[ki] : void 0;
11744
+ },
11745
+ text(i, input) {
11746
+ const s = log[entryOffset(i, stride)];
11747
+ const e = log[entryOffset(i, stride) + 1];
11748
+ return input.slice(s, e);
11749
+ }
11750
+ };
11751
+ }
11752
+ function appendEntryRange(map, key, first, last) {
11753
+ let indices = map.get(key);
11754
+ if (!indices) {
11755
+ indices = [];
11756
+ map.set(key, indices);
11757
+ }
11758
+ for (let i = first; i <= last; i++) indices.push(i);
11759
+ }
11760
+ function buildGap(entries, start, end, first, last) {
11761
+ const entryIndices = [];
11762
+ for (let i = first; i <= last; i++) entryIndices.push(i);
11763
+ return {
11764
+ start,
11765
+ end,
11766
+ entryIndices,
11767
+ hasKind(kind) {
11768
+ for (const i of entryIndices) {
11769
+ if (entries.kind(i) === kind) return true;
11770
+ }
11771
+ return false;
11772
+ },
11773
+ text(input) {
11774
+ return input.slice(start, end);
11775
+ }
11776
+ };
11777
+ }
11778
+ function buildRootMaps(entries) {
11779
+ const before = /* @__PURE__ */ new Map();
11780
+ const after = /* @__PURE__ */ new Map();
11781
+ const beforeGaps = /* @__PURE__ */ new Map();
11782
+ const afterGaps = /* @__PURE__ */ new Map();
11783
+ const gaps = [];
11784
+ if (entries.length === 0) return { before, after, beforeGaps, afterGaps, gaps };
11785
+ const appendGap = (first2, last, start2, end2) => {
11786
+ const gap = buildGap(entries, start2, end2, first2, last);
11787
+ gaps.push(gap);
11788
+ afterGaps.set(start2, gap);
11789
+ beforeGaps.set(end2, gap);
11790
+ appendEntryRange(after, start2, first2, last);
11791
+ appendEntryRange(before, end2, first2, last);
11792
+ };
11793
+ let first = 0;
11794
+ let start = entries.start(0);
11795
+ let end = entries.end(0);
11796
+ for (let i = 1; i < entries.length; i++) {
11797
+ const nextStart = entries.start(i);
11798
+ const nextEnd = entries.end(i);
11799
+ if (nextStart === end) {
11800
+ end = nextEnd;
11801
+ continue;
11802
+ }
11803
+ appendGap(first, i - 1, start, end);
11804
+ first = i;
11805
+ start = nextStart;
11806
+ end = nextEnd;
11807
+ }
11808
+ appendGap(first, entries.length - 1, start, end);
11809
+ return { before, after, beforeGaps, afterGaps, gaps };
11810
+ }
11811
+ function buildRootTriviaIndex(log, labels) {
11812
+ const entries = triviaEntries(log, labels);
11813
+ let maps;
11814
+ const getMaps = () => {
11815
+ maps ??= buildRootMaps(entries);
11816
+ return maps;
11817
+ };
11818
+ return {
11819
+ entries,
11820
+ labels,
11821
+ get before() {
11822
+ return getMaps().before;
11823
+ },
11824
+ get after() {
11825
+ return getMaps().after;
11826
+ },
11827
+ entryIndicesBefore(offset) {
11828
+ return getMaps().before.get(offset) ?? EMPTY_INDICES;
11829
+ },
11830
+ entryIndicesAfter(offset) {
11831
+ return getMaps().after.get(offset) ?? EMPTY_INDICES;
11832
+ },
11833
+ gapBefore(offset) {
11834
+ return getMaps().beforeGaps.get(offset);
11835
+ },
11836
+ gapAfter(offset) {
11837
+ return getMaps().afterGaps.get(offset);
11838
+ },
11839
+ gaps() {
11840
+ return getMaps().gaps;
11841
+ },
11842
+ gapsWithKind(kind) {
11843
+ const kinds = typeof kind === "string" ? [kind] : kind;
11844
+ const matches2 = [];
11845
+ for (const gap of getMaps().gaps) {
11846
+ for (const k of kinds) {
11847
+ if (gap.hasKind(k)) {
11848
+ matches2.push(gap);
11849
+ break;
11850
+ }
11851
+ }
11852
+ }
11853
+ return matches2.length === 0 ? EMPTY_GAPS : matches2;
11854
+ }
11855
+ };
11856
+ }
11857
+
11365
11858
  // src/functional/run.ts
11366
11859
  var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
11860
+ function triviaKindLabelsFromRunnable(r) {
11861
+ if (!r) return void 0;
11862
+ if (typeof r === "function") return r._meta?.triviaKindLabels;
11863
+ const grammarTrivia = r._meta.grammarTrivia;
11864
+ return r._meta.triviaKindLabels ?? grammarTrivia?._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
11865
+ }
11367
11866
  function runOnce(entry, input, options, phase, profileState) {
11368
11867
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
11369
11868
  throw new TypeError(
@@ -11376,6 +11875,7 @@ function runOnce(entry, input, options, phase, profileState) {
11376
11875
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
11377
11876
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
11378
11877
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
11878
+ const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
11379
11879
  const stamped = entry;
11380
11880
  assertHostModeCompatible(
11381
11881
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -11387,7 +11887,7 @@ function runOnce(entry, input, options, phase, profileState) {
11387
11887
  ...skipGlobalSinks ? { _pmProfile: profile } : { _triviaLog: triviaLog, _errors: errors, ...profile === void 0 ? {} : { _pmProfile: profile } },
11388
11888
  build: options.build,
11389
11889
  state: options.state,
11390
- ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
11890
+ ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
11391
11891
  ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
11392
11892
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
11393
11893
  ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
@@ -11410,6 +11910,8 @@ function runOnce(entry, input, options, phase, profileState) {
11410
11910
  expected: r.ok ? [] : r.expected ?? [],
11411
11911
  errors,
11412
11912
  triviaLog,
11913
+ ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
11914
+ triviaMap: buildRootTriviaIndex(triviaLog, triviaKindLabels),
11413
11915
  unconsumedFrom
11414
11916
  };
11415
11917
  }
@@ -11868,43 +12370,6 @@ function createVisitor(handlers) {
11868
12370
  return (node2) => api.visit(node2);
11869
12371
  }
11870
12372
 
11871
- // src/cst/trivia-entries.ts
11872
- function entryOffset(i, stride) {
11873
- return i * stride;
11874
- }
11875
- function triviaEntries(log, labels, opts) {
11876
- const baseStride = opts?.nodeLog ? 3 : 2;
11877
- const stride = labels ? baseStride + 1 : baseStride;
11878
- const length = Math.floor(log.length / stride);
11879
- return {
11880
- length,
11881
- labels,
11882
- stride,
11883
- start(i) {
11884
- return log[entryOffset(i, stride)];
11885
- },
11886
- end(i) {
11887
- return log[entryOffset(i, stride) + 1];
11888
- },
11889
- insertIndex(i) {
11890
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11891
- },
11892
- kindIndex(i) {
11893
- if (!labels) return void 0;
11894
- return log[entryOffset(i, stride) + baseStride];
11895
- },
11896
- kind(i) {
11897
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11898
- return ki !== void 0 ? labels[ki] : void 0;
11899
- },
11900
- text(i, input) {
11901
- const s = log[entryOffset(i, stride)];
11902
- const e = log[entryOffset(i, stride) + 1];
11903
- return input.slice(s, e);
11904
- }
11905
- };
11906
- }
11907
-
11908
12373
  // src/cst/offset-model.ts
11909
12374
  var { isFinite } = Number;
11910
12375
  function floorIndex(arr, len, x) {