parseman 0.39.1 → 0.41.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 (41) hide show
  1. package/README.md +9 -0
  2. package/dist/combinators/node.d.ts +15 -0
  3. package/dist/combinators/node.d.ts.map +1 -1
  4. package/dist/compiler/codegen.d.ts.map +1 -1
  5. package/dist/compiler/inline-callback.d.ts +9 -0
  6. package/dist/compiler/inline-callback.d.ts.map +1 -1
  7. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  8. package/dist/compiler/value-usage.d.ts.map +1 -1
  9. package/dist/cst/trivia-entries.d.ts +52 -0
  10. package/dist/cst/trivia-entries.d.ts.map +1 -1
  11. package/dist/functional/run.d.ts +11 -2
  12. package/dist/functional/run.d.ts.map +1 -1
  13. package/dist/index.cjs +326 -91
  14. package/dist/index.cjs.map +4 -4
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +326 -91
  18. package/dist/index.js.map +4 -4
  19. package/dist/language-service/index.cjs +155 -2
  20. package/dist/language-service/index.cjs.map +4 -4
  21. package/dist/language-service/index.js +155 -2
  22. package/dist/language-service/index.js.map +4 -4
  23. package/dist/plugin/evaluator.d.ts.map +1 -1
  24. package/dist/plugin/index.cjs +196 -58
  25. package/dist/plugin/index.cjs.map +4 -4
  26. package/dist/plugin/index.js +196 -58
  27. package/dist/plugin/index.js.map +4 -4
  28. package/dist/run/index.cjs +155 -1
  29. package/dist/run/index.cjs.map +4 -4
  30. package/dist/run/index.d.ts +7 -4
  31. package/dist/run/index.d.ts.map +1 -1
  32. package/dist/run/index.js +155 -1
  33. package/dist/run/index.js.map +4 -4
  34. package/dist/spec/index.cjs +35 -11
  35. package/dist/spec/index.cjs.map +2 -2
  36. package/dist/spec/index.js +35 -11
  37. package/dist/spec/index.js.map +2 -2
  38. package/dist/types.d.ts +1 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/version.d.ts +1 -1
  41. package/package.json +2 -1
package/dist/index.cjs CHANGED
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  blankLinesIn: () => blankLinesIn,
40
40
  buildLineIndex: () => buildLineIndex,
41
41
  buildOffsetIndex: () => buildOffsetIndex,
42
+ buildRootTriviaIndex: () => buildRootTriviaIndex,
42
43
  buildTriviaIndex: () => buildTriviaIndex,
43
44
  charClassMembers: () => charClassMembers,
44
45
  choice: () => choice,
