parseman 0.40.0 → 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.
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":
@@ -3478,7 +3481,7 @@ function leaf(root, fn) {
3478
3481
  }
3479
3482
 
3480
3483
  // src/version.ts
3481
- var PARSEMAN_VERSION = "0.40.0";
3484
+ var PARSEMAN_VERSION = "0.41.0";
3482
3485
 
3483
3486
  // src/cst/host-mode.ts
3484
3487
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -6422,7 +6425,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6422
6425
  ` if (${m.end} > _e) {`,
6423
6426
  ` if (_cap) {`,
6424
6427
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6425
- ` 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})`,
6426
6429
  ` }`,
6427
6430
  ` _e = ${m.end}`,
6428
6431
  ` continue`,
@@ -6478,7 +6481,7 @@ function analyzeTriviaFastPath(trivia2) {
6478
6481
  var CAP_RECORD = [
6479
6482
  ` if (_cap && _e > _pos) {`,
6480
6483
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6481
- ` 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)`,
6482
6485
  ` }`
6483
6486
  ].join("\n");
6484
6487
  function composeFastLoop(shapes) {
@@ -6538,7 +6541,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6538
6541
  ` const _ce = _e + _m${i}[0].length`,
6539
6542
  ` if (_cap) {`,
6540
6543
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6541
- ` 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})`,
6542
6545
  ` }`,
6543
6546
  ` _e = _ce`,
6544
6547
  ` _matched = true`,
@@ -6576,7 +6579,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6576
6579
  ` const _ce = _r${i}.span.end`,
6577
6580
  ` if (_cap) {`,
6578
6581
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6579
- ` 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})`,
6580
6583
  ` }`,
6581
6584
  ` _e = _ce`,
6582
6585
  ` _matched = true`,
@@ -6662,6 +6665,9 @@ function transformFnSource(fn, fnSrc) {
6662
6665
  function replaceParam(body, param, valueVar) {
6663
6666
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6664
6667
  }
6668
+ function hasExplicitObjectKey(body, param) {
6669
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6670
+ }
6665
6671
  function stripForIdCheck(body) {
6666
6672
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6667
6673
  }
@@ -6704,10 +6710,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6704
6710
  const allowed = new Set(valueVars);
6705
6711
  for (let i = 0; i < slots.length; i++) {
6706
6712
  const name = slots[i];
6707
- 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]);
6708
6716
  }
6709
6717
  return hasFreeIdentifiers(body, allowed) ? null : body;
6710
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
+ }
6711
6726
 
6712
6727
  // src/compiler/codegen.ts
6713
6728
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6958,6 +6973,17 @@ function ensureRegexDecl(ctx, source, flags) {
6958
6973
  }
6959
6974
  return rName;
6960
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
+ }
6961
6987
  function ensureTriviaFn(ctx) {
6962
6988
  const trivia2 = ctx.activeTrivia;
6963
6989
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -7023,7 +7049,7 @@ function ensureTriviaFn(ctx) {
7023
7049
  ` }`,
7024
7050
  ` if (_cap && _e > _pos) {`,
7025
7051
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
7026
- ` 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)`,
7027
7053
  ` }`,
7028
7054
  ` return _e`,
7029
7055
  `}`
@@ -7484,14 +7510,19 @@ function emitSeqValues(def, ctx, pos) {
7484
7510
  continue;
7485
7511
  } else {
7486
7512
  const trivFn = ensureTriviaFn(ctx);
7513
+ const markLog = v(ctx, "_mklg");
7487
7514
  const scanEndV = v(ctx, "_sne");
7488
- 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
+ );
7489
7520
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7490
7521
  stmts.push(...r2.stmts);
7491
7522
  const endAfterV = v(ctx, "_sea");
7492
7523
  stmts.push(
7493
7524
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7494
- `${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}`
7495
7526
  );
7496
7527
  valueVars.push(r2.valueVar);
7497
7528
  continue;
@@ -7721,19 +7752,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7721
7752
  return false;
7722
7753
  }
7723
7754
  }
7724
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7755
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7725
7756
  if (parserUsesRouted2(def.selector)) {
7726
7757
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7727
7758
  }
7728
7759
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7729
7760
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7730
7761
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7731
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7732
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7733
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7734
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7735
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7736
- 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;
7737
7769
  const selector = emit(def.selector, ctx, pos);
