parseman 0.41.0 → 0.42.1

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 (51) 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/parser.d.ts +6 -0
  6. package/dist/combinators/parser.d.ts.map +1 -1
  7. package/dist/combinators/regex.d.ts.map +1 -1
  8. package/dist/combinators/scanTo.d.ts.map +1 -1
  9. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  10. package/dist/compiler/codegen.d.ts +5 -0
  11. package/dist/compiler/codegen.d.ts.map +1 -1
  12. package/dist/compiler/inline-build.d.ts +1 -1
  13. package/dist/compiler/inline-build.d.ts.map +1 -1
  14. package/dist/compiler/line-index.d.ts +1 -15
  15. package/dist/compiler/line-index.d.ts.map +1 -1
  16. package/dist/compiler/linker.d.ts +1 -0
  17. package/dist/compiler/linker.d.ts.map +1 -1
  18. package/dist/cst/capture-buffer.d.ts.map +1 -1
  19. package/dist/index.cjs +483 -181
  20. package/dist/index.cjs.map +4 -4
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +483 -181
  24. package/dist/index.js.map +4 -4
  25. package/dist/language-service/index.cjs +48 -2
  26. package/dist/language-service/index.cjs.map +3 -3
  27. package/dist/language-service/index.js +48 -2
  28. package/dist/language-service/index.js.map +3 -3
  29. package/dist/line-index.d.ts +41 -0
  30. package/dist/line-index.d.ts.map +1 -0
  31. package/dist/plugin/index.cjs +646 -169
  32. package/dist/plugin/index.cjs.map +4 -4
  33. package/dist/plugin/index.d.ts.map +1 -1
  34. package/dist/plugin/index.js +646 -169
  35. package/dist/plugin/index.js.map +4 -4
  36. package/dist/recovery/scan.d.ts.map +1 -1
  37. package/dist/regex/first-set.d.ts.map +1 -1
  38. package/dist/run/index.cjs +47 -1
  39. package/dist/run/index.cjs.map +3 -3
  40. package/dist/run/index.d.ts +3 -2
  41. package/dist/run/index.d.ts.map +1 -1
  42. package/dist/run/index.js +47 -1
  43. package/dist/run/index.js.map +3 -3
  44. package/dist/spec/index.cjs +462 -327
  45. package/dist/spec/index.cjs.map +4 -4
  46. package/dist/spec/index.js +462 -327
  47. package/dist/spec/index.js.map +4 -4
  48. package/dist/types.d.ts +18 -0
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/version.d.ts +1 -1
  51. package/package.json +1 -1
@@ -357,90 +357,63 @@ function markUnusedValues(root) {
357
357
  visit(resolveRoot(root), true);
358
358
  }
359
359
 