@@ -2711,9 +2712,11 @@ function markUnusedValues(root) {
2711
2712
  visit(def.parser, consumed);
2712
2713
  visit(def.sentinel, false);
2713
2714
  return;
2715
+ case "token":
2716
+ visit(def.parser, false);
2717
+ return;
2714
2718
  case "label":
2715
2719
  case "trivia":
2716
- case "token":
2717
2720
  case "attempt":
2718
2721
  case "withCtx":
2719
2722
  case "expect":
@@ -3115,12 +3118,30 @@ function isCstChild(value) {
3115
3118
  function missingInferredType() {
3116
3119
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
3117
3120
  }
3121
+ function normalizeProject(project) {
3122
+ if (project === void 0) return void 0;
3123
+ if (!Number.isInteger(project) || project < 0) {
3124
+ throw new Error("node() project child must be a non-negative integer");
3125
+ }
3126
+ return project;
3127
+ }
3128
+ function projectChild(children2, project, type) {
3129
+ if (!(project in children2)) {
3130
+ throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
3131
+ }
3132
+ return unwrapChild(children2[project]);
3133
+ }
3118
3134
  function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3119
3135
  const hasExplicitType = typeof typeOrCombinator === "string";
3120
3136
  const type = hasExplicitType ? typeOrCombinator : void 0;
3121
3137
  const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
3122
- const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
3123
- const opts = hasExplicitType ? maybeOpts : buildOrOpts;
3138
+ const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
3139
+ const build = typeof buildArg === "function" ? buildArg : void 0;
3140
+ const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
3141
+ const project = normalizeProject(opts?.project);
3142
+ if (project !== void 0 && build !== void 0) {
3143
+ throw new Error("node() options cannot combine project with a build callback");
3144
+ }
3124
3145
  const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
3125
3146
  const meta = {
3126
3147
  firstSet: combinator._meta.firstSet,
@@ -3134,11 +3155,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3134
3155
  if (unwrap && collapse) {
3135
3156
  throw new Error("node() options cannot set both unwrap and collapse");
3136
3157
  }
3137
- const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3138
- const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
3139
- const clonesState = build ? buildReadsState(def) : true;
3158
+ if (project !== void 0 && (unwrap || collapse)) {
3159
+ throw new Error("node() options cannot combine project with unwrap or collapse");
3160
+ }
3161
+ 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;
3162
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3163
+ const clonesState = build ? buildReadsState(def) : project === void 0;
3140
3164
  const hasOwnFields = parserHasOwnFields(combinator);
3141
- const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : true);
3165
+ const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
3142
3166
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3143
3167
  let failExpected;
3144
3168
  return {
@@ -3153,14 +3177,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3153
3177
  }
3154
3178
  return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
3155
3179
  }
3156
- const hostCst = build !== void 0 && cstOutputHost(ctx.build);
3180
+ const hasDirectValue = build !== void 0 || project !== void 0;
3181
+ const hostCst = hasDirectValue && cstOutputHost(ctx.build);
3157
3182
  const effTrivia = capturesTrivia || hostCst;
3158
3183
  const effFields = capturesFields || hostCst && hasOwnFields;
3159
3184
  const saved = beginCstNodeCapture(ctx);
3160
3185
  const savedFields = ctx._fields;
3161
3186
  ctx._fields = effFields ? [] : void 0;
3162
3187
  const savedMask = ctx._triviaCaptureMask;
3163
- if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3188
+ if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3164
3189
  ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
3165
3190
  }
3166
3191
  if (!effTrivia) ctx.captureTrivia = false;
@@ -3178,7 +3203,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3178
3203
  const nodeType = def.type ?? missingInferredType();
3179
3204
  const cstOutput = cstOutputHost(ctx.build);
3180
3205
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3181
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3206
+ 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, r.span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3182
3207
  const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span: r.span };
3183
3208
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3184
3209
  pushCstChild(ctx, built, rawEntry);
@@ -3456,7 +3481,7 @@ function leaf(root, fn) {
3456
3481
  }
3457
3482
 
3458
3483
  // src/version.ts
3459
- var PARSEMAN_VERSION = "0.39.1";
3484
+ var PARSEMAN_VERSION = "0.41.0";
3460
3485
 
3461
3486
  // src/cst/host-mode.ts
3462
3487
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -6400,7 +6425,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6400
6425
  ` if (${m.end} > _e) {`,
6401
6426
  ` if (_cap) {`,
6402
6427
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6403
- ` if (_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})`,
6428
+ ` 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})`,
6404
6429
  ` }`,
6405
6430
  ` _e = ${m.end}`,
6406
6431
  ` continue`,
