parseman 0.42.1 → 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 (68) 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/node.d.ts +21 -7
  8. package/dist/combinators/node.d.ts.map +1 -1
  9. package/dist/combinators/parser.d.ts +17 -2
  10. package/dist/combinators/parser.d.ts.map +1 -1
  11. package/dist/combinators/token.d.ts +3 -2
  12. package/dist/combinators/token.d.ts.map +1 -1
  13. package/dist/combinators/trivia-skip.d.ts +1 -0
  14. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  15. package/dist/compiler/codegen.d.ts +4 -0
  16. package/dist/compiler/codegen.d.ts.map +1 -1
  17. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  18. package/dist/compiler/linker.d.ts +6 -1
  19. package/dist/compiler/linker.d.ts.map +1 -1
  20. package/dist/compiler/scannable-run.d.ts +1 -1
  21. package/dist/compiler/scannable-run.d.ts.map +1 -1
  22. package/dist/compiler/trivia-fast-path.d.ts +4 -3
  23. package/dist/compiler/trivia-fast-path.d.ts.map +1 -1
  24. package/dist/cst/reflection.d.ts +24 -0
  25. package/dist/cst/reflection.d.ts.map +1 -0
  26. package/dist/cst/trivia-entries.d.ts +15 -9
  27. package/dist/cst/trivia-entries.d.ts.map +1 -1
  28. package/dist/cst/trivia-kinds.d.ts +15 -11
  29. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  30. package/dist/cst/types.d.ts +2 -0
  31. package/dist/cst/types.d.ts.map +1 -1
  32. package/dist/cst/walk.d.ts +27 -62
  33. package/dist/cst/walk.d.ts.map +1 -1
  34. package/dist/functional/run.d.ts +22 -16
  35. package/dist/functional/run.d.ts.map +1 -1
  36. package/dist/index.cjs +1651 -1207
  37. package/dist/index.cjs.map +4 -4
  38. package/dist/index.d.ts +6 -5
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1651 -1207
  41. package/dist/index.js.map +4 -4
  42. package/dist/language-service/index.cjs +186 -135
  43. package/dist/language-service/index.cjs.map +4 -4
  44. package/dist/language-service/index.d.ts +1 -1
  45. package/dist/language-service/index.d.ts.map +1 -1
  46. package/dist/language-service/index.js +186 -135
  47. package/dist/language-service/index.js.map +4 -4
  48. package/dist/plugin/evaluator.d.ts +1 -0
  49. package/dist/plugin/evaluator.d.ts.map +1 -1
  50. package/dist/plugin/index.cjs +1525 -1048
  51. package/dist/plugin/index.cjs.map +4 -4
  52. package/dist/plugin/index.d.ts.map +1 -1
  53. package/dist/plugin/index.js +1525 -1048
  54. package/dist/plugin/index.js.map +4 -4
  55. package/dist/run/index.cjs +152 -102
  56. package/dist/run/index.cjs.map +3 -3
  57. package/dist/run/index.d.ts +1 -1
  58. package/dist/run/index.d.ts.map +1 -1
  59. package/dist/run/index.js +152 -102
  60. package/dist/run/index.js.map +3 -3
  61. package/dist/spec/index.cjs +1381 -1152
  62. package/dist/spec/index.cjs.map +4 -4
  63. package/dist/spec/index.js +1381 -1152
  64. package/dist/spec/index.js.map +4 -4
  65. package/dist/types.d.ts +27 -1
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/version.d.ts +1 -1
  68. 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,
@@ -121,7 +122,6 @@ __export(index_exports, {
121
122
  trivia: () => trivia,
122
123
  triviaEntries: () => triviaEntries,
123
124
  triviaKindMask: () => triviaKindMask,
124
- walk: () => walk,
125
125
  when: () => when,
126
126
  withCtx: () => withCtx,
127
127
  word: () => word
@@ -1183,1035 +1183,1099 @@ function keywords(words, opts = {}) {
1183
1183
  };
1184
1184
  }
1185
1185
 
1186
- // src/recovery/scan.ts
1187
- function probeAt(sentinel, input, pos, ctx) {
1188
- const s = {
1189
- _probe: ctx._probe,
1190
- _errors: ctx._errors,
1191
- _cstLeaves: ctx._cstLeaves,
1192
- _cstChildren: ctx._cstChildren,
1193
- _cstRawChildren: ctx._cstRawChildren,
1194
- _cstTriviaLog: ctx._cstTriviaLog,
1195
- _triviaLog: ctx._triviaLog,
1196
- _fields: ctx._fields,
1197
- _cstBuf: ctx._cstBuf,
1198
- _tolerant: ctx._tolerant,
1199
- _sync: ctx._sync
1200
- };
1201
- ctx._probe = void 0;
1202
- ctx._errors = void 0;
1203
- ctx._cstLeaves = void 0;
1204
- ctx._cstChildren = void 0;
1205
- ctx._cstRawChildren = void 0;
1206
- ctx._cstTriviaLog = void 0;
1207
- ctx._triviaLog = void 0;
1208
- ctx._fields = void 0;
1209
- ctx._cstBuf = void 0;
1210
- ctx._tolerant = void 0;
1211
- ctx._sync = void 0;
1212
- try {
1213
- return sentinel.parse(input, pos, ctx).ok;
1214
- } finally {
1215
- ctx._probe = s._probe;
1216
- ctx._errors = s._errors;
1217
- ctx._cstLeaves = s._cstLeaves;
1218
- ctx._cstChildren = s._cstChildren;
1219
- ctx._cstRawChildren = s._cstRawChildren;
1220
- ctx._cstTriviaLog = s._cstTriviaLog;
1221
- ctx._triviaLog = s._triviaLog;
1222
- ctx._fields = s._fields;
1223
- ctx._cstBuf = s._cstBuf;
1224
- ctx._tolerant = s._tolerant;
1225
- ctx._sync = s._sync;
1226
- }
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;
1227
1192
  }
1228
- function orSentinel(a, b) {
1229
- if (b === void 0) return a;
1230
- return {
1231
- _tag: "orSentinel",
1232
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1233
- _def: { tag: "unknown" },
1234
- parse(input, pos, ctx) {
1235
- const ra = a.parse(input, pos, ctx);
1236
- if (ra.ok) return ra;
1237
- return b.parse(input, pos, ctx);
1238
- }
1239
- };
1193
+ function peelLabel(p) {
1194
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1195
+ return null;
1240
1196
  }
1241
- function firstSetSentinel(fs) {
1242
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
1243
- const ranges = fs.ranges;
1244
- return {
1245
- _tag: "firstSetSentinel",
1246
- _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
1247
- _def: { tag: "unknown" },
1248
- parse(input, pos) {
1249
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1250
- if (code !== void 0) {
1251
- for (const r of ranges) {
1252
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1253
- }
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;
1254
1216
  }
1255
- 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;
1256
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
1257
1231
  };
1232
+ labeledTriviaSpecs.set(trivia2, spec);
1233
+ return spec;
1258
1234
  }
1259
- function recoverScan(input, from, ctx, sync, expected) {
1260
- let scanPos = from;
1261
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1262
- const span = { start: from, end: scanPos };
1263
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
1264
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1265
- ctx._errors?.push(error);
1266
- return { error, end: scanPos };
1267
- }
1268
- function matchesAt(sentinel, input, pos, ctx) {
1269
- 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 };
1270
1240
  }
1271
- function captureError(ctx, error) {
1272
- 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 };
1273
1261
  }
1274
- var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
1275
-
1276
- // src/combinators/expect.ts
1277
- function deriveExpected(c) {
1278
- 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;
1279
1276
  }
1280
- function derive(c, seen) {
1281
- const deriveExpected2 = (p) => derive(p, seen);
1282
- const def = c._def;
1283
- switch (def.tag) {
1284
- case "literal":
1285
- return [JSON.stringify(def.value)];
1286
- case "regex":
1287
- return [`/${def.source}/`];
1288
- case "keywords":
1289
- return def.words.map((w) => JSON.stringify(w));
1290
- case "label":
1291
- return [def.label];
1292
- case "choice":
1293
- return def.parsers.flatMap(deriveExpected2);
1294
- case "dispatch":
1295
- return deriveExpected2(def.selector);
1296
- // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
1297
- // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
1298
- // able to fail first — deriving from term 0 alone named a token the parse
1299
- // never actually required. A leading `not(…)` is zero-width and contributes
1300
- // nothing (its own expectation is about what must NOT be here), but it is
1301
- // nullable, so keep scanning past it. Stop at the first term that must match.
1302
- case "sequence": {
1303
- const out = [];
1304
- for (const term of def.parsers) {
1305
- if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
1306
- 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;
1307
1288
  }
1308
- return out;
1309
1289
  }
1310
- case "attempt":
1311
- return deriveExpected2(def.parser);
1312
- // Delegating wrappers whose first-token failure is their inner parser's — must
1313
- // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1314
- // node, which reads this) names the real expected token, not the wrapper tag.
1315
- case "field":
1316
- case "withCtx":
1317
- case "recover":
1318
- return deriveExpected2(def.parser);
1319
- case "skip":
1320
- return deriveExpected2(def.main);
1321
- case "expect":
1322
- return def.expected;
1323
- case "node":
1324
- case "grammar":
1325
- case "trivia":
1326
- case "token":
1327
- case "leaf":
1328
- case "optional":
1329
- case "many":
1330
- case "oneOrMore":
1331
- case "transform":
1332
- case "not":
1333
- case "peek":
1334
- return deriveExpected2(def.parser);
1335
- case "routed":
1336
- return ["routed()"];
1337
- case "lazy": {
1338
- const name = c._ruleName;
1339
- if (seen.has(c)) return name ? [name] : [];
1340
- seen.add(c);
1341
- try {
1342
- return deriveExpected2(def.thunk());
1343
- } catch {
1344
- return name ? [name] : [];
1345
- } finally {
1346
- 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);
1347
1312
  }
1348
1313
  }
1349
- default:
1350
- return [];
1351
1314
  }
1352
- }
1353
- function expect(combinator, label2) {
1354
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1355
- const meta = {
1356
- firstSet: combinator._meta.firstSet,
1357
- canMatchNewline: combinator._meta.canMatchNewline,
1358
- isTrivia: false
1359
- };
1360
- return {
1361
- _tag: "expect",
1362
- _meta: meta,
1363
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1364
- parse(input, pos, ctx) {
1365
- const result = combinator.parse(input, pos, ctx);
1366
- if (result.ok) return result;
1367
- const span = { start: pos, end: pos };
1368
- const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
1369
- ctx._errors?.push(error);
1370
- if (ctx._tolerant) captureError(ctx, error);
1371
- 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;
1372
1321
  }
1373
- };
1374
- }
1375
- function isParseError(value) {
1376
- return typeof value === "object" && value !== null && value._tag === "parseError";
1322
+ }
1377
1323
  }
1378
-
1379
- // src/combinators/choice.ts
1380
- function choice(...args) {
1381
- const parsers = args.map((a) => "gate" in a ? a.combinator : a);
1382
- const gates = args.map((a) => "gate" in a ? a.gate : null);
1383
- const hasGates = gates.some((g) => g !== null);
1384
- const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
1385
- let combined = { kind: "empty" };
1386
- for (const p of parsers) combined = union(combined, p._meta.firstSet);
1387
- const meta = {
1388
- firstSet: combined,
1389
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1390
- isTrivia: false,
1391
- disjoint
1392
- };
1393
- const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1394
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1395
- let greedyLitMap = null;
1396
- let sortedParsers = null;
1397
- const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
1398
- if (strategy?.tag === "greedyClassify") {
1399
- greedyLitMap = /* @__PURE__ */ new Map();
1400
- for (let i = 0; i < parsers.length; i++) {
1401
- if (i === strategy.superIndex) continue;
1402
- const litVal = getCoreLiteralValue(parsers[i]);
1403
- if (litVal !== null) greedyLitMap.set(litVal, i);
1404
- }
1405
- } else if (strategy?.tag === "literalsLongestFirst") {
1406
- 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;
1407
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);
1408
1343
  return {
1409
- _tag: "choice",
1410
- _meta: meta,
1411
- _def: {
1412
- tag: "choice",
1413
- parsers,
1414
- gates,
1415
- disjoint,
1416
- strategy: strategy ?? { tag: "firstMatch" },
1417
- autoNot
1418
- },
1419
- parse(input, pos, ctx) {
1420
- const expected = [];
1421
- if (disjoint && pos < input.length) {
1422
- const code = input.codePointAt(pos);
1423
- let idx = code < 128 ? asciiDispatch[code] : -1;
1424
- if (idx < 0) {
1425
- for (let i = 0; i < parsers.length; i++) {
1426
- if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1427
- idx = i;
1428
- break;
1429
- }
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]);
1430
1406
  }
1431
1407
  }
1432
- if (idx >= 0) {
1433
- const gate2 = gates[idx];
1434
- if (gate2 && !gate2(ctx.state)) {
1435
- 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]);
1436
1411
  }