7738
7770
  const outV = v(ctx, "_dval");
7739
7771
  const outE = v(ctx, "_dend");
@@ -7758,13 +7790,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7758
7790
  stmts.push(head);
7759
7791
  ctx.indent++;
7760
7792
  const usesRouted = branchUsesRouted2(entry);
7761
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7793
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7794
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7762
7795
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7763
7796
  const errMark = mayError ? v(ctx, "_derr") : null;
7764
7797
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7765
- if (routedV) {
7798
+ if (usesRouted) {
7766
7799
  stmts.push(
7767
- `${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} } }`] : [],
7768
7801
  ...selectorLeafMark ? [
7769
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}`
7770
7803
  ] : []
@@ -7772,7 +7805,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7772
7805
  }
7773
7806
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7774
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
+ }
7775
7816
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
7817
+ ctx.routedLocal = savedRoutedLocal;
7818
+ ctx.noHoist = savedNoHoist;
7776
7819
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7777
7820
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7778
7821
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7782,7 +7825,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7782
7825
  ...tail.stmts,
7783
7826
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7784
7827
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7785
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
7828
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7786
7829
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7787
7830
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7788
7831
  );
@@ -7797,7 +7840,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7797
7840
  }
7798
7841
  const emitMatcherTails = () => {
7799
7842
  for (const matcher of def.matchers ?? []) {
7800
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
7843
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7801
7844
  wroteBranch = true;
7802
7845
  }
7803
7846
  };
@@ -7822,10 +7865,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7822
7865
  }
7823
7866
  return parts.join(" && ");
7824
7867
  }
7825
- function emitDispatchMatcherCondition(valueVar, matcher) {
7868
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7826
7869
  if (matcher.kind === "matches") {
7827
7870
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7828
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
7871
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7829
7872
  }
7830
7873
  const text = matcher.value;
7831
7874
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -8028,6 +8071,28 @@ function emitsAsNamedFn(p, ctx) {
8028
8071
  const usage = ctx.lazyUsage;
8029
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;
8030
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
+ }
8031
8096
  function armReplayInScope(arm, ctx) {
8032
8097
  let p = arm;
8033
8098
  for (; ; ) {
@@ -8278,15 +8343,16 @@ function emitSepBy(_p, def, ctx, pos) {
8278
8343
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8279
8344
  const postSepMarks = () => {
8280
8345
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8281
- 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");
8282
8347
  return {
8283
8348
  decl: [
8284
8349
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8285
8350
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8286
8351
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8287
- `${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`
8288
8354
  ],
8289
- 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}; `
8290
8356
  };
8291
8357
  };
8292
8358
  if (rec) {
@@ -8325,16 +8391,18 @@ function emitSepBy(_p, def, ctx, pos) {
8325
8391
  const markTl = v(ctx, "_mktl");
8326
8392
  const markLog = v(ctx, "_mklg");
8327
8393
  const markLv = v(ctx, "_mklv");
8394
+ const markFld = v(ctx, "_mkf");
8328
8395
  const spV = v(ctx, "_sp");
8329
8396
  stmts.push(
8330
8397
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8331
8398
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8332
8399
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8333
8400
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8401
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8334
8402
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8335
8403
  );
8336
8404
  sepAtPos = spV;
8337
- 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}; `;
8338
8406
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8339
8407
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8340
8408
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8372,16 +8440,18 @@ function emitSepBy(_p, def, ctx, pos) {
8372
8440
  } else {
8373
8441
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8374
8442
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8443
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8375
8444
  if (markLv) {
8376
8445
  stmts.push(
8377
8446
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8378
- `${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`
8379
8449
  );
8380
8450
  }
8381
8451
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8382
8452
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8383
8453
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8384
- 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}; ` : "";
8385
8455
  const post = postSepMarks();
8386
8456
  stmts.push(...post.decl);
8387
8457
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8451,7 +8521,7 @@ function emitScanTo(def, ctx, pos) {
8451
8521
  return { stmts, valueVar: valV, endVar: curV };
8452
8522
  }
8453
8523
  function emitNot(def, ctx, pos) {
8454
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8524
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8455
8525
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8456
8526
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8457
8527
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8490,6 +8560,17 @@ function emitPeek(def, ctx, pos) {
8490
8560
  };
8491
8561
  }
8492
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
+ }
8493
8574
  const item = v(ctx, "_rt");
8494
8575
  return {
8495
8576
  stmts: [
@@ -8985,6 +9066,9 @@ function emitDispatch(p, ctx, pos) {
8985
9066
  return emitSepBy(p, def, ctx, pos);
8986
9067
  case "transform": {
8987
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
+ }
8988
9072
  if (fnSrc && def.parser._def.tag === "sequence") {
8989
9073
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8990
9074
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9674,8 +9758,8 @@ function assertRuleName(name) {
9674
9758
  );
9675
9759
  }
9676
9760
  }
9677
- function publicRuleWrapperSource(rule, fnSource) {
9678
- const labels = rule._meta.triviaKindLabels;
9761
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9762
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9679
9763
  if (labels === void 0) return fnSource;
9680
9764
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9681
9765
  }
@@ -9844,7 +9928,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9844
9928
  ...r.stmts,
9845
9929
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9846
9930
  `}`
9847
- ].join("\n")));
9931
+ ].join("\n"), ctx.triviaKindLabels));
9848
9932
  }