@@ -6456,7 +6481,7 @@ function analyzeTriviaFastPath(trivia2) {
6456
6481
  var CAP_RECORD = [
6457
6482
  ` if (_cap && _e > _pos) {`,
6458
6483
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6459
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6484
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6460
6485
  ` }`
6461
6486
  ].join("\n");
6462
6487
  function composeFastLoop(shapes) {
@@ -6516,7 +6541,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6516
6541
  ` const _ce = _e + _m${i}[0].length`,
6517
6542
  ` if (_cap) {`,
6518
6543
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6519
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6544
+ ` 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})`,
6520
6545
  ` }`,
6521
6546
  ` _e = _ce`,
6522
6547
  ` _matched = true`,
@@ -6554,7 +6579,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6554
6579
  ` const _ce = _r${i}.span.end`,
6555
6580
  ` if (_cap) {`,
6556
6581
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6557
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6582
+ ` 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})`,
6558
6583
  ` }`,
6559
6584
  ` _e = _ce`,
6560
6585
  ` _matched = true`,
@@ -6640,6 +6665,9 @@ function transformFnSource(fn, fnSrc) {
6640
6665
  function replaceParam(body, param, valueVar) {
6641
6666
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6642
6667
  }
6668
+ function hasExplicitObjectKey(body, param) {
6669
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6670
+ }
6643
6671
  function stripForIdCheck(body) {
6644
6672
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6645
6673
  }
@@ -6682,10 +6710,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6682
6710
  const allowed = new Set(valueVars);
6683
6711
  for (let i = 0; i < slots.length; i++) {
6684
6712
  const name = slots[i];
6685
- if (name) body = replaceParam(body, name, valueVars[i]);
6713
+ if (!name) continue;
6714
+ if (hasExplicitObjectKey(body, name)) return null;
6715
+ body = replaceParam(body, name, valueVars[i]);
6686
6716
  }
6687
6717
  return hasFreeIdentifiers(body, allowed) ? null : body;
6688
6718
  }
6719
+ function isDispatchTailOnlyTransform(src) {
6720
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
6721
+ if (!m) return false;
6722
+ const slots = parseArrayDestructure(m[1], 2);
6723
+ const tail = slots[1];
6724
+ return tail !== null && m[2].trim() === tail;
6725
+ }
6689
6726
 
6690
6727
  // src/compiler/codegen.ts
6691
6728
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6936,6 +6973,17 @@ function ensureRegexDecl(ctx, source, flags) {
6936
6973
  }
6937
6974
  return rName;
6938
6975
  }
6976
+ function ensurePlainRegexDecl(ctx, source, flags) {
6977
+ const f = flags.replace(/[gy]/g, "");
6978
+ const key = `${source}/${f}`;
6979
+ let rName = ctx.regexMap.get(key);
6980
+ if (rName === void 0) {
6981
+ rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
6982
+ ctx.regexDecls.push(`const ${rName} = ${new RegExp(source, f).toString()}`);
6983
+ ctx.regexMap.set(key, rName);
6984
+ }
6985
+ return rName;
6986
+ }
6939
6987
  function ensureTriviaFn(ctx) {
6940
6988
  const trivia2 = ctx.activeTrivia;
6941
6989
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -7001,7 +7049,7 @@ function ensureTriviaFn(ctx) {
7001
7049
  ` }`,
7002
7050
  ` if (_cap && _e > _pos) {`,
7003
7051
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
7004
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
7052
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
7005
7053
  ` }`,
7006
7054
  ` return _e`,
7007
7055
  `}`
@@ -7462,14 +7510,19 @@ function emitSeqValues(def, ctx, pos) {
7462
7510
  continue;
7463
7511
  } else {
7464
7512
  const trivFn = ensureTriviaFn(ctx);
7513
+ const markLog = v(ctx, "_mklg");
7465
7514
  const scanEndV = v(ctx, "_sne");
7466
- stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
7515
+ const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7516
+ stmts.push(
7517
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7518
+ `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`
7519
+ );
7467
7520
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7468
7521
  stmts.push(...r2.stmts);
7469
7522
  const endAfterV = v(ctx, "_sea");
7470
7523
  stmts.push(
7471
7524
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7472
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
7525
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7473
7526
  );
7474
7527
  valueVars.push(r2.valueVar);
7475
7528
  continue;
@@ -7699,19 +7752,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7699
7752
  return false;
7700
7753
  }
7701
7754
  }
7702
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7755
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7703
7756
  if (parserUsesRouted2(def.selector)) {
7704
7757
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7705
7758
  }
7706
7759
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7707
7760
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7708
7761
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7709
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7710
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7711
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7712
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7713
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7714
- const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
7762
+ const selectorNeedsRollback = hasRoutedBranch && (ctx.capturing === true && capturesLeaf(def.selector) || ctx.activeTrivia !== void 0 && parserHasTriviaSite(def.selector) || parserEnablesTriviaCapture(def.selector) || parserHasOwnFields(def.selector) || mayRecordRecoveryError(def.selector, !!ctx.recovery));
7763
+ const selectorLeafMark = selectorNeedsRollback ? v(ctx, "_dsl") : null;
7764
+ const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7765
+ const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7766
+ const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
7767
+ const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7768
+ const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7715
7769
  const selector = emit(def.selector, ctx, pos);
7716
7770
  const outV = v(ctx, "_dval");
7717
7771
  const outE = v(ctx, "_dend");
@@ -7736,13 +7790,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7736
7790
  stmts.push(head);
7737
7791
  ctx.indent++;
7738
7792
  const usesRouted = branchUsesRouted2(entry);
7739
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7793
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7794
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7740
7795
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7741
7796
  const errMark = mayError ? v(ctx, "_derr") : null;
7742
7797
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7743
- if (routedV) {
7798
+ if (usesRouted) {
7744
7799
  stmts.push(
7745
- `${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
7800
+ ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7746
7801
  ...selectorLeafMark ? [
7747
7802
  `${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}`
7748
7803
  ] : []
@@ -7750,7 +7805,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7750
7805
  }
7751
7806
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7752
7807
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
7808
+ const savedRoutedLocal = ctx.routedLocal;
7809
+ const savedNoHoist = ctx.noHoist;
7810
+ if (usesRouted && !needsRoutedContext) {
7811
+ ctx.routedLocal = { valueVar: selector.valueVar, startVar: pos, endVar: selector.endVar };
7812
+ ctx.noHoist = true;
7813
+ } else if (usesRouted) {
7814
+ ctx.routedLocal = void 0;
7815
+ }
7753
7816
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
7817
+ ctx.routedLocal = savedRoutedLocal;
7818
+ ctx.noHoist = savedNoHoist;
7754
7819
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7755
7820
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7756
7821
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7760,7 +7825,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7760
7825
  ...tail.stmts,
7761
7826
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7762
7827
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7763
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
7828
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7764
7829
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7765
7830
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7766
7831
  );
@@ -7775,7 +7840,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7775
7840
  }
7776
7841
  const emitMatcherTails = () => {
7777
7842
  for (const matcher of def.matchers ?? []) {
7778
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
7843
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7779
7844
  wroteBranch = true;
7780
7845
  }
7781
7846
  };
@@ -7800,10 +7865,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7800
7865
  }
7801
7866
  return parts.join(" && ");
7802
7867
  }
7803
- function emitDispatchMatcherCondition(valueVar, matcher) {
7868
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7804
7869
  if (matcher.kind === "matches") {
7805
7870
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7806
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
7871
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7807
7872
  }
7808
7873
  const text = matcher.value;
7809
7874
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -8006,6 +8071,28 @@ function emitsAsNamedFn(p, ctx) {
8006
8071
  const usage = ctx.lazyUsage;
8007
8072
  return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
8008
8073
  }
8074
+ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8075
+ if (seen.has(p)) return false;
8076
+ seen.add(p);
8077
+ if (p._def.tag === "lazy") {
8078
+ if (ctx.ruleNames?.has(p) || ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8079
+ const usage = ctx.lazyUsage;
8080
+ if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
8081
+ try {
8082
+ return routedNeedsContextBridge(p._def.thunk(), ctx, seen);
8083
+ } catch {
8084
+ return parserUsesRouted2(p);
8085
+ }
8086
+ }
8087
+ return parserUsesRouted2(p);
8088
+ }
8089
+ if (ctx.ruleNames?.has(p)) return parserUsesRouted2(p);
8090
+ if (ctx.namedParsers.has(p)) return parserUsesRouted2(p);
8091
+ const d = p._def;
8092
+ if (d.tag === "dispatch") return false;
8093
+ if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8094
+ return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8095
+ }
8009
8096
  function armReplayInScope(arm, ctx) {
8010
8097
  let p = arm;
8011
8098
  for (; ; ) {
@@ -8256,15 +8343,16 @@ function emitSepBy(_p, def, ctx, pos) {
8256
8343
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8257
8344
  const postSepMarks = () => {
8258
8345
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8259
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg");
8346
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8260
8347
  return {
8261
8348
  decl: [
8262
8349
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8263
8350
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8264
8351
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8265
- `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`
8352
+ `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8353
+ `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8266
8354
  ],
8267
- 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}; `
8355
+ 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}; `
8268
8356
  };
8269
8357
  };
8270
8358
  if (rec) {
@@ -8303,16 +8391,18 @@ function emitSepBy(_p, def, ctx, pos) {
8303
8391
  const markTl = v(ctx, "_mktl");
8304
8392
  const markLog = v(ctx, "_mklg");
8305
8393
  const markLv = v(ctx, "_mklv");
8394
+ const markFld = v(ctx, "_mkf");
8306
8395
  const spV = v(ctx, "_sp");
8307
8396
  stmts.push(
8308
8397
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8309
8398
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8310
8399
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8311
8400
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8401
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8312
8402
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8313
8403
  );
8314
8404
  sepAtPos = spV;
8315
- 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}; `;
8405
+ 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}; `;
8316
8406
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8317
8407
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8318
8408
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8350,16 +8440,18 @@ function emitSepBy(_p, def, ctx, pos) {
8350
8440
  } else {
8351
8441
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8352
8442
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8443
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8353
8444
  if (markLv) {
8354
8445
  stmts.push(
8355
8446
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8356
- `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
8447
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8448
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`
8357
8449
  );
8358
8450
  }
8359
8451
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8360
8452
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8361
8453
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8362
- const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; ` : "";
8454
+ const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; ` : "";
8363
8455
  const post = postSepMarks();
8364
8456
  stmts.push(...post.decl);
8365
8457
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8429,7 +8521,7 @@ function emitScanTo(def, ctx, pos) {
8429
8521
  return { stmts, valueVar: valV, endVar: curV };
8430
8522
  }
8431
8523
  function emitNot(def, ctx, pos) {
8432
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8524
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8433
8525
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8434
8526
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8435
8527
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8468,6 +8560,17 @@ function emitPeek(def, ctx, pos) {
8468
8560
  };
8469
8561
  }
8470
8562
  function emitRouted(ctx, pos) {
8563
+ const local = ctx.routedLocal;
8564
+ if (local !== void 0) {
8565
+ return {
8566
+ stmts: [
8567
+ ...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
8568
+ ...emitLeafCapture(ctx, local.valueVar, local.startVar, local.endVar)
8569
+ ],
8570
+ valueVar: local.valueVar,
8571
+ endVar: local.endVar
8572
+ };
8573
+ }
8471
8574
  const item = v(ctx, "_rt");
8472
8575
  return {
8473
8576
  stmts: [
@@ -8619,14 +8722,20 @@ function emitLeaf(def, ctx, pos) {
8619
8722
  endVar: inner.endVar
8620
8723
  };
8621
8724
  }
8725
+ function emitNodeProjectExpr(type, project, chV) {
8726
+ const child = `${chV}[${project}]`;
8727
+ const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
8728
+ const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
8729
+ return `(${project} in ${chV} ? ${value} : ${missing})`;
8730
+ }
8622
8731
  function emitNode(def, ctx, pos) {
8623
8732
  if (def.type === void 0) {
8624
8733
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
8625
8734
  }
8626
- const structural = def.build === void 0;
8627
- const mkType = structural ? null : analyzeMkInlineBuild(def);
8735
+ const structural = def.build === void 0 && def.project === void 0;
8736
+ const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
8628
8737
  let buildIdx = null;
8629
- if (!mkType && !structural) {
8738
+ if (!mkType && !structural && def.project === void 0) {
8630
8739
  buildIdx = ctx.buildFns.length;
8631
8740
  ctx.buildFns.push(def.build);
8632
8741
  ctx.buildSrcs.push(def.buildSrc ?? null);
@@ -8634,12 +8743,13 @@ function emitNode(def, ctx, pos) {
8634
8743
  const i = ind(ctx);
8635
8744
  const cstOut = ctx.hostMode === "cst" && !structural;
8636
8745
  if (!structural && !cstOut) ctx.hostBranchElided = true;
8637
- const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
8638
- const clonesState = !structural && (cstOut || buildReadsState(def));
8639
- const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
8640
- const capturesRaw = !structural && (cstOut || mkType !== null || buildReadsRaw(def));
8746
+ const hasProject = def.project !== void 0;
8747
+ const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
8748
+ const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
8749
+ const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
8750
+ const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
8641
8751
  const hasFields = parserHasOwnFields(def.parser);
8642
- const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
8752
+ const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
8643
8753
  const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
8644
8754
  const chV = v(ctx, "_ch");
8645
8755
  const rawV = v(ctx, "_raw");
@@ -8737,7 +8847,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8737
8847
  );
8738
8848
  }
8739
8849
  const ndV = v(ctx, "_nd");
8740
- const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8850
+ const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8741
8851
  const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8742
8852
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8743
8853
  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;
@@ -8956,6 +9066,9 @@ function emitDispatch(p, ctx, pos) {
8956
9066
  return emitSepBy(p, def, ctx, pos);
8957
9067
  case "transform": {
8958
9068
  const fnSrc = transformFnSource(def.fn, def.fnSrc);
9069
+ if (fnSrc && def.parser._def.tag === "dispatch" && isDispatchTailOnlyTransform(fnSrc)) {
9070
+ return emitDispatchCombinator(def.parser, def.parser._def, ctx, pos, "tail");
9071
+ }
8959
9072
  if (fnSrc && def.parser._def.tag === "sequence") {
8960
9073
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8961
9074
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9645,8 +9758,8 @@ function assertRuleName(name) {
9645
9758
  );
9646
9759
  }
9647
9760
  }
9648
- function publicRuleWrapperSource(rule, fnSource) {
9649
- const labels = rule._meta.triviaKindLabels;
9761
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9762
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9650
9763
  if (labels === void 0) return fnSource;
9651
9764
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9652
9765
  }
@@ -9815,7 +9928,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9815
9928
  ...r.stmts,
9816
9929
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9817
9930
  `}`
9818
- ].join("\n")));
9931
+ ].join("\n"), ctx.triviaKindLabels));
9819
9932
  }
9820
9933
  const firstSets = /* @__PURE__ */ new Map();
9821
9934
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10022,6 +10135,10 @@ function repeatOpts(min, max, trailing) {
10022
10135
  if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
10023
10136
  return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
10024
10137
  }
10138
+ function projectOpt(project) {
10139
+ if (project === void 0) return void 0;
10140
+ return `project: ${project}`;
10141
+ }
10025
10142
  function matcherExpr(entry) {
10026
10143
  switch (entry.kind) {
10027
10144
  case "startsWith":
@@ -10415,9 +10532,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10415
10532
  }
10416
10533
  case "node": {
10417
10534
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10535
+ const projectEntry = projectOpt(def.project);
10418
10536
  const optEntries = [
10419
10537
  ...def.unwrap ? ["unwrap: true"] : [],
10420
10538
  ...def.collapse ? ["collapse: true"] : [],
10539
+ ...projectEntry === void 0 ? [] : [projectEntry],
10421
10540
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10422
10541
  ...def.trailingTrivia ? ["trailingTrivia: true"] : []
10423
10542
  ];
@@ -11327,8 +11446,158 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11327
11446
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11328
11447
  }
11329
11448
 
11449
+ // src/cst/trivia-entries.ts
11450
+ var EMPTY_INDICES = Object.freeze([]);
11451
+ var EMPTY_GAPS = Object.freeze([]);
11452
+ function entryOffset(i, stride) {
11453
+ return i * stride;
11454
+ }
11455
+ function triviaEntries(log, labels, opts) {
11456
+ const baseStride = opts?.nodeLog ? 3 : 2;
11457
+ const stride = labels ? baseStride + 1 : baseStride;
11458
+ const length = Math.floor(log.length / stride);
11459
+ return {
11460
+ length,
11461
+ labels,
11462
+ stride,
11463
+ start(i) {
11464
+ return log[entryOffset(i, stride)];
11465
+ },
11466
+ end(i) {
11467
+ return log[entryOffset(i, stride) + 1];
11468
+ },
11469
+ insertIndex(i) {
11470
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11471
+ },
11472
+ kindIndex(i) {
11473
+ if (!labels) return void 0;
11474
+ return log[entryOffset(i, stride) + baseStride];
11475
+ },
11476
+ kind(i) {
11477
+ const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11478
+ return ki !== void 0 ? labels[ki] : void 0;
11479
+ },
11480
+ text(i, input) {
11481
+ const s = log[entryOffset(i, stride)];
11482
+ const e = log[entryOffset(i, stride) + 1];
11483
+ return input.slice(s, e);
11484
+ }
11485
+ };
11486
+ }
11487
+ function appendEntryRange(map, key, first, last) {
11488
+ let indices = map.get(key);
11489
+ if (!indices) {
11490
+ indices = [];
11491
+ map.set(key, indices);
11492
+ }
11493
+ for (let i = first; i <= last; i++) indices.push(i);
11494
+ }
11495
+ function buildGap(entries, start, end, first, last) {
11496
+ const entryIndices = [];
11497
+ for (let i = first; i <= last; i++) entryIndices.push(i);
11498
+ return {
11499
+ start,
11500
+ end,
11501
+ entryIndices,
11502
+ hasKind(kind) {
11503
+ for (const i of entryIndices) {
11504
+ if (entries.kind(i) === kind) return true;
11505
+ }
11506
+ return false;
11507
+ },
11508
+ text(input) {
11509
+ return input.slice(start, end);
11510
+ }
11511
+ };
11512
+ }
11513
+ function buildRootMaps(entries) {
11514
+ const before = /* @__PURE__ */ new Map();
11515
+ const after = /* @__PURE__ */ new Map();
11516
+ const beforeGaps = /* @__PURE__ */ new Map();
11517
+ const afterGaps = /* @__PURE__ */ new Map();
11518
+ const gaps = [];
11519
+ if (entries.length === 0) return { before, after, beforeGaps, afterGaps, gaps };
11520
+ const appendGap = (first2, last, start2, end2) => {
11521
+ const gap = buildGap(entries, start2, end2, first2, last);
11522
+ gaps.push(gap);
11523
+ afterGaps.set(start2, gap);
11524
+ beforeGaps.set(end2, gap);
11525
+ appendEntryRange(after, start2, first2, last);
11526
+ appendEntryRange(before, end2, first2, last);
11527
+ };
11528
+ let first = 0;
11529
+ let start = entries.start(0);
11530
+ let end = entries.end(0);
11531
+ for (let i = 1; i < entries.length; i++) {
11532
+ const nextStart = entries.start(i);
11533
+ const nextEnd = entries.end(i);
11534
+ if (nextStart === end) {
11535
+ end = nextEnd;
11536
+ continue;
11537
+ }
11538
+ appendGap(first, i - 1, start, end);
11539
+ first = i;
11540
+ start = nextStart;
11541
+ end = nextEnd;
11542
+ }
11543
+ appendGap(first, entries.length - 1, start, end);
11544
+ return { before, after, beforeGaps, afterGaps, gaps };
11545
+ }
11546
+ function buildRootTriviaIndex(log, labels) {
11547
+ const entries = triviaEntries(log, labels);
11548
+ let maps;
11549
+ const getMaps = () => {
11550
+ maps ??= buildRootMaps(entries);
11551
+ return maps;
11552
+ };
11553
+ return {
11554
+ entries,
11555
+ labels,
11556
+ get before() {
11557
+ return getMaps().before;
11558
+ },
11559
+ get after() {
11560
+ return getMaps().after;
11561
+ },
11562
+ entryIndicesBefore(offset) {
11563
+ return getMaps().before.get(offset) ?? EMPTY_INDICES;
11564
+ },
11565
+ entryIndicesAfter(offset) {
11566
+ return getMaps().after.get(offset) ?? EMPTY_INDICES;
11567
+ },
11568
+ gapBefore(offset) {
11569
+ return getMaps().beforeGaps.get(offset);
11570
+ },
11571
+ gapAfter(offset) {
11572
+ return getMaps().afterGaps.get(offset);
11573
+ },
11574
+ gaps() {
11575
+ return getMaps().gaps;
11576
+ },
11577
+ gapsWithKind(kind) {
11578
+ const kinds = typeof kind === "string" ? [kind] : kind;
11579
+ const matches2 = [];
11580
+ for (const gap of getMaps().gaps) {
11581
+ for (const k of kinds) {
11582
+ if (gap.hasKind(k)) {
11583
+ matches2.push(gap);
11584
+ break;
11585
+ }
11586
+ }
11587
+ }
11588
+ return matches2.length === 0 ? EMPTY_GAPS : matches2;
11589
+ }
11590
+ };
11591
+ }
11592
+
11330
11593
  // src/functional/run.ts
11331
11594
  var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
11595
+ function triviaKindLabelsFromRunnable(r) {
11596
+ if (!r) return void 0;
11597
+ if (typeof r === "function") return r._meta?.triviaKindLabels;
11598
+ const grammarTrivia = r._meta.grammarTrivia;
11599
+ return r._meta.triviaKindLabels ?? grammarTrivia?._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
11600
+ }
11332
11601
  function runOnce(entry, input, options, phase, profileState) {
11333
11602
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
11334
11603
  throw new TypeError(
@@ -11341,6 +11610,7 @@ function runOnce(entry, input, options, phase, profileState) {
11341
11610
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
11342
11611
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
11343
11612
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
11613
+ const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
11344
11614
  const stamped = entry;
11345
11615
  assertHostModeCompatible(
11346
11616
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -11352,7 +11622,7 @@ function runOnce(entry, input, options, phase, profileState) {
11352
11622
  ...skipGlobalSinks ? { _pmProfile: profile } : { _triviaLog: triviaLog, _errors: errors, ...profile === void 0 ? {} : { _pmProfile: profile } },
11353
11623
  build: options.build,
11354
11624
  state: options.state,
11355
- ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
11625
+ ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
11356
11626
  ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
11357
11627
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
11358
11628
  ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
@@ -11375,6 +11645,8 @@ function runOnce(entry, input, options, phase, profileState) {
11375
11645
  expected: r.ok ? [] : r.expected ?? [],
11376
11646
  errors,
11377
11647
  triviaLog,
11648
+ ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
11649
+ triviaMap: buildRootTriviaIndex(triviaLog, triviaKindLabels),
11378
11650
  unconsumedFrom
11379
11651
  };
11380
11652
  }
@@ -11697,7 +11969,7 @@ function coverageEntry(entry, collector, maps, trace) {
11697
11969
  case "peek":
11698
11970
  return peek(build(def.parser));
11699
11971
  case "node": {
11700
- const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
11972
+ const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.project !== void 0 ? { project: def.project } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
11701
11973
  return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
11702
11974
  }
11703
11975
  case "guard":
@@ -11833,43 +12105,6 @@ function createVisitor(handlers) {
11833
12105
  return (node2) => api.visit(node2);
11834
12106
  }
11835
12107
 
11836
- // src/cst/trivia-entries.ts
11837
- function entryOffset(i, stride) {
11838
- return i * stride;
11839
- }
11840
- function triviaEntries(log, labels, opts) {
11841
- const baseStride = opts?.nodeLog ? 3 : 2;
11842
- const stride = labels ? baseStride + 1 : baseStride;
11843
- const length = Math.floor(log.length / stride);
11844
- return {
11845
- length,
11846
- labels,
11847
- stride,
11848
- start(i) {
11849
- return log[entryOffset(i, stride)];
11850
- },
11851
- end(i) {
11852
- return log[entryOffset(i, stride) + 1];
11853
- },
11854
- insertIndex(i) {
11855
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11856
- },
11857
- kindIndex(i) {
11858
- if (!labels) return void 0;
11859
- return log[entryOffset(i, stride) + baseStride];
11860
- },
11861
- kind(i) {
11862
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11863
- return ki !== void 0 ? labels[ki] : void 0;
11864
- },
11865
- text(i, input) {
11866
- const s = log[entryOffset(i, stride)];
11867
- const e = log[entryOffset(i, stride) + 1];
11868
- return input.slice(s, e);
11869
- }
11870
- };
11871
- }
11872
-
11873
12108
  // src/cst/offset-model.ts
11874
12109
  var { isFinite } = Number;
11875
12110
  function floorIndex(arr, len, x) {