1437
- const result = parsers[idx].parse(input, pos, ctx);
1438
- if (result.ok) return result;
1439
- expected.push(...result.expected);
1440
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
1441
- return { ok: false, expected, span: { start: pos, end: pos } };
1442
- }
1443
- return {
1444
- ok: false,
1445
- expected: parsers.flatMap((p) => {
1446
- const r = p.parse(input, pos, ctx);
1447
- return r.ok ? [] : r.expected;
1448
- }),
1449
- span: { start: pos, end: pos }
1450
- };
1451
- }
1452
- if (strategy?.tag === "greedyClassify") {
1453
- const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
1454
- if (!superResult.ok) return superResult;
1455
- const end = superResult.span.end;
1456
- const litIdx = greedyLitMap.get(input.slice(pos, end));
1457
- if (litIdx !== void 0) {
1458
- const litVal = getCoreLiteralValue(parsers[litIdx]);
1459
- const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
1460
- return { ok: true, value, span: { start: pos, end } };
1461
- }
1462
- return superResult;
1463
- }
1464
- if (strategy?.tag === "literalsLongestFirst") {
1465
- for (const p of sortedParsers) {
1466
- const r = p.parse(input, pos, ctx);
1467
- if (r.ok) return r;
1468
- expected.push(...r.expected);
1469
- }
1470
- return { ok: false, expected, span: { start: pos, end: pos } };
1471
- }
1472
- for (let i = 0; i < parsers.length; i++) {
1473
- if (gates[i] && !gates[i](ctx.state)) continue;
1474
- const mark = saveCstMark(ctx);
1475
- const logLen = ctx._triviaLog?.length;
1476
- const result = parsers[i].parse(input, pos, ctx);
1477
- if (!result.ok) {
1478
- rollbackCstCapture(ctx, mark);
1479
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1480
- expected.push(...result.expected);
1481
- if (result.committed) return { ok: false, expected, span: result.span, committed: true };
1482
- continue;
1483
- }
1484
- const checks = autoNot[i];
1485
- if (checks && autoNotFires(input, result.span.end, checks)) {
1486
- rollbackCstCapture(ctx, mark);
1487
- if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
1488
- continue;
1489
1412
  }
1490
- return result;
1491
1413
  }
1492
- return { ok: false, expected, span: { start: pos, end: pos } };
1493
- }
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)
1494
1421
  };
1495
1422
  }
1496
- function detectStrategy(parsers) {
1497
- const regexIndices = [];
1498
- const literalIndices = [];
1499
- for (let i = 0; i < parsers.length; i++) {
1500
- if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
1501
- else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
1502
- }
1503
- if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
1504
- const superIndex = regexIndices[0];
1505
- const regexDef = getCoreRegexDef(parsers[superIndex]);
1506
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
1507
- const re = new RegExp(regexDef.source, flags);
1508
- const allSubsumed = literalIndices.every((i) => {
1509
- const litVal = getCoreLiteralValue(parsers[i]);
1510
- re.lastIndex = 0;
1511
- const m = re.exec(litVal);
1512
- return m !== null && m[0] === litVal;
1513
- });
1514
- 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;
1515
1438
  }
1516
- if (parsers.length === literalIndices.length) {
1517
- const sortedIndices = [...literalIndices].sort(
1518
- (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
1519
- );
1520
- 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;
1521
1445
  }
1522
- const shared = detectSharedPrefix(parsers);
1523
- if (shared !== null) return shared;
1524
- return { tag: "firstMatch" };
1525
- }
1526
- function bareLeadingTermKey(term) {
1527
- const d = term._def;
1528
- if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
1529
- if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
1530
- return null;
1531
- }
1532
- function detectSharedPrefix(parsers) {
1533
- if (parsers.length < 2) return null;
1534
- let key = null;
1535
- let prefix = null;
1536
- const members = [];
1537
- for (let i = 0; i < parsers.length; i++) {
1538
- const term0 = leadingTermOfArm(parsers[i]);
1539
- if (term0 === null) return null;
1540
- const k = bareLeadingTermKey(term0);
1541
- if (k === null) return null;
1542
- if (key === null) {
1543
- key = k;
1544
- prefix = term0;
1545
- } else if (k !== key) return null;
1546
- 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;
1547
1450
  }
1548
- if (prefix === null || members.length < 2) return null;
1549
- 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;
1550
1453
  }
1551
- function leadingTermOfArm(arm) {
1552
- let d = arm._def;
1553
- for (; ; ) {
1554
- if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
1555
- d = d.parser._def;
1556
- 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 };
1557
1464
  }
1558
- break;
1559
- }
1560
- if (d.tag !== "sequence" || d.parsers.length < 2) return null;
1561
- return d.parsers[0];
1562
- }
1563
- function computeAutoNot(parsers) {
1564
- return parsers.map((p, i) => {
1565
- const litVal = getCoreLiteralValue(p);
1566
- if (litVal === null) return null;
1567
- const checks = [];
1568
- for (let j = i + 1; j < parsers.length; j++) {
1569
- const other = parsers[j];
1570
- const otherLit = getCoreLiteralValue(other);
1571
- if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
1572
- checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
1573
- continue;
1574
- }
1575
- const regexDef = getCoreRegexDef(other);
1576
- if (regexDef !== null) {
1577
- const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
1578
- if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
1579
- }
1465
+ if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
1466
+ return scanWithLabels(input, cur, ctx);
1580
1467
  }
1581
- return checks.length > 0 ? checks : null;
1582
- });
1583
- }
1584
- function autoNotFires(input, end, checks) {
1585
- for (const check of checks) {
1586
- if (check.kind === "firstSet") {
1587
- const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
1588
- if (inFirstSet(code, check.set)) return true;
1589
- } else {
1590
- 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
+ };
1591
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 };
1592
1486
  }
1593
- return false;
1594
- }
1595
- function getCoreLiteralValue(p) {
1596
- const def = p._def;
1597
- if (def.tag === "literal" && !def.caseInsensitive) return def.value;
1598
- if (def.tag === "transform") return getCoreLiteralValue(def.parser);
1599
- return null;
1600
- }
1601
- function getCoreRegexDef(p) {
1602
- const def = p._def;
1603
- if (def.tag === "regex") return { source: def.source, flags: def.flags };
1604
- if (def.tag === "transform") return getCoreRegexDef(def.parser);
1605
- if (def.tag === "label") return getCoreRegexDef(def.parser);
1606
- return null;
1607
- }
1608
- function applyTransforms(p, value, span) {
1609
- const def = p._def;
1610
- if (def.tag === "transform") {
1611
- const inner = applyTransforms(def.parser, value, span);
1612
- 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 };
1613
1493
  }
1614
- return value;
1615
- }
1616
- function continuationFirstSet(lit, source, flags) {
1617
- const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
1618
- re.lastIndex = 0;
1619
- const base = re.exec(lit);
1620
- if (!base || base[0] !== lit) return null;
1621
- const contCodes = [];
1622
- for (let code = 1; code < 128; code++) {
1623
- re.lastIndex = 0;
1624
- const m = re.exec(lit + String.fromCharCode(code));
1625
- 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;
1626
1498
  }
1627
- if (contCodes.length === 0) return null;
1628
- return codesToFirstSet(contCodes);
1629
- }
1630
- function codesToFirstSet(codes) {
1631
- codes.sort((a, b) => a - b);
1632
- const ranges = [];
1633
- let lo = codes[0], hi = codes[0];
1634
- for (let i = 1; i < codes.length; i++) {
1635
- if (codes[i] === hi + 1) {
1636
- hi = codes[i];
1637
- } else {
1638
- ranges.push({ lo, hi });
1639
- lo = hi = codes[i];
1640
- }
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 };
1641
1503
  }
1642
- ranges.push({ lo, hi });
1643
- 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 };
1644
1518
  }
1645
- function inFirstSet(code, fs) {
1646
- if (fs.kind === "any") return true;
1647
- if (fs.kind === "empty") return false;
1648
- for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1649
- 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;
1650
1524
  }
1651
- function areDisjoint(sets) {
1652
- if (sets.some((s) => s.kind === "any")) return false;
1653
- for (let i = 0; i < sets.length; i++)
1654
- for (let j = i + 1; j < sets.length; j++)
1655
- if (intersects(sets[i], sets[j])) return false;
1656
- 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;
1657
1531
  }
1658
- function buildAsciiDispatch(parsers) {
1659
- const table = Array(128).fill(-1);
1660
- for (let i = 0; i < parsers.length; i++) {
1661
- const fs = parsers[i]._meta.firstSet;
1662
- if (fs.kind !== "ranges") continue;
1663
- for (const { lo, hi } of fs.ranges) {
1664
- for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1665
- 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
+ }
1666
1555
  }
1556
+ break;
1667
1557
  }
1668
- }
1669
- return table;
1670
- }
1671
-
1672
- // src/cst/trivia-kinds.ts
1673
- function unwrapTrivia(p) {
1674
- let cur = p;
1675
- while (cur._def.tag === "trivia") cur = cur._def.parser;
1676
- return cur;
1558
+ return pos;
1559
+ };
1677
1560
  }
1678
- function peelLabel(p) {
1679
- if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1680
- 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);
1681
1565
  }
1682
- function analyzeLabeledTrivia(trivia2) {
1683
- let core = unwrapTrivia(trivia2);
1684
- let minRepeats = 1;
1685
- if (core._def.tag === "oneOrMore") {
1686
- core = core._def.parser;
1687
- minRepeats = 1;
1688
- } else if (core._def.tag === "many") {
1689
- core = core._def.parser;
1690
- minRepeats = 0;
1691
- }
1692
- const arms = [];
1693
- if (core._def.tag === "choice") {
1694
- for (let i = 0; i < core._def.parsers.length; i++) {
1695
- const peeled = peelLabel(core._def.parsers[i]);
1696
- if (!peeled) return null;
1697
- arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1698
- }
1699
- } else {
1700
- const peeled = peelLabel(core);
1701
- if (!peeled) return null;
1702
- 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;
1703
1570
  }
1704
- return { labels: arms.map((a) => a.label), arms, minRepeats };
1571
+ return false;
1705
1572
  }
1706
- function matchArmAt(input, pos, arm) {
1707
- const r = arm.parse(input, pos, { trackLines: false });
1708
- if (!r.ok || r.span.end <= pos) return null;
1709
- 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
+ };
1710
1581
  }
1711
- function scanLabeledTriviaChunks(input, cur, spec) {
1712
- const chunks = [];
1713
- let pos = cur;
1714
- while (pos < input.length) {
1715
- let matched = null;
1716
- for (const arm of spec.arms) {
1717
- const m = matchArmAt(input, pos, arm.parser);
1718
- if (m) {
1719
- matched = { end: m.end, kindIndex: arm.kindIndex };
1720
- break;
1721
- }
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++;
1722
1590
  }
1723
- if (!matched) break;
1724
- chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1725
- 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;
1726
1603
  }
1727
- if (chunks.length < spec.minRepeats) {
1728
- 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) };
1729
1608
  }
1730
- return { end: pos, chunks };
1609
+ return null;
1731
1610
  }
1732
- function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1733
- const chunks = [];
1734
- let pos = cur;
1735
- while (pos < input.length) {
1736
- const c = input.charCodeAt(pos);
1737
- if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1738
- const start = pos;
1739
- pos++;
1740
- while (pos < input.length) {
1741
- const c2 = input.charCodeAt(pos);
1742
- if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1743
- 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;
1744
1631
  }
1745
- chunks.push({ start, end: pos, kindIndex: wsKind });
1746
- continue;
1747
- }
1748
- if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1749
- let j = pos + 2;
1750
- while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
1751
- if (j + 1 < input.length && input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47) {
1752
- const start = pos;
1753
- pos = j + 2;
1754
- 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
+ }
1755
1639
  continue;
1756
1640
  }
1757
1641
  break;
1758
1642
  }
1759
- break;
1760
- }
1761
- return { end: pos, chunks };
1762
- }
1763
- function tryFastLabeledScan(input, cur, trivia2) {
1764
- const spec = analyzeLabeledTrivia(trivia2);
1765
- if (!spec || spec.arms.length !== 2) return null;
1766
- const wsArm = spec.arms.find((a) => {
1767
- const src = getCoreRegexDef(a.parser)?.source;
1768
- return src != null && !src.includes("\\*");
1769
- });
1770
- const commentArm = spec.arms.find((a) => {
1771
- const src = getCoreRegexDef(a.parser)?.source;
1772
- return src != null && src.includes("\\*");
1773
- });
1774
- if (!wsArm || !commentArm) return null;
1775
- const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1776
- if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1777
- return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1643
+ return pos;
1644
+ };
1778
1645
  }
1779
- function recordTriviaChunks(ctx, chunks) {
1780
- const kinds = ctx.triviaKindLabels;
1781
- const mask = ctx._triviaCaptureMask;
1782
- for (const ch2 of chunks) {
1783
- pushTriviaLogEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1784
- if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1785
- if (mask === void 0 || kinds === void 0 || (mask & 1 << ch2.kindIndex) !== 0) {
1786
- pushCstTriviaEntry(ctx, ch2.start, ch2.end, kinds ? ch2.kindIndex : void 0);
1787
- }
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;
1788
1665
  }
1789
1666
  }
1667
+ arms.push(body.slice(start));
1668
+ return arms;
1790
1669
  }
1791
- function triviaKindMask(labels, keep) {
1792
- if (!labels) return void 0;
1793
- let mask = 0;
1794
- for (const name of keep) {
1795
- const idx = labels.indexOf(name);
1796
- 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);
1797
1680
  }
1798
- 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);
1799
1692
  }
1800
1693
 