360
- // src/combinators/parser.ts
361
- var RULE_ORDER = "__parsemanRuleOrder";
362
- function tagRule(r, key) {
363
- ;
364
- r._ruleName = key;
365
- if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
366
- }
367
- function isDefinableRef(v) {
368
- return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
369
- }
370
- function ruleNameOf(r) {
371
- return r._ruleName;
360
+ // src/line-index.ts
361
+ function createLineIndex() {
362
+ return { lineStarts: [0] };
372
363
  }
373
- function isNamedRuleRefForAnotherRule(r, key) {
374
- const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
375
- return name !== void 0 && name !== key;
376
- }
377
- function rules(a, b) {
378
- const factory = typeof a === "function" ? a : b;
379
- const options = typeof a === "function" ? b : a;
380
- const cache = {};
381
- const proxy = new Proxy(cache, {
382
- get(target, key) {
383
- if (typeof key !== "string") return void 0;
384
- const record = target;
385
- if (!(key in record)) {
386
- const r = ref();
387
- tagRule(r, key);
388
- record[key] = r;
389
- }
390
- return record[key];
391
- }
392
- });
393
- const definitions = factory(proxy);
394
- for (const key of Object.keys(definitions)) {
395
- const placeholder = cache[key];
396
- const parser2 = definitions[key];
397
- if (placeholder === parser2) {
398
- throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
399
- }
400
- if (isDefinableRef(placeholder)) {
401
- if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
402
- placeholder.define(parser2);
403
- placeholder._meta.firstSet = parser2._meta.firstSet;
404
- placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
405
- } else if (isNamedRuleRefForAnotherRule(parser2, key)) {
406
- const alias = ref();
407
- tagRule(alias, key);
408
- alias.define(parser2);
409
- alias._meta.firstSet = parser2._meta.firstSet;
410
- alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
411
- cache[key] = alias;
412
- } else {
413
- tagRule(parser2, key);
414
- cache[key] = parser2;
415
- }
416
- }
417
- if (options?.trivia != null) {
418
- for (const key of Object.keys(definitions)) {
419
- const rule = cache[key];
420
- if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
421
- }
422
- }
423
- if (options?.scanSkip != null) {
424
- for (const key of Object.keys(definitions)) {
425
- const rule = cache[key];
426
- if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
427
- }
364
+ function recordLineRange(index, input, start, end) {
365
+ const lineStarts = index.lineStarts;
366
+ for (let i = start; i < end; i++) {
367
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
428
368
  }
429
- if (options?.hostMode === "cst") {
430
- for (const key of Object.keys(definitions)) {
431
- const rule = cache[key];
432
- if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
433
- }
369
+ }
370
+ function recordLineRangeFromContext(ctx, input, _startHint, end) {
371
+ if (!ctx.trackLines) return;
372
+ const from = ctx._lineScannedTo ?? 0;
373
+ if (end <= from) return;
374
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
375
+ if (!index) return;
376
+ recordLineRange(index, input, from, end);
377
+ ctx._lineScannedTo = end;
378
+ }
379
+ function normalizeLineIndex(index) {
380
+ const starts = index.lineStarts;
381
+ starts.sort((a, b) => a - b);
382
+ let write = 0;
383
+ for (let read = 0; read < starts.length; read++) {
384
+ const value = starts[read];
385
+ if (write === 0 || starts[write - 1] !== value) starts[write++] = value;
434
386
  }
435
- for (const key of Object.keys(definitions)) {
436
- markUnusedValues(cache[key]);
387
+ starts.length = write;
388
+ if (starts.length === 0 || starts[0] !== 0) starts.unshift(0);
389
+ return index;
390
+ }
391
+ function offsetToLineCol(index, offset) {
392
+ const { lineStarts } = index;
393
+ let lo = 0;
394
+ let hi = lineStarts.length - 1;
395
+ while (lo < hi) {
396
+ const mid = lo + hi + 1 >> 1;
397
+ if (lineStarts[mid] <= offset) lo = mid;
398
+ else hi = mid - 1;
437
399
  }
438
- Object.defineProperty(cache, RULE_ORDER, {
439
- value: Object.keys(definitions),
440
- enumerable: false,
441
- configurable: true
442
- });
443
- return cache;
400
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
401
+ }
402
+ function annotateSpan(span, index) {
403
+ const s = offsetToLineCol(index, span.start);
404
+ const e = offsetToLineCol(index, span.end);
405
+ return {
406
+ ...span,
407
+ startLine: s.line,
408
+ startColumn: s.col,
409
+ endLine: e.line,
410
+ endColumn: e.col
411
+ };
412
+ }
413
+ function annotateSpanFromLineContext(span, ctx) {
414
+ if (!ctx.trackLines) return span;
415
+ const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
416
+ return index ? annotateSpan(span, index) : span;
444
417
  }
445
418
 
446
419
  // src/cst/capture-buffer.ts
@@ -484,7 +457,12 @@ function endCstNodeCapture(ctx, saved) {
484
457
  return materialized;
485
458
  }
486
459
  function pushCstLeaf(ctx, leaf2) {
487
- pushCstChild(ctx, leaf2, leaf2);
460
+ if (!ctx.trackLines) {
461
+ pushCstChild(ctx, leaf2, leaf2);
462
+ return;
463
+ }
464
+ const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
465
+ pushCstChild(ctx, annotated, annotated);
488
466
  }
489
467
  function pushCstChild(ctx, built, rawEntry) {
490
468
  const b = ctx._cstBuf;
@@ -674,7 +652,9 @@ function firstSetSentinel(fs) {
674
652
  function recoverScan(input, from, ctx, sync, expected) {
675
653
  let scanPos = from;
676
654
  while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
677
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
655
+ const span = { start: from, end: scanPos };
656
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
657
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
678
658
  ctx._errors?.push(error);
679
659
  return { error, end: scanPos };
680
660
  }
@@ -776,7 +756,8 @@ function expect(combinator, label2) {
776
756
  parse(input, pos, ctx) {
777
757
  const result = combinator.parse(input, pos, ctx);
778
758
  if (result.ok) return result;
779
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
759
+ const span = { start: pos, end: pos };
760
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
780
761
  ctx._errors?.push(error);
781
762
  if (ctx._tolerant) captureError(ctx, error);
782
763
  return { ok: true, value: error, span: { start: pos, end: pos } };
@@ -1047,34 +1028,329 @@ function codesToFirstSet(codes) {
1047
1028
  lo = hi = codes[i];
1048
1029
  }
1049
1030
  }
1050
- ranges.push({ lo, hi });
1051
- return { kind: "ranges", ranges };
1052
- }
1053
- function inFirstSet(code, fs) {
1054
- if (fs.kind === "any") return true;
1055
- if (fs.kind === "empty") return false;
1056
- for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1057
- return false;
1058
- }
1059
- function areDisjoint(sets) {
1060
- if (sets.some((s) => s.kind === "any")) return false;
1061
- for (let i = 0; i < sets.length; i++)
1062
- for (let j2 = i + 1; j2 < sets.length; j2++)
1063
- if (intersects(sets[i], sets[j2])) return false;
1064
- return true;
1065
- }
1066
- function buildAsciiDispatch(parsers) {
1067
- const table = Array(128).fill(-1);
1068
- for (let i = 0; i < parsers.length; i++) {
1069
- const fs = parsers[i]._meta.firstSet;
1070
- if (fs.kind !== "ranges") continue;
1071
- for (const { lo, hi } of fs.ranges) {
1072
- for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1073
- table[code] = i;
1031
+ ranges.push({ lo, hi });
1032
+ return { kind: "ranges", ranges };
1033
+ }
1034
+ function inFirstSet(code, fs) {
1035
+ if (fs.kind === "any") return true;
1036
+ if (fs.kind === "empty") return false;
1037
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1038
+ return false;
1039
+ }
1040
+ function areDisjoint(sets) {
1041
+ if (sets.some((s) => s.kind === "any")) return false;
1042
+ for (let i = 0; i < sets.length; i++)
1043
+ for (let j2 = i + 1; j2 < sets.length; j2++)
1044
+ if (intersects(sets[i], sets[j2])) return false;
1045
+ return true;
1046
+ }
1047
+ function buildAsciiDispatch(parsers) {
1048
+ const table = Array(128).fill(-1);
1049
+ for (let i = 0; i < parsers.length; i++) {
1050
+ const fs = parsers[i]._meta.firstSet;
1051
+ if (fs.kind !== "ranges") continue;
1052
+ for (const { lo, hi } of fs.ranges) {
1053
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1054
+ table[code] = i;
1055
+ }
1056
+ }
1057
+ }
1058
+ return table;
1059
+ }
1060
+
1061
+ // src/cst/trivia-kinds.ts
1062
+ function unwrapTrivia(p) {
1063
+ let cur = p;
1064
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1065
+ return cur;
1066
+ }
1067
+ function peelLabel(p) {
1068
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1069
+ return null;
1070
+ }
1071
+ function analyzeLabeledTrivia(trivia2) {
1072
+ let core = unwrapTrivia(trivia2);
1073
+ let minRepeats = 1;
1074
+ if (core._def.tag === "oneOrMore") {
1075
+ core = core._def.parser;
1076
+ minRepeats = 1;
1077
+ } else if (core._def.tag === "many") {
1078
+ core = core._def.parser;
1079
+ minRepeats = 0;
1080
+ }
1081
+ const arms = [];
1082
+ if (core._def.tag === "choice") {
1083
+ for (let i = 0; i < core._def.parsers.length; i++) {
1084
+ const peeled = peelLabel(core._def.parsers[i]);
1085
+ if (!peeled) return null;
1086
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1087
+ }
1088
+ } else {
1089
+ const peeled = peelLabel(core);
1090
+ if (!peeled) return null;
1091
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1092
+ }
1093
+ return { labels: arms.map((a) => a.label), arms, minRepeats };
1094
+ }
1095
+ function matchArmAt(input, pos, arm) {
1096
+ const r = arm.parse(input, pos, { trackLines: false });
1097
+ if (!r.ok || r.span.end <= pos) return null;
1098
+ return { end: r.span.end };
1099
+ }
1100
+ function scanLabeledTriviaChunks(input, cur, spec) {
1101
+ const chunks = [];
1102
+ let pos = cur;
1103
+ while (pos < input.length) {
1104
+ let matched = null;
1105
+ for (const arm of spec.arms) {
1106
+ const m = matchArmAt(input, pos, arm.parser);
1107
+ if (m) {
1108
+ matched = { end: m.end, kindIndex: arm.kindIndex };
1109
+ break;
1110
+ }
1111
+ }
1112
+ if (!matched) break;
1113
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1114
+ pos = matched.end;
1115
+ }
1116
+ if (chunks.length < spec.minRepeats) {
1117
+ return { end: cur, chunks: [] };
1118
+ }
1119
+ return { end: pos, chunks };
1120
+ }
1121
+ function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1122
+ const chunks = [];
1123
+ let pos = cur;
1124
+ while (pos < input.length) {
1125
+ const c = input.charCodeAt(pos);
1126
+ if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1127
+ const start = pos;
1128
+ pos++;
1129
+ while (pos < input.length) {
1130
+ const c2 = input.charCodeAt(pos);
1131
+ if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1132
+ else break;
1133
+ }
1134
+ chunks.push({ start, end: pos, kindIndex: wsKind });
1135
+ continue;
1136
+ }
1137
+ if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1138
+ let j2 = pos + 2;
1139
+ while (j2 + 1 < input.length && !(input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47)) j2++;
1140
+ if (j2 + 1 < input.length && input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47) {
1141
+ const start = pos;
1142
+ pos = j2 + 2;
1143
+ chunks.push({ start, end: pos, kindIndex: commentKind });
1144
+ continue;
1145
+ }
1146
+ break;
1147
+ }
1148
+ break;
1149
+ }
1150
+ return { end: pos, chunks };
1151
+ }
1152
+ function tryFastLabeledScan(input, cur, trivia2) {
1153
+ const spec = analyzeLabeledTrivia(trivia2);
1154
+ if (!spec || spec.arms.length !== 2) return null;
1155
+ const wsArm = spec.arms.find((a) => {
1156
+ const src = getCoreRegexDef(a.parser)?.source;
1157
+ return src != null && !src.includes("\\*");
1158
+ });
1159
+ const commentArm = spec.arms.find((a) => {
1160
+ const src = getCoreRegexDef(a.parser)?.source;
1161
+ return src != null && src.includes("\\*");
1162
+ });
1163
+ if (!wsArm || !commentArm) return null;
1164
+ const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1165
+ if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1166
+ return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1167
+ }
1168
+ function recordTriviaChunks(ctx, chunks) {
1169
+ const kinds = ctx.triviaKindLabels;
1170
+ const mask = ctx._triviaCaptureMask;
1171
+ for (const ch of chunks) {
1172
+ pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1173
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1174
+ if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
1175
+ pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1176
+ }
1177
+ }
1178
+ }
1179
+ }
1180
+ function triviaKindMask(labels, keep) {
1181
+ if (!labels) return void 0;
1182
+ let mask = 0;
1183
+ for (const name of keep) {
1184
+ const idx = labels.indexOf(name);
1185
+ if (idx >= 0) mask |= 1 << idx;
1186
+ }
1187
+ return mask;
1188
+ }
1189
+
1190
+ // src/combinators/grammar.ts
1191
+ function annotateResultLines(result, index) {
1192
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
1193
+ const errors = annotated.errors;
1194
+ if (errors) {
1195
+ ;
1196
+ annotated.errors = errors.map((error) => ({
1197
+ ...error,
1198
+ span: annotateSpan(error.span, index)
1199
+ }));
1200
+ }
1201
+ return annotated;
1202
+ }
1203
+ function createParseLineContext(input, pos) {
1204
+ const lineIndex = createLineIndex();
1205
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
1206
+ return { lineIndex, lineScannedTo: pos };
1207
+ }
1208
+ function parser(opts, root) {
1209
+ const clearTrivia = opts.trivia === null;
1210
+ return {
1211
+ _tag: "grammar",
1212
+ _meta: root._meta,
1213
+ _def: {
1214
+ tag: "grammar",
1215
+ parser: root,
1216
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
1217
+ clearTrivia,
1218
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
1219
+ trackLines: opts.trackLines ?? false
1220
+ },
1221
+ parse(input, pos, _ctx) {
1222
+ const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
1223
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
1224
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
1225
+ const ctx = {
1226
+ ..._ctx,
1227
+ trackLines,
1228
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
1229
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
1230
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
1231
+ ...clearTrivia ? {
1232
+ trivia: void 0,
1233
+ triviaKindLabels: void 0
1234
+ } : opts.trivia != null ? {
1235
+ trivia: opts.trivia,
1236
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
1237
+ } : {},
1238
+ ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
1239
+ // Kind-filter for per-node capture. Resolve against this scope's trivia
1240
+ // labels — this parser's own trivia if it declares one, else the INHERITED
1241
+ // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
1242
+ // trivia is inherited rather than re-declared here. No labels → undefined
1243
+ // (capture all).
1244
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
1245
+ };
1246
+ const result = root.parse(input, pos ?? 0, ctx);
1247
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
1248
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
1249
+ }
1250
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
1251
+ }
1252
+ };
1253
+ }
1254
+
1255
+ // src/combinators/parser.ts
1256
+ var RULE_ORDER = "__parsemanRuleOrder";
1257
+ function tagRule(r, key) {
1258
+ ;
1259
+ r._ruleName = key;
1260
+ if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
1261
+ }
1262
+ function isDefinableRef(v) {
1263
+ return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
1264
+ }
1265
+ function ruleNameOf(r) {
1266
+ return r._ruleName;
1267
+ }
1268
+ function isNamedRuleRefForAnotherRule(r, key) {
1269
+ const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
1270
+ return name !== void 0 && name !== key;
1271
+ }
1272
+ function rules(a, b) {
1273
+ const factory = typeof a === "function" ? a : b;
1274
+ const options = typeof a === "function" ? b : a;
1275
+ const cache = {};
1276
+ const proxy = new Proxy(cache, {
1277
+ get(target, key) {
1278
+ if (typeof key !== "string") return void 0;
1279
+ const record = target;
1280
+ if (!(key in record)) {
1281
+ const r = ref();
1282
+ tagRule(r, key);
1283
+ record[key] = r;
1284
+ }
1285
+ return record[key];
1286
+ }
1287
+ });
1288
+ const definitions = factory(proxy);
1289
+ for (const key of Object.keys(definitions)) {
1290
+ const placeholder = cache[key];
1291
+ const parser2 = definitions[key];
1292
+ if (placeholder === parser2) {
1293
+ throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
1294
+ }
1295
+ if (isDefinableRef(placeholder)) {
1296
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
1297
+ placeholder.define(parser2);
1298
+ placeholder._meta.firstSet = parser2._meta.firstSet;
1299
+ placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
1300
+ } else if (isNamedRuleRefForAnotherRule(parser2, key)) {
1301
+ const alias = ref();
1302
+ tagRule(alias, key);
1303
+ alias.define(parser2);
1304
+ alias._meta.firstSet = parser2._meta.firstSet;
1305
+ alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
1306
+ cache[key] = alias;
1307
+ } else {
1308
+ tagRule(parser2, key);
1309
+ cache[key] = parser2;
1310
+ }
1311
+ }
1312
+ if (options?.trivia != null) {
1313
+ for (const key of Object.keys(definitions)) {
1314
+ const rule = cache[key];
1315
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
1316
+ }
1317
+ }
1318
+ if (options?.scanSkip != null) {
1319
+ for (const key of Object.keys(definitions)) {
1320
+ const rule = cache[key];
1321
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
1322
+ }
1323
+ }
1324
+ if (options?.hostMode === "cst") {
1325
+ for (const key of Object.keys(definitions)) {
1326
+ const rule = cache[key];
1327
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
1328
+ }
1329
+ }
1330
+ if (options?.trackLines === true) {
1331
+ for (const key of Object.keys(definitions)) {
1332
+ const rule = cache[key];
1333
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
1334
+ }
1335
+ for (const key of Object.keys(definitions)) {
1336
+ const rule = cache[key];
1337
+ if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
1338
+ const wrapped = parser({ trackLines: true }, rule);
1339
+ tagRule(wrapped, key);
1340
+ wrapped._meta.grammarTrackLines = true;
1341
+ cache[key] = wrapped;
1074
1342
  }
1075
1343
  }
1076
1344
  }
1077
- return table;
1345
+ for (const key of Object.keys(definitions)) {
1346
+ markUnusedValues(cache[key]);
1347
+ }
1348
+ Object.defineProperty(cache, RULE_ORDER, {
1349
+ value: Object.keys(definitions),
1350
+ enumerable: false,
1351
+ configurable: true
1352
+ });
1353
+ return cache;
1078
1354
  }
1079
1355
 
1080
1356
  // src/analysis/duplication.ts
@@ -1116,6 +1392,7 @@ function literal(value, opts = {}) {
1116
1392
  canMatchNewline: value.includes("\n"),
1117
1393
  isTrivia: false
1118
1394
  };
1395
+ const canMatchNewline = meta.canMatchNewline;
1119
1396
  if (caseInsensitive) {
1120
1397
  const upper = value.toUpperCase();
1121
1398
  const lower = value.toLowerCase();
@@ -1132,6 +1409,7 @@ function literal(value, opts = {}) {
1132
1409
  return function parse2(input, pos, ctx) {
1133
1410
  if (input.charCodeAt(pos) === code) {
1134
1411
  const span = { start: pos, end: pos + 1 };
1412
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
1135
1413
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1136
1414
  return { ok: true, value, span };
1137
1415
  }
@@ -1145,6 +1423,7 @@ function literal(value, opts = {}) {
1145
1423
  const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
1146
1424
  if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
1147
1425
  const span = { start: pos, end };
1426
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
1148
1427
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
1149
1428
  return { ok: true, value: matchedValue, span };
1150
1429
  }
@@ -1309,6 +1588,7 @@ function regex(pattern, flags = "") {
1309
1588
  if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
1310
1589
  const value = input.slice(pos, scanEnd);
1311
1590
  const span2 = { start: pos, end: scanEnd };
1591
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
1312
1592
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
1313
1593
  return { ok: true, value, span: span2 };
1314
1594
  }
@@ -1318,141 +1598,13 @@ function regex(pattern, flags = "") {
1318
1598
  return failAt(ctx, [`/${source}/`], pos);
1319
1599
  }
1320
1600
  const span = { start: pos, end: pos + m[0].length };
1601
+ if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
1321
1602
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
1322
1603
  return { ok: true, value: m[0], span };
1323
1604
  }
1324
1605
  };
1325
1606
  }
1326
1607
 
1327
- // src/cst/trivia-kinds.ts
1328
- function unwrapTrivia(p) {
1329
- let cur = p;
1330
- while (cur._def.tag === "trivia") cur = cur._def.parser;
1331
- return cur;
1332
- }
1333
- function peelLabel(p) {
1334
- if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1335
- return null;
1336
- }
1337
- function analyzeLabeledTrivia(trivia2) {
1338
- let core = unwrapTrivia(trivia2);
1339
- let minRepeats = 1;
1340
- if (core._def.tag === "oneOrMore") {
1341
- core = core._def.parser;
1342
- minRepeats = 1;
1343
- } else if (core._def.tag === "many") {
1344
- core = core._def.parser;
1345
- minRepeats = 0;
1346
- }
1347
- const arms = [];
1348
- if (core._def.tag === "choice") {
1349
- for (let i = 0; i < core._def.parsers.length; i++) {
1350
- const peeled = peelLabel(core._def.parsers[i]);
1351
- if (!peeled) return null;
1352
- arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1353
- }
1354
- } else {
1355
- const peeled = peelLabel(core);
1356
- if (!peeled) return null;
1357
- arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1358
- }
1359
- return { labels: arms.map((a) => a.label), arms, minRepeats };
1360
- }
1361
- function matchArmAt(input, pos, arm) {
1362
- const r = arm.parse(input, pos, { trackLines: false });
1363
- if (!r.ok || r.span.end <= pos) return null;
1364
- return { end: r.span.end };
1365
- }
1366
- function scanLabeledTriviaChunks(input, cur, spec) {
1367
- const chunks = [];
1368
- let pos = cur;
1369
- while (pos < input.length) {
1370
- let matched = null;
1371
- for (const arm of spec.arms) {
1372
- const m = matchArmAt(input, pos, arm.parser);
1373
- if (m) {
1374
- matched = { end: m.end, kindIndex: arm.kindIndex };
1375
- break;
1376
- }
1377
- }
1378
- if (!matched) break;
1379
- chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1380
- pos = matched.end;
1381
- }
1382
- if (chunks.length < spec.minRepeats) {
1383
- return { end: cur, chunks: [] };
1384
- }
1385
- return { end: pos, chunks };
1386
- }
1387
- function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1388
- const chunks = [];
1389
- let pos = cur;
1390
- while (pos < input.length) {
1391
- const c = input.charCodeAt(pos);
1392
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1393
- const start = pos;
1394
- pos++;
1395
- while (pos < input.length) {
1396
- const c2 = input.charCodeAt(pos);
1397
- if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1398
- else break;
1399
- }
1400
- chunks.push({ start, end: pos, kindIndex: wsKind });
1401
- continue;
1402
- }
1403
- if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1404
- let j2 = pos + 2;
1405
- while (j2 + 1 < input.length && !(input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47)) j2++;
1406
- if (j2 + 1 < input.length && input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47) {
1407
- const start = pos;
1408
- pos = j2 + 2;
1409
- chunks.push({ start, end: pos, kindIndex: commentKind });
1410
- continue;
1411
- }
1412
- break;
1413
- }
1414
- break;
1415
- }
1416
- return { end: pos, chunks };
1417
- }
1418
- function tryFastLabeledScan(input, cur, trivia2) {
1419
- const spec = analyzeLabeledTrivia(trivia2);
1420
- if (!spec || spec.arms.length !== 2) return null;
1421
- const wsArm = spec.arms.find((a) => {
1422
- const src = getCoreRegexDef(a.parser)?.source;
1423
- return src != null && !src.includes("\\*");
1424
- });
1425
- const commentArm = spec.arms.find((a) => {
1426
- const src = getCoreRegexDef(a.parser)?.source;
1427
- return src != null && src.includes("\\*");
1428
- });
1429
- if (!wsArm || !commentArm) return null;
1430
- const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1431
- if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1432
- return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1433
- }
1434
- function recordTriviaChunks(ctx, chunks) {
1435
- const kinds = ctx.triviaKindLabels;
1436
- const mask = ctx._triviaCaptureMask;
1437
- for (const ch of chunks) {
1438
- pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1439
- if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1440
- if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
1441
- pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1442
- }
1443
- }
1444
- }
1445
- }
1446
- function triviaKindMask(labels, keep) {
1447
- if (!labels) return void 0;
1448
- let mask = 0;
1449
- for (const name of keep) {
1450
- const idx = labels.indexOf(name);
1451
- if (idx >= 0) mask |= 1 << idx;
1452
- }
1453
- return mask;
1454
- }
1455
-
1456
1608
  // src/combinators/trivia-skip.ts
