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
package/dist/index.cjs CHANGED
@@ -44,6 +44,7 @@ __export(index_exports, {
44
44
  buildTriviaIndex: () => buildTriviaIndex,
45
45
  charClassMembers: () => charClassMembers,
46
46
  choice: () => choice,
47
+ classifiedTrivia: () => classifiedTrivia,
47
48
  collectLeafSlots: () => collectLeafSlots,
48
49
  commentsIn: () => commentsIn,
49
50
  compile: () => compile,
@@ -1182,1035 +1183,1099 @@ function keywords(words, opts = {}) {
1182
1183
  };
1183
1184
  }
1184
1185
 
1185
- // src/recovery/scan.ts
1186
- function probeAt(sentinel, input, pos, ctx) {
1187
- const s = {
1188
- _probe: ctx._probe,
1189
- _errors: ctx._errors,
1190
- _cstLeaves: ctx._cstLeaves,
1191
- _cstChildren: ctx._cstChildren,
1192
- _cstRawChildren: ctx._cstRawChildren,
1193
- _cstTriviaLog: ctx._cstTriviaLog,
1194
- _triviaLog: ctx._triviaLog,
1195
- _fields: ctx._fields,
1196
- _cstBuf: ctx._cstBuf,
1197
- _tolerant: ctx._tolerant,
1198
- _sync: ctx._sync
1199
- };
1200
- ctx._probe = void 0;
1201
- ctx._errors = void 0;
1202
- ctx._cstLeaves = void 0;
1203
- ctx._cstChildren = void 0;
1204
- ctx._cstRawChildren = void 0;
1205
- ctx._cstTriviaLog = void 0;
1206
- ctx._triviaLog = void 0;
1207
- ctx._fields = void 0;
1208
- ctx._cstBuf = void 0;
1209
- ctx._tolerant = void 0;
1210
- ctx._sync = void 0;
1211
- try {
1212
- return sentinel.parse(input, pos, ctx).ok;
1213
- } finally {
1214
- ctx._probe = s._probe;
1215
- ctx._errors = s._errors;
1216
- ctx._cstLeaves = s._cstLeaves;
1217
- ctx._cstChildren = s._cstChildren;
1218
- ctx._cstRawChildren = s._cstRawChildren;
1219
- ctx._cstTriviaLog = s._cstTriviaLog;
1220
- ctx._triviaLog = s._triviaLog;
1221
- ctx._fields = s._fields;
1222
- ctx._cstBuf = s._cstBuf;
1223
- ctx._tolerant = s._tolerant;
1224
- ctx._sync = s._sync;
1225
- }
1186
+ // src/cst/trivia-kinds.ts
1187
+ var labeledTriviaSpecs = /* @__PURE__ */ new WeakMap();
1188
+ function unwrapTrivia(p) {
1189
+ let cur = p;
1190
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1191
+ return cur;
1226
1192
  }
1227
- function orSentinel(a, b) {
1228
- if (b === void 0) return a;
1229
- return {
1230
- _tag: "orSentinel",
1231
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1232
- _def: { tag: "unknown" },
1233
- parse(input, pos, ctx) {
1234
- const ra = a.parse(input, pos, ctx);
1235
- if (ra.ok) return ra;
1236
- return b.parse(input, pos, ctx);
1237
- }
1238
- };
1193
+ function peelLabel(p) {
1194
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1195
+ return null;
1239
1196
  }
1240
- function firstSetSentinel(fs) {
1241
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
1242
- const ranges = fs.ranges;
1243
- return {
1244
- _tag: "firstSetSentinel",
1245
- _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
1246
- _def: { tag: "unknown" },
1247
- parse(input, pos) {
1248
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1249
- if (code !== void 0) {
1250
- for (const r of ranges) {
1251
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1252
- }
1197
+ function analyzeLabeledTrivia(trivia2) {
1198
+ const cached = labeledTriviaSpecs.get(trivia2);
1199
+ if (cached !== void 0) return cached;
1200
+ let core = unwrapTrivia(trivia2);
1201
+ let minRepeats = 1;
1202
+ if (core._def.tag === "oneOrMore") {
1203
+ core = core._def.parser;
1204
+ minRepeats = 1;
1205
+ } else if (core._def.tag === "many") {
1206
+ core = core._def.parser;
1207
+ minRepeats = 0;
1208
+ }
1209
+ const arms = [];
1210
+ if (core._def.tag === "choice") {
1211
+ for (let i = 0; i < core._def.parsers.length; i++) {
1212
+ const peeled = peelLabel(core._def.parsers[i]);
1213
+ if (!peeled) {
1214
+ labeledTriviaSpecs.set(trivia2, null);
1215
+ return null;
1253
1216
  }
1254
- return { ok: false, expected: [], span: { start: pos, end: pos } };
1217
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1218
+ }
1219
+ } else {
1220
+ const peeled = peelLabel(core);
1221
+ if (!peeled) {
1222
+ labeledTriviaSpecs.set(trivia2, null);
1223
+ return null;
1255
1224
  }
1225
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1226
+ }
1227
+ const spec = {
1228
+ labels: arms.map((a) => a.label),
1229
+ arms,
1230
+ minRepeats
1256
1231
  };
1232
+ labeledTriviaSpecs.set(trivia2, spec);
1233
+ return spec;
1257
1234
  }
1258
- function recoverScan(input, from, ctx, sync, expected) {
1259
- let scanPos = from;
1260
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1261
- const span = { start: from, end: scanPos };
1262
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1263
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1264
- ctx._errors?.push(error);
1265
- return { error, end: scanPos };
1266
- }
1267
- function matchesAt(sentinel, input, pos, ctx) {
1268
- return probeAt(sentinel, input, pos, ctx);
1235
+ function matchArmAt(input, pos, arm, state) {
1236
+ if (!startsFirstSet(arm, input, pos)) return null;
1237
+ const r = arm.parse(input, pos, { trackLines: false, state });
1238
+ if (!r.ok || r.span.end <= pos) return null;
1239
+ return { end: r.span.end };
1269
1240
  }
1270
- function captureError(ctx, error) {
1271
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1241
+ function scanLabeledTriviaChunks(input, cur, spec, state) {
1242
+ const chunks = [];
1243
+ let pos = cur;
1244
+ while (pos < input.length) {
1245
+ let matched = null;
1246
+ for (const arm of spec.arms) {
1247
+ const m = matchArmAt(input, pos, arm.parser, state);
1248
+ if (m) {
1249
+ matched = { end: m.end, kindIndex: arm.kindIndex };
1250
+ break;
1251
+ }
1252
+ }
1253
+ if (!matched) break;
1254
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1255
+ pos = matched.end;
1256
+ }
1257
+ if (chunks.length < spec.minRepeats) {
1258
+ return { end: cur, chunks: [] };
1259
+ }
1260
+ return { end: pos, chunks };
1272
1261
  }
1273
- var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
1274
-
1275
- // src/combinators/expect.ts
1276
- function deriveExpected(c) {
1277
- return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1262
+ function scanLabeledTriviaEnd(input, cur, spec, state) {
1263
+ let pos = cur;
1264
+ let count = 0;
1265
+ while (pos < input.length) {
1266
+ let matched = null;
1267
+ for (const arm of spec.arms) {
1268
+ matched = matchArmAt(input, pos, arm.parser, state);
1269
+ if (matched) break;
1270
+ }
1271
+ if (!matched) break;
1272
+ pos = matched.end;
1273
+ count++;
1274
+ }
1275
+ return count < spec.minRepeats ? cur : pos;
1278
1276
  }
1279
- function derive(c, seen) {
1280
- const deriveExpected2 = (p) => derive(p, seen);
1281
- const def = c._def;
1282
- switch (def.tag) {
1283
- case "literal":
1284
- return [JSON.stringify(def.value)];
1285
- case "regex":
1286
- return [`/${def.source}/`];
1287
- case "keywords":
1288
- return def.words.map((w) => JSON.stringify(w));
1289
- case "label":
1290
- return [def.label];
1291
- case "choice":
1292
- return def.parsers.flatMap(deriveExpected2);
1293
- case "dispatch":
1294
- return deriveExpected2(def.selector);
1295
- // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1296
- // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1297
- // able to fail first — deriving from term 0 alone named a token the parse
1298
- // never actually required. A leading `not(…)` is zero-width and contributes
1299
- // nothing (its own expectation is about what must NOT be here), but it is
1300
- // nullable, so keep scanning past it. Stop at the first term that must match.
1301
- case "sequence": {
1302
- const out = [];
1303
- for (const term of def.parsers) {
1304
- if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1305
- if (!matchesEmpty(term)) break;
1277
+ function visitLabeledTrivia(input, cur, spec, state, visit) {
1278
+ if (spec.minRepeats > 1) return void 0;
1279
+ let pos = cur;
1280
+ let count = 0;
1281
+ while (pos < input.length) {
1282
+ let matched = null;
1283
+ for (const arm of spec.arms) {
1284
+ const match = matchArmAt(input, pos, arm.parser, state);
1285
+ if (match) {
1286
+ matched = { end: match.end, kindIndex: arm.kindIndex };
1287
+ break;
1306
1288
  }
1307
- return out;
1308
1289
  }
1309
- case "attempt":
1310
- return deriveExpected2(def.parser);
1311
- // Delegating wrappers whose first-token failure is their inner parser's — must
1312
- // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1313
- // node, which reads this) names the real expected token, not the wrapper tag.
1314
- case "field":
1315
- case "withCtx":
1316
- case "recover":
1317
- return deriveExpected2(def.parser);
1318
- case "skip":
1319
- return deriveExpected2(def.main);
1320
- case "expect":
1321
- return def.expected;
1322
- case "node":
1323
- case "grammar":
1324
- case "trivia":
1325
- case "token":
1326
- case "leaf":
1327
- case "optional":
1328
- case "many":
1329
- case "oneOrMore":
1330
- case "transform":
1331
- case "not":
1332
- case "peek":
1333
- return deriveExpected2(def.parser);
1334
- case "routed":
1335
- return ["routed()"];
1336
- case "lazy": {
1337
- const name = c._ruleName;
1338
- if (seen.has(c)) return name ? [name] : [];
1339
- seen.add(c);
1340
- try {
1341
- return deriveExpected2(def.thunk());
1342
- } catch {
1343
- return name ? [name] : [];
1344
- } finally {
1345
- seen.delete(c);
1290
+ if (!matched) break;
1291
+ visit(pos, matched.end, matched.kindIndex);
1292
+ pos = matched.end;
1293
+ count++;
1294
+ }
1295
+ return count < spec.minRepeats ? cur : pos;
1296
+ }
1297
+ function recordTriviaChunks(ctx, chunks) {
1298
+ const kinds = ctx.triviaKindLabels;
1299
+ const mask = ctx._triviaCaptureMask;
1300
+ const rootLog = ctx._rootTriviaLog;
1301
+ const rootKinds = ctx._rootTriviaKindIndex;
1302
+ const rootMark = rootLog?.length ?? 0;
1303
+ for (const ch2 of chunks) {
1304
+ pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1305
+ const rootKindIndex = ctx._rootTriviaCapture === false || rootLog === void 0 || rootKinds === void 0 || kinds === void 0 ? -1 : rootKinds[kinds[ch2.kindIndex] ?? ""] ?? -1;
1306
+ if (rootKindIndex >= 0) {
1307
+ rootLog.push(0, 0, ch2.start, ch2.end, rootKindIndex);
1308
+ }
1309
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1310
+ if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1311
+ pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1346
1312
  }
1347
1313
  }
1348
- default:
1349
- return [];
1350
1314
  }
1351
- }
1352
- function expect(combinator, label2) {
1353
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1354
- const meta = {
1355
- firstSet: combinator._meta.firstSet,
1356
- canMatchNewline: combinator._meta.canMatchNewline,
1357
- isTrivia: false
1358
- };
1359
- return {
1360
- _tag: "expect",
1361
- _meta: meta,
1362
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1363
- parse(input, pos, ctx) {
1364
- const result = combinator.parse(input, pos, ctx);
1365
- if (result.ok) return result;
1366
- const span = { start: pos, end: pos };
1367
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1368
- ctx._errors?.push(error);
1369
- if (ctx._tolerant) captureError(ctx, error);
1370
- return { ok: true, value: error, span: { start: pos, end: pos } };
1315
+ if (rootLog !== void 0 && rootLog.length !== rootMark && chunks.length > 0) {
1316
+ const start = chunks[0].start;
1317
+ const end = chunks[chunks.length - 1].end;
1318
+ for (let offset = rootMark; offset < rootLog.length; offset += 5) {
1319
+ rootLog[offset] = start;
1320
+ rootLog[offset + 1] = end;
1371
1321
  }
1372
- };
1373
- }
1374
- function isParseError(value) {
1375
- return typeof value === "object" && value !== null && value._tag === "parseError";
1322
+ }
1376
1323
  }
1377
-
1378
- // src/combinators/choice.ts
1379
- function choice(...args) {
1380
- const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1381
- const gates = args.map((a) => "gate" in a ? a.gate : null);
1382
- const hasGates = gates.some((g) => g !== null);
1383
- const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1384
- let combined = { kind: "empty" };
1385
- for (const p of parsers) combined = union(combined, p._meta.firstSet);
1386
- const meta = {
1387
- firstSet: combined,
1388
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1389
- isTrivia: false,
1390
- disjoint
1391
- };
1392
- const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1393
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1394
- let greedyLitMap = null;
1395
- let sortedParsers = null;
1396
- const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1397
- if (strategy?.tag === "greedyClassify") {
1398
- greedyLitMap = /* @__PURE__ */ new Map();
1399
- for (let i = 0; i < parsers.length; i++) {
1400
- if (i === strategy.superIndex) continue;
1401
- const litVal = getCoreLiteralValue(parsers[i]);
1402
- if (litVal !== null) greedyLitMap.set(litVal, i);
1403
- }
1404
- } else if (strategy?.tag === "literalsLongestFirst") {
1405
- sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
1324
+ function triviaKindMask(labels, keep) {
1325
+ if (!labels) return void 0;
1326
+ let mask = 0;
1327
+ for (const name of keep) {
1328
+ const idx = labels.indexOf(name);
1329
+ if (idx >= 0) mask |= 1 << idx;
1406
1330
  }
1331
+ return mask;
1332
+ }
1333
+
1334
+ // src/combinators/trivia-skip.ts
1335
+ var NOOP_COMMIT = () => {
1336
+ };
1337
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1338
+ function needsDeferredTriviaCommit(ctx) {
1339
+ return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1340
+ }
1341
+ function saveTriviaMark(ctx) {
1342
+ const m = saveCstMark(ctx);
1407
1343
  return {
1408
- _tag: "choice",
1409
- _meta: meta,
1410
- _def: {
1411
- tag: "choice",
1412
- parsers,
1413
- gates,
1414
- disjoint,
1415
- strategy: strategy ?? { tag: "firstMatch" },
1416
- autoNot
1417
- },
1418
- parse(input, pos, ctx) {
1419
- const expected = [];
1420
- if (disjoint && pos < input.length) {
1421
- const code = input.codePointAt(pos);
1422
- let idx = code < 128 ? asciiDispatch[code] : -1;
1423
- if (idx < 0) {
1424
- for (let i = 0; i < parsers.length; i++) {
1425
- if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1426
- idx = i;
1427
- break;
1428
- }
1344
+ raw: m.raw,
1345
+ tlog: m.tlog,
1346
+ leaves: m.leaves,
1347
+ fields: m.fields,
1348
+ errors: m.errors,
1349
+ log: ctx._triviaLog ? ctx._triviaLog.length : 0,
1350
+ rootLog: ctx._rootTriviaLog ? ctx._rootTriviaLog.length : 0
1351
+ };
1352
+ }
1353
+ function rollbackTrivia(ctx, mark) {
1354
+ rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1355
+ if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1356
+ if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1357
+ }
1358
+ function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1359
+ const probeCtx = {
1360
+ trackLines: ctx.trackLines,
1361
+ state: ctx.state,
1362
+ ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1363
+ ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1364
+ ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1365
+ };
1366
+ const result = triviaP.parse(input, cur, probeCtx);
1367
+ ctx._lineScannedTo = probeCtx._lineScannedTo;
1368
+ return result;
1369
+ }
1370
+ function saveLookaheadMark(ctx) {
1371
+ return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1372
+ }
1373
+ function rollbackLookahead(ctx, mark) {
1374
+ rollbackTrivia(ctx, mark);
1375
+ if (ctx._probe) ctx._probe.best = mark.probeBest;
1376
+ }
1377
+ function scanWithLabels(input, cur, ctx) {
1378
+ const triviaP = ctx.trivia;
1379
+ const spec = analyzeLabeledTrivia(triviaP);
1380
+ if (!spec) return { end: cur, commit: NOOP_COMMIT };
1381
+ const log = ctx._triviaLog;
1382
+ const rootLog = ctx._rootTriviaLog;
1383
+ const rootKinds = ctx._rootTriviaKindIndex;
1384
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1385
+ const mask = ctx._triviaCaptureMask;
1386
+ let fullRows;
1387
+ let rootRows;
1388
+ let cstRows;
1389
+ const visitedEnd = visitLabeledTrivia(input, cur, spec, ctx.state, (start, matchEnd, kindIndex) => {
1390
+ if (log !== void 0) (fullRows ??= []).push(start, matchEnd, kindIndex);
1391
+ const selectedKind = rootLog === void 0 || rootKinds === void 0 || ctx._rootTriviaCapture === false ? void 0 : rootKinds[spec.labels[kindIndex] ?? ""];
1392
+ if (selectedKind !== void 0) (rootRows ??= []).push(start, matchEnd, selectedKind);
1393
+ if (captureTl && (mask === void 0 || (mask & 1 << kindIndex) !== 0)) {
1394
+ (cstRows ??= []).push(start, matchEnd, kindIndex);
1395
+ }
1396
+ });
1397
+ if (visitedEnd !== void 0) {
1398
+ if (visitedEnd === cur) return { end: cur, commit: NOOP_COMMIT };
1399
+ return {
1400
+ end: visitedEnd,
1401
+ commit: () => {
1402
+ if (fullRows !== void 0 && log !== void 0) log.push(...fullRows);
1403
+ if (rootRows !== void 0 && rootLog !== void 0) {
1404
+ for (let i = 0; i < rootRows.length; i += 3) {
1405
+ rootLog.push(cur, visitedEnd, rootRows[i], rootRows[i + 1], rootRows[i + 2]);
1429
1406
  }
1430
1407
  }
1431
- if (idx >= 0) {
1432
- const gate2 = gates[idx];
1433
- if (gate2 && !gate2(ctx.state)) {
1434
- return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1408
+ if (cstRows !== void 0) {
1409
+ for (let i = 0; i < cstRows.length; i += 3) {
1410
+ pushCstTriviaEntry(ctx, cstRows[i], cstRows[i + 1], cstRows[i + 2]);
1435
1411
  }
1436
- const result = parsers[idx].parse(input, pos, ctx);
1437
- if (result.ok) return result;
1438
- expected.push(...result.expected);
1439
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1440
- return { ok: false, expected, span: { start: pos, end: pos } };
1441
- }
1442
- return {
1443
- ok: false,
1444
- expected: parsers.flatMap((p) => {
1445
- const r = p.parse(input, pos, ctx);
1446
- return r.ok ? [] : r.expected;
1447
- }),
1448
- span: { start: pos, end: pos }
1449
- };
1450
- }
1451
- if (strategy?.tag === "greedyClassify") {
1452
- const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1453
- if (!superResult.ok) return superResult;
1454
- const end = superResult.span.end;
1455
- const litIdx = greedyLitMap.get(input.slice(pos, end));
1456
- if (litIdx !== void 0) {
1457
- const litVal = getCoreLiteralValue(parsers[litIdx]);
1458
- const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1459
- return { ok: true, value, span: { start: pos, end } };
1460
- }
1461
- return superResult;
1462
- }
1463
- if (strategy?.tag === "literalsLongestFirst") {
1464
- for (const p of sortedParsers) {
1465
- const r = p.parse(input, pos, ctx);
1466
- if (r.ok) return r;
1467
- expected.push(...r.expected);
1468
- }
1469
- return { ok: false, expected, span: { start: pos, end: pos } };
1470
- }
1471
- for (let i = 0; i < parsers.length; i++) {
1472
- if (gates[i] && !gates[i](ctx.state)) continue;
1473
- const mark = saveCstMark(ctx);
1474
- const logLen = ctx._triviaLog?.length;
1475
- const result = parsers[i].parse(input, pos, ctx);
1476
- if (!result.ok) {
1477
- rollbackCstCapture(ctx, mark);
1478
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1479
- expected.push(...result.expected);
1480
- if (result.committed) return { ok: false, expected, span: result.span, committed: true };
1481
- continue;
1482
- }
1483
- const checks = autoNot[i];
1484
- if (checks && autoNotFires(input, result.span.end, checks)) {
1485
- rollbackCstCapture(ctx, mark);
1486
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1487
- continue;
1488
1412
  }
1489
- return result;
1490
1413
  }
1491
- return { ok: false, expected, span: { start: pos, end: pos } };
1492
- }
1414
+ };
1415
+ }
1416
+ const { end, chunks } = scanLabeledTriviaChunks(input, cur, spec, ctx.state);
1417
+ if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1418
+ return {
1419
+ end,
1420
+ commit: () => recordTriviaChunks(ctx, chunks)
1493
1421
  };
1494
1422
  }
1495
- function detectStrategy(parsers) {
1496
- const regexIndices = [];
1497
- const literalIndices = [];
1498
- for (let i = 0; i < parsers.length; i++) {
1499
- if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
1500
- else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
1501
- }
1502
- if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
1503
- const superIndex = regexIndices[0];
1504
- const regexDef = getCoreRegexDef(parsers[superIndex]);
1505
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
1506
- const re = new RegExp(regexDef.source, flags);
1507
- const allSubsumed = literalIndices.every((i) => {
1508
- const litVal = getCoreLiteralValue(parsers[i]);
1509
- re.lastIndex = 0;
1510
- const m = re.exec(litVal);
1511
- return m !== null && m[0] === litVal;
1512
- });
1513
- if (allSubsumed) return { tag: "greedyClassify", superIndex };
1423
+ function skipWithLabels(input, cur, ctx) {
1424
+ const spec = analyzeLabeledTrivia(ctx.trivia);
1425
+ if (spec) return scanLabeledTriviaEnd(input, cur, spec, ctx.state);
1426
+ const tr = parseTriviaNoCapture(ctx.trivia, input, cur, ctx);
1427
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1428
+ }
1429
+ function advanceTrivia(input, cur, ctx) {
1430
+ const triviaP = ctx.trivia;
1431
+ if (!triviaP) return cur;
1432
+ if (!ctx.trackLines) {
1433
+ const fast2 = fastTriviaScanner(triviaP);
1434
+ if (fast2) return fast2(input, cur);
1435
+ if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1436
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1437
+ return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1514
1438
  }
1515
- if (parsers.length === literalIndices.length) {
1516
- const sortedIndices = [...literalIndices].sort(
1517
- (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
1518
- );
1519
- return { tag: "literalsLongestFirst", sortedIndices };
1439
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1440
+ const fast = fastTriviaScanner(triviaP);
1441
+ if (fast) {
1442
+ const end = fast(input, cur);
1443
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1444
+ return end;
1520
1445
  }
1521
- const shared = detectSharedPrefix(parsers);
1522
- if (shared !== null) return shared;
1523
- return { tag: "firstMatch" };
1524
- }
1525
- function bareLeadingTermKey(term) {
1526
- const d = term._def;
1527
- if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
1528
- if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
1529
- return null;
1530
- }
1531
- function detectSharedPrefix(parsers) {
1532
- if (parsers.length < 2) return null;
1533
- let key = null;
1534
- let prefix = null;
1535
- const members = [];
1536
- for (let i = 0; i < parsers.length; i++) {
1537
- const term0 = leadingTermOfArm(parsers[i]);
1538
- if (term0 === null) return null;
1539
- const k = bareLeadingTermKey(term0);
1540
- if (k === null) return null;
1541
- if (key === null) {
1542
- key = k;
1543
- prefix = term0;
1544
- } else if (k !== key) return null;
1545
- members.push(i);
1446
+ if (ctx.triviaKindLabels) {
1447
+ const end = skipWithLabels(input, cur, ctx);
1448
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1449
+ return end;
1546
1450
  }
1547
- if (prefix === null || members.length < 2) return null;
1548
- return { tag: "sharedPrefix", prefix, members };
1451
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1452
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1549
1453
  }
1550
- function leadingTermOfArm(arm) {
1551
- let d = arm._def;
1552
- for (; ; ) {
1553
- if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
1554
- d = d.parser._def;
1555
- continue;
1454
+ function scanTrivia(input, cur, ctx) {
1455
+ const triviaP = ctx.trivia;
1456
+ if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1457
+ const log = ctx._triviaLog;
1458
+ const rootLog = ctx._rootTriviaLog;
1459
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1460
+ if (!ctx.trackLines) {
1461
+ const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1462
+ if (fast2 && log === void 0 && !captureTl) {
1463
+ return { end: fast2(input, cur), commit: NOOP_COMMIT };
1556
1464
  }
1557
- break;
1558
- }
1559
- if (d.tag !== "sequence" || d.parsers.length < 2) return null;
1560
- return d.parsers[0];
1561
- }
1562
- function computeAutoNot(parsers) {
1563
- return parsers.map((p, i) => {
1564
- const litVal = getCoreLiteralValue(p);
1565
- if (litVal === null) return null;
1566
- const checks = [];
1567
- for (let j = i + 1; j < parsers.length; j++) {
1568
- const other = parsers[j];
1569
- const otherLit = getCoreLiteralValue(other);
1570
- if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
1571
- checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
1572
- continue;
1573
- }
1574
- const regexDef = getCoreRegexDef(other);
1575
- if (regexDef !== null) {
1576
- const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
1577
- if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
1578
- }
1465
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1466
+ return scanWithLabels(input, cur, ctx);
1579
1467
  }
1580
- return checks.length > 0 ? checks : null;
1581
- });
1582
- }
1583
- function autoNotFires(input, end, checks) {
1584
- for (const check of checks) {
1585
- if (check.kind === "firstSet") {
1586
- const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
1587
- if (inFirstSet(code, check.set)) return true;
1588
- } else {
1589
- if (input.startsWith(check.value, end)) return true;
1468
+ if (ctx.triviaKindLabels) return { end: skipWithLabels(input, cur, ctx), commit: NOOP_COMMIT };
1469
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1470
+ const tr3 = triviaP.parse(input, cur, {
1471
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1472
+ state: ctx.state
1473
+ });
1474
+ if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1475
+ const end = tr3.span.end;
1476
+ return {
1477
+ end,
1478
+ commit: () => {
1479
+ pushTriviaLogEntry(ctx, cur, end);
1480
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1481
+ }
1482
+ };
1590
1483
  }
1484
+ const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1485
+ return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1591
1486
  }
1592
- return false;
1593
- }
1594
- function getCoreLiteralValue(p) {
1595
- const def = p._def;
1596
- if (def.tag === "literal" && !def.caseInsensitive) return def.value;
1597
- if (def.tag === "transform") return getCoreLiteralValue(def.parser);
1598
- return null;
1599
- }
1600
- function getCoreRegexDef(p) {
1601
- const def = p._def;
1602
- if (def.tag === "regex") return { source: def.source, flags: def.flags };
1603
- if (def.tag === "transform") return getCoreRegexDef(def.parser);
1604
- if (def.tag === "label") return getCoreRegexDef(def.parser);
1605
- return null;
1606
- }
1607
- function applyTransforms(p, value, span) {
1608
- const def = p._def;
1609
- if (def.tag === "transform") {
1610
- const inner = applyTransforms(def.parser, value, span);
1611
- return def.fn(inner, span);
1487
+ const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1488
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1489
+ if (fast && log === void 0 && !captureTl) {
1490
+ const end = fast(input, cur);
1491
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1492
+ return { end, commit: NOOP_COMMIT };
1612
1493
  }
1613
- return value;
1614
- }
1615
- function continuationFirstSet(lit, source, flags) {
1616
- const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
1617
- re.lastIndex = 0;
1618
- const base = re.exec(lit);
1619
- if (!base || base[0] !== lit) return null;
1620
- const contCodes = [];
1621
- for (let code = 1; code < 128; code++) {
1622
- re.lastIndex = 0;
1623
- const m = re.exec(lit + String.fromCharCode(code));
1624
- if (m && m[0].length > lit.length) contCodes.push(code);
1494
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1495
+ const scan = scanWithLabels(input, cur, ctx);
1496
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1497
+ return scan;
1625
1498
  }
1626
- if (contCodes.length === 0) return null;
1627
- return codesToFirstSet(contCodes);
1628
- }
1629
- function codesToFirstSet(codes) {
1630
- codes.sort((a, b) => a - b);
1631
- const ranges = [];
1632
- let lo = codes[0], hi = codes[0];
1633
- for (let i = 1; i < codes.length; i++) {
1634
- if (codes[i] === hi + 1) {
1635
- hi = codes[i];
1636
- } else {
1637
- ranges.push({ lo, hi });
1638
- lo = hi = codes[i];
1639
- }
1499
+ if (ctx.triviaKindLabels) {
1500
+ const end = skipWithLabels(input, cur, ctx);
1501
+ if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1502
+ return { end, commit: NOOP_COMMIT };
1640
1503
  }
1641
- ranges.push({ lo, hi });
1642
- return { kind: "ranges", ranges };
1504
+ if (log !== void 0 || rootLog !== void 0 || captureTl) {
1505
+ const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1506
+ if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1507
+ const end = tr2.span.end;
1508
+ return {
1509
+ end,
1510
+ commit: () => {
1511
+ pushTriviaLogEntry(ctx, cur, end);
1512
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1513
+ }
1514
+ };
1515
+ }
1516
+ const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1517
+ return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1643
1518
  }
1644
- function inFirstSet(code, fs) {
1645
- if (fs.kind === "any") return true;
1646
- if (fs.kind === "empty") return false;
1647
- for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1648
- return false;
1519
+ function consumeTrivia(input, cur, ctx) {
1520
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1521
+ const scan = scanTrivia(input, cur, ctx);
1522
+ scan.commit();
1523
+ return scan.end;
1649
1524
  }
1650
- function areDisjoint(sets) {
1651
- if (sets.some((s) => s.kind === "any")) return false;
1652
- for (let i = 0; i < sets.length; i++)
1653
- for (let j = i + 1; j < sets.length; j++)
1654
- if (intersects(sets[i], sets[j])) return false;
1655
- return true;
1525
+ function fastTriviaScanner(trivia2) {
1526
+ const cached = fastTriviaCache.get(trivia2);
1527
+ if (cached !== void 0) return cached;
1528
+ const scanner = buildFastTriviaScanner(trivia2);
1529
+ fastTriviaCache.set(trivia2, scanner);
1530
+ return scanner;
1656
1531
  }
1657
- function buildAsciiDispatch(parsers) {
1658
- const table = Array(128).fill(-1);
1659
- for (let i = 0; i < parsers.length; i++) {
1660
- const fs = parsers[i]._meta.firstSet;
1661
- if (fs.kind !== "ranges") continue;
1662
- for (const { lo, hi } of fs.ranges) {
1663
- for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1664
- table[code] = i;
1532
+ function buildFastTriviaScanner(trivia2) {
1533
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1534
+ const direct = regexTriviaScanner(core);
1535
+ if (direct) return direct;
1536
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1537
+ if (!repeat) return null;
1538
+ const one = regexTriviaScanner(repeat);
1539
+ if (one) return loopScanner([one]);
1540
+ if (repeat._def.tag !== "choice") return null;
1541
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1542
+ if (arms.some((s) => s === null)) return null;
1543
+ return loopScanner(arms);
1544
+ }
1545
+ function loopScanner(arms) {
1546
+ return (input, cur) => {
1547
+ let pos = cur;
1548
+ scan: while (pos < input.length) {
1549
+ for (const arm of arms) {
1550
+ const end = arm(input, pos);
1551
+ if (end > pos) {
1552
+ pos = end;
1553
+ continue scan;
1554
+ }
1665
1555
  }
1556
+ break;
1666
1557
  }
1667
- }
1668
- return table;
1669
- }
1670
-
1671
- // src/cst/trivia-kinds.ts
1672
- function unwrapTrivia(p) {
1673
- let cur = p;
1674
- while (cur._def.tag === "trivia") cur = cur._def.parser;
1675
- return cur;
1558
+ return pos;
1559
+ };
1676
1560
  }
1677
- function peelLabel(p) {
1678
- if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1679
- return null;
1561
+ function regexTriviaScanner(parser2) {
1562
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1563
+ const source = parser2._def.source;
1564
+ return classRunSource(source) ?? altStarSource(source);
1680
1565
  }
1681
- function analyzeLabeledTrivia(trivia2) {
1682
- let core = unwrapTrivia(trivia2);
1683
- let minRepeats = 1;
1684
- if (core._def.tag === "oneOrMore") {
1685
- core = core._def.parser;
1686
- minRepeats = 1;
1687
- } else if (core._def.tag === "many") {
1688
- core = core._def.parser;
1689
- minRepeats = 0;
1690
- }
1691
- const arms = [];
1692
- if (core._def.tag === "choice") {
1693
- for (let i = 0; i < core._def.parsers.length; i++) {
1694
- const peeled = peelLabel(core._def.parsers[i]);
1695
- if (!peeled) return null;
1696
- arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1697
- }
1698
- } else {
1699
- const peeled = peelLabel(core);
1700
- if (!peeled) return null;
1701
- arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1566
+ function inRanges2(cp, ranges) {
1567
+ for (let i = 0; i < ranges.length; i++) {
1568
+ const r = ranges[i];
1569
+ if (cp >= r[0] && cp <= r[1]) return true;
1702
1570
  }
1703
- return { labels: arms.map((a) => a.label), arms, minRepeats };
1571
+ return false;
1704
1572
  }
1705
- function matchArmAt(input, pos, arm) {
1706
- const r = arm.parse(input, pos, { trackLines: false });
1707
- if (!r.ok || r.span.end <= pos) return null;
1708
- return { end: r.span.end };
1573
+ function classScanner(classBody) {
1574
+ const ranges = parseClassRanges(classBody);
1575
+ if (!ranges) return null;
1576
+ return (input, cur) => {
1577
+ let pos = cur;
1578
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1579
+ return pos;
1580
+ };
1709
1581
  }
1710
- function scanLabeledTriviaChunks(input, cur, spec) {
1711
- const chunks = [];
1712
- let pos = cur;
1713
- while (pos < input.length) {
1714
- let matched = null;
1715
- for (const arm of spec.arms) {
1716
- const m = matchArmAt(input, pos, arm.parser);
1717
- if (m) {
1718
- matched = { end: m.end, kindIndex: arm.kindIndex };
1719
- break;
1720
- }
1582
+ function untilLineBreakScanner(leaderCode) {
1583
+ return (input, cur) => {
1584
+ if (input.charCodeAt(cur) !== leaderCode) return cur;
1585
+ let pos = cur + 1;
1586
+ while (pos < input.length) {
1587
+ const cc = input.charCodeAt(pos);
1588
+ if (cc === 10 || cc === 13) break;
1589
+ pos++;
1721
1590
  }
1722
- if (!matched) break;
1723
- chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1724
- pos = matched.end;
1591
+ return pos;
1592
+ };
1593
+ }
1594
+ function classRunSource(source) {
1595
+ const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1596
+ return m ? classScanner(m[1]) : null;
1597
+ }
1598
+ function classifyTriviaArm(arm) {
1599
+ const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1600
+ if (cls) {
1601
+ const ranges = parseClassRanges(cls[1]);
1602
+ return ranges ? { kind: "class", ranges } : null;
1725
1603
  }
1726
- if (chunks.length < spec.minRepeats) {
1727
- return { end: cur, chunks: [] };
1604
+ const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1605
+ if (lc) {
1606
+ const marker = lc[1];
1607
+ return { kind: "untilLineBreak", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1728
1608
  }
1729
- return { end: pos, chunks };
1609
+ return null;
1730
1610
  }
1731
- function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1732
- const chunks = [];
1733
- let pos = cur;
1734
- while (pos < input.length) {
1735
- const c = input.charCodeAt(pos);
1736
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1737
- const start = pos;
1738
- pos++;
1739
- while (pos < input.length) {
1740
- const c2 = input.charCodeAt(pos);
1741
- if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1742
- else break;
1611
+ function armScanner(arm) {
1612
+ if (arm.kind === "untilLineBreak") return untilLineBreakScanner(arm.code);
1613
+ const ranges = arm.ranges;
1614
+ return (input, cur) => {
1615
+ let pos = cur;
1616
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1617
+ return pos;
1618
+ };
1619
+ }
1620
+ function fusedTriviaScanner(ranges, leaders) {
1621
+ const c0 = leaders[0];
1622
+ const single = leaders.length === 1;
1623
+ return (input, cur) => {
1624
+ let pos = cur;
1625
+ const len = input.length;
1626
+ for (; ; ) {
1627
+ const c = input.charCodeAt(pos);
1628
+ if (pos < len && inRanges2(c, ranges)) {
1629
+ pos++;
1630
+ continue;
1743
1631
  }
1744
- chunks.push({ start, end: pos, kindIndex: wsKind });
1745
- continue;
1746
- }
1747
- if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1748
- let j = pos + 2;
1749
- while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
1750
- if (j + 1 < input.length && input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47) {
1751
- const start = pos;
1752
- pos = j + 2;
1753
- chunks.push({ start, end: pos, kindIndex: commentKind });
1632
+ if (single ? c === c0 : leaders.includes(c)) {
1633
+ pos++;
1634
+ while (pos < len) {
1635
+ const cc = input.charCodeAt(pos);
1636
+ if (cc === 10 || cc === 13) break;
1637
+ pos++;
1638
+ }
1754
1639
  continue;
1755
1640
  }
1756
1641
  break;
1757
1642
  }
1758
- break;
1759
- }
1760
- return { end: pos, chunks };
1761
- }
1762
- function tryFastLabeledScan(input, cur, trivia2) {
1763
- const spec = analyzeLabeledTrivia(trivia2);
1764
- if (!spec || spec.arms.length !== 2) return null;
1765
- const wsArm = spec.arms.find((a) => {
1766
- const src = getCoreRegexDef(a.parser)?.source;
1767
- return src != null && !src.includes("\\*");
1768
- });
1769
- const commentArm = spec.arms.find((a) => {
1770
- const src = getCoreRegexDef(a.parser)?.source;
1771
- return src != null && src.includes("\\*");
1772
- });
1773
- if (!wsArm || !commentArm) return null;
1774
- const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1775
- if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1776
- return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1643
+ return pos;
1644
+ };
1777
1645
  }
1778
- function recordTriviaChunks(ctx, chunks) {
1779
- const kinds = ctx.triviaKindLabels;
1780
- const mask = ctx._triviaCaptureMask;
1781
- for (const ch2 of chunks) {
1782
- pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1783
- if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1784
- if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1785
- pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1786
- }
1646
+ function splitTopLevelAlts(body) {
1647
+ const arms = [];
1648
+ let inClass = false;
1649
+ let start = 0;
1650
+ for (let i = 0; i < body.length; i++) {
1651
+ const c = body[i];
1652
+ if (c === "\\") {
1653
+ i++;
1654
+ continue;
1655
+ }
1656
+ if (inClass) {
1657
+ if (c === "]") inClass = false;
1658
+ continue;
1659
+ }
1660
+ if (c === "[") inClass = true;
1661
+ else if (c === "(") return null;
1662
+ else if (c === "|") {
1663
+ arms.push(body.slice(start, i));
1664
+ start = i + 1;
1787
1665
  }
1788
1666
  }
1667
+ arms.push(body.slice(start));
1668
+ return arms;
1789
1669
  }
1790
- function triviaKindMask(labels, keep) {
1791
- if (!labels) return void 0;
1792
- let mask = 0;
1793
- for (const name of keep) {
1794
- const idx = labels.indexOf(name);
1795
- if (idx >= 0) mask |= 1 << idx;
1670
+ function altStarSource(source) {
1671
+ const m = /^\(\?:(.*)\)[*+]$/.exec(source);
1672
+ if (!m) return null;
1673
+ const armSrcs = splitTopLevelAlts(m[1]);
1674
+ if (!armSrcs || armSrcs.length < 2) return null;
1675
+ const arms = [];
1676
+ for (const src of armSrcs) {
1677
+ const arm = classifyTriviaArm(src);
1678
+ if (!arm) return null;
1679
+ arms.push(arm);
1796
1680
  }
1797
- return mask;
1681
+ const ranges = [];
1682
+ const leaders = [];
1683
+ for (const arm of arms) {
1684
+ if (arm.kind === "class") ranges.push(...arm.ranges);
1685
+ else leaders.push(arm.code);
1686
+ }
1687
+ if (leaders.some((code) => inRanges2(code, ranges))) {
1688
+ return loopScanner(arms.map(armScanner));
1689
+ }
1690
+ if (leaders.length === 0) return armScanner({ kind: "class", ranges });
1691
+ return fusedTriviaScanner(ranges, leaders);
1798
1692
  }
1799
1693
 
1800
- // src/combinators/trivia-skip.ts
1801
- var NOOP_COMMIT = () => {
1802
- };
1803
- var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1804
- function needsDeferredTriviaCommit(ctx) {
1805
- return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1806
- }
1807
- function saveTriviaMark(ctx) {
1808
- const m = saveCstMark(ctx);
1809
- return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
1810
- }
1811
- function rollbackTrivia(ctx, mark) {
1812
- rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1813
- if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1814
- }
1815
- function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1816
- const probeCtx = {
1817
- trackLines: ctx.trackLines,
1818
- state: ctx.state,
1819
- ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1820
- ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1821
- ...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
1694
+ // src/recovery/scan.ts
1695
+ function probeAt(sentinel, input, pos, ctx) {
1696
+ const s = {
1697
+ _probe: ctx._probe,
1698
+ _errors: ctx._errors,
1699
+ _cstLeaves: ctx._cstLeaves,
1700
+ _cstChildren: ctx._cstChildren,
1701
+ _cstRawChildren: ctx._cstRawChildren,
1702
+ _cstTriviaLog: ctx._cstTriviaLog,
1703
+ _triviaLog: ctx._triviaLog,
1704
+ _rootTriviaLog: ctx._rootTriviaLog,
1705
+ _fields: ctx._fields,
1706
+ _cstBuf: ctx._cstBuf,
1707
+ _tolerant: ctx._tolerant,
1708
+ _sync: ctx._sync
1822
1709
  };
1823
- const result = triviaP.parse(input, cur, probeCtx);
1824
- ctx._lineScannedTo = probeCtx._lineScannedTo;
1825
- return result;
1826
- }
1827
- function saveLookaheadMark(ctx) {
1828
- return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1829
- }
1830
- function rollbackLookahead(ctx, mark) {
1831
- rollbackTrivia(ctx, mark);
1832
- if (ctx._probe) ctx._probe.best = mark.probeBest;
1710
+ ctx._probe = void 0;
1711
+ ctx._errors = void 0;
1712
+ ctx._cstLeaves = void 0;
1713
+ ctx._cstChildren = void 0;
1714
+ ctx._cstRawChildren = void 0;
1715
+ ctx._cstTriviaLog = void 0;
1716
+ ctx._triviaLog = void 0;
1717
+ ctx._rootTriviaLog = void 0;
1718
+ ctx._fields = void 0;
1719
+ ctx._cstBuf = void 0;
1720
+ ctx._tolerant = void 0;
1721
+ ctx._sync = void 0;
1722
+ try {
1723
+ return sentinel.parse(input, pos, ctx).ok;
1724
+ } finally {
1725
+ ctx._probe = s._probe;
1726
+ ctx._errors = s._errors;
1727
+ ctx._cstLeaves = s._cstLeaves;
1728
+ ctx._cstChildren = s._cstChildren;
1729
+ ctx._cstRawChildren = s._cstRawChildren;
1730
+ ctx._cstTriviaLog = s._cstTriviaLog;
1731
+ ctx._triviaLog = s._triviaLog;
1732
+ ctx._rootTriviaLog = s._rootTriviaLog;
1733
+ ctx._fields = s._fields;
1734
+ ctx._cstBuf = s._cstBuf;
1735
+ ctx._tolerant = s._tolerant;
1736
+ ctx._sync = s._sync;
1737
+ }
1833
1738
  }
1834
- function scanWithLabels(input, cur, ctx) {
1835
- const triviaP = ctx.trivia;
1836
- const spec = analyzeLabeledTrivia(triviaP);
1837
- if (!spec) return { end: cur, commit: NOOP_COMMIT };
1838
- const fast = tryFastLabeledScan(input, cur, triviaP);
1839
- const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
1840
- if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1739
+ function orSentinel(a, b) {
1740
+ if (b === void 0) return a;
1841
1741
  return {
1842
- end,
1843
- commit: () => recordTriviaChunks(ctx, chunks)
1844
- };
1845
- }
1846
- function advanceTrivia(input, cur, ctx) {
1847
- const triviaP = ctx.trivia;
1848
- if (!triviaP) return cur;
1849
- if (!ctx.trackLines) {
1850
- const fast2 = fastTriviaScanner(triviaP);
1851
- if (fast2) return fast2(input, cur);
1852
- if (ctx.triviaKindLabels) {
1853
- const scan = scanWithLabels(input, cur, ctx);
1854
- return scan.end;
1742
+ _tag: "orSentinel",
1743
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1744
+ _def: { tag: "unknown" },
1745
+ parse(input, pos, ctx) {
1746
+ const ra = a.parse(input, pos, ctx);
1747
+ if (ra.ok) return ra;
1748
+ return b.parse(input, pos, ctx);
1855
1749
  }
1856
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1857
- return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1858
- }
1859
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1860
- const fast = fastTriviaScanner(triviaP);
1861
- if (fast) {
1862
- const end = fast(input, cur);
1863
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1864
- return end;
1865
- }
1866
- if (ctx.triviaKindLabels) {
1867
- const scan = scanWithLabels(input, cur, ctx);
1868
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1869
- return scan.end;
1870
- }
1871
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1872
- return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1750
+ };
1873
1751
  }
1874
- function scanTrivia(input, cur, ctx) {
1875
- const triviaP = ctx.trivia;
1876
- if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1877
- const log = ctx._triviaLog;
1878
- const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1879
- if (!ctx.trackLines) {
1880
- const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1881
- if (fast2 && log === void 0 && !captureTl) {
1882
- return { end: fast2(input, cur), commit: NOOP_COMMIT };
1883
- }
1884
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1885
- return scanWithLabels(input, cur, ctx);
1886
- }
1887
- if (log !== void 0 || captureTl) {
1888
- const tr3 = triviaP.parse(input, cur, {
1889
- trackLines: log !== void 0 ? false : ctx.trackLines,
1890
- state: ctx.state
1891
- });
1892
- if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1893
- const end = tr3.span.end;
1894
- return {
1895
- end,
1896
- commit: () => {
1897
- pushTriviaLogEntry(ctx, cur, end);
1898
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1752
+ function firstSetSentinel(fs) {
1753
+ if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
1754
+ const ranges = fs.ranges;
1755
+ return {
1756
+ _tag: "firstSetSentinel",
1757
+ _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
1758
+ _def: { tag: "unknown" },
1759
+ parse(input, pos) {
1760
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
1761
+ if (code !== void 0) {
1762
+ for (const r of ranges) {
1763
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1899
1764
  }
1900
- };
1765
+ }
1766
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
1901
1767
  }
1902
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1903
- return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1904
- }
1905
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1906
- const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1907
- if (fast && log === void 0 && !captureTl) {
1908
- const end = fast(input, cur);
1909
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1910
- return { end, commit: NOOP_COMMIT };
1911
- }
1912
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1913
- const scan = scanWithLabels(input, cur, ctx);
1914
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1915
- return scan;
1916
- }
1917
- if (log !== void 0 || captureTl) {
1918
- const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1919
- if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1920
- const end = tr2.span.end;
1921
- return {
1922
- end,
1923
- commit: () => {
1924
- pushTriviaLogEntry(ctx, cur, end);
1925
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1926
- }
1927
- };
1928
- }
1929
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1930
- return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1768
+ };
1931
1769
  }
1932
- function consumeTrivia(input, cur, ctx) {
1933
- if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1934
- const scan = scanTrivia(input, cur, ctx);
1935
- scan.commit();
1936
- return scan.end;
1770
+ function recoverScan(input, from, ctx, sync, expected) {
1771
+ let scanPos = from;
1772
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1773
+ const span = { start: from, end: scanPos };
1774
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1775
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1776
+ ctx._errors?.push(error);
1777
+ return { error, end: scanPos };
1937
1778
  }
1938
- function fastTriviaScanner(trivia2) {
1939
- const cached = fastTriviaCache.get(trivia2);
1940
- if (cached !== void 0) return cached;
1941
- const scanner = buildFastTriviaScanner(trivia2);
1942
- fastTriviaCache.set(trivia2, scanner);
1943
- return scanner;
1779
+ function matchesAt(sentinel, input, pos, ctx) {
1780
+ return probeAt(sentinel, input, pos, ctx);
1944
1781
  }
1945
- function buildFastTriviaScanner(trivia2) {
1946
- const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1947
- const direct = regexTriviaScanner(core);
1948
- if (direct) return direct;
1949
- const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1950
- if (!repeat) return null;
1951
- const one = regexTriviaScanner(repeat);
1952
- if (one) return loopScanner([one]);
1953
- if (repeat._def.tag !== "choice") return null;
1954
- const arms = repeat._def.parsers.map(regexTriviaScanner);
1955
- if (arms.some((s) => s === null)) return null;
1956
- return loopScanner(arms);
1782
+ function captureError(ctx, error) {
1783
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1957
1784
  }
1958
- function loopScanner(arms) {
1959
- return (input, cur) => {
1960
- let pos = cur;
1961
- scan: while (pos < input.length) {
1962
- for (const arm of arms) {
1963
- const end = arm(input, pos);
1964
- if (end > pos) {
1965
- pos = end;
1966
- continue scan;
1785
+ var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
1786
+
1787
+ // src/combinators/sequence.ts
1788
+ function sequence(...parsers) {
1789
+ const meta = {
1790
+ // Union through the nullable prefix — a leading optional()/many() lets a later
1791
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
1792
+ firstSet: sequenceFirstSet(parsers),
1793
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1794
+ isTrivia: false
1795
+ };
1796
+ const def = { tag: "sequence", parsers };
1797
+ let followSentinels;
1798
+ function parseTolerant(input, pos, ctx) {
1799
+ followSentinels ??= parsers.map((_, i) => {
1800
+ const fs = parsers.slice(i + 1).reduce(
1801
+ (acc, p) => union(acc, firstSetOf(p)),
1802
+ { kind: "empty" }
1803
+ );
1804
+ return firstSetSentinel(fs);
1805
+ });
1806
+ const values = def.valueUnused ? void 0 : [];
1807
+ let cur = pos;
1808
+ const inheritedSync = ctx._sync;
1809
+ try {
1810
+ for (let i = 0; i < parsers.length; i++) {
1811
+ ctx._sync = followSentinels[i] ?? inheritedSync;
1812
+ if (ctx.trivia && i > 0) {
1813
+ const mark = saveTriviaMark(ctx);
1814
+ let scanEnd;
1815
+ if (needsDeferredTriviaCommit(ctx)) {
1816
+ const scan = scanTrivia(input, cur, ctx);
1817
+ scan.commit();
1818
+ scanEnd = scan.end;
1819
+ } else {
1820
+ scanEnd = advanceTrivia(input, cur, ctx);
1821
+ }
1822
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1823
+ if (!result2.ok) return result2;
1824
+ if (result2.span.end > scanEnd) cur = result2.span.end;
1825
+ else rollbackTrivia(ctx, mark);
1826
+ if (values !== void 0) values.push(result2.value);
1827
+ continue;
1967
1828
  }
1829
+ const result = parsers[i].parse(input, cur, ctx);
1830
+ if (!result.ok) return result;
1831
+ if (values !== void 0) values.push(result.value);
1832
+ cur = result.span.end;
1968
1833
  }
1969
- break;
1834
+ } finally {
1835
+ ctx._sync = inheritedSync;
1836
+ }
1837
+ return {
1838
+ ok: true,
1839
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1840
+ value: values ?? void 0,
1841
+ span: { start: pos, end: cur }
1842
+ };
1843
+ }
1844
+ return {
1845
+ _tag: "sequence",
1846
+ _meta: meta,
1847
+ _def: def,
1848
+ parse(input, pos, ctx) {
1849
+ if (ctx._tolerant) return parseTolerant(input, pos, ctx);
1850
+ const values = def.valueUnused ? void 0 : [];
1851
+ let cur = pos;
1852
+ for (let i = 0; i < parsers.length; i++) {
1853
+ if (ctx.trivia && i > 0) {
1854
+ let scanEnd;
1855
+ let mark = saveTriviaMark(ctx);
1856
+ if (needsDeferredTriviaCommit(ctx)) {
1857
+ const scan = scanTrivia(input, cur, ctx);
1858
+ scan.commit();
1859
+ scanEnd = scan.end;
1860
+ } else {
1861
+ scanEnd = advanceTrivia(input, cur, ctx);
1862
+ }
1863
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1864
+ if (!result2.ok) return result2;
1865
+ if (result2.span.end > scanEnd) {
1866
+ cur = result2.span.end;
1867
+ } else {
1868
+ rollbackTrivia(ctx, mark);
1869
+ }
1870
+ if (values !== void 0) values.push(result2.value);
1871
+ continue;
1872
+ }
1873
+ const result = parsers[i].parse(input, cur, ctx);
1874
+ if (!result.ok) return result;
1875
+ if (values !== void 0) values.push(result.value);
1876
+ cur = result.span.end;
1877
+ }
1878
+ return {
1879
+ ok: true,
1880
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1881
+ value: values ?? void 0,
1882
+ span: { start: pos, end: cur }
1883
+ };
1970
1884
  }
1971
- return pos;
1972
1885
  };
1973
1886
  }
1974
- function regexTriviaScanner(parser2) {
1975
- if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1976
- const source = parser2._def.source;
1977
- return classRunSource(source) ?? altStarSource(source) ?? (blockCommentSource(source) ? scanBlockComment : null);
1887
+
1888
+ // src/combinators/expect.ts
1889
+ function deriveExpected(c) {
1890
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1978
1891
  }
1979
- function inRanges2(cp, ranges) {
1980
- for (let i = 0; i < ranges.length; i++) {
1981
- const r = ranges[i];
1982
- if (cp >= r[0] && cp <= r[1]) return true;
1892
+ function derive(c, seen) {
1893
+ const deriveExpected2 = (p) => derive(p, seen);
1894
+ const def = c._def;
1895
+ switch (def.tag) {
1896
+ case "literal":
1897
+ return [JSON.stringify(def.value)];
1898
+ case "regex":
1899
+ return [`/${def.source}/`];
1900
+ case "keywords":
1901
+ return def.words.map((w) => JSON.stringify(w));
1902
+ case "label":
1903
+ return [def.label];
1904
+ case "choice":
1905
+ return def.parsers.flatMap(deriveExpected2);
1906
+ case "dispatch":
1907
+ return deriveExpected2(def.selector);
1908
+ // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1909
+ // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1910
+ // able to fail first — deriving from term 0 alone named a token the parse
1911
+ // never actually required. A leading `not(…)` is zero-width and contributes
1912
+ // nothing (its own expectation is about what must NOT be here), but it is
1913
+ // nullable, so keep scanning past it. Stop at the first term that must match.
1914
+ case "sequence": {
1915
+ const out = [];
1916
+ for (const term of def.parsers) {
1917
+ if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1918
+ if (!matchesEmpty(term)) break;
1919
+ }
1920
+ return out;
1921
+ }
1922
+ case "attempt":
1923
+ return deriveExpected2(def.parser);
1924
+ // Delegating wrappers whose first-token failure is their inner parser's — must
1925
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1926
+ // node, which reads this) names the real expected token, not the wrapper tag.
1927
+ case "field":
1928
+ case "withCtx":
1929
+ case "recover":
1930
+ return deriveExpected2(def.parser);
1931
+ case "skip":
1932
+ return deriveExpected2(def.main);
1933
+ case "expect":
1934
+ return def.expected;
1935
+ case "node":
1936
+ case "grammar":
1937
+ case "trivia":
1938
+ case "token":
1939
+ case "leaf":
1940
+ case "optional":
1941
+ case "many":
1942
+ case "oneOrMore":
1943
+ case "transform":
1944
+ case "not":
1945
+ case "peek":
1946
+ return deriveExpected2(def.parser);
1947
+ case "routed":
1948
+ return ["routed()"];
1949
+ case "lazy": {
1950
+ const name = c._ruleName;
1951
+ if (seen.has(c)) return name ? [name] : [];
1952
+ seen.add(c);
1953
+ try {
1954
+ return deriveExpected2(def.thunk());
1955
+ } catch {
1956
+ return name ? [name] : [];
1957
+ } finally {
1958
+ seen.delete(c);
1959
+ }
1960
+ }
1961
+ default:
1962
+ return [];
1983
1963
  }
1984
- return false;
1985
1964
  }
1986
- function classScanner(classBody) {
1987
- const ranges = parseClassRanges(classBody);
1988
- if (!ranges) return null;
1989
- return (input, cur) => {
1990
- let pos = cur;
1991
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1992
- return pos;
1965
+ function expect(combinator, label2) {
1966
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1967
+ const meta = {
1968
+ firstSet: combinator._meta.firstSet,
1969
+ canMatchNewline: combinator._meta.canMatchNewline,
1970
+ isTrivia: false
1993
1971
  };
1994
- }
1995
- function lineCommentScanner(commentCode) {
1996
- return (input, cur) => {
1997
- if (input.charCodeAt(cur) !== commentCode) return cur;
1998
- let pos = cur + 1;
1999
- while (pos < input.length) {
2000
- const cc = input.charCodeAt(pos);
2001
- if (cc === 10 || cc === 13) break;
2002
- pos++;
1972
+ return {
1973
+ _tag: "expect",
1974
+ _meta: meta,
1975
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
1976
+ parse(input, pos, ctx) {
1977
+ const result = combinator.parse(input, pos, ctx);
1978
+ if (result.ok) return result;
1979
+ const span = { start: pos, end: pos };
1980
+ const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1981
+ ctx._errors?.push(error);
1982
+ if (ctx._tolerant) captureError(ctx, error);
1983
+ return { ok: true, value: error, span: { start: pos, end: pos } };
2003
1984
  }
2004
- return pos;
2005
1985
  };
2006
1986
  }
2007
- function classRunSource(source) {
2008
- const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
2009
- return m ? classScanner(m[1]) : null;
1987
+ function isParseError(value) {
1988
+ return typeof value === "object" && value !== null && value._tag === "parseError";
2010
1989
  }
2011
- function classifyTriviaArm(arm) {
2012
- const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
2013
- if (cls) {
2014
- const ranges = parseClassRanges(cls[1]);
2015
- return ranges ? { kind: "class", ranges } : null;
1990
+
1991
+ // src/combinators/choice.ts
1992
+ function choice(...args) {
1993
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1994
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
1995
+ const hasGates = gates.some((g) => g !== null);
1996
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1997
+ let combined = { kind: "empty" };
1998
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
1999
+ const meta = {
2000
+ firstSet: combined,
2001
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2002
+ isTrivia: false,
2003
+ disjoint
2004
+ };
2005
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
2006
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
2007
+ let greedyLitMap = null;
2008
+ let sortedParsers = null;
2009
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
2010
+ if (strategy?.tag === "greedyClassify") {
2011
+ greedyLitMap = /* @__PURE__ */ new Map();
2012
+ for (let i = 0; i < parsers.length; i++) {
2013
+ if (i === strategy.superIndex) continue;
2014
+ const litVal = getCoreLiteralValue(parsers[i]);
2015
+ if (litVal !== null) greedyLitMap.set(litVal, i);
2016
+ }
2017
+ } else if (strategy?.tag === "literalsLongestFirst") {
2018
+ sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
2016
2019
  }
2017
- const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
2018
- if (lc) {
2019
- const marker = lc[1];
2020
- return { kind: "comment", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
2020
+ return {
2021
+ _tag: "choice",
2022
+ _meta: meta,
2023
+ _def: {
2024
+ tag: "choice",
2025
+ parsers,
2026
+ gates,
2027
+ disjoint,
2028
+ strategy: strategy ?? { tag: "firstMatch" },
2029
+ autoNot
2030
+ },
2031
+ parse(input, pos, ctx) {
2032
+ const expected = [];
2033
+ if (disjoint && pos < input.length) {
2034
+ const code = input.codePointAt(pos);
2035
+ let idx = code < 128 ? asciiDispatch[code] : -1;
2036
+ if (idx < 0) {
2037
+ for (let i = 0; i < parsers.length; i++) {
2038
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
2039
+ idx = i;
2040
+ break;
2041
+ }
2042
+ }
2043
+ }
2044
+ if (idx >= 0) {
2045
+ const gate2 = gates[idx];
2046
+ if (gate2 && !gate2(ctx.state)) {
2047
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
2048
+ }
2049
+ const result = parsers[idx].parse(input, pos, ctx);
2050
+ if (result.ok) return result;
2051
+ expected.push(...result.expected);
2052
+ if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
2053
+ return { ok: false, expected, span: { start: pos, end: pos } };
2054
+ }
2055
+ return {
2056
+ ok: false,
2057
+ expected: parsers.flatMap((p) => {
2058
+ const r = p.parse(input, pos, ctx);
2059
+ return r.ok ? [] : r.expected;
2060
+ }),
2061
+ span: { start: pos, end: pos }
2062
+ };
2063
+ }
2064
+ if (strategy?.tag === "greedyClassify") {
2065
+ const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
2066
+ if (!superResult.ok) return superResult;
2067
+ const end = superResult.span.end;
2068
+ const litIdx = greedyLitMap.get(input.slice(pos, end));
2069
+ if (litIdx !== void 0) {
2070
+ const litVal = getCoreLiteralValue(parsers[litIdx]);
2071
+ const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
2072
+ return { ok: true, value, span: { start: pos, end } };
2073
+ }
2074
+ return superResult;
2075
+ }
2076
+ if (strategy?.tag === "literalsLongestFirst") {
2077
+ for (const p of sortedParsers) {
2078
+ const r = p.parse(input, pos, ctx);
2079
+ if (r.ok) return r;
2080
+ expected.push(...r.expected);
2081
+ }
2082
+ return { ok: false, expected, span: { start: pos, end: pos } };
2083
+ }
2084
+ for (let i = 0; i < parsers.length; i++) {
2085
+ if (gates[i] && !gates[i](ctx.state)) continue;
2086
+ const mark = saveTriviaMark(ctx);
2087
+ const result = parsers[i].parse(input, pos, ctx);
2088
+ if (!result.ok) {
2089
+ rollbackTrivia(ctx, mark);
2090
+ expected.push(...result.expected);
2091
+ if (result.committed) return { ok: false, expected, span: result.span, committed: true };
2092
+ continue;
2093
+ }
2094
+ const checks = autoNot[i];
2095
+ if (checks && autoNotFires(input, result.span.end, checks)) {
2096
+ rollbackTrivia(ctx, mark);
2097
+ continue;
2098
+ }
2099
+ return result;
2100
+ }
2101
+ return { ok: false, expected, span: { start: pos, end: pos } };
2102
+ }
2103
+ };
2104
+ }
2105
+ function detectStrategy(parsers) {
2106
+ const regexIndices = [];
2107
+ const literalIndices = [];
2108
+ for (let i = 0; i < parsers.length; i++) {
2109
+ if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
2110
+ else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
2111
+ }
2112
+ if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
2113
+ const superIndex = regexIndices[0];
2114
+ const regexDef = getCoreRegexDef(parsers[superIndex]);
2115
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
2116
+ const re = new RegExp(regexDef.source, flags);
2117
+ const allSubsumed = literalIndices.every((i) => {
2118
+ const litVal = getCoreLiteralValue(parsers[i]);
2119
+ re.lastIndex = 0;
2120
+ const m = re.exec(litVal);
2121
+ return m !== null && m[0] === litVal;
2122
+ });
2123
+ if (allSubsumed) return { tag: "greedyClassify", superIndex };
2124
+ }
2125
+ if (parsers.length === literalIndices.length) {
2126
+ const sortedIndices = [...literalIndices].sort(
2127
+ (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
2128
+ );
2129
+ return { tag: "literalsLongestFirst", sortedIndices };
2021
2130
  }
2131
+ const shared = detectSharedPrefix(parsers);
2132
+ if (shared !== null) return shared;
2133
+ return { tag: "firstMatch" };
2134
+ }
2135
+ function bareLeadingTermKey(term) {
2136
+ const d = term._def;
2137
+ if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
2138
+ if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
2022
2139
  return null;
2023
2140
  }
2024
- function armScanner(arm) {
2025
- if (arm.kind === "comment") return lineCommentScanner(arm.code);
2026
- const ranges = arm.ranges;
2027
- return (input, cur) => {
2028
- let pos = cur;
2029
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
2030
- return pos;
2031
- };
2141
+ function detectSharedPrefix(parsers) {
2142
+ if (parsers.length < 2) return null;
2143
+ let key = null;
2144
+ let prefix = null;
2145
+ const members = [];
2146
+ for (let i = 0; i < parsers.length; i++) {
2147
+ const term0 = leadingTermOfArm(parsers[i]);
2148
+ if (term0 === null) return null;
2149
+ const k = bareLeadingTermKey(term0);
2150
+ if (k === null) return null;
2151
+ if (key === null) {
2152
+ key = k;
2153
+ prefix = term0;
2154
+ } else if (k !== key) return null;
2155
+ members.push(i);
2156
+ }
2157
+ if (prefix === null || members.length < 2) return null;
2158
+ return { tag: "sharedPrefix", prefix, members };
2032
2159
  }
2033
- function fusedTriviaScanner(ranges, commentCodes) {
2034
- const c0 = commentCodes[0];
2035
- const single = commentCodes.length === 1;
2036
- return (input, cur) => {
2037
- let pos = cur;
2038
- const len = input.length;
2039
- for (; ; ) {
2040
- const c = input.charCodeAt(pos);
2041
- if (pos < len && inRanges2(c, ranges)) {
2042
- pos++;
2160
+ function leadingTermOfArm(arm) {
2161
+ let d = arm._def;
2162
+ for (; ; ) {
2163
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
2164
+ d = d.parser._def;
2165
+ continue;
2166
+ }
2167
+ break;
2168
+ }
2169
+ if (d.tag !== "sequence" || d.parsers.length < 2) return null;
2170
+ return d.parsers[0];
2171
+ }
2172
+ function computeAutoNot(parsers) {
2173
+ return parsers.map((p, i) => {
2174
+ const litVal = getCoreLiteralValue(p);
2175
+ if (litVal === null) return null;
2176
+ const checks = [];
2177
+ for (let j = i + 1; j < parsers.length; j++) {
2178
+ const other = parsers[j];
2179
+ const otherLit = getCoreLiteralValue(other);
2180
+ if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
2181
+ checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
2043
2182
  continue;
2044
2183
  }
2045
- if (single ? c === c0 : commentCodes.includes(c)) {
2046
- pos++;
2047
- while (pos < len) {
2048
- const cc = input.charCodeAt(pos);
2049
- if (cc === 10 || cc === 13) break;
2050
- pos++;
2051
- }
2052
- continue;
2184
+ const regexDef = getCoreRegexDef(other);
2185
+ if (regexDef !== null) {
2186
+ const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
2187
+ if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
2053
2188
  }
2054
- break;
2055
2189
  }
2056
- return pos;
2057
- };
2190
+ return checks.length > 0 ? checks : null;
2191
+ });
2058
2192
  }
2059
- function splitTopLevelAlts(body) {
2060
- const arms = [];
2061
- let inClass = false;
2062
- let start = 0;
2063
- for (let i = 0; i < body.length; i++) {
2064
- const c = body[i];
2065
- if (c === "\\") {
2066
- i++;
2067
- continue;
2068
- }
2069
- if (inClass) {
2070
- if (c === "]") inClass = false;
2071
- continue;
2072
- }
2073
- if (c === "[") inClass = true;
2074
- else if (c === "(") return null;
2075
- else if (c === "|") {
2076
- arms.push(body.slice(start, i));
2077
- start = i + 1;
2193
+ function autoNotFires(input, end, checks) {
2194
+ for (const check of checks) {
2195
+ if (check.kind === "firstSet") {
2196
+ const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
2197
+ if (inFirstSet(code, check.set)) return true;
2198
+ } else {
2199
+ if (input.startsWith(check.value, end)) return true;
2078
2200
  }
2079
2201
  }
2080
- arms.push(body.slice(start));
2081
- return arms;
2202
+ return false;
2082
2203
  }
2083
- function altStarSource(source) {
2084
- const m = /^\(\?:(.*)\)[*+]$/.exec(source);
2085
- if (!m) return null;
2086
- const armSrcs = splitTopLevelAlts(m[1]);
2087
- if (!armSrcs || armSrcs.length < 2) return null;
2088
- const arms = [];
2089
- for (const src of armSrcs) {
2090
- const arm = classifyTriviaArm(src);
2091
- if (!arm) return null;
2092
- arms.push(arm);
2093
- }
2094
- const ranges = [];
2095
- const commentCodes = [];
2096
- for (const arm of arms) {
2097
- if (arm.kind === "class") ranges.push(...arm.ranges);
2098
- else commentCodes.push(arm.code);
2099
- }
2100
- if (commentCodes.some((code) => inRanges2(code, ranges))) {
2101
- return loopScanner(arms.map(armScanner));
2102
- }
2103
- if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
2104
- return fusedTriviaScanner(ranges, commentCodes);
2204
+ function getCoreLiteralValue(p) {
2205
+ const def = p._def;
2206
+ if (def.tag === "literal" && !def.caseInsensitive) return def.value;
2207
+ if (def.tag === "transform") return getCoreLiteralValue(def.parser);
2208
+ return null;
2209
+ }
2210
+ function getCoreRegexDef(p) {
2211
+ const def = p._def;
2212
+ if (def.tag === "regex") return { source: def.source, flags: def.flags };
2213
+ if (def.tag === "transform") return getCoreRegexDef(def.parser);
2214
+ if (def.tag === "label") return getCoreRegexDef(def.parser);
2215
+ return null;
2105
2216
  }
2106
- function blockCommentSource(source) {
2107
- return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
2217
+ function applyTransforms(p, value, span) {
2218
+ const def = p._def;
2219
+ if (def.tag === "transform") {
2220
+ const inner = applyTransforms(def.parser, value, span);
2221
+ return def.fn(inner, span);
2222
+ }
2223
+ return value;
2108
2224
  }
2109
- function scanBlockComment(input, cur) {
2110
- if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
2111
- const close = input.indexOf("*/", cur + 2);
2112
- return close === -1 ? cur : close + 2;
2225
+ function continuationFirstSet(lit, source, flags) {
2226
+ const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
2227
+ re.lastIndex = 0;
2228
+ const base = re.exec(lit);
2229
+ if (!base || base[0] !== lit) return null;
2230
+ const contCodes = [];
2231
+ for (let code = 1; code < 128; code++) {
2232
+ re.lastIndex = 0;
2233
+ const m = re.exec(lit + String.fromCharCode(code));
2234
+ if (m && m[0].length > lit.length) contCodes.push(code);
2235
+ }
2236
+ if (contCodes.length === 0) return null;
2237
+ return codesToFirstSet(contCodes);
2113
2238
  }
2114
-
2115
- // src/combinators/sequence.ts
2116
- function sequence(...parsers) {
2117
- const meta = {
2118
- // Union through the nullable prefix — a leading optional()/many() lets a later
2119
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
2120
- firstSet: sequenceFirstSet(parsers),
2121
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2122
- isTrivia: false
2123
- };
2124
- const def = { tag: "sequence", parsers };
2125
- let followSentinels;
2126
- function parseTolerant(input, pos, ctx) {
2127
- followSentinels ??= parsers.map((_, i) => {
2128
- const fs = parsers.slice(i + 1).reduce(
2129
- (acc, p) => union(acc, firstSetOf(p)),
2130
- { kind: "empty" }
2131
- );
2132
- return firstSetSentinel(fs);
2133
- });
2134
- const values = def.valueUnused ? void 0 : [];
2135
- let cur = pos;
2136
- const inheritedSync = ctx._sync;
2137
- try {
2138
- for (let i = 0; i < parsers.length; i++) {
2139
- ctx._sync = followSentinels[i] ?? inheritedSync;
2140
- if (ctx.trivia && i > 0) {
2141
- const mark = saveTriviaMark(ctx);
2142
- let scanEnd;
2143
- if (needsDeferredTriviaCommit(ctx)) {
2144
- const scan = scanTrivia(input, cur, ctx);
2145
- scan.commit();
2146
- scanEnd = scan.end;
2147
- } else {
2148
- scanEnd = advanceTrivia(input, cur, ctx);
2149
- }
2150
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2151
- if (!result2.ok) return result2;
2152
- if (result2.span.end > scanEnd) cur = result2.span.end;
2153
- else rollbackTrivia(ctx, mark);
2154
- if (values !== void 0) values.push(result2.value);
2155
- continue;
2156
- }
2157
- const result = parsers[i].parse(input, cur, ctx);
2158
- if (!result.ok) return result;
2159
- if (values !== void 0) values.push(result.value);
2160
- cur = result.span.end;
2161
- }
2162
- } finally {
2163
- ctx._sync = inheritedSync;
2239
+ function codesToFirstSet(codes) {
2240
+ codes.sort((a, b) => a - b);
2241
+ const ranges = [];
2242
+ let lo = codes[0], hi = codes[0];
2243
+ for (let i = 1; i < codes.length; i++) {
2244
+ if (codes[i] === hi + 1) {
2245
+ hi = codes[i];
2246
+ } else {
2247
+ ranges.push({ lo, hi });
2248
+ lo = hi = codes[i];
2164
2249
  }
2165
- return {
2166
- ok: true,
2167
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2168
- value: values ?? void 0,
2169
- span: { start: pos, end: cur }
2170
- };
2171
2250
  }
2172
- return {
2173
- _tag: "sequence",
2174
- _meta: meta,
2175
- _def: def,
2176
- parse(input, pos, ctx) {
2177
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2178
- const values = def.valueUnused ? void 0 : [];
2179
- let cur = pos;
2180
- for (let i = 0; i < parsers.length; i++) {
2181
- if (ctx.trivia && i > 0) {
2182
- let scanEnd;
2183
- let mark = saveTriviaMark(ctx);
2184
- if (needsDeferredTriviaCommit(ctx)) {
2185
- const scan = scanTrivia(input, cur, ctx);
2186
- scan.commit();
2187
- scanEnd = scan.end;
2188
- } else {
2189
- scanEnd = advanceTrivia(input, cur, ctx);
2190
- }
2191
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2192
- if (!result2.ok) return result2;
2193
- if (result2.span.end > scanEnd) {
2194
- cur = result2.span.end;
2195
- } else {
2196
- rollbackTrivia(ctx, mark);
2197
- }
2198
- if (values !== void 0) values.push(result2.value);
2199
- continue;
2200
- }
2201
- const result = parsers[i].parse(input, cur, ctx);
2202
- if (!result.ok) return result;
2203
- if (values !== void 0) values.push(result.value);
2204
- cur = result.span.end;
2251
+ ranges.push({ lo, hi });
2252
+ return { kind: "ranges", ranges };
2253
+ }
2254
+ function inFirstSet(code, fs) {
2255
+ if (fs.kind === "any") return true;
2256
+ if (fs.kind === "empty") return false;
2257
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
2258
+ return false;
2259
+ }
2260
+ function areDisjoint(sets) {
2261
+ if (sets.some((s) => s.kind === "any")) return false;
2262
+ for (let i = 0; i < sets.length; i++)
2263
+ for (let j = i + 1; j < sets.length; j++)
2264
+ if (intersects(sets[i], sets[j])) return false;
2265
+ return true;
2266
+ }
2267
+ function buildAsciiDispatch(parsers) {
2268
+ const table = Array(128).fill(-1);
2269
+ for (let i = 0; i < parsers.length; i++) {
2270
+ const fs = parsers[i]._meta.firstSet;
2271
+ if (fs.kind !== "ranges") continue;
2272
+ for (const { lo, hi } of fs.ranges) {
2273
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
2274
+ table[code] = i;
2205
2275
  }
2206
- return {
2207
- ok: true,
2208
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2209
- value: values ?? void 0,
2210
- span: { start: pos, end: cur }
2211
- };
2212
2276
  }
2213
- };
2277
+ }
2278
+ return table;
2214
2279
  }
2215
2280
 
2216
2281
  // src/combinators/dispatch.ts
@@ -2473,10 +2538,12 @@ function attempt(parser2) {
2473
2538
  }
2474
2539
  const mark = saveCstMark(ctx);
2475
2540
  const log = ctx._triviaLog?.length;
2541
+ const rootLog = ctx._rootTriviaLog?.length;
2476
2542
  const result = parser2.parse(input, pos, ctx);
2477
2543
  if (result.ok) return result;
2478
2544
  rollbackCstCapture(ctx, mark);
2479
2545
  if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
2546
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
2480
2547
  if (result.committed) return result;
2481
2548
  return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
2482
2549
  }
@@ -2917,18 +2984,37 @@ function createParseLineContext(input, pos) {
2917
2984
  }
2918
2985
  function parser(opts, root) {
2919
2986
  const clearTrivia = opts.trivia === null;
2987
+ const opaqueRootCapture = opts.rootCapture === "opaque";
2988
+ if (opaqueRootCapture && opts.trivia === void 0) {
2989
+ throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
2990
+ }
2920
2991
  return {
2921
2992
  _tag: "grammar",
2922
- _meta: root._meta,
2993
+ _meta: {
2994
+ ...root._meta,
2995
+ // Trivia classification describes this grammar's own active trivia
2996
+ // scope. A directly nested grammar may have classified trivia of its
2997
+ // own, but that must not advertise classification for this wrapper.
2998
+ triviaKindLabels: void 0,
2999
+ rootTriviaClassified: void 0,
3000
+ ...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
3001
+ ...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
3002
+ },
2923
3003
  _def: {
2924
3004
  tag: "grammar",
2925
3005
  parser: root,
2926
3006
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2927
3007
  clearTrivia,
3008
+ ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
2928
3009
  ...opts.captureTrivia ? { captureTrivia: true } : {},
2929
3010
  trackLines: opts.trackLines ?? false
2930
3011
  },
2931
3012
  parse(input, pos, _ctx) {
3013
+ if (_ctx?._rootTriviaStrictScopes && opts.trivia !== void 0 && opts.trivia !== null && !opts.trivia._meta.rootTriviaClassified && !opaqueRootCapture) {
3014
+ throw new TypeError(
3015
+ "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'."
3016
+ );
3017
+ }
2932
3018
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2933
3019
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2934
3020
  const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
@@ -2951,7 +3037,11 @@ function parser(opts, root) {
2951
3037
  // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2952
3038
  // trivia is inherited rather than re-declared here. No labels → undefined
2953
3039
  // (capture all).
2954
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3040
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {},
3041
+ // This is a property of the local trivia scope, not a post-parse filter:
3042
+ // nested recognition can still skip its trivia, but selected root rows
3043
+ // must never be written for an explicitly opaque region.
3044
+ ...opaqueRootCapture ? { _rootTriviaCapture: false } : {}
2955
3045
  };
2956
3046
  const result = root.parse(input, pos ?? 0, ctx);
2957
3047
  if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
@@ -3634,6 +3724,25 @@ function trivia(combinator) {
3634
3724
  parse: combinator.parse.bind(combinator)
3635
3725
  };
3636
3726
  }
3727
+ function classifiedTrivia(arms) {
3728
+ const entries = Object.entries(arms);
3729
+ if (entries.length === 0) {
3730
+ throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
3731
+ }
3732
+ for (let i = 0; i < entries.length; i++) {
3733
+ const [name, arm] = entries[i];
3734
+ const first = arm._meta.firstSet;
3735
+ if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
3736
+ throw new TypeError(
3737
+ `classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
3738
+ );
3739
+ }
3740
+ }
3741
+ const labeledArms = entries.map(([name, arm]) => label(name, arm));
3742
+ const result = trivia(oneOrMore(choice(...labeledArms)));
3743
+ result._meta.rootTriviaClassified = true;
3744
+ return result;
3745
+ }
3637
3746
  function label(name, combinator) {
3638
3747
  return {
3639
3748
  _tag: combinator._tag,
@@ -3680,6 +3789,7 @@ function token(root) {
3680
3789
  const savedRaw = ctx._cstRawChildren;
3681
3790
  const savedTriviaLog = ctx._cstTriviaLog;
3682
3791
  const savedOuterTriviaLog = ctx._triviaLog;
3792
+ const savedRootTriviaLog = ctx._rootTriviaLog;
3683
3793
  const wasCapturing = cstCaptureActive(ctx);
3684
3794
  ctx.trivia = void 0;
3685
3795
  ctx.triviaKindLabels = void 0;
@@ -3689,6 +3799,7 @@ function token(root) {
3689
3799
  ctx._cstRawChildren = void 0;
3690
3800
  ctx._cstTriviaLog = void 0;
3691
3801
  delete ctx._triviaLog;
3802
+ delete ctx._rootTriviaLog;
3692
3803
  let result;
3693
3804
  try {
3694
3805
  result = root.parse(input, pos, ctx);
@@ -3702,6 +3813,8 @@ function token(root) {
3702
3813
  ctx._cstTriviaLog = savedTriviaLog;
3703
3814
  if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
3704
3815
  else ctx._triviaLog = savedOuterTriviaLog;
3816
+ if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
3817
+ else ctx._rootTriviaLog = savedRootTriviaLog;
3705
3818
  }
3706
3819
  if (!result.ok) return result;
3707
3820
  const span = result.span;
@@ -3756,7 +3869,7 @@ function leaf(root, fn) {
3756
3869
  }
3757
3870
 
3758
3871
  // src/version.ts
3759
- var PARSEMAN_VERSION = "0.43.0";
3872
+ var PARSEMAN_VERSION = "0.44.0";
3760
3873
 
3761
3874
  // src/cst/host-mode.ts
3762
3875
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -5654,9 +5767,196 @@ function buildGrammarPlan(entry, winners) {
5654
5767
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
5655
5768
  }
5656
5769
 
5770
+ // src/cst/trivia-entries.ts
5771
+ var EMPTY_INDICES = Object.freeze([]);
5772
+ var EMPTY_GAPS = Object.freeze([]);
5773
+ var SELECTED_ROOT_STRIDE = 5;
5774
+ function entryOffset(i, stride) {
5775
+ return i * stride;
5776
+ }
5777
+ function triviaEntries(log, labels, opts) {
5778
+ const baseStride = opts?.nodeLog ? 3 : 2;
5779
+ const stride = labels ? baseStride + 1 : baseStride;
5780
+ const length = Math.floor(log.length / stride);
5781
+ return {
5782
+ length,
5783
+ labels,
5784
+ stride,
5785
+ start(i) {
5786
+ return log[entryOffset(i, stride)];
5787
+ },
5788
+ end(i) {
5789
+ return log[entryOffset(i, stride) + 1];
5790
+ },
5791
+ insertIndex(i) {
5792
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
5793
+ },
5794
+ kindIndex(i) {
5795
+ if (!labels) return void 0;
5796
+ return log[entryOffset(i, stride) + baseStride];
5797
+ },
5798
+ kind(i) {
5799
+ const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
5800
+ return ki !== void 0 ? labels[ki] : void 0;
5801
+ },
5802
+ text(i, input) {
5803
+ const s = log[entryOffset(i, stride)];
5804
+ const e = log[entryOffset(i, stride) + 1];
5805
+ return input.slice(s, e);
5806
+ }
5807
+ };
5808
+ }
5809
+ function buildRootTriviaIndex(log, labels) {
5810
+ const length = Math.floor(log.length / SELECTED_ROOT_STRIDE);
5811
+ const markerOffset = (i) => i * SELECTED_ROOT_STRIDE;
5812
+ const ownedRangeStart = (i) => log[markerOffset(i)];
5813
+ const ownedRangeEnd = (i) => log[markerOffset(i) + 1];
5814
+ const markerStart = (i) => log[markerOffset(i) + 2];
5815
+ const markerEnd = (i) => log[markerOffset(i) + 3];
5816
+ const markerKind = (i) => log[markerOffset(i) + 4];
5817
+ const entries = {
5818
+ length,
5819
+ labels,
5820
+ stride: SELECTED_ROOT_STRIDE,
5821
+ start: markerStart,
5822
+ end: markerEnd,
5823
+ insertIndex: () => void 0,
5824
+ kindIndex: markerKind,
5825
+ kind(i) {
5826
+ return labels[markerKind(i)];
5827
+ },
5828
+ text(i, input) {
5829
+ return input.slice(markerStart(i), markerEnd(i));
5830
+ }
5831
+ };
5832
+ const lowerBound = (offset, by) => {
5833
+ let lo = 0;
5834
+ let hi = length;
5835
+ while (lo < hi) {
5836
+ const mid = lo + hi >>> 1;
5837
+ if (by(mid) < offset) lo = mid + 1;
5838
+ else hi = mid;
5839
+ }
5840
+ return lo;
5841
+ };
5842
+ const gapRowsAt = (offset, direction) => {
5843
+ const edge = direction === "before" ? ownedRangeEnd : ownedRangeStart;
5844
+ let first = lowerBound(offset, edge);
5845
+ if (first === length || edge(first) !== offset) return void 0;
5846
+ const start = ownedRangeStart(first);
5847
+ const end = ownedRangeEnd(first);
5848
+ while (first > 0 && ownedRangeStart(first - 1) === start && ownedRangeEnd(first - 1) === end) first--;
5849
+ let last = first + 1;
5850
+ while (last < length && ownedRangeStart(last) === start && ownedRangeEnd(last) === end) last++;
5851
+ return [first, last];
5852
+ };
5853
+ const indices = (first, last) => {
5854
+ const out = [];
5855
+ for (let i = first; i < last; i++) out.push(i);
5856
+ return out;
5857
+ };
5858
+ const makeGap = (first, last) => {
5859
+ const start = ownedRangeStart(first);
5860
+ const end = ownedRangeEnd(first);
5861
+ let entryIndices;
5862
+ return {
5863
+ start,
5864
+ end,
5865
+ get entryIndices() {
5866
+ return entryIndices ??= indices(first, last);
5867
+ },
5868
+ hasKind(kind) {
5869
+ for (let i = first; i < last; i++) {
5870
+ if (labels[markerKind(i)] === kind) return true;
5871
+ }
5872
+ return false;
5873
+ },
5874
+ text(input) {
5875
+ return input.slice(start, end);
5876
+ }
5877
+ };
5878
+ };
5879
+ let maps;
5880
+ const getMaps = () => {
5881
+ if (maps !== void 0) return maps;
5882
+ const before = /* @__PURE__ */ new Map();
5883
+ const after = /* @__PURE__ */ new Map();
5884
+ const beforeGaps = /* @__PURE__ */ new Map();
5885
+ const afterGaps = /* @__PURE__ */ new Map();
5886
+ const gaps = [];
5887
+ for (let first = 0; first < length; ) {
5888
+ let last = first + 1;
5889
+ while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
5890
+ const gap = makeGap(first, last);
5891
+ gaps.push(gap);
5892
+ afterGaps.set(gap.start, gap);
5893
+ beforeGaps.set(gap.end, gap);
5894
+ after.set(gap.start, [...gap.entryIndices]);
5895
+ before.set(gap.end, [...gap.entryIndices]);
5896
+ first = last;
5897
+ }
5898
+ maps = { before, after, beforeGaps, afterGaps, gaps };
5899
+ return maps;
5900
+ };
5901
+ return {
5902
+ entries,
5903
+ labels,
5904
+ get before() {
5905
+ return getMaps().before;
5906
+ },
5907
+ get after() {
5908
+ return getMaps().after;
5909
+ },
5910
+ entryIndicesBefore(offset) {
5911
+ const rows = gapRowsAt(offset, "before");
5912
+ return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
5913
+ },
5914
+ entryIndicesAfter(offset) {
5915
+ const rows = gapRowsAt(offset, "after");
5916
+ return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
5917
+ },
5918
+ gapBefore(offset) {
5919
+ const rows = gapRowsAt(offset, "before");
5920
+ return rows ? makeGap(rows[0], rows[1]) : void 0;
5921
+ },
5922
+ gapAfter(offset) {
5923
+ const rows = gapRowsAt(offset, "after");
5924
+ return rows ? makeGap(rows[0], rows[1]) : void 0;
5925
+ },
5926
+ gaps() {
5927
+ return getMaps().gaps;
5928
+ },
5929
+ gapsWithKind(kind) {
5930
+ const kinds = typeof kind === "string" ? [kind] : kind;
5931
+ const matches2 = [];
5932
+ for (let first = 0; first < length; ) {
5933
+ let last = first + 1;
5934
+ while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
5935
+ let matched = false;
5936
+ for (let i = first; i < last && !matched; i++) {
5937
+ const label2 = labels[markerKind(i)];
5938
+ for (const kind2 of kinds) {
5939
+ if (label2 === kind2) {
5940
+ matched = true;
5941
+ break;
5942
+ }
5943
+ }
5944
+ }
5945
+ if (matched) matches2.push(makeGap(first, last));
5946
+ first = last;
5947
+ }
5948
+ return matches2.length === 0 ? EMPTY_GAPS : matches2;
5949
+ }
5950
+ };
5951
+ }
5952
+
5657
5953
  // src/compiler/scannable-run.ts
5658
5954
  var BACKSLASH = 92;
5659
5955
  var META = new Set("()[]{}*+?|^$.".split(""));
5956
+ var SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER = Array.from(
5957
+ { length: SELECTED_ROOT_STRIDE - 3 },
5958
+ () => "0"
5959
+ ).join(", ");
5660
5960
  function classToRanges(cls) {
5661
5961
  if (cls === "\\d") return shorthandRanges("d");
5662
5962
  if (cls === "\\w") return shorthandRanges("w");
@@ -6695,13 +6995,15 @@ function scanBranch(shape, mint) {
6695
6995
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6696
6996
  return [...m.setup, ` if (${m.end} > _e) { _e = ${m.end}; continue }`].join("\n");
6697
6997
  }
6698
- function scanBranchLabeled(shape, kindIndex, mint) {
6998
+ function scanBranchLabeled(shape, kindIndex, label2, mint) {
6699
6999
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6700
7000
  return [
6701
7001
  ...m.setup,
6702
7002
  ` if (${m.end} > _e) {`,
6703
7003
  ` if (_cap) {`,
6704
7004
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
7005
+ ` const _rk = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(label2)}] ?? -1)`,
7006
+ ` if (_rk >= 0) _ctx._rootTriviaLog.push(${SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER}, _e, ${m.end}, _rk)`,
6705
7007
  ` 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})`,
6706
7008
  ` }`,
6707
7009
  ` _e = ${m.end}`,
@@ -6761,6 +7063,11 @@ var CAP_RECORD = [
6761
7063
  ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6762
7064
  ` }`
6763
7065
  ].join("\n");
7066
+ var SELECTED_ROOT_FINISH = [
7067
+ ` if (_cap && _ctx._rootTriviaCapture !== false && _ctx._rootTriviaLog !== undefined && _ctx._rootTriviaLog.length !== _rootMark) {`,
7068
+ ` for (let _ri = _rootMark; _ri < _ctx._rootTriviaLog.length; _ri += ${SELECTED_ROOT_STRIDE}) { _ctx._rootTriviaLog[_ri] = _pos; _ctx._rootTriviaLog[_ri + 1] = _e }`,
7069
+ ` }`
7070
+ ].join("\n");
6764
7071
  function composeFastLoop(shapes) {
6765
7072
  const mint = makeMint();
6766
7073
  return [
@@ -6789,7 +7096,7 @@ function analyzeLabeledScannableRun(trivia2) {
6789
7096
  const d = getCoreRegexDef(arm.parser);
6790
7097
  const shape = d ? scanShapeFromRegex(d.source, d.flags) : null;
6791
7098
  if (!shape) return null;
6792
- out.push({ shape, kindIndex: arm.kindIndex });
7099
+ out.push({ shape, kindIndex: arm.kindIndex, label: arm.label });
6793
7100
  }
6794
7101
  return out;
6795
7102
  }
@@ -6798,11 +7105,13 @@ function buildLabeledScannableTriviaFnDecl(fnName, arms) {
6798
7105
  return [
6799
7106
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6800
7107
  ` let _e = _pos`,
7108
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6801
7109
  ` while (_e < input.length) {`,
6802
7110
  ` const c = input.charCodeAt(_e)`,
6803
- ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, mint)),
7111
+ ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, a.label, mint)),
6804
7112
  ` break`,
6805
7113
  ` }`,
7114
+ SELECTED_ROOT_FINISH,
6806
7115
  ` return _e`,
6807
7116
  `}`
6808
7117
  ].join("\n");
@@ -6818,6 +7127,8 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6818
7127
  ` const _ce = _e + _m${i}[0].length`,
6819
7128
  ` if (_cap) {`,
6820
7129
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
7130
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
7131
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6821
7132
  ` 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})`,
6822
7133
  ` }`,
6823
7134
  ` _e = _ce`,
@@ -6829,11 +7140,13 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6829
7140
  return [
6830
7141
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6831
7142
  ` let _e = _pos`,
7143
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6832
7144
  ` while (_e < input.length) {`,
6833
7145
  ` let _matched = false`,
6834
7146
  tryArms,
6835
7147
  ` if (!_matched) break`,
6836
7148
  ` }`,
7149
+ SELECTED_ROOT_FINISH,
6837
7150
  ` return _e`,
6838
7151
  `}`
6839
7152
  ].join("\n");
@@ -6856,6 +7169,8 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6856
7169
  ` const _ce = _r${i}.span.end`,
6857
7170
  ` if (_cap) {`,
6858
7171
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
7172
+ ` const _rk${i} = _ctx._rootTriviaCapture === false || _ctx._rootTriviaLog === undefined ? -1 : (_ctx._rootTriviaKindIndex?.[${JSON.stringify(arm.label)}] ?? -1)`,
7173
+ ` if (_rk${i} >= 0) _ctx._rootTriviaLog.push(0, 0, _e, _ce, _rk${i})`,
6859
7174
  ` 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})`,
6860
7175
  ` }`,
6861
7176
  ` _e = _ce`,
@@ -6867,11 +7182,13 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6867
7182
  return [
6868
7183
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6869
7184
  ` let _e = _pos`,
7185
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6870
7186
  ` while (_e < input.length) {`,
6871
7187
  ` let _matched = false`,
6872
7188
  tryArms,
6873
7189
  ` if (!_matched) break`,
6874
7190
  ` }`,
7191
+ SELECTED_ROOT_FINISH,
6875
7192
  ` return _e`,
6876
7193
  `}`
6877
7194
  ].join("\n");
@@ -7094,6 +7411,9 @@ var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) retur
7094
7411
  var LINE_TRACK_DECL = "const _trackLines = (_ctx, input, start, end) => { const from = _ctx._lineScannedTo ?? 0; if (end <= from) return; for (let i = from; i < end; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1); _ctx._lineScannedTo = end }";
7095
7412
  var LINE_SPAN_DECL = "const _lineCol = (_ctx, offset) => { const starts = _ctx._lineStarts; let lo = 0, hi = starts.length - 1; while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (starts[mid] <= offset) lo = mid; else hi = mid - 1 } return [lo + 1, offset - starts[lo] + 1] }\nconst _spanLines = (_ctx, start, end) => { const s = _lineCol(_ctx, start), e = _lineCol(_ctx, end); return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] } }";
7096
7413
  var _loweringSink = null;
7414
+ function hasSelectedRootTrivia(ctx) {
7415
+ return ctx.rootTriviaClassified === true;
7416
+ }
7097
7417
  function v(ctx, prefix = "_v") {
7098
7418
  return `${prefix}${ctx.vars++}`;
7099
7419
  }
@@ -7403,10 +7723,12 @@ function planDisjointDispatch(parsers) {
7403
7723
  }
7404
7724
  return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
7405
7725
  }
7406
- function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
7726
+ function captureRestoreBody(ctx, mL, mR, mTl, mLg, mF = null, mRootLg = null) {
7407
7727
  const fieldRestore = mF ? `; if (_ctx._fields && _ctx._fields.length !== ${mF}) _ctx._fields.length = ${mF}` : "";
7408
7728
  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}`;
7409
- return mLg ? `${base}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : base;
7729
+ const logRestore = mLg ? `; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${mLg}) _ctx._triviaLog.length = ${mLg}` : "";
7730
+ const rootLogRestore = hasSelectedRootTrivia(ctx) && mRootLg ? `; if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${mRootLg}) _ctx._rootTriviaLog.length = ${mRootLg}` : "";
7731
+ return `${base}${logRestore}${rootLogRestore}`;
7410
7732
  }
7411
7733
  function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
7412
7734
  if (seen.has(p)) return false;
@@ -7616,7 +7938,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
7616
7938
  `${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
7617
7939
  `${ind0}}`,
7618
7940
  ...mL ? [
7619
- `${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
7941
+ `${ind0}if (!${okV}) { ${captureRestoreBody(ctx, mL, mR, mTl, null, mF)} }`
7620
7942
  ] : []
7621
7943
  ];
7622
7944
  return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
@@ -7813,11 +8135,13 @@ function emitSeqValues(def, ctx, pos) {
7813
8135
  const markV = v(ctx, "_mk");
7814
8136
  const markTl = v(ctx, "_mktl");
7815
8137
  const markLog = v(ctx, "_mklg");
8138
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7816
8139
  const scanEndV = v(ctx, "_sne");
7817
8140
  stmts.push(
7818
8141
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7819
8142
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7820
8143
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8144
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7821
8145
  `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7822
8146
  ...emitLineTrack(ctx, curV, scanEndV)
7823
8147
  );
@@ -7826,17 +8150,19 @@ function emitSeqValues(def, ctx, pos) {
7826
8150
  const endAfterV = v(ctx, "_sea");
7827
8151
  stmts.push(
7828
8152
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7829
- `${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}; }`
8153
+ `${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};` : ""} }`
7830
8154
  );
7831
8155
  valueVars.push(r2.valueVar);
7832
8156
  continue;
7833
8157
  } else {
7834
8158
  const trivFn = ensureTriviaFn(ctx);
7835
8159
  const markLog = v(ctx, "_mklg");
8160
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7836
8161
  const scanEndV = v(ctx, "_sne");
7837
- const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
8162
+ const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? "(_ctx._triviaLog !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7838
8163
  stmts.push(
7839
8164
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8165
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7840
8166
  `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7841
8167
  ...emitLineTrack(ctx, curV, scanEndV)
7842
8168
  );
@@ -7845,7 +8171,7 @@ function emitSeqValues(def, ctx, pos) {
7845
8171
  const endAfterV = v(ctx, "_sea");
7846
8172
  stmts.push(
7847
8173
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7848
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
8174
+ `${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};` : ""} }`
7849
8175
  );
7850
8176
  valueVars.push(r2.valueVar);
7851
8177
  continue;
@@ -8087,6 +8413,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8087
8413
  const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
8088
8414
  const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
8089
8415
  const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
8416
+ const selectorRootLogMark = selectorNeedsRollback && hasSelectedRootTrivia(ctx) ? v(ctx, "_dsrg") : null;
8090
8417
  const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
8091
8418
  const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
8092
8419
  const selector = emit(def.selector, ctx, pos);
@@ -8099,6 +8426,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8099
8426
  `${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
8100
8427
  `${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
8101
8428
  `${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
8429
+ ...selectorRootLogMark ? [`${ind(ctx)}const ${selectorRootLogMark} = _ctx._rootTriviaLog?.length ?? 0`] : [],
8102
8430
  `${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
8103
8431
  `${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
8104
8432
  ] : [],
@@ -8118,16 +8446,18 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8118
8446
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
8119
8447
  const errMark = mayError ? v(ctx, "_derr") : null;
8120
8448
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
8449
+ const rootLogMark = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_drlog") : null;
8121
8450
  if (usesRouted) {
8122
8451
  stmts.push(
8123
8452
  ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
8124
8453
  ...selectorLeafMark ? [
8125
- `${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}`
8454
+ `${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}`
8126
8455
  ] : []
8127
8456
  );
8128
8457
  }
8129
8458
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
8130
8459
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
8460
+ if (rootLogMark) stmts.push(`${ind(ctx)}const ${rootLogMark} = _ctx._rootTriviaLog?.length ?? 0`);
8131
8461
  const savedRoutedLocal = ctx.routedLocal;
8132
8462
  const savedNoHoist = ctx.noHoist;
8133
8463
  if (usesRouted && !needsRoutedContext) {
@@ -8142,11 +8472,12 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8142
8472
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
8143
8473
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
8144
8474
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
8475
+ const rootLogRollback = rootLogMark ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${rootLogMark}) _ctx._rootTriviaLog.length = ${rootLogMark}; ` : "";
8145
8476
  const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
8146
8477
  const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
8147
8478
  stmts.push(
8148
8479
  ...tail.stmts,
8149
- `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8480
+ `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${rootLogRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8150
8481
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
8151
8482
  `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
8152
8483
  `${ind(ctx)}${outE} = ${tail.endVar}`,
@@ -8327,11 +8658,13 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8327
8658
  const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
8328
8659
  const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
8329
8660
  const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
8661
+ const markRootLog = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_cmlrg") : null;
8330
8662
  const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
8331
8663
  const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
8332
- const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
8664
+ const captureRollback = markLeaves ? captureRestoreBody(ctx, markLeaves, markRaw, markTl, markLog, markFields, markRootLog) : "";
8665
+ const rootRollback = markRootLog && !markLeaves ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}` : "";
8333
8666
  const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
8334
- const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
8667
+ const rollback = [captureRollback, rootRollback, errorRollback].filter(Boolean).join("; ");
8335
8668
  const failSlot = atStart ? staticFx : "_ctx._fx";
8336
8669
  stmts.push(`${ind0}if (${skipCond}) {`);
8337
8670
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
@@ -8346,6 +8679,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8346
8679
  ...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
8347
8680
  );
8348
8681
  }
8682
+ if (markRootLog) stmts.push(`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog?.length ?? 0`);
8349
8683
  if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
8350
8684
  const arm = emitFallible(p, ctx, pos, atStart);
8351
8685
  const { stmts: armStmts, okVar, valVar, endVar } = arm;
@@ -8533,21 +8867,29 @@ function emitMany(def, ctx, pos) {
8533
8867
  const markV = v(ctx, "_mk");
8534
8868
  const markTl = v(ctx, "_mktl");
8535
8869
  const markLog = v(ctx, "_mklg");
8870
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8536
8871
  const npV = v(ctx, "_np");
8537
8872
  stmts.push(
8538
8873
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8539
8874
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8540
8875
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8876
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8541
8877
  `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8542
8878
  ...emitLineTrack(ctx, curV, npV)
8543
8879
  );
8544
8880
  itemPos = npV;
8545
- 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}; `;
8881
+ 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};` : ""} `;
8546
8882
  } else {
8547
8883
  const trivFn = ensureTriviaFn(ctx);
8884
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8548
8885
  const npV = v(ctx, "_np");
8549
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, npV));
8886
+ stmts.push(
8887
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8888
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
8889
+ ...emitLineTrack(ctx, curV, npV)
8890
+ );
8550
8891
  itemPos = npV;
8892
+ rollback = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8551
8893
  }
8552
8894
  }
8553
8895
  if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
@@ -8607,9 +8949,10 @@ function emitAttempt(p, def, ctx, pos) {
8607
8949
  const raw = v(ctx, "_atr");
8608
8950
  const trivia2 = v(ctx, "_att");
8609
8951
  const log = v(ctx, "_atg");
8952
+ const rootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_atrg") : null;
8610
8953
  const fields = v(ctx, "_atf");
8611
8954
  const errors = v(ctx, "_ate");
8612
- 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}`;
8955
+ 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}`;
8613
8956
  const traceId = ctx.coverage?.plan.attempts.get(p);
8614
8957
  const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
8615
8958
  const preGuard = [];
@@ -8625,7 +8968,7 @@ function emitAttempt(p, def, ctx, pos) {
8625
8968
  return {
8626
8969
  stmts: [
8627
8970
  ...preGuard,
8628
- `${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`,
8971
+ `${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`,
8629
8972
  ...inner.stmts,
8630
8973
  ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
8631
8974
  ],
@@ -8667,16 +9010,17 @@ function emitSepBy(_p, def, ctx, pos) {
8667
9010
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8668
9011
  const postSepMarks = () => {
8669
9012
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8670
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
9013
+ 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");
8671
9014
  return {
8672
9015
  decl: [
8673
9016
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8674
9017
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8675
9018
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8676
9019
  `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
9020
+ ...rlg ? [`${ind(ctx)}const ${rlg} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8677
9021
  `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8678
9022
  ],
8679
- 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}; `
9023
+ 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}; `
8680
9024
  };
8681
9025
  };
8682
9026
  if (rec) {
@@ -8714,6 +9058,7 @@ function emitSepBy(_p, def, ctx, pos) {
8714
9058
  const markV = v(ctx, "_mk");
8715
9059
  const markTl = v(ctx, "_mktl");
8716
9060
  const markLog = v(ctx, "_mklg");
9061
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8717
9062
  const markLv = v(ctx, "_mklv");
8718
9063
  const markFld = v(ctx, "_mkf");
8719
9064
  const spV = v(ctx, "_sp");
@@ -8721,13 +9066,14 @@ function emitSepBy(_p, def, ctx, pos) {
8721
9066
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8722
9067
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8723
9068
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
9069
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8724
9070
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8725
9071
  `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8726
9072
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8727
9073
  ...emitLineTrack(ctx, curV, spV)
8728
9074
  );
8729
9075
  sepAtPos = spV;
8730
- 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}; `;
9076
+ 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}; `;
8731
9077
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8732
9078
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8733
9079
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8745,19 +9091,30 @@ function emitSepBy(_p, def, ctx, pos) {
8745
9091
  );
8746
9092
  } else {
8747
9093
  const trivFn = ensureTriviaFn(ctx);
9094
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8748
9095
  const spV = v(ctx, "_sp");
8749
- stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`, ...emitLineTrack(ctx, curV, spV));
9096
+ stmts.push(
9097
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
9098
+ `${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
9099
+ ...emitLineTrack(ctx, curV, spV)
9100
+ );
8750
9101
  sepAtPos = spV;
8751
9102
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8752
9103
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8753
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
9104
+ const rollbackToSep = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
9105
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
9106
+ const postRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_psrlg") : null;
8754
9107
  const npV = v(ctx, "_np");
8755
- stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`, ...emitLineTrack(ctx, sepEnd, npV));
9108
+ stmts.push(
9109
+ ...postRootLog ? [`${ind(ctx)}const ${postRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
9110
+ `${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx, ${hasSelectedRootTrivia(ctx) ? "_ctx._rootTriviaLog !== undefined ? 2 : 0" : "0"})`,
9111
+ ...emitLineTrack(ctx, sepEnd, npV)
9112
+ );
8756
9113
  const next = emitFallible(def.parser, ctx, npV, true);
8757
9114
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8758
9115
  stmts.push(
8759
9116
  ...nextStmts,
8760
- ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
9117
+ ...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, postRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${postRootLog}) _ctx._rootTriviaLog.length = ${postRootLog}; ` : "")),
8761
9118
  `${ind(ctx)}${arrV}.push(${nextVal})`,
8762
9119
  `${ind(ctx)}${curV} = ${nextEnd}`
8763
9120
  );
@@ -8852,6 +9209,7 @@ function emitNot(def, ctx, pos) {
8852
9209
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8853
9210
  const tl = sinksLive ? v(ctx, "_ntt") : null;
8854
9211
  const log = sinksLive ? v(ctx, "_ntg") : null;
9212
+ const rootLog = sinksLive && hasSelectedRootTrivia(ctx) ? v(ctx, "_ntrg") : null;
8855
9213
  const fields = sinksLive ? v(ctx, "_ntf") : null;
8856
9214
  const errors = sinksLive ? v(ctx, "_nte") : null;
8857
9215
  const { stmts, okVar } = emitFallible(def.parser, ctx, pos, true);
@@ -8859,11 +9217,11 @@ function emitNot(def, ctx, pos) {
8859
9217
  return {
8860
9218
  stmts: [
8861
9219
  ...sinksLive ? [
8862
- `${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`
9220
+ `${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`
8863
9221
  ] : [],
8864
9222
  ...stmts,
8865
9223
  ...sinksLive ? [
8866
- `${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}`
9224
+ `${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}`
8867
9225
  ] : [],
8868
9226
  ...emitIfFail(ctx, okVar, failBody(ctx, label2, pos))
8869
9227
  ],
@@ -8999,16 +9357,17 @@ function emitToken(def, ctx, pos) {
8999
9357
  const sk = v(ctx, "_tokKinds");
9000
9358
  const stl = v(ctx, "_tokTl");
9001
9359
  const sol = v(ctx, "_tokLog");
9360
+ const srl = hasSelectedRootTrivia(ctx) ? v(ctx, "_tokRootLog") : null;
9002
9361
  const sb = v(ctx, "_tokBuf");
9003
9362
  const valV = v(ctx, "_tok");
9004
9363
  return {
9005
9364
  stmts: [
9006
- `${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`,
9007
- `${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`,
9365
+ `${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`,
9366
+ `${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`,
9008
9367
  `${i}try {`,
9009
9368
  ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
9010
9369
  `${i}} finally {`,
9011
- `${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}`,
9370
+ `${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}`,
9012
9371
  `${i}}`,
9013
9372
  ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
9014
9373
  `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
@@ -9487,6 +9846,8 @@ function emitDispatch(p, ctx, pos) {
9487
9846
  case "grammar": {
9488
9847
  const savedTrivia = ctx.activeTrivia;
9489
9848
  const savedKindLabels = ctx.triviaKindLabels;
9849
+ const opaqueRootCapture = hasSelectedRootTrivia(ctx) && def.rootCapture === "opaque";
9850
+ 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;
9490
9851
  if (def.clearTrivia) {
9491
9852
  ctx.activeTrivia = void 0;
9492
9853
  ctx.triviaKindLabels = void 0;
@@ -9497,13 +9858,38 @@ function emitDispatch(p, ctx, pos) {
9497
9858
  }
9498
9859
  }
9499
9860
  const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
9861
+ const savedRootCapture = opaqueRootCapture ? v(ctx, "_grtc") : null;
9862
+ const opaqueValue = opaqueRootCapture ? v(ctx, "_grtv") : null;
9863
+ const opaqueEnd = opaqueRootCapture ? v(ctx, "_grte") : null;
9864
+ if (opaqueRootCapture) ctx.indent++;
9500
9865
  const r = emit(def.parser, ctx, pos);
9866
+ if (opaqueRootCapture) ctx.indent--;
9501
9867
  ctx.activeTrivia = savedTrivia;
9502
9868
  ctx.triviaKindLabels = savedKindLabels;
9503
- if (!savedCapture) return r;
9869
+ if (!savedCapture && !opaqueRootCapture) return strictScopeCheck === void 0 ? r : {
9870
+ ...r,
9871
+ stmts: [strictScopeCheck, ...r.stmts]
9872
+ };
9873
+ if (opaqueRootCapture) {
9874
+ return {
9875
+ stmts: [
9876
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9877
+ `${ind(ctx)}let ${opaqueValue}, ${opaqueEnd}`,
9878
+ `${ind(ctx)}${savedCapture ? `const ${savedCapture} = _ctx.captureTrivia; ` : ""}const ${savedRootCapture} = _ctx._rootTriviaCapture; _ctx._rootTriviaCapture = false`,
9879
+ `${ind(ctx)}try {`,
9880
+ ...savedCapture ? [`${ind(ctx)} _ctx.captureTrivia = true`] : [],
9881
+ ...r.stmts,
9882
+ `${ind(ctx)} ${opaqueValue} = ${r.valueVar}; ${opaqueEnd} = ${r.endVar}`,
9883
+ `${ind(ctx)}} finally { ${savedCapture ? `_ctx.captureTrivia = ${savedCapture}; ` : ""}_ctx._rootTriviaCapture = ${savedRootCapture} }`
9884
+ ],
9885
+ valueVar: opaqueValue,
9886
+ endVar: opaqueEnd
9887
+ };
9888
+ }
9504
9889
  return {
9505
9890
  ...r,
9506
9891
  stmts: [
9892
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9507
9893
  `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
9508
9894
  ...r.stmts,
9509
9895
  `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
@@ -9988,6 +10374,7 @@ function compile(combinator, mapFnSources, opts) {
9988
10374
  runDuplicationDiagnostic(combinator, opts?.duplication);
9989
10375
  markUnusedValues(combinator);
9990
10376
  const grammarTrivia = combinator._meta.grammarTrivia;
10377
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || combinator._meta.rootTriviaClassified === true;
9991
10378
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9992
10379
  const grammarHostMode = combinator._meta.grammarHostMode;
9993
10380
  const grammarTrackLines = combinator._meta.grammarTrackLines;
@@ -10014,7 +10401,11 @@ function compile(combinator, mapFnSources, opts) {
10014
10401
  lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
10015
10402
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
10016
10403
  lazyUsage: analyzeLazyUsage(combinator),
10017
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10404
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10405
+ ...grammarTrivia ? {
10406
+ activeTrivia: grammarTrivia,
10407
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10408
+ } : {},
10018
10409
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10019
10410
  };
10020
10411
  const r = emit(combinator, ctx, "_pos");
@@ -10162,10 +10553,11 @@ function assertRuleName(name) {
10162
10553
  );
10163
10554
  }
10164
10555
  }
10165
- function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
10166
- const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
10167
- if (labels === void 0) return fnSource;
10168
- return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
10556
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambientRootTriviaClassified) {
10557
+ const labels = ambientTriviaKindLabels ?? rule._meta.triviaKindLabels;
10558
+ const classified = ambientRootTriviaClassified ?? rule._meta.rootTriviaClassified;
10559
+ if (labels === void 0 && classified === void 0) return fnSource;
10560
+ return `Object.assign(${fnSource}, { _meta: {${labels === void 0 ? "" : ` triviaKindLabels: ${JSON.stringify(labels)},`}${classified === void 0 ? "" : " rootTriviaClassified: true,"} } })`;
10169
10561
  }
10170
10562
  function compileLinkable(ruleMapArg, ns, opts) {
10171
10563
  if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
@@ -10173,6 +10565,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10173
10565
  if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
10174
10566
  for (const [, rule] of ruleMapArg) markUnusedValues(rule);
10175
10567
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
10568
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || ruleMapArg.some(([, rule]) => rule._meta.rootTriviaClassified === true);
10176
10569
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10177
10570
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10178
10571
  const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10216,7 +10609,11 @@ function compileLinkable(ruleMapArg, ns, opts) {
10216
10609
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10217
10610
  ns,
10218
10611
  deferFirstSetRefs: true,
10219
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10612
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10613
+ ...grammarTrivia ? {
10614
+ activeTrivia: grammarTrivia,
10615
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10616
+ } : {},
10220
10617
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10221
10618
  };
10222
10619
  const seen = /* @__PURE__ */ new Map();
@@ -10348,7 +10745,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10348
10745
  ...r.stmts,
10349
10746
  ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10350
10747
  `}`
10351
- ].join("\n"), ctx.triviaKindLabels));
10748
+ ].join("\n"), ctx.triviaKindLabels, ctx.rootTriviaClassified));
10352
10749
  }
10353
10750
  const firstSets = /* @__PURE__ */ new Map();
10354
10751
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10697,6 +11094,7 @@ function evalRuleMapIR(ir) {
10697
11094
  "transform",
10698
11095
  "skip",
10699
11096
  "trivia",
11097
+ "classifiedTrivia",
10700
11098
  "label",
10701
11099
  "field",
10702
11100
  "expect",
@@ -10737,6 +11135,7 @@ function evalRuleMapIR(ir) {
10737
11135
  transform,
10738
11136
  skip,
10739
11137
  trivia,
11138
+ classifiedTrivia,
10740
11139
  label,
10741
11140
  field,
10742
11141
  expect,
@@ -10983,8 +11382,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10983
11382
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
10984
11383
  }
10985
11384
  case "grammar": {
10986
- const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
10987
- return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
11385
+ const classified = def.triviaParser?._meta.rootTriviaClassified === true;
11386
+ const spec = classified && def.triviaParser ? analyzeLabeledTrivia(def.triviaParser) : null;
11387
+ if (classified && !spec) throw new Unserializable("classified trivia without labeled arms");
11388
+ 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";
11389
+ return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.rootCapture ? `, rootCapture: ${JSON.stringify(def.rootCapture)}` : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
10988
11390
  }
10989
11391
  case "withCtx": {
10990
11392
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -11881,157 +12283,26 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11881
12283
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11882
12284
  }
11883
12285
 
11884
- // src/cst/trivia-entries.ts
11885
- var EMPTY_INDICES = Object.freeze([]);
11886
- var EMPTY_GAPS = Object.freeze([]);
11887
- function entryOffset(i, stride) {
11888
- return i * stride;
11889
- }
11890
- function triviaEntries(log, labels, opts) {
11891
- const baseStride = opts?.nodeLog ? 3 : 2;
11892
- const stride = labels ? baseStride + 1 : baseStride;
11893
- const length = Math.floor(log.length / stride);
11894
- return {
11895
- length,
11896
- labels,
11897
- stride,
11898
- start(i) {
11899
- return log[entryOffset(i, stride)];
11900
- },
11901
- end(i) {
11902
- return log[entryOffset(i, stride) + 1];
11903
- },
11904
- insertIndex(i) {
11905
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11906
- },
11907
- kindIndex(i) {
11908
- if (!labels) return void 0;
11909
- return log[entryOffset(i, stride) + baseStride];
11910
- },
11911
- kind(i) {
11912
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11913
- return ki !== void 0 ? labels[ki] : void 0;
11914
- },
11915
- text(i, input) {
11916
- const s = log[entryOffset(i, stride)];
11917
- const e = log[entryOffset(i, stride) + 1];
11918
- return input.slice(s, e);
11919
- }
11920
- };
11921
- }
11922
- function appendEntryRange(map, key, first, last) {
11923
- let indices = map.get(key);
11924
- if (!indices) {
11925
- indices = [];
11926
- map.set(key, indices);
11927
- }
11928
- for (let i = first; i <= last; i++) indices.push(i);
11929
- }
11930
- function buildGap(entries, start, end, first, last) {
11931
- const entryIndices = [];
11932
- for (let i = first; i <= last; i++) entryIndices.push(i);
11933
- return {
11934
- start,
11935
- end,
11936
- entryIndices,
11937
- hasKind(kind) {
11938
- for (const i of entryIndices) {
11939
- if (entries.kind(i) === kind) return true;
11940
- }
11941
- return false;
11942
- },
11943
- text(input) {
11944
- return input.slice(start, end);
11945
- }
11946
- };
11947
- }
11948
- function buildRootMaps(entries) {
11949
- const before = /* @__PURE__ */ new Map();
11950
- const after = /* @__PURE__ */ new Map();
11951
- const beforeGaps = /* @__PURE__ */ new Map();
11952
- const afterGaps = /* @__PURE__ */ new Map();
11953
- const gaps = [];
11954
- if (entries.length === 0) return { before, after, beforeGaps, afterGaps, gaps };
11955
- const appendGap = (first2, last, start2, end2) => {
11956
- const gap = buildGap(entries, start2, end2, first2, last);
11957
- gaps.push(gap);
11958
- afterGaps.set(start2, gap);
11959
- beforeGaps.set(end2, gap);
11960
- appendEntryRange(after, start2, first2, last);
11961
- appendEntryRange(before, end2, first2, last);
11962
- };
11963
- let first = 0;
11964
- let start = entries.start(0);
11965
- let end = entries.end(0);
11966
- for (let i = 1; i < entries.length; i++) {
11967
- const nextStart = entries.start(i);
11968
- const nextEnd = entries.end(i);
11969
- if (nextStart === end) {
11970
- end = nextEnd;
11971
- continue;
11972
- }
11973
- appendGap(first, i - 1, start, end);
11974
- first = i;
11975
- start = nextStart;
11976
- end = nextEnd;
11977
- }
11978
- appendGap(first, entries.length - 1, start, end);
11979
- return { before, after, beforeGaps, afterGaps, gaps };
11980
- }
11981
- function buildRootTriviaIndex(log, labels) {
11982
- const entries = triviaEntries(log, labels);
11983
- let maps;
11984
- const getMaps = () => {
11985
- maps ??= buildRootMaps(entries);
11986
- return maps;
11987
- };
11988
- return {
11989
- entries,
11990
- labels,
11991
- get before() {
11992
- return getMaps().before;
11993
- },
11994
- get after() {
11995
- return getMaps().after;
11996
- },
11997
- entryIndicesBefore(offset) {
11998
- return getMaps().before.get(offset) ?? EMPTY_INDICES;
11999
- },
12000
- entryIndicesAfter(offset) {
12001
- return getMaps().after.get(offset) ?? EMPTY_INDICES;
12002
- },
12003
- gapBefore(offset) {
12004
- return getMaps().beforeGaps.get(offset);
12005
- },
12006
- gapAfter(offset) {
12007
- return getMaps().afterGaps.get(offset);
12008
- },
12009
- gaps() {
12010
- return getMaps().gaps;
12011
- },
12012
- gapsWithKind(kind) {
12013
- const kinds = typeof kind === "string" ? [kind] : kind;
12014
- const matches2 = [];
12015
- for (const gap of getMaps().gaps) {
12016
- for (const k of kinds) {
12017
- if (gap.hasKind(k)) {
12018
- matches2.push(gap);
12019
- break;
12020
- }
12021
- }
12022
- }
12023
- return matches2.length === 0 ? EMPTY_GAPS : matches2;
12024
- }
12025
- };
12026
- }
12027
-
12028
12286
  // src/functional/run.ts
12029
12287
  var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
12030
12288
  function triviaKindLabelsFromRunnable(r) {
12031
12289
  if (!r) return void 0;
12032
12290
  if (typeof r === "function") return r._meta?.triviaKindLabels;
12033
12291
  const grammarTrivia = r._meta.grammarTrivia;
12034
- return r._meta.triviaKindLabels ?? grammarTrivia?._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
12292
+ return grammarTrivia?._meta.triviaKindLabels ?? r._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
12293
+ }
12294
+ function rootTriviaClassifiedFromRunnable(r) {
12295
+ if (!r) return false;
12296
+ if (typeof r === "function") return r._meta?.rootTriviaClassified === true;
12297
+ const grammarTrivia = r._meta.grammarTrivia;
12298
+ return grammarTrivia?._meta.rootTriviaClassified === true || r._meta.rootTriviaClassified === true;
12299
+ }
12300
+ function makeSelectedRootLabelIndex(labels) {
12301
+ const index = /* @__PURE__ */ Object.create(null);
12302
+ for (let i = 0; i < labels.length; i++) {
12303
+ if (index[labels[i]] === void 0) index[labels[i]] = i;
12304
+ }
12305
+ return index;
12035
12306
  }
12036
12307
  function runOnce(entry, input, options, phase, profileState) {
12037
12308
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
@@ -12039,13 +12310,31 @@ function runOnce(entry, input, options, phase, profileState) {
12039
12310
  `run(): start production is ${entry === null ? "null" : typeof entry}, not a rule \u2014 the requested grammar rule does not exist (check the rule name).`
12040
12311
  );
12041
12312
  }
12042
- const triviaLog = [];
12313
+ const rootTriviaSelection = options.rootTrivia?.select;
12314
+ const captureRootTrivia = rootTriviaSelection !== void 0 && rootTriviaSelection.length > 0;
12315
+ const selectedRootLog = captureRootTrivia ? [] : void 0;
12316
+ const selectedRootLabelIndex = captureRootTrivia ? makeSelectedRootLabelIndex(rootTriviaSelection) : void 0;
12043
12317
  const errors = [];
12044
12318
  const profile = profileState ?? (phase === void 0 ? void 0 : { phase, nodes: 0, childSlots: 0, rawSlots: 0, triviaSlots: 0, fieldSlots: 0, hostCalls: 0 });
12045
12319
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
12046
12320
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
12047
12321
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
12048
12322
  const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
12323
+ if (captureRootTrivia && triviaKindLabels === void 0) {
12324
+ throw new TypeError("run(): rootTrivia.select requires labeled grammar trivia.");
12325
+ }
12326
+ if (captureRootTrivia) {
12327
+ for (const label2 of rootTriviaSelection) {
12328
+ if (!triviaKindLabels.includes(label2)) {
12329
+ throw new TypeError(`run(): rootTrivia.select contains unknown trivia label ${JSON.stringify(label2)}.`);
12330
+ }
12331
+ }
12332
+ }
12333
+ if (captureRootTrivia && !rootTriviaClassifiedFromRunnable(entry) && !rootTriviaClassifiedFromRunnable(options.trivia)) {
12334
+ throw new TypeError(
12335
+ "run(): rootTrivia.select requires classifiedTrivia() at the root."
12336
+ );
12337
+ }
12049
12338
  const stamped = entry;
12050
12339
  assertHostModeCompatible(
12051
12340
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -12054,7 +12343,15 @@ function runOnce(entry, input, options, phase, profileState) {
12054
12343
  );
12055
12344
  const ctx = {
12056
12345
  trackLines: false,
12057
- ...skipGlobalSinks ? { _pmProfile: profile } : { _triviaLog: triviaLog, _errors: errors, ...profile === void 0 ? {} : { _pmProfile: profile } },
12346
+ ...skipGlobalSinks ? { _pmProfile: profile } : {
12347
+ ...captureRootTrivia ? {
12348
+ _rootTriviaLog: selectedRootLog,
12349
+ _rootTriviaKindIndex: selectedRootLabelIndex,
12350
+ _rootTriviaStrictScopes: true
12351
+ } : {},
12352
+ _errors: errors,
12353
+ ...profile === void 0 ? {} : { _pmProfile: profile }
12354
+ },
12058
12355
  build: options.build,
12059
12356
  state: options.state,
12060
12357
  ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
@@ -12079,9 +12376,13 @@ function runOnce(entry, input, options, phase, profileState) {
12079
12376
  span: r.span ?? { start: 0, end: 0 },
12080
12377
  expected: r.ok ? [] : r.expected ?? [],
12081
12378
  errors,
12082
- triviaLog,
12083
- ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
12084
- triviaMap: buildRootTriviaIndex(triviaLog, triviaKindLabels),
12379
+ ...selectedRootLog !== void 0 && selectedRootLog.length > 0 ? {
12380
+ rootTrivia: {
12381
+ rows: selectedRootLog,
12382
+ select: rootTriviaSelection,
12383
+ index: buildRootTriviaIndex(selectedRootLog, rootTriviaSelection)
12384
+ }
12385
+ } : {},
12085
12386
  unconsumedFrom
12086
12387
  };
12087
12388
  }