1801
- // src/combinators/trivia-skip.ts
1802
- var NOOP_COMMIT = () => {
1803
- };
1804
- var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1805
- function needsDeferredTriviaCommit(ctx) {
1806
- return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1807
- }
1808
- function saveTriviaMark(ctx) {
1809
- const m = saveCstMark(ctx);
1810
- return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
1811
- }
1812
- function rollbackTrivia(ctx, mark) {
1813
- rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1814
- if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1815
- }
1816
- function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1817
- const probeCtx = {
1818
- trackLines: ctx.trackLines,
1819
- state: ctx.state,
1820
- ...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
1821
- ...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
1822
- ...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
1823
1709
  };
1824
- const result = triviaP.parse(input, cur, probeCtx);
1825
- ctx._lineScannedTo = probeCtx._lineScannedTo;
1826
- return result;
1827
- }
1828
- function saveLookaheadMark(ctx) {
1829
- return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1830
- }
1831
- function rollbackLookahead(ctx, mark) {
1832
- rollbackTrivia(ctx, mark);
1833
- 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
+ }
1834
1738
  }
1835
- function scanWithLabels(input, cur, ctx) {
1836
- const triviaP = ctx.trivia;
1837
- const spec = analyzeLabeledTrivia(triviaP);
1838
- if (!spec) return { end: cur, commit: NOOP_COMMIT };
1839
- const fast = tryFastLabeledScan(input, cur, triviaP);
1840
- const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
1841
- if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1739
+ function orSentinel(a, b) {
1740
+ if (b === void 0) return a;
1842
1741
  return {
1843
- end,
1844
- commit: () => recordTriviaChunks(ctx, chunks)
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);
1749
+ }
1845
1750
  };
1846
1751
  }
1847
- function advanceTrivia(input, cur, ctx) {
1848
- const triviaP = ctx.trivia;
1849
- if (!triviaP) return cur;
1850
- if (!ctx.trackLines) {
1851
- const fast2 = fastTriviaScanner(triviaP);
1852
- if (fast2) return fast2(input, cur);
1853
- if (ctx.triviaKindLabels) {
1854
- const scan = scanWithLabels(input, cur, ctx);
1855
- return scan.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 } };
1764
+ }
1765
+ }
1766
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
1856
1767
  }
1857
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1858
- return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
1859
- }
1860
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1861
- const fast = fastTriviaScanner(triviaP);
1862
- if (fast) {
1863
- const end = fast(input, cur);
1864
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1865
- return end;
1866
- }
1867
- if (ctx.triviaKindLabels) {
1868
- const scan = scanWithLabels(input, cur, ctx);
1869
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1870
- return scan.end;
1871
- }
1872
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1873
- return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1768
+ };
1874
1769
  }
1875
- function scanTrivia(input, cur, ctx) {
1876
- const triviaP = ctx.trivia;
1877
- if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1878
- const log = ctx._triviaLog;
1879
- const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1880
- if (!ctx.trackLines) {
1881
- const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1882
- if (fast2 && log === void 0 && !captureTl) {
1883
- return { end: fast2(input, cur), commit: NOOP_COMMIT };
1884
- }
1885
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1886
- return scanWithLabels(input, cur, ctx);
1887
- }
1888
- if (log !== void 0 || captureTl) {
1889
- const tr3 = triviaP.parse(input, cur, {
1890
- trackLines: log !== void 0 ? false : ctx.trackLines,
1891
- state: ctx.state
1892
- });
1893
- if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1894
- const end = tr3.span.end;
1895
- return {
1896
- end,
1897
- commit: () => {
1898
- pushTriviaLogEntry(ctx, cur, end);
1899
- if (captureTl) pushCstTriviaEntry(ctx, cur, 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 };
1778
+ }
1779
+ function matchesAt(sentinel, input, pos, ctx) {
1780
+ return probeAt(sentinel, input, pos, ctx);
1781
+ }
1782
+ function captureError(ctx, error) {
1783
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1784
+ }
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;
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;
1833
+ }
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
+ };
1884
+ }
1885
+ };
1886
+ }
1887
+
1888
+ // src/combinators/expect.ts
1889
+ function deriveExpected(c) {
1890
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
1891
+ }
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 [];
1963
+ }
1964
+ }
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
1971
+ };
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 } };
1984
+ }
1985
+ };
1986
+ }
1987
+ function isParseError(value) {
1988
+ return typeof value === "object" && value !== null && value._tag === "parseError";
1989
+ }
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]);
2019
+ }
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 } };
1900
2073
  }
1901
- };
1902
- }
1903
- const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1904
- return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
1905
- }
1906
- const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
1907
- const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1908
- if (fast && log === void 0 && !captureTl) {
1909
- const end = fast(input, cur);
1910
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
1911
- return { end, commit: NOOP_COMMIT };
1912
- }
1913
- if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1914
- const scan = scanWithLabels(input, cur, ctx);
1915
- if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
1916
- return scan;
1917
- }
1918
- if (log !== void 0 || captureTl) {
1919
- const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
1920
- if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1921
- const end = tr2.span.end;
1922
- return {
1923
- end,
1924
- commit: () => {
1925
- pushTriviaLogEntry(ctx, cur, end);
1926
- if (captureTl) pushCstTriviaEntry(ctx, cur, end);
2074
+ return superResult;
1927
2075
  }
1928
- };
1929
- }
1930
- const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
1931
- return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1932
- }
1933
- function consumeTrivia(input, cur, ctx) {
1934
- if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1935
- const scan = scanTrivia(input, cur, ctx);
1936
- scan.commit();
1937
- return scan.end;
1938
- }
1939
- function fastTriviaScanner(trivia2) {
1940
- const cached = fastTriviaCache.get(trivia2);
1941
- if (cached !== void 0) return cached;
1942
- const scanner = buildFastTriviaScanner(trivia2);
1943
- fastTriviaCache.set(trivia2, scanner);
1944
- return scanner;
1945
- }
1946
- function buildFastTriviaScanner(trivia2) {
1947
- const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1948
- const direct = regexTriviaScanner(core);
1949
- if (direct) return direct;
1950
- const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1951
- if (!repeat) return null;
1952
- const one = regexTriviaScanner(repeat);
1953
- if (one) return loopScanner([one]);
1954
- if (repeat._def.tag !== "choice") return null;
1955
- const arms = repeat._def.parsers.map(regexTriviaScanner);
1956
- if (arms.some((s) => s === null)) return null;
1957
- return loopScanner(arms);
1958
- }
1959
- function loopScanner(arms) {
1960
- return (input, cur) => {
1961
- let pos = cur;
1962
- scan: while (pos < input.length) {
1963
- for (const arm of arms) {
1964
- const end = arm(input, pos);
1965
- if (end > pos) {
1966
- pos = end;
1967
- continue scan;
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);
1968
2081
  }
2082
+ return { ok: false, expected, span: { start: pos, end: pos } };
1969
2083
  }
1970
- break;
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 } };
1971
2102
  }
1972
- return pos;
1973
2103
  };
1974
2104
  }
1975
- function regexTriviaScanner(parser2) {
1976
- if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1977
- const source = parser2._def.source;
1978
- return classRunSource(source) ?? altStarSource(source) ?? (blockCommentSource(source) ? scanBlockComment : null);
1979
- }
1980
- function inRanges2(cp, ranges) {
1981
- for (let i = 0; i < ranges.length; i++) {
1982
- const r = ranges[i];
1983
- if (cp >= r[0] && cp <= r[1]) return true;
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);
1984
2111
  }
1985
- return false;
1986
- }
1987
- function classScanner(classBody) {
1988
- const ranges = parseClassRanges(classBody);
1989
- if (!ranges) return null;
1990
- return (input, cur) => {
1991
- let pos = cur;
1992
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1993
- return pos;
1994
- };
1995
- }
1996
- function lineCommentScanner(commentCode) {
1997
- return (input, cur) => {
1998
- if (input.charCodeAt(cur) !== commentCode) return cur;
1999
- let pos = cur + 1;
2000
- while (pos < input.length) {
2001
- const cc = input.charCodeAt(pos);
2002
- if (cc === 10 || cc === 13) break;
2003
- pos++;
2004
- }
2005
- return pos;
2006
- };
2007
- }
2008
- function classRunSource(source) {
2009
- const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
2010
- return m ? classScanner(m[1]) : null;
2011
- }
2012
- function classifyTriviaArm(arm) {
2013
- const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
2014
- if (cls) {
2015
- const ranges = parseClassRanges(cls[1]);
2016
- return ranges ? { kind: "class", ranges } : null;
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 };
2017
2124
  }
2018
- const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
2019
- if (lc) {
2020
- const marker = lc[1];
2021
- return { kind: "comment", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
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 };
2022
2130
  }
2023
- return null;
2131
+ const shared = detectSharedPrefix(parsers);
2132
+ if (shared !== null) return shared;
2133
+ return { tag: "firstMatch" };
2024
2134
  }