1457
1609
  var NOOP_COMMIT = () => {
1458
1610
  };
@@ -1468,6 +1620,18 @@ function rollbackTrivia(ctx, mark) {
1468
1620
  rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1469
1621
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1470
1622
  }
1623
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1624
+ const probeCtx = {
1625
+ trackLines: ctx.trackLines,
1626
+ state: ctx.state,
1627
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1628
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1629
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1630
+ };
1631
+ const result = triviaP.parse(input, cur, probeCtx);
1632
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1633
+ return result;
1634
+ }
1471
1635
  function saveLookaheadMark(ctx) {
1472
1636
  return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1473
1637
  }
@@ -1490,13 +1654,29 @@ function scanWithLabels(input, cur, ctx) {
1490
1654
  function advanceTrivia(input, cur, ctx) {
1491
1655
  const triviaP = ctx.trivia;
1492
1656
  if (!triviaP) return cur;
1657
+ if (!ctx.trackLines) {
1658
+ const fast2 = fastTriviaScanner(triviaP);
1659
+ if (fast2) return fast2(input, cur);
1660
+ if (ctx.triviaKindLabels) {
1661
+ const scan = scanWithLabels(input, cur, ctx);
1662
+ return scan.end;
1663
+ }
1664
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1665
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1666
+ }
1667
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1493
1668
  const fast = fastTriviaScanner(triviaP);
1494
- if (fast) return fast(input, cur);
1669
+ if (fast) {
1670
+ const end = fast(input, cur);
1671
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1672
+ return end;
1673
+ }
1495
1674
  if (ctx.triviaKindLabels) {
1496
1675
  const scan = scanWithLabels(input, cur, ctx);
1676
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1497
1677
  return scan.end;
1498
1678
  }
1499
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1679
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1500
1680
  return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1501
1681
  }
1502
1682
  function scanTrivia(input, cur, ctx) {
@@ -1504,18 +1684,46 @@ function scanTrivia(input, cur, ctx) {
1504
1684
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1505
1685
  const log = ctx._triviaLog;
1506
1686
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1687
+ if (!ctx.trackLines) {
1688
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1689
+ if (fast2 && log === void 0 && !captureTl) {
1690
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1691
+ }
1692
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1693
+ return scanWithLabels(input, cur, ctx);
1694
+ }
1695
+ if (log !== void 0 || captureTl) {
1696
+ const tr3 = triviaP.parse(input, cur, {
1697
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1698
+ state: ctx.state
1699
+ });
1700
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1701
+ const end = tr3.span.end;
1702
+ return {
1703
+ end,
1704
+ commit: () => {
1705
+ pushTriviaLogEntry(ctx, cur, end);
1706
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1707
+ }
1708
+ };
1709
+ }
1710
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1711
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1712
+ }
1713
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1507
1714
  const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1508
1715
  if (fast && log === void 0 && !captureTl) {
1509
- return { end: fast(input, cur), commit: NOOP_COMMIT };
1716
+ const end = fast(input, cur);
1717
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1718
+ return { end, commit: NOOP_COMMIT };
1510
1719
  }
1511
1720
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1512
- return scanWithLabels(input, cur, ctx);
1721
+ const scan = scanWithLabels(input, cur, ctx);
1722
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1723
+ return scan;
1513
1724
  }
1514
1725
  if (log !== void 0 || captureTl) {
1515
- const tr2 = triviaP.parse(input, cur, {
1516
- trackLines: log !== void 0 ? false : ctx.trackLines,
1517
- state: ctx.state
1518
- });
1726
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1519
1727
  if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1520
1728
  const end = tr2.span.end;
1521
1729
  return {
@@ -1526,7 +1734,7 @@ function scanTrivia(input, cur, ctx) {
1526
1734
  }
1527
1735
  };
1528
1736
  }
1529
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1737
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1530
1738
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1531
1739
  }
