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
@@ -317,6 +317,65 @@ function failAt(ctx, expected, pos) {
317
317
  return r;
318
318
  }
319
319
 
320
+ // src/line-index.ts
321
+ function createLineIndex() {
322
+ return { lineStarts: [0] };
323
+ }
324
+ function recordLineRange(index, input, start, end) {
325
+ const lineStarts = index.lineStarts;
326
+ for (let i = start; i < end; i++) {
327
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
328
+ }
329
+ }
330
+ function recordLineRangeFromContext(ctx, input, _startHint, end) {
331
+ if (!ctx.trackLines) return;
332
+ const from = ctx._lineScannedTo ?? 0;
333
+ if (end <= from) return;
334
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
335
+ if (!index) return;
336
+ recordLineRange(index, input, from, end);
337
+ ctx._lineScannedTo = end;
338
+ }
339
+ function normalizeLineIndex(index) {
340
+ const starts = index.lineStarts;
341
+ starts.sort((a, b) => a - b);
342
+ let write = 0;
343
+ for (let read = 0; read < starts.length; read++) {
344
+ const value = starts[read];
345
+ if (write === 0 || starts[write - 1] !== value) starts[write++] = value;
346
+ }
347
+ starts.length = write;
348
+ if (starts.length === 0 || starts[0] !== 0) starts.unshift(0);
349
+ return index;
350
+ }
351
+ function offsetToLineCol(index, offset) {
352
+ const { lineStarts } = index;
353
+ let lo = 0;
354
+ let hi = lineStarts.length - 1;
355
+ while (lo < hi) {
356
+ const mid = lo + hi + 1 >> 1;
357
+ if (lineStarts[mid] <= offset) lo = mid;
358
+ else hi = mid - 1;
359
+ }
360
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
361
+ }
362
+ function annotateSpan(span, index) {
363
+ const s = offsetToLineCol(index, span.start);
364
+ const e = offsetToLineCol(index, span.end);
365
+ return {
366
+ ...span,
367
+ startLine: s.line,
368
+ startColumn: s.col,
369
+ endLine: e.line,
370
+ endColumn: e.col
371
+ };
372
+ }
373
+ function annotateSpanFromLineContext(span, ctx) {
374
+ if (!ctx.trackLines) return span;
375
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
376
+ return index ? annotateSpan(span, index) : span;
377
+ }
378
+
320
379
  // src/cst/capture-buffer.ts
321
380
  var EMPTY = [];
322
381
  var EMPTY_TL = [];
@@ -358,7 +417,12 @@ function endCstNodeCapture(ctx, saved) {
358
417
  return materialized;
359
418
  }
360
419
  function pushCstLeaf(ctx, leaf2) {
361
- pushCstChild(ctx, leaf2, leaf2);
420
+ if (!ctx.trackLines) {
421
+ pushCstChild(ctx, leaf2, leaf2);
422
+ return;
423
+ }
424
+ const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
425
+ pushCstChild(ctx, annotated, annotated);
362
426
  }
363
427
  function pushCstChild(ctx, built, rawEntry) {
364
428
  const b = ctx._cstBuf;
@@ -492,6 +556,7 @@ function literal(value, opts = {}) {
492
556
  canMatchNewline: value.includes("\n"),
493
557
  isTrivia: false
494
558
  };
559
+ const canMatchNewline = meta.canMatchNewline;
495
560
  if (caseInsensitive) {
496
561
  const upper = value.toUpperCase();
497
562
  const lower = value.toLowerCase();
@@ -508,6 +573,7 @@ function literal(value, opts = {}) {
508
573
  return function parse3(input, pos, ctx) {
509
574
  if (input.charCodeAt(pos) === code) {
510
575
  const span = { start: pos, end: pos + 1 };
576
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
511
577
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
512
578
  return { ok: true, value, span };
513
579
  }
@@ -521,6 +587,7 @@ function literal(value, opts = {}) {
521
587
  const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
522
588
  if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
523
589
  const span = { start: pos, end };
590
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
524
591
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
525
592
  return { ok: true, value: matchedValue, span };
526
593
  }
@@ -688,6 +755,7 @@ function regex(pattern, flags = "") {
688
755
  if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
689
756
  const value = input.slice(pos, scanEnd);
690
757
  const span2 = { start: pos, end: scanEnd };
758
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
691
759
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
692
760
  return { ok: true, value, span: span2 };
693
761
  }
@@ -697,6 +765,7 @@ function regex(pattern, flags = "") {
697
765
  return failAt(ctx, [`/${source}/`], pos);
698
766
  }
699
767
  const span = { start: pos, end: pos + m[0].length };
768
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
700
769
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
701
770
  return { ok: true, value: m[0], span };
702
771
  }
@@ -835,8 +904,8 @@ function parseRegex(src) {
835
904
  }
836
905
  if (src[k] !== "]") throw BAIL;
837
906
  i = k + 1;
838
- if (negated) return charNode(any(), true);
839
907
  const ranges = parseClassRanges(body);
908
+ if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
840
909
  if (!ranges) return charNode(any(), true);
841
910
  return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
842
911
  };
@@ -932,7 +1001,7 @@ function firstSet(n) {
932
1001
  }
933
1002
  }
934
1003
  }