2025
- function armScanner(arm) {
2026
- if (arm.kind === "comment") return lineCommentScanner(arm.code);
2027
- const ranges = arm.ranges;
2028
- return (input, cur) => {
2029
- let pos = cur;
2030
- while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
2031
- return pos;
2032
- };
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}`;
2139
+ return null;
2033
2140
  }
2034
- function fusedTriviaScanner(ranges, commentCodes) {
2035
- const c0 = commentCodes[0];
2036
- const single = commentCodes.length === 1;
2037
- return (input, cur) => {
2038
- let pos = cur;
2039
- const len = input.length;
2040
- for (; ; ) {
2041
- const c = input.charCodeAt(pos);
2042
- if (pos < len && inRanges2(c, ranges)) {
2043
- pos++;
2044
- continue;
2045
- }
2046
- if (single ? c === c0 : commentCodes.includes(c)) {
2047
- pos++;
2048
- while (pos < len) {
2049
- const cc = input.charCodeAt(pos);
2050
- if (cc === 10 || cc === 13) break;
2051
- pos++;
2052
- }
2053
- continue;
2054
- }
2055
- break;
2056
- }
2057
- return pos;
2058
- };
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 };
2059
2159
  }
2060
- function splitTopLevelAlts(body) {
2061
- const arms = [];
2062
- let inClass = false;
2063
- let start = 0;
2064
- for (let i = 0; i < body.length; i++) {
2065
- const c = body[i];
2066
- if (c === "\\") {
2067
- i++;
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;
2068
2165
  continue;
2069
2166
  }
2070
- if (inClass) {
2071
- if (c === "]") inClass = false;
2072
- continue;
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) });
2182
+ continue;
2183
+ }
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 });
2188
+ }
2073
2189
  }
2074
- if (c === "[") inClass = true;
2075
- else if (c === "(") return null;
2076
- else if (c === "|") {
2077
- arms.push(body.slice(start, i));
2078
- start = i + 1;
2190
+ return checks.length > 0 ? checks : null;
2191
+ });
2192
+ }
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;
2079
2200
  }
2080
2201
  }
2081
- arms.push(body.slice(start));
2082
- return arms;
2202
+ return false;
2083
2203
  }
2084
- function altStarSource(source) {
2085
- const m = /^\(\?:(.*)\)[*+]$/.exec(source);
2086
- if (!m) return null;
2087
- const armSrcs = splitTopLevelAlts(m[1]);
2088
- if (!armSrcs || armSrcs.length < 2) return null;
2089
- const arms = [];
2090
- for (const src of armSrcs) {
2091
- const arm = classifyTriviaArm(src);
2092
- if (!arm) return null;
2093
- arms.push(arm);
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;
2216
+ }
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);
2094
2222
  }
2095
- const ranges = [];
2096
- const commentCodes = [];
2097
- for (const arm of arms) {
2098
- if (arm.kind === "class") ranges.push(...arm.ranges);
2099
- else commentCodes.push(arm.code);
2223
+ return value;
2224
+ }
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);
2100
2235
  }
2101
- if (commentCodes.some((code) => inRanges2(code, ranges))) {
2102
- return loopScanner(arms.map(armScanner));
2236
+ if (contCodes.length === 0) return null;
2237
+ return codesToFirstSet(contCodes);
2238
+ }
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];
2249
+ }
2103
2250
  }
2104
- if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
2105
- return fusedTriviaScanner(ranges, commentCodes);
2251
+ ranges.push({ lo, hi });
2252
+ return { kind: "ranges", ranges };
2106
2253
  }
2107
- function blockCommentSource(source) {
2108
- return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
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;
2109
2259
  }
2110
- function scanBlockComment(input, cur) {
2111
- if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
2112
- const close = input.indexOf("*/", cur + 2);
2113
- return close === -1 ? cur : close + 2;
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;
2114
2266
  }
2115
-
2116
- // src/combinators/sequence.ts
2117
- function sequence(...parsers) {
2118
- const meta = {
2119
- // Union through the nullable prefix — a leading optional()/many() lets a later
2120
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
2121
- firstSet: sequenceFirstSet(parsers),
2122
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
2123
- isTrivia: false
2124
- };
2125
- const def = { tag: "sequence", parsers };
2126
- let followSentinels;
2127
- function parseTolerant(input, pos, ctx) {
2128
- followSentinels ??= parsers.map((_, i) => {
2129
- const fs = parsers.slice(i + 1).reduce(
2130
- (acc, p) => union(acc, firstSetOf(p)),
2131
- { kind: "empty" }
2132
- );
2133
- return firstSetSentinel(fs);
2134
- });
2135
- const values = def.valueUnused ? void 0 : [];
2136
- let cur = pos;
2137
- const inheritedSync = ctx._sync;
2138
- try {
2139
- for (let i = 0; i < parsers.length; i++) {
2140
- ctx._sync = followSentinels[i] ?? inheritedSync;
2141
- if (ctx.trivia && i > 0) {
2142
- const mark = saveTriviaMark(ctx);
2143
- let scanEnd;
2144
- if (needsDeferredTriviaCommit(ctx)) {
2145
- const scan = scanTrivia(input, cur, ctx);
2146
- scan.commit();
2147
- scanEnd = scan.end;
2148
- } else {
2149
- scanEnd = advanceTrivia(input, cur, ctx);
2150
- }
2151
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2152
- if (!result2.ok) return result2;
2153
- if (result2.span.end > scanEnd) cur = result2.span.end;
2154
- else rollbackTrivia(ctx, mark);
2155
- if (values !== void 0) values.push(result2.value);
2156
- continue;
2157
- }
2158
- const result = parsers[i].parse(input, cur, ctx);
2159
- if (!result.ok) return result;
2160
- if (values !== void 0) values.push(result.value);
2161
- cur = result.span.end;
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;
2162
2275
  }
2163
- } finally {
2164
- ctx._sync = inheritedSync;
2165
2276
  }
2166
- return {
2167
- ok: true,
2168
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2169
- value: values ?? void 0,
2170
- span: { start: pos, end: cur }
2171
- };
2172
2277
  }
2173
- return {
2174
- _tag: "sequence",
2175
- _meta: meta,
2176
- _def: def,
2177
- parse(input, pos, ctx) {
2178
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2179
- const values = def.valueUnused ? void 0 : [];
2180
- let cur = pos;
2181
- for (let i = 0; i < parsers.length; i++) {
2182
- if (ctx.trivia && i > 0) {
2183
- let scanEnd;
2184
- let mark = saveTriviaMark(ctx);
2185
- if (needsDeferredTriviaCommit(ctx)) {
2186
- const scan = scanTrivia(input, cur, ctx);
2187
- scan.commit();
2188
- scanEnd = scan.end;
2189
- } else {
2190
- scanEnd = advanceTrivia(input, cur, ctx);
2191
- }
2192
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2193
- if (!result2.ok) return result2;
2194
- if (result2.span.end > scanEnd) {
2195
- cur = result2.span.end;
2196
- } else {
2197
- rollbackTrivia(ctx, mark);
2198
- }
2199
- if (values !== void 0) values.push(result2.value);
2200
- continue;
2201
- }
2202
- const result = parsers[i].parse(input, cur, ctx);
2203
- if (!result.ok) return result;
2204
- if (values !== void 0) values.push(result.value);
2205
- cur = result.span.end;
2206
- }
2207
- return {
2208
- ok: true,
2209
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2210
- value: values ?? void 0,
2211
- span: { start: pos, end: cur }
2212
- };
2213
- }
2214
- };
2278
+ return table;
2215
2279
  }
2216
2280
 
2217
2281
  // src/combinators/dispatch.ts
@@ -2474,10 +2538,12 @@ function attempt(parser2) {
2474
2538
  }
2475
2539
  const mark = saveCstMark(ctx);
2476
2540
  const log = ctx._triviaLog?.length;
2541
+ const rootLog = ctx._rootTriviaLog?.length;
2477
2542
  const result = parser2.parse(input, pos, ctx);
2478
2543
  if (result.ok) return result;
2479
2544
  rollbackCstCapture(ctx, mark);
2480
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;
2481
2547
  if (result.committed) return result;
2482
2548
  return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
2483
2549
  }
@@ -2918,18 +2984,37 @@ function createParseLineContext(input, pos) {
2918
2984
  }
2919
2985
  function parser(opts, root) {
2920
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
+ }
2921
2991
  return {
2922
2992
  _tag: "grammar",
2923
- _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
+ },
2924
3003
  _def: {
2925
3004
  tag: "grammar",
2926
3005
  parser: root,
2927
3006
  triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2928
3007
  clearTrivia,
3008
+ ...opaqueRootCapture ? { rootCapture: "opaque" } : {},
2929
3009
  ...opts.captureTrivia ? { captureTrivia: true } : {},
2930
3010
  trackLines: opts.trackLines ?? false
2931
3011
  },
2932
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
+ }
2933
3018
  const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2934
3019
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2935
3020
  const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
@@ -2952,7 +3037,11 @@ function parser(opts, root) {
2952
3037
  // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2953
3038
  // trivia is inherited rather than re-declared here. No labels → undefined
2954
3039
  // (capture all).
2955
- ...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 } : {}
2956
3045
  };
2957
3046
  const result = root.parse(input, pos ?? 0, ctx);
2958
3047
  if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
@@ -2993,6 +3082,126 @@ function parse(combinator, input, opts = {}) {
2993
3082
  return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
2994
3083
  }
2995
3084
 
3085
+ // src/cst/reflection.ts
3086
+ var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
3087
+ function childrenOf(def) {
3088
+ switch (def.tag) {
3089
+ case "sequence":
3090
+ case "choice":
3091
+ return def.parsers;
3092
+ case "dispatch":
3093
+ return [
3094
+ def.selector,
3095
+ ...def.cases.map((c) => c.parser),
3096
+ ...def.matchers ? def.matchers.map((c) => c.parser) : [],
3097
+ ...def.otherwise ? [def.otherwise] : []
3098
+ ];
3099
+ case "many":
3100
+ case "oneOrMore":
3101
+ case "optional":
3102
+ case "attempt":
3103
+ case "transform":
3104
+ case "trivia":
3105
+ case "token":
3106
+ case "leaf":
3107
+ case "label":
3108
+ case "field":
3109
+ case "not":
3110
+ case "peek":
3111
+ case "node":
3112
+ case "withCtx":
3113
+ case "recover":
3114
+ case "expect":
3115
+ return [def.parser];
3116
+ case "grammar":
3117
+ return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
3118
+ case "sepBy":
3119
+ return [def.parser, def.separator];
3120
+ case "skip":
3121
+ return [def.main, def.skipped];
3122
+ case "scanTo":
3123
+ return [def.sentinel, ...def.skip];
3124
+ case "literal":
3125
+ case "regex":
3126
+ case "keywords":
3127
+ case "routed":
3128
+ case "guard":
3129
+ case "lazy":
3130
+ case "unknown":
3131
+ return [];
3132
+ }
3133
+ }
3134
+ function addNode(out, def) {
3135
+ if (def.type === void 0) return;
3136
+ const existing = out.get(def.type);
3137
+ if (existing === void 0) {
3138
+ out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
3139
+ return;
3140
+ }
3141
+ if (def.tags === void 0) return;
3142
+ for (const tag of def.tags) {
3143
+ if (!existing.includes(tag)) existing.push(tag);
3144
+ }
3145
+ }
3146
+ function collectFromCombinator(parser2, out, seen, followLazy = true) {
3147
+ if (seen.has(parser2)) return;
3148
+ seen.add(parser2);
3149
+ const def = parser2._def;
3150
+ if (def.tag === "lazy") {
3151
+ if (followLazy) {
3152
+ try {
3153
+ collectFromCombinator(def.thunk(), out, seen, followLazy);
3154
+ } catch {
3155
+ }
3156
+ }
3157
+ return;
3158
+ }
3159
+ if (def.tag === "node") addNode(out, def);
3160
+ for (const child of childrenOf(def)) collectFromCombinator(child, out, seen, followLazy);
3161
+ }
3162
+ function collectGrammarReflection(ruleMap, opts) {
3163
+ const byType = /* @__PURE__ */ new Map();
3164
+ const followLazy = opts?.followLazy !== false;
3165
+ for (const [, rule] of ruleMap) {
3166
+ if (!followLazy && rule._def.tag === "lazy") {
3167
+ try {
3168
+ const resolved = rule._def.thunk();
3169
+ if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
3170
+ } catch {
3171
+ }
3172
+ continue;
3173
+ }
3174
+ collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
3175
+ }
3176
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
3177
+ }
3178
+ function mergeGrammarReflections(reflections) {
3179
+ const byType = /* @__PURE__ */ new Map();
3180
+ for (const reflection of reflections) {
3181
+ for (const node2 of reflection.nodes) {
3182
+ const tags = byType.get(node2.type);
3183
+ if (tags === void 0) {
3184
+ byType.set(node2.type, [...node2.tags]);
3185
+ continue;
3186
+ }
3187
+ for (const tag of node2.tags) {
3188
+ if (!tags.includes(tag)) tags.push(tag);
3189
+ }
3190
+ }
3191
+ }
3192
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
3193
+ }
3194
+ function attachGrammarReflection(grammar, reflection) {
3195
+ Object.defineProperty(grammar, GRAMMAR_REFLECTION, { value: reflection, enumerable: false, configurable: true });
3196
+ return grammar;
3197
+ }
3198
+ function grammarReflectionOf(grammar) {
3199
+ return grammar[GRAMMAR_REFLECTION];
3200
+ }
3201
+ function grammarReflectionSource(reflection) {
3202
+ return `{ nodes: ${JSON.stringify(reflection.nodes)} }`;
3203
+ }
3204
+
2996
3205
  // src/combinators/parser.ts
2997
3206
  var RULE_ORDER = "__parsemanRuleOrder";
2998
3207
  function tagRule(r, key) {
@@ -3091,6 +3300,7 @@ function rules(a, b) {
3091
3300
  enumerable: false,
3092
3301
  configurable: true
3093
3302
  });
3303
+ attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
3094
3304
  return cache;
3095
3305
  }
3096
3306
 
@@ -3411,13 +3621,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3411
3621
  const collapse = opts?.collapse === true;
3412
3622
  const captureTrivia = opts?.captureTrivia === true;
3413
3623
  const trailingTrivia = opts?.trailingTrivia === true;
3624
+ const tags = opts?.tags;
3414
3625
  if (unwrap && collapse) {
3415
3626
  throw new Error("node() options cannot set both unwrap and collapse");
3416
3627
  }
3417
3628
  if (project !== void 0 && (unwrap || collapse)) {
3418
3629
  throw new Error("node() options cannot combine project with unwrap or collapse");
3419
3630
  }
3420
- const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3631
+ const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
3421
3632
  const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3422
3633
  const clonesState = build ? buildReadsState(def) : project === void 0;
3423
3634
  const hasOwnFields = parserHasOwnFields(combinator);
@@ -3463,7 +3674,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3463
3674
  const cstOutput = cstOutputHost(ctx.build);
3464
3675
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
3465
3676
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3466
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3677
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3467
3678
  const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
3468
3679
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3469
3680
  pushCstChild(ctx, built, rawEntry);
@@ -3513,6 +3724,25 @@ function trivia(combinator) {
3513
3724
  parse: combinator.parse.bind(combinator)
3514
3725
  };
3515
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
+ }
3516
3746
  function label(name, combinator) {
3517
3747
  return {
3518
3748
  _tag: combinator._tag,
@@ -3559,6 +3789,7 @@ function token(root) {
3559
3789
  const savedRaw = ctx._cstRawChildren;
3560
3790
  const savedTriviaLog = ctx._cstTriviaLog;
3561
3791
  const savedOuterTriviaLog = ctx._triviaLog;
3792
+ const savedRootTriviaLog = ctx._rootTriviaLog;
3562
3793
  const wasCapturing = cstCaptureActive(ctx);
3563
3794
  ctx.trivia = void 0;
3564
3795
  ctx.triviaKindLabels = void 0;
@@ -3568,6 +3799,7 @@ function token(root) {
3568
3799
  ctx._cstRawChildren = void 0;
3569
3800
  ctx._cstTriviaLog = void 0;
3570
3801
  delete ctx._triviaLog;
3802
+ delete ctx._rootTriviaLog;
3571
3803
  let result;
3572
3804
  try {
3573
3805
  result = root.parse(input, pos, ctx);
@@ -3581,6 +3813,8 @@ function token(root) {
3581
3813
  ctx._cstTriviaLog = savedTriviaLog;
3582
3814
  if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
3583
3815
  else ctx._triviaLog = savedOuterTriviaLog;
3816
+ if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
3817
+ else ctx._rootTriviaLog = savedRootTriviaLog;
3584
3818
  }
3585
3819
  if (!result.ok) return result;
3586
3820
  const span = result.span;
@@ -3635,7 +3869,7 @@ function leaf(root, fn) {
3635
3869
  }
3636
3870
 
3637
3871
  // src/version.ts
3638
- var PARSEMAN_VERSION = "0.42.1";
3872
+ var PARSEMAN_VERSION = "0.44.0";
3639
3873
 
3640
3874
  // src/cst/host-mode.ts
3641
3875
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -3701,7 +3935,7 @@ var SUGGESTIONS = {
3701
3935
  function classifyBroadArm(arm, resolve) {
3702
3936
  const seen = /* @__PURE__ */ new Set();
3703
3937
  const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
3704
- const walk2 = (p) => {
3938
+ const walk = (p) => {
3705
3939
  if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
3706
3940
  seen.add(p);
3707
3941
  const d = p._def;
@@ -3715,7 +3949,7 @@ function classifyBroadArm(arm, resolve) {
3715
3949
  // peek() CARRIES its body's first-set, so it is only broad when the body is
3716
3950
  // (or the body is nullable) — walk in for the real cause.
3717
3951
  case "peek":
3718
- return walk2(d.parser);
3952
+ return walk(d.parser);
3719
3953
  case "scanTo":
3720
3954
  return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
3721
3955
  // `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