1532
1740
  function consumeTrivia(input, cur, ctx) {
@@ -2179,7 +2387,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2179
2387
  let cur = pos;
2180
2388
  const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
2181
2389
  const probeCtx = {
2182
- trackLines: ctx.trackLines,
2390
+ trackLines: false,
2183
2391
  state: ctx.state,
2184
2392
  ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
2185
2393
  };
@@ -2192,6 +2400,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2192
2400
  while (cur < input.length) {
2193
2401
  const s = sentinel.parse(input, cur, probeCtx);
2194
2402
  if (s.ok) {
2403
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
2195
2404
  emit(cur);
2196
2405
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2197
2406
  }
@@ -2207,6 +2416,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2207
2416
  if (!advanced) cur++;
2208
2417
  }
2209
2418
  if (orEOF) {
2419
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
2210
2420
  emit(cur);
2211
2421
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2212
2422
  }
@@ -2816,89 +3026,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2816
3026
  const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2817
3027
  const nodeType = def.type ?? missingInferredType();
2818
3028
  const cstOutput = cstOutputHost(ctx.build);
3029
+ const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
2819
3030
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2820
- 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 };
2821
- 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 };
3031
+ 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 };
3032
+ 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 };
2822
3033
  if (saved.buf !== void 0 || saved.ch !== void 0) {
2823
3034
  pushCstChild(ctx, built, rawEntry);
2824
3035
  }
