parseman 0.41.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 (46) hide show
  1. package/dist/combinators/expect.d.ts.map +1 -1
  2. package/dist/combinators/grammar.d.ts.map +1 -1
  3. package/dist/combinators/literal.d.ts.map +1 -1
  4. package/dist/combinators/node.d.ts.map +1 -1
  5. package/dist/combinators/regex.d.ts.map +1 -1
  6. package/dist/combinators/scanTo.d.ts.map +1 -1
  7. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  8. package/dist/compiler/codegen.d.ts +3 -0
  9. package/dist/compiler/codegen.d.ts.map +1 -1
  10. package/dist/compiler/inline-build.d.ts +1 -1
  11. package/dist/compiler/inline-build.d.ts.map +1 -1
  12. package/dist/compiler/line-index.d.ts +1 -15
  13. package/dist/compiler/line-index.d.ts.map +1 -1
  14. package/dist/cst/capture-buffer.d.ts.map +1 -1
  15. package/dist/index.cjs +364 -99
  16. package/dist/index.cjs.map +4 -4
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +364 -99
  20. package/dist/index.js.map +4 -4
  21. package/dist/language-service/index.cjs +48 -2
  22. package/dist/language-service/index.cjs.map +3 -3
  23. package/dist/language-service/index.js +48 -2
  24. package/dist/language-service/index.js.map +3 -3
  25. package/dist/line-index.d.ts +41 -0
  26. package/dist/line-index.d.ts.map +1 -0
  27. package/dist/plugin/index.cjs +334 -93
  28. package/dist/plugin/index.cjs.map +4 -4
  29. package/dist/plugin/index.js +334 -93
  30. package/dist/plugin/index.js.map +4 -4
  31. package/dist/recovery/scan.d.ts.map +1 -1
  32. package/dist/regex/first-set.d.ts.map +1 -1
  33. package/dist/run/index.cjs +47 -1
  34. package/dist/run/index.cjs.map +3 -3
  35. package/dist/run/index.d.ts +3 -2
  36. package/dist/run/index.d.ts.map +1 -1
  37. package/dist/run/index.js +47 -1
  38. package/dist/run/index.js.map +3 -3
  39. package/dist/spec/index.cjs +170 -50
  40. package/dist/spec/index.cjs.map +4 -4
  41. package/dist/spec/index.js +170 -50
  42. package/dist/spec/index.js.map +4 -4
  43. package/dist/types.d.ts +12 -0
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/version.d.ts +1 -1
  46. package/package.json +1 -1
@@ -477,6 +477,65 @@ function rules(a, b) {
477
477
  return cache;
478
478
  }
479
479
 
480
+ // src/line-index.ts
481
+ function createLineIndex() {
482
+ return { lineStarts: [0] };
483
+ }
484
+ function recordLineRange(index, input, start, end) {
485
+ const lineStarts = index.lineStarts;
486
+ for (let i = start; i < end; i++) {
487
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
488
+ }
489
+ }
490
+ function recordLineRangeFromContext(ctx, input, _startHint, end) {
491
+ if (!ctx.trackLines) return;
492
+ const from = ctx._lineScannedTo ?? 0;
493
+ if (end <= from) return;
494
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
495
+ if (!index) return;
496
+ recordLineRange(index, input, from, end);
497
+ ctx._lineScannedTo = end;
498
+ }
499
+ function normalizeLineIndex(index) {
500
+ const starts = index.lineStarts;
501
+ starts.sort((a, b) => a - b);
502
+ let write = 0;
503
+ for (let read = 0; read < starts.length; read++) {
504
+ const value = starts[read];
505
+ if (write === 0 || starts[write - 1] !== value) starts[write++] = value;
506
+ }
507
+ starts.length = write;
508
+ if (starts.length === 0 || starts[0] !== 0) starts.unshift(0);
509
+ return index;
510
+ }
511
+ function offsetToLineCol(index, offset) {
512
+ const { lineStarts } = index;
513
+ let lo = 0;
514
+ let hi = lineStarts.length - 1;
515
+ while (lo < hi) {
516
+ const mid = lo + hi + 1 >> 1;
517
+ if (lineStarts[mid] <= offset) lo = mid;
518
+ else hi = mid - 1;
519
+ }
520
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
521
+ }
522
+ function annotateSpan(span, index) {
523
+ const s = offsetToLineCol(index, span.start);
524
+ const e = offsetToLineCol(index, span.end);
525
+ return {
526
+ ...span,
527
+ startLine: s.line,
528
+ startColumn: s.col,
529
+ endLine: e.line,
530
+ endColumn: e.col
531
+ };
532
+ }
533
+ function annotateSpanFromLineContext(span, ctx) {
534
+ if (!ctx.trackLines) return span;
535
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
536
+ return index ? annotateSpan(span, index) : span;
537
+ }
538
+
480
539
  // src/cst/capture-buffer.ts
481
540
  var EMPTY = [];
482
541
  var EMPTY_TL = [];
@@ -518,7 +577,12 @@ function endCstNodeCapture(ctx, saved) {
518
577
  return materialized;
519
578
  }
520
579
  function pushCstLeaf(ctx, leaf2) {
521
- pushCstChild(ctx, leaf2, leaf2);
580
+ if (!ctx.trackLines) {
581
+ pushCstChild(ctx, leaf2, leaf2);
582
+ return;
583
+ }
584
+ const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
585
+ pushCstChild(ctx, annotated, annotated);
522
586
  }
523
587
  function pushCstChild(ctx, built, rawEntry) {
524
588
  const b = ctx._cstBuf;
@@ -708,7 +772,9 @@ function firstSetSentinel(fs) {
708
772
  function recoverScan(input, from, ctx, sync, expected) {
709
773
  let scanPos = from;
710
774
  while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
711
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
775
+ const span = { start: from, end: scanPos };
776
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
777
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
712
778
  ctx._errors?.push(error);
713
779
  return { error, end: scanPos };
714
780
  }
@@ -810,7 +876,8 @@ function expect(combinator, label2) {
810
876
  parse(input, pos, ctx) {
811
877
  const result = combinator.parse(input, pos, ctx);
812
878
  if (result.ok) return result;
813
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
879
+ const span = { start: pos, end: pos };
880
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
814
881
  ctx._errors?.push(error);
815
882
  if (ctx._tolerant) captureError(ctx, error);
816
883
  return { ok: true, value: error, span: { start: pos, end: pos } };
@@ -1150,6 +1217,7 @@ function literal(value, opts = {}) {
1150
1217
  canMatchNewline: value.includes("\n"),
1151
1218
  isTrivia: false
1152
1219
  };
1220
+ const canMatchNewline = meta.canMatchNewline;
1153
1221
  if (caseInsensitive) {
1154
1222
  const upper = value.toUpperCase();
1155
1223
  const lower = value.toLowerCase();
@@ -1166,6 +1234,7 @@ function literal(value, opts = {}) {
1166
1234
  return function parse2(input, pos, ctx) {
1167
1235
  if (input.charCodeAt(pos) === code) {
1168
1236
  const span = { start: pos, end: pos + 1 };
1237
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
1169
1238
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1170
1239
  return { ok: true, value, span };
1171
1240
  }
@@ -1179,6 +1248,7 @@ function literal(value, opts = {}) {
1179
1248
  const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
1180
1249
  if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
1181
1250
  const span = { start: pos, end };
1251
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
1182
1252
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
1183
1253
  return { ok: true, value: matchedValue, span };
1184
1254
  }
@@ -1343,6 +1413,7 @@ function regex(pattern, flags = "") {
1343
1413
  if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
1344
1414
  const value = input.slice(pos, scanEnd);
1345
1415
  const span2 = { start: pos, end: scanEnd };
1416
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
1346
1417
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
1347
1418
  return { ok: true, value, span: span2 };
1348
1419
  }
@@ -1352,6 +1423,7 @@ function regex(pattern, flags = "") {
1352
1423
  return failAt(ctx, [`/${source}/`], pos);
1353
1424
  }
1354
1425
  const span = { start: pos, end: pos + m[0].length };
1426
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
1355
1427
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
1356
1428
  return { ok: true, value: m[0], span };
1357
1429
  }
@@ -1502,6 +1574,18 @@ function rollbackTrivia(ctx, mark) {
1502
1574
  rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1503
1575
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1504
1576
  }
1577
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1578
+ const probeCtx = {
1579
+ trackLines: ctx.trackLines,
1580
+ state: ctx.state,
1581
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1582
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1583
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1584
+ };
1585
+ const result = triviaP.parse(input, cur, probeCtx);
1586
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1587
+ return result;
1588
+ }
1505
1589
  function saveLookaheadMark(ctx) {
1506
1590
  return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1507
1591
  }
@@ -1524,13 +1608,29 @@ function scanWithLabels(input, cur, ctx) {
1524
1608
  function advanceTrivia(input, cur, ctx) {
1525
1609
  const triviaP = ctx.trivia;
1526
1610
  if (!triviaP) return cur;
1611
+ if (!ctx.trackLines) {
1612
+ const fast2 = fastTriviaScanner(triviaP);
1613
+ if (fast2) return fast2(input, cur);
1614
+ if (ctx.triviaKindLabels) {
1615
+ const scan = scanWithLabels(input, cur, ctx);
1616
+ return scan.end;
1617
+ }
1618
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1619
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1620
+ }
1621
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1527
1622
  const fast = fastTriviaScanner(triviaP);
1528
- if (fast) return fast(input, cur);
1623
+ if (fast) {
1624
+ const end = fast(input, cur);
1625
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1626
+ return end;
1627
+ }
1529
1628
  if (ctx.triviaKindLabels) {
1530
1629
  const scan = scanWithLabels(input, cur, ctx);
1630
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1531
1631
  return scan.end;
1532
1632
  }
1533
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1633
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1534
1634
  return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1535
1635
  }
1536
1636
  function scanTrivia(input, cur, ctx) {
@@ -1538,18 +1638,46 @@ function scanTrivia(input, cur, ctx) {
1538
1638
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1539
1639
  const log = ctx._triviaLog;
1540
1640
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1641
+ if (!ctx.trackLines) {
1642
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1643
+ if (fast2 && log === void 0 && !captureTl) {
1644
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1645
+ }
1646
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1647
+ return scanWithLabels(input, cur, ctx);
1648
+ }
1649
+ if (log !== void 0 || captureTl) {
1650
+ const tr3 = triviaP.parse(input, cur, {
1651
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1652
+ state: ctx.state
1653
+ });
1654
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1655
+ const end = tr3.span.end;
1656
+ return {
1657
+ end,
1658
+ commit: () => {
1659
+ pushTriviaLogEntry(ctx, cur, end);
1660
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1661
+ }
1662
+ };
1663
+ }
1664
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1665
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1666
+ }
1667
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1541
1668
  const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1542
1669
  if (fast && log === void 0 && !captureTl) {
1543
- return { end: fast(input, cur), commit: NOOP_COMMIT };
1670
+ const end = fast(input, cur);
1671
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1672
+ return { end, commit: NOOP_COMMIT };
1544
1673
  }
1545
1674
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1546
- return scanWithLabels(input, cur, ctx);
1675
+ const scan = scanWithLabels(input, cur, ctx);
1676
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1677
+ return scan;
1547
1678
  }
1548
1679
  if (log !== void 0 || captureTl) {
1549
- const tr2 = triviaP.parse(input, cur, {
1550
- trackLines: log !== void 0 ? false : ctx.trackLines,
1551
- state: ctx.state
1552
- });
1680
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1553
1681
  if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1554
1682
  const end = tr2.span.end;
1555
1683
  return {
@@ -1560,7 +1688,7 @@ function scanTrivia(input, cur, ctx) {
1560
1688
  }
1561
1689
  };
1562
1690
  }
1563
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1691
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1564
1692
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1565
1693
  }
1566
1694
  function consumeTrivia(input, cur, ctx) {
@@ -2213,7 +2341,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2213
2341
  let cur = pos;
2214
2342
  const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
2215
2343
  const probeCtx = {
2216
- trackLines: ctx.trackLines,
2344
+ trackLines: false,
2217
2345
  state: ctx.state,
2218
2346
  ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
2219
2347
  };
@@ -2226,6 +2354,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2226
2354
  while (cur < input.length) {
2227
2355
  const s = sentinel.parse(input, cur, probeCtx);
2228
2356
  if (s.ok) {
2357
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
2229
2358
  emit(cur);
2230
2359
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2231
2360
  }
@@ -2241,6 +2370,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2241
2370
  if (!advanced) cur++;
2242
2371
  }
2243
2372
  if (orEOF) {
2373
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
2244
2374
  emit(cur);
2245
2375
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2246
2376
  }
@@ -2850,49 +2980,36 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2850
2980
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2851
2981
  const nodeType = def.type ?? missingInferredType();
2852
2982
  const cstOutput = cstOutputHost(ctx.build);
2983
+ const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
2853
2984
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2854
- const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, hostState) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, hostState) : build(children, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
2855
- 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 };
2985
+ const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : build(children, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, 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 };
2986
+ 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 };
2856
2987
  if (saved.buf !== void 0 || saved.ch !== void 0) {
2857
2988
  pushCstChild(ctx, built, rawEntry);
2858
2989
  }
2859
- return { ok: true, value: built, span: r.span };
2990
+ return { ok: true, value: built, span };
2860
2991
  }
2861
2992
  };
2862
2993
  }
2863
2994
 
2864
- // src/compiler/line-index.ts
2865
- function buildLineIndex(input) {
2866
- const lineStarts = [0];
2867
- for (let i = 0; i < input.length; i++) {
2868
- if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
2869
- }
2870
- return { lineStarts };
2871
- }
2872
- function offsetToLineCol(index, offset) {
2873
- const { lineStarts } = index;
2874
- let lo = 0;
2875
- let hi = lineStarts.length - 1;
2876
- while (lo < hi) {
2877
- const mid = lo + hi + 1 >> 1;
2878
- if (lineStarts[mid] <= offset) lo = mid;
2879
- else hi = mid - 1;
2995
+ // src/combinators/grammar.ts
2996
+ function annotateResultLines(result, index) {
2997
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
2998
+ const errors = annotated.errors;
2999
+ if (errors) {
3000
+ ;
3001
+ annotated.errors = errors.map((error) => ({
3002
+ ...error,
3003
+ span: annotateSpan(error.span, index)
3004
+ }));
2880
3005
  }
2881
- return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
3006
+ return annotated;
2882
3007
  }
2883
- function annotateSpan(span, index) {
2884
- const s = offsetToLineCol(index, span.start);
2885
- const e = offsetToLineCol(index, span.end);
2886
- return {
2887
- ...span,
2888
- startLine: s.line,
2889
- startColumn: s.col,
2890
- endLine: e.line,
2891
- endColumn: e.col
2892
- };
3008
+ function createParseLineContext(input, pos) {
3009
+ const lineIndex = createLineIndex();
3010
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3011
+ return { lineIndex, lineScannedTo: pos };
2893
3012
  }
2894
-
2895
- // src/combinators/grammar.ts
2896
3013
  function parser(opts, root) {
2897
3014
  const clearTrivia = opts.trivia === null;
2898
3015
  return {
@@ -2908,9 +3025,13 @@ function parser(opts, root) {
2908
3025
  },
2909
3026
  parse(input, pos, _ctx) {
2910
3027
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3028
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3029
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
2911
3030
  const ctx = {
2912
3031
  ..._ctx,
2913
3032
  trackLines,
3033
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
3034
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
2914
3035
  // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2915
3036
  ...clearTrivia ? {
2916
3037
  trivia: void 0,
@@ -2928,11 +3049,10 @@ function parser(opts, root) {
2928
3049
  ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2929
3050
  };
2930
3051
  const result = root.parse(input, pos ?? 0, ctx);
2931
- if (trackLines) {
2932
- const idx = buildLineIndex(input);
2933
- return { ...result, span: annotateSpan(result.span, idx) };
3052
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3053
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
2934
3054
  }
2935
- return result;
3055
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
2936
3056
  }
2937
3057
  };
2938
3058
  }
@@ -3220,7 +3340,7 @@ function normalizeCstCollapse(collapse) {
3220
3340
  return typeof collapse === "function" ? collapse : void 0;
3221
3341
  }
3222
3342
  function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
3223
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
3343
+ return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children] };
3224
3344
  }
3225
3345
  function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
3226
3346
  if (typeof typeOrOptions === "string") {