@@ -3729,7 +3963,7 @@ function classifyBroadArm(arm, resolve) {
3729
3963
  case "attempt":
3730
3964
  case "withCtx":
3731
3965
  case "recover":
3732
- return walk2(d.parser);
3966
+ return walk(d.parser);
3733
3967
  case "lazy": {
3734
3968
  const name = p._ruleName;
3735
3969
  let target;
@@ -3741,13 +3975,13 @@ function classifyBroadArm(arm, resolve) {
3741
3975
  return { cause: "cross-artifact-ref", detail: `unresolved ref${name ? ` g.${name}` : ""}`, unresolvedExternal: name !== void 0 };
3742
3976
  target = bound;
3743
3977
  }
3744
- const inner = walk2(target);
3978
+ const inner = walk(target);
3745
3979
  if (name !== void 0) return inner ? relabel(inner, "cross-artifact-ref", `via ref g.${name} \u2192 ${inner.detail}`) : null;
3746
3980
  return inner;
3747
3981
  }
3748
3982
  case "optional":
3749
3983
  case "many": {
3750
- const inner = walk2(d.parser);
3984
+ const inner = walk(d.parser);
3751
3985
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3752
3986
  }
3753
3987
  case "oneOrMore":
@@ -3760,9 +3994,9 @@ function classifyBroadArm(arm, resolve) {
3760
3994
  case "node":
3761
3995
  case "grammar":
3762
3996
  case "expect":
3763
- return walk2(d.parser);
3997
+ return walk(d.parser);
3764
3998
  case "skip":
3765
- return walk2(d.main);
3999
+ return walk(d.main);
3766
4000
  case "sequence": {
3767
4001
  let sawNullablePrefix = false;
3768
4002
  for (const t of d.parsers) {
@@ -3771,7 +4005,7 @@ function classifyBroadArm(arm, resolve) {
3771
4005
  continue;
3772
4006
  }
3773
4007
  if (isAny(firstSetOf(t, /* @__PURE__ */ new Set(), resolve))) {
3774
- const inner = walk2(t);
4008
+ const inner = walk(t);
3775
4009
  if (sawNullablePrefix)
3776
4010
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3777
4011
  return inner ?? { cause: "broad-recognizer", detail: "sequence leading term is broad" };
@@ -3786,18 +4020,18 @@ function classifyBroadArm(arm, resolve) {
3786
4020
  }
3787
4021
  case "choice": {
3788
4022
  for (const a of d.parsers) {
3789
- const r = walk2(a);
4023
+ const r = walk(a);
3790
4024
  if (r) return relabel(r, r.cause, `choice arm \u2192 ${r.detail}`);
3791
4025
  }
3792
4026
  return null;
3793
4027
  }
3794
4028
  case "dispatch":
3795
- return walk2(d.selector);
4029
+ return walk(d.selector);
3796
4030
  default:
3797
4031
  return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
3798
4032
  }
3799
4033
  };
3800
- return walk2(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
4034
+ return walk(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
3801
4035
  }
3802
4036
  function peelToLeading(arm) {
3803
4037
  let d = arm._def;
@@ -3999,7 +4233,7 @@ function formatGatingWarnings(report) {
3999
4233
 
4000
4234
  // src/analysis/duplication.ts
4001
4235
  var siteToString = (s) => s.path === "" ? s.rule : `${s.rule} \u203A ${s.path}`;
4002
- function childrenOf(d) {
4236
+ function childrenOf2(d) {
4003
4237
  switch (d.tag) {
4004
4238
  case "sequence":
4005
4239
  case "choice":
@@ -4133,7 +4367,7 @@ function render(p, depth = 3) {
4133
4367
  break;
4134
4368
  }
4135
4369
  if (depth <= 0) return `${d.tag}(\u2026)`;
4136
- const kids = childrenOf(d).map((k) => render(k, depth - 1));
4370
+ const kids = childrenOf2(d).map((k) => render(k, depth - 1));
4137
4371
  switch (d.tag) {
4138
4372
  case "sequence":
4139
4373
  return `sequence(${kids.join(", ")})`;
@@ -4328,7 +4562,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4328
4562
  if (hit !== void 0) return hit;
4329
4563
  const d = p._def;
4330
4564
  shapeCache.set(p, interner.hole);
4331
- const kids = childrenOf(d);
4565
+ const kids = childrenOf2(d);
4332
4566
  const id = interner.of(`${payloadKey(p, d)}|${kids.map(shapeOf).join(",")}`);
4333
4567
  shapeCache.set(p, id);
4334
4568
  return id;
@@ -4338,7 +4572,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4338
4572
  if (hit !== void 0) return hit;
4339
4573
  sizeCache.set(p, 1);
4340
4574
  let n = 1;
4341
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4575
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4342
4576
  sizeCache.set(p, n);
4343
4577
  return n;
4344
4578
  };
@@ -4351,7 +4585,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4351
4585
  visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
4352
4586
  const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
4353
4587
  const innerReducer = enclosingReducer || d.tag === "node" && (d.build !== void 0 || d.buildSrc !== void 0) || d.tag === "transform" || d.tag === "leaf";
4354
- const kids = childrenOf(d);
4588
+ const kids = childrenOf2(d);
4355
4589
  kids.forEach((k, i) => {
4356
4590
  const seg = segment(d, i);
4357
4591
  visit(k, here.rule, here.path === "" ? seg : `${here.path} \u203A ${seg}`, inner, innerReducer);
@@ -4411,7 +4645,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4411
4645
  function markSubtree(p, into) {
4412
4646
  if (into.has(p)) return;
4413
4647
  into.add(p);
4414
- for (const k of childrenOf(p._def)) markSubtree(k, into);
4648
+ for (const k of childrenOf2(p._def)) markSubtree(k, into);
4415
4649
  }
4416
4650
  var stripMembers = (f) => {
4417
4651
  const { _members, ...rest } = f;
@@ -4451,7 +4685,7 @@ function findNearDuplicates(visited, interner, shapeOf, minSize) {
4451
4685
  if (hit !== void 0) return hit;
4452
4686
  holeCache.set(p, []);
4453
4687
  const d = p._def;
4454
- const kids = childrenOf(d);
4688
+ const kids = childrenOf2(d);
4455
4689
  const kidShapes = kids.map(shapeOf);
4456
4690
  const payload = payloadKey(p, d);
4457
4691
  const out2 = [];
@@ -4512,7 +4746,7 @@ function findDivergentSlot(members, shapeOf) {
4512
4746
  let cur = [...members];
4513
4747
  for (let guard2 = 0; guard2 < 64; guard2++) {
4514
4748
  const d0 = cur[0]._def;
4515
- const kidLists = cur.map((c) => childrenOf(c._def));
4749
+ const kidLists = cur.map((c) => childrenOf2(c._def));
4516
4750
  const arity = kidLists[0].length;
4517
4751
  if (kidLists.some((k) => k.length !== arity) || arity === 0) break;
4518
4752
  const diff = [];
@@ -4525,7 +4759,7 @@ function findDivergentSlot(members, shapeOf) {
4525
4759
  path.push(i);
4526
4760
  defs.push(d0);
4527
4761
  cur = kidLists.map((k) => k[i]);
4528
- const nextArity = childrenOf(cur[0]._def).length;
4762
+ const nextArity = childrenOf2(cur[0]._def).length;
4529
4763
  const samePayload = cur.every((c) => payloadKey(c, c._def) === payloadKey(cur[0], cur[0]._def));
4530
4764
  if (!samePayload || nextArity === 0) break;
4531
4765
  }
@@ -4533,7 +4767,7 @@ function findDivergentSlot(members, shapeOf) {
4533
4767
  let slotSize = 0;
4534
4768
  const sizeOf = (p) => {
4535
4769
  let n = 1;
4536
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4770
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4537
4771
  return n;
4538
4772
  };
4539
4773
  for (const c of cur) slotSize = Math.max(slotSize, sizeOf(c));
@@ -4542,7 +4776,7 @@ function findDivergentSlot(members, shapeOf) {
4542
4776
  function renderWithHole(p, path, depth = 0) {
4543
4777
  if (depth === path.length) return "\u2039slot\u203A";
4544
4778
  const d = p._def;
4545
- const kids = childrenOf(d);
4779
+ const kids = childrenOf2(d);
4546
4780
  const idx = path[depth];
4547
4781
  const parts = kids.map((k, i) => i === idx ? renderWithHole(k, path, depth + 1) : render(k, 2));
4548
4782
  switch (d.tag) {
@@ -5000,7 +5234,7 @@ function capturesPositionally(p, seen = /* @__PURE__ */ new Set()) {
5000
5234
  seen.add(p);
5001
5235
  const d = p._def;
5002
5236
  if (d.tag === "field" || d.tag === "label") return true;
5003
- for (const k of childrenOf(d)) if (capturesPositionally(k, seen)) return true;
5237
+ for (const k of childrenOf2(d)) if (capturesPositionally(k, seen)) return true;
5004
5238
  return false;
5005
5239
  }
5006
5240
  function detectHandRolledSepBy(terms, shapeOf) {
@@ -5106,7 +5340,7 @@ function nestedNodeTypes(root, out, seen, isRoot) {
5106
5340
  }
5107
5341
  return;
5108
5342
  }
5109
- for (const k of childrenOf(d)) nestedNodeTypes(k, out, seen, false);
5343
+ for (const k of childrenOf2(d)) nestedNodeTypes(k, out, seen, false);
5110
5344
  }
5111
5345
  var MAX_LOST_TYPES = 8;
5112
5346
  function findStructureLoss(visited, resolve) {
@@ -5533,9 +5767,196 @@ function buildGrammarPlan(entry, winners) {
5533
5767
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
5534
5768
  }
5535
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
+
5536
5953
  // src/compiler/scannable-run.ts
5537
5954
  var BACKSLASH = 92;
5538
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(", ");
5539
5960
  function classToRanges(cls) {
5540
5961
  if (cls === "\\d") return shorthandRanges("d");
5541
5962
  if (cls === "\\w") return shorthandRanges("w");
@@ -6574,13 +6995,15 @@ function scanBranch(shape, mint) {
6574
6995
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6575
6996
  return [...m.setup, ` if (${m.end} > _e) { _e = ${m.end}; continue }`].join("\n");
6576
6997
  }
6577
- function scanBranchLabeled(shape, kindIndex, mint) {
6998
+ function scanBranchLabeled(shape, kindIndex, label2, mint) {
6578
6999
  const m = emitShapeMatch(shape, "_e", mint, " ", "c");
6579
7000
  return [
6580
7001
  ...m.setup,
6581
7002
  ` if (${m.end} > _e) {`,
6582
7003
  ` if (_cap) {`,
6583
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)`,
6584
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})`,
6585
7008
  ` }`,
6586
7009
  ` _e = ${m.end}`,
@@ -6640,6 +7063,11 @@ var CAP_RECORD = [
6640
7063
  ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6641
7064
  ` }`
6642
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");
6643
7071
  function composeFastLoop(shapes) {
6644
7072
  const mint = makeMint();
6645
7073
  return [
@@ -6668,7 +7096,7 @@ function analyzeLabeledScannableRun(trivia2) {
6668
7096
  const d = getCoreRegexDef(arm.parser);
6669
7097
  const shape = d ? scanShapeFromRegex(d.source, d.flags) : null;
6670
7098
  if (!shape) return null;
6671
- out.push({ shape, kindIndex: arm.kindIndex });
7099
+ out.push({ shape, kindIndex: arm.kindIndex, label: arm.label });
6672
7100
  }
6673
7101
  return out;
6674
7102
  }
@@ -6677,11 +7105,13 @@ function buildLabeledScannableTriviaFnDecl(fnName, arms) {
6677
7105
  return [
6678
7106
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6679
7107
  ` let _e = _pos`,
7108
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6680
7109
  ` while (_e < input.length) {`,
6681
7110
  ` const c = input.charCodeAt(_e)`,
6682
- ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, mint)),
7111
+ ...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex, a.label, mint)),
6683
7112
  ` break`,
6684
7113
  ` }`,
7114
+ SELECTED_ROOT_FINISH,
6685
7115
  ` return _e`,
6686
7116
  `}`
6687
7117
  ].join("\n");
@@ -6697,6 +7127,8 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6697
7127
  ` const _ce = _e + _m${i}[0].length`,
6698
7128
  ` if (_cap) {`,
6699
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})`,
6700
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})`,
6701
7133
  ` }`,
6702
7134
  ` _e = _ce`,
@@ -6708,11 +7140,13 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6708
7140
  return [
6709
7141
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6710
7142
  ` let _e = _pos`,
7143
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6711
7144
  ` while (_e < input.length) {`,
6712
7145
  ` let _matched = false`,
6713
7146
  tryArms,
6714
7147
  ` if (!_matched) break`,
6715
7148
  ` }`,
7149
+ SELECTED_ROOT_FINISH,
6716
7150
  ` return _e`,
6717
7151
  `}`
6718
7152
  ].join("\n");
@@ -6735,6 +7169,8 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6735
7169
  ` const _ce = _r${i}.span.end`,
6736
7170
  ` if (_cap) {`,
6737
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})`,
6738
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})`,
6739
7175
  ` }`,
6740
7176
  ` _e = _ce`,
@@ -6746,11 +7182,13 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6746
7182
  return [
6747
7183
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
6748
7184
  ` let _e = _pos`,
7185
+ ` const _rootMark = _cap && _ctx._rootTriviaLog !== undefined ? _ctx._rootTriviaLog.length : 0`,
6749
7186
  ` while (_e < input.length) {`,
6750
7187
  ` let _matched = false`,
6751
7188
  tryArms,
6752
7189
  ` if (!_matched) break`,
6753
7190
  ` }`,
7191
+ SELECTED_ROOT_FINISH,
6754
7192
  ` return _e`,
6755
7193
  `}`
6756
7194
  ].join("\n");
@@ -6973,6 +7411,9 @@ var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) retur
6973
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 }";
6974
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] } }";
6975
7413
  var _loweringSink = null;
7414
+ function hasSelectedRootTrivia(ctx) {
7415
+ return ctx.rootTriviaClassified === true;
7416
+ }
6976
7417
  function v(ctx, prefix = "_v") {
6977
7418
  return `${prefix}${ctx.vars++}`;
6978
7419
  }
@@ -7282,10 +7723,12 @@ function planDisjointDispatch(parsers) {
7282
7723
  }
7283
7724
  return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
7284
7725
  }
7285
- function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
7726
+ function captureRestoreBody(ctx, mL, mR, mTl, mLg, mF = null, mRootLg = null) {
7286
7727
  const fieldRestore = mF ? `; if (_ctx._fields && _ctx._fields.length !== ${mF}) _ctx._fields.length = ${mF}` : "";
7287
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}`;
7288
- 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}`;
7289
7732
  }
7290
7733
  function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
7291
7734
  if (seen.has(p)) return false;
@@ -7495,7 +7938,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
7495
7938
  `${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
7496
7939
  `${ind0}}`,
7497
7940
  ...mL ? [
7498
- `${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
7941
+ `${ind0}if (!${okV}) { ${captureRestoreBody(ctx, mL, mR, mTl, null, mF)} }`
7499
7942
  ] : []
7500
7943
  ];
7501
7944
  return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
@@ -7692,11 +8135,13 @@ function emitSeqValues(def, ctx, pos) {
7692
8135
  const markV = v(ctx, "_mk");
7693
8136
  const markTl = v(ctx, "_mktl");
7694
8137
  const markLog = v(ctx, "_mklg");
8138
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7695
8139
  const scanEndV = v(ctx, "_sne");
7696
8140
  stmts.push(
7697
8141
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
7698
8142
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
7699
8143
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8144
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7700
8145
  `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`,
7701
8146
  ...emitLineTrack(ctx, curV, scanEndV)
7702
8147
  );
@@ -7705,17 +8150,19 @@ function emitSeqValues(def, ctx, pos) {
7705
8150
  const endAfterV = v(ctx, "_sea");
7706
8151
  stmts.push(
7707
8152
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7708
- `${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};` : ""} }`
7709
8154
  );
7710
8155
  valueVars.push(r2.valueVar);
7711
8156
  continue;
7712
8157
  } else {
7713
8158
  const trivFn = ensureTriviaFn(ctx);
7714
8159
  const markLog = v(ctx, "_mklg");
8160
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
7715
8161
  const scanEndV = v(ctx, "_sne");
7716
- 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";
7717
8163
  stmts.push(
7718
8164
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8165
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
7719
8166
  `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
7720
8167
  ...emitLineTrack(ctx, curV, scanEndV)
7721
8168
  );
@@ -7724,7 +8171,7 @@ function emitSeqValues(def, ctx, pos) {
7724
8171
  const endAfterV = v(ctx, "_sea");
7725
8172
  stmts.push(
7726
8173
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7727
- `${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};` : ""} }`
7728
8175
  );
7729
8176
  valueVars.push(r2.valueVar);
7730
8177
  continue;
@@ -7966,6 +8413,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7966
8413
  const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7967
8414
  const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7968
8415
  const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
8416
+ const selectorRootLogMark = selectorNeedsRollback && hasSelectedRootTrivia(ctx) ? v(ctx, "_dsrg") : null;
7969
8417
  const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7970
8418
  const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7971
8419
  const selector = emit(def.selector, ctx, pos);
@@ -7978,6 +8426,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7978
8426
  `${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
7979
8427
  `${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
7980
8428
  `${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
8429
+ ...selectorRootLogMark ? [`${ind(ctx)}const ${selectorRootLogMark} = _ctx._rootTriviaLog?.length ?? 0`] : [],
7981
8430
  `${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
7982
8431
  `${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
7983
8432
  ] : [],
@@ -7997,16 +8446,18 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7997
8446
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7998
8447
  const errMark = mayError ? v(ctx, "_derr") : null;
7999
8448
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
8449
+ const rootLogMark = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_drlog") : null;
8000
8450
  if (usesRouted) {
8001
8451
  stmts.push(
8002
8452
  ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
8003
8453
  ...selectorLeafMark ? [
8004
- `${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}`
8005
8455
  ] : []
8006
8456
  );
8007
8457
  }
8008
8458
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
8009
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`);
8010
8461
  const savedRoutedLocal = ctx.routedLocal;
8011
8462
  const savedNoHoist = ctx.noHoist;
8012
8463
  if (usesRouted && !needsRoutedContext) {
@@ -8021,11 +8472,12 @@ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
8021
8472
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
8022
8473
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
8023
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}; ` : "";
8024
8476
  const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
8025
8477
  const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
8026
8478
  stmts.push(
8027
8479
  ...tail.stmts,
8028
- `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8480
+ `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${rootLogRollback}${coverageFailure}${committedFailBody(ctx)} }`,
8029
8481
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
8030
8482
  `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
8031
8483
  `${ind(ctx)}${outE} = ${tail.endVar}`,
@@ -8206,11 +8658,13 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8206
8658
  const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
8207
8659
  const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
8208
8660
  const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
8661
+ const markRootLog = ctx.activeTrivia && hasSelectedRootTrivia(ctx) ? v(ctx, "_cmlrg") : null;
8209
8662
  const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
8210
8663
  const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
8211
- 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}` : "";
8212
8666
  const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
8213
- const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
8667
+ const rollback = [captureRollback, rootRollback, errorRollback].filter(Boolean).join("; ");
8214
8668
  const failSlot = atStart ? staticFx : "_ctx._fx";
8215
8669
  stmts.push(`${ind0}if (${skipCond}) {`);
8216
8670
  if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
@@ -8225,6 +8679,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
8225
8679
  ...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
8226
8680
  );
8227
8681
  }
8682
+ if (markRootLog) stmts.push(`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog?.length ?? 0`);
8228
8683
  if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
8229
8684
  const arm = emitFallible(p, ctx, pos, atStart);
8230
8685
  const { stmts: armStmts, okVar, valVar, endVar } = arm;
@@ -8293,7 +8748,7 @@ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8293
8748
  const d = p._def;
8294
8749
  if (d.tag === "dispatch") return false;
8295
8750
  if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8296
- return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8751
+ return childrenOf3(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8297
8752
  }
8298
8753
  function armReplayInScope(arm, ctx) {
8299
8754
  let p = arm;
@@ -8412,21 +8867,29 @@ function emitMany(def, ctx, pos) {
8412
8867
  const markV = v(ctx, "_mk");
8413
8868
  const markTl = v(ctx, "_mktl");
8414
8869
  const markLog = v(ctx, "_mklg");
8870
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8415
8871
  const npV = v(ctx, "_np");
8416
8872
  stmts.push(
8417
8873
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8418
8874
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8419
8875
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8876
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8420
8877
  `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8421
8878
  ...emitLineTrack(ctx, curV, npV)
8422
8879
  );
8423
8880
  itemPos = npV;
8424
- 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};` : ""} `;
8425
8882
  } else {
8426
8883
  const trivFn = ensureTriviaFn(ctx);
8884
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8427
8885
  const npV = v(ctx, "_np");
8428
- 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
+ );
8429
8891
  itemPos = npV;
8892
+ rollback = markRootLog ? `if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog}; ` : "";
8430
8893
  }
8431
8894
  }
8432
8895
  if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
@@ -8486,9 +8949,10 @@ function emitAttempt(p, def, ctx, pos) {
8486
8949
  const raw = v(ctx, "_atr");
8487
8950
  const trivia2 = v(ctx, "_att");
8488
8951
  const log = v(ctx, "_atg");
8952
+ const rootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_atrg") : null;
8489
8953
  const fields = v(ctx, "_atf");
8490
8954
  const errors = v(ctx, "_ate");
8491
- 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}`;
8492
8956
  const traceId = ctx.coverage?.plan.attempts.get(p);
8493
8957
  const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
8494
8958
  const preGuard = [];
@@ -8504,7 +8968,7 @@ function emitAttempt(p, def, ctx, pos) {
8504
8968
  return {
8505
8969
  stmts: [
8506
8970
  ...preGuard,
8507
- `${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`,
8508
8972
  ...inner.stmts,
8509
8973
  ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
8510
8974
  ],
@@ -8546,16 +9010,17 @@ function emitSepBy(_p, def, ctx, pos) {
8546
9010
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8547
9011
  const postSepMarks = () => {
8548
9012
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8549
- 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");
8550
9014
  return {
8551
9015
  decl: [
8552
9016
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8553
9017
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8554
9018
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8555
9019
  `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
9020
+ ...rlg ? [`${ind(ctx)}const ${rlg} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8556
9021
  `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8557
9022
  ],
8558
- 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}; `
8559
9024
  };
8560
9025
  };
8561
9026
  if (rec) {
@@ -8593,6 +9058,7 @@ function emitSepBy(_p, def, ctx, pos) {
8593
9058
  const markV = v(ctx, "_mk");
8594
9059
  const markTl = v(ctx, "_mktl");
8595
9060
  const markLog = v(ctx, "_mklg");
9061
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8596
9062
  const markLv = v(ctx, "_mklv");
8597
9063
  const markFld = v(ctx, "_mkf");
8598
9064
  const spV = v(ctx, "_sp");
@@ -8600,13 +9066,14 @@ function emitSepBy(_p, def, ctx, pos) {
8600
9066
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8601
9067
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8602
9068
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
9069
+ ...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
8603
9070
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8604
9071
  `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8605
9072
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`,
8606
9073
  ...emitLineTrack(ctx, curV, spV)
8607
9074
  );
8608
9075
  sepAtPos = spV;
8609
- 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}; `;
8610
9077
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8611
9078
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8612
9079
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8624,19 +9091,30 @@ function emitSepBy(_p, def, ctx, pos) {
8624
9091
  );
8625
9092
  } else {
8626
9093
  const trivFn = ensureTriviaFn(ctx);
9094
+ const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
8627
9095
  const spV = v(ctx, "_sp");
8628
- 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
+ );
8629
9101
  sepAtPos = spV;
8630
9102
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8631
9103
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8632
- 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;
8633
9107
  const npV = v(ctx, "_np");
8634
- 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
+ );
8635
9113
  const next = emitFallible(def.parser, ctx, npV, true);
8636
9114
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
8637
9115
  stmts.push(
8638
9116
  ...nextStmts,
8639
- ...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}; ` : "")),
8640
9118
  `${ind(ctx)}${arrV}.push(${nextVal})`,
8641
9119
  `${ind(ctx)}${curV} = ${nextEnd}`
8642
9120
  );
@@ -8731,6 +9209,7 @@ function emitNot(def, ctx, pos) {
8731
9209
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8732
9210
  const tl = sinksLive ? v(ctx, "_ntt") : null;
8733
9211
  const log = sinksLive ? v(ctx, "_ntg") : null;
9212
+ const rootLog = sinksLive && hasSelectedRootTrivia(ctx) ? v(ctx, "_ntrg") : null;
8734
9213
  const fields = sinksLive ? v(ctx, "_ntf") : null;
8735
9214
  const errors = sinksLive ? v(ctx, "_nte") : null;
8736
9215
  const { stmts, okVar } = emitFallible(def.parser, ctx, pos, true);
@@ -8738,11 +9217,11 @@ function emitNot(def, ctx, pos) {
8738
9217
  return {
8739
9218
  stmts: [
8740
9219
  ...sinksLive ? [
8741
- `${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`
8742
9221
  ] : [],
8743
9222
  ...stmts,
8744
9223
  ...sinksLive ? [
8745
- `${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}`
8746
9225
  ] : [],
8747
9226
  ...emitIfFail(ctx, okVar, failBody(ctx, label2, pos))
8748
9227
  ],
@@ -8878,16 +9357,17 @@ function emitToken(def, ctx, pos) {
8878
9357
  const sk = v(ctx, "_tokKinds");
8879
9358
  const stl = v(ctx, "_tokTl");
8880
9359
  const sol = v(ctx, "_tokLog");
9360
+ const srl = hasSelectedRootTrivia(ctx) ? v(ctx, "_tokRootLog") : null;
8881
9361
  const sb = v(ctx, "_tokBuf");
8882
9362
  const valV = v(ctx, "_tok");
8883
9363
  return {
8884
9364
  stmts: [
8885
- `${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`,
8886
- `${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`,
8887
9367
  `${i}try {`,
8888
9368
  ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
8889
9369
  `${i}} finally {`,
8890
- `${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}`,
8891
9371
  `${i}}`,
8892
9372
  ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
8893
9373
  `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
@@ -9056,7 +9536,8 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
9056
9536
  const nodeSpanV = ctx.lineTracking ? v(ctx, "_nspan") : nodeSpanExpr;
9057
9537
  if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
9058
9538
  const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: ${nodeSpanV}, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, nodeSpanV, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
9059
- const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
9539
+ const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
9540
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${hostBuildArgs})`;
9060
9541
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
9061
9542
  const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
9062
9543
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
@@ -9365,6 +9846,8 @@ function emitDispatch(p, ctx, pos) {
9365
9846
  case "grammar": {
9366
9847
  const savedTrivia = ctx.activeTrivia;
9367
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;
9368
9851
  if (def.clearTrivia) {
9369
9852
  ctx.activeTrivia = void 0;
9370
9853
  ctx.triviaKindLabels = void 0;
@@ -9375,13 +9858,38 @@ function emitDispatch(p, ctx, pos) {
9375
9858
  }
9376
9859
  }
9377
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++;
9378
9865
  const r = emit(def.parser, ctx, pos);
9866
+ if (opaqueRootCapture) ctx.indent--;
9379
9867
  ctx.activeTrivia = savedTrivia;
9380
9868
  ctx.triviaKindLabels = savedKindLabels;
9381
- 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
+ }
9382
9889
  return {
9383
9890
  ...r,
9384
9891
  stmts: [
9892
+ ...strictScopeCheck === void 0 ? [] : [strictScopeCheck],
9385
9893
  `${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
9386
9894
  ...r.stmts,
9387
9895
  `${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
@@ -9519,7 +10027,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9519
10027
  return false;
9520
10028
  }
9521
10029
  }
9522
- return childrenOf2(d).some((child) => hasLineTrackingDef(child, seen));
10030
+ return childrenOf3(d).some((child) => hasLineTrackingDef(child, seen));
9523
10031
  }
9524
10032
  function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9525
10033
  if (seen.has(p)) return false;
@@ -9538,7 +10046,7 @@ function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9538
10046
  case "dispatch":
9539
10047
  return false;
9540
10048
  default:
9541
- return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
10049
+ return childrenOf3(d).some((child) => parserUsesRouted2(child, seen));
9542
10050
  }
9543
10051
  }
9544
10052
  function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
@@ -9553,9 +10061,9 @@ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
9553
10061
  return false;
9554
10062
  }
9555
10063
  }
9556
- return childrenOf2(d).some((child) => hasDirectBuildDef(child, seen));
10064
+ return childrenOf3(d).some((child) => hasDirectBuildDef(child, seen));
9557
10065
  }
9558
- function childrenOf2(def) {
10066
+ function childrenOf3(def) {
9559
10067
  switch (def.tag) {
9560
10068
  case "sequence":
9561
10069
  case "choice":
@@ -9630,7 +10138,7 @@ function subtreeSizes(roots) {
9630
10138
  const def = p._def;
9631
10139
  let s = 1;
9632
10140
  if (def.tag !== "lazy") {
9633
- for (const child of childrenOf2(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
10141
+ for (const child of childrenOf3(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
9634
10142
  }
9635
10143
  sizes.set(p, s);
9636
10144
  return s;
@@ -9651,7 +10159,7 @@ function subtreeSizes(roots) {
9651
10159
  return;
9652
10160
  }
9653
10161
  sz(p);
9654
- for (const child of childrenOf2(def)) visit(child);
10162
+ for (const child of childrenOf3(def)) visit(child);
9655
10163
  };
9656
10164
  for (const root of roots) visit(root);
9657
10165
  return sizes;
@@ -9661,7 +10169,7 @@ function analyzeLazyUsageMulti(roots) {
9661
10169
  const recursive = /* @__PURE__ */ new Set();
9662
10170
  const descended = /* @__PURE__ */ new Set();
9663
10171
  const active = /* @__PURE__ */ new Set();
9664
- function walk2(p) {
10172
+ function walk(p) {
9665
10173
  const def = p._def;
9666
10174
  if (def.tag === "lazy") {
9667
10175
  counts.set(p, (counts.get(p) ?? 0) + 1);
@@ -9678,17 +10186,17 @@ function analyzeLazyUsageMulti(roots) {
9678
10186
  return;
9679
10187
  }
9680
10188
  active.add(p);
9681
- walk2(resolved);
10189
+ walk(resolved);
9682
10190
  active.delete(p);
9683
10191
  return;
9684
10192
  }
9685
10193
  if (isHoistableTag(def.tag)) {
9686
10194
  counts.set(p, (counts.get(p) ?? 0) + 1);
9687
10195
  }
9688
- for (const child of childrenOf2(def)) walk2(child);
10196
+ for (const child of childrenOf3(def)) walk(child);
9689
10197
  }
9690
10198
  const rootsArr = [...roots];
9691
- for (const root of rootsArr) walk2(root);
10199
+ for (const root of rootsArr) walk(root);
9692
10200
  return { counts, recursive, sizes: subtreeSizes(rootsArr) };
9693
10201
  }
9694
10202
  function ruleDependencies(ruleMap) {
@@ -9698,7 +10206,7 @@ function ruleDependencies(ruleMap) {
9698
10206
  for (const [name, comb] of ruleMap) {
9699
10207
  const found = /* @__PURE__ */ new Set();
9700
10208
  const seen = /* @__PURE__ */ new Set();
9701
- const walk2 = (p, isRoot) => {
10209
+ const walk = (p, isRoot) => {
9702
10210
  const def = p._def;
9703
10211
  const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
9704
10212
  if (!isRoot && boundary !== void 0) {
@@ -9714,12 +10222,12 @@ function ruleDependencies(ruleMap) {
9714
10222
  } catch {
9715
10223
  return;
9716
10224
  }
9717
- walk2(resolved, false);
10225
+ walk(resolved, false);
9718
10226
  return;
9719
10227
  }
9720
- for (const child of childrenOf2(def)) walk2(child, false);
10228
+ for (const child of childrenOf3(def)) walk(child, false);
9721
10229
  };
9722
- walk2(comb, true);
10230
+ walk(comb, true);
9723
10231
  deps.set(name, [...found]);
9724
10232
  }
9725
10233
  return deps;
@@ -9866,6 +10374,7 @@ function compile(combinator, mapFnSources, opts) {
9866
10374
  runDuplicationDiagnostic(combinator, opts?.duplication);
9867
10375
  markUnusedValues(combinator);
9868
10376
  const grammarTrivia = combinator._meta.grammarTrivia;
10377
+ const rootTriviaClassified = grammarTrivia?._meta.rootTriviaClassified === true || combinator._meta.rootTriviaClassified === true;
9869
10378
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9870
10379
  const grammarHostMode = combinator._meta.grammarHostMode;
9871
10380
  const grammarTrackLines = combinator._meta.grammarTrackLines;
@@ -9892,7 +10401,11 @@ function compile(combinator, mapFnSources, opts) {
9892
10401
  lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9893
10402
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9894
10403
  lazyUsage: analyzeLazyUsage(combinator),
9895
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10404
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10405
+ ...grammarTrivia ? {
10406
+ activeTrivia: grammarTrivia,
10407
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10408
+ } : {},
9896
10409
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
9897
10410
  };
9898
10411
  const r = emit(combinator, ctx, "_pos");
@@ -10040,10 +10553,11 @@ function assertRuleName(name) {
10040
10553
  );
10041
10554
  }
10042
10555
  }
10043
- function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
10044
- const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
10045
- if (labels === void 0) return fnSource;
10046
- 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,"} } })`;
10047
10561
  }
10048
10562
  function compileLinkable(ruleMapArg, ns, opts) {
10049
10563
  if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
@@ -10051,6 +10565,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10051
10565
  if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
10052
10566
  for (const [, rule] of ruleMapArg) markUnusedValues(rule);
10053
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);
10054
10569
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10055
10570
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10056
10571
  const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
@@ -10064,6 +10579,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10064
10579
  return false;
10065
10580
  }
10066
10581
  });
10582
+ const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
10067
10583
  const ctx = {
10068
10584
  vars: 0,
10069
10585
  indent: 1,
@@ -10093,7 +10609,11 @@ function compileLinkable(ruleMapArg, ns, opts) {
10093
10609
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10094
10610
  ns,
10095
10611
  deferFirstSetRefs: true,
10096
- ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
10612
+ ...rootTriviaClassified ? { rootTriviaClassified: true } : {},
10613
+ ...grammarTrivia ? {
10614
+ activeTrivia: grammarTrivia,
10615
+ triviaKindLabels: grammarTrivia._meta.triviaKindLabels
10616
+ } : {},
10097
10617
  ...grammarScanSkip ? { activeScanSkip: grammarScanSkip } : {}
10098
10618
  };
10099
10619
  const seen = /* @__PURE__ */ new Map();
@@ -10139,7 +10659,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10139
10659
  scanExternal(resolved);
10140
10660
  return;
10141
10661
  }
10142
- for (const child of childrenOf2(def)) scanExternal(child);
10662
+ for (const child of childrenOf3(def)) scanExternal(child);
10143
10663
  };
10144
10664
  for (const [, rule] of ruleMap) scanExternal(rule);
10145
10665
  }
