parseman 0.43.0 → 0.44.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 (52) hide show
  1. package/dist/combinators/attempt.d.ts.map +1 -1
  2. package/dist/combinators/choice.d.ts.map +1 -1
  3. package/dist/combinators/grammar.d.ts +7 -0
  4. package/dist/combinators/grammar.d.ts.map +1 -1
  5. package/dist/combinators/map.d.ts +11 -0
  6. package/dist/combinators/map.d.ts.map +1 -1
  7. package/dist/combinators/token.d.ts +3 -2
  8. package/dist/combinators/token.d.ts.map +1 -1
  9. package/dist/combinators/trivia-skip.d.ts +1 -0
  10. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  11. package/dist/compiler/codegen.d.ts.map +1 -1
  12. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  13. package/dist/compiler/scannable-run.d.ts +1 -1
  14. package/dist/compiler/scannable-run.d.ts.map +1 -1
  15. package/dist/compiler/trivia-fast-path.d.ts +4 -3
  16. package/dist/compiler/trivia-fast-path.d.ts.map +1 -1
  17. package/dist/cst/trivia-entries.d.ts +15 -9
  18. package/dist/cst/trivia-entries.d.ts.map +1 -1
  19. package/dist/cst/trivia-kinds.d.ts +15 -11
  20. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  21. package/dist/functional/run.d.ts +22 -16
  22. package/dist/functional/run.d.ts.map +1 -1
  23. package/dist/index.cjs +1416 -1115
  24. package/dist/index.cjs.map +4 -4
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +1416 -1115
  28. package/dist/index.js.map +4 -4
  29. package/dist/language-service/index.cjs +161 -102
  30. package/dist/language-service/index.cjs.map +3 -3
  31. package/dist/language-service/index.js +161 -102
  32. package/dist/language-service/index.js.map +3 -3
  33. package/dist/plugin/evaluator.d.ts.map +1 -1
  34. package/dist/plugin/index.cjs +1217 -985
  35. package/dist/plugin/index.cjs.map +4 -4
  36. package/dist/plugin/index.d.ts.map +1 -1
  37. package/dist/plugin/index.js +1217 -985
  38. package/dist/plugin/index.js.map +4 -4
  39. package/dist/run/index.cjs +152 -102
  40. package/dist/run/index.cjs.map +3 -3
  41. package/dist/run/index.d.ts +1 -1
  42. package/dist/run/index.d.ts.map +1 -1
  43. package/dist/run/index.js +152 -102
  44. package/dist/run/index.js.map +3 -3
  45. package/dist/spec/index.cjs +1414 -1286
  46. package/dist/spec/index.cjs.map +4 -4
  47. package/dist/spec/index.js +1414 -1286
  48. package/dist/spec/index.js.map +4 -4
  49. package/dist/types.d.ts +25 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/version.d.ts +1 -1
  52. package/package.json +1 -1
@@ -1071,843 +1071,433 @@ function keywords(words, opts = {}) {
1071
1071
  };
1072
1072
  }
1073
1073
 