935
- function firstCanBeNewline(n) {
1004
+ function canConsumeNewline(n) {
936
1005
  switch (n.t) {
937
1006
  case "char":
938
1007
  return n.nl;
@@ -941,16 +1010,11 @@ function firstCanBeNewline(n) {
941
1010
  case "empty":
942
1011
  return false;
943
1012
  case "rep":
944
- return firstCanBeNewline(n.node);
1013
+ return canConsumeNewline(n.node);
945
1014
  case "alt":
946
- return n.arms.some(firstCanBeNewline);
947
- case "seq": {
948
- for (const part of n.parts) {
949
- if (firstCanBeNewline(part)) return true;
950
- if (!nullable(part)) break;
951
- }
952
- return false;
953
- }
1015
+ return n.arms.some(canConsumeNewline);
1016
+ case "seq":
1017
+ return n.parts.some(canConsumeNewline);
954
1018
  }
955
1019
  }
956
1020
  function firstSetFromRegex(source) {
@@ -960,8 +1024,8 @@ function firstSetFromRegex(source) {
960
1024
  } catch {
961
1025
  return { firstSet: any(), canMatchNewline: true };
962
1026
  }
963
- if (nullable(ast)) return { firstSet: any(), canMatchNewline: true };
964
- return { firstSet: firstSet(ast), canMatchNewline: firstCanBeNewline(ast) };
1027
+ if (nullable(ast)) return { firstSet: any(), canMatchNewline: canConsumeNewline(ast) };
1028
+ return { firstSet: firstSet(ast), canMatchNewline: canConsumeNewline(ast) };
965
1029
  }
966
1030
 
967
1031
  // src/combinators/case-fold.ts
@@ -1118,7 +1182,9 @@ function firstSetSentinel(fs2) {
1118
1182
  function recoverScan(input, from, ctx, sync, expected) {
1119
1183
  let scanPos = from;
1120
1184
  while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1121
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
1185
+ const span = { start: from, end: scanPos };
1186
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1187
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1122
1188
  ctx._errors?.push(error);
1123
1189
  return { error, end: scanPos };
1124
1190
  }
@@ -1220,7 +1286,8 @@ function expect(combinator, label2) {
1220
1286
  parse(input, pos, ctx) {
1221
1287
  const result = combinator.parse(input, pos, ctx);
1222
1288
  if (result.ok) return result;
1223
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
1289
+ const span = { start: pos, end: pos };
1290
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1224
1291
  ctx._errors?.push(error);
1225
1292
  if (ctx._tolerant) captureError(ctx, error);
1226
1293
  return { ok: true, value: error, span: { start: pos, end: pos } };
@@ -1665,6 +1732,18 @@ function rollbackTrivia(ctx, mark) {
1665
1732
  rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1666
1733
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1667
1734
  }
1735
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1736
+ const probeCtx = {
1737
+ trackLines: ctx.trackLines,
1738
+ state: ctx.state,
1739
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1740
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1741
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1742
+ };
1743
+ const result = triviaP.parse(input, cur, probeCtx);
1744
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1745
+ return result;
1746
+ }
1668
1747
  function saveLookaheadMark(ctx) {
1669
1748
  return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1670
1749
  }
@@ -1687,13 +1766,29 @@ function scanWithLabels(input, cur, ctx) {
1687
1766
  function advanceTrivia(input, cur, ctx) {
1688
1767
  const triviaP = ctx.trivia;
1689
1768
  if (!triviaP) return cur;
1769
+ if (!ctx.trackLines) {
1770
+ const fast2 = fastTriviaScanner(triviaP);
1771
+ if (fast2) return fast2(input, cur);
1772
+ if (ctx.triviaKindLabels) {
1773
+ const scan = scanWithLabels(input, cur, ctx);
1774
+ return scan.end;
1775
+ }
1776
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1777
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1778
+ }
1779
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1690
1780
  const fast = fastTriviaScanner(triviaP);
1691
- if (fast) return fast(input, cur);
1781
+ if (fast) {
1782
+ const end = fast(input, cur);
1783
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1784
+ return end;
1785
+ }
1692
1786
  if (ctx.triviaKindLabels) {
1693
1787
  const scan = scanWithLabels(input, cur, ctx);
1788
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1694
1789
  return scan.end;
1695
1790
  }
1696
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1791
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1697
1792
  return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1698
1793
  }
1699
1794
  function scanTrivia(input, cur, ctx) {
@@ -1701,18 +1796,46 @@ function scanTrivia(input, cur, ctx) {
1701
1796
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1702
1797
  const log = ctx._triviaLog;
1703
1798
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1799
+ if (!ctx.trackLines) {
1800
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1801
+ if (fast2 && log === void 0 && !captureTl) {
1802
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1803
+ }
1804
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1805
+ return scanWithLabels(input, cur, ctx);
1806
+ }
1807
+ if (log !== void 0 || captureTl) {
1808
+ const tr3 = triviaP.parse(input, cur, {
1809
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1810
+ state: ctx.state
1811
+ });
1812
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1813
+ const end = tr3.span.end;
1814
+ return {
1815
+ end,
1816
+ commit: () => {
1817
+ pushTriviaLogEntry(ctx, cur, end);
1818
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1819
+ }
1820
+ };
1821
+ }
1822
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1823
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1824
+ }
1825
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1704
1826
  const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1705
1827
  if (fast && log === void 0 && !captureTl) {
1706
- return { end: fast(input, cur), commit: NOOP_COMMIT };
1828
+ const end = fast(input, cur);
1829
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1830
+ return { end, commit: NOOP_COMMIT };
1707
1831
  }
1708
1832
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1709
- return scanWithLabels(input, cur, ctx);
1833
+ const scan = scanWithLabels(input, cur, ctx);
1834
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1835
+ return scan;
1710
1836
  }
1711
1837
  if (log !== void 0 || captureTl) {
1712
- const tr2 = triviaP.parse(input, cur, {
1713
- trackLines: log !== void 0 ? false : ctx.trackLines,
1714
- state: ctx.state
1715
- });
1838
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1716
1839
  if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1717
1840
  const end = tr2.span.end;
1718
1841
  return {
@@ -1723,7 +1846,7 @@ function scanTrivia(input, cur, ctx) {
1723
1846
  }
1724
1847
  };
1725
1848
  }
1726
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1849
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1727
1850
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1728
1851
  }
1729
1852
  function consumeTrivia(input, cur, ctx) {
@@ -2617,9 +2740,11 @@ function markUnusedValues(root) {
2617
2740
  visit(def.parser, consumed);
2618
2741
  visit(def.sentinel, false);
2619
2742
  return;
2743
+ case "token":
2744
+ visit(def.parser, false);
2745
+ return;
2620
2746
  case "label":
2621
2747
  case "trivia":
2622
- case "token":
2623
2748
  case "attempt":
2624
2749
  case "withCtx":
2625
2750
  case "expect":
@@ -3105,13 +3230,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3105
3230
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3106
3231
  const nodeType = def.type ?? missingInferredType();
3107
3232
  const cstOutput = cstOutputHost(ctx.build);
3233
+ const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
3108
3234
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3109
- 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 };
3110
- 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 };
3235
+ 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 };
3236
+ 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 };
3111
3237
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3112
3238
  pushCstChild(ctx, built, rawEntry);
3113
3239
  }
3114
- return { ok: true, value: built, span: r.span };
3240
+ return { ok: true, value: built, span };
3115
3241
  }
3116
3242
  };
3117
3243
  }
@@ -3182,38 +3308,24 @@ function field(name, combinator) {
3182
3308
  };
3183
3309
  }
3184
3310
 