@@ -10225,7 +10745,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10225
10745
  ...r.stmts,
10226
10746
  ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10227
10747
  `}`
10228
- ].join("\n"), ctx.triviaKindLabels));
10748
+ ].join("\n"), ctx.triviaKindLabels, ctx.rootTriviaClassified));
10229
10749
  }
10230
10750
  const firstSets = /* @__PURE__ */ new Map();
10231
10751
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10261,6 +10781,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10261
10781
  hostBranchElided: !!ctx.hostBranchElided,
10262
10782
  hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
10263
10783
  isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule), externalRefs),
10784
+ nodeMeta,
10264
10785
  mfFns: mfSrcs ? [] : ctx.mapFns,
10265
10786
  buildFns: buildSrcs ? [] : ctx.buildFns
10266
10787
  };
@@ -10281,7 +10802,7 @@ function hasExternalRuleRef(ruleMap) {
10281
10802
  if (resolved === void 0) return p._ruleName !== void 0;
10282
10803
  return visit(resolved);
10283
10804
  }
10284
- return childrenOf2(def).some(visit);
10805
+ return childrenOf3(def).some(visit);
10285
10806
  };
10286
10807
  return ruleMap.some(([, rule]) => visit(rule));
10287
10808
  }
@@ -10303,7 +10824,7 @@ function hasSemanticReduction(roots, externalRefs) {
10303
10824
  return true;
10304
10825
  }
