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
@@ -1106,843 +1106,433 @@ function keywords(words, opts = {}) {
1106
1106
  };
1107
1107
  }
1108
1108
 
1109
- // src/recovery/scan.ts
1110
- function probeAt(sentinel, input, pos, ctx) {
1111
- const s = {
1112
- _probe: ctx._probe,
1113
- _errors: ctx._errors,
1114
- _cstLeaves: ctx._cstLeaves,
1115
- _cstChildren: ctx._cstChildren,
1116
- _cstRawChildren: ctx._cstRawChildren,
1117
- _cstTriviaLog: ctx._cstTriviaLog,
1118
- _triviaLog: ctx._triviaLog,
1119
- _fields: ctx._fields,
1120
- _cstBuf: ctx._cstBuf,
1121
- _tolerant: ctx._tolerant,
1122
- _sync: ctx._sync
1123
- };
1124
- ctx._probe = void 0;
1125
- ctx._errors = void 0;
1126
- ctx._cstLeaves = void 0;
1127
- ctx._cstChildren = void 0;
1128
- ctx._cstRawChildren = void 0;
1129
- ctx._cstTriviaLog = void 0;
1130
- ctx._triviaLog = void 0;
1131
- ctx._fields = void 0;
1132
- ctx._cstBuf = void 0;
1133
- ctx._tolerant = void 0;
1134
- ctx._sync = void 0;
1135
- try {
1136
- return sentinel.parse(input, pos, ctx).ok;
1137
- } finally {
1138
- ctx._probe = s._probe;
1139
- ctx._errors = s._errors;
1140
- ctx._cstLeaves = s._cstLeaves;
1141
- ctx._cstChildren = s._cstChildren;
1142
- ctx._cstRawChildren = s._cstRawChildren;
1143
- ctx._cstTriviaLog = s._cstTriviaLog;
1144
- ctx._triviaLog = s._triviaLog;
1145
- ctx._fields = s._fields;
1146
- ctx._cstBuf = s._cstBuf;
1147
- ctx._tolerant = s._tolerant;
1148
- ctx._sync = s._sync;
1149
- }
1109
+ // src/cst/trivia-kinds.ts
1110
+ var labeledTriviaSpecs = /* @__PURE__ */ new WeakMap();
1111
+ function unwrapTrivia(p) {
1112
+ let cur = p;
1113
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1114
+ return cur;
1150
1115
  }
1151
- function orSentinel(a, b) {
1152
- if (b === void 0) return a;
1153
- return {
1154
- _tag: "orSentinel",
1155
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1156
- _def: { tag: "unknown" },
1157
- parse(input, pos, ctx) {
1158
- const ra = a.parse(input, pos, ctx);
1159
- if (ra.ok) return ra;
1160
- return b.parse(input, pos, ctx);
1161
- }
1162
- };
1116
+ function peelLabel(p) {
1117
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1118
+ return null;
1163
1119
  }
1164
- function firstSetSentinel(fs2) {
1165
- if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
1166
- const ranges = fs2.ranges;
1167
- return {
1168
- _tag: "firstSetSentinel",
1169
- _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
1170
- _def: { tag: "unknown" },
1171
- parse(input, pos) {
1172
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1173
- if (code !== void 0) {
1174
- for (const r of ranges) {
1175
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1176
- }
1120
+ function analyzeLabeledTrivia(trivia2) {
1121
+ const cached = labeledTriviaSpecs.get(trivia2);
1122
+ if (cached !== void 0) return cached;
1123
+ let core = unwrapTrivia(trivia2);
1124
+ let minRepeats = 1;
1125
+ if (core._def.tag === "oneOrMore") {
1126
+ core = core._def.parser;
1127
+ minRepeats = 1;
1128
+ } else if (core._def.tag === "many") {
1129
+ core = core._def.parser;
1130
+ minRepeats = 0;
1131
+ }
1132
+ const arms = [];
1133
+ if (core._def.tag === "choice") {
1134
+ for (let i = 0; i < core._def.parsers.length; i++) {
1135
+ const peeled = peelLabel(core._def.parsers[i]);
1136
+ if (!peeled) {
1137
+ labeledTriviaSpecs.set(trivia2, null);
1138
+ return null;
1177
1139
  }
1178
- return { ok: false, expected: [], span: { start: pos, end: pos } };
1140
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1141
+ }
1142
+ } else {
1143
+ const peeled = peelLabel(core);
1144
+ if (!peeled) {
1145
+ labeledTriviaSpecs.set(trivia2, null);
1146
+ return null;
1179
1147
  }
1148
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1149
+ }
1150
+ const spec = {
1151
+ labels: arms.map((a) => a.label),
1152
+ arms,
1153
+ minRepeats
1180
1154
  };
1155
+ labeledTriviaSpecs.set(trivia2, spec);
1156
+ return spec;
1181
1157
  }
1182
- function recoverScan(input, from, ctx, sync, expected) {
1183
- let scanPos = from;
1184
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1185
- const span = { start: from, end: scanPos };
1186
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1187
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1188
- ctx._errors?.push(error);
1189
- return { error, end: scanPos };
1190
- }
1191
- function matchesAt(sentinel, input, pos, ctx) {
1192
- return probeAt(sentinel, input, pos, ctx);
1158
+ function matchArmAt(input, pos, arm, state) {
1159
+ if (!startsFirstSet(arm, input, pos)) return null;
1160
+ const r = arm.parse(input, pos, { trackLines: false, state });
1161
+ if (!r.ok || r.span.end <= pos) return null;
1162
+ return { end: r.span.end };
1193
1163
  }
1194
- function captureError(ctx, error) {
1195
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1164
+ function scanLabeledTriviaChunks(input, cur, spec, state) {
1165
+ const chunks = [];
1166
+ let pos = cur;
1167
+ while (pos < input.length) {
1168
+ let matched = null;
1169
+ for (const arm of spec.arms) {
1170
+ const m = matchArmAt(input, pos, arm.parser, state);
1171
+ if (m) {
1172
+ matched = { end: m.end, kindIndex: arm.kindIndex };
1173
+ break;
1174
+ }
1175
+ }
1176
+ if (!matched) break;
1177
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1178
+ pos = matched.end;
1179
+ }
1180
+ if (chunks.length < spec.minRepeats) {
1181
+ return { end: cur, chunks: [] };
1182
+ }
1183
+ return { end: pos, chunks };
1196
1184
  }
1197
-
1198
- // src/combinators/expect.ts
1199
- function deriveExpected(c) {
1200
- return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1185
+ function scanLabeledTriviaEnd(input, cur, spec, state) {
1186
+ let pos = cur;
1187
+ let count = 0;
1188
+ while (pos < input.length) {
1189
+ let matched = null;
1190
+ for (const arm of spec.arms) {
1191
+ matched = matchArmAt(input, pos, arm.parser, state);
1192
+ if (matched) break;
1193
+ }
1194
+ if (!matched) break;
1195
+ pos = matched.end;
1196
+ count++;
1197
+ }
1198
+ return count < spec.minRepeats ? cur : pos;
1201
1199
  }
1202
- function derive(c, seen) {
1203
- const deriveExpected2 = (p) => derive(p, seen);
1204
- const def = c._def;
1205
- switch (def.tag) {
1206
- case "literal":
1207
- return [JSON.stringify(def.value)];
1208
- case "regex":
1209
- return [`/${def.source}/`];
1210
- case "keywords":
1211
- return def.words.map((w) => JSON.stringify(w));
1212
- case "label":
1213
- return [def.label];
1214
- case "choice":
1215
- return def.parsers.flatMap(deriveExpected2);
1216
- case "dispatch":
1217
- return deriveExpected2(def.selector);
1218
- // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1219
- // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1220
- // able to fail first — deriving from term 0 alone named a token the parse
1221
- // never actually required. A leading `not(…)` is zero-width and contributes
1222
- // nothing (its own expectation is about what must NOT be here), but it is
1223
- // nullable, so keep scanning past it. Stop at the first term that must match.
1224
- case "sequence": {
1225
- const out = [];
1226
- for (const term of def.parsers) {
1227
- if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1228
- if (!matchesEmpty(term)) break;
1200
+ function visitLabeledTrivia(input, cur, spec, state, visit) {
1201
+ if (spec.minRepeats > 1) return void 0;
1202
+ let pos = cur;
1203
+ let count = 0;
1204
+ while (pos < input.length) {
1205
+ let matched = null;
1206
+ for (const arm of spec.arms) {
1207
+ const match = matchArmAt(input, pos, arm.parser, state);
1208
+ if (match) {
1209
+ matched = { end: match.end, kindIndex: arm.kindIndex };
1210
+ break;
1229
1211
  }
1230
- return out;
1231
1212
  }
1232
- case "attempt":
1233
- return deriveExpected2(def.parser);
1234
- // Delegating wrappers whose first-token failure is their inner parser's — must
1235
- // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1236
- // node, which reads this) names the real expected token, not the wrapper tag.
1237
- case "field":
1238
- case "withCtx":
1239
- case "recover":
1240
- return deriveExpected2(def.parser);
1241
- case "skip":
1242
- return deriveExpected2(def.main);
1243
- case "expect":
1244
- return def.expected;
1245
- case "node":
1246
- case "grammar":
1247
- case "trivia":
1248
- case "token":
1249
- case "leaf":
1250
- case "optional":
1251
- case "many":
1252
- case "oneOrMore":
1253
- case "transform":
1254
- case "not":
1255
- case "peek":
1256
- return deriveExpected2(def.parser);
1257
- case "routed":
1258
- return ["routed()"];
1259
- case "lazy": {
1260
- const name = c._ruleName;
1261
- if (seen.has(c)) return name ? [name] : [];
1262
- seen.add(c);
1263
- try {
1264
- return deriveExpected2(def.thunk());
1265
- } catch {
1266
- return name ? [name] : [];
1267
- } finally {
1268
- seen.delete(c);
1213
+ if (!matched) break;
1214
+ visit(pos, matched.end, matched.kindIndex);
1215
+ pos = matched.end;
1216
+ count++;
1217
+ }
1218
+ return count < spec.minRepeats ? cur : pos;
1219
+ }
1220
+ function recordTriviaChunks(ctx, chunks) {
1221
+ const kinds = ctx.triviaKindLabels;
1222
+ const mask = ctx._triviaCaptureMask;
1223
+ const rootLog = ctx._rootTriviaLog;
1224
+ const rootKinds = ctx._rootTriviaKindIndex;
1225
+ const rootMark = rootLog?.length ?? 0;
1226
+ for (const ch2 of chunks) {
1227
+ pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1228
+ const rootKindIndex = ctx._rootTriviaCapture === false || rootLog === void 0 || rootKinds === void 0 || kinds === void 0 ? -1 : rootKinds[kinds[ch2.kindIndex] ?? ""] ?? -1;
1229
+ if (rootKindIndex >= 0) {
1230
+ rootLog.push(0, 0, ch2.start, ch2.end, rootKindIndex);
1231
+ }
1232
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1233
+ if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1234
+ pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1269
1235
  }
1270
1236
  }
1271
- default:
1272
- return [];
1273
1237
  }
1274
- }
1275
- function expect(combinator, label2) {
1276
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1277
- const meta = {
1278
- firstSet: combinator._meta.firstSet,
1279
- canMatchNewline: combinator._meta.canMatchNewline,
1280
- isTrivia: false
1281
- };
1282
- return {
1283
- _tag: "expect",
1284
- _meta: meta,
1285
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1286
- parse(input, pos, ctx) {
1287
- const result = combinator.parse(input, pos, ctx);
1288
- if (result.ok) return result;
1289
- const span = { start: pos, end: pos };
1290
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1291
- ctx._errors?.push(error);
1292
- if (ctx._tolerant) captureError(ctx, error);
1293
- return { ok: true, value: error, span: { start: pos, end: pos } };
1238
+ if (rootLog !== void 0 && rootLog.length !== rootMark && chunks.length > 0) {
1239
+ const start = chunks[0].start;
1240
+ const end = chunks[chunks.length - 1].end;
1241
+ for (let offset = rootMark; offset < rootLog.length; offset += 5) {
1242
+ rootLog[offset] = start;
1243
+ rootLog[offset + 1] = end;
1294
1244
  }
1295
- };
1245
+ }
1296
1246
  }
1297
-
1298
- // src/combinators/choice.ts
1299
- function choice(...args) {
1300
- const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1301
- const gates = args.map((a) => "gate" in a ? a.gate : null);
1302
- const hasGates = gates.some((g) => g !== null);
1303
- const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1304
- let combined = { kind: "empty" };
1305
- for (const p of parsers) combined = union(combined, p._meta.firstSet);
1306
- const meta = {
1307
- firstSet: combined,
1308
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1309
- isTrivia: false,
1310
- disjoint
1311
- };
1312
- const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1313
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1314
- let greedyLitMap = null;
1315
- let sortedParsers = null;
1316
- const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1317
- if (strategy?.tag === "greedyClassify") {
1318
- greedyLitMap = /* @__PURE__ */ new Map();
1319
- for (let i = 0; i < parsers.length; i++) {
1320
- if (i === strategy.superIndex) continue;
1321
- const litVal = getCoreLiteralValue(parsers[i]);
1322
- if (litVal !== null) greedyLitMap.set(litVal, i);
1323
- }
1324
- } else if (strategy?.tag === "literalsLongestFirst") {
1325
- sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
1247
+ function triviaKindMask(labels, keep) {
1248
+ if (!labels) return void 0;
1249
+ let mask = 0;
1250
+ for (const name of keep) {
1251
+ const idx = labels.indexOf(name);
1252
+ if (idx >= 0) mask |= 1 << idx;
1326
1253
  }
1254
+ return mask;
1255
+ }
1256
+
1257
+ // src/combinators/trivia-skip.ts
1258
+ var NOOP_COMMIT = () => {
1259
+ };
1260
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1261
+ function needsDeferredTriviaCommit(ctx) {
1262
+ return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1263
+ }
1264
+ function saveTriviaMark(ctx) {
1265
+ const m = saveCstMark(ctx);
1327
1266
  return {
1328
- _tag: "choice",
1329
- _meta: meta,
1330
- _def: {
1331
- tag: "choice",
1332
- parsers,
1333
- gates,
1334
- disjoint,
1335
- strategy: strategy ?? { tag: "firstMatch" },
1336
- autoNot
1337
- },
1338
- parse(input, pos, ctx) {
1339
- const expected = [];
1340
- if (disjoint && pos < input.length) {
1341
- const code = input.codePointAt(pos);
1342
- let idx = code < 128 ? asciiDispatch[code] : -1;
1343
- if (idx < 0) {
1344
- for (let i = 0; i < parsers.length; i++) {
1345
- if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1346
- idx = i;
1347
- break;
1348
- }
1267
+ raw: m.raw,
1268
+ tlog: m.tlog,
1269
+ leaves: m.leaves,
1270
+ fields: m.fields,
1271
+ errors: m.errors,
1272
+ log: ctx._triviaLog ? ctx._triviaLog.length : 0,
1273
+ rootLog: ctx._rootTriviaLog ? ctx._rootTriviaLog.length : 0
1274
+ };
1275
+ }
1276
+ function rollbackTrivia(ctx, mark) {
1277
+ rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1278
+ if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1279
+ if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1280
+ }
1281
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1282
+ const probeCtx = {
1283
+ trackLines: ctx.trackLines,
1284
+ state: ctx.state,
1285
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1286
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1287
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1288
+ };
1289
+ const result = triviaP.parse(input, cur, probeCtx);
1290
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1291
+ return result;
1292
+ }
1293
+ function saveLookaheadMark(ctx) {
1294
+ return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1295
+ }
1296
+ function rollbackLookahead(ctx, mark) {
1297
+ rollbackTrivia(ctx, mark);
1298
+ if (ctx._probe) ctx._probe.best = mark.probeBest;
1299
+ }
1300
+ function scanWithLabels(input, cur, ctx) {
1301
+ const triviaP = ctx.trivia;
1302
+ const spec = analyzeLabeledTrivia(triviaP);
1303
+ if (!spec) return { end: cur, commit: NOOP_COMMIT };
1304
+ const log = ctx._triviaLog;
1305
+ const rootLog = ctx._rootTriviaLog;
1306
+ const rootKinds = ctx._rootTriviaKindIndex;
1307
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1308
+ const mask = ctx._triviaCaptureMask;
1309
+ let fullRows;
1310
+ let rootRows;
1311
+ let cstRows;
1312
+ const visitedEnd = visitLabeledTrivia(input, cur, spec, ctx.state, (start, matchEnd, kindIndex) => {
1313
+ if (log !== void 0) (fullRows ??= []).push(start, matchEnd, kindIndex);
1314
+ const selectedKind = rootLog === void 0 || rootKinds === void 0 || ctx._rootTriviaCapture === false ? void 0 : rootKinds[spec.labels[kindIndex] ?? ""];
1315
+ if (selectedKind !== void 0) (rootRows ??= []).push(start, matchEnd, selectedKind);
1316
+ if (captureTl && (mask === void 0 || (mask & 1 << kindIndex) !== 0)) {
1317
+ (cstRows ??= []).push(start, matchEnd, kindIndex);
1318
+ }
1319
+ });
1320
+ if (visitedEnd !== void 0) {
1321
+ if (visitedEnd === cur) return { end: cur, commit: NOOP_COMMIT };
1322
+ return {
1323
+ end: visitedEnd,
1324
+ commit: () => {
1325
+ if (fullRows !== void 0 && log !== void 0) log.push(...fullRows);
1326
+ if (rootRows !== void 0 && rootLog !== void 0) {
1327
+ for (let i = 0; i < rootRows.length; i += 3) {
1328
+ rootLog.push(cur, visitedEnd, rootRows[i], rootRows[i + 1], rootRows[i + 2]);
1349
1329
  }
1350
1330
  }
1351
- if (idx >= 0) {
1352
- const gate2 = gates[idx];
1353
- if (gate2 && !gate2(ctx.state)) {
1354
- return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1331
+ if (cstRows !== void 0) {
1332
+ for (let i = 0; i < cstRows.length; i += 3) {
1333
+ pushCstTriviaEntry(ctx, cstRows[i], cstRows[i + 1], cstRows[i + 2]);
1355
1334
  }
1356
- const result = parsers[idx].parse(input, pos, ctx);
1357
- if (result.ok) return result;
1358
- expected.push(...result.expected);
1359
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1360
- return { ok: false, expected, span: { start: pos, end: pos } };
1361
- }
1362
- return {
1363
- ok: false,
1364
- expected: parsers.flatMap((p) => {
1365
- const r = p.parse(input, pos, ctx);
1366
- return r.ok ? [] : r.expected;
1367
- }),
1368
- span: { start: pos, end: pos }
1369
- };
1370
- }
1371
- if (strategy?.tag === "greedyClassify") {
1372
- const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1373
- if (!superResult.ok) return superResult;
1374
- const end = superResult.span.end;
1375
- const litIdx = greedyLitMap.get(input.slice(pos, end));
1376
- if (litIdx !== void 0) {
1377
- const litVal = getCoreLiteralValue(parsers[litIdx]);
1378
- const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1379
- return { ok: true, value, span: { start: pos, end } };
1380
- }
1381
- return superResult;
1382
- }
1383
- if (strategy?.tag === "literalsLongestFirst") {
1384
- for (const p of sortedParsers) {
1385
- const r = p.parse(input, pos, ctx);
1386
- if (r.ok) return r;
1387
- expected.push(...r.expected);
1388
- }
1389
- return { ok: false, expected, span: { start: pos, end: pos } };
1390
- }
1391
- for (let i = 0; i < parsers.length; i++) {
1392
- if (gates[i] && !gates[i](ctx.state)) continue;
1393
- const mark = saveCstMark(ctx);
1394
- const logLen = ctx._triviaLog?.length;
1395
- const result = parsers[i].parse(input, pos, ctx);
1396
- if (!result.ok) {
1397
- rollbackCstCapture(ctx, mark);
1398
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1399
- expected.push(...result.expected);
1400
- if (result.committed) return { ok: false, expected, span: result.span, committed: true };
1401
- continue;
1402
1335
  }
1403
- const checks = autoNot[i];
1404
- if (checks && autoNotFires(input, result.span.end, checks)) {
1405
- rollbackCstCapture(ctx, mark);
1406
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1407
- continue;
1408
- }
1409
- return result;
1410
1336
  }
1411
- return { ok: false, expected, span: { start: pos, end: pos } };
1412
- }
1337
+ };
1338
+ }
1339
+ const { end, chunks } = scanLabeledTriviaChunks(input, cur, spec, ctx.state);
1340
+ if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1341
+ return {
1342
+ end,
1343
+ commit: () => recordTriviaChunks(ctx, chunks)
1413
1344
  };
1414
1345
  }
1415
- function detectStrategy(parsers) {
1416
- const regexIndices = [];
1417
- const literalIndices = [];
1418
- for (let i = 0; i < parsers.length; i++) {
1419
- if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
1420
- else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
1421
- }
1422
- if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
1423
- const superIndex = regexIndices[0];
1424
- const regexDef = getCoreRegexDef(parsers[superIndex]);
1425
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
1426
- const re = new RegExp(regexDef.source, flags);
1427
- const allSubsumed = literalIndices.every((i) => {
1428
- const litVal = getCoreLiteralValue(parsers[i]);
1429
- re.lastIndex = 0;
1430
- const m = re.exec(litVal);
1431
- return m !== null && m[0] === litVal;
1432
- });
1433
- if (allSubsumed) return { tag: "greedyClassify", superIndex };
1346
+ function skipWithLabels(input, cur, ctx) {
1347
+ const spec = analyzeLabeledTrivia(ctx.trivia);
1348
+ if (spec) return scanLabeledTriviaEnd(input, cur, spec, ctx.state);
1349
+ const tr = parseTriviaNoCapture(ctx.trivia, input, cur, ctx);
1350
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1351
+ }
1352
+ function advanceTrivia(input, cur, ctx) {
1353
+ const triviaP = ctx.trivia;
1354
+ if (!triviaP) return cur;
1355
+ if (!ctx.trackLines) {
1356
+ const fast2 = fastTriviaScanner(triviaP);
1357
+ if (fast2) return fast2(input, cur);
1358
+ if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1359
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1360
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1434
1361
  }
1435
- if (parsers.length === literalIndices.length) {
1436
- const sortedIndices = [...literalIndices].sort(
1437
- (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
1438
- );
1439
- return { tag: "literalsLongestFirst", sortedIndices };
1362
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1363
+ const fast = fastTriviaScanner(triviaP);
1364
+ if (fast) {
1365
+ const end = fast(input, cur);
1366
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1367
+ return end;
1440
1368
  }
1441
- const shared = detectSharedPrefix(parsers);
1442
- if (shared !== null) return shared;
1443
- return { tag: "firstMatch" };
1444
- }
1445
- function bareLeadingTermKey(term) {
1446
- const d = term._def;
1447
- if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
1448
- if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
1449
- return null;
1450
- }
1451
- function detectSharedPrefix(parsers) {
1452
- if (parsers.length < 2) return null;
1453
- let key = null;
1454
- let prefix = null;
1455
- const members = [];
1456
- for (let i = 0; i < parsers.length; i++) {
1457
- const term0 = leadingTermOfArm(parsers[i]);
1458
- if (term0 === null) return null;
1459
- const k = bareLeadingTermKey(term0);
1460
- if (k === null) return null;
1461
- if (key === null) {
1462
- key = k;
1463
- prefix = term0;
1464
- } else if (k !== key) return null;
1465
- members.push(i);
1369
+ if (ctx.triviaKindLabels) {
1370
+ const end = skipWithLabels(input, cur, ctx);
1371
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1372
+ return end;
1466
1373
  }
1467
- if (prefix === null || members.length < 2) return null;
1468
- return { tag: "sharedPrefix", prefix, members };
1374
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1375
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1469
1376
  }
1470
- function leadingTermOfArm(arm) {
1471
- let d = arm._def;
1472
- for (; ; ) {
1473
- if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
1474
- d = d.parser._def;
1475
- continue;
1377
+ function scanTrivia(input, cur, ctx) {
1378
+ const triviaP = ctx.trivia;
1379
+ if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1380
+ const log = ctx._triviaLog;
1381
+ const rootLog = ctx._rootTriviaLog;
1382
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1383
+ if (!ctx.trackLines) {
1384
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1385
+ if (fast2 && log === void 0 && !captureTl) {
1386
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1476
1387
  }
1477
- break;
1478
- }
1479
- if (d.tag !== "sequence" || d.parsers.length < 2) return null;
1480
- return d.parsers[0];
1481
- }
1482
- function computeAutoNot(parsers) {
1483
- return parsers.map((p, i) => {
1484
- const litVal = getCoreLiteralValue(p);
1485
- if (litVal === null) return null;
1486
- const checks = [];
1487
- for (let j = i + 1; j < parsers.length; j++) {
1488
- const other = parsers[j];
1489
- const otherLit = getCoreLiteralValue(other);
1490
- if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
1491
- checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
1492
- continue;
1493
- }
1494
- const regexDef = getCoreRegexDef(other);
1495
- if (regexDef !== null) {
1496
- const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
1497
- if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
1498
- }
1388
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1389
+ return scanWithLabels(input, cur, ctx);
1499
1390
  }
1500
- return checks.length > 0 ? checks : null;
1501
- });
1502
- }
1503
- function autoNotFires(input, end, checks) {
1504
- for (const check of checks) {
1505
- if (check.kind === "firstSet") {
1506
- const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
1507
- if (inFirstSet(code, check.set)) return true;
1508
- } else {
1509
- if (input.startsWith(check.value, end)) return true;
1391
+ if (ctx.triviaKindLabels) return { end: skipWithLabels(input, cur, ctx), commit: NOOP_COMMIT };
1392
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1393
+ const tr3 = triviaP.parse(input, cur, {
1394
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1395
+ state: ctx.state
1396
+ });
1397
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1398
+ const end = tr3.span.end;
1399
+ return {
1400
+ end,
1401
+ commit: () => {
1402
+ pushTriviaLogEntry(ctx, cur, end);
1403
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1404
+ }
1405
+ };
1510
1406
  }
1407
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1408
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1511
1409
  }
1512
- return false;
1513
- }
1514
- function getCoreLiteralValue(p) {
1515
- const def = p._def;
1516
- if (def.tag === "literal" && !def.caseInsensitive) return def.value;
1517
- if (def.tag === "transform") return getCoreLiteralValue(def.parser);
1518
- return null;
1519
- }
1520
- function getCoreRegexDef(p) {
1521
- const def = p._def;
1522
- if (def.tag === "regex") return { source: def.source, flags: def.flags };
1523
- if (def.tag === "transform") return getCoreRegexDef(def.parser);
1524
- if (def.tag === "label") return getCoreRegexDef(def.parser);
1525
- return null;
1526
- }
1527
- function applyTransforms(p, value, span) {
1528
- const def = p._def;
1529
- if (def.tag === "transform") {
1530
- const inner = applyTransforms(def.parser, value, span);
1531
- return def.fn(inner, span);
1410
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1411
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1412
+ if (fast && log === void 0 && !captureTl) {
1413
+ const end = fast(input, cur);
1414
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1415
+ return { end, commit: NOOP_COMMIT };
1532
1416
  }
1533
- return value;
1534
- }
1535
- function continuationFirstSet(lit, source, flags) {
1536
- const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
1537
- re.lastIndex = 0;
1538
- const base = re.exec(lit);
1539
- if (!base || base[0] !== lit) return null;
1540
- const contCodes = [];
1541
- for (let code = 1; code < 128; code++) {
1542
- re.lastIndex = 0;
1543
- const m = re.exec(lit + String.fromCharCode(code));
1544
- if (m && m[0].length > lit.length) contCodes.push(code);
1417
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1418
+ const scan = scanWithLabels(input, cur, ctx);
1419
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1420
+ return scan;
1545
1421
  }
1546
- if (contCodes.length === 0) return null;
1547
- return codesToFirstSet(contCodes);
1548
- }
1549
- function codesToFirstSet(codes) {
1550
- codes.sort((a, b) => a - b);
1551
- const ranges = [];
1552
- let lo = codes[0], hi = codes[0];
1553
- for (let i = 1; i < codes.length; i++) {
1554
- if (codes[i] === hi + 1) {
1555
- hi = codes[i];
1556
- } else {
1557
- ranges.push({ lo, hi });
1558
- lo = hi = codes[i];
1559
- }
1422
+ if (ctx.triviaKindLabels) {
1423
+ const end = skipWithLabels(input, cur, ctx);
1424
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1425
+ return { end, commit: NOOP_COMMIT };
1560
1426
  }
1561
- ranges.push({ lo, hi });
1562
- return { kind: "ranges", ranges };
1427
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1428
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1429
+ if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1430
+ const end = tr2.span.end;
1431
+ return {
1432
+ end,
1433
+ commit: () => {
1434
+ pushTriviaLogEntry(ctx, cur, end);
1435
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1436
+ }
1437
+ };
1438
+ }
1439
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1440
+ return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1563
1441
  }
1564
- function inFirstSet(code, fs2) {
1565
- if (fs2.kind === "any") return true;
1566
- if (fs2.kind === "empty") return false;
1567
- for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
1568
- return false;
1442
+ function consumeTrivia(input, cur, ctx) {
1443
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1444
+ const scan = scanTrivia(input, cur, ctx);
1445
+ scan.commit();
1446
+ return scan.end;
1569
1447
  }
1570
- function areDisjoint(sets) {
1571
- if (sets.some((s) => s.kind === "any")) return false;
1572
- for (let i = 0; i < sets.length; i++)
1573
- for (let j = i + 1; j < sets.length; j++)
1574
- if (intersects(sets[i], sets[j])) return false;
1575
- return true;
1448
+ function fastTriviaScanner(trivia2) {
1449
+ const cached = fastTriviaCache.get(trivia2);
1450
+ if (cached !== void 0) return cached;
1451
+ const scanner = buildFastTriviaScanner(trivia2);
1452
+ fastTriviaCache.set(trivia2, scanner);
1453
+ return scanner;
1576
1454
  }
1577
- function buildAsciiDispatch(parsers) {
1578
- const table = Array(128).fill(-1);
1579
- for (let i = 0; i < parsers.length; i++) {
1580
- const fs2 = parsers[i]._meta.firstSet;
1581
- if (fs2.kind !== "ranges") continue;
1582
- for (const { lo, hi } of fs2.ranges) {
1583
- for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1584
- table[code] = i;
1455
+ function buildFastTriviaScanner(trivia2) {
1456
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1457
+ const direct = regexTriviaScanner(core);
1458
+ if (direct) return direct;
1459
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1460
+ if (!repeat) return null;
1461
+ const one = regexTriviaScanner(repeat);
1462
+ if (one) return loopScanner([one]);
1463
+ if (repeat._def.tag !== "choice") return null;
1464
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1465
+ if (arms.some((s) => s === null)) return null;
1466
+ return loopScanner(arms);
1467
+ }
1468
+ function loopScanner(arms) {
1469
+ return (input, cur) => {
1470
+ let pos = cur;
1471
+ scan: while (pos < input.length) {
1472
+ for (const arm of arms) {
1473
+ const end = arm(input, pos);
1474
+ if (end > pos) {
1475
+ pos = end;
1476
+ continue scan;
1477
+ }
1585
1478
  }
1479
+ break;
1586
1480
  }
1587
- }
1588
- return table;
1589
- }
1590
-
1591
- // src/cst/trivia-kinds.ts
1592
- function unwrapTrivia(p) {
1593
- let cur = p;
1594
- while (cur._def.tag === "trivia") cur = cur._def.parser;
1595
- return cur;
1481
+ return pos;
1482
+ };
1596
1483
  }
1597
- function peelLabel(p) {
1598
- if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1599
- return null;
1484
+ function regexTriviaScanner(parser2) {
1485
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1486
+ const source = parser2._def.source;
1487
+ return classRunSource(source) ?? altStarSource(source);
1600
1488
  }
1601
- function analyzeLabeledTrivia(trivia2) {
1602
- let core = unwrapTrivia(trivia2);
1603
- let minRepeats = 1;
1604
- if (core._def.tag === "oneOrMore") {
1605
- core = core._def.parser;
1606
- minRepeats = 1;
1607
- } else if (core._def.tag === "many") {
1608
- core = core._def.parser;
1609
- minRepeats = 0;
1610
- }
1611
- const arms = [];
1612
- if (core._def.tag === "choice") {
1613
- for (let i = 0; i < core._def.parsers.length; i++) {
1614
- const peeled = peelLabel(core._def.parsers[i]);
1615
- if (!peeled) return null;
1616
- arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1617
- }
1618
- } else {
1619
- const peeled = peelLabel(core);
1620
- if (!peeled) return null;
1621
- arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1489
+ function inRanges2(cp, ranges) {
1490
+ for (let i = 0; i < ranges.length; i++) {
1491
+ const r = ranges[i];
1492
+ if (cp >= r[0] && cp <= r[1]) return true;
1622
1493
  }
1623
- return { labels: arms.map((a) => a.label), arms, minRepeats };
1494
+ return false;
1624
1495
  }
1625
- function matchArmAt(input, pos, arm) {
1626
- const r = arm.parse(input, pos, { trackLines: false });
1627
- if (!r.ok || r.span.end <= pos) return null;
1628
- return { end: r.span.end };
1496
+ function classScanner(classBody) {
1497
+ const ranges = parseClassRanges(classBody);
1498
+ if (!ranges) return null;
1499
+ return (input, cur) => {
1500
+ let pos = cur;
1501
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1502
+ return pos;
1503
+ };
1629
1504
  }
1630
- function scanLabeledTriviaChunks(input, cur, spec) {
1631
- const chunks = [];
1632
- let pos = cur;
1633
- while (pos < input.length) {
1634
- let matched = null;
1635
- for (const arm of spec.arms) {
1636
- const m = matchArmAt(input, pos, arm.parser);
1637
- if (m) {
1638
- matched = { end: m.end, kindIndex: arm.kindIndex };
1639
- break;
1640
- }
1505
+ function untilLineBreakScanner(leaderCode) {
1506
+ return (input, cur) => {
1507
+ if (input.charCodeAt(cur) !== leaderCode) return cur;
1508
+ let pos = cur + 1;
1509
+ while (pos < input.length) {
1510
+ const cc = input.charCodeAt(pos);
1511
+ if (cc === 10 || cc === 13) break;
1512
+ pos++;
1641
1513
  }
1642
- if (!matched) break;
1643
- chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1644
- pos = matched.end;
1514
+ return pos;
1515
+ };
1516
+ }
1517
+ function classRunSource(source) {
1518
+ const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1519
+ return m ? classScanner(m[1]) : null;
1520
+ }
1521
+ function classifyTriviaArm(arm) {
1522
+ const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1523
+ if (cls) {
1524
+ const ranges = parseClassRanges(cls[1]);
1525
+ return ranges ? { kind: "class", ranges } : null;
1645
1526
  }
1646
- if (chunks.length < spec.minRepeats) {
1647
- return { end: cur, chunks: [] };
1527
+ const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1528
+ if (lc) {
1529
+ const marker = lc[1];
1530
+ return { kind: "untilLineBreak", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1648
1531
  }
1649
- return { end: pos, chunks };
1650
- }
1651
- function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1652
- const chunks = [];
1653
- let pos = cur;
1654
- while (pos < input.length) {
1655
- const c = input.charCodeAt(pos);
1656
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1657
- const start = pos;
1658
- pos++;
1659
- while (pos < input.length) {
1660
- const c2 = input.charCodeAt(pos);
1661
- if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1662
- else break;
1663
- }
1664
- chunks.push({ start, end: pos, kindIndex: wsKind });
1665
- continue;
1666
- }
1667
- if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1668
- let j = pos + 2;
1669
- while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
1670
- if (j + 1 < input.length && input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47) {
1671
- const start = pos;
1672
- pos = j + 2;
1673
- chunks.push({ start, end: pos, kindIndex: commentKind });
1674
- continue;
1675
- }
1676
- break;
1677
- }
1678
- break;
1679
- }
1680
- return { end: pos, chunks };
1681
- }
1682
- function tryFastLabeledScan(input, cur, trivia2) {
1683
- const spec = analyzeLabeledTrivia(trivia2);
1684
- if (!spec || spec.arms.length !== 2) return null;
1685
- const wsArm = spec.arms.find((a) => {
1686
- const src = getCoreRegexDef(a.parser)?.source;
1687
- return src != null && !src.includes("\\*");
1688
- });
1689
- const commentArm = spec.arms.find((a) => {
1690
- const src = getCoreRegexDef(a.parser)?.source;
1691
- return src != null && src.includes("\\*");
1692
- });
1693
- if (!wsArm || !commentArm) return null;
1694
- const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1695
- if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1696
- return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1697
- }
1698
- function recordTriviaChunks(ctx, chunks) {
1699
- const kinds = ctx.triviaKindLabels;
1700
- const mask = ctx._triviaCaptureMask;
1701
- for (const ch2 of chunks) {
1702
- pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1703
- if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1704
- if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1705
- pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1706
- }
1707
- }
1708
- }
1709
- }
1710
- function triviaKindMask(labels, keep) {
1711
- if (!labels) return void 0;
1712
- let mask = 0;
1713
- for (const name of keep) {
1714
- const idx = labels.indexOf(name);
1715
- if (idx >= 0) mask |= 1 << idx;
1716
- }
1717
- return mask;
1718
- }
1719
-
1720
- // src/combinators/trivia-skip.ts
1721
- var NOOP_COMMIT = () => {
1722
- };
1723
- var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1724
- function needsDeferredTriviaCommit(ctx) {
1725
- return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1726
- }
1727
- function saveTriviaMark(ctx) {
1728
- const m = saveCstMark(ctx);
1729
- return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
1730
- }
1731
- function rollbackTrivia(ctx, mark) {
1732
- rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1733
- if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1734
- }
1735
- function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1736
- const probeCtx = {
1737
- trackLines: ctx.trackLines,
1738
- state: ctx.state,
1739
- ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1740
- ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1741
- ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1742
- };
1743
- const result = triviaP.parse(input, cur, probeCtx);
1744
- ctx._lineScannedTo = probeCtx._lineScannedTo;
1745
- return result;
1746
- }
1747
- function saveLookaheadMark(ctx) {
1748
- return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1749
- }
1750
- function rollbackLookahead(ctx, mark) {
1751
- rollbackTrivia(ctx, mark);
1752
- if (ctx._probe) ctx._probe.best = mark.probeBest;
1753
- }
1754
- function scanWithLabels(input, cur, ctx) {
1755
- const triviaP = ctx.trivia;
1756
- const spec = analyzeLabeledTrivia(triviaP);
1757
- if (!spec) return { end: cur, commit: NOOP_COMMIT };
1758
- const fast = tryFastLabeledScan(input, cur, triviaP);
1759
- const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
1760
- if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1761
- return {
1762
- end,
1763
- commit: () => recordTriviaChunks(ctx, chunks)
1764
- };
1765
- }
1766
- function advanceTrivia(input, cur, ctx) {
1767
- const triviaP = ctx.trivia;
1768
- if (!triviaP) return cur;
1769
- if (!ctx.trackLines) {
1770
- const fast2 = fastTriviaScanner(triviaP);
1771
- if (fast2) return fast2(input, cur);
1772
- if (ctx.triviaKindLabels) {
1773
- const scan = scanWithLabels(input, cur, ctx);
1774
- return scan.end;
1775
- }
1776
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1777
- return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1778
- }
1779
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1780
- const fast = fastTriviaScanner(triviaP);
1781
- if (fast) {
1782
- const end = fast(input, cur);
1783
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1784
- return end;
1785
- }
1786
- if (ctx.triviaKindLabels) {
1787
- const scan = scanWithLabels(input, cur, ctx);
1788
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1789
- return scan.end;
1790
- }
1791
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1792
- return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1793
- }
1794
- function scanTrivia(input, cur, ctx) {
1795
- const triviaP = ctx.trivia;
1796
- if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1797
- const log = ctx._triviaLog;
1798
- const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1799
- if (!ctx.trackLines) {
1800
- const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1801
- if (fast2 && log === void 0 && !captureTl) {
1802
- return { end: fast2(input, cur), commit: NOOP_COMMIT };
1803
- }
1804
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1805
- return scanWithLabels(input, cur, ctx);
1806
- }
1807
- if (log !== void 0 || captureTl) {
1808
- const tr3 = triviaP.parse(input, cur, {
1809
- trackLines: log !== void 0 ? false : ctx.trackLines,
1810
- state: ctx.state
1811
- });
1812
- if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1813
- const end = tr3.span.end;
1814
- return {
1815
- end,
1816
- commit: () => {
1817
- pushTriviaLogEntry(ctx, cur, end);
1818
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1819
- }
1820
- };
1821
- }
1822
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1823
- return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1824
- }
1825
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1826
- const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1827
- if (fast && log === void 0 && !captureTl) {
1828
- const end = fast(input, cur);
1829
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1830
- return { end, commit: NOOP_COMMIT };
1831
- }
1832
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1833
- const scan = scanWithLabels(input, cur, ctx);
1834
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1835
- return scan;
1836
- }
1837
- if (log !== void 0 || captureTl) {
1838
- const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1839
- if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1840
- const end = tr2.span.end;
1841
- return {
1842
- end,
1843
- commit: () => {
1844
- pushTriviaLogEntry(ctx, cur, end);
1845
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1846
- }
1847
- };
1848
- }
1849
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1850
- return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1851
- }
1852
- function consumeTrivia(input, cur, ctx) {
1853
- if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1854
- const scan = scanTrivia(input, cur, ctx);
1855
- scan.commit();
1856
- return scan.end;
1857
- }
1858
- function fastTriviaScanner(trivia2) {
1859
- const cached = fastTriviaCache.get(trivia2);
1860
- if (cached !== void 0) return cached;
1861
- const scanner = buildFastTriviaScanner(trivia2);
1862
- fastTriviaCache.set(trivia2, scanner);
1863
- return scanner;
1864
- }
1865
- function buildFastTriviaScanner(trivia2) {
1866
- const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1867
- const direct = regexTriviaScanner(core);
1868
- if (direct) return direct;
1869
- const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1870
- if (!repeat) return null;
1871
- const one = regexTriviaScanner(repeat);
1872
- if (one) return loopScanner([one]);
1873
- if (repeat._def.tag !== "choice") return null;
1874
- const arms = repeat._def.parsers.map(regexTriviaScanner);
1875
- if (arms.some((s) => s === null)) return null;
1876
- return loopScanner(arms);
1877
- }
1878
- function loopScanner(arms) {
1879
- return (input, cur) => {
1880
- let pos = cur;
1881
- scan: while (pos < input.length) {
1882
- for (const arm of arms) {
1883
- const end = arm(input, pos);
1884
- if (end > pos) {
1885
- pos = end;
1886
- continue scan;
1887
- }
1888
- }
1889
- break;
1890
- }
1891
- return pos;
1892
- };
1893
- }
1894
- function regexTriviaScanner(parser2) {
1895
- if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1896
- const source = parser2._def.source;
1897
- return classRunSource(source) ?? altStarSource(source) ?? (blockCommentSource(source) ? scanBlockComment : null);
1898
- }
1899
- function inRanges2(cp, ranges) {
1900
- for (let i = 0; i < ranges.length; i++) {
1901
- const r = ranges[i];
1902
- if (cp >= r[0] && cp <= r[1]) return true;
1903
- }
1904
- return false;
1905
- }
1906
- function classScanner(classBody) {
1907
- const ranges = parseClassRanges(classBody);
1908
- if (!ranges) return null;
1909
- return (input, cur) => {
1910
- let pos = cur;
1911
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1912
- return pos;
1913
- };
1914
- }
1915
- function lineCommentScanner(commentCode) {
1916
- return (input, cur) => {
1917
- if (input.charCodeAt(cur) !== commentCode) return cur;
1918
- let pos = cur + 1;
1919
- while (pos < input.length) {
1920
- const cc = input.charCodeAt(pos);
1921
- if (cc === 10 || cc === 13) break;
1922
- pos++;
1923
- }
1924
- return pos;
1925
- };
1926
- }
1927
- function classRunSource(source) {
1928
- const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1929
- return m ? classScanner(m[1]) : null;
1930
- }
1931
- function classifyTriviaArm(arm) {
1932
- const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1933
- if (cls) {
1934
- const ranges = parseClassRanges(cls[1]);
1935
- return ranges ? { kind: "class", ranges } : null;
1936
- }
1937
- const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1938
- if (lc) {
1939
- const marker = lc[1];
1940
- return { kind: "comment", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1941
- }
1942
- return null;
1532
+ return null;
1943
1533
  }
1944
1534
  function armScanner(arm) {
1945
- if (arm.kind === "comment") return lineCommentScanner(arm.code);
1535
+ if (arm.kind === "untilLineBreak") return untilLineBreakScanner(arm.code);
1946
1536
  const ranges = arm.ranges;
1947
1537
  return (input, cur) => {
1948
1538
  let pos = cur;
@@ -1950,9 +1540,9 @@ function armScanner(arm) {
1950
1540
  return pos;
1951
1541
  };
1952
1542
  }
1953
- function fusedTriviaScanner(ranges, commentCodes) {
1954
- const c0 = commentCodes[0];
1955
- const single = commentCodes.length === 1;
1543
+ function fusedTriviaScanner(ranges, leaders) {
1544
+ const c0 = leaders[0];
1545
+ const single = leaders.length === 1;
1956
1546
  return (input, cur) => {
1957
1547
  let pos = cur;
1958
1548
  const len = input.length;
@@ -1962,7 +1552,7 @@ function fusedTriviaScanner(ranges, commentCodes) {
1962
1552
  pos++;
1963
1553
  continue;
1964
1554
  }
1965
- if (single ? c === c0 : commentCodes.includes(c)) {
1555
+ if (single ? c === c0 : leaders.includes(c)) {
1966
1556
  pos++;
1967
1557
  while (pos < len) {
1968
1558
  const cc = input.charCodeAt(pos);
@@ -1971,166 +1561,640 @@ function fusedTriviaScanner(ranges, commentCodes) {
1971
1561
  }
1972
1562
  continue;
1973
1563
  }
1974
- break;
1564
+ break;
1565
+ }
1566
+ return pos;
1567
+ };
1568
+ }
1569
+ function splitTopLevelAlts(body) {
1570
+ const arms = [];
1571
+ let inClass = false;
1572
+ let start = 0;
1573
+ for (let i = 0; i < body.length; i++) {
1574
+ const c = body[i];
1575
+ if (c === "\\") {
1576
+ i++;
1577
+ continue;
1578
+ }
1579
+ if (inClass) {
1580
+ if (c === "]") inClass = false;
1581
+ continue;
1582
+ }
1583
+ if (c === "[") inClass = true;
1584
+ else if (c === "(") return null;
1585
+ else if (c === "|") {
1586
+ arms.push(body.slice(start, i));
1587
+ start = i + 1;
1588
+ }
1589
+ }
1590
+ arms.push(body.slice(start));
1591
+ return arms;
1592
+ }
1593
+ function altStarSource(source) {
1594
+ const m = /^\(\?:(.*)\)[*+]$/.exec(source);
1595
+ if (!m) return null;
1596
+ const armSrcs = splitTopLevelAlts(m[1]);
1597
+ if (!armSrcs || armSrcs.length < 2) return null;
1598
+ const arms = [];
1599
+ for (const src of armSrcs) {
1600
+ const arm = classifyTriviaArm(src);
1601
+ if (!arm) return null;
1602
+ arms.push(arm);
1603
+ }
1604
+ const ranges = [];
1605
+ const leaders = [];
1606
+ for (const arm of arms) {
1607
+ if (arm.kind === "class") ranges.push(...arm.ranges);
1608
+ else leaders.push(arm.code);
1609
+ }
1610
+ if (leaders.some((code) => inRanges2(code, ranges))) {
1611
+ return loopScanner(arms.map(armScanner));
1612
+ }
1613
+ if (leaders.length === 0) return armScanner({ kind: "class", ranges });
1614
+ return fusedTriviaScanner(ranges, leaders);
1615
+ }
1616
+
1617
+ // src/recovery/scan.ts
1618
+ function probeAt(sentinel, input, pos, ctx) {
1619
+ const s = {
1620
+ _probe: ctx._probe,
1621
+ _errors: ctx._errors,
1622
+ _cstLeaves: ctx._cstLeaves,
1623
+ _cstChildren: ctx._cstChildren,
1624
+ _cstRawChildren: ctx._cstRawChildren,
1625
+ _cstTriviaLog: ctx._cstTriviaLog,
1626
+ _triviaLog: ctx._triviaLog,
1627
+ _rootTriviaLog: ctx._rootTriviaLog,
1628
+ _fields: ctx._fields,
1629
+ _cstBuf: ctx._cstBuf,
1630
+ _tolerant: ctx._tolerant,
1631
+ _sync: ctx._sync
1632
+ };
1633
+ ctx._probe = void 0;
1634
+ ctx._errors = void 0;
1635
+ ctx._cstLeaves = void 0;
1636
+ ctx._cstChildren = void 0;
1637
+ ctx._cstRawChildren = void 0;
1638
+ ctx._cstTriviaLog = void 0;
1639
+ ctx._triviaLog = void 0;
1640
+ ctx._rootTriviaLog = void 0;
1641
+ ctx._fields = void 0;
1642
+ ctx._cstBuf = void 0;
1643
+ ctx._tolerant = void 0;
1644
+ ctx._sync = void 0;
1645
+ try {
1646
+ return sentinel.parse(input, pos, ctx).ok;
1647
+ } finally {
1648
+ ctx._probe = s._probe;
1649
+ ctx._errors = s._errors;
1650
+ ctx._cstLeaves = s._cstLeaves;
1651
+ ctx._cstChildren = s._cstChildren;
1652
+ ctx._cstRawChildren = s._cstRawChildren;
1653
+ ctx._cstTriviaLog = s._cstTriviaLog;
1654
+ ctx._triviaLog = s._triviaLog;
1655
+ ctx._rootTriviaLog = s._rootTriviaLog;
1656
+ ctx._fields = s._fields;
1657
+ ctx._cstBuf = s._cstBuf;
1658
+ ctx._tolerant = s._tolerant;
1659
+ ctx._sync = s._sync;
1660
+ }
1661
+ }
1662
+ function orSentinel(a, b) {
1663
+ if (b === void 0) return a;
1664
+ return {
1665
+ _tag: "orSentinel",
1666
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1667
+ _def: { tag: "unknown" },
1668
+ parse(input, pos, ctx) {
1669
+ const ra = a.parse(input, pos, ctx);
1670
+ if (ra.ok) return ra;
1671
+ return b.parse(input, pos, ctx);
1672
+ }
1673
+ };
1674
+ }
1675
+ function firstSetSentinel(fs2) {
1676
+ if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
1677
+ const ranges = fs2.ranges;
1678
+ return {
1679
+ _tag: "firstSetSentinel",
1680
+ _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
1681
+ _def: { tag: "unknown" },
1682
+ parse(input, pos) {
1683
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
1684
+ if (code !== void 0) {
1685
+ for (const r of ranges) {
1686
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1687
+ }
1688
+ }
1689
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
1690
+ }
1691
+ };
1692
+ }
1693
+ function recoverScan(input, from, ctx, sync, expected) {
1694
+ let scanPos = from;
1695
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1696
+ const span = { start: from, end: scanPos };
1697
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1698
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1699
+ ctx._errors?.push(error);
1700
+ return { error, end: scanPos };
1701
+ }
1702
+ function matchesAt(sentinel, input, pos, ctx) {
1703
+ return probeAt(sentinel, input, pos, ctx);
1704
+ }
1705
+ function captureError(ctx, error) {
1706
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1707
+ }
1708
+
1709
+ // src/combinators/sequence.ts
1710
+ function sequence(...parsers) {
1711
+ const meta = {
1712
+ // Union through the nullable prefix — a leading optional()/many() lets a later
1713
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
1714
+ firstSet: sequenceFirstSet(parsers),
1715
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1716
+ isTrivia: false
1717
+ };
1718
+ const def = { tag: "sequence", parsers };
1719
+ let followSentinels;
1720
+ function parseTolerant(input, pos, ctx) {
1721
+ followSentinels ??= parsers.map((_, i) => {
1722
+ const fs2 = parsers.slice(i + 1).reduce(
1723
+ (acc, p) => union(acc, firstSetOf(p)),
1724
+ { kind: "empty" }
1725
+ );
1726
+ return firstSetSentinel(fs2);
1727
+ });
1728
+ const values = def.valueUnused ? void 0 : [];
1729
+ let cur = pos;
1730
+ const inheritedSync = ctx._sync;
1731
+ try {
1732
+ for (let i = 0; i < parsers.length; i++) {
1733
+ ctx._sync = followSentinels[i] ?? inheritedSync;
1734
+ if (ctx.trivia && i > 0) {
1735
+ const mark = saveTriviaMark(ctx);
1736
+ let scanEnd;
1737
+ if (needsDeferredTriviaCommit(ctx)) {
1738
+ const scan = scanTrivia(input, cur, ctx);
1739
+ scan.commit();
1740
+ scanEnd = scan.end;
1741
+ } else {
1742
+ scanEnd = advanceTrivia(input, cur, ctx);
1743
+ }
1744
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1745
+ if (!result2.ok) return result2;
1746
+ if (result2.span.end > scanEnd) cur = result2.span.end;
1747
+ else rollbackTrivia(ctx, mark);
1748
+ if (values !== void 0) values.push(result2.value);
1749
+ continue;
1750
+ }
1751
+ const result = parsers[i].parse(input, cur, ctx);
1752
+ if (!result.ok) return result;
1753
+ if (values !== void 0) values.push(result.value);
1754
+ cur = result.span.end;
1755
+ }
1756
+ } finally {
1757
+ ctx._sync = inheritedSync;
1758
+ }
1759
+ return {
1760
+ ok: true,
1761
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1762
+ value: values ?? void 0,
1763
+ span: { start: pos, end: cur }
1764
+ };
1765
+ }
1766
+ return {
1767
+ _tag: "sequence",
1768
+ _meta: meta,
1769
+ _def: def,
1770
+ parse(input, pos, ctx) {
1771
+ if (ctx._tolerant) return parseTolerant(input, pos, ctx);
1772
+ const values = def.valueUnused ? void 0 : [];
1773
+ let cur = pos;
1774
+ for (let i = 0; i < parsers.length; i++) {
1775
+ if (ctx.trivia && i > 0) {
1776
+ let scanEnd;
1777
+ let mark = saveTriviaMark(ctx);
1778
+ if (needsDeferredTriviaCommit(ctx)) {
1779
+ const scan = scanTrivia(input, cur, ctx);
1780
+ scan.commit();
1781
+ scanEnd = scan.end;
1782
+ } else {
1783
+ scanEnd = advanceTrivia(input, cur, ctx);
1784
+ }
1785
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1786
+ if (!result2.ok) return result2;
1787
+ if (result2.span.end > scanEnd) {
1788
+ cur = result2.span.end;
1789
+ } else {
1790
+ rollbackTrivia(ctx, mark);
1791
+ }
1792
+ if (values !== void 0) values.push(result2.value);
1793
+ continue;
1794
+ }
1795
+ const result = parsers[i].parse(input, cur, ctx);
1796
+ if (!result.ok) return result;
1797
+ if (values !== void 0) values.push(result.value);
1798
+ cur = result.span.end;
1799
+ }
1800
+ return {
1801
+ ok: true,
1802
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1803
+ value: values ?? void 0,
1804
+ span: { start: pos, end: cur }
1805
+ };
1806
+ }
1807
+ };
1808
+ }
1809
+
1810
+ // src/combinators/expect.ts
1811
+ function deriveExpected(c) {
1812
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1813
+ }
1814
+ function derive(c, seen) {
1815
+ const deriveExpected2 = (p) => derive(p, seen);
1816
+ const def = c._def;
1817
+ switch (def.tag) {
1818
+ case "literal":
1819
+ return [JSON.stringify(def.value)];
1820
+ case "regex":
1821
+ return [`/${def.source}/`];
1822
+ case "keywords":
1823
+ return def.words.map((w) => JSON.stringify(w));
1824
+ case "label":
1825
+ return [def.label];
1826
+ case "choice":
1827
+ return def.parsers.flatMap(deriveExpected2);
1828
+ case "dispatch":
1829
+ return deriveExpected2(def.selector);
1830
+ // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1831
+ // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1832
+ // able to fail first — deriving from term 0 alone named a token the parse
1833
+ // never actually required. A leading `not(…)` is zero-width and contributes
1834
+ // nothing (its own expectation is about what must NOT be here), but it is
1835
+ // nullable, so keep scanning past it. Stop at the first term that must match.
1836
+ case "sequence": {
1837
+ const out = [];
1838
+ for (const term of def.parsers) {
1839
+ if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1840
+ if (!matchesEmpty(term)) break;
1841
+ }
1842
+ return out;
1843
+ }
1844
+ case "attempt":
1845
+ return deriveExpected2(def.parser);
1846
+ // Delegating wrappers whose first-token failure is their inner parser's — must
1847
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1848
+ // node, which reads this) names the real expected token, not the wrapper tag.
1849
+ case "field":
1850
+ case "withCtx":
1851
+ case "recover":
1852
+ return deriveExpected2(def.parser);
1853
+ case "skip":
1854
+ return deriveExpected2(def.main);
1855
+ case "expect":
1856
+ return def.expected;
1857
+ case "node":
1858
+ case "grammar":
1859
+ case "trivia":
1860
+ case "token":
1861
+ case "leaf":
1862
+ case "optional":
1863
+ case "many":
1864
+ case "oneOrMore":
1865
+ case "transform":
1866
+ case "not":
1867
+ case "peek":
1868
+ return deriveExpected2(def.parser);
1869
+ case "routed":
1870
+ return ["routed()"];
1871
+ case "lazy": {
1872
+ const name = c._ruleName;
1873
+ if (seen.has(c)) return name ? [name] : [];
1874
+ seen.add(c);
1875
+ try {
1876
+ return deriveExpected2(def.thunk());
1877
+ } catch {
1878
+ return name ? [name] : [];
1879
+ } finally {
1880
+ seen.delete(c);
1881
+ }
1882
+ }
1883
+ default:
1884
+ return [];
1885
+ }
1886
+ }
1887
+ function expect(combinator, label2) {
1888
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1889
+ const meta = {
1890
+ firstSet: combinator._meta.firstSet,
1891
+ canMatchNewline: combinator._meta.canMatchNewline,
1892
+ isTrivia: false
1893
+ };
1894
+ return {
1895
+ _tag: "expect",
1896
+ _meta: meta,
1897
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
1898
+ parse(input, pos, ctx) {
1899
+ const result = combinator.parse(input, pos, ctx);
1900
+ if (result.ok) return result;
1901
+ const span = { start: pos, end: pos };
1902
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1903
+ ctx._errors?.push(error);
1904
+ if (ctx._tolerant) captureError(ctx, error);
1905
+ return { ok: true, value: error, span: { start: pos, end: pos } };
1906
+ }
1907
+ };
1908
+ }
1909
+
1910
+ // src/combinators/choice.ts
1911
+ function choice(...args) {
1912
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1913
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
1914
+ const hasGates = gates.some((g) => g !== null);
1915
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1916
+ let combined = { kind: "empty" };
1917
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
1918
+ const meta = {
1919
+ firstSet: combined,
1920
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1921
+ isTrivia: false,
1922
+ disjoint
1923
+ };
1924
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1925
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1926
+ let greedyLitMap = null;
1927
+ let sortedParsers = null;
1928
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1929
+ if (strategy?.tag === "greedyClassify") {
1930
+ greedyLitMap = /* @__PURE__ */ new Map();
1931
+ for (let i = 0; i < parsers.length; i++) {
1932
+ if (i === strategy.superIndex) continue;
1933
+ const litVal = getCoreLiteralValue(parsers[i]);
1934
+ if (litVal !== null) greedyLitMap.set(litVal, i);
1935
+ }
1936
+ } else if (strategy?.tag === "literalsLongestFirst") {
1937
+ sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
1938
+ }
1939
+ return {
1940
+ _tag: "choice",
1941
+ _meta: meta,
1942
+ _def: {
1943
+ tag: "choice",
1944
+ parsers,
1945
+ gates,
1946
+ disjoint,
1947
+ strategy: strategy ?? { tag: "firstMatch" },
1948
+ autoNot
1949
+ },
1950
+ parse(input, pos, ctx) {
1951
+ const expected = [];
1952
+ if (disjoint && pos < input.length) {
1953
+ const code = input.codePointAt(pos);
1954
+ let idx = code < 128 ? asciiDispatch[code] : -1;
1955
+ if (idx < 0) {
1956
+ for (let i = 0; i < parsers.length; i++) {
1957
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1958
+ idx = i;
1959
+ break;
1960
+ }
1961
+ }
1962
+ }
1963
+ if (idx >= 0) {
1964
+ const gate2 = gates[idx];
1965
+ if (gate2 && !gate2(ctx.state)) {
1966
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1967
+ }
1968
+ const result = parsers[idx].parse(input, pos, ctx);
1969
+ if (result.ok) return result;
1970
+ expected.push(...result.expected);
1971
+ if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1972
+ return { ok: false, expected, span: { start: pos, end: pos } };
1973
+ }
1974
+ return {
1975
+ ok: false,
1976
+ expected: parsers.flatMap((p) => {
1977
+ const r = p.parse(input, pos, ctx);
1978
+ return r.ok ? [] : r.expected;
1979
+ }),
1980
+ span: { start: pos, end: pos }
1981
+ };
1982
+ }
1983
+ if (strategy?.tag === "greedyClassify") {
1984
+ const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1985
+ if (!superResult.ok) return superResult;
1986
+ const end = superResult.span.end;
1987
+ const litIdx = greedyLitMap.get(input.slice(pos, end));
1988
+ if (litIdx !== void 0) {
1989
+ const litVal = getCoreLiteralValue(parsers[litIdx]);
1990
+ const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1991
+ return { ok: true, value, span: { start: pos, end } };
1992
+ }
1993
+ return superResult;
1994
+ }
1995
+ if (strategy?.tag === "literalsLongestFirst") {
1996
+ for (const p of sortedParsers) {
1997
+ const r = p.parse(input, pos, ctx);
1998
+ if (r.ok) return r;
1999
+ expected.push(...r.expected);
2000
+ }
2001
+ return { ok: false, expected, span: { start: pos, end: pos } };
2002
+ }
2003
+ for (let i = 0; i < parsers.length; i++) {
2004
+ if (gates[i] && !gates[i](ctx.state)) continue;
2005
+ const mark = saveTriviaMark(ctx);
2006
+ const result = parsers[i].parse(input, pos, ctx);
2007
+ if (!result.ok) {
2008
+ rollbackTrivia(ctx, mark);
2009
+ expected.push(...result.expected);
2010
+ if (result.committed) return { ok: false, expected, span: result.span, committed: true };
2011
+ continue;
2012
+ }
2013
+ const checks = autoNot[i];
2014
+ if (checks && autoNotFires(input, result.span.end, checks)) {
2015
+ rollbackTrivia(ctx, mark);
2016
+ continue;
2017
+ }
2018
+ return result;
2019
+ }
2020
+ return { ok: false, expected, span: { start: pos, end: pos } };
2021
+ }
2022
+ };
2023
+ }
2024
+ function detectStrategy(parsers) {
2025
+ const regexIndices = [];
2026
+ const literalIndices = [];
2027
+ for (let i = 0; i < parsers.length; i++) {
2028
+ if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
2029
+ else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
2030
+ }
2031
+ if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
2032
+ const superIndex = regexIndices[0];
2033
+ const regexDef = getCoreRegexDef(parsers[superIndex]);
2034
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
2035
+ const re = new RegExp(regexDef.source, flags);
2036
+ const allSubsumed = literalIndices.every((i) => {
2037
+ const litVal = getCoreLiteralValue(parsers[i]);
2038
+ re.lastIndex = 0;
2039
+ const m = re.exec(litVal);
2040
+ return m !== null && m[0] === litVal;
2041
+ });
2042
+ if (allSubsumed) return { tag: "greedyClassify", superIndex };
2043
+ }
2044
+ if (parsers.length === literalIndices.length) {
2045
+ const sortedIndices = [...literalIndices].sort(
2046
+ (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
2047
+ );
2048
+ return { tag: "literalsLongestFirst", sortedIndices };
2049
+ }
2050
+ const shared = detectSharedPrefix(parsers);
2051
+ if (shared !== null) return shared;
2052
+ return { tag: "firstMatch" };
2053
+ }
2054
+ function bareLeadingTermKey(term) {
2055
+ const d = term._def;
2056
+ if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
2057
+ if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
2058
+ return null;
2059
+ }
2060
+ function detectSharedPrefix(parsers) {
2061
+ if (parsers.length < 2) return null;
2062
+ let key = null;
2063
+ let prefix = null;
2064
+ const members = [];
2065
+ for (let i = 0; i < parsers.length; i++) {
2066
+ const term0 = leadingTermOfArm(parsers[i]);
2067
+ if (term0 === null) return null;
2068
+ const k = bareLeadingTermKey(term0);
2069
+ if (k === null) return null;
2070
+ if (key === null) {
2071
+ key = k;
2072
+ prefix = term0;
2073
+ } else if (k !== key) return null;
2074
+ members.push(i);
2075
+ }
2076
+ if (prefix === null || members.length < 2) return null;
2077
+ return { tag: "sharedPrefix", prefix, members };
2078
+ }
2079
+ function leadingTermOfArm(arm) {
2080
+ let d = arm._def;
2081
+ for (; ; ) {
2082
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
2083
+ d = d.parser._def;
2084
+ continue;
2085
+ }
2086
+ break;
2087
+ }
2088
+ if (d.tag !== "sequence" || d.parsers.length < 2) return null;
2089
+ return d.parsers[0];
2090
+ }
2091
+ function computeAutoNot(parsers) {
2092
+ return parsers.map((p, i) => {
2093
+ const litVal = getCoreLiteralValue(p);
2094
+ if (litVal === null) return null;
2095
+ const checks = [];
2096
+ for (let j = i + 1; j < parsers.length; j++) {
2097
+ const other = parsers[j];
2098
+ const otherLit = getCoreLiteralValue(other);
2099
+ if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
2100
+ checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
2101
+ continue;
2102
+ }
2103
+ const regexDef = getCoreRegexDef(other);
2104
+ if (regexDef !== null) {
2105
+ const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
2106
+ if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
2107
+ }
1975
2108
  }
1976
- return pos;
1977
- };
2109
+ return checks.length > 0 ? checks : null;
2110
+ });
1978
2111
  }
1979
- function splitTopLevelAlts(body) {
1980
- const arms = [];
1981
- let inClass = false;
1982
- let start = 0;
1983
- for (let i = 0; i < body.length; i++) {
1984
- const c = body[i];
1985
- if (c === "\\") {
1986
- i++;
1987
- continue;
1988
- }
1989
- if (inClass) {
1990
- if (c === "]") inClass = false;
1991
- continue;
1992
- }
1993
- if (c === "[") inClass = true;
1994
- else if (c === "(") return null;
1995
- else if (c === "|") {
1996
- arms.push(body.slice(start, i));
1997
- start = i + 1;
2112
+ function autoNotFires(input, end, checks) {
2113
+ for (const check of checks) {
2114
+ if (check.kind === "firstSet") {
2115
+ const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
2116
+ if (inFirstSet(code, check.set)) return true;
2117
+ } else {
2118
+ if (input.startsWith(check.value, end)) return true;
1998
2119
  }
1999
2120
  }
2000
- arms.push(body.slice(start));
2001
- return arms;
2121
+ return false;
2002
2122
  }
2003
- function altStarSource(source) {
2004
- const m = /^\(\?:(.*)\)[*+]$/.exec(source);
2005
- if (!m) return null;
2006
- const armSrcs = splitTopLevelAlts(m[1]);
2007
- if (!armSrcs || armSrcs.length < 2) return null;
2008
- const arms = [];
2009
- for (const src of armSrcs) {
2010
- const arm = classifyTriviaArm(src);
2011
- if (!arm) return null;
2012
- arms.push(arm);
2123
+ function getCoreLiteralValue(p) {
2124
+ const def = p._def;
2125
+ if (def.tag === "literal" && !def.caseInsensitive) return def.value;
2126
+ if (def.tag === "transform") return getCoreLiteralValue(def.parser);
2127
+ return null;
2128
+ }
2129
+ function getCoreRegexDef(p) {
2130
+ const def = p._def;
2131
+ if (def.tag === "regex") return { source: def.source, flags: def.flags };
2132
+ if (def.tag === "transform") return getCoreRegexDef(def.parser);
2133
+ if (def.tag === "label") return getCoreRegexDef(def.parser);
2134
+ return null;
2135
+ }
2136
+ function applyTransforms(p, value, span) {
2137
+ const def = p._def;
2138
+ if (def.tag === "transform") {
2139
+ const inner = applyTransforms(def.parser, value, span);
2140
+ return def.fn(inner, span);
2013
2141
  }
2014
- const ranges = [];
2015
- const commentCodes = [];
2016
- for (const arm of arms) {
2017
- if (arm.kind === "class") ranges.push(...arm.ranges);
2018
- else commentCodes.push(arm.code);
2142
+ return value;
2143
+ }
2144
+ function continuationFirstSet(lit, source, flags) {
2145
+ const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
2146
+ re.lastIndex = 0;
2147
+ const base = re.exec(lit);
2148
+ if (!base || base[0] !== lit) return null;
2149
+ const contCodes = [];
2150
+ for (let code = 1; code < 128; code++) {
2151
+ re.lastIndex = 0;
2152
+ const m = re.exec(lit + String.fromCharCode(code));
2153
+ if (m && m[0].length > lit.length) contCodes.push(code);
2019
2154
  }
2020
- if (commentCodes.some((code) => inRanges2(code, ranges))) {
2021
- return loopScanner(arms.map(armScanner));
2155
+ if (contCodes.length === 0) return null;
2156
+ return codesToFirstSet(contCodes);
2157
+ }
2158
+ function codesToFirstSet(codes) {
2159
+ codes.sort((a, b) => a - b);
2160
+ const ranges = [];
2161
+ let lo = codes[0], hi = codes[0];
2162
+ for (let i = 1; i < codes.length; i++) {
2163
+ if (codes[i] === hi + 1) {
2164
+ hi = codes[i];
2165
+ } else {
2166
+ ranges.push({ lo, hi });
2167
+ lo = hi = codes[i];
2168
+ }
2022
2169
  }
2023
- if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
2024
- return fusedTriviaScanner(ranges, commentCodes);
2170
+ ranges.push({ lo, hi });
2171
+ return { kind: "ranges", ranges };
2025
2172
  }
2026
- function blockCommentSource(source) {
2027
- return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
2173
+ function inFirstSet(code, fs2) {
2174
+ if (fs2.kind === "any") return true;
2175
+ if (fs2.kind === "empty") return false;
2176
+ for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
2177
+ return false;
2028
2178
  }
2029
- function scanBlockComment(input, cur) {
2030
- if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
2031
- const close = input.indexOf("*/", cur + 2);
2032
- return close === -1 ? cur : close + 2;
2179
+ function areDisjoint(sets) {
2180
+ if (sets.some((s) => s.kind === "any")) return false;
2181
+ for (let i = 0; i < sets.length; i++)
2182
+ for (let j = i + 1; j < sets.length; j++)
2183
+ if (intersects(sets[i], sets[j])) return false;
2184
+ return true;
2033
2185
  }
2034
-
2035
- // src/combinators/sequence.ts
2036
- function sequence(...parsers) {
2037
- const meta = {
2038
- // Union through the nullable prefix — a leading optional()/many() lets a later
2039
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
2040
- firstSet: sequenceFirstSet(parsers),
2041
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2042
- isTrivia: false
2043
- };
2044
- const def = { tag: "sequence", parsers };
2045
- let followSentinels;
2046
- function parseTolerant(input, pos, ctx) {
2047
- followSentinels ??= parsers.map((_, i) => {
2048
- const fs2 = parsers.slice(i + 1).reduce(
2049
- (acc, p) => union(acc, firstSetOf(p)),
2050
- { kind: "empty" }
2051
- );
2052
- return firstSetSentinel(fs2);
2053
- });
2054
- const values = def.valueUnused ? void 0 : [];
2055
- let cur = pos;
2056
- const inheritedSync = ctx._sync;
2057
- try {
2058
- for (let i = 0; i < parsers.length; i++) {
2059
- ctx._sync = followSentinels[i] ?? inheritedSync;
2060
- if (ctx.trivia && i > 0) {
2061
- const mark = saveTriviaMark(ctx);
2062
- let scanEnd;
2063
- if (needsDeferredTriviaCommit(ctx)) {
2064
- const scan = scanTrivia(input, cur, ctx);
2065
- scan.commit();
2066
- scanEnd = scan.end;
2067
- } else {
2068
- scanEnd = advanceTrivia(input, cur, ctx);
2069
- }
2070
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2071
- if (!result2.ok) return result2;
2072
- if (result2.span.end > scanEnd) cur = result2.span.end;
2073
- else rollbackTrivia(ctx, mark);
2074
- if (values !== void 0) values.push(result2.value);
2075
- continue;
2076
- }
2077
- const result = parsers[i].parse(input, cur, ctx);
2078
- if (!result.ok) return result;
2079
- if (values !== void 0) values.push(result.value);
2080
- cur = result.span.end;
2186
+ function buildAsciiDispatch(parsers) {
2187
+ const table = Array(128).fill(-1);
2188
+ for (let i = 0; i < parsers.length; i++) {
2189
+ const fs2 = parsers[i]._meta.firstSet;
2190
+ if (fs2.kind !== "ranges") continue;
2191
+ for (const { lo, hi } of fs2.ranges) {
2192
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
2193
+ table[code] = i;
2081
2194
  }
2082
- } finally {
2083
- ctx._sync = inheritedSync;
2084
2195
  }
2085
- return {
2086
- ok: true,
2087
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2088
- value: values ?? void 0,
2089
- span: { start: pos, end: cur }
2090
- };
2091
2196
  }
2092
- return {
2093
- _tag: "sequence",
2094
- _meta: meta,
2095
- _def: def,
2096
- parse(input, pos, ctx) {
2097
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2098
- const values = def.valueUnused ? void 0 : [];
2099
- let cur = pos;
2100
- for (let i = 0; i < parsers.length; i++) {
2101
- if (ctx.trivia && i > 0) {
2102
- let scanEnd;
2103
- let mark = saveTriviaMark(ctx);
2104
- if (needsDeferredTriviaCommit(ctx)) {
2105
- const scan = scanTrivia(input, cur, ctx);
2106
- scan.commit();
2107
- scanEnd = scan.end;
2108
- } else {
2109
- scanEnd = advanceTrivia(input, cur, ctx);
2110
- }
2111
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2112
- if (!result2.ok) return result2;
2113
- if (result2.span.end > scanEnd) {
2114
- cur = result2.span.end;
2115
- } else {
2116
- rollbackTrivia(ctx, mark);
2117
- }
2118
- if (values !== void 0) values.push(result2.value);
2119
- continue;
2120
- }
2121
- const result = parsers[i].parse(input, cur, ctx);
2122
- if (!result.ok) return result;
2123
- if (values !== void 0) values.push(result.value);
2124
- cur = result.span.end;
2125
- }
2126
- return {
2127
- ok: true,
2128
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2129
- value: values ?? void 0,
2130
- span: { start: pos, end: cur }
2131
- };
2132
- }
2133
- };
2197
+ return table;
2134
2198
  }
2135
2199
 
2136
2200
  // src/combinators/dispatch.ts
@@ -2390,10 +2454,12 @@ function attempt(parser2) {
2390
2454
  }
2391
2455
  const mark = saveCstMark(ctx);
2392
2456
  const log = ctx._triviaLog?.length;
2457
+ const rootLog = ctx._rootTriviaLog?.length;
2393
2458
  const result = parser2.parse(input, pos, ctx);
2394
2459
  if (result.ok) return result;
2395
2460
  rollbackCstCapture(ctx, mark);
2396
2461
  if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
2462
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
2397
2463
  if (result.committed) return result;
2398
2464
  return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
2399
2465
  }
@@ -2797,18 +2863,37 @@ function createParseLineContext(input, pos) {
2797
2863
  }
2798
2864
  function parser(opts, root) {
2799
2865
  const clearTrivia = opts.trivia === null;
2866
+ const opaqueRootCapture = opts.rootCapture === "opaque";
2867
+ if (opaqueRootCapture && opts.trivia === void 0) {
2868
+ throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
2869
+ }
2800
2870
  return {
2801
2871
  _tag: "grammar",
2802
- _meta: root._meta,
2872
+ _meta: {
2873
+ ...root._meta,
2874
+ // Trivia classification describes this grammar's own active trivia
2875
+ // scope. A directly nested grammar may have classified trivia of its
2876
+ // own, but that must not advertise classification for this wrapper.
2877
+ triviaKindLabels: void 0,
2878
+ rootTriviaClassified: void 0,
2879
+ ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
2880
+ ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
2881
+ },
2803
2882
  _def: {
2804
2883
  tag: "grammar",
2805
2884
  parser: root,
2806
2885
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2807
2886
  clearTrivia,
2887
+ ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
2808
2888
  ...opts.captureTrivia ? { captureTrivia: true } : {},
2809
2889
  trackLines: opts.trackLines ?? false
2810
2890
  },
2811
2891
  parse(input, pos, _ctx) {
2892
+ if (_ctx?._rootTriviaStrictScopes && opts.trivia !== void 0 && opts.trivia !== null && !opts.trivia._meta.rootTriviaClassified && !opaqueRootCapture) {
2893
+ throw new TypeError(
2894
+ "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'."
2895
+ );
2896
+ }
2812
2897
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2813
2898
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2814
2899
  const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
@@ -2831,7 +2916,11 @@ function parser(opts, root) {
2831
2916
  // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2832
2917
  // trivia is inherited rather than re-declared here. No labels → undefined
2833
2918
  // (capture all).
2834
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2919
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {},
2920
+ // This is a property of the local trivia scope, not a post-parse filter:
2921
+ // nested recognition can still skip its trivia, but selected root rows
2922
+ // must never be written for an explicitly opaque region.
2923
+ ...opaqueRootCapture ? { _rootTriviaCapture: false } : {}
2835
2924
  };
2836
2925
  const result = root.parse(input, pos ?? 0, ctx);
2837
2926
  if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
@@ -3484,6 +3573,25 @@ function trivia(combinator) {
3484
3573
  parse: combinator.parse.bind(combinator)
3485
3574
  };
3486
3575
  }
3576
+ function classifiedTrivia(arms) {
3577
+ const entries = Object.entries(arms);
3578
+ if (entries.length === 0) {
3579
+ throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
3580
+ }
3581
+ for (let i = 0; i < entries.length; i++) {
3582
+ const [name, arm] = entries[i];
3583
+ const first = arm._meta.firstSet;
3584
+ if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
3585
+ throw new TypeError(
3586
+ `classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
3587
+ );
3588
+ }
3589
+ }
3590
+ const labeledArms = entries.map(([name, arm]) => label(name, arm));
3591
+ const result = trivia(oneOrMore(choice(...labeledArms)));
3592
+ result._meta.rootTriviaClassified = true;
3593
+ return result;
3594
+ }
3487
3595
  function label(name, combinator) {
3488
3596
  return {
3489
3597
  _tag: combinator._tag,
@@ -3530,6 +3638,7 @@ function token(root) {
3530
3638
  const savedRaw = ctx._cstRawChildren;
3531
3639
  const savedTriviaLog = ctx._cstTriviaLog;
3532
3640
  const savedOuterTriviaLog = ctx._triviaLog;
3641
+ const savedRootTriviaLog = ctx._rootTriviaLog;
3533
3642
  const wasCapturing = cstCaptureActive(ctx);
3534
3643
  ctx.trivia = void 0;
3535
3644
  ctx.triviaKindLabels = void 0;
@@ -3539,6 +3648,7 @@ function token(root) {
3539
3648
  ctx._cstRawChildren = void 0;
3540
3649
  ctx._cstTriviaLog = void 0;
3541
3650
  delete ctx._triviaLog;
3651
+ delete ctx._rootTriviaLog;
3542
3652
  let result;
3543
3653
  try {
3544
3654
  result = root.parse(input, pos, ctx);
@@ -3552,6 +3662,8 @@ function token(root) {
3552
3662
  ctx._cstTriviaLog = savedTriviaLog;
3553
3663
  if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
3554
3664
  else ctx._triviaLog = savedOuterTriviaLog;
3665
+ if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
3666
+ else ctx._rootTriviaLog = savedRootTriviaLog;
3555
3667
  }
3556
3668
  if (!result.ok) return result;
3557
3669
  const span = result.span;
@@ -3606,7 +3718,7 @@ function leaf(root, fn) {
3606
3718
  }
3607
3719
 
3608
3720
  // src/version.ts
3609
- var PARSEMAN_VERSION = "0.43.0";
3721
+ var PARSEMAN_VERSION = "0.44.0";
3610
3722
 
3611
3723
  // src/cst/host-mode.ts
3612
3724
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -5504,9 +5616,18 @@ function buildGrammarPlan(entry, winners) {
5504
5616
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
5505
5617
  }
5506
5618
 
5619
+ // src/cst/trivia-entries.ts
5620
+ var EMPTY_INDICES = Object.freeze([]);
5621
+ var EMPTY_GAPS = Object.freeze([]);
5622
+ var SELECTED_ROOT_STRIDE = 5;
5623
+
5507
5624
  // src/compiler/scannable-run.ts
5508
5625
  var BACKSLASH = 92;
5509
5626
  var META = new Set("()[]{}*+?|^$.".split(""));
5627
+ var SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER = Array.from(
5628
+ { length: SELECTED_ROOT_STRIDE - 3 },
5629
+ () => "0"
5630
+ ).join(", ");
5510
5631
  function classToRanges(cls) {
5511
5632
  if (cls === "\\d") return shorthandRanges("d");
5512
5633
  if (cls === "\\w") return shorthandRanges("w");
@@ -6545,13 +6666,15 @@ function scanBranch(shape, mint) {
6545
6666
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6546
6667
  return [...m.setup, ` if (${m.end} > _e) { _e = ${m.end}; continue }`].join("\n");
6547
6668
  }
6548
- function scanBranchLabeled(shape, kindIndex, mint) {
6669
+ function scanBranchLabeled(shape, kindIndex, label2, mint) {
6549
6670
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6550
6671
  return [
6551
6672
  ...m.setup,
6552
6673
  ` if (${m.end} > _e) {`,
6553
6674
  ` if (_cap) {`,
6554
6675
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6676
+ ` const _rk = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(label2)}] ?? -1)`,
6677
+ ` if (_rk >= 0) _ctx._rootTriviaLog.push(${SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER}, _e, ${m.end}, _rk)`,
6555
6678
  ` 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})`,
6556
6679
  ` }`,
6557
6680
  ` _e = ${m.end}`,
@@ -6611,6 +6734,11 @@ var CAP_RECORD = [
6611
6734
  ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6612
6735
  ` }`
6613
6736
  ].join("\n");
6737
+ var SELECTED_ROOT_FINISH = [
6738
+ ` if (_cap && _ctx._rootTriviaCapture !== false && _ctx._rootTriviaLog !== undefined && _ctx._rootTriviaLog.length !== _rootMark) {`,
6739
+ ` for (let _ri = _rootMark; _ri < _ctx._rootTriviaLog.length; _ri += ${SELECTED_ROOT_STRIDE}) { _ctx._rootTriviaLog[_ri] = _pos; _ctx._rootTriviaLog[_ri + 1] = _e }`,
6740
+ ` }`
6741
+ ].join("\n");
6614
6742
  function composeFastLoop(shapes) {
6615
6743
  const mint = makeMint();
6616
6744
  return [
@@ -6639,7 +6767,7 @@ function analyzeLabeledScannableRun(trivia2) {
6639
6767
  const d = getCoreRegexDef(arm.parser);
6640
6768
  const shape = d ? scanShapeFromRegex(d.source, d.flags) : null;
6641
6769
  if (!shape) return null;
6642
- out.push({ shape, kindIndex: arm.kindIndex });
6770
+ out.push({ shape, kindIndex: arm.kindIndex, label: arm.label });
6643
6771
  }
6644
6772
  return out;
6645
6773
  }
@@ -6648,11 +6776,13 @@ function buildLabeledScannableTriviaFnDecl(fnName, arms) {
6648
6776
  return [
6649
6777
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6650
6778
  ` let _e = _pos`,
6779
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6651
6780
  ` while (_e < input.length) {`,
6652
6781
  ` const c = input.charCodeAt(_e)`,
6653
- ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, mint)),
6782
+ ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, a.label, mint)),
6654
6783
  ` break`,
6655
6784
  ` }`,
6785
+ SELECTED_ROOT_FINISH,
6656
6786
  ` return _e`,
6657
6787
  `}`
6658
6788
  ].join("\n");
@@ -6668,6 +6798,8 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6668
6798
  ` const _ce = _e + _m${i}[0].length`,
6669
6799
  ` if (_cap) {`,
6670
6800
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6801
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
6802
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6671
6803
  ` 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})`,
6672
6804
  ` }`,
6673
6805
  ` _e = _ce`,
@@ -6679,11 +6811,13 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6679
6811
  return [
6680
6812
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6681
6813
  ` let _e = _pos`,
6814
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6682
6815
  ` while (_e < input.length) {`,
6683
6816
  ` let _matched = false`,
6684
6817
  tryArms,
6685
6818
  ` if (!_matched) break`,
6686
6819
  ` }`,
6820
+ SELECTED_ROOT_FINISH,
6687
6821
  ` return _e`,
6688
6822
  `}`
6689
6823
  ].join("\n");
@@ -6706,6 +6840,8 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6706
6840
  ` const _ce = _r${i}.span.end`,
6707
6841
  ` if (_cap) {`,
6708
6842
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6843
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
6844
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6709
6845
  ` 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})`,
6710
6846
  ` }`,
6711
6847
  ` _e = _ce`,
@@ -6717,11 +6853,13 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6717
6853
  return [
6718
6854
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6719
6855
  ` let _e = _pos`,
6856
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6720
6857
  ` while (_e < input.length) {`,
6721
6858
  ` let _matched = false`,
6722
6859
  tryArms,
6723
6860
  ` if (!_matched) break`,
6724
6861
  ` }`,
6862
+ SELECTED_ROOT_FINISH,
6725
6863
  ` return _e`,
6726
6864
  `}`
6727
6865
  ].join("\n");
@@ -6952,6 +7090,9 @@ function endLoweringCapture() {
6952
7090
  _loweringSink = null;
6953
7091
  return misses;
6954
7092
  }
7093
+ function hasSelectedRootTrivia(ctx) {
7094
+ return ctx.rootTriviaClassified === true;
7095
+ }
6955
7096
  function v(ctx, prefix = "_v") {
6956
7097
  return `${prefix}${ctx.vars++}`;
6957
7098
  }
@@ -7261,10 +7402,12 @@ function planDisjointDispatch(parsers) {
7261
7402
  }
7262
7403
  return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
7263
7404
  }
7264
- function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
7405
+ function captureRestoreBody(ctx, mL, mR, mTl, mLg, mF = null, mRootLg = null) {
7265
7406
  const fieldRestore = mF ? `; if (_ctx._fields && _ctx._fields.length !== ${mF}) _ctx._fields.length = ${mF}` : "";
7266
7407
  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}`;
7267
- return mLg ? `${base}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : base;
7408
+ const logRestore = mLg ? `; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : "";
7409
+ const rootLogRestore = hasSelectedRootTrivia(ctx) && mRootLg ? `; if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${mRootLg}) _ctx._rootTriviaLog.length = ${mRootLg}` : "";
7410
+ return `${base}${logRestore}${rootLogRestore}`;
7268
7411
  }
7269
7412
  function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
7270
7413
  if (seen.has(p)) return false;
@@ -7474,7 +7617,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
7474
7617
  `${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
7475
7618
  `${ind0}}`,
7476
7619
  ...mL ? [
7477
- `${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
7620
+ `${ind0}if (!${okV}) { ${captureRestoreBody(ctx, mL, mR, mTl, null, mF)} }`
7478
7621
  ] : []
7479
7622
  ];
7480
7623
  return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
@@ -7671,11 +7814,13 @@ function emitSeqValues(def, ctx, pos) {
7671
7814
  const markV = v(ctx, "_mk");
7672
7815
  const markTl = v(ctx, "_mktl");
7673
7816
  const markLog = v(ctx, "_mklg");
7817
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7674
7818
  const scanEndV = v(ctx, "_sne");
7675
7819
  stmts.push(
7676
7820
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7677
7821
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7678
7822
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7823
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7679
7824
  `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7680
7825
  ...emitLineTrack(ctx, curV, scanEndV)
7681
7826
  );
@@ -7684,17 +7829,19 @@ function emitSeqValues(def, ctx, pos) {
7684
7829
  const endAfterV = v(ctx, "_sea");
7685
7830
  stmts.push(
7686
7831
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7687
- `${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}; }`
7832
+ `${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};` : ""} }`
7688
7833
  );
7689
7834
  valueVars.push(r2.valueVar);
7690
7835
  continue;
7691
7836
  } else {
7692
7837
  const trivFn = ensureTriviaFn(ctx);
7693
7838
  const markLog = v(ctx, "_mklg");
7839
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7694
7840
  const scanEndV = v(ctx, "_sne");
7695
- const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7841
+ const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? "(_ctx._triviaLog !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7696
7842
  stmts.push(
7697
7843
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7844
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7698
7845
  `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7699
7846
  ...emitLineTrack(ctx, curV, scanEndV)
7700
7847
  );
@@ -7703,7 +7850,7 @@ function emitSeqValues(def, ctx, pos) {
7703
7850
  const endAfterV = v(ctx, "_sea");
7704
7851
  stmts.push(
7705
7852
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7706
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7853
+ `${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};` : ""} }`
7707
7854
  );
7708
7855
  valueVars.push(r2.valueVar);
7709
7856
  continue;
@@ -7945,6 +8092,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7945
8092
  const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7946
8093
  const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7947
8094
  const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
8095
+ const selectorRootLogMark = selectorNeedsRollback && hasSelectedRootTrivia(ctx) ? v(ctx, "_dsrg") : null;
7948
8096
  const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7949
8097
  const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7950
8098
  const selector = emit(def.selector, ctx, pos);
@@ -7957,6 +8105,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7957
8105
  `${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
7958
8106
  `${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
7959
8107
  `${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
8108
+ ...selectorRootLogMark ? [`${ind(ctx)}const ${selectorRootLogMark} = _ctx._rootTriviaLog?.length ?? 0`] : [],
7960
8109
  `${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
7961
8110
  `${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
7962
8111
  ] : [],
@@ -7976,16 +8125,18 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7976
8125
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7977
8126
  const errMark = mayError ? v(ctx, "_derr") : null;
7978
8127
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
8128
+ const rootLogMark = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_drlog") : null;
7979
8129
  if (usesRouted) {
7980
8130
  stmts.push(
7981
8131
  ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7982
8132
  ...selectorLeafMark ? [
7983
- `${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}`
8133
+ `${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}`
7984
8134
  ] : []
7985
8135
  );
7986
8136
  }
7987
8137
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7988
8138
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
8139
+ if (rootLogMark) stmts.push(`${ind(ctx)}const ${rootLogMark} = _ctx._rootTriviaLog?.length ?? 0`);
7989
8140
  const savedRoutedLocal = ctx.routedLocal;
7990
8141
  const savedNoHoist = ctx.noHoist;
7991
8142
  if (usesRouted && !needsRoutedContext) {
@@ -8000,11 +8151,12 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8000
8151
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
8001
8152
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
8002
8153
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
8154
+ const rootLogRollback = rootLogMark ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rootLogMark}) _ctx._rootTriviaLog.length = ${rootLogMark}; ` : "";
8003
8155
  const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
8004
8156
  const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
8005
8157
  stmts.push(
8006
8158
  ...tail.stmts,
8007
- `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8159
+ `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${rootLogRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8008
8160
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
8009
8161
  `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
8010
8162
  `${ind(ctx)}${outE} = ${tail.endVar}`,
@@ -8185,11 +8337,13 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8185
8337
  const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
8186
8338
  const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
8187
8339
  const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
8340
+ const markRootLog = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_cmlrg") : null;
8188
8341
  const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
8189
8342
  const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
8190
- const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
8343
+ const captureRollback = markLeaves ? captureRestoreBody(ctx, markLeaves, markRaw, markTl, markLog, markFields, markRootLog) : "";
8344
+ const rootRollback = markRootLog && !markLeaves ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}` : "";
8191
8345
  const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
8192
- const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
8346
+ const rollback = [captureRollback, rootRollback, errorRollback].filter(Boolean).join("; ");
8193
8347
  const failSlot = atStart ? staticFx : "_ctx._fx";
8194
8348
  stmts.push(`${ind0}if (${skipCond}) {`);
8195
8349
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
@@ -8204,6 +8358,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8204
8358
  ...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
8205
8359
  );
8206
8360
  }
8361
+ if (markRootLog) stmts.push(`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog?.length ?? 0`);
8207
8362
  if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
8208
8363
  const arm = emitFallible(p, ctx, pos, atStart);
8209
8364
  const { stmts: armStmts, okVar, valVar, endVar } = arm;
@@ -8391,21 +8546,29 @@ function emitMany(def, ctx, pos) {
8391
8546
  const markV = v(ctx, "_mk");
8392
8547
  const markTl = v(ctx, "_mktl");
8393
8548
  const markLog = v(ctx, "_mklg");
8549
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8394
8550
  const npV = v(ctx, "_np");
8395
8551
  stmts.push(
8396
8552
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8397
8553
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8398
8554
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8555
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8399
8556
  `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8400
8557
  ...emitLineTrack(ctx, curV, npV)
8401
8558
  );
8402
8559
  itemPos = npV;
8403
- 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}; `;
8560
+ 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};` : ""} `;
8404
8561
  } else {
8405
8562
  const trivFn = ensureTriviaFn(ctx);
8563
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8406
8564
  const npV = v(ctx, "_np");
8407
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, npV));
8565
+ stmts.push(
8566
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8567
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8568
+ ...emitLineTrack(ctx, curV, npV)
8569
+ );
8408
8570
  itemPos = npV;
8571
+ rollback = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8409
8572
  }
8410
8573
  }
8411
8574
  if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
@@ -8465,9 +8628,10 @@ function emitAttempt(p, def, ctx, pos) {
8465
8628
  const raw = v(ctx, "_atr");
8466
8629
  const trivia2 = v(ctx, "_att");
8467
8630
  const log = v(ctx, "_atg");
8631
+ const rootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_atrg") : null;
8468
8632
  const fields = v(ctx, "_atf");
8469
8633
  const errors = v(ctx, "_ate");
8470
- 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}`;
8634
+ 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}`;
8471
8635
  const traceId = ctx.coverage?.plan.attempts.get(p);
8472
8636
  const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
8473
8637
  const preGuard = [];
@@ -8483,7 +8647,7 @@ function emitAttempt(p, def, ctx, pos) {
8483
8647
  return {
8484
8648
  stmts: [
8485
8649
  ...preGuard,
8486
- `${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`,
8650
+ `${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`,
8487
8651
  ...inner.stmts,
8488
8652
  ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
8489
8653
  ],
@@ -8525,16 +8689,17 @@ function emitSepBy(_p, def, ctx, pos) {
8525
8689
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8526
8690
  const postSepMarks = () => {
8527
8691
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8528
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8692
+ 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");
8529
8693
  return {
8530
8694
  decl: [
8531
8695
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8532
8696
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8533
8697
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8534
8698
  `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8699
+ ...rlg ? [`${ind(ctx)}const ${rlg} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8535
8700
  `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8536
8701
  ],
8537
- 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}; `
8702
+ 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}; `
8538
8703
  };
8539
8704
  };
8540
8705
  if (rec) {
@@ -8572,6 +8737,7 @@ function emitSepBy(_p, def, ctx, pos) {
8572
8737
  const markV = v(ctx, "_mk");
8573
8738
  const markTl = v(ctx, "_mktl");
8574
8739
  const markLog = v(ctx, "_mklg");
8740
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8575
8741
  const markLv = v(ctx, "_mklv");
8576
8742
  const markFld = v(ctx, "_mkf");
8577
8743
  const spV = v(ctx, "_sp");
@@ -8579,13 +8745,14 @@ function emitSepBy(_p, def, ctx, pos) {
8579
8745
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8580
8746
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8581
8747
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8748
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8582
8749
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8583
8750
  `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8584
8751
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8585
8752
  ...emitLineTrack(ctx, curV, spV)
8586
8753
  );
8587
8754
  sepAtPos = spV;
8588
- 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}; `;
8755
+ 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}; `;
8589
8756
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8590
8757
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8591
8758
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8603,19 +8770,30 @@ function emitSepBy(_p, def, ctx, pos) {
8603
8770
  );
8604
8771
  } else {
8605
8772
  const trivFn = ensureTriviaFn(ctx);
8773
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8606
8774
  const spV = v(ctx, "_sp");
8607
- stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, spV));
8775
+ stmts.push(
8776
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8777
+ `${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8778
+ ...emitLineTrack(ctx, curV, spV)
8779
+ );
8608
8780
  sepAtPos = spV;
8609
8781
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8610
8782
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8611
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8783
+ const rollbackToSep = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8784
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8785
+ const postRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_psrlg") : null;
8612
8786
  const npV = v(ctx, "_np");
8613
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`, ...emitLineTrack(ctx, sepEnd, npV));
8787
+ stmts.push(
8788
+ ...postRootLog ? [`${ind(ctx)}const ${postRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8789
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8790
+ ...emitLineTrack(ctx, sepEnd, npV)
8791
+ );
8614
8792
  const next = emitFallible(def.parser, ctx, npV, true);
8615
8793
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8616
8794
  stmts.push(
8617
8795
  ...nextStmts,
8618
- ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
8796
+ ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, postRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${postRootLog}) _ctx._rootTriviaLog.length = ${postRootLog}; ` : "")),
8619
8797
  `${ind(ctx)}${arrV}.push(${nextVal})`,
8620
8798
  `${ind(ctx)}${curV} = ${nextEnd}`
8621
8799
  );
@@ -8710,6 +8888,7 @@ function emitNot(def, ctx, pos) {
8710
8888
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8711
8889
  const tl = sinksLive ? v(ctx, "_ntt") : null;
8712
8890
  const log = sinksLive ? v(ctx, "_ntg") : null;
8891
+ const rootLog = sinksLive && hasSelectedRootTrivia(ctx) ? v(ctx, "_ntrg") : null;
8713
8892
  const fields = sinksLive ? v(ctx, "_ntf") : null;
8714
8893
  const errors = sinksLive ? v(ctx, "_nte") : null;
8715
8894
  const { stmts, okVar } = emitFallible(def.parser, ctx, pos, true);
@@ -8717,11 +8896,11 @@ function emitNot(def, ctx, pos) {
8717
8896
  return {
8718
8897
  stmts: [
8719
8898
  ...sinksLive ? [
8720
- `${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`
8899
+ `${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`
8721
8900
  ] : [],
8722
8901
  ...stmts,
8723
8902
  ...sinksLive ? [
8724
- `${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}`
8903
+ `${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}`
8725
8904
  ] : [],
8726
8905
  ...emitIfFail(ctx, okVar, failBody(ctx, label2, pos))
8727
8906
  ],
@@ -8857,16 +9036,17 @@ function emitToken(def, ctx, pos) {
8857
9036
  const sk = v(ctx, "_tokKinds");
8858
9037
  const stl = v(ctx, "_tokTl");
8859
9038
  const sol = v(ctx, "_tokLog");
9039
+ const srl = hasSelectedRootTrivia(ctx) ? v(ctx, "_tokRootLog") : null;
8860
9040
  const sb = v(ctx, "_tokBuf");
8861
9041
  const valV = v(ctx, "_tok");
8862
9042
  return {
8863
9043
  stmts: [
8864
- `${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`,
8865
- `${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`,
9044
+ `${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`,
9045
+ `${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`,
8866
9046
  `${i}try {`,
8867
9047
  ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
8868
9048
  `${i}} finally {`,
8869
- `${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}`,
9049
+ `${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}`,
8870
9050
  `${i}}`,
8871
9051
  ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
8872
9052
  `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
@@ -9345,6 +9525,8 @@ function emitDispatch(p, ctx, pos) {
9345
9525
  case "grammar": {
9346
9526
  const savedTrivia = ctx.activeTrivia;
9347
9527
  const savedKindLabels = ctx.triviaKindLabels;
9528
+ const opaqueRootCapture = hasSelectedRootTrivia(ctx) && def.rootCapture === "opaque";
9529
+ 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;
9348
9530
  if (def.clearTrivia) {
9349
9531
  ctx.activeTrivia = void 0;
9350
9532
  ctx.triviaKindLabels = void 0;
@@ -9355,13 +9537,38 @@ function emitDispatch(p, ctx, pos) {
9355
9537
  }
9356
9538
  }
9357
9539
  const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
9540
+ const savedRootCapture = opaqueRootCapture ? v(ctx, "_grtc") : null;
9541
+ const opaqueValue = opaqueRootCapture ? v(ctx, "_grtv") : null;
9542
+ const opaqueEnd = opaqueRootCapture ? v(ctx, "_grte") : null;
9543
+ if (opaqueRootCapture) ctx.indent++;
9358
9544
  const r = emit(def.parser, ctx, pos);
9545
+ if (opaqueRootCapture) ctx.indent--;
9359
9546
  ctx.activeTrivia = savedTrivia;
9360
9547
  ctx.triviaKindLabels = savedKindLabels;
9361
- if (!savedCapture) return r;
9548
+ if (!savedCapture && !opaqueRootCapture) return strictScopeCheck === void 0 ? r : {
9549
+ ...r,
9550
+ stmts: [strictScopeCheck, ...r.stmts]
9551
+ };
9552
+ if (opaqueRootCapture) {
9553
+ return {
9554
+ stmts: [
9555
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9556
+ `${ind(ctx)}let ${opaqueValue}, ${opaqueEnd}`,
9557
+ `${ind(ctx)}${savedCapture ? `const ${savedCapture} = _ctx.captureTrivia; ` : ""}const ${savedRootCapture} = _ctx._rootTriviaCapture; _ctx._rootTriviaCapture = false`,
9558
+ `${ind(ctx)}try {`,
9559
+ ...savedCapture ? [`${ind(ctx)} _ctx.captureTrivia = true`] : [],
9560
+ ...r.stmts,
9561
+ `${ind(ctx)} ${opaqueValue} = ${r.valueVar}; ${opaqueEnd} = ${r.endVar}`,
9562
+ `${ind(ctx)}} finally { ${savedCapture ? `_ctx.captureTrivia = ${savedCapture}; ` : ""}_ctx._rootTriviaCapture = ${savedRootCapture} }`
9563
+ ],
9564
+ valueVar: opaqueValue,
9565
+ endVar: opaqueEnd
9566
+ };
9567
+ }
9362
9568
  return {
9363
9569
  ...r,
9364
9570
  stmts: [
9571
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9365
9572
  `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
9366
9573
  ...r.stmts,
9367
9574
  `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
@@ -9846,6 +10053,7 @@ function compile(combinator, mapFnSources, opts) {
9846
10053
  runDuplicationDiagnostic(combinator, opts?.duplication);
9847
10054
  markUnusedValues(combinator);
9848
10055
  const grammarTrivia = combinator._meta.grammarTrivia;
10056
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || combinator._meta.rootTriviaClassified === true;
9849
10057
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9850
10058
  const grammarHostMode = combinator._meta.grammarHostMode;
9851
10059
  const grammarTrackLines = combinator._meta.grammarTrackLines;
@@ -9872,7 +10080,11 @@ function compile(combinator, mapFnSources, opts) {
9872
10080
  lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9873
10081
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9874
10082
  lazyUsage: analyzeLazyUsage(combinator),
9875
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10083
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10084
+ ...grammarTrivia ? {
10085
+ activeTrivia: grammarTrivia,
10086
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10087
+ } : {},
9876
10088
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
9877
10089
  };
9878
10090
  const r = emit(combinator, ctx, "_pos");
@@ -10020,10 +10232,11 @@ function assertRuleName(name) {
10020
10232
  );
10021
10233
  }
10022
10234
  }
10023
- function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
10024
- const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
10025
- if (labels === void 0) return fnSource;
10026
- return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
10235
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambientRootTriviaClassified) {
10236
+ const labels = ambientTriviaKindLabels ?? rule._meta.triviaKindLabels;
10237
+ const classified = ambientRootTriviaClassified ?? rule._meta.rootTriviaClassified;
10238
+ if (labels === void 0 && classified === void 0) return fnSource;
10239
+ return `Object.assign(${fnSource}, { _meta: {${labels === void 0 ? "" : ` triviaKindLabels: ${JSON.stringify(labels)},`}${classified === void 0 ? "" : " rootTriviaClassified: true,"} } })`;
10027
10240
  }
10028
10241
  function compileRuleMap(ruleMap, opts) {
10029
10242
  runGatingDiagnosticRules(ruleMap, opts?.gating);
@@ -10031,6 +10244,7 @@ function compileRuleMap(ruleMap, opts) {
10031
10244
  for (const [, rule] of ruleMap) markUnusedValues(rule);
10032
10245
  const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
10033
10246
  const grammarTrivia = opts?.trivia;
10247
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || ruleMap.some(([, rule]) => rule._meta.rootTriviaClassified === true);
10034
10248
  const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10035
10249
  const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10036
10250
  const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10057,7 +10271,11 @@ function compileRuleMap(ruleMap, opts) {
10057
10271
  lineTracking: grammarTrackLines,
10058
10272
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
10059
10273
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10060
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10274
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10275
+ ...grammarTrivia ? {
10276
+ activeTrivia: grammarTrivia,
10277
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10278
+ } : {},
10061
10279
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10062
10280
  };
10063
10281
  const seenNames = /* @__PURE__ */ new Map();
@@ -10145,7 +10363,7 @@ function compileRuleMap(ruleMap, opts) {
10145
10363
  return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
10146
10364
  };
10147
10365
  const objBody = perEntry.map(({ key, rule, r }) => {
10148
- const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels);
10366
+ const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels, ctx.rootTriviaClassified);
10149
10367
  return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
10150
10368
  }).join(",\n");
10151
10369
  const replacement = [
@@ -10174,6 +10392,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10174
10392
  if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
10175
10393
  for (const [, rule] of ruleMapArg) markUnusedValues(rule);
10176
10394
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
10395
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || ruleMapArg.some(([, rule]) => rule._meta.rootTriviaClassified === true);
10177
10396
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10178
10397
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10179
10398
  const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10217,7 +10436,11 @@ function compileLinkable(ruleMapArg, ns, opts) {
10217
10436
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10218
10437
  ns,
10219
10438
  deferFirstSetRefs: true,
10220
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10439
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10440
+ ...grammarTrivia ? {
10441
+ activeTrivia: grammarTrivia,
10442
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10443
+ } : {},
10221
10444
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10222
10445
  };
10223
10446
  const seen = /* @__PURE__ */ new Map();
@@ -10349,7 +10572,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10349
10572
  ...r.stmts,
10350
10573
  ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10351
10574
  `}`
10352
- ].join("\n"), ctx.triviaKindLabels));
10575
+ ].join("\n"), ctx.triviaKindLabels, ctx.rootTriviaClassified));
10353
10576
  }
10354
10577
  const firstSets = /* @__PURE__ */ new Map();
10355
10578
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10698,6 +10921,7 @@ function evalRuleMapIR(ir) {
10698
10921
  "transform",
10699
10922
  "skip",
10700
10923
  "trivia",
10924
+ "classifiedTrivia",
10701
10925
  "label",
10702
10926
  "field",
10703
10927
  "expect",
@@ -10738,6 +10962,7 @@ function evalRuleMapIR(ir) {
10738
10962
  transform,
10739
10963
  skip,
10740
10964
  trivia,
10965
+ classifiedTrivia,
10741
10966
  label,
10742
10967
  field,
10743
10968
  expect,
@@ -10984,8 +11209,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10984
11209
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
10985
11210
  }
10986
11211
  case "grammar": {
10987
- const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
10988
- return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
11212
+ const classified = def.triviaParser?._meta.rootTriviaClassified === true;
11213
+ const spec = classified && def.triviaParser ? analyzeLabeledTrivia(def.triviaParser) : null;
11214
+ if (classified && !spec) throw new Unserializable("classified trivia without labeled arms");
11215
+ 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";
11216
+ return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.rootCapture ? `, rootCapture: ${JSON.stringify(def.rootCapture)}` : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
10989
11217
  }
10990
11218
  case "withCtx": {
10991
11219
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -11217,10 +11445,6 @@ function gate(predicate) {
11217
11445
  };
11218
11446
  }
11219
11447
 
11220
- // src/cst/trivia-entries.ts
11221
- var EMPTY_INDICES = Object.freeze([]);
11222
- var EMPTY_GAPS = Object.freeze([]);
11223
-
11224
11448
  // src/cst/offset-model.ts
11225
11449
  var { isFinite } = Number;
11226
11450
 
@@ -11472,6 +11696,9 @@ var SUPPORTED = {
11472
11696
  optional: (...a) => optional(a[0]),
11473
11697
  skip: (...a) => skip(a[0], a[1]),
11474
11698
  trivia: (...a) => trivia(a[0]),
11699
+ classifiedTrivia: (...a) => classifiedTrivia(
11700
+ a[0]
11701
+ ),
11475
11702
  label: (...a) => label(a[0], a[1]),
11476
11703
  field: (...a) => field(a[0], a[1]),
11477
11704
  noTrivia: (...a) => noTrivia(a[0]),
@@ -13278,7 +13505,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
13278
13505
  if (isComposeLeafCall(init)) {
13279
13506
  const fused = compileComposeLeafCall(init);
13280
13507
  if (!fused) {
13281
- throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
13508
+ const reasons = warnings.slice(-4);
13509
+ throw new Error(
13510
+ `${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden` + (reasons.length ? `
13511
+ causes:
13512
+ - ${reasons.join("\n - ")}` : "")
13513
+ );
13282
13514
  }
13283
13515
  replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
13284
13516
  markUsedImportedFactories(fused.importedFactories);