3185
- // src/compiler/line-index.ts
3186
- function buildLineIndex(input) {
3187
- const lineStarts = [0];
3188
- for (let i = 0; i < input.length; i++) {
3189
- if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
3311
+ // src/combinators/grammar.ts
3312
+ function annotateResultLines(result, index) {
3313
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
3314
+ const errors = annotated.errors;
3315
+ if (errors) {
3316
+ ;
3317
+ annotated.errors = errors.map((error) => ({
3318
+ ...error,
3319
+ span: annotateSpan(error.span, index)
3320
+ }));
3190
3321
  }
3191
- return { lineStarts };
3322
+ return annotated;
3192
3323
  }
3193
- function offsetToLineCol(index, offset) {
3194
- const { lineStarts } = index;
3195
- let lo = 0;
3196
- let hi = lineStarts.length - 1;
3197
- while (lo < hi) {
3198
- const mid = lo + hi + 1 >> 1;
3199
- if (lineStarts[mid] <= offset) lo = mid;
3200
- else hi = mid - 1;
3201
- }
3202
- return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
3324
+ function createParseLineContext(input, pos) {
3325
+ const lineIndex = createLineIndex();
3326
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3327
+ return { lineIndex, lineScannedTo: pos };
3203
3328
  }
3204
- function annotateSpan(span, index) {
3205
- const s = offsetToLineCol(index, span.start);
3206
- const e = offsetToLineCol(index, span.end);
3207
- return {
3208
- ...span,
3209
- startLine: s.line,
3210
- startColumn: s.col,
3211
- endLine: e.line,
3212
- endColumn: e.col
3213
- };
3214
- }
3215
-
3216
- // src/combinators/grammar.ts
3217
3329
  function parser(opts, root) {
3218
3330
  const clearTrivia = opts.trivia === null;
3219
3331
  return {
@@ -3229,9 +3341,13 @@ function parser(opts, root) {
3229
3341
  },
3230
3342
  parse(input, pos, _ctx) {
3231
3343
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3344
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3345
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
3232
3346
  const ctx = {
3233
3347
  ..._ctx,
3234
3348
  trackLines,
3349
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
3350
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3235
3351
  // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
3236
3352
  ...clearTrivia ? {
3237
3353
  trivia: void 0,
@@ -3249,11 +3365,10 @@ function parser(opts, root) {
3249
3365
  ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3250
3366
  };
3251
3367
  const result = root.parse(input, pos ?? 0, ctx);
3252
- if (trackLines) {
3253
- const idx = buildLineIndex(input);
3254
- return { ...result, span: annotateSpan(result.span, idx) };
3368
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3369
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
3255
3370
  }
3256
- return result;
3371
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3257
3372
  }
3258
3373
  };
3259
3374
  }
@@ -3357,7 +3472,7 @@ function leaf(root, fn) {
3357
3472
  }
3358
3473
 
3359
3474
  // src/version.ts
3360
- var PARSEMAN_VERSION = "0.40.0";
3475
+ var PARSEMAN_VERSION = "0.42.0";
3361
3476
 
3362
3477
  // src/cst/host-mode.ts
3363
3478
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -5041,7 +5156,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5041
5156
  let cur = pos;
5042
5157
  const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
5043
5158
  const probeCtx = {
5044
- trackLines: ctx.trackLines,
5159
+ trackLines: false,
5045
5160
  state: ctx.state,
5046
5161
  ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
5047
5162
  };
@@ -5054,6 +5169,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5054
5169
  while (cur < input.length) {
5055
5170
  const s = sentinel.parse(input, cur, probeCtx);
5056
5171
  if (s.ok) {
5172
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5057
5173
  emit2(cur);
5058
5174
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5059
5175
  }
@@ -5069,6 +5185,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
5069
5185
  if (!advanced) cur++;
5070
5186
  }
5071
5187
  if (orEOF) {
5188
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5072
5189
  emit2(cur);
5073
5190
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5074
5191
  }
@@ -6301,7 +6418,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6301
6418
  ` if (${m.end} > _e) {`,
6302
6419
  ` if (_cap) {`,
6303
6420
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6304
- ` 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})`,
6421
+ ` 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})`,
6305
6422
  ` }`,
6306
6423
  ` _e = ${m.end}`,
6307
6424
  ` continue`,
@@ -6357,7 +6474,7 @@ function analyzeTriviaFastPath(trivia2) {
6357
6474
  var CAP_RECORD = [
6358
6475
  ` if (_cap && _e > _pos) {`,
6359
6476
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6360
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6477
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6361
6478
  ` }`
6362
6479
  ].join("\n");
6363
6480
  function composeFastLoop(shapes) {
@@ -6417,7 +6534,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6417
6534
  ` const _ce = _e + _m${i}[0].length`,
6418
6535
  ` if (_cap) {`,
6419
6536
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6420
- ` 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})`,
6537
+ ` 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})`,
6421
6538
  ` }`,
6422
6539
  ` _e = _ce`,
6423
6540
  ` _matched = true`,
@@ -6455,7 +6572,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6455
6572
  ` const _ce = _r${i}.span.end`,
6456
6573
  ` if (_cap) {`,
6457
6574
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6458
- ` 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})`,
6575
+ ` 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})`,
6459
6576
  ` }`,
6460
6577
  ` _e = _ce`,
6461
6578
  ` _matched = true`,
@@ -6507,8 +6624,8 @@ function analyzeMkInlineBuild(def) {
6507
6624
  if (looseMkBuildRe(def.type).test(src)) return def.type;
6508
6625
  return null;
6509
6626
  }
6510
- function emitInlineMkNodeExpr(type, chV, rawV, pos, endVar, tlV) {
6511
- return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: { start: ${pos}, end: ${endVar} }, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
6627
+ function emitInlineMkNodeExpr(type, chV, rawV, spanExpr, tlV) {
6628
+ return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: ${spanExpr}, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
6512
6629
  }
6513
6630
 
6514
6631
  // src/compiler/inline-callback.ts
@@ -6541,6 +6658,9 @@ function transformFnSource(fn, fnSrc) {
6541
6658
  function replaceParam(body, param, valueVar) {
6542
6659
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6543
6660
  }
6661
+ function hasExplicitObjectKey(body, param) {
6662
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6663
+ }
6544
6664
  function stripForIdCheck(body) {
6545
6665
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6546
6666
  }
@@ -6583,10 +6703,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6583
6703
  const allowed = new Set(valueVars);
6584
6704
  for (let i = 0; i < slots.length; i++) {
6585
6705
  const name = slots[i];
6586
- if (name) body = replaceParam(body, name, valueVars[i]);
6706
+ if (!name) continue;
6707
+ if (hasExplicitObjectKey(body, name)) return null;
6708
+ body = replaceParam(body, name, valueVars[i]);
6587
6709
  }
6588
6710
  return hasFreeIdentifiers(body, allowed) ? null : body;
6589
6711
  }
6712
+ function isDispatchTailOnlyTransform(src) {
6713
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
6714
+ if (!m) return false;
6715
+ const slots = parseArrayDestructure(m[1], 2);
6716
+ const tail = slots[1];
6717
+ return tail !== null && m[2].trim() === tail;
6718
+ }
6590
6719
 
6591
6720
  // src/compiler/codegen.ts
6592
6721
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6678,6 +6807,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
6678
6807
  }
6679
6808
  }
6680
6809
  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 }";
6810
+ 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 }";
6811
+ 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] } }";
6681
6812
  var _loweringSink = null;
6682
6813
  function beginLoweringCapture() {
6683
6814
  _loweringSink = /* @__PURE__ */ new Set();
@@ -6826,14 +6957,46 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
6826
6957
  if (ctx.capAsTrivia) return [];
6827
6958
  const i = ind(ctx);
6828
6959
  const lf = v(ctx, "_lf");
6960
+ const spanExpr = emitSpanExpr(ctx, startExpr, endExpr);
6829
6961
  return [
6830
6962
  `${i}if (_ctx._cstLeaves || _ctx._cstRawChildren) {`,
6831
- `${i} const ${lf} = { _tag: 'leaf', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } }`,
6963
+ `${i} const ${lf} = { _tag: 'leaf', value: ${valExpr}, span: ${spanExpr} }`,
6832
6964
  `${i} if (_ctx._cstLeaves) _ctx._cstLeaves.push(${lf})`,
6833
6965
  `${i} if (_ctx._cstRawChildren) _ctx._cstRawChildren.push(${lf})`,
6834
6966
  `${i}}`
6835
6967
  ];
6836
6968
  }
6969
+ function emitSpanExpr(ctx, startExpr, endExpr) {
6970
+ if (!ctx.lineTracking) return `{ start: ${startExpr}, end: ${endExpr} }`;
6971
+ ctx.needsLineSpan = true;
6972
+ return `_spanLines(_ctx, ${startExpr}, ${endExpr})`;
6973
+ }
6974
+ function emitLineTrack(ctx, startExpr, endExpr) {
6975
+ if (!ctx.lineTracking) return [];
6976
+ ctx.needsLineTrack = true;
6977
+ return [`${ind(ctx)}_trackLines(_ctx, input, ${startExpr}, ${endExpr})`];
6978
+ }
6979
+ function emitLiteralLineTrack(ctx, startExpr, value) {
6980
+ if (!ctx.lineTracking) return [];
6981
+ const lineDeltas = [];
6982
+ for (let i = 0; i < value.length; i++) {
6983
+ if (value.charCodeAt(i) === 10) lineDeltas.push(i + 1);
6984
+ }
6985
+ if (lineDeltas.length === 0) return [];
6986
+ const fromV = v(ctx, "_ltFrom");
6987
+ const endExpr = value.length === 0 ? startExpr : `${startExpr} + ${value.length}`;
6988
+ return [
6989
+ `${ind(ctx)}const ${fromV} = _ctx._lineScannedTo ?? 0`,
6990
+ `${ind(ctx)}if (${endExpr} > ${fromV}) {`,
6991
+ `${ind(ctx)} for (let i = ${fromV}; i < ${startExpr}; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1)`,
6992
+ ...lineDeltas.map((delta) => {
6993
+ const lineStart = `${startExpr} + ${delta}`;
6994
+ return `${ind(ctx)} if (${lineStart} > ${fromV}) _ctx._lineStarts.push(${lineStart})`;
6995
+ }),
6996
+ `${ind(ctx)} _ctx._lineScannedTo = ${endExpr}`,
6997
+ `${ind(ctx)}}`
6998
+ ];
6999
+ }
6837
7000
  function ensureRegexDecl(ctx, source, flags) {
6838
7001
  const f = "y" + flags.replace(/[gy]/g, "");
6839
7002
  const key = `${source}/${f}`;
@@ -6845,6 +7008,17 @@ function ensureRegexDecl(ctx, source, flags) {
6845
7008
  }
6846
7009
  return rName;
6847
7010
  }
7011
+ function ensurePlainRegexDecl(ctx, source, flags) {
7012
+ const f = flags.replace(/[gy]/g, "");
7013
+ const key = `${source}/${f}`;
7014
+ let rName = ctx.regexMap.get(key);
7015
+ if (rName === void 0) {
7016
+ rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
7017
+ ctx.regexDecls.push(`const ${rName} = ${new RegExp(source, f).toString()}`);
7018
+ ctx.regexMap.set(key, rName);
7019
+ }
7020
+ return rName;
7021
+ }
6848
7022
  function ensureTriviaFn(ctx) {
6849
7023
  const trivia2 = ctx.activeTrivia;
6850
7024
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -6910,7 +7084,7 @@ function ensureTriviaFn(ctx) {
6910
7084
  ` }`,
6911
7085
  ` if (_cap && _e > _pos) {`,
6912
7086
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6913
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
7087
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6914
7088
  ` }`,
6915
7089
  ` return _e`,
6916
7090
  `}`
@@ -7207,6 +7381,7 @@ function emitLit(def, ctx, pos) {
7207
7381
  );
7208
7382
  }
7209
7383
  const endVar = len === 0 ? pos : `${pos} + ${len}`;
7384
+ stmts.push(...emitLiteralLineTrack(ctx, pos, value));
7210
7385
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7211
7386
  return { stmts, valueVar: vv, endVar };
7212
7387
  }
@@ -7286,7 +7461,7 @@ function emitKeywords(def, ctx, pos) {
7286
7461
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7287
7462
  return { stmts, valueVar: vv, endVar };
7288
7463
  }
7289
- function emitRegex(def, ctx, pos) {
7464
+ function emitRegex(def, ctx, pos, canMatchNewline = true) {
7290
7465
  const expectedStr = JSON.stringify(`/${def.source}/`);
7291
7466
  const shape = scanShapeFromRegex(def.source, def.flags);
7292
7467
  if (shape) {
@@ -7299,7 +7474,11 @@ function emitRegex(def, ctx, pos) {
7299
7474
  fresh: (prefix) => v(ctx, prefix)
7300
7475
  });
7301
7476
  if (scanned) {
7302
- const stmts2 = [...scanned.stmts, ...emitLeafCapture(ctx, vv2, pos, scanned.endVar)];
7477
+ const stmts2 = [
7478
+ ...scanned.stmts,
7479
+ ...canMatchNewline ? emitLineTrack(ctx, pos, scanned.endVar) : [],
7480
+ ...emitLeafCapture(ctx, vv2, pos, scanned.endVar)
7481
+ ];
7303
7482
  return { stmts: stmts2, valueVar: vv2, endVar: scanned.endVar };
7304
7483
  }
7305
7484
  }
@@ -7321,6 +7500,7 @@ function emitRegex(def, ctx, pos) {
7321
7500
  `${ind(ctx)}const ${vv} = ${mv}[0]`
7322
7501
  ];
7323
7502
  const endVar = `${pos} + ${vv}.length`;
7503
+ if (canMatchNewline) stmts.push(...emitLineTrack(ctx, pos, endVar));
7324
7504
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
7325
7505
  return { stmts, valueVar: vv, endVar };
7326
7506
  }
@@ -7358,7 +7538,8 @@ function emitSeqValues(def, ctx, pos) {
7358
7538
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7359
7539
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7360
7540
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7361
- `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`
7541
+ `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7542
+ ...emitLineTrack(ctx, curV, scanEndV)
7362
7543
  );
7363
7544
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7364
7545
  stmts.push(...r2.stmts);
@@ -7371,14 +7552,20 @@ function emitSeqValues(def, ctx, pos) {
7371
7552
  continue;
7372
7553
  } else {
7373
7554
  const trivFn = ensureTriviaFn(ctx);
7555
+ const markLog = v(ctx, "_mklg");
7374
7556
  const scanEndV = v(ctx, "_sne");
7375
- stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
7557
+ const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7558
+ stmts.push(
7559
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7560
+ `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7561
+ ...emitLineTrack(ctx, curV, scanEndV)
7562
+ );
7376
7563
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7377
7564
  stmts.push(...r2.stmts);
7378
7565
  const endAfterV = v(ctx, "_sea");
7379
7566
  stmts.push(
7380
7567
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7381
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
7568
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7382
7569
  );
7383
7570
  valueVars.push(r2.valueVar);
7384
7571
  continue;
@@ -7608,19 +7795,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7608
7795
  return false;
7609
7796
  }