10305
10826
  }
10306
- return childrenOf2(def).some(visit);
10827
+ return childrenOf3(def).some(visit);
10307
10828
  };
10308
10829
  return roots.some(visit);
10309
10830
  }
@@ -10376,7 +10897,7 @@ function withCtx(extra, combinator) {
10376
10897
  }
10377
10898
 
10378
10899
  // src/compiler/ir-serialize.ts
10379
- function childrenOf3(def) {
10900
+ function childrenOf4(def) {
10380
10901
  switch (def.tag) {
10381
10902
  case "sequence":
10382
10903
  case "choice":
@@ -10440,6 +10961,10 @@ function projectOpt(project) {
10440
10961
  if (project === void 0) return void 0;
10441
10962
  return `project: ${project}`;
10442
10963
  }
10964
+ function tagsOpt(tags) {
10965
+ if (tags === void 0 || tags.length === 0) return void 0;
10966
+ return `tags: ${JSON.stringify(tags)}`;
10967
+ }
10443
10968
  function matcherExpr(entry) {
10444
10969
  switch (entry.kind) {
10445
10970
  case "startsWith":
@@ -10569,6 +11094,7 @@ function evalRuleMapIR(ir) {
10569
11094
  "transform",
10570
11095
  "skip",
10571
11096
  "trivia",
11097
+ "classifiedTrivia",
10572
11098
  "label",
10573
11099
  "field",
10574
11100
  "expect",
@@ -10609,6 +11135,7 @@ function evalRuleMapIR(ir) {
10609
11135
  transform,
10610
11136
  skip,
10611
11137
  trivia,
11138
+ classifiedTrivia,
10612
11139
  label,
10613
11140
  field,
10614
11141
  expect,
@@ -10653,7 +11180,7 @@ var Serializer = class {
10653
11180
  if (target) this.assertNoRuleRef(target, seen);
10654
11181
  return;
10655
11182
  }
10656
- for (const child of childrenOf3(c._def)) this.assertNoRuleRef(child, seen);
11183
+ for (const child of childrenOf4(c._def)) this.assertNoRuleRef(child, seen);
10657
11184
  }
10658
11185
  /** A `rules()` map wraps each rule value in a named `lazy` proxy; the real body is
10659
11186
  * its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
@@ -10717,7 +11244,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10717
11244
  this.counts.set(c, (this.counts.get(c) ?? 0) + 1);
10718
11245
  if ((this.counts.get(c) ?? 0) > 1) return;
10719
11246
  active.add(c);
10720
- for (const child of childrenOf3(def)) this.analyze(child, active);
11247
+ for (const child of childrenOf4(def)) this.analyze(child, active);
10721
11248
  active.delete(c);
10722
11249
  }
10723
11250
  /** Reference `c`: a const var if it has one (emitting its decl first), else inline.
@@ -10834,12 +11361,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10834
11361
  case "node": {
10835
11362
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10836
11363
  const projectEntry = projectOpt(def.project);
11364
+ const tagEntry = tagsOpt(def.tags);
10837
11365
  const optEntries = [
10838
11366
  ...def.unwrap ? ["unwrap: true"] : [],
10839
11367
  ...def.collapse ? ["collapse: true"] : [],
10840
11368
  ...projectEntry === void 0 ? [] : [projectEntry],
10841
11369
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10842
- ...def.trailingTrivia ? ["trailingTrivia: true"] : []
11370
+ ...def.trailingTrivia ? ["trailingTrivia: true"] : [],
11371
+ ...tagEntry === void 0 ? [] : [tagEntry]
10843
11372
  ];
10844
11373
  const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
10845
11374
  if (def.type === void 0) {
@@ -10853,8 +11382,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10853
11382
  return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
10854
11383
  }
10855
11384
  case "grammar": {
10856
- const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
10857
- 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)})`;
10858
11390
  }
10859
11391
  case "withCtx": {
10860
11392
  if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
@@ -10887,15 +11419,16 @@ function normalizeCstCollapse(collapse) {
10887
11419
  }
10888
11420
  return typeof collapse === "function" ? collapse : void 0;
10889
11421
  }
10890
- function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
10891
- return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
11422
+ function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state, tags) {
11423
+ return tags !== void 0 && tags.length > 0 ? { _tag: "node", type, tags, span: { ...span }, state: state ?? null, children: [...children2] } : { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
10892
11424
  }
10893
- function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
11425
+ function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state, _tags) {
10894
11426
  if (typeof typeOrOptions === "string") {
10895
11427
  return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
10896
11428
  }
10897
11429
  const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
10898
- const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2);
11430
+ const materializeTags = typeOrOptions?.tags === true;
11431
+ const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
10899
11432
  host._parsemanCstOutput = true;
10900
11433
  if (collapse) host._parsemanCstCollapse = collapse;
10901
11434
  return host;
@@ -10937,6 +11470,7 @@ function fusedBody(pieces) {
10937
11470
  ...[...winner].map(([k, p]) => p.ruleFns.get(k))
10938
11471
  ];
10939
11472
  const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
11473
+ const reflection = mergeGrammarReflections([...winner].map(([k, p]) => p.nodeMeta.get(k) ?? { nodes: [] }));
10940
11474
  const { mode, elided } = hostModeOfPieces(pieces);
10941
11475
  const rawBody = [
10942
11476
  ...lines,
@@ -10945,6 +11479,7 @@ function fusedBody(pieces) {
10945
11479
  "}",
10946
11480
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_MODE.description)}), { value: ${JSON.stringify(mode)}, enumerable: false })`,
10947
11481
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_ELIDED.description)}), { value: ${JSON.stringify(elided)}, enumerable: false })`,
11482
+ `Object.defineProperty(_map, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`,
10948
11483
  // …and on each rule FUNCTION, because `run(map.Rule, …)` is handed the rule, not the
10949
11484
  // map, and would otherwise have nothing to check against. Done once at fuse time,
10950
11485
  // before any rule has been called, so it costs nothing per parse.
@@ -11748,157 +12283,26 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11748
12283
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11749
12284
  }
11750
12285
 
11751
- // src/cst/trivia-entries.ts
11752
- var EMPTY_INDICES = Object.freeze([]);
11753
- var EMPTY_GAPS = Object.freeze([]);
11754
- function entryOffset(i, stride) {
11755
- return i * stride;
11756
- }
11757
- function triviaEntries(log, labels, opts) {
11758
- const baseStride = opts?.nodeLog ? 3 : 2;
11759
- const stride = labels ? baseStride + 1 : baseStride;
11760
- const length = Math.floor(log.length / stride);
11761
- return {
11762
- length,
11763
- labels,
11764
- stride,
11765
- start(i) {
11766
- return log[entryOffset(i, stride)];
11767
- },
11768
- end(i) {
11769
- return log[entryOffset(i, stride) + 1];
11770
- },
11771
- insertIndex(i) {
11772
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11773
- },
11774
- kindIndex(i) {
11775
- if (!labels) return void 0;
11776
- return log[entryOffset(i, stride) + baseStride];
11777
- },
11778
- kind(i) {
11779
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11780
- return ki !== void 0 ? labels[ki] : void 0;
11781
- },
11782
- text(i, input) {
11783
- const s = log[entryOffset(i, stride)];
11784
- const e = log[entryOffset(i, stride) + 1];
11785
- return input.slice(s, e);
11786
- }
11787
- };
11788
- }
11789
- function appendEntryRange(map, key, first, last) {
11790
- let indices = map.get(key);
11791
- if (!indices) {
11792
- indices = [];
11793
- map.set(key, indices);
11794
- }
11795
- for (let i = first; i <= last; i++) indices.push(i);
11796
- }
11797
- function buildGap(entries, start, end, first, last) {
11798
- const entryIndices = [];
11799
- for (let i = first; i <= last; i++) entryIndices.push(i);
11800
- return {
11801
- start,
11802
- end,
11803
- entryIndices,
11804
- hasKind(kind) {
11805
- for (const i of entryIndices) {
11806
- if (entries.kind(i) === kind) return true;
11807
- }
11808
- return false;
11809
- },
11810
- text(input) {
11811
- return input.slice(start, end);
11812
- }
11813
- };
11814
- }
11815
- function buildRootMaps(entries) {
11816
- const before = /* @__PURE__ */ new Map();
11817
- const after = /* @__PURE__ */ new Map();
11818
- const beforeGaps = /* @__PURE__ */ new Map();
11819
- const afterGaps = /* @__PURE__ */ new Map();
11820
- const gaps = [];
11821
- if (entries.length === 0) return { before, after, beforeGaps, afterGaps, gaps };
11822
- const appendGap = (first2, last, start2, end2) => {
11823
- const gap = buildGap(entries, start2, end2, first2, last);
11824
- gaps.push(gap);
11825
- afterGaps.set(start2, gap);
11826
- beforeGaps.set(end2, gap);
11827
- appendEntryRange(after, start2, first2, last);
11828
- appendEntryRange(before, end2, first2, last);
11829
- };
11830
- let first = 0;
11831
- let start = entries.start(0);
11832
- let end = entries.end(0);
11833
- for (let i = 1; i < entries.length; i++) {
11834
- const nextStart = entries.start(i);
11835
- const nextEnd = entries.end(i);
11836
- if (nextStart === end) {
11837
- end = nextEnd;
11838
- continue;
11839
- }
11840
- appendGap(first, i - 1, start, end);
11841
- first = i;
11842
- start = nextStart;
11843
- end = nextEnd;
11844
- }
11845
- appendGap(first, entries.length - 1, start, end);
11846
- return { before, after, beforeGaps, afterGaps, gaps };
11847
- }
11848
- function buildRootTriviaIndex(log, labels) {
11849
- const entries = triviaEntries(log, labels);
11850
- let maps;
11851
- const getMaps = () => {
11852
- maps ??= buildRootMaps(entries);
11853
- return maps;
11854
- };
11855
- return {
11856
- entries,
11857
- labels,
11858
- get before() {
11859
- return getMaps().before;
11860
- },
11861
- get after() {
11862
- return getMaps().after;
11863
- },
11864
- entryIndicesBefore(offset) {
11865
- return getMaps().before.get(offset) ?? EMPTY_INDICES;
11866
- },
11867
- entryIndicesAfter(offset) {
11868
- return getMaps().after.get(offset) ?? EMPTY_INDICES;
11869
- },
11870
- gapBefore(offset) {
11871
- return getMaps().beforeGaps.get(offset);
11872
- },
11873
- gapAfter(offset) {
11874
- return getMaps().afterGaps.get(offset);
11875
- },
11876
- gaps() {
11877
- return getMaps().gaps;
11878
- },
11879
- gapsWithKind(kind) {
11880
- const kinds = typeof kind === "string" ? [kind] : kind;
11881
- const matches2 = [];
11882
- for (const gap of getMaps().gaps) {
11883
- for (const k of kinds) {
11884
- if (gap.hasKind(k)) {
11885
- matches2.push(gap);
11886
- break;
11887
- }
11888
- }
11889
- }
11890
- return matches2.length === 0 ? EMPTY_GAPS : matches2;
11891
- }
11892
- };
11893
- }
11894
-
11895
12286
  // src/functional/run.ts
11896
12287
  var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
11897
12288
  function triviaKindLabelsFromRunnable(r) {
11898
12289
  if (!r) return void 0;
11899
12290
  if (typeof r === "function") return r._meta?.triviaKindLabels;
11900
12291
  const grammarTrivia = r._meta.grammarTrivia;
11901
- 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;
11902
12306
  }
11903
12307
  function runOnce(entry, input, options, phase, profileState) {
11904
12308
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
@@ -11906,13 +12310,31 @@ function runOnce(entry, input, options, phase, profileState) {
11906
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).`
11907
12311
  );
11908
12312
  }
11909
- 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;
11910
12317
  const errors = [];
11911
12318
  const profile = profileState ?? (phase === void 0 ? void 0 : { phase, nodes: 0, childSlots: 0, rawSlots: 0, triviaSlots: 0, fieldSlots: 0, hostCalls: 0 });
11912
12319
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
11913
12320
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
11914
12321
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
11915
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
+ }
11916
12338
  const stamped = entry;
11917
12339
  assertHostModeCompatible(
11918
12340
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -11921,7 +12343,15 @@ function runOnce(entry, input, options, phase, profileState) {
11921
12343
  );
11922
12344
  const ctx = {
11923
12345
  trackLines: false,
11924
- ...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
+ },
11925
12355
  build: options.build,
11926
12356
  state: options.state,
11927
12357
  ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
@@ -11946,9 +12376,13 @@ function runOnce(entry, input, options, phase, profileState) {
11946
12376
  span: r.span ?? { start: 0, end: 0 },
11947
12377
  expected: r.ok ? [] : r.expected ?? [],
11948
12378
  errors,
11949
- triviaLog,
11950
- ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
11951
- 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
+ } : {},
11952
12386
  unconsumedFrom
11953
12387
  };
11954
12388
  }
@@ -12373,38 +12807,48 @@ function buildTriviaIndex(root, input = "", opts) {
12373
12807
  }
12374
12808
 
12375
12809
  // src/cst/walk.ts
12376
- function walk(root, visitor, ctx = void 0) {
12377
- const go = (node2, parent) => {
12378
- const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
12379
- const children2 = node2.children;
12380
- if (descend !== false && Array.isArray(children2)) {
12381
- for (const child of children2) go(child, node2);
12382
- }
12383
- visitor.leave?.(node2, parent, ctx);
12384
- };
12385
- go(root, null);
12386
- }
12387
- function createVisitor(handlers) {
12388
- const api = {
12389
- visit(node2) {
12390
- const handler = node2.type !== void 0 ? handlers[node2.type] : void 0;
12391
- if (handler) return handler(node2, api);
12392
- api.visitChildren(node2);
12393
- return void 0;
12394
- },
12395
- visitChildren(node2) {
12396
- const out = [];
12397
- const children2 = node2.children;
12398
- if (Array.isArray(children2)) {
12399
- for (const child of children2) {
12400
- const r = api.visit(child);
12401
- if (r !== void 0) out.push(r);
12810
+ function isCombinator(value) {
12811
+ return !!value && typeof value === "object" && "_def" in value && "_meta" in value && typeof value.parse === "function";
12812
+ }
12813
+ function reflectionFor(grammar) {
12814
+ const stamped = grammarReflectionOf(grammar);
12815
+ if (stamped) return stamped;
12816
+ const entries = Object.entries(grammar).filter((entry) => isCombinator(entry[1]));
12817
+ return collectGrammarReflection(entries);
12818
+ }
12819
+ function createVisitor(grammar, spec) {
12820
+ const reflection = reflectionFor(grammar);
12821
+ const typeHandlers = spec.type;
12822
+ const tagSpec = spec.tag;
12823
+ const tagHandlersByType = /* @__PURE__ */ new Map();
12824
+ if (tagSpec !== void 0) {
12825
+ for (const node2 of reflection.nodes) {
12826
+ const handlers = [];
12827
+ for (const tag of node2.tags) {
12828
+ const handler = tagSpec[tag];
12829
+ if (handler) handlers.push(handler);
12830
+ }
12831
+ if (handlers.length > 0) tagHandlersByType.set(node2.type, handlers);
12832
+ }
12833
+ }
12834
+ return (root, ctx = void 0) => {
12835
+ const go = (node2, parent) => {
12836
+ const descend = spec.enter ? spec.enter(node2, parent, ctx) : void 0;
12837
+ if (node2._tag === "node" && node2.type !== void 0) {
12838
+ typeHandlers?.[node2.type]?.(node2, parent, ctx);
12839
+ const tagHandlers = tagHandlersByType.get(node2.type);
12840
+ if (tagHandlers !== void 0) {
12841
+ for (const handler of tagHandlers) handler(node2, parent, ctx);
12402
12842
  }
12403
12843
  }
12404
- return out;
12405
- }
12844
+ const children2 = node2.children;
12845
+ if (descend !== false && Array.isArray(children2)) {
12846
+ for (const child of children2) go(child, node2);
12847
+ }
12848
+ spec.leave?.(node2, parent, ctx);
12849
+ };
12850
+ go(root, null);
12406
12851
  };
12407
- return (node2) => api.visit(node2);
12408
12852
  }
12409
12853
 
12410
12854
  // src/cst/offset-model.ts