1074
- // src/recovery/scan.ts
1075
- function probeAt(sentinel, input, pos, ctx) {
1076
- const s = {
1077
- _probe: ctx._probe,
1078
- _errors: ctx._errors,
1079
- _cstLeaves: ctx._cstLeaves,
1080
- _cstChildren: ctx._cstChildren,
1081
- _cstRawChildren: ctx._cstRawChildren,
1082
- _cstTriviaLog: ctx._cstTriviaLog,
1083
- _triviaLog: ctx._triviaLog,
1084
- _fields: ctx._fields,
1085
- _cstBuf: ctx._cstBuf,
1086
- _tolerant: ctx._tolerant,
1087
- _sync: ctx._sync
1088
- };
1089
- ctx._probe = void 0;
1090
- ctx._errors = void 0;
1091
- ctx._cstLeaves = void 0;
1092
- ctx._cstChildren = void 0;
1093
- ctx._cstRawChildren = void 0;
1094
- ctx._cstTriviaLog = void 0;
1095
- ctx._triviaLog = void 0;
1096
- ctx._fields = void 0;
1097
- ctx._cstBuf = void 0;
1098
- ctx._tolerant = void 0;
1099
- ctx._sync = void 0;
1100
- try {
1101
- return sentinel.parse(input, pos, ctx).ok;
1102
- } finally {
1103
- ctx._probe = s._probe;
1104
- ctx._errors = s._errors;
1105
- ctx._cstLeaves = s._cstLeaves;
1106
- ctx._cstChildren = s._cstChildren;
1107
- ctx._cstRawChildren = s._cstRawChildren;
1108
- ctx._cstTriviaLog = s._cstTriviaLog;
1109
- ctx._triviaLog = s._triviaLog;
1110
- ctx._fields = s._fields;
1111
- ctx._cstBuf = s._cstBuf;
1112
- ctx._tolerant = s._tolerant;
1113
- ctx._sync = s._sync;
1114
- }
1074
+ // src/cst/trivia-kinds.ts
1075
+ var labeledTriviaSpecs = /* @__PURE__ */ new WeakMap();
1076
+ function unwrapTrivia(p) {
1077
+ let cur = p;
1078
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1079
+ return cur;
1115
1080
  }
1116
- function orSentinel(a, b) {
1117
- if (b === void 0) return a;
1118
- return {
1119
- _tag: "orSentinel",
1120
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1121
- _def: { tag: "unknown" },
1122
- parse(input, pos, ctx) {
1123
- const ra = a.parse(input, pos, ctx);
1124
- if (ra.ok) return ra;
1125
- return b.parse(input, pos, ctx);
1126
- }
1127
- };
1081
+ function peelLabel(p) {
1082
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1083
+ return null;
1128
1084
  }
1129
- function firstSetSentinel(fs2) {
1130
- if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
1131
- const ranges = fs2.ranges;
1132
- return {
1133
- _tag: "firstSetSentinel",
1134
- _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
1135
- _def: { tag: "unknown" },
1136
- parse(input, pos) {
1137
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1138
- if (code !== void 0) {
1139
- for (const r of ranges) {
1140
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1141
- }
1085
+ function analyzeLabeledTrivia(trivia2) {
1086
+ const cached = labeledTriviaSpecs.get(trivia2);
1087
+ if (cached !== void 0) return cached;
1088
+ let core = unwrapTrivia(trivia2);
1089
+ let minRepeats = 1;
1090
+ if (core._def.tag === "oneOrMore") {
1091
+ core = core._def.parser;
1092
+ minRepeats = 1;
1093
+ } else if (core._def.tag === "many") {
1094
+ core = core._def.parser;
1095
+ minRepeats = 0;
1096
+ }
1097
+ const arms = [];
1098
+ if (core._def.tag === "choice") {
1099
+ for (let i = 0; i < core._def.parsers.length; i++) {
1100
+ const peeled = peelLabel(core._def.parsers[i]);
1101
+ if (!peeled) {
1102
+ labeledTriviaSpecs.set(trivia2, null);
1103
+ return null;
1142
1104
  }
1143
- return { ok: false, expected: [], span: { start: pos, end: pos } };
1105
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1106
+ }
1107
+ } else {
1108
+ const peeled = peelLabel(core);
1109
+ if (!peeled) {
1110
+ labeledTriviaSpecs.set(trivia2, null);
1111
+ return null;
1144
1112
  }
1113
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1114
+ }
1115
+ const spec = {
1116
+ labels: arms.map((a) => a.label),
1117
+ arms,
1118
+ minRepeats
1145
1119
  };
1120
+ labeledTriviaSpecs.set(trivia2, spec);
1121
+ return spec;
1146
1122
  }
1147
- function recoverScan(input, from, ctx, sync, expected) {
1148
- let scanPos = from;
1149
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1150
- const span = { start: from, end: scanPos };
1151
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1152
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1153
- ctx._errors?.push(error);
1154
- return { error, end: scanPos };
1155
- }
1156
- function matchesAt(sentinel, input, pos, ctx) {
1157
- return probeAt(sentinel, input, pos, ctx);
1123
+ function matchArmAt(input, pos, arm, state) {
1124
+ if (!startsFirstSet(arm, input, pos)) return null;
1125
+ const r = arm.parse(input, pos, { trackLines: false, state });
1126
+ if (!r.ok || r.span.end <= pos) return null;
1127
+ return { end: r.span.end };
1158
1128
  }
1159
- function captureError(ctx, error) {
1160
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1129
+ function scanLabeledTriviaChunks(input, cur, spec, state) {
1130
+ const chunks = [];
1131
+ let pos = cur;
1132
+ while (pos < input.length) {
1133
+ let matched = null;
1134
+ for (const arm of spec.arms) {
1135
+ const m = matchArmAt(input, pos, arm.parser, state);
1136
+ if (m) {
1137
+ matched = { end: m.end, kindIndex: arm.kindIndex };
1138
+ break;
1139
+ }
1140
+ }
1141
+ if (!matched) break;
1142
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1143
+ pos = matched.end;
1144
+ }
1145
+ if (chunks.length < spec.minRepeats) {
1146
+ return { end: cur, chunks: [] };
1147
+ }
1148
+ return { end: pos, chunks };
1161
1149
  }
1162
-
1163
- // src/combinators/expect.ts
1164
- function deriveExpected(c) {
1165
- return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1150
+ function scanLabeledTriviaEnd(input, cur, spec, state) {
1151
+ let pos = cur;
1152
+ let count = 0;
1153
+ while (pos < input.length) {
1154
+ let matched = null;
1155
+ for (const arm of spec.arms) {
1156
+ matched = matchArmAt(input, pos, arm.parser, state);
1157
+ if (matched) break;
1158
+ }
1159
+ if (!matched) break;
1160
+ pos = matched.end;
1161
+ count++;
1162
+ }
1163
+ return count < spec.minRepeats ? cur : pos;
1166
1164
  }
1167
- function derive(c, seen) {
1168
- const deriveExpected2 = (p) => derive(p, seen);
1169
- const def = c._def;
1170
- switch (def.tag) {
1171
- case "literal":
1172
- return [JSON.stringify(def.value)];
1173
- case "regex":
1174
- return [`/${def.source}/`];
1175
- case "keywords":
1176
- return def.words.map((w) => JSON.stringify(w));
1177
- case "label":
1178
- return [def.label];
1179
- case "choice":
1180
- return def.parsers.flatMap(deriveExpected2);
1181
- case "dispatch":
1182
- return deriveExpected2(def.selector);
1183
- // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1184
- // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1185
- // able to fail first — deriving from term 0 alone named a token the parse
1186
- // never actually required. A leading `not(…)` is zero-width and contributes
1187
- // nothing (its own expectation is about what must NOT be here), but it is
1188
- // nullable, so keep scanning past it. Stop at the first term that must match.
1189
- case "sequence": {
1190
- const out = [];
1191
- for (const term of def.parsers) {
1192
- if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1193
- if (!matchesEmpty(term)) break;
1165
+ function visitLabeledTrivia(input, cur, spec, state, visit) {
1166
+ if (spec.minRepeats > 1) return void 0;
1167
+ let pos = cur;
1168
+ let count = 0;
1169
+ while (pos < input.length) {
1170
+ let matched = null;
1171
+ for (const arm of spec.arms) {
1172
+ const match = matchArmAt(input, pos, arm.parser, state);
1173
+ if (match) {
1174
+ matched = { end: match.end, kindIndex: arm.kindIndex };
1175
+ break;
1194
1176
  }
1195
- return out;
1196
1177
  }
1197
- case "attempt":
1198
- return deriveExpected2(def.parser);
1199
- // Delegating wrappers whose first-token failure is their inner parser's — must
1200
- // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1201
- // node, which reads this) names the real expected token, not the wrapper tag.
1202
- case "field":
1203
- case "withCtx":
1204
- case "recover":
1205
- return deriveExpected2(def.parser);
1206
- case "skip":
1207
- return deriveExpected2(def.main);
1208
- case "expect":
1209
- return def.expected;
1210
- case "node":
1211
- case "grammar":
1212
- case "trivia":
1213
- case "token":
1214
- case "leaf":
1215
- case "optional":
1216
- case "many":
1217
- case "oneOrMore":
1218
- case "transform":
1219
- case "not":
1220
- case "peek":
1221
- return deriveExpected2(def.parser);
1222
- case "routed":
1223
- return ["routed()"];
1224
- case "lazy": {
1225
- const name = c._ruleName;
1226
- if (seen.has(c)) return name ? [name] : [];
1227
- seen.add(c);
1228
- try {
1229
- return deriveExpected2(def.thunk());
1230
- } catch {
1231
- return name ? [name] : [];
1232
- } finally {
1233
- seen.delete(c);
1178
+ if (!matched) break;
1179
+ visit(pos, matched.end, matched.kindIndex);
1180
+ pos = matched.end;
1181
+ count++;
1182
+ }
1183
+ return count < spec.minRepeats ? cur : pos;
1184
+ }
1185
+ function recordTriviaChunks(ctx, chunks) {
1186
+ const kinds = ctx.triviaKindLabels;
1187
+ const mask = ctx._triviaCaptureMask;
1188
+ const rootLog = ctx._rootTriviaLog;
1189
+ const rootKinds = ctx._rootTriviaKindIndex;
1190
+ const rootMark = rootLog?.length ?? 0;
1191
+ for (const ch2 of chunks) {
1192
+ pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1193
+ const rootKindIndex = ctx._rootTriviaCapture === false || rootLog === void 0 || rootKinds === void 0 || kinds === void 0 ? -1 : rootKinds[kinds[ch2.kindIndex] ?? ""] ?? -1;
1194
+ if (rootKindIndex >= 0) {
1195
+ rootLog.push(0, 0, ch2.start, ch2.end, rootKindIndex);
1196
+ }
1197
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1198
+ if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1199
+ pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1234
1200
  }
1235
1201
  }
1236
- default:
1237
- return [];
1238
1202
  }
1239
- }
1240
- function expect(combinator, label2) {
1241
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1242
- const meta = {
1243
- firstSet: combinator._meta.firstSet,
1244
- canMatchNewline: combinator._meta.canMatchNewline,
1245
- isTrivia: false
1246
- };
1247
- return {
1248
- _tag: "expect",
1249
- _meta: meta,
1250
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1251
- parse(input, pos, ctx) {
1252
- const result = combinator.parse(input, pos, ctx);
1253
- if (result.ok) return result;
1254
- const span = { start: pos, end: pos };
1255
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1256
- ctx._errors?.push(error);
1257
- if (ctx._tolerant) captureError(ctx, error);
1258
- return { ok: true, value: error, span: { start: pos, end: pos } };
1203
+ if (rootLog !== void 0 && rootLog.length !== rootMark && chunks.length > 0) {
1204
+ const start = chunks[0].start;
1205
+ const end = chunks[chunks.length - 1].end;
1206
+ for (let offset = rootMark; offset < rootLog.length; offset += 5) {
1207
+ rootLog[offset] = start;
1208
+ rootLog[offset + 1] = end;
1259
1209
  }
1260
- };
1210
+ }
1261
1211
  }
1262
-
1263
- // src/combinators/choice.ts
1264
- function choice(...args) {
1265
- const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1266
- const gates = args.map((a) => "gate" in a ? a.gate : null);
1267
- const hasGates = gates.some((g) => g !== null);
1268
- const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1269
- let combined = { kind: "empty" };
1270
- for (const p of parsers) combined = union(combined, p._meta.firstSet);
1271
- const meta = {
1272
- firstSet: combined,
1273
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1274
- isTrivia: false,
1275
- disjoint
1276
- };
1277
- const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1278
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1279
- let greedyLitMap = null;
1280
- let sortedParsers = null;
1281
- const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1282
- if (strategy?.tag === "greedyClassify") {
1283
- greedyLitMap = /* @__PURE__ */ new Map();
1284
- for (let i = 0; i < parsers.length; i++) {
1285
- if (i === strategy.superIndex) continue;
1286
- const litVal = getCoreLiteralValue(parsers[i]);
1287
- if (litVal !== null) greedyLitMap.set(litVal, i);
1288
- }
1289
- } else if (strategy?.tag === "literalsLongestFirst") {
1290
- sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
1212
+ function triviaKindMask(labels, keep) {
1213
+ if (!labels) return void 0;
1214
+ let mask = 0;
1215
+ for (const name of keep) {
1216
+ const idx = labels.indexOf(name);
1217
+ if (idx >= 0) mask |= 1 << idx;
1291
1218
  }
1219
+ return mask;
1220
+ }
1221
+
1222
+ // src/combinators/trivia-skip.ts
1223
+ var NOOP_COMMIT = () => {
1224
+ };
1225
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1226
+ function needsDeferredTriviaCommit(ctx) {
1227
+ return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1228
+ }
1229
+ function saveTriviaMark(ctx) {
1230
+ const m = saveCstMark(ctx);
1292
1231
  return {
1293
- _tag: "choice",
1294
- _meta: meta,
1295
- _def: {
1296
- tag: "choice",
1297
- parsers,
1298
- gates,
1299
- disjoint,
1300
- strategy: strategy ?? { tag: "firstMatch" },
1301
- autoNot
1302
- },
1303
- parse(input, pos, ctx) {
1304
- const expected = [];
1305
- if (disjoint && pos < input.length) {
1306
- const code = input.codePointAt(pos);
1307
- let idx = code < 128 ? asciiDispatch[code] : -1;
1308
- if (idx < 0) {
1309
- for (let i = 0; i < parsers.length; i++) {
1310
- if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1311
- idx = i;
1312
- break;
1313
- }
1232
+ raw: m.raw,
1233
+ tlog: m.tlog,
1234
+ leaves: m.leaves,
1235
+ fields: m.fields,
1236
+ errors: m.errors,
1237
+ log: ctx._triviaLog ? ctx._triviaLog.length : 0,
1238
+ rootLog: ctx._rootTriviaLog ? ctx._rootTriviaLog.length : 0
1239
+ };
1240
+ }
1241
+ function rollbackTrivia(ctx, mark) {
1242
+ rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1243
+ if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1244
+ if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1245
+ }
1246
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1247
+ const probeCtx = {
1248
+ trackLines: ctx.trackLines,
1249
+ state: ctx.state,
1250
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1251
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1252
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1253
+ };
1254
+ const result = triviaP.parse(input, cur, probeCtx);
1255
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1256
+ return result;
1257
+ }
1258
+ function saveLookaheadMark(ctx) {
1259
+ return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1260
+ }
1261
+ function rollbackLookahead(ctx, mark) {
1262
+ rollbackTrivia(ctx, mark);
1263
+ if (ctx._probe) ctx._probe.best = mark.probeBest;
1264
+ }
1265
+ function scanWithLabels(input, cur, ctx) {
1266
+ const triviaP = ctx.trivia;
1267
+ const spec = analyzeLabeledTrivia(triviaP);
1268
+ if (!spec) return { end: cur, commit: NOOP_COMMIT };
1269
+ const log = ctx._triviaLog;
1270
+ const rootLog = ctx._rootTriviaLog;
1271
+ const rootKinds = ctx._rootTriviaKindIndex;
1272
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1273
+ const mask = ctx._triviaCaptureMask;
1274
+ let fullRows;
1275
+ let rootRows;
1276
+ let cstRows;
1277
+ const visitedEnd = visitLabeledTrivia(input, cur, spec, ctx.state, (start, matchEnd, kindIndex) => {
1278
+ if (log !== void 0) (fullRows ??= []).push(start, matchEnd, kindIndex);
1279
+ const selectedKind = rootLog === void 0 || rootKinds === void 0 || ctx._rootTriviaCapture === false ? void 0 : rootKinds[spec.labels[kindIndex] ?? ""];
1280
+ if (selectedKind !== void 0) (rootRows ??= []).push(start, matchEnd, selectedKind);
1281
+ if (captureTl && (mask === void 0 || (mask & 1 << kindIndex) !== 0)) {
1282
+ (cstRows ??= []).push(start, matchEnd, kindIndex);
1283
+ }
1284
+ });
1285
+ if (visitedEnd !== void 0) {
1286
+ if (visitedEnd === cur) return { end: cur, commit: NOOP_COMMIT };
1287
+ return {
1288
+ end: visitedEnd,
1289
+ commit: () => {
1290
+ if (fullRows !== void 0 && log !== void 0) log.push(...fullRows);
1291
+ if (rootRows !== void 0 && rootLog !== void 0) {
1292
+ for (let i = 0; i < rootRows.length; i += 3) {
1293
+ rootLog.push(cur, visitedEnd, rootRows[i], rootRows[i + 1], rootRows[i + 2]);
1314
1294
  }
1315
1295
  }
1316
- if (idx >= 0) {
1317
- const gate2 = gates[idx];
1318
- if (gate2 && !gate2(ctx.state)) {
1319
- return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1296
+ if (cstRows !== void 0) {
1297
+ for (let i = 0; i < cstRows.length; i += 3) {
1298
+ pushCstTriviaEntry(ctx, cstRows[i], cstRows[i + 1], cstRows[i + 2]);
1320
1299
  }
1321
- const result = parsers[idx].parse(input, pos, ctx);
1322
- if (result.ok) return result;
1323
- expected.push(...result.expected);
1324
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1325
- return { ok: false, expected, span: { start: pos, end: pos } };
1326
- }
1327
- return {
1328
- ok: false,
1329
- expected: parsers.flatMap((p) => {
1330
- const r = p.parse(input, pos, ctx);
1331
- return r.ok ? [] : r.expected;
1332
- }),
1333
- span: { start: pos, end: pos }
1334
- };
1335
- }
1336
- if (strategy?.tag === "greedyClassify") {
1337
- const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1338
- if (!superResult.ok) return superResult;
1339
- const end = superResult.span.end;
1340
- const litIdx = greedyLitMap.get(input.slice(pos, end));
1341
- if (litIdx !== void 0) {
1342
- const litVal = getCoreLiteralValue(parsers[litIdx]);
1343
- const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1344
- return { ok: true, value, span: { start: pos, end } };
1345
- }
1346
- return superResult;
1347
- }
1348
- if (strategy?.tag === "literalsLongestFirst") {
1349
- for (const p of sortedParsers) {
1350
- const r = p.parse(input, pos, ctx);
1351
- if (r.ok) return r;
1352
- expected.push(...r.expected);
1353
- }
1354
- return { ok: false, expected, span: { start: pos, end: pos } };
1355
- }
1356
- for (let i = 0; i < parsers.length; i++) {
1357
- if (gates[i] && !gates[i](ctx.state)) continue;
1358
- const mark = saveCstMark(ctx);
1359
- const logLen = ctx._triviaLog?.length;
1360
- const result = parsers[i].parse(input, pos, ctx);
1361
- if (!result.ok) {
1362
- rollbackCstCapture(ctx, mark);
1363
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1364
- expected.push(...result.expected);
1365
- if (result.committed) return { ok: false, expected, span: result.span, committed: true };
1366
- continue;
1367
1300
  }
1368
- const checks = autoNot[i];
1369
- if (checks && autoNotFires(input, result.span.end, checks)) {
1370
- rollbackCstCapture(ctx, mark);
1371
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1372
- continue;
1373
- }
1374
- return result;
1375
1301
  }
1376
- return { ok: false, expected, span: { start: pos, end: pos } };
1377
- }
1302
+ };
1303
+ }
1304
+ const { end, chunks } = scanLabeledTriviaChunks(input, cur, spec, ctx.state);
1305
+ if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1306
+ return {
1307
+ end,
1308
+ commit: () => recordTriviaChunks(ctx, chunks)
1378
1309
  };
1379
1310
  }
1380
- function detectStrategy(parsers) {
1381
- const regexIndices = [];
1382
- const literalIndices = [];
1383
- for (let i = 0; i < parsers.length; i++) {
1384
- if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
1385
- else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
1386
- }
1387
- if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
1388
- const superIndex = regexIndices[0];
1389
- const regexDef = getCoreRegexDef(parsers[superIndex]);
1390
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
1391
- const re = new RegExp(regexDef.source, flags);
1392
- const allSubsumed = literalIndices.every((i) => {
1393
- const litVal = getCoreLiteralValue(parsers[i]);
1394
- re.lastIndex = 0;
1395
- const m = re.exec(litVal);
1396
- return m !== null && m[0] === litVal;
1397
- });
1398
- if (allSubsumed) return { tag: "greedyClassify", superIndex };
1311
+ function skipWithLabels(input, cur, ctx) {
1312
+ const spec = analyzeLabeledTrivia(ctx.trivia);
1313
+ if (spec) return scanLabeledTriviaEnd(input, cur, spec, ctx.state);
1314
+ const tr = parseTriviaNoCapture(ctx.trivia, input, cur, ctx);
1315
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1316
+ }
1317
+ function advanceTrivia(input, cur, ctx) {
1318
+ const triviaP = ctx.trivia;
1319
+ if (!triviaP) return cur;
1320
+ if (!ctx.trackLines) {
1321
+ const fast2 = fastTriviaScanner(triviaP);
1322
+ if (fast2) return fast2(input, cur);
1323
+ if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1324
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1325
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1399
1326
  }
1400
- if (parsers.length === literalIndices.length) {
1401
- const sortedIndices = [...literalIndices].sort(
1402
- (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
1403
- );
1404
- return { tag: "literalsLongestFirst", sortedIndices };
1327
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1328
+ const fast = fastTriviaScanner(triviaP);
1329
+ if (fast) {
1330
+ const end = fast(input, cur);
1331
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1332
+ return end;
1405
1333
  }
1406
- const shared = detectSharedPrefix(parsers);
1407
- if (shared !== null) return shared;
1408
- return { tag: "firstMatch" };
1409
- }
1410
- function bareLeadingTermKey(term) {
1411
- const d = term._def;
1412
- if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
1413
- if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
1414
- return null;
1415
- }
1416
- function detectSharedPrefix(parsers) {
1417
- if (parsers.length < 2) return null;
1418
- let key = null;
1419
- let prefix = null;
1420
- const members = [];
1421
- for (let i = 0; i < parsers.length; i++) {
1422
- const term0 = leadingTermOfArm(parsers[i]);
1423
- if (term0 === null) return null;
1424
- const k = bareLeadingTermKey(term0);
1425
- if (k === null) return null;
1426
- if (key === null) {
1427
- key = k;
1428
- prefix = term0;
1429
- } else if (k !== key) return null;
1430
- members.push(i);
1334
+ if (ctx.triviaKindLabels) {
1335
+ const end = skipWithLabels(input, cur, ctx);
1336
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1337
+ return end;
1431
1338
  }
1432
- if (prefix === null || members.length < 2) return null;
1433
- return { tag: "sharedPrefix", prefix, members };
1339
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1340
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1434
1341
  }
1435
- function leadingTermOfArm(arm) {
1436
- let d = arm._def;
1437
- for (; ; ) {
1438
- if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
1439
- d = d.parser._def;
1440
- continue;
1342
+ function scanTrivia(input, cur, ctx) {
1343
+ const triviaP = ctx.trivia;
1344
+ if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1345
+ const log = ctx._triviaLog;
1346
+ const rootLog = ctx._rootTriviaLog;
1347
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1348
+ if (!ctx.trackLines) {
1349
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1350
+ if (fast2 && log === void 0 && !captureTl) {
1351
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1441
1352
  }
1442
- break;
1443
- }
1444
- if (d.tag !== "sequence" || d.parsers.length < 2) return null;
1445
- return d.parsers[0];
1446
- }
1447
- function computeAutoNot(parsers) {
1448
- return parsers.map((p, i) => {
1449
- const litVal = getCoreLiteralValue(p);
1450
- if (litVal === null) return null;
1451
- const checks = [];
1452
- for (let j = i + 1; j < parsers.length; j++) {
1453
- const other = parsers[j];
1454
- const otherLit = getCoreLiteralValue(other);
1455
- if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
1456
- checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
1457
- continue;
1458
- }
1459
- const regexDef = getCoreRegexDef(other);
1460
- if (regexDef !== null) {
1461
- const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
1462
- if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
1463
- }
1353
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1354
+ return scanWithLabels(input, cur, ctx);
1464
1355
  }
1465
- return checks.length > 0 ? checks : null;
1466
- });
1467
- }
1468
- function autoNotFires(input, end, checks) {
1469
- for (const check of checks) {
1470
- if (check.kind === "firstSet") {
1471
- const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
1472
- if (inFirstSet(code, check.set)) return true;
1473
- } else {
1474
- if (input.startsWith(check.value, end)) return true;
1356
+ if (ctx.triviaKindLabels) return { end: skipWithLabels(input, cur, ctx), commit: NOOP_COMMIT };
1357
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1358
+ const tr3 = triviaP.parse(input, cur, {
1359
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1360
+ state: ctx.state
1361
+ });
1362
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1363
+ const end = tr3.span.end;
1364
+ return {
1365
+ end,
1366
+ commit: () => {
1367
+ pushTriviaLogEntry(ctx, cur, end);
1368
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1369
+ }
1370
+ };
1475
1371
  }
1372
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1373
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1476
1374
  }
1477
- return false;
1478
- }
1479
- function getCoreLiteralValue(p) {
1480
- const def = p._def;
1481
- if (def.tag === "literal" && !def.caseInsensitive) return def.value;
1482
- if (def.tag === "transform") return getCoreLiteralValue(def.parser);
1483
- return null;
1484
- }
1485
- function getCoreRegexDef(p) {
1486
- const def = p._def;
1487
- if (def.tag === "regex") return { source: def.source, flags: def.flags };
1488
- if (def.tag === "transform") return getCoreRegexDef(def.parser);
1489
- if (def.tag === "label") return getCoreRegexDef(def.parser);
1490
- return null;
1491
- }
1492
- function applyTransforms(p, value, span) {
1493
- const def = p._def;
1494
- if (def.tag === "transform") {
1495
- const inner = applyTransforms(def.parser, value, span);
1496
- return def.fn(inner, span);
1375
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1376
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1377
+ if (fast && log === void 0 && !captureTl) {
1378
+ const end = fast(input, cur);
1379
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1380
+ return { end, commit: NOOP_COMMIT };
1497
1381
  }
1498
- return value;
1499
- }
1500
- function continuationFirstSet(lit, source, flags) {
1501
- const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
1502
- re.lastIndex = 0;
1503
- const base = re.exec(lit);
1504
- if (!base || base[0] !== lit) return null;
1505
- const contCodes = [];
1506
- for (let code = 1; code < 128; code++) {
1507
- re.lastIndex = 0;
1508
- const m = re.exec(lit + String.fromCharCode(code));
1509
- if (m && m[0].length > lit.length) contCodes.push(code);
1382
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1383
+ const scan = scanWithLabels(input, cur, ctx);
1384
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1385
+ return scan;
1510
1386
  }
1511
- if (contCodes.length === 0) return null;
1512
- return codesToFirstSet(contCodes);
1513
- }
1514
- function codesToFirstSet(codes) {
1515
- codes.sort((a, b) => a - b);
1516
- const ranges = [];
1517
- let lo = codes[0], hi = codes[0];
1518
- for (let i = 1; i < codes.length; i++) {
1519
- if (codes[i] === hi + 1) {
1520
- hi = codes[i];
1521
- } else {
1522
- ranges.push({ lo, hi });
1523
- lo = hi = codes[i];
1524
- }
1387
+ if (ctx.triviaKindLabels) {
1388
+ const end = skipWithLabels(input, cur, ctx);
1389
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1390
+ return { end, commit: NOOP_COMMIT };
1525
1391
  }
1526
- ranges.push({ lo, hi });
1527
- return { kind: "ranges", ranges };
1392
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1393
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1394
+ if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1395
+ const end = tr2.span.end;
1396
+ return {
1397
+ end,
1398
+ commit: () => {
1399
+ pushTriviaLogEntry(ctx, cur, end);
1400
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1401
+ }
1402
+ };
1403
+ }
1404
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1405
+ return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1528
1406
  }
1529
- function inFirstSet(code, fs2) {
1530
- if (fs2.kind === "any") return true;
1531
- if (fs2.kind === "empty") return false;
1532
- for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
1533
- return false;
1407
+ function consumeTrivia(input, cur, ctx) {
1408
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1409
+ const scan = scanTrivia(input, cur, ctx);
1410
+ scan.commit();
1411
+ return scan.end;
1534
1412
  }
1535
- function areDisjoint(sets) {
1536
- if (sets.some((s) => s.kind === "any")) return false;
1537
- for (let i = 0; i < sets.length; i++)
1538
- for (let j = i + 1; j < sets.length; j++)
1539
- if (intersects(sets[i], sets[j])) return false;
1540
- return true;
1413
+ function fastTriviaScanner(trivia2) {
1414
+ const cached = fastTriviaCache.get(trivia2);
1415
+ if (cached !== void 0) return cached;
1416
+ const scanner = buildFastTriviaScanner(trivia2);
1417
+ fastTriviaCache.set(trivia2, scanner);
1418
+ return scanner;
1541
1419
  }
1542
- function buildAsciiDispatch(parsers) {
1543
- const table = Array(128).fill(-1);
1544
- for (let i = 0; i < parsers.length; i++) {
1545
- const fs2 = parsers[i]._meta.firstSet;
1546
- if (fs2.kind !== "ranges") continue;
1547
- for (const { lo, hi } of fs2.ranges) {
1548
- for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1549
- table[code] = i;
1420
+ function buildFastTriviaScanner(trivia2) {
1421
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1422
+ const direct = regexTriviaScanner(core);
1423
+ if (direct) return direct;
1424
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1425
+ if (!repeat) return null;
1426
+ const one = regexTriviaScanner(repeat);
1427
+ if (one) return loopScanner([one]);
1428
+ if (repeat._def.tag !== "choice") return null;
1429
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1430
+ if (arms.some((s) => s === null)) return null;
1431
+ return loopScanner(arms);
1432
+ }
1433
+ function loopScanner(arms) {
1434
+ return (input, cur) => {
1435
+ let pos = cur;
1436
+ scan: while (pos < input.length) {
1437
+ for (const arm of arms) {
1438
+ const end = arm(input, pos);
1439
+ if (end > pos) {
1440
+ pos = end;
1441
+ continue scan;
1442
+ }
1550
1443
  }
1444
+ break;
1551
1445
  }
1552
- }
1553
- return table;
1554
- }
1555
-
1556
- // src/cst/trivia-kinds.ts
1557
- function unwrapTrivia(p) {
1558
- let cur = p;
1559
- while (cur._def.tag === "trivia") cur = cur._def.parser;
1560
- return cur;
1446
+ return pos;
1447
+ };
1561
1448
  }
1562
- function peelLabel(p) {
1563
- if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1564
- return null;
1449
+ function regexTriviaScanner(parser2) {
1450
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1451
+ const source = parser2._def.source;
1452
+ return classRunSource(source) ?? altStarSource(source);
1565
1453
  }
1566
- function analyzeLabeledTrivia(trivia2) {
1567
- let core = unwrapTrivia(trivia2);
1568
- let minRepeats = 1;
1569
- if (core._def.tag === "oneOrMore") {
1570
- core = core._def.parser;
1571
- minRepeats = 1;
1572
- } else if (core._def.tag === "many") {
1573
- core = core._def.parser;
1574
- minRepeats = 0;
1575
- }
1576
- const arms = [];
1577
- if (core._def.tag === "choice") {
1578
- for (let i = 0; i < core._def.parsers.length; i++) {
1579
- const peeled = peelLabel(core._def.parsers[i]);
1580
- if (!peeled) return null;
1581
- arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1582
- }
1583
- } else {
1584
- const peeled = peelLabel(core);
1585
- if (!peeled) return null;
1586
- arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1454
+ function inRanges2(cp, ranges) {
1455
+ for (let i = 0; i < ranges.length; i++) {
1456
+ const r = ranges[i];
1457
+ if (cp >= r[0] && cp <= r[1]) return true;
1587
1458
  }
1588
- return { labels: arms.map((a) => a.label), arms, minRepeats };
1459
+ return false;
1589
1460
  }
1590
- function matchArmAt(input, pos, arm) {
1591
- const r = arm.parse(input, pos, { trackLines: false });
1592
- if (!r.ok || r.span.end <= pos) return null;
1593
- return { end: r.span.end };
1461
+ function classScanner(classBody) {
1462
+ const ranges = parseClassRanges(classBody);
1463
+ if (!ranges) return null;
1464
+ return (input, cur) => {
1465
+ let pos = cur;
1466
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1467
+ return pos;
1468
+ };
1594
1469
  }
1595
- function scanLabeledTriviaChunks(input, cur, spec) {
1596
- const chunks = [];
1597
- let pos = cur;
1598
- while (pos < input.length) {
1599
- let matched = null;
1600
- for (const arm of spec.arms) {
1601
- const m = matchArmAt(input, pos, arm.parser);
1602
- if (m) {
1603
- matched = { end: m.end, kindIndex: arm.kindIndex };
1604
- break;
1605
- }
1470
+ function untilLineBreakScanner(leaderCode) {
1471
+ return (input, cur) => {
1472
+ if (input.charCodeAt(cur) !== leaderCode) return cur;
1473
+ let pos = cur + 1;
1474
+ while (pos < input.length) {
1475
+ const cc = input.charCodeAt(pos);
1476
+ if (cc === 10 || cc === 13) break;
1477
+ pos++;
1606
1478
  }
1607
- if (!matched) break;
1608
- chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1609
- pos = matched.end;
1479
+ return pos;
1480
+ };
1481
+ }
1482
+ function classRunSource(source) {
1483
+ const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1484
+ return m ? classScanner(m[1]) : null;
1485
+ }
1486
+ function classifyTriviaArm(arm) {
1487
+ const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1488
+ if (cls) {
1489
+ const ranges = parseClassRanges(cls[1]);
1490
+ return ranges ? { kind: "class", ranges } : null;
1610
1491
  }
1611
- if (chunks.length < spec.minRepeats) {
1612
- return { end: cur, chunks: [] };
1492
+ const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1493
+ if (lc) {
1494
+ const marker = lc[1];
1495
+ return { kind: "untilLineBreak", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1613
1496
  }
1614
- return { end: pos, chunks };
1615
- }
1616
- function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1617
- const chunks = [];
1618
- let pos = cur;
1619
- while (pos < input.length) {
1620
- const c = input.charCodeAt(pos);
1621
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1622
- const start = pos;
1623
- pos++;
1624
- while (pos < input.length) {
1625
- const c2 = input.charCodeAt(pos);
1626
- if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1627
- else break;
1628
- }
1629
- chunks.push({ start, end: pos, kindIndex: wsKind });
1630
- continue;
1631
- }
1632
- if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1633
- let j = pos + 2;
1634
- while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
1635
- if (j + 1 < input.length && input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47) {
1636
- const start = pos;
1637
- pos = j + 2;
1638
- chunks.push({ start, end: pos, kindIndex: commentKind });
1639
- continue;
1640
- }
1641
- break;
1642
- }
1643
- break;
1644
- }
1645
- return { end: pos, chunks };
1646
- }
1647
- function tryFastLabeledScan(input, cur, trivia2) {
1648
- const spec = analyzeLabeledTrivia(trivia2);
1649
- if (!spec || spec.arms.length !== 2) return null;
1650
- const wsArm = spec.arms.find((a) => {
1651
- const src = getCoreRegexDef(a.parser)?.source;
1652
- return src != null && !src.includes("\\*");
1653
- });
1654
- const commentArm = spec.arms.find((a) => {
1655
- const src = getCoreRegexDef(a.parser)?.source;
1656
- return src != null && src.includes("\\*");
1657
- });
1658
- if (!wsArm || !commentArm) return null;
1659
- const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1660
- if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1661
- return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1662
- }
1663
- function recordTriviaChunks(ctx, chunks) {
1664
- const kinds = ctx.triviaKindLabels;
1665
- const mask = ctx._triviaCaptureMask;
1666
- for (const ch2 of chunks) {
1667
- pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1668
- if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1669
- if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1670
- pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1671
- }
1672
- }
1673
- }
1674
- }
1675
- function triviaKindMask(labels, keep) {
1676
- if (!labels) return void 0;
1677
- let mask = 0;
1678
- for (const name of keep) {
1679
- const idx = labels.indexOf(name);
1680
- if (idx >= 0) mask |= 1 << idx;
1681
- }
1682
- return mask;
1683
- }
1684
-
1685
- // src/combinators/trivia-skip.ts
1686
- var NOOP_COMMIT = () => {
1687
- };
1688
- var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1689
- function needsDeferredTriviaCommit(ctx) {
1690
- return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1691
- }
1692
- function saveTriviaMark(ctx) {
1693
- const m = saveCstMark(ctx);
1694
- return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
1695
- }
1696
- function rollbackTrivia(ctx, mark) {
1697
- rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1698
- if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1699
- }
1700
- function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1701
- const probeCtx = {
1702
- trackLines: ctx.trackLines,
1703
- state: ctx.state,
1704
- ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1705
- ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1706
- ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1707
- };
1708
- const result = triviaP.parse(input, cur, probeCtx);
1709
- ctx._lineScannedTo = probeCtx._lineScannedTo;
1710
- return result;
1711
- }
1712
- function saveLookaheadMark(ctx) {
1713
- return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1714
- }
1715
- function rollbackLookahead(ctx, mark) {
1716
- rollbackTrivia(ctx, mark);
1717
- if (ctx._probe) ctx._probe.best = mark.probeBest;
1718
- }
1719
- function scanWithLabels(input, cur, ctx) {
1720
- const triviaP = ctx.trivia;
1721
- const spec = analyzeLabeledTrivia(triviaP);
1722
- if (!spec) return { end: cur, commit: NOOP_COMMIT };
1723
- const fast = tryFastLabeledScan(input, cur, triviaP);
1724
- const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
1725
- if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1726
- return {
1727
- end,
1728
- commit: () => recordTriviaChunks(ctx, chunks)
1729
- };
1730
- }
1731
- function advanceTrivia(input, cur, ctx) {
1732
- const triviaP = ctx.trivia;
1733
- if (!triviaP) return cur;
1734
- if (!ctx.trackLines) {
1735
- const fast2 = fastTriviaScanner(triviaP);
1736
- if (fast2) return fast2(input, cur);
1737
- if (ctx.triviaKindLabels) {
1738
- const scan = scanWithLabels(input, cur, ctx);
1739
- return scan.end;
1740
- }
1741
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1742
- return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1743
- }
1744
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1745
- const fast = fastTriviaScanner(triviaP);
1746
- if (fast) {
1747
- const end = fast(input, cur);
1748
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1749
- return end;
1750
- }
1751
- if (ctx.triviaKindLabels) {
1752
- const scan = scanWithLabels(input, cur, ctx);
1753
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1754
- return scan.end;
1755
- }
1756
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1757
- return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1758
- }
1759
- function scanTrivia(input, cur, ctx) {
1760
- const triviaP = ctx.trivia;
1761
- if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1762
- const log = ctx._triviaLog;
1763
- const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1764
- if (!ctx.trackLines) {
1765
- const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1766
- if (fast2 && log === void 0 && !captureTl) {
1767
- return { end: fast2(input, cur), commit: NOOP_COMMIT };
1768
- }
1769
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1770
- return scanWithLabels(input, cur, ctx);
1771
- }
1772
- if (log !== void 0 || captureTl) {
1773
- const tr3 = triviaP.parse(input, cur, {
1774
- trackLines: log !== void 0 ? false : ctx.trackLines,
1775
- state: ctx.state
1776
- });
1777
- if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1778
- const end = tr3.span.end;
1779
- return {
1780
- end,
1781
- commit: () => {
1782
- pushTriviaLogEntry(ctx, cur, end);
1783
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1784
- }
1785
- };
1786
- }
1787
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1788
- return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1789
- }
1790
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1791
- const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1792
- if (fast && log === void 0 && !captureTl) {
1793
- const end = fast(input, cur);
1794
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1795
- return { end, commit: NOOP_COMMIT };
1796
- }
1797
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1798
- const scan = scanWithLabels(input, cur, ctx);
1799
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1800
- return scan;
1801
- }
1802
- if (log !== void 0 || captureTl) {
1803
- const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1804
- if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1805
- const end = tr2.span.end;
1806
- return {
1807
- end,
1808
- commit: () => {
1809
- pushTriviaLogEntry(ctx, cur, end);
1810
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1811
- }
1812
- };
1813
- }
1814
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1815
- return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1816
- }
1817
- function consumeTrivia(input, cur, ctx) {
1818
- if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1819
- const scan = scanTrivia(input, cur, ctx);
1820
- scan.commit();
1821
- return scan.end;
1822
- }
1823
- function fastTriviaScanner(trivia2) {
1824
- const cached = fastTriviaCache.get(trivia2);
1825
- if (cached !== void 0) return cached;
1826
- const scanner = buildFastTriviaScanner(trivia2);
1827
- fastTriviaCache.set(trivia2, scanner);
1828
- return scanner;
1829
- }
1830
- function buildFastTriviaScanner(trivia2) {
1831
- const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1832
- const direct = regexTriviaScanner(core);
1833
- if (direct) return direct;
1834
- const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1835
- if (!repeat) return null;
1836
- const one = regexTriviaScanner(repeat);
1837
- if (one) return loopScanner([one]);
1838
- if (repeat._def.tag !== "choice") return null;
1839
- const arms = repeat._def.parsers.map(regexTriviaScanner);
1840
- if (arms.some((s) => s === null)) return null;
1841
- return loopScanner(arms);
1842
- }
1843
- function loopScanner(arms) {
1844
- return (input, cur) => {
1845
- let pos = cur;
1846
- scan: while (pos < input.length) {
1847
- for (const arm of arms) {
1848
- const end = arm(input, pos);
1849
- if (end > pos) {
1850
- pos = end;
1851
- continue scan;
1852
- }
1853
- }
1854
- break;
1855
- }
1856
- return pos;
1857
- };
1858
- }
1859
- function regexTriviaScanner(parser2) {
1860
- if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1861
- const source = parser2._def.source;
1862
- return classRunSource(source) ?? altStarSource(source) ?? (blockCommentSource(source) ? scanBlockComment : null);
1863
- }
1864
- function inRanges2(cp, ranges) {
1865
- for (let i = 0; i < ranges.length; i++) {
1866
- const r = ranges[i];
1867
- if (cp >= r[0] && cp <= r[1]) return true;
1868
- }
1869
- return false;
1870
- }
1871
- function classScanner(classBody) {
1872
- const ranges = parseClassRanges(classBody);
1873
- if (!ranges) return null;
1874
- return (input, cur) => {
1875
- let pos = cur;
1876
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1877
- return pos;
1878
- };
1879
- }
1880
- function lineCommentScanner(commentCode) {
1881
- return (input, cur) => {
1882
- if (input.charCodeAt(cur) !== commentCode) return cur;
1883
- let pos = cur + 1;
1884
- while (pos < input.length) {
1885
- const cc = input.charCodeAt(pos);
1886
- if (cc === 10 || cc === 13) break;
1887
- pos++;
1888
- }
1889
- return pos;
1890
- };
1891
- }
1892
- function classRunSource(source) {
1893
- const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1894
- return m ? classScanner(m[1]) : null;
1895
- }
1896
- function classifyTriviaArm(arm) {
1897
- const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1898
- if (cls) {
1899
- const ranges = parseClassRanges(cls[1]);
1900
- return ranges ? { kind: "class", ranges } : null;
1901
- }
1902
- const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1903
- if (lc) {
1904
- const marker = lc[1];
1905
- return { kind: "comment", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1906
- }
1907
- return null;
1497
+ return null;
1908
1498
  }
1909
1499
  function armScanner(arm) {
1910
- if (arm.kind === "comment") return lineCommentScanner(arm.code);
1500
+ if (arm.kind === "untilLineBreak") return untilLineBreakScanner(arm.code);
1911
1501
  const ranges = arm.ranges;
1912
1502
  return (input, cur) => {
1913
1503
  let pos = cur;
@@ -1915,9 +1505,9 @@ function armScanner(arm) {
1915
1505
  return pos;
1916
1506
  };
1917
1507
  }
1918
- function fusedTriviaScanner(ranges, commentCodes) {
1919
- const c0 = commentCodes[0];
1920
- const single = commentCodes.length === 1;
1508
+ function fusedTriviaScanner(ranges, leaders) {
1509
+ const c0 = leaders[0];
1510
+ const single = leaders.length === 1;
1921
1511
  return (input, cur) => {
1922
1512
  let pos = cur;
1923
1513
  const len = input.length;
@@ -1927,7 +1517,7 @@ function fusedTriviaScanner(ranges, commentCodes) {
1927
1517
  pos++;
1928
1518
  continue;
1929
1519
  }
1930
- if (single ? c === c0 : commentCodes.includes(c)) {
1520
+ if (single ? c === c0 : leaders.includes(c)) {
1931
1521
  pos++;
1932
1522
  while (pos < len) {
1933
1523
  const cc = input.charCodeAt(pos);
@@ -1936,166 +1526,640 @@ function fusedTriviaScanner(ranges, commentCodes) {
1936
1526
  }
1937
1527
  continue;
1938
1528
  }
1939
- break;
1529
+ break;
1530
+ }
1531
+ return pos;
1532
+ };
1533
+ }
1534
+ function splitTopLevelAlts(body) {
1535
+ const arms = [];
1536
+ let inClass = false;
1537
+ let start = 0;
1538
+ for (let i = 0; i < body.length; i++) {
1539
+ const c = body[i];
1540
+ if (c === "\\") {
1541
+ i++;
1542
+ continue;
1543
+ }
1544
+ if (inClass) {
1545
+ if (c === "]") inClass = false;
1546
+ continue;
1547
+ }
1548
+ if (c === "[") inClass = true;
1549
+ else if (c === "(") return null;
1550
+ else if (c === "|") {
1551
+ arms.push(body.slice(start, i));
1552
+ start = i + 1;
1553
+ }
1554
+ }
1555
+ arms.push(body.slice(start));
1556
+ return arms;
1557
+ }
1558
+ function altStarSource(source) {
1559
+ const m = /^\(\?:(.*)\)[*+]$/.exec(source);
1560
+ if (!m) return null;
1561
+ const armSrcs = splitTopLevelAlts(m[1]);
1562
+ if (!armSrcs || armSrcs.length < 2) return null;
1563
+ const arms = [];
1564
+ for (const src of armSrcs) {
1565
+ const arm = classifyTriviaArm(src);
1566
+ if (!arm) return null;
1567
+ arms.push(arm);
1568
+ }
1569
+ const ranges = [];
1570
+ const leaders = [];
1571
+ for (const arm of arms) {
1572
+ if (arm.kind === "class") ranges.push(...arm.ranges);
1573
+ else leaders.push(arm.code);
1574
+ }
1575
+ if (leaders.some((code) => inRanges2(code, ranges))) {
1576
+ return loopScanner(arms.map(armScanner));
1577
+ }
1578
+ if (leaders.length === 0) return armScanner({ kind: "class", ranges });
1579
+ return fusedTriviaScanner(ranges, leaders);
1580
+ }
1581
+
1582
+ // src/recovery/scan.ts
1583
+ function probeAt(sentinel, input, pos, ctx) {
1584
+ const s = {
1585
+ _probe: ctx._probe,
1586
+ _errors: ctx._errors,
1587
+ _cstLeaves: ctx._cstLeaves,
1588
+ _cstChildren: ctx._cstChildren,
1589
+ _cstRawChildren: ctx._cstRawChildren,
1590
+ _cstTriviaLog: ctx._cstTriviaLog,
1591
+ _triviaLog: ctx._triviaLog,
1592
+ _rootTriviaLog: ctx._rootTriviaLog,
1593
+ _fields: ctx._fields,
1594
+ _cstBuf: ctx._cstBuf,
1595
+ _tolerant: ctx._tolerant,
1596
+ _sync: ctx._sync
1597
+ };
1598
+ ctx._probe = void 0;
1599
+ ctx._errors = void 0;
1600
+ ctx._cstLeaves = void 0;
1601
+ ctx._cstChildren = void 0;
1602
+ ctx._cstRawChildren = void 0;
1603
+ ctx._cstTriviaLog = void 0;
1604
+ ctx._triviaLog = void 0;
1605
+ ctx._rootTriviaLog = void 0;
1606
+ ctx._fields = void 0;
1607
+ ctx._cstBuf = void 0;
1608
+ ctx._tolerant = void 0;
1609
+ ctx._sync = void 0;
1610
+ try {
1611
+ return sentinel.parse(input, pos, ctx).ok;
1612
+ } finally {
1613
+ ctx._probe = s._probe;
1614
+ ctx._errors = s._errors;
1615
+ ctx._cstLeaves = s._cstLeaves;
1616
+ ctx._cstChildren = s._cstChildren;
1617
+ ctx._cstRawChildren = s._cstRawChildren;
1618
+ ctx._cstTriviaLog = s._cstTriviaLog;
1619
+ ctx._triviaLog = s._triviaLog;
1620
+ ctx._rootTriviaLog = s._rootTriviaLog;
1621
+ ctx._fields = s._fields;
1622
+ ctx._cstBuf = s._cstBuf;
1623
+ ctx._tolerant = s._tolerant;
1624
+ ctx._sync = s._sync;
1625
+ }
1626
+ }
1627
+ function orSentinel(a, b) {
1628
+ if (b === void 0) return a;
1629
+ return {
1630
+ _tag: "orSentinel",
1631
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1632
+ _def: { tag: "unknown" },
1633
+ parse(input, pos, ctx) {
1634
+ const ra = a.parse(input, pos, ctx);
1635
+ if (ra.ok) return ra;
1636
+ return b.parse(input, pos, ctx);
1637
+ }
1638
+ };
1639
+ }
1640
+ function firstSetSentinel(fs2) {
1641
+ if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
1642
+ const ranges = fs2.ranges;
1643
+ return {
1644
+ _tag: "firstSetSentinel",
1645
+ _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
1646
+ _def: { tag: "unknown" },
1647
+ parse(input, pos) {
1648
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
1649
+ if (code !== void 0) {
1650
+ for (const r of ranges) {
1651
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1652
+ }
1653
+ }
1654
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
1655
+ }
1656
+ };
1657
+ }
1658
+ function recoverScan(input, from, ctx, sync, expected) {
1659
+ let scanPos = from;
1660
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1661
+ const span = { start: from, end: scanPos };
1662
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1663
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1664
+ ctx._errors?.push(error);
1665
+ return { error, end: scanPos };
1666
+ }
1667
+ function matchesAt(sentinel, input, pos, ctx) {
1668
+ return probeAt(sentinel, input, pos, ctx);
1669
+ }
1670
+ function captureError(ctx, error) {
1671
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1672
+ }
1673
+
1674
+ // src/combinators/sequence.ts
1675
+ function sequence(...parsers) {
1676
+ const meta = {
1677
+ // Union through the nullable prefix — a leading optional()/many() lets a later
1678
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
1679
+ firstSet: sequenceFirstSet(parsers),
1680
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1681
+ isTrivia: false
1682
+ };
1683
+ const def = { tag: "sequence", parsers };
1684
+ let followSentinels;
1685
+ function parseTolerant(input, pos, ctx) {
1686
+ followSentinels ??= parsers.map((_, i) => {
1687
+ const fs2 = parsers.slice(i + 1).reduce(
1688
+ (acc, p) => union(acc, firstSetOf(p)),
1689
+ { kind: "empty" }
1690
+ );
1691
+ return firstSetSentinel(fs2);
1692
+ });
1693
+ const values = def.valueUnused ? void 0 : [];
1694
+ let cur = pos;
1695
+ const inheritedSync = ctx._sync;
1696
+ try {
1697
+ for (let i = 0; i < parsers.length; i++) {
1698
+ ctx._sync = followSentinels[i] ?? inheritedSync;
1699
+ if (ctx.trivia && i > 0) {
1700
+ const mark = saveTriviaMark(ctx);
1701
+ let scanEnd;
1702
+ if (needsDeferredTriviaCommit(ctx)) {
1703
+ const scan = scanTrivia(input, cur, ctx);
1704
+ scan.commit();
1705
+ scanEnd = scan.end;
1706
+ } else {
1707
+ scanEnd = advanceTrivia(input, cur, ctx);
1708
+ }
1709
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1710
+ if (!result2.ok) return result2;
1711
+ if (result2.span.end > scanEnd) cur = result2.span.end;
1712
+ else rollbackTrivia(ctx, mark);
1713
+ if (values !== void 0) values.push(result2.value);
1714
+ continue;
1715
+ }
1716
+ const result = parsers[i].parse(input, cur, ctx);
1717
+ if (!result.ok) return result;
1718
+ if (values !== void 0) values.push(result.value);
1719
+ cur = result.span.end;
1720
+ }
1721
+ } finally {
1722
+ ctx._sync = inheritedSync;
1723
+ }
1724
+ return {
1725
+ ok: true,
1726
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1727
+ value: values ?? void 0,
1728
+ span: { start: pos, end: cur }
1729
+ };
1730
+ }
1731
+ return {
1732
+ _tag: "sequence",
1733
+ _meta: meta,
1734
+ _def: def,
1735
+ parse(input, pos, ctx) {
1736
+ if (ctx._tolerant) return parseTolerant(input, pos, ctx);
1737
+ const values = def.valueUnused ? void 0 : [];
1738
+ let cur = pos;
1739
+ for (let i = 0; i < parsers.length; i++) {
1740
+ if (ctx.trivia && i > 0) {
1741
+ let scanEnd;
1742
+ let mark = saveTriviaMark(ctx);
1743
+ if (needsDeferredTriviaCommit(ctx)) {
1744
+ const scan = scanTrivia(input, cur, ctx);
1745
+ scan.commit();
1746
+ scanEnd = scan.end;
1747
+ } else {
1748
+ scanEnd = advanceTrivia(input, cur, ctx);
1749
+ }
1750
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1751
+ if (!result2.ok) return result2;
1752
+ if (result2.span.end > scanEnd) {
1753
+ cur = result2.span.end;
1754
+ } else {
1755
+ rollbackTrivia(ctx, mark);
1756
+ }
1757
+ if (values !== void 0) values.push(result2.value);
1758
+ continue;
1759
+ }
1760
+ const result = parsers[i].parse(input, cur, ctx);
1761
+ if (!result.ok) return result;
1762
+ if (values !== void 0) values.push(result.value);
1763
+ cur = result.span.end;
1764
+ }
1765
+ return {
1766
+ ok: true,
1767
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1768
+ value: values ?? void 0,
1769
+ span: { start: pos, end: cur }
1770
+ };
1771
+ }
1772
+ };
1773
+ }
1774
+
1775
+ // src/combinators/expect.ts
1776
+ function deriveExpected(c) {
1777
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1778
+ }
1779
+ function derive(c, seen) {
1780
+ const deriveExpected2 = (p) => derive(p, seen);
1781
+ const def = c._def;
1782
+ switch (def.tag) {
1783
+ case "literal":
1784
+ return [JSON.stringify(def.value)];
1785
+ case "regex":
1786
+ return [`/${def.source}/`];
1787
+ case "keywords":
1788
+ return def.words.map((w) => JSON.stringify(w));
1789
+ case "label":
1790
+ return [def.label];
1791
+ case "choice":
1792
+ return def.parsers.flatMap(deriveExpected2);
1793
+ case "dispatch":
1794
+ return deriveExpected2(def.selector);
1795
+ // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1796
+ // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1797
+ // able to fail first — deriving from term 0 alone named a token the parse
1798
+ // never actually required. A leading `not(…)` is zero-width and contributes
1799
+ // nothing (its own expectation is about what must NOT be here), but it is
1800
+ // nullable, so keep scanning past it. Stop at the first term that must match.
1801
+ case "sequence": {
1802
+ const out = [];
1803
+ for (const term of def.parsers) {
1804
+ if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1805
+ if (!matchesEmpty(term)) break;
1806
+ }
1807
+ return out;
1808
+ }
1809
+ case "attempt":
1810
+ return deriveExpected2(def.parser);
1811
+ // Delegating wrappers whose first-token failure is their inner parser's — must
1812
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1813
+ // node, which reads this) names the real expected token, not the wrapper tag.
1814
+ case "field":
1815
+ case "withCtx":
1816
+ case "recover":
1817
+ return deriveExpected2(def.parser);
1818
+ case "skip":
1819
+ return deriveExpected2(def.main);
1820
+ case "expect":
1821
+ return def.expected;
1822
+ case "node":
1823
+ case "grammar":
1824
+ case "trivia":
1825
+ case "token":
1826
+ case "leaf":
1827
+ case "optional":
1828
+ case "many":
1829
+ case "oneOrMore":
1830
+ case "transform":
1831
+ case "not":
1832
+ case "peek":
1833
+ return deriveExpected2(def.parser);
1834
+ case "routed":
1835
+ return ["routed()"];
1836
+ case "lazy": {
1837
+ const name = c._ruleName;
1838
+ if (seen.has(c)) return name ? [name] : [];
1839
+ seen.add(c);
1840
+ try {
1841
+ return deriveExpected2(def.thunk());
1842
+ } catch {
1843
+ return name ? [name] : [];
1844
+ } finally {
1845
+ seen.delete(c);
1846
+ }
1847
+ }
1848
+ default:
1849
+ return [];
1850
+ }
1851
+ }
1852
+ function expect(combinator, label2) {
1853
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1854
+ const meta = {
1855
+ firstSet: combinator._meta.firstSet,
1856
+ canMatchNewline: combinator._meta.canMatchNewline,
1857
+ isTrivia: false
1858
+ };
1859
+ return {
1860
+ _tag: "expect",
1861
+ _meta: meta,
1862
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
1863
+ parse(input, pos, ctx) {
1864
+ const result = combinator.parse(input, pos, ctx);
1865
+ if (result.ok) return result;
1866
+ const span = { start: pos, end: pos };
1867
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1868
+ ctx._errors?.push(error);
1869
+ if (ctx._tolerant) captureError(ctx, error);
1870
+ return { ok: true, value: error, span: { start: pos, end: pos } };
1871
+ }
1872
+ };
1873
+ }
1874
+
1875
+ // src/combinators/choice.ts
1876
+ function choice(...args) {
1877
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1878
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
1879
+ const hasGates = gates.some((g) => g !== null);
1880
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1881
+ let combined = { kind: "empty" };
1882
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
1883
+ const meta = {
1884
+ firstSet: combined,
1885
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1886
+ isTrivia: false,
1887
+ disjoint
1888
+ };
1889
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1890
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1891
+ let greedyLitMap = null;
1892
+ let sortedParsers = null;
1893
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1894
+ if (strategy?.tag === "greedyClassify") {
1895
+ greedyLitMap = /* @__PURE__ */ new Map();
1896
+ for (let i = 0; i < parsers.length; i++) {
1897
+ if (i === strategy.superIndex) continue;
1898
+ const litVal = getCoreLiteralValue(parsers[i]);
1899
+ if (litVal !== null) greedyLitMap.set(litVal, i);
1900
+ }
1901
+ } else if (strategy?.tag === "literalsLongestFirst") {
1902
+ sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
1903
+ }
1904
+ return {
1905
+ _tag: "choice",
1906
+ _meta: meta,
1907
+ _def: {
1908
+ tag: "choice",
1909
+ parsers,
1910
+ gates,
1911
+ disjoint,
1912
+ strategy: strategy ?? { tag: "firstMatch" },
1913
+ autoNot
1914
+ },
1915
+ parse(input, pos, ctx) {
1916
+ const expected = [];
1917
+ if (disjoint && pos < input.length) {
1918
+ const code = input.codePointAt(pos);
1919
+ let idx = code < 128 ? asciiDispatch[code] : -1;
1920
+ if (idx < 0) {
1921
+ for (let i = 0; i < parsers.length; i++) {
1922
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1923
+ idx = i;
1924
+ break;
1925
+ }
1926
+ }
1927
+ }
1928
+ if (idx >= 0) {
1929
+ const gate2 = gates[idx];
1930
+ if (gate2 && !gate2(ctx.state)) {
1931
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1932
+ }
1933
+ const result = parsers[idx].parse(input, pos, ctx);
1934
+ if (result.ok) return result;
1935
+ expected.push(...result.expected);
1936
+ if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1937
+ return { ok: false, expected, span: { start: pos, end: pos } };
1938
+ }
1939
+ return {
1940
+ ok: false,
1941
+ expected: parsers.flatMap((p) => {
1942
+ const r = p.parse(input, pos, ctx);
1943
+ return r.ok ? [] : r.expected;
1944
+ }),
1945
+ span: { start: pos, end: pos }
1946
+ };
1947
+ }
1948
+ if (strategy?.tag === "greedyClassify") {
1949
+ const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1950
+ if (!superResult.ok) return superResult;
1951
+ const end = superResult.span.end;
1952
+ const litIdx = greedyLitMap.get(input.slice(pos, end));
1953
+ if (litIdx !== void 0) {
1954
+ const litVal = getCoreLiteralValue(parsers[litIdx]);
1955
+ const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1956
+ return { ok: true, value, span: { start: pos, end } };
1957
+ }
1958
+ return superResult;
1959
+ }
1960
+ if (strategy?.tag === "literalsLongestFirst") {
1961
+ for (const p of sortedParsers) {
1962
+ const r = p.parse(input, pos, ctx);
1963
+ if (r.ok) return r;
1964
+ expected.push(...r.expected);
1965
+ }
1966
+ return { ok: false, expected, span: { start: pos, end: pos } };
1967
+ }
1968
+ for (let i = 0; i < parsers.length; i++) {
1969
+ if (gates[i] && !gates[i](ctx.state)) continue;
1970
+ const mark = saveTriviaMark(ctx);
1971
+ const result = parsers[i].parse(input, pos, ctx);
1972
+ if (!result.ok) {
1973
+ rollbackTrivia(ctx, mark);
1974
+ expected.push(...result.expected);
1975
+ if (result.committed) return { ok: false, expected, span: result.span, committed: true };
1976
+ continue;
1977
+ }
1978
+ const checks = autoNot[i];
1979
+ if (checks && autoNotFires(input, result.span.end, checks)) {
1980
+ rollbackTrivia(ctx, mark);
1981
+ continue;
1982
+ }
1983
+ return result;
1984
+ }
1985
+ return { ok: false, expected, span: { start: pos, end: pos } };
1986
+ }
1987
+ };
1988
+ }
1989
+ function detectStrategy(parsers) {
1990
+ const regexIndices = [];
1991
+ const literalIndices = [];
1992
+ for (let i = 0; i < parsers.length; i++) {
1993
+ if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
1994
+ else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
1995
+ }
1996
+ if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
1997
+ const superIndex = regexIndices[0];
1998
+ const regexDef = getCoreRegexDef(parsers[superIndex]);
1999
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
2000
+ const re = new RegExp(regexDef.source, flags);
2001
+ const allSubsumed = literalIndices.every((i) => {
2002
+ const litVal = getCoreLiteralValue(parsers[i]);
2003
+ re.lastIndex = 0;
2004
+ const m = re.exec(litVal);
2005
+ return m !== null && m[0] === litVal;
2006
+ });
2007
+ if (allSubsumed) return { tag: "greedyClassify", superIndex };
2008
+ }
2009
+ if (parsers.length === literalIndices.length) {
2010
+ const sortedIndices = [...literalIndices].sort(
2011
+ (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
2012
+ );
2013
+ return { tag: "literalsLongestFirst", sortedIndices };
2014
+ }
2015
+ const shared = detectSharedPrefix(parsers);
2016
+ if (shared !== null) return shared;
2017
+ return { tag: "firstMatch" };
2018
+ }
2019
+ function bareLeadingTermKey(term) {
2020
+ const d = term._def;
2021
+ if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
2022
+ if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
2023
+ return null;
2024
+ }
2025
+ function detectSharedPrefix(parsers) {
2026
+ if (parsers.length < 2) return null;
2027
+ let key = null;
2028
+ let prefix = null;
2029
+ const members = [];
2030
+ for (let i = 0; i < parsers.length; i++) {
2031
+ const term0 = leadingTermOfArm(parsers[i]);
2032
+ if (term0 === null) return null;
2033
+ const k = bareLeadingTermKey(term0);
2034
+ if (k === null) return null;
2035
+ if (key === null) {
2036
+ key = k;
2037
+ prefix = term0;
2038
+ } else if (k !== key) return null;
2039
+ members.push(i);
2040
+ }
2041
+ if (prefix === null || members.length < 2) return null;
2042
+ return { tag: "sharedPrefix", prefix, members };
2043
+ }
2044
+ function leadingTermOfArm(arm) {
2045
+ let d = arm._def;
2046
+ for (; ; ) {
2047
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
2048
+ d = d.parser._def;
2049
+ continue;
2050
+ }
2051
+ break;
2052
+ }
2053
+ if (d.tag !== "sequence" || d.parsers.length < 2) return null;
2054
+ return d.parsers[0];
2055
+ }
2056
+ function computeAutoNot(parsers) {
2057
+ return parsers.map((p, i) => {
2058
+ const litVal = getCoreLiteralValue(p);
2059
+ if (litVal === null) return null;
2060
+ const checks = [];
2061
+ for (let j = i + 1; j < parsers.length; j++) {
2062
+ const other = parsers[j];
2063
+ const otherLit = getCoreLiteralValue(other);
2064
+ if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
2065
+ checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
2066
+ continue;
2067
+ }
2068
+ const regexDef = getCoreRegexDef(other);
2069
+ if (regexDef !== null) {
2070
+ const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
2071
+ if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
2072
+ }
1940
2073
  }
1941
- return pos;
1942
- };
2074
+ return checks.length > 0 ? checks : null;
2075
+ });
1943
2076
  }
1944
- function splitTopLevelAlts(body) {
1945
- const arms = [];
1946
- let inClass = false;
1947
- let start = 0;
1948
- for (let i = 0; i < body.length; i++) {
1949
- const c = body[i];
1950
- if (c === "\\") {
1951
- i++;
1952
- continue;
1953
- }
1954
- if (inClass) {
1955
- if (c === "]") inClass = false;
1956
- continue;
1957
- }
1958
- if (c === "[") inClass = true;
1959
- else if (c === "(") return null;
1960
- else if (c === "|") {
1961
- arms.push(body.slice(start, i));
1962
- start = i + 1;
2077
+ function autoNotFires(input, end, checks) {
2078
+ for (const check of checks) {
2079
+ if (check.kind === "firstSet") {
2080
+ const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
2081
+ if (inFirstSet(code, check.set)) return true;
2082
+ } else {
2083
+ if (input.startsWith(check.value, end)) return true;
1963
2084
  }
1964
2085
  }
1965
- arms.push(body.slice(start));
1966
- return arms;
2086
+ return false;
1967
2087
  }
1968
- function altStarSource(source) {
1969
- const m = /^\(\?:(.*)\)[*+]$/.exec(source);
1970
- if (!m) return null;
1971
- const armSrcs = splitTopLevelAlts(m[1]);
1972
- if (!armSrcs || armSrcs.length < 2) return null;
1973
- const arms = [];
1974
- for (const src of armSrcs) {
1975
- const arm = classifyTriviaArm(src);
1976
- if (!arm) return null;
1977
- arms.push(arm);
2088
+ function getCoreLiteralValue(p) {
2089
+ const def = p._def;
2090
+ if (def.tag === "literal" && !def.caseInsensitive) return def.value;
2091
+ if (def.tag === "transform") return getCoreLiteralValue(def.parser);
2092
+ return null;
2093
+ }
2094
+ function getCoreRegexDef(p) {
2095
+ const def = p._def;
2096
+ if (def.tag === "regex") return { source: def.source, flags: def.flags };
2097
+ if (def.tag === "transform") return getCoreRegexDef(def.parser);
2098
+ if (def.tag === "label") return getCoreRegexDef(def.parser);
2099
+ return null;
2100
+ }
2101
+ function applyTransforms(p, value, span) {
2102
+ const def = p._def;
2103
+ if (def.tag === "transform") {
2104
+ const inner = applyTransforms(def.parser, value, span);
2105
+ return def.fn(inner, span);
1978
2106
  }
1979
- const ranges = [];
1980
- const commentCodes = [];
1981
- for (const arm of arms) {
1982
- if (arm.kind === "class") ranges.push(...arm.ranges);
1983
- else commentCodes.push(arm.code);
2107
+ return value;
2108
+ }
2109
+ function continuationFirstSet(lit, source, flags) {
2110
+ const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
2111
+ re.lastIndex = 0;
2112
+ const base = re.exec(lit);
2113
+ if (!base || base[0] !== lit) return null;
2114
+ const contCodes = [];
2115
+ for (let code = 1; code < 128; code++) {
2116
+ re.lastIndex = 0;
2117
+ const m = re.exec(lit + String.fromCharCode(code));
2118
+ if (m && m[0].length > lit.length) contCodes.push(code);
1984
2119
  }
1985
- if (commentCodes.some((code) => inRanges2(code, ranges))) {
1986
- return loopScanner(arms.map(armScanner));
2120
+ if (contCodes.length === 0) return null;
2121
+ return codesToFirstSet(contCodes);
2122
+ }
2123
+ function codesToFirstSet(codes) {
2124
+ codes.sort((a, b) => a - b);
2125
+ const ranges = [];
2126
+ let lo = codes[0], hi = codes[0];
2127
+ for (let i = 1; i < codes.length; i++) {
2128
+ if (codes[i] === hi + 1) {
2129
+ hi = codes[i];
2130
+ } else {
2131
+ ranges.push({ lo, hi });
2132
+ lo = hi = codes[i];
2133
+ }
1987
2134
  }
1988
- if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
1989
- return fusedTriviaScanner(ranges, commentCodes);
2135
+ ranges.push({ lo, hi });
2136
+ return { kind: "ranges", ranges };
1990
2137
  }
1991
- function blockCommentSource(source) {
1992
- return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
2138
+ function inFirstSet(code, fs2) {
2139
+ if (fs2.kind === "any") return true;
2140
+ if (fs2.kind === "empty") return false;
2141
+ for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
2142
+ return false;
1993
2143
  }
1994
- function scanBlockComment(input, cur) {
1995
- if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
1996
- const close = input.indexOf("*/", cur + 2);
1997
- return close === -1 ? cur : close + 2;
2144
+ function areDisjoint(sets) {
2145
+ if (sets.some((s) => s.kind === "any")) return false;
2146
+ for (let i = 0; i < sets.length; i++)
2147
+ for (let j = i + 1; j < sets.length; j++)
2148
+ if (intersects(sets[i], sets[j])) return false;
2149
+ return true;
1998
2150
  }
1999
-
2000
- // src/combinators/sequence.ts
2001
- function sequence(...parsers) {
2002
- const meta = {
2003
- // Union through the nullable prefix — a leading optional()/many() lets a later
2004
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
2005
- firstSet: sequenceFirstSet(parsers),
2006
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2007
- isTrivia: false
2008
- };
2009
- const def = { tag: "sequence", parsers };
2010
- let followSentinels;
2011
- function parseTolerant(input, pos, ctx) {
2012
- followSentinels ??= parsers.map((_, i) => {
2013
- const fs2 = parsers.slice(i + 1).reduce(
2014
- (acc, p) => union(acc, firstSetOf(p)),
2015
- { kind: "empty" }
2016
- );
2017
- return firstSetSentinel(fs2);
2018
- });
2019
- const values = def.valueUnused ? void 0 : [];
2020
- let cur = pos;
2021
- const inheritedSync = ctx._sync;
2022
- try {
2023
- for (let i = 0; i < parsers.length; i++) {
2024
- ctx._sync = followSentinels[i] ?? inheritedSync;
2025
- if (ctx.trivia && i > 0) {
2026
- const mark = saveTriviaMark(ctx);
2027
- let scanEnd;
2028
- if (needsDeferredTriviaCommit(ctx)) {
2029
- const scan = scanTrivia(input, cur, ctx);
2030
- scan.commit();
2031
- scanEnd = scan.end;
2032
- } else {
2033
- scanEnd = advanceTrivia(input, cur, ctx);
2034
- }
2035
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2036
- if (!result2.ok) return result2;
2037
- if (result2.span.end > scanEnd) cur = result2.span.end;
2038
- else rollbackTrivia(ctx, mark);
2039
- if (values !== void 0) values.push(result2.value);
2040
- continue;
2041
- }
2042
- const result = parsers[i].parse(input, cur, ctx);
2043
- if (!result.ok) return result;
2044
- if (values !== void 0) values.push(result.value);
2045
- cur = result.span.end;
2151
+ function buildAsciiDispatch(parsers) {
2152
+ const table = Array(128).fill(-1);
2153
+ for (let i = 0; i < parsers.length; i++) {
2154
+ const fs2 = parsers[i]._meta.firstSet;
2155
+ if (fs2.kind !== "ranges") continue;
2156
+ for (const { lo, hi } of fs2.ranges) {
2157
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
2158
+ table[code] = i;
2046
2159
  }
2047
- } finally {
2048
- ctx._sync = inheritedSync;
2049
2160
  }
2050
- return {
2051
- ok: true,
2052
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2053
- value: values ?? void 0,
2054
- span: { start: pos, end: cur }
2055
- };
2056
2161
  }
2057
- return {
2058
- _tag: "sequence",
2059
- _meta: meta,
2060
- _def: def,
2061
- parse(input, pos, ctx) {
2062
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2063
- const values = def.valueUnused ? void 0 : [];
2064
- let cur = pos;
2065
- for (let i = 0; i < parsers.length; i++) {
2066
- if (ctx.trivia && i > 0) {
2067
- let scanEnd;
2068
- let mark = saveTriviaMark(ctx);
2069
- if (needsDeferredTriviaCommit(ctx)) {
2070
- const scan = scanTrivia(input, cur, ctx);
2071
- scan.commit();
2072
- scanEnd = scan.end;
2073
- } else {
2074
- scanEnd = advanceTrivia(input, cur, ctx);
2075
- }
2076
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2077
- if (!result2.ok) return result2;
2078
- if (result2.span.end > scanEnd) {
2079
- cur = result2.span.end;
2080
- } else {
2081
- rollbackTrivia(ctx, mark);
2082
- }
2083
- if (values !== void 0) values.push(result2.value);
2084
- continue;
2085
- }
2086
- const result = parsers[i].parse(input, cur, ctx);
2087
- if (!result.ok) return result;
2088
- if (values !== void 0) values.push(result.value);
2089
- cur = result.span.end;
2090
- }
2091
- return {
2092
- ok: true,
2093
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2094
- value: values ?? void 0,
2095
- span: { start: pos, end: cur }
2096
- };
2097
- }
2098
- };
2162
+ return table;
2099
2163
  }
2100
2164
 
2101
2165
  // src/combinators/dispatch.ts
@@ -2355,10 +2419,12 @@ function attempt(parser2) {
2355
2419
  }
2356
2420
  const mark = saveCstMark(ctx);
2357
2421
  const log = ctx._triviaLog?.length;
2422
+ const rootLog = ctx._rootTriviaLog?.length;
2358
2423
  const result = parser2.parse(input, pos, ctx);
2359
2424
  if (result.ok) return result;
2360
2425
  rollbackCstCapture(ctx, mark);
2361
2426
  if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
2427
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
2362
2428
  if (result.committed) return result;
2363
2429
  return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
2364
2430
  }
@@ -2762,18 +2828,37 @@ function createParseLineContext(input, pos) {
2762
2828
  }
2763
2829
  function parser(opts, root) {
2764
2830
  const clearTrivia = opts.trivia === null;
2831
+ const opaqueRootCapture = opts.rootCapture === "opaque";
2832
+ if (opaqueRootCapture && opts.trivia === void 0) {
2833
+ throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
2834
+ }
2765
2835
  return {
2766
2836
  _tag: "grammar",
2767
- _meta: root._meta,
2837
+ _meta: {
2838
+ ...root._meta,
2839
+ // Trivia classification describes this grammar's own active trivia
2840
+ // scope. A directly nested grammar may have classified trivia of its
2841
+ // own, but that must not advertise classification for this wrapper.
2842
+ triviaKindLabels: void 0,
2843
+ rootTriviaClassified: void 0,
2844
+ ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
2845
+ ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
2846
+ },
2768
2847
  _def: {
2769
2848
  tag: "grammar",
2770
2849
  parser: root,
2771
2850
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2772
2851
  clearTrivia,
2852
+ ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
2773
2853
  ...opts.captureTrivia ? { captureTrivia: true } : {},
2774
2854
  trackLines: opts.trackLines ?? false
2775
2855
  },
2776
2856
  parse(input, pos, _ctx) {
2857
+ if (_ctx?._rootTriviaStrictScopes && opts.trivia !== void 0 && opts.trivia !== null && !opts.trivia._meta.rootTriviaClassified && !opaqueRootCapture) {
2858
+ throw new TypeError(
2859
+ "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'."
2860
+ );
2861
+ }
2777
2862
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2778
2863
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2779
2864
  const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
@@ -2796,7 +2881,11 @@ function parser(opts, root) {
2796
2881
  // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2797
2882
  // trivia is inherited rather than re-declared here. No labels → undefined
2798
2883
  // (capture all).
2799
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2884
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {},
2885
+ // This is a property of the local trivia scope, not a post-parse filter:
2886
+ // nested recognition can still skip its trivia, but selected root rows
2887
+ // must never be written for an explicitly opaque region.
2888
+ ...opaqueRootCapture ? { _rootTriviaCapture: false } : {}
2800
2889
  };
2801
2890
  const result = root.parse(input, pos ?? 0, ctx);
2802
2891
  if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
@@ -3449,6 +3538,25 @@ function trivia(combinator) {
3449
3538
  parse: combinator.parse.bind(combinator)
3450
3539
  };
3451
3540
  }
3541
+ function classifiedTrivia(arms) {
3542
+ const entries = Object.entries(arms);
3543
+ if (entries.length === 0) {
3544
+ throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
3545
+ }
3546
+ for (let i = 0; i < entries.length; i++) {
3547
+ const [name, arm] = entries[i];
3548
+ const first = arm._meta.firstSet;
3549
+ if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
3550
+ throw new TypeError(
3551
+ `classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
3552
+ );
3553
+ }
3554
+ }
3555
+ const labeledArms = entries.map(([name, arm]) => label(name, arm));
3556
+ const result = trivia(oneOrMore(choice(...labeledArms)));
3557
+ result._meta.rootTriviaClassified = true;
3558
+ return result;
3559
+ }
3452
3560
  function label(name, combinator) {
3453
3561
  return {
3454
3562
  _tag: combinator._tag,
@@ -3495,6 +3603,7 @@ function token(root) {
3495
3603
  const savedRaw = ctx._cstRawChildren;
3496
3604
  const savedTriviaLog = ctx._cstTriviaLog;
3497
3605
  const savedOuterTriviaLog = ctx._triviaLog;
3606
+ const savedRootTriviaLog = ctx._rootTriviaLog;
3498
3607
  const wasCapturing = cstCaptureActive(ctx);
3499
3608
  ctx.trivia = void 0;
3500
3609
  ctx.triviaKindLabels = void 0;
@@ -3504,6 +3613,7 @@ function token(root) {
3504
3613
  ctx._cstRawChildren = void 0;
3505
3614
  ctx._cstTriviaLog = void 0;
3506
3615
  delete ctx._triviaLog;
3616
+ delete ctx._rootTriviaLog;
3507
3617
  let result;
3508
3618
  try {
3509
3619
  result = root.parse(input, pos, ctx);
@@ -3517,6 +3627,8 @@ function token(root) {
3517
3627
  ctx._cstTriviaLog = savedTriviaLog;
3518
3628
  if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
3519
3629
  else ctx._triviaLog = savedOuterTriviaLog;
3630
+ if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
3631
+ else ctx._rootTriviaLog = savedRootTriviaLog;
3520
3632
  }
3521
3633
  if (!result.ok) return result;
3522
3634
  const span = result.span;
@@ -3571,7 +3683,7 @@ function leaf(root, fn) {
3571
3683
  }
3572
3684
 
3573
3685
  // src/version.ts
3574
- var PARSEMAN_VERSION = "0.43.0";
3686
+ var PARSEMAN_VERSION = "0.44.0";
3575
3687
 
3576
3688
  // src/cst/host-mode.ts
3577
3689
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -5469,9 +5581,18 @@ function buildGrammarPlan(entry, winners) {
5469
5581
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
5470
5582
  }
5471
5583
 
5584
+ // src/cst/trivia-entries.ts
5585
+ var EMPTY_INDICES = Object.freeze([]);
5586
+ var EMPTY_GAPS = Object.freeze([]);
5587
+ var SELECTED_ROOT_STRIDE = 5;
5588
+
5472
5589
  // src/compiler/scannable-run.ts
5473
5590
  var BACKSLASH = 92;
5474
5591
  var META = new Set("()[]{}*+?|^$.".split(""));
5592
+ var SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER = Array.from(
5593
+ { length: SELECTED_ROOT_STRIDE - 3 },
5594
+ () => "0"
5595
+ ).join(", ");
5475
5596
  function classToRanges(cls) {
5476
5597
  if (cls === "\\d") return shorthandRanges("d");
5477
5598
  if (cls === "\\w") return shorthandRanges("w");
@@ -6510,13 +6631,15 @@ function scanBranch(shape, mint) {
6510
6631
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6511
6632
  return [...m.setup, ` if (${m.end} > _e) { _e = ${m.end}; continue }`].join("\n");
6512
6633
  }
6513
- function scanBranchLabeled(shape, kindIndex, mint) {
6634
+ function scanBranchLabeled(shape, kindIndex, label2, mint) {
6514
6635
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6515
6636
  return [
6516
6637
  ...m.setup,
6517
6638
  ` if (${m.end} > _e) {`,
6518
6639
  ` if (_cap) {`,
6519
6640
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6641
+ ` const _rk = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(label2)}] ?? -1)`,
6642
+ ` if (_rk >= 0) _ctx._rootTriviaLog.push(${SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER}, _e, ${m.end}, _rk)`,
6520
6643
  ` 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})`,
6521
6644
  ` }`,
6522
6645
  ` _e = ${m.end}`,
@@ -6576,6 +6699,11 @@ var CAP_RECORD = [
6576
6699
  ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6577
6700
  ` }`
6578
6701
  ].join("\n");
6702
+ var SELECTED_ROOT_FINISH = [
6703
+ ` if (_cap && _ctx._rootTriviaCapture !== false && _ctx._rootTriviaLog !== undefined && _ctx._rootTriviaLog.length !== _rootMark) {`,
6704
+ ` for (let _ri = _rootMark; _ri < _ctx._rootTriviaLog.length; _ri += ${SELECTED_ROOT_STRIDE}) { _ctx._rootTriviaLog[_ri] = _pos; _ctx._rootTriviaLog[_ri + 1] = _e }`,
6705
+ ` }`
6706
+ ].join("\n");
6579
6707
  function composeFastLoop(shapes) {
6580
6708
  const mint = makeMint();
6581
6709
  return [
@@ -6604,7 +6732,7 @@ function analyzeLabeledScannableRun(trivia2) {
6604
6732
  const d = getCoreRegexDef(arm.parser);
6605
6733
  const shape = d ? scanShapeFromRegex(d.source, d.flags) : null;
6606
6734
  if (!shape) return null;
6607
- out.push({ shape, kindIndex: arm.kindIndex });
6735
+ out.push({ shape, kindIndex: arm.kindIndex, label: arm.label });
6608
6736
  }
6609
6737
  return out;
6610
6738
  }
@@ -6613,11 +6741,13 @@ function buildLabeledScannableTriviaFnDecl(fnName, arms) {
6613
6741
  return [
6614
6742
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6615
6743
  ` let _e = _pos`,
6744
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6616
6745
  ` while (_e < input.length) {`,
6617
6746
  ` const c = input.charCodeAt(_e)`,
6618
- ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, mint)),
6747
+ ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, a.label, mint)),
6619
6748
  ` break`,
6620
6749
  ` }`,
6750
+ SELECTED_ROOT_FINISH,
6621
6751
  ` return _e`,
6622
6752
  `}`
6623
6753
  ].join("\n");
@@ -6633,6 +6763,8 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6633
6763
  ` const _ce = _e + _m${i}[0].length`,
6634
6764
  ` if (_cap) {`,
6635
6765
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6766
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
6767
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6636
6768
  ` 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})`,
6637
6769
  ` }`,
6638
6770
  ` _e = _ce`,
@@ -6644,11 +6776,13 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6644
6776
  return [
6645
6777
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6646
6778
  ` let _e = _pos`,
6779
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6647
6780
  ` while (_e < input.length) {`,
6648
6781
  ` let _matched = false`,
6649
6782
  tryArms,
6650
6783
  ` if (!_matched) break`,
6651
6784
  ` }`,
6785
+ SELECTED_ROOT_FINISH,
6652
6786
  ` return _e`,
6653
6787
  `}`
6654
6788
  ].join("\n");
@@ -6671,6 +6805,8 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6671
6805
  ` const _ce = _r${i}.span.end`,
6672
6806
  ` if (_cap) {`,
6673
6807
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6808
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
6809
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6674
6810
  ` 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})`,
6675
6811
  ` }`,
6676
6812
  ` _e = _ce`,
@@ -6682,11 +6818,13 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6682
6818
  return [
6683
6819
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6684
6820
  ` let _e = _pos`,
6821
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6685
6822
  ` while (_e < input.length) {`,
6686
6823
  ` let _matched = false`,
6687
6824
  tryArms,
6688
6825
  ` if (!_matched) break`,
6689
6826
  ` }`,
6827
+ SELECTED_ROOT_FINISH,
6690
6828
  ` return _e`,
6691
6829
  `}`
6692
6830
  ].join("\n");
@@ -6917,6 +7055,9 @@ function endLoweringCapture() {
6917
7055
  _loweringSink = null;
6918
7056
  return misses;
6919
7057
  }
7058
+ function hasSelectedRootTrivia(ctx) {
7059
+ return ctx.rootTriviaClassified === true;
7060
+ }
6920
7061
  function v(ctx, prefix = "_v") {
6921
7062
  return `${prefix}${ctx.vars++}`;
6922
7063
  }
@@ -7226,10 +7367,12 @@ function planDisjointDispatch(parsers) {
7226
7367
  }
7227
7368
  return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
7228
7369
  }
7229
- function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
7370
+ function captureRestoreBody(ctx, mL, mR, mTl, mLg, mF = null, mRootLg = null) {
7230
7371
  const fieldRestore = mF ? `; if (_ctx._fields && _ctx._fields.length !== ${mF}) _ctx._fields.length = ${mF}` : "";
7231
7372
  const base = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${mL}) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${mR}) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${mTl}) _ctx._cstTriviaLog.length = ${mTl}${fieldRestore}`;
7232
- return mLg ? `${base}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : base;
7373
+ const logRestore = mLg ? `; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : "";
7374
+ const rootLogRestore = hasSelectedRootTrivia(ctx) && mRootLg ? `; if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${mRootLg}) _ctx._rootTriviaLog.length = ${mRootLg}` : "";
7375
+ return `${base}${logRestore}${rootLogRestore}`;
7233
7376
  }
7234
7377
  function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
7235
7378
  if (seen.has(p)) return false;
@@ -7439,7 +7582,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
7439
7582
  `${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
7440
7583
  `${ind0}}`,
7441
7584
  ...mL ? [
7442
- `${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
7585
+ `${ind0}if (!${okV}) { ${captureRestoreBody(ctx, mL, mR, mTl, null, mF)} }`
7443
7586
  ] : []
7444
7587
  ];
7445
7588
  return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
@@ -7636,11 +7779,13 @@ function emitSeqValues(def, ctx, pos) {
7636
7779
  const markV = v(ctx, "_mk");
7637
7780
  const markTl = v(ctx, "_mktl");
7638
7781
  const markLog = v(ctx, "_mklg");
7782
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7639
7783
  const scanEndV = v(ctx, "_sne");
7640
7784
  stmts.push(
7641
7785
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7642
7786
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7643
7787
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7788
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7644
7789
  `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7645
7790
  ...emitLineTrack(ctx, curV, scanEndV)
7646
7791
  );
@@ -7649,17 +7794,19 @@ function emitSeqValues(def, ctx, pos) {
7649
7794
  const endAfterV = v(ctx, "_sea");
7650
7795
  stmts.push(
7651
7796
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7652
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) { ${curV} = ${endAfterV} } else { 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}; }`
7797
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) { ${curV} = ${endAfterV} } else { 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};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} }`
7653
7798
  );
7654
7799
  valueVars.push(r2.valueVar);
7655
7800
  continue;
7656
7801
  } else {
7657
7802
  const trivFn = ensureTriviaFn(ctx);
7658
7803
  const markLog = v(ctx, "_mklg");
7804
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7659
7805
  const scanEndV = v(ctx, "_sne");
7660
- const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7806
+ const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? "(_ctx._triviaLog !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7661
7807
  stmts.push(
7662
7808
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7809
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7663
7810
  `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7664
7811
  ...emitLineTrack(ctx, curV, scanEndV)
7665
7812
  );
@@ -7668,7 +7815,7 @@ function emitSeqValues(def, ctx, pos) {
7668
7815
  const endAfterV = v(ctx, "_sea");
7669
7816
  stmts.push(
7670
7817
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7671
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7818
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} }`
7672
7819
  );
7673
7820
  valueVars.push(r2.valueVar);
7674
7821
  continue;
@@ -7910,6 +8057,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7910
8057
  const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7911
8058
  const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7912
8059
  const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
8060
+ const selectorRootLogMark = selectorNeedsRollback && hasSelectedRootTrivia(ctx) ? v(ctx, "_dsrg") : null;
7913
8061
  const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7914
8062
  const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7915
8063
  const selector = emit(def.selector, ctx, pos);
@@ -7922,6 +8070,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7922
8070
  `${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
7923
8071
  `${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
7924
8072
  `${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
8073
+ ...selectorRootLogMark ? [`${ind(ctx)}const ${selectorRootLogMark} = _ctx._rootTriviaLog?.length ?? 0`] : [],
7925
8074
  `${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
7926
8075
  `${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
7927
8076
  ] : [],
@@ -7941,16 +8090,18 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7941
8090
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7942
8091
  const errMark = mayError ? v(ctx, "_derr") : null;
7943
8092
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
8093
+ const rootLogMark = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_drlog") : null;
7944
8094
  if (usesRouted) {
7945
8095
  stmts.push(
7946
8096
  ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7947
8097
  ...selectorLeafMark ? [
7948
- `${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}`
8098
+ `${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};${selectorRootLogMark ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${selectorRootLogMark}) _ctx._rootTriviaLog.length = ${selectorRootLogMark};` : ""} if (_ctx._fields && _ctx._fields.length !== ${selectorFieldMark}) _ctx._fields.length = ${selectorFieldMark}; if (_ctx._errors && _ctx._errors.length !== ${selectorErrorMark}) _ctx._errors.length = ${selectorErrorMark}`
7949
8099
  ] : []
7950
8100
  );
7951
8101
  }
7952
8102
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7953
8103
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
8104
+ if (rootLogMark) stmts.push(`${ind(ctx)}const ${rootLogMark} = _ctx._rootTriviaLog?.length ?? 0`);
7954
8105
  const savedRoutedLocal = ctx.routedLocal;
7955
8106
  const savedNoHoist = ctx.noHoist;
7956
8107
  if (usesRouted && !needsRoutedContext) {
@@ -7965,11 +8116,12 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7965
8116
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7966
8117
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7967
8118
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
8119
+ const rootLogRollback = rootLogMark ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rootLogMark}) _ctx._rootTriviaLog.length = ${rootLogMark}; ` : "";
7968
8120
  const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
7969
8121
  const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
7970
8122
  stmts.push(
7971
8123
  ...tail.stmts,
7972
- `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8124
+ `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${rootLogRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7973
8125
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7974
8126
  `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7975
8127
  `${ind(ctx)}${outE} = ${tail.endVar}`,
@@ -8150,11 +8302,13 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8150
8302
  const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
8151
8303
  const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
8152
8304
  const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
8305
+ const markRootLog = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_cmlrg") : null;
8153
8306
  const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
8154
8307
  const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
8155
- const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
8308
+ const captureRollback = markLeaves ? captureRestoreBody(ctx, markLeaves, markRaw, markTl, markLog, markFields, markRootLog) : "";
8309
+ const rootRollback = markRootLog && !markLeaves ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}` : "";
8156
8310
  const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
8157
- const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
8311
+ const rollback = [captureRollback, rootRollback, errorRollback].filter(Boolean).join("; ");
8158
8312
  const failSlot = atStart ? staticFx : "_ctx._fx";
8159
8313
  stmts.push(`${ind0}if (${skipCond}) {`);
8160
8314
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
@@ -8169,6 +8323,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8169
8323
  ...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
8170
8324
  );
8171
8325
  }
8326
+ if (markRootLog) stmts.push(`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog?.length ?? 0`);
8172
8327
  if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
8173
8328
  const arm = emitFallible(p, ctx, pos, atStart);
8174
8329
  const { stmts: armStmts, okVar, valVar, endVar } = arm;
@@ -8356,21 +8511,29 @@ function emitMany(def, ctx, pos) {
8356
8511
  const markV = v(ctx, "_mk");
8357
8512
  const markTl = v(ctx, "_mktl");
8358
8513
  const markLog = v(ctx, "_mklg");
8514
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8359
8515
  const npV = v(ctx, "_np");
8360
8516
  stmts.push(
8361
8517
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8362
8518
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8363
8519
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8520
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8364
8521
  `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8365
8522
  ...emitLineTrack(ctx, curV, npV)
8366
8523
  );
8367
8524
  itemPos = npV;
8368
- 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}; `;
8525
+ 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};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} `;
8369
8526
  } else {
8370
8527
  const trivFn = ensureTriviaFn(ctx);
8528
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8371
8529
  const npV = v(ctx, "_np");
8372
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, npV));
8530
+ stmts.push(
8531
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8532
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8533
+ ...emitLineTrack(ctx, curV, npV)
8534
+ );
8373
8535
  itemPos = npV;
8536
+ rollback = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8374
8537
  }
8375
8538
  }
8376
8539
  if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
@@ -8430,9 +8593,10 @@ function emitAttempt(p, def, ctx, pos) {
8430
8593
  const raw = v(ctx, "_atr");
8431
8594
  const trivia2 = v(ctx, "_att");
8432
8595
  const log = v(ctx, "_atg");
8596
+ const rootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_atrg") : null;
8433
8597
  const fields = v(ctx, "_atf");
8434
8598
  const errors = v(ctx, "_ate");
8435
- const rollback = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${leaves}) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${raw}) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${trivia2}) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${log}) _ctx._triviaLog.length = ${log}; if (_ctx._fields && _ctx._fields.length !== ${fields}) _ctx._fields.length = ${fields}; if (_ctx._errors && _ctx._errors.length !== ${errors}) _ctx._errors.length = ${errors}`;
8599
+ const rollback = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${leaves}) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${raw}) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${trivia2}) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${log}) _ctx._triviaLog.length = ${log};${rootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rootLog}) _ctx._rootTriviaLog.length = ${rootLog};` : ""} if (_ctx._fields && _ctx._fields.length !== ${fields}) _ctx._fields.length = ${fields}; if (_ctx._errors && _ctx._errors.length !== ${errors}) _ctx._errors.length = ${errors}`;
8436
8600
  const traceId = ctx.coverage?.plan.attempts.get(p);
8437
8601
  const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
8438
8602
  const preGuard = [];
@@ -8448,7 +8612,7 @@ function emitAttempt(p, def, ctx, pos) {
8448
8612
  return {
8449
8613
  stmts: [
8450
8614
  ...preGuard,
8451
- `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
8615
+ `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0${rootLog ? `, ${rootLog} = _ctx._rootTriviaLog?.length ?? 0` : ""}, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
8452
8616
  ...inner.stmts,
8453
8617
  ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
8454
8618
  ],
@@ -8490,16 +8654,17 @@ function emitSepBy(_p, def, ctx, pos) {
8490
8654
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8491
8655
  const postSepMarks = () => {
8492
8656
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8493
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8657
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), rlg = hasSelectedRootTrivia(ctx) ? v(ctx, "_trlg") : null, fl = v(ctx, "_tlf");
8494
8658
  return {
8495
8659
  decl: [
8496
8660
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8497
8661
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8498
8662
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8499
8663
  `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8664
+ ...rlg ? [`${ind(ctx)}const ${rlg} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8500
8665
  `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8501
8666
  ],
8502
- 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}; `
8667
+ 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};${rlg ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rlg}) _ctx._rootTriviaLog.length = ${rlg};` : ""} if (_ctx._fields && _ctx._fields.length !== ${fl}) _ctx._fields.length = ${fl}; `
8503
8668
  };
8504
8669
  };
8505
8670
  if (rec) {
@@ -8537,6 +8702,7 @@ function emitSepBy(_p, def, ctx, pos) {
8537
8702
  const markV = v(ctx, "_mk");
8538
8703
  const markTl = v(ctx, "_mktl");
8539
8704
  const markLog = v(ctx, "_mklg");
8705
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8540
8706
  const markLv = v(ctx, "_mklv");
8541
8707
  const markFld = v(ctx, "_mkf");
8542
8708
  const spV = v(ctx, "_sp");
@@ -8544,13 +8710,14 @@ function emitSepBy(_p, def, ctx, pos) {
8544
8710
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8545
8711
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8546
8712
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8713
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8547
8714
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8548
8715
  `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8549
8716
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8550
8717
  ...emitLineTrack(ctx, curV, spV)
8551
8718
  );
8552
8719
  sepAtPos = spV;
8553
- 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}; `;
8720
+ 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};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; `;
8554
8721
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8555
8722
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8556
8723
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8568,19 +8735,30 @@ function emitSepBy(_p, def, ctx, pos) {
8568
8735
  );
8569
8736
  } else {
8570
8737
  const trivFn = ensureTriviaFn(ctx);
8738
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8571
8739
  const spV = v(ctx, "_sp");
8572
- stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, spV));
8740
+ stmts.push(
8741
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8742
+ `${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8743
+ ...emitLineTrack(ctx, curV, spV)
8744
+ );
8573
8745
  sepAtPos = spV;
8574
8746
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8575
8747
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8576
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8748
+ const rollbackToSep = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8749
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8750
+ const postRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_psrlg") : null;
8577
8751
  const npV = v(ctx, "_np");
8578
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`, ...emitLineTrack(ctx, sepEnd, npV));
8752
+ stmts.push(
8753
+ ...postRootLog ? [`${ind(ctx)}const ${postRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8754
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8755
+ ...emitLineTrack(ctx, sepEnd, npV)
8756
+ );
8579
8757
  const next = emitFallible(def.parser, ctx, npV, true);
8580
8758
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8581
8759
  stmts.push(
8582
8760
  ...nextStmts,
8583
- ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
8761
+ ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, postRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${postRootLog}) _ctx._rootTriviaLog.length = ${postRootLog}; ` : "")),
8584
8762
  `${ind(ctx)}${arrV}.push(${nextVal})`,
8585
8763
  `${ind(ctx)}${curV} = ${nextEnd}`
8586
8764
  );
@@ -8675,6 +8853,7 @@ function emitNot(def, ctx, pos) {
8675
8853
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8676
8854
  const tl = sinksLive ? v(ctx, "_ntt") : null;
8677
8855
  const log = sinksLive ? v(ctx, "_ntg") : null;
8856
+ const rootLog = sinksLive && hasSelectedRootTrivia(ctx) ? v(ctx, "_ntrg") : null;
8678
8857
  const fields = sinksLive ? v(ctx, "_ntf") : null;
8679
8858
  const errors = sinksLive ? v(ctx, "_nte") : null;
8680
8859
  const { stmts, okVar } = emitFallible(def.parser, ctx, pos, true);
@@ -8682,11 +8861,11 @@ function emitNot(def, ctx, pos) {
8682
8861
  return {
8683
8862
  stmts: [
8684
8863
  ...sinksLive ? [
8685
- `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${tl} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`
8864
+ `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${tl} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0${rootLog ? `, ${rootLog} = _ctx._rootTriviaLog?.length ?? 0` : ""}, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`
8686
8865
  ] : [],
8687
8866
  ...stmts,
8688
8867
  ...sinksLive ? [
8689
- `${ind(ctx)}if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${leaves}) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${raw}) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${log}) _ctx._triviaLog.length = ${log}; if (_ctx._fields && _ctx._fields.length !== ${fields}) _ctx._fields.length = ${fields}; if (_ctx._errors && _ctx._errors.length !== ${errors}) _ctx._errors.length = ${errors}`
8868
+ `${ind(ctx)}if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${leaves}) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${raw}) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${log}) _ctx._triviaLog.length = ${log};${rootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rootLog}) _ctx._rootTriviaLog.length = ${rootLog};` : ""} if (_ctx._fields && _ctx._fields.length !== ${fields}) _ctx._fields.length = ${fields}; if (_ctx._errors && _ctx._errors.length !== ${errors}) _ctx._errors.length = ${errors}`
8690
8869
  ] : [],
8691
8870
  ...emitIfFail(ctx, okVar, failBody(ctx, label2, pos))
8692
8871
  ],
@@ -8822,16 +9001,17 @@ function emitToken(def, ctx, pos) {
8822
9001
  const sk = v(ctx, "_tokKinds");
8823
9002
  const stl = v(ctx, "_tokTl");
8824
9003
  const sol = v(ctx, "_tokLog");
9004
+ const srl = hasSelectedRootTrivia(ctx) ? v(ctx, "_tokRootLog") : null;
8825
9005
  const sb = v(ctx, "_tokBuf");
8826
9006
  const valV = v(ctx, "_tok");
8827
9007
  return {
8828
9008
  stmts: [
8829
- `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${sv} = _ctx.trivia, ${sk} = _ctx.triviaKindLabels, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
8830
- `${i}_ctx.trivia = undefined; _ctx.triviaKindLabels = undefined; _ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
9009
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${sv} = _ctx.trivia, ${sk} = _ctx.triviaKindLabels, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog${srl ? `, ${srl} = _ctx._rootTriviaLog` : ""}, ${sb} = _ctx._cstBuf`,
9010
+ `${i}_ctx.trivia = undefined; _ctx.triviaKindLabels = undefined; _ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined;${srl ? " _ctx._rootTriviaLog = undefined;" : ""} _ctx._cstBuf = undefined`,
8831
9011
  `${i}try {`,
8832
9012
  ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
8833
9013
  `${i}} finally {`,
8834
- `${i} _ctx.trivia = ${sv}; _ctx.triviaKindLabels = ${sk}; _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
9014
+ `${i} _ctx.trivia = ${sv}; _ctx.triviaKindLabels = ${sk}; _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol};${srl ? ` _ctx._rootTriviaLog = ${srl};` : ""} _ctx._cstBuf = ${sb}`,
8835
9015
  `${i}}`,
8836
9016
  ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
8837
9017
  `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
@@ -9310,6 +9490,8 @@ function emitDispatch(p, ctx, pos) {
9310
9490
  case "grammar": {
9311
9491
  const savedTrivia = ctx.activeTrivia;
9312
9492
  const savedKindLabels = ctx.triviaKindLabels;
9493
+ const opaqueRootCapture = hasSelectedRootTrivia(ctx) && def.rootCapture === "opaque";
9494
+ const strictScopeCheck = hasSelectedRootTrivia(ctx) && def.triviaParser !== void 0 && !def.triviaParser._meta.rootTriviaClassified && !opaqueRootCapture ? `${ind(ctx)}if (_ctx._rootTriviaStrictScopes) throw new TypeError(${JSON.stringify("parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.")})` : void 0;
9313
9495
  if (def.clearTrivia) {
9314
9496
  ctx.activeTrivia = void 0;
9315
9497
  ctx.triviaKindLabels = void 0;
@@ -9320,13 +9502,38 @@ function emitDispatch(p, ctx, pos) {
9320
9502
  }
9321
9503
  }
9322
9504
  const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
9505
+ const savedRootCapture = opaqueRootCapture ? v(ctx, "_grtc") : null;
9506
+ const opaqueValue = opaqueRootCapture ? v(ctx, "_grtv") : null;
9507
+ const opaqueEnd = opaqueRootCapture ? v(ctx, "_grte") : null;
9508
+ if (opaqueRootCapture) ctx.indent++;
9323
9509
  const r = emit(def.parser, ctx, pos);
9510
+ if (opaqueRootCapture) ctx.indent--;
9324
9511
  ctx.activeTrivia = savedTrivia;
9325
9512
  ctx.triviaKindLabels = savedKindLabels;
9326
- if (!savedCapture) return r;
9513
+ if (!savedCapture && !opaqueRootCapture) return strictScopeCheck === void 0 ? r : {
9514
+ ...r,
9515
+ stmts: [strictScopeCheck, ...r.stmts]
9516
+ };
9517
+ if (opaqueRootCapture) {
9518
+ return {
9519
+ stmts: [
9520
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9521
+ `${ind(ctx)}let ${opaqueValue}, ${opaqueEnd}`,
9522
+ `${ind(ctx)}${savedCapture ? `const ${savedCapture} = _ctx.captureTrivia; ` : ""}const ${savedRootCapture} = _ctx._rootTriviaCapture; _ctx._rootTriviaCapture = false`,
9523
+ `${ind(ctx)}try {`,
9524
+ ...savedCapture ? [`${ind(ctx)} _ctx.captureTrivia = true`] : [],
9525
+ ...r.stmts,
9526
+ `${ind(ctx)} ${opaqueValue} = ${r.valueVar}; ${opaqueEnd} = ${r.endVar}`,
9527
+ `${ind(ctx)}} finally { ${savedCapture ? `_ctx.captureTrivia = ${savedCapture}; ` : ""}_ctx._rootTriviaCapture = ${savedRootCapture} }`
9528
+ ],
9529
+ valueVar: opaqueValue,
9530
+ endVar: opaqueEnd
9531
+ };
9532
+ }
9327
9533
  return {
9328
9534
  ...r,
9329
9535
  stmts: [
9536
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9330
9537
  `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
9331
9538
  ...r.stmts,
9332
9539
  `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
@@ -9811,6 +10018,7 @@ function compile(combinator, mapFnSources, opts) {
9811
10018
  runDuplicationDiagnostic(combinator, opts?.duplication);
9812
10019
  markUnusedValues(combinator);
9813
10020
  const grammarTrivia = combinator._meta.grammarTrivia;
10021
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || combinator._meta.rootTriviaClassified === true;
9814
10022
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9815
10023
  const grammarHostMode = combinator._meta.grammarHostMode;
9816
10024
  const grammarTrackLines = combinator._meta.grammarTrackLines;
@@ -9837,7 +10045,11 @@ function compile(combinator, mapFnSources, opts) {
9837
10045
  lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9838
10046
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9839
10047
  lazyUsage: analyzeLazyUsage(combinator),
9840
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10048
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10049
+ ...grammarTrivia ? {
10050
+ activeTrivia: grammarTrivia,
10051
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10052
+ } : {},
9841
10053
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
9842
10054
  };
9843
10055
  const r = emit(combinator, ctx, "_pos");
@@ -9985,10 +10197,11 @@ function assertRuleName(name) {
9985
10197
  );
9986
10198
  }
9987
10199
  }
9988
- function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9989
- const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9990
- if (labels === void 0) return fnSource;
9991
- return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
10200
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambientRootTriviaClassified) {
10201
+ const labels = ambientTriviaKindLabels ?? rule._meta.triviaKindLabels;
10202
+ const classified = ambientRootTriviaClassified ?? rule._meta.rootTriviaClassified;
10203
+ if (labels === void 0 && classified === void 0) return fnSource;
10204
+ return `Object.assign(${fnSource}, { _meta: {${labels === void 0 ? "" : ` triviaKindLabels: ${JSON.stringify(labels)},`}${classified === void 0 ? "" : " rootTriviaClassified: true,"} } })`;
9992
10205
  }
9993
10206
  function compileRuleMap(ruleMap, opts) {
9994
10207
  runGatingDiagnosticRules(ruleMap, opts?.gating);
@@ -9996,6 +10209,7 @@ function compileRuleMap(ruleMap, opts) {
9996
10209
  for (const [, rule] of ruleMap) markUnusedValues(rule);
9997
10210
  const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
9998
10211
  const grammarTrivia = opts?.trivia;
10212
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || ruleMap.some(([, rule]) => rule._meta.rootTriviaClassified === true);
9999
10213
  const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10000
10214
  const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10001
10215
  const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10022,7 +10236,11 @@ function compileRuleMap(ruleMap, opts) {
10022
10236
  lineTracking: grammarTrackLines,
10023
10237
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
10024
10238
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10025
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10239
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10240
+ ...grammarTrivia ? {
10241
+ activeTrivia: grammarTrivia,
10242
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10243
+ } : {},
10026
10244
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10027
10245
  };
10028
10246
  const seenNames = /* @__PURE__ */ new Map();
@@ -10110,7 +10328,7 @@ function compileRuleMap(ruleMap, opts) {
10110
10328
  return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
10111
10329
  };
10112
10330
  const objBody = perEntry.map(({ key, rule, r }) => {
10113
- const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels);
10331
+ const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels, ctx.rootTriviaClassified);
10114
10332
  return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
10115
10333
  }).join(",\n");
10116
10334
  const replacement = [
@@ -10139,6 +10357,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10139
10357
  if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
10140
10358
  for (const [, rule] of ruleMapArg) markUnusedValues(rule);
10141
10359
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
10360
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || ruleMapArg.some(([, rule]) => rule._meta.rootTriviaClassified === true);
10142
10361
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10143
10362
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10144
10363
  const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10182,7 +10401,11 @@ function compileLinkable(ruleMapArg, ns, opts) {
10182
10401
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10183
10402
  ns,
10184
10403
  deferFirstSetRefs: true,
10185
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10404
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10405
+ ...grammarTrivia ? {
10406
+ activeTrivia: grammarTrivia,
10407
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10408
+ } : {},
10186
10409
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10187
10410
  };
10188
10411
  const seen = /* @__PURE__ */ new Map();
@@ -10314,7 +10537,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10314
10537
  ...r.stmts,
10315
10538
  ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10316
10539
  `}`
10317
- ].join("\n"), ctx.triviaKindLabels));
10540
+ ].join("\n"), ctx.triviaKindLabels, ctx.rootTriviaClassified));
10318
10541
  }
10319
10542
  const firstSets = /* @__PURE__ */ new Map();
10320
10543
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10663,6 +10886,7 @@ function evalRuleMapIR(ir) {
10663
10886
  "transform",
10664
10887
  "skip",
10665
10888
  "trivia",
10889
+ "classifiedTrivia",
10666
10890
  "label",
10667
10891
  "field",
10668
10892
  "expect",
@@ -10703,6 +10927,7 @@ function evalRuleMapIR(ir) {
10703
10927
  transform,
10704
10928
  skip,
10705
10929
  trivia,
10930
+ classifiedTrivia,
10706
10931
  label,
10707
10932
  field,
10708
10933
  expect,
@@ -10949,8 +11174,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10949
11174
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
10950
11175
  }
10951
11176
  case "grammar": {
10952
- const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
10953
- return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
11177
+ const classified = def.triviaParser?._meta.rootTriviaClassified === true;
11178
+ const spec = classified && def.triviaParser ? analyzeLabeledTrivia(def.triviaParser) : null;
11179
+ if (classified && !spec) throw new Unserializable("classified trivia without labeled arms");
11180
+ const trivia2 = def.clearTrivia ? "null" : spec ? `classifiedTrivia({ ${spec.arms.map((arm) => `${JSON.stringify(arm.label)}: ${kid(arm.parser)}`).join(", ")} })` : def.triviaParser ? kid(def.triviaParser) : "undefined";
11181
+ return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.rootCapture ? `, rootCapture: ${JSON.stringify(def.rootCapture)}` : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
10954
11182
  }
10955
11183
  case "withCtx": {
10956
11184
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -11182,10 +11410,6 @@ function gate(predicate) {
11182
11410
  };
11183
11411
  }
11184
11412
 
11185
- // src/cst/trivia-entries.ts
11186
- var EMPTY_INDICES = Object.freeze([]);
11187
- var EMPTY_GAPS = Object.freeze([]);
11188
-
11189
11413
  // src/cst/offset-model.ts
11190
11414
  var { isFinite } = Number;
11191
11415
 
@@ -11437,6 +11661,9 @@ var SUPPORTED = {
11437
11661
  optional: (...a) => optional(a[0]),
11438
11662
  skip: (...a) => skip(a[0], a[1]),
11439
11663
  trivia: (...a) => trivia(a[0]),
11664
+ classifiedTrivia: (...a) => classifiedTrivia(
11665
+ a[0]
11666
+ ),
11440
11667
  label: (...a) => label(a[0], a[1]),
11441
11668
  field: (...a) => field(a[0], a[1]),
11442
11669
  noTrivia: (...a) => noTrivia(a[0]),
@@ -13243,7 +13470,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
13243
13470
  if (isComposeLeafCall(init)) {
13244
13471
  const fused = compileComposeLeafCall(init);
13245
13472
  if (!fused) {
13246
- throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
13473
+ const reasons = warnings.slice(-4);
13474
+ throw new Error(
13475
+ `${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden` + (reasons.length ? `
13476
+ causes:
13477
+ - ${reasons.join("\n - ")}` : "")
13478
+ );
13247
13479
  }
13248
13480
  replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
13249
13481
  markUsedImportedFactories(fused.importedFactories);