7610
7797
  }
7611
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7798
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7612
7799
  if (parserUsesRouted2(def.selector)) {
7613
7800
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7614
7801
  }
7615
7802
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7616
7803
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7617
7804
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7618
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7619
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7620
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7621
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7622
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7623
- const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
7805
+ 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));
7806
+ const selectorLeafMark = selectorNeedsRollback ? v(ctx, "_dsl") : null;
7807
+ const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7808
+ const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7809
+ const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
7810
+ const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7811
+ const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7624
7812
  const selector = emit(def.selector, ctx, pos);
7625
7813
  const outV = v(ctx, "_dval");
7626
7814
  const outE = v(ctx, "_dend");
@@ -7645,13 +7833,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7645
7833
  stmts.push(head);
7646
7834
  ctx.indent++;
7647
7835
  const usesRouted = branchUsesRouted2(entry);
7648
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7836
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7837
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7649
7838
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7650
7839
  const errMark = mayError ? v(ctx, "_derr") : null;
7651
7840
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7652
- if (routedV) {
7841
+ if (usesRouted) {
7653
7842
  stmts.push(
7654
- `${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
7843
+ ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7655
7844
  ...selectorLeafMark ? [
7656
7845
  `${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}`
7657
7846
  ] : []
@@ -7659,7 +7848,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7659
7848
  }
7660
7849
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7661
7850
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
7851
+ const savedRoutedLocal = ctx.routedLocal;
7852
+ const savedNoHoist = ctx.noHoist;
7853
+ if (usesRouted && !needsRoutedContext) {
7854
+ ctx.routedLocal = { valueVar: selector.valueVar, startVar: pos, endVar: selector.endVar };
7855
+ ctx.noHoist = true;
7856
+ } else if (usesRouted) {
7857
+ ctx.routedLocal = void 0;
7858
+ }
7662
7859
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
7860
+ ctx.routedLocal = savedRoutedLocal;
7861
+ ctx.noHoist = savedNoHoist;
7663
7862
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7664
7863
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7665
7864
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7669,7 +7868,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7669
7868
  ...tail.stmts,
7670
7869
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7671
7870
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7672
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
7871
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7673
7872
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7674
7873
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7675
7874
  );
@@ -7684,7 +7883,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7684
7883
  }
7685
7884
  const emitMatcherTails = () => {
7686
7885
  for (const matcher of def.matchers ?? []) {
7687
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
7886
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7688
7887
  wroteBranch = true;
7689
7888
  }
7690
7889
  };
@@ -7709,10 +7908,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7709
7908
  }
7710
7909
  return parts.join(" && ");
7711
7910
  }
7712
- function emitDispatchMatcherCondition(valueVar, matcher) {
7911
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7713
7912
  if (matcher.kind === "matches") {
7714
7913
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7715
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
7914
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7716
7915
  }
7717
7916
  const text = matcher.value;
7718
7917
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -7915,6 +8114,28 @@ function emitsAsNamedFn(p, ctx) {
7915
8114
  const usage = ctx.lazyUsage;
7916
8115
  return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
7917
8116
  }
8117
+ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8118
+ if (seen.has(p)) return false;
8119
+ seen.add(p);
8120
+ if (p._def.tag === "lazy") {
8121
+ if (ctx.ruleNames?.has(p) || ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8122
+ const usage = ctx.lazyUsage;
8123
+ if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
8124
+ try {
8125
+ return routedNeedsContextBridge(p._def.thunk(), ctx, seen);
8126
+ } catch {
8127
+ return parserUsesRouted2(p);
8128
+ }
8129
+ }
8130
+ return parserUsesRouted2(p);
8131
+ }
8132
+ if (ctx.ruleNames?.has(p)) return parserUsesRouted2(p);
8133
+ if (ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8134
+ const d = p._def;
8135
+ if (d.tag === "dispatch") return false;
8136
+ if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8137
+ return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8138
+ }
7918
8139
  function armReplayInScope(arm, ctx) {
7919
8140
  let p = arm;
7920
8141
  for (; ; ) {
@@ -8037,14 +8258,15 @@ function emitMany(def, ctx, pos) {
8037
8258
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8038
8259
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8039
8260
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8040
- `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`
8261
+ `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8262
+ ...emitLineTrack(ctx, curV, npV)
8041
8263
  );
8042
8264
  itemPos = npV;
8043
8265
  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}; `;
8044
8266
  } else {
8045
8267
  const trivFn = ensureTriviaFn(ctx);
8046
8268
  const npV = v(ctx, "_np");
8047
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`);
8269
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, npV));
8048
8270
  itemPos = npV;
8049
8271
  }
8050
8272
  }
@@ -8165,15 +8387,16 @@ function emitSepBy(_p, def, ctx, pos) {
8165
8387
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8166
8388
  const postSepMarks = () => {
8167
8389
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8168
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg");
8390
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8169
8391
  return {
8170
8392
  decl: [
8171
8393
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8172
8394
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8173
8395
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8174
- `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`
8396
+ `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8397
+ `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8175
8398
  ],
8176
- 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}; `
8399
+ 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}; `
8177
8400
  };
8178
8401
  };
8179
8402
  if (rec) {
@@ -8212,23 +8435,26 @@ function emitSepBy(_p, def, ctx, pos) {
8212
8435
  const markTl = v(ctx, "_mktl");
8213
8436
  const markLog = v(ctx, "_mklg");
8214
8437
  const markLv = v(ctx, "_mklv");
8438
+ const markFld = v(ctx, "_mkf");
8215
8439
  const spV = v(ctx, "_sp");
8216
8440
  stmts.push(
8217
8441
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8218
8442
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8219
8443
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8220
8444
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8221
- `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8445
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8446
+ `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8447
+ ...emitLineTrack(ctx, curV, spV)
8222
8448
  );
8223
8449
  sepAtPos = spV;
8224
- 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}; `;
8450
+ 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}; `;
8225
8451
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8226
8452
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8227
8453
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8228
8454
  const post = postSepMarks();
8229
8455
  stmts.push(...post.decl);
8230
8456
  const npV = v(ctx, "_np");
8231
- stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
8457
+ stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`, ...emitLineTrack(ctx, sepEnd, npV));
8232
8458
  const next = emitFallible(def.parser, ctx, npV, true);
8233
8459
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8234
8460
  stmts.push(
@@ -8240,13 +8466,13 @@ function emitSepBy(_p, def, ctx, pos) {
8240
8466
  } else {
8241
8467
  const trivFn = ensureTriviaFn(ctx);
8242
8468
  const spV = v(ctx, "_sp");
8243
- stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
8469
+ stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, spV));
8244
8470
  sepAtPos = spV;
8245
8471
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8246
8472
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8247
8473
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8248
8474
  const npV = v(ctx, "_np");
8249
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
8475
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`, ...emitLineTrack(ctx, sepEnd, npV));
8250
8476
  const next = emitFallible(def.parser, ctx, npV, true);
8251
8477
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8252
8478
  stmts.push(
@@ -8259,16 +8485,18 @@ function emitSepBy(_p, def, ctx, pos) {
8259
8485
  } else {
8260
8486
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8261
8487
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8488
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8262
8489
  if (markLv) {
8263
8490
  stmts.push(
8264
8491
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8265
- `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
8492
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8493
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`
8266
8494
  );
8267
8495
  }
8268
8496
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8269
8497
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8270
8498
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8271
- 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}; ` : "";
8499
+ 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}; ` : "";
8272
8500
  const post = postSepMarks();
8273
8501
  stmts.push(...post.decl);
8274
8502
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8331,6 +8559,7 @@ function emitScanTo(def, ctx, pos) {
8331
8559
  }
8332
8560
  const valV = v(ctx);
8333
8561
  stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
8562
+ stmts.push(...emitLineTrack(ctx, pos, curV));
8334
8563
  if (ctx.capturing) {
8335
8564
  const cap = reindentStmts(emitLeafCapture(ctx, valV, pos, curV), ctx.indent + 1);
8336
8565
  stmts.push(`${ind(ctx)}if (${curV} > ${pos}) {`, ...cap, `${ind(ctx)}}`);
@@ -8338,7 +8567,7 @@ function emitScanTo(def, ctx, pos) {
8338
8567
  return { stmts, valueVar: valV, endVar: curV };
8339
8568
  }
8340
8569
  function emitNot(def, ctx, pos) {
8341
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8570
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8342
8571
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8343
8572
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8344
8573
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8377,6 +8606,17 @@ function emitPeek(def, ctx, pos) {
8377
8606
  };
8378
8607
  }
8379
8608
  function emitRouted(ctx, pos) {
8609
+ const local = ctx.routedLocal;
8610
+ if (local !== void 0) {
8611
+ return {
8612
+ stmts: [
8613
+ ...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
8614
+ ...emitLeafCapture(ctx, local.valueVar, local.startVar, local.endVar)
8615
+ ],
8616
+ valueVar: local.valueVar,
8617
+ endVar: local.endVar
8618
+ };
8619
+ }
8380
8620
  const item = v(ctx, "_rt");
8381
8621
  return {
8382
8622
  stmts: [
@@ -8463,7 +8703,7 @@ function tokenNullableRegex(def) {
8463
8703
  }
8464
8704
  function emitToken(def, ctx, pos) {
8465
8705
  const lowered = tokenNullableRegex(def);
8466
- if (lowered) return emitRegex(lowered, ctx, pos);
8706
+ if (lowered) return emitRegex(lowered, ctx, pos, def.parser._meta.canMatchNewline);
8467
8707
  const savedTrivia = ctx.activeTrivia;
8468
8708
  const savedKindLabels = ctx.triviaKindLabels;
8469
8709
  ctx.activeTrivia = void 0;
@@ -8613,7 +8853,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8613
8853
  stmts.push(...innerStmts);
8614
8854
  if (def.trailingTrivia === true && ctx.activeTrivia) {
8615
8855
  const triviaFn = ensureTriviaFn(ctx);
8616
- stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
8856
+ stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`, ...emitLineTrack(ctx, innerEndVar, endVar));
8617
8857
  }
8618
8858
  if (sf && fArr) {
8619
8859
  stmts.push(`${i}const ${fArr} = _ctx._fields`);
@@ -8653,8 +8893,11 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8653
8893
  );
8654
8894
  }
8655
8895
  const ndV = v(ctx, "_nd");
8656
- 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})`;
8657
- const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8896
+ const nodeSpanExpr = emitSpanExpr(ctx, pos, endVar);
8897
+ const nodeSpanV = ctx.lineTracking ? v(ctx, "_nspan") : nodeSpanExpr;
8898
+ if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
8899
+ 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})`;
8900
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
8658
8901
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8659
8902
  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;
8660
8903
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
@@ -8664,7 +8907,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8664
8907
  `${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
8665
8908
  `${i}if (!(${profileRecognizer})) {`,
8666
8909
  `${i} if (${sc}) ${sc}.push(${ndV})`,
8667
- `${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} } })`,
8910
+ `${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} })`,
8668
8911
  `${i}}`
8669
8912
  );
8670
8913
  return { stmts, valueVar: ndV, endVar };
@@ -8680,7 +8923,8 @@ function emitRuntimeFallback(parser2, ctx, pos) {
8680
8923
  `${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
8681
8924
  ...emitIfFail(ctx, `!${rv}.ok`, failStmt),
8682
8925
  `${ind(ctx)}const ${vv} = ${rv}.value`,
8683
- `${ind(ctx)}const ${ev} = ${rv}.span.end`
8926
+ `${ind(ctx)}const ${ev} = ${rv}.span.end`,
8927
+ ...parser2._meta.canMatchNewline ? emitLineTrack(ctx, pos, ev) : []
8684
8928
  ];
8685
8929
  return { stmts, valueVar: vv, endVar: ev };
8686
8930
  }
@@ -8746,7 +8990,8 @@ function emitRecover(def, ctx, pos) {
8746
8990
  `${ind0} if (${sentOk}) break`,
8747
8991
  `${ind0} ${scanV}++`,
8748
8992
  `${ind0} }`,
8749
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
8993
+ ...emitLineTrack(ctx, pos, scanV).map((s) => `${ind0} ${s.trim()}`),
8994
+ `${ind0} const ${errV} = { _tag: 'parseError', span: ${emitSpanExpr(ctx, pos, scanV)}, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
8750
8995
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
8751
8996
  `${ind0} ${valVar} = ${errV}`,
8752
8997
  `${ind0} ${endVar} = ${scanV}`,
@@ -8762,7 +9007,7 @@ function emitExpect(def, ctx, pos) {
8762
9007
  const stmts = [
8763
9008
  ...innerStmts,
8764
9009
  `${ind0}if (!${okVar}) {`,
8765
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
9010
+ `${ind0} const ${errV} = { _tag: 'parseError', span: ${emitSpanExpr(ctx, pos, pos)}, expected: ${JSON.stringify(def.expected)} }`,
8766
9011
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
8767
9012
  // Embed the missing-token error as a `parseError` CST child, mirroring the
8768
9013
  // interpreter (expect.ts) and the list-recovery emit sites — guarded on
@@ -8852,7 +9097,7 @@ function emitDispatch(p, ctx, pos) {
8852
9097
  case "literal":
8853
9098
  return emitLit(def, ctx, pos);
8854
9099
  case "regex":
8855
- return emitRegex(def, ctx, pos);
9100
+ return emitRegex(def, ctx, pos, p._meta.canMatchNewline);
8856
9101
  case "keywords":
8857
9102
  return emitKeywords(def, ctx, pos);
8858
9103
  case "sequence":
@@ -8872,6 +9117,9 @@ function emitDispatch(p, ctx, pos) {
8872
9117
  return emitSepBy(p, def, ctx, pos);
8873
9118
  case "transform": {
8874
9119
  const fnSrc = transformFnSource(def.fn, def.fnSrc);
9120
+ if (fnSrc && def.parser._def.tag === "dispatch" && isDispatchTailOnlyTransform(fnSrc)) {
9121
+ return emitDispatchCombinator(def.parser, def.parser._def, ctx, pos, "tail");
9122
+ }
8875
9123
  if (fnSrc && def.parser._def.tag === "sequence") {
8876
9124
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8877
9125
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9099,6 +9347,20 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
9099
9347
  return false;
9100
9348
  }
9101
9349
  }
9350
+ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9351
+ if (seen.has(p)) return false;
9352
+ seen.add(p);
9353
+ const d = p._def;
9354
+ if (d.tag === "grammar" && d.trackLines) return true;
9355
+ if (d.tag === "lazy") {
9356
+ try {
9357
+ return hasLineTrackingDef(d.thunk(), seen);
9358
+ } catch {
9359
+ return false;
9360
+ }
9361
+ }
9362
+ return childrenOf2(d).some((child) => hasLineTrackingDef(child, seen));
9363
+ }
9102
9364
  function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9103
9365
  if (seen.has(p)) return false;
9104
9366
  seen.add(p);
@@ -9466,6 +9728,7 @@ function compile(combinator, mapFnSources, opts) {
9466
9728
  capturing: hasNodeDef(combinator),
9467
9729
  recovery: opts?.recovery ?? false,
9468
9730
  hostMode: opts?.hostMode ?? grammarHostMode ?? "ast",
9731
+ lineTracking: opts?.trackLines === true || hasLineTrackingDef(combinator),
9469
9732
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9470
9733
  lazyUsage: analyzeLazyUsage(combinator),
9471
9734
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9489,9 +9752,13 @@ function compile(combinator, mapFnSources, opts) {
9489
9752
  const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
9490
9753
  const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
9491
9754
  const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
9755
+ const lineTrackDecls = ctx.needsLineTrack ? [LINE_TRACK_DECL] : [];
9756
+ const lineSpanDecls = ctx.needsLineSpan ? [LINE_SPAN_DECL] : [];
9492
9757
  const source = [
9493
9758
  ...emptyTlDecls,
9494
9759
  ...hostReadsDecls,
9760
+ ...lineTrackDecls,
9761
+ ...lineSpanDecls,
9495
9762
  ...ctx.regexDecls,
9496
9763
  ...ctx.expectedDecls,
9497
9764
  "",
@@ -9504,6 +9771,8 @@ function compile(combinator, mapFnSources, opts) {
9504
9771
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
9505
9772
  ...emptyTlDecls,
9506
9773
  ...hostReadsDecls,
9774
+ ...lineTrackDecls,
9775
+ ...lineSpanDecls,
9507
9776
  ...ctx.regexDecls,
9508
9777
  ...ctx.expectedDecls,
9509
9778
  ...namedPrelude,
@@ -9522,6 +9791,25 @@ function compile(combinator, mapFnSources, opts) {
9522
9791
  trackLines: false,
9523
9792
  ...ctx.triviaKindLabels ? { triviaKindLabels: ctx.triviaKindLabels } : {}
9524
9793
  };
9794
+ const annotateWithTrackedLines = (result, lineStarts) => {
9795
+ const index = normalizeLineIndex({ lineStarts });
9796
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
9797
+ const errors = annotated.errors;
9798
+ if (errors) {
9799
+ ;
9800
+ annotated.errors = errors.map((error) => ({
9801
+ ...error,
9802
+ span: annotateSpan(error.span, index)
9803
+ }));
9804
+ }
9805
+ return annotated;
9806
+ };
9807
+ const trackedCtx = (base, input, pos) => {
9808
+ if (!ctx.lineTracking) return base;
9809
+ const lineIndex = { lineStarts: [0] };
9810
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
9811
+ return { ...base, trackLines: true, _lineStarts: lineIndex.lineStarts, _lineScannedTo: pos };
9812
+ };
9525
9813
  const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
9526
9814
  const effectiveSources = mapFnSources ?? derivedSrcs;
9527
9815
  const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
@@ -9529,17 +9817,46 @@ function compile(combinator, mapFnSources, opts) {
9529
9817
  const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
9530
9818
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
9531
9819
  const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
9532
- return {
9820
+ const compiledMeta = {
9533
9821
  source,
9534
9822
  inlineExpression,
9535
9823
  ...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
9536
- ...gatingReport === void 0 ? {} : { gating: gatingReport },
9824
+ ...gatingReport === void 0 ? {} : { gating: gatingReport }
9825
+ };
9826
+ if (!ctx.lineTracking) {
9827
+ return {
9828
+ ...compiledMeta,
9829
+ parse(input, pos = 0) {
9830
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
9831
+ },
9832
+ parseWithContext(input, parseCtx, pos = 0) {
9833
+ assertHostModeCompatible(ctx.hostMode ?? "ast", parseCtx.build, !!ctx.hostBranchElided);
9834
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9835
+ },
9836
+ // Note: collects expect() errors via _errors. Unlike interpreter
9837
+ // parse({recover:true}) it does NOT populate furthestFail — the compiled path
9838
+ // inlines failures for throughput and deliberately skips _probe bookkeeping.
9839
+ // Callers wanting a furthest-position diagnostic detect unconsumed input
9840
+ // (span.end < input.length) instead, which is mode-agnostic.
9841
+ parseWithErrors(input, pos = 0) {
9842
+ const errors = [];
9843
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
9844
+ return { ...result, errors };
9845
+ }
9846
+ };
9847
+ }
9848
+ return {
9849
+ ...compiledMeta,
9537
9850
  parse(input, pos = 0) {
9538
- return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
9851
+ const parseCtx = trackedCtx(defaultCtx, input, pos);
9852
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9853
+ return annotateWithTrackedLines(result, parseCtx._lineStarts);
9539
9854
  },
9540
9855
  parseWithContext(input, parseCtx, pos = 0) {
9541
9856
  assertHostModeCompatible(ctx.hostMode ?? "ast", parseCtx.build, !!ctx.hostBranchElided);
9542
- return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
9857
+ const activeCtx = trackedCtx(parseCtx, input, pos);
9858
+ const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, activeCtx);
9859
+ return activeCtx.trackLines ? annotateWithTrackedLines(result, activeCtx._lineStarts) : result;
9543
9860
  },
9544
9861
  // Note: collects expect() errors via _errors. Unlike interpreter
9545
9862
  // parse({recover:true}) it does NOT populate furthestFail — the compiled path
@@ -9548,8 +9865,9 @@ function compile(combinator, mapFnSources, opts) {
9548
9865
  // (span.end < input.length) instead, which is mode-agnostic.
9549
9866
  parseWithErrors(input, pos = 0) {
9550
9867
  const errors = [];
9551
- const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
9552
- return { ...result, errors };
9868
+ const parseCtx = trackedCtx({ ...defaultCtx, _errors: errors }, input, pos);
9869
+ const result = { ...fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx), errors };
9870
+ return annotateWithTrackedLines(result, parseCtx._lineStarts);
9553
9871
  }
9554
9872
  };
9555
9873
  }
@@ -9561,8 +9879,8 @@ function assertRuleName(name) {
9561
9879
  );
9562
9880
  }
9563
9881
  }
9564
- function publicRuleWrapperSource(rule, fnSource) {
9565
- const labels = rule._meta.triviaKindLabels;
9882
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9883
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9566
9884
  if (labels === void 0) return fnSource;
9567
9885
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9568
9886
  }
@@ -9633,6 +9951,8 @@ function compileRuleMap(ruleMap, opts) {
9633
9951
  const hoistedDecls = [
9634
9952
  ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
9635
9953
  ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "",
9954
+ ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "",
9955
+ ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "",
9636
9956
  ...ctx.regexDecls.map((d) => ` ${d}`),
9637
9957
  ...ctx.expectedDecls.map((d) => ` ${d}`),
9638
9958
  mfDecl,
@@ -9670,7 +9990,7 @@ function compileRuleMap(ruleMap, opts) {
9670
9990
  return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
9671
9991
  };
9672
9992
  const objBody = perEntry.map(({ key, rule, r }) => {
9673
- const src = publicRuleWrapperSource(rule, entryFnText(r, rule));
9993
+ const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels);
9674
9994
  return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
9675
9995
  }).join(",\n");
9676
9996
  const replacement = [
@@ -9857,7 +10177,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9857
10177
  ...r.stmts,
9858
10178
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9859
10179
  `}`
9860
- ].join("\n")));
10180
+ ].join("\n"), ctx.triviaKindLabels));
9861
10181
  }
9862
10182
  const firstSets = /* @__PURE__ */ new Map();
9863
10183
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -9962,12 +10282,16 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootR
9962
10282
  const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
9963
10283
  const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
9964
10284
  const hostReadsDecl = ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "";
9965
- const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl;
10285
+ const lineTrackDecl = ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "";
10286
+ const lineSpanDecl = ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "";
10287
+ const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!lineTrackDecl || !!lineSpanDecl;
9966
10288
  if (!needsWrapper) return innerFn;
9967
10289
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
9968
10290
  const hoistedDecls = [
9969
10291
  emptyTlDecl,
9970
10292
  hostReadsDecl,
10293
+ lineTrackDecl,
10294
+ lineSpanDecl,
9971
10295
  ...ctx.regexDecls.map((d) => ` ${d}`),
9972
10296
  ...ctx.expectedDecls.map((d) => ` ${d}`),
9973
10297
  mfDecl,
@@ -10506,7 +10830,7 @@ function normalizeCstCollapse(collapse) {
10506
10830
  return typeof collapse === "function" ? collapse : void 0;
10507
10831
  }
10508
10832
  function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
10509
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
10833
+ return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
10510
10834
  }
10511
10835
  function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
10512
10836
  if (typeof typeOrOptions === "string") {
@@ -10710,6 +11034,10 @@ function gate(predicate) {
10710
11034
  };
10711
11035
  }
10712
11036
 
11037
+ // src/cst/trivia-entries.ts
11038
+ var EMPTY_INDICES = Object.freeze([]);
11039
+ var EMPTY_GAPS = Object.freeze([]);
11040
+
10713
11041
  // src/cst/offset-model.ts
10714
11042
  var { isFinite } = Number;
10715
11043