9849
9933
  const firstSets = /* @__PURE__ */ new Map();
9850
9934
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -11362,8 +11446,158 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11362
11446
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11363
11447
  }
11364
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
+
11365
11593
  // src/functional/run.ts
11366
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
+ }
11367
11601
  function runOnce(entry, input, options, phase, profileState) {
11368
11602
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
11369
11603
  throw new TypeError(
@@ -11376,6 +11610,7 @@ function runOnce(entry, input, options, phase, profileState) {
11376
11610
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
11377
11611
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
11378
11612
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
11613
+ const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
11379
11614
  const stamped = entry;
11380
11615
  assertHostModeCompatible(
11381
11616
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -11387,7 +11622,7 @@ function runOnce(entry, input, options, phase, profileState) {
11387
11622
  ...skipGlobalSinks ? { _pmProfile: profile } : { _triviaLog: triviaLog, _errors: errors, ...profile === void 0 ? {} : { _pmProfile: profile } },
11388
11623
  build: options.build,
11389
11624
  state: options.state,
11390
- ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
11625
+ ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
11391
11626
  ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
11392
11627
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
11393
11628
  ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
@@ -11410,6 +11645,8 @@ function runOnce(entry, input, options, phase, profileState) {
11410
11645
  expected: r.ok ? [] : r.expected ?? [],
11411
11646
  errors,
11412
11647
  triviaLog,
11648
+ ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
11649
+ triviaMap: buildRootTriviaIndex(triviaLog, triviaKindLabels),
11413
11650
  unconsumedFrom
11414
11651
  };
11415
11652
  }
@@ -11868,43 +12105,6 @@ function createVisitor(handlers) {
11868
12105
  return (node2) => api.visit(node2);
11869
12106
  }
11870
12107
 
11871
- // src/cst/trivia-entries.ts
11872
- function entryOffset(i, stride) {
11873
- return i * stride;
11874
- }
11875
- function triviaEntries(log, labels, opts) {
11876
- const baseStride = opts?.nodeLog ? 3 : 2;
11877
- const stride = labels ? baseStride + 1 : baseStride;
11878
- const length = Math.floor(log.length / stride);
11879
- return {
11880
- length,
11881
- labels,
11882
- stride,
11883
- start(i) {
11884
- return log[entryOffset(i, stride)];
11885
- },
11886
- end(i) {
11887
- return log[entryOffset(i, stride) + 1];
11888
- },
11889
- insertIndex(i) {
11890
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11891
- },
11892
- kindIndex(i) {
11893
- if (!labels) return void 0;
11894
- return log[entryOffset(i, stride) + baseStride];
11895
- },
11896
- kind(i) {
11897
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11898
- return ki !== void 0 ? labels[ki] : void 0;
11899
- },
11900
- text(i, input) {
11901
- const s = log[entryOffset(i, stride)];
11902
- const e = log[entryOffset(i, stride) + 1];
11903
- return input.slice(s, e);
11904
- }
11905
- };
11906
- }
11907
-
11908
12108
  // src/cst/offset-model.ts
11909
12109
  var { isFinite } = Number;
11910
12110
  function floorIndex(arr, len, x) {