2825
- return { ok: true, value: built, span: r.span };
2826
- }
2827
- };
2828
- }
2829
-
2830
- // src/compiler/line-index.ts
2831
- function buildLineIndex(input) {
2832
- const lineStarts = [0];
2833
- for (let i = 0; i < input.length; i++) {
2834
- if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
2835
- }
2836
- return { lineStarts };
2837
- }
2838
- function offsetToLineCol(index, offset) {
2839
- const { lineStarts } = index;
2840
- let lo = 0;
2841
- let hi = lineStarts.length - 1;
2842
- while (lo < hi) {
2843
- const mid = lo + hi + 1 >> 1;
2844
- if (lineStarts[mid] <= offset) lo = mid;
2845
- else hi = mid - 1;
2846
- }
2847
- return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
2848
- }
2849
- function annotateSpan(span, index) {
2850
- const s = offsetToLineCol(index, span.start);
2851
- const e = offsetToLineCol(index, span.end);
2852
- return {
2853
- ...span,
2854
- startLine: s.line,
2855
- startColumn: s.col,
2856
- endLine: e.line,
2857
- endColumn: e.col
2858
- };
2859
- }
2860
-
2861
- // src/combinators/grammar.ts
2862
- function parser(opts, root) {
2863
- const clearTrivia = opts.trivia === null;
2864
- return {
2865
- _tag: "grammar",
2866
- _meta: root._meta,
2867
- _def: {
2868
- tag: "grammar",
2869
- parser: root,
2870
- triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2871
- clearTrivia,
2872
- ...opts.captureTrivia ? { captureTrivia: true } : {},
2873
- trackLines: opts.trackLines ?? false
2874
- },
2875
- parse(input, pos, _ctx) {
2876
- const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2877
- const ctx = {
2878
- ..._ctx,
2879
- trackLines,
2880
- // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2881
- ...clearTrivia ? {
2882
- trivia: void 0,
2883
- triviaKindLabels: void 0
2884
- } : opts.trivia != null ? {
2885
- trivia: opts.trivia,
2886
- ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
2887
- } : {},
2888
- ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
2889
- // Kind-filter for per-node capture. Resolve against this scope's trivia
2890
- // labels — this parser's own trivia if it declares one, else the INHERITED
2891
- // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2892
- // trivia is inherited rather than re-declared here. No labels → undefined
2893
- // (capture all).
2894
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2895
- };
2896
- const result = root.parse(input, pos ?? 0, ctx);
2897
- if (trackLines) {
2898
- const idx = buildLineIndex(input);
2899
- return { ...result, span: annotateSpan(result.span, idx) };
2900
- }
2901
- return result;
3036
+ return { ok: true, value: built, span };
2902
3037
  }
2903
3038
  };
2904
3039
  }
@@ -3186,7 +3321,7 @@ function normalizeCstCollapse(collapse) {
3186
3321
  return typeof collapse === "function" ? collapse : void 0;
3187
3322
  }
3188
3323
  function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
3189
- return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
3324
+ return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children] };
3190
3325
  }
3191
3326
  function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
3192
3327
  if (typeof typeOrOptions === "string") {