parseman 0.56.0 → 0.57.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 (75) hide show
  1. package/dist/analysis/diagnostics.js +379 -72
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +379 -72
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/node.d.ts +1 -1
  6. package/dist/compiler/build-arity.d.ts +1 -1
  7. package/dist/compiler/build-arity.d.ts.map +1 -1
  8. package/dist/cst/trivia-kinds.d.ts +9 -1
  9. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  10. package/dist/index.js +446 -75
  11. package/dist/index.js.map +3 -3
  12. package/dist/language-service/index.js +1 -0
  13. package/dist/language-service/index.js.map +1 -1
  14. package/dist/parse-context.d.ts.map +1 -1
  15. package/dist/plugin/entry-supercompiler.d.ts +1 -1
  16. package/dist/plugin/entry-supercompiler.d.ts.map +1 -1
  17. package/dist/plugin/index.d.ts +27 -1
  18. package/dist/plugin/index.d.ts.map +1 -1
  19. package/dist/plugin/index.js +930 -157
  20. package/dist/plugin/index.js.map +3 -3
  21. package/dist/plugin/ir-eval.d.ts +2 -0
  22. package/dist/plugin/ir-eval.d.ts.map +1 -1
  23. package/dist/regex/classes.d.ts.map +1 -1
  24. package/dist/run/index.js +1 -0
  25. package/dist/run/index.js.map +1 -1
  26. package/dist/table/assemble.d.ts +9 -0
  27. package/dist/table/assemble.d.ts.map +1 -1
  28. package/dist/table/child-slots.d.ts +4 -6
  29. package/dist/table/child-slots.d.ts.map +1 -1
  30. package/dist/table/compile-rule-map.d.ts +14 -2
  31. package/dist/table/compile-rule-map.d.ts.map +1 -1
  32. package/dist/table/emit-assembly.d.ts +17 -2
  33. package/dist/table/emit-assembly.d.ts.map +1 -1
  34. package/dist/table/emit.d.ts +5 -1
  35. package/dist/table/emit.d.ts.map +1 -1
  36. package/dist/table/encode.d.ts.map +1 -1
  37. package/dist/table/exec-baseline.d.ts.map +1 -1
  38. package/dist/table/exec.d.ts.map +1 -1
  39. package/dist/table/index.js +442 -70
  40. package/dist/table/index.js.map +3 -3
  41. package/dist/table/ops.d.ts +9 -6
  42. package/dist/table/ops.d.ts.map +1 -1
  43. package/dist/table/program.d.ts +13 -0
  44. package/dist/table/program.d.ts.map +1 -1
  45. package/dist/table/select-hot.d.ts +6 -0
  46. package/dist/table/select-hot.d.ts.map +1 -0
  47. package/dist/table/trivia-gap.d.ts +31 -0
  48. package/dist/table/trivia-gap.d.ts.map +1 -0
  49. package/dist/types.d.ts +17 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/version.d.ts +1 -1
  52. package/package.json +4 -1
  53. package/src/combinators/node.ts +6 -13
  54. package/src/combinators/trivia-skip.ts +44 -1
  55. package/src/compiler/build-arity.ts +3 -3
  56. package/src/cst/trivia-kinds.ts +12 -1
  57. package/src/parse-context.ts +1 -0
  58. package/src/plugin/entry-supercompiler.ts +8 -9
  59. package/src/plugin/index.ts +138 -13
  60. package/src/plugin/ir-eval.ts +7 -1
  61. package/src/regex/classes.ts +3 -0
  62. package/src/table/assemble.ts +122 -24
  63. package/src/table/child-slots.ts +4 -6
  64. package/src/table/compile-rule-map.ts +55 -15
  65. package/src/table/emit-assembly.ts +139 -26
  66. package/src/table/emit.ts +8 -7
  67. package/src/table/encode.ts +69 -21
  68. package/src/table/exec-baseline.ts +1 -3
  69. package/src/table/exec.ts +7 -6
  70. package/src/table/ops.ts +9 -6
  71. package/src/table/program.ts +24 -0
  72. package/src/table/select-hot.ts +70 -0
  73. package/src/table/trivia-gap.ts +109 -0
  74. package/src/types.ts +18 -0
  75. package/src/version.ts +1 -1
@@ -707,6 +707,7 @@ function literalCodePoints(frag) {
707
707
  if (ch2 === "\\") {
708
708
  const e = frag[i + 1];
709
709
  if (e === void 0) return null;
710
+ if (!(e in CLASS_ESCAPES) && /\w/.test(e)) return null;
710
711
  out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
711
712
  i += 2;
712
713
  continue;
@@ -819,6 +820,7 @@ function createParseContext() {
819
820
  _rootTriviaKindIndex: void 0,
820
821
  _rootTriviaStrictScopes: void 0,
821
822
  _rootTriviaCapture: void 0,
823
+ _gap: void 0,
822
824
  _cstTriviaLog: void 0,
823
825
  _fields: void 0,
824
826
  _cstBuf: void 0,
@@ -1301,7 +1303,10 @@ function labeledTriviaSpec(arms, minRepeats) {
1301
1303
  arms,
1302
1304
  minRepeats,
1303
1305
  visitor: commonLabeledTriviaVisitor({ arms, minRepeats }),
1304
- charArms: charArmsFor({ arms, minRepeats })
1306
+ charArms: charArmsFor({ arms, minRepeats }),
1307
+ rootKinds: void 0,
1308
+ rootLeaders: [],
1309
+ rootScan: null
1305
1310
  };
1306
1311
  }
1307
1312
  function matchArmAt(input, pos, arm, state) {
@@ -1761,8 +1766,50 @@ function loopScanner(arms) {
1761
1766
  function regexTriviaScanner(parser2) {
1762
1767
  const d = parser2._def.tag === "label" ? parser2._def.parser._def : parser2._def;
1763
1768
  if (d.tag !== "regex" || d.flags) return null;
1764
- const source = d.source;
1765
- return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source);
1769
+ return sourceScanner(d.source);
1770
+ }
1771
+ function sourceScanner(source) {
1772
+ return classRunSource(source) ?? altStarSource(source) ?? prefixRunSource(source) ?? delimitedSource(source) ?? sharedPrefixAltSource(source);
1773
+ }
1774
+ function sharedPrefixAltSource(source) {
1775
+ const m = /^((?:\\.|[^\\[\]()*+?|^$.{}])+)\(\?:(.*)\)$/.exec(source);
1776
+ if (!m) return null;
1777
+ const alts = [];
1778
+ const body = m[2];
1779
+ let depth = 0;
1780
+ let start = 0;
1781
+ for (let i = 0; i < body.length; i++) {
1782
+ const c = body[i];
1783
+ if (c === "\\") {
1784
+ i++;
1785
+ continue;
1786
+ }
1787
+ if (c === "[") {
1788
+ while (i < body.length && body[i] !== "]") i += body[i] === "\\" ? 2 : 1;
1789
+ continue;
1790
+ }
1791
+ if (c === "(") depth++;
1792
+ else if (c === ")" && --depth < 0) return null;
1793
+ else if (c === "|" && depth === 0) {
1794
+ alts.push(body.slice(start, i));
1795
+ start = i + 1;
1796
+ }
1797
+ }
1798
+ if (depth !== 0 || alts.length === 0) return null;
1799
+ alts.push(body.slice(start));
1800
+ const scanners = [];
1801
+ for (const alt of alts) {
1802
+ const scanner = sourceScanner(m[1] + alt);
1803
+ if (scanner === null) return null;
1804
+ scanners.push(scanner);
1805
+ }
1806
+ return (input, cur) => {
1807
+ for (const scanner of scanners) {
1808
+ const end = scanner(input, cur);
1809
+ if (end > cur) return end;
1810
+ }
1811
+ return cur;
1812
+ };
1766
1813
  }
1767
1814
  function bmpString(cps) {
1768
1815
  if (!cps) return null;
@@ -4208,6 +4255,12 @@ function scanRefs(s) {
4208
4255
  refs.push(...s.skip);
4209
4256
  return refs;
4210
4257
  }
4258
+ function assemblyExtraIps(prog) {
4259
+ const ips = [];
4260
+ for (const s of prog.scans ?? []) for (const r of scanRefs(s)) ips.push(r[0]);
4261
+ for (const set of prog.scanSkip ?? []) for (const r of set) ips.push(r[0]);
4262
+ return ips;
4263
+ }
4211
4264
  function expandCompact(p) {
4212
4265
  if ("code" in p) return p;
4213
4266
  return ownTableProgram({
@@ -4338,6 +4391,11 @@ function classHas2(cls, code) {
4338
4391
  for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
4339
4392
  return false;
4340
4393
  }
4394
+ function dispatchIsExclusive(arms, cc) {
4395
+ const resolved = [];
4396
+ for (const ci of arms) if (ci >= 0) resolved[ci] = resolveClass(cc[ci]);
4397
+ return resolveDispatch(arms, resolved).exclusive;
4398
+ }
4341
4399
  function resolveDispatch(arms, cc) {
4342
4400
  const ascii = new Uint8Array(128);
4343
4401
  const hi = [];
@@ -5442,7 +5500,7 @@ function confirmedArityForDef(def) {
5442
5500
  severity: "warn",
5443
5501
  where: `node("${def.type ?? "<inferred>"}")`,
5444
5502
  subject,
5445
- fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
5503
+ fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and hands it \`_ctx.state\` on every match`,
5446
5504
  otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
5447
5505
  });
5448
5506
  return null;
@@ -5818,7 +5876,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5818
5876
  }
5819
5877
  const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
5820
5878
  const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
5821
- const clonesState = build ? buildReadsState(def) : project === void 0;
5879
+ const readsState = build ? buildReadsState(def) : project === void 0;
5822
5880
  const hasOwnFields = parserHasOwnFields(combinator);
5823
5881
  const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
5824
5882
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
@@ -5859,12 +5917,11 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5859
5917
  ctx._triviaCaptureMask = savedMask;
5860
5918
  const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
5861
5919
  if (!r.ok) return r;
5862
- const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
5920
+ const st = readsState ? ctx.state : void 0;
5863
5921
  const nodeType = def.type ?? missingInferredType();
5864
5922
  const cstOutput = cstOutputHost(ctx.build);
5865
5923
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
5866
- const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
5867
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !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 };
5924
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !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, ctx.state, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, ctx.state, 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 };
5868
5925
  const rawEntry2 = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
5869
5926
  if (saved.buf !== void 0 || saved.ch !== void 0) {
5870
5927
  pushCstChild(ctx, built, rawEntry2);
@@ -6807,6 +6864,33 @@ var Encoder = class {
6807
6864
  return childrenOf(def);
6808
6865
  }
6809
6866
  }
6867
+ /**
6868
+ * THE FIRST-CHARACTER GATE OF AN `optional`, `not` OR `peek` CHILD.
6869
+ *
6870
+ * A non-nullable child cannot match at a character outside its first set, so
6871
+ * the wrapper's outcome there is already decided: `optional` yields `null`,
6872
+ * `not` succeeds, `peek` fails with its own set. The interpreter's `optional`
6873
+ * makes that test itself (`repeat.ts` `startsFirstSet`); the table entered the
6874
+ * child — a rollback mark, the call, the child's own failure — to learn it.
6875
+ *
6876
+ * The gate is an `OP_GATE` row around the child, so every engine runs it
6877
+ * unchanged, a probe or tolerant parse forwards through it as for a node's
6878
+ * gate, and the wrapper's row keeps its layout. The engines test the class
6879
+ * before taking the wrapper's mark. The first set is resolved through
6880
+ * `winners`, the analysis a choice arm's gate uses, so a composed rule's set
6881
+ * is the merged one. A scalar `not` child stays bare: `scalarTerminalNotChild`
6882
+ * already reduces it to one recognizer call.
6883
+ */
6884
+ lookaheadGate(p, child) {
6885
+ const op = this.code[child];
6886
+ if (op === OP_GATE || op === OP_LIT || op === OP_LIT_CI || op === OP_LIT_TRACK || op === OP_LIT_CI_TRACK || op === OP_RX || op === OP_RX_TRACK) return child;
6887
+ const rr = this.refResolver();
6888
+ if (matchesEmpty(p, /* @__PURE__ */ new Set(), rr)) return child;
6889
+ const cls = this.charClass(firstSetOf(p, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
6890
+ if (cls < 0) return child;
6891
+ const e = deriveExpected(p);
6892
+ return this.emit(OP_GATE, cls, child, this.expected(e.length > 0 ? e : [p._tag]));
6893
+ }
6810
6894
  /** A first set becomes a char class string, or −1 for `any`. */
6811
6895
  charClass(fs) {
6812
6896
  if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
@@ -6818,12 +6902,19 @@ var Encoder = class {
6818
6902
  this.ccIndex.set(spec, i);
6819
6903
  return i;
6820
6904
  }
6821
- /** Bind a guard only when its class is already part of the program. Repeat
6822
- * gating must not grow the compact artifact merely to avoid a failed call. */
6823
- existingCharClass(fs) {
6824
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
6825
- const hit = this.ccIndex.get(encodeClassSpec(fs.ranges));
6826
- return hit !== void 0 && hit < 100 ? hit : -1;
6905
+ /**
6906
+ * The first set a node's or an attempt's fail-fast gate tests. A bare
6907
+ * cross-rule ref resolves through `winners` (a compose OVERRIDE may widen
6908
+ * it). Any other body keeps its construction-time `_meta.firstSet`, except
6909
+ * where that is `any`: under `compose()` a body that reaches a rule of
6910
+ * another piece is built before that rule exists, so its cached set is
6911
+ * `any` and the node got NO gate (jess's `CompoundSelector` was entered at
6912
+ * `{`, `Call` at `}`). The resolved set is the one a choice arm's gate uses,
6913
+ * over the final merged map.
6914
+ */
6915
+ gateFirstSet(p) {
6916
+ const cached = p._meta.firstSet;
6917
+ return p._def.tag === "lazy" || cached.kind === "any" ? firstSetOf(p, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : cached;
6827
6918
  }
6828
6919
  /**
6829
6920
  * Wrap one choice arm in its `autoNot` checks (`OP_REJECT`).
@@ -7128,6 +7219,12 @@ var Encoder = class {
7128
7219
  if (transactionalFirst[i] !== void 0) classes[i] = -1;
7129
7220
  }
7130
7221
  }
7222
+ if (d.gates.some((g) => g !== null && g !== void 0) && !dispatchIsExclusive(classes, this.cc)) {
7223
+ for (let k = 0; k < classes.length; k++) {
7224
+ const gate = d.gates[order[k]];
7225
+ if (gate !== null && gate !== void 0) classes[k] = -1;
7226
+ }
7227
+ }
7131
7228
  const dispIdx = this.disp.length;
7132
7229
  this.disp.push(classes);
7133
7230
  let rollbackMask = kids.length > 31 ? -1 : 0;
@@ -7157,7 +7254,7 @@ var Encoder = class {
7157
7254
  case "oneOrMore": {
7158
7255
  const child = this.node(d.parser).ip;
7159
7256
  const rr = this.refResolver();
7160
- const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.existingCharClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7257
+ const itemClass = matchesEmpty(d.parser, /* @__PURE__ */ new Set(), rr) ? -1 : this.charClass(firstSetOf(d.parser, /* @__PURE__ */ new Set(), rr, this.activeTrivia));
7161
7258
  const op = d.valueUnused ? OP_REPV : OP_REP;
7162
7259
  const min = d.tag === "many" ? 0 : d.min;
7163
7260
  return this.rec ? this.emit(op, child, min, d.max ?? -1, -1, 0, this.expected(deriveExpected(d.parser)), itemClass) : this.emit(op, child, min, d.max ?? -1, -1, 0);
@@ -7181,7 +7278,7 @@ var Encoder = class {
7181
7278
  return d.min >= 2 ? this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags, this.expected(deriveExpected(d.parser))) : this.emit(OP_REP, child, d.min, d.max ?? -1, sep, flags);
7182
7279
  }
7183
7280
  case "optional": {
7184
- const head = this.emit(OP_OPT, this.node(d.parser).ip);
7281
+ const head = this.emit(OP_OPT, this.lookaheadGate(d.parser, this.node(d.parser).ip));
7185
7282
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(head);
7186
7283
  return head;
7187
7284
  }
@@ -7229,8 +7326,8 @@ var Encoder = class {
7229
7326
  // every CST node, so this is load-bearing, not reflection trivia.
7230
7327
  d.tags === void 0 ? -1 : this.constant(d.tags)
7231
7328
  );
7232
- if (matchesEmpty(d.parser)) return body;
7233
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
7329
+ if (matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return body;
7330
+ const fs = this.gateFirstSet(d.parser);
7234
7331
  if (fs.kind === "any") return body;
7235
7332
  const cls = this.charClass(fs);
7236
7333
  if (cls < 0) return body;
@@ -7322,7 +7419,7 @@ var Encoder = class {
7322
7419
  // other engine reported `['not(literal)']`. It hid because `expected` is a
7323
7420
  // TOP-LEVEL field on `RunResult` and is NOT part of the identity digest.
7324
7421
  case "not":
7325
- return this.emit(OP_NOT, this.node(d.parser).ip, this.expected(assertionFailureExpected(false, d.parser._tag)));
7422
+ return this.emit(OP_NOT, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(false, d.parser._tag)));
7326
7423
  case "guard":
7327
7424
  return this.emit(OP_GUARD, this.fn(d.predicate, d.predSrc ?? null), this.expected(["gate"]));
7328
7425
  case "adjacency":
@@ -7343,14 +7440,14 @@ var Encoder = class {
7343
7440
  return this.emit(OP_WITHCTX, this.constant(d.extra), this.node(d.parser).ip);
7344
7441
  }
7345
7442
  case "peek":
7346
- return this.emit(OP_PEEK, this.node(d.parser).ip, this.expected(assertionFailureExpected(true, d.parser._tag)));
7443
+ return this.emit(OP_PEEK, this.lookaheadGate(d.parser, this.node(d.parser).ip), this.expected(assertionFailureExpected(true, d.parser._tag)));
7347
7444
  // A TRANSACTION IS A ROW. See `OP_ATTEMPT` for why the transparent
7348
7445
  // lowering was correct only for a choice arm.
7349
7446
  case "attempt": {
7350
7447
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip, d.contain === true ? 1 : 0);
7351
7448
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7352
- const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
7353
- if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
7449
+ const fs = this.gateFirstSet(d.parser);
7450
+ if (fs.kind === "any" || matchesEmpty(d.parser, /* @__PURE__ */ new Set(), this.refResolver())) return inner;
7354
7451
  const cls = this.charClass(fs);
7355
7452
  if (cls < 0) return inner;
7356
7453
  const e = deriveExpected(d.parser);
@@ -9075,7 +9172,10 @@ var EMITTED_PARAMS = [
9075
9172
  // Appended for trivia-attributing fields (`field(…, { leadingTrivia })`);
9076
9173
  // old factories ignore them.
9077
9174
  "LEAD",
9078
- "triviaFieldCapture"
9175
+ "triviaFieldCapture",
9176
+ // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
9177
+ // factories ignore it.
9178
+ "skipDeferredTrivia"
9079
9179
  ];
9080
9180
  var RUNTIME_PRELUDE = `
9081
9181
  let _pfScan=null
@@ -9096,7 +9196,7 @@ function _skipTrivia(input,cur,ctx){
9096
9196
  const s=_pfScan
9097
9197
  if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
9098
9198
  if(s!==null)return skipTriviaScanned(s,input,cur,ctx)
9099
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
9199
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
9100
9200
  return advanceTrivia(input,cur,ctx)
9101
9201
  }
9102
9202
  function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,{_tag:'leaf',value,span:{start:s,end:e}})}
@@ -9303,7 +9403,7 @@ function rebuildPools(cc, fx, disp, plan) {
9303
9403
  })
9304
9404
  };
9305
9405
  }
9306
- function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9406
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select) {
9307
9407
  const { code, k, fx, disp, dsp, triviaLabelled } = t2;
9308
9408
  const swapLegal = !cfg.trackLines;
9309
9409
  const hostCst = cfg.hostCst;
@@ -9402,6 +9502,8 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9402
9502
  };
9403
9503
  const bodies = [];
9404
9504
  const byIp = /* @__PURE__ */ new Map();
9505
+ const externals = [];
9506
+ const siteBytes = /* @__PURE__ */ new Map();
9405
9507
  const reached = /* @__PURE__ */ new Set();
9406
9508
  const prelude = [];
9407
9509
  const skipDefs = [];
@@ -9537,6 +9639,18 @@ return 1
9537
9639
  tokenDecisionRefs.set(dispatchIp, made);
9538
9640
  return made;
9539
9641
  }
9642
+ function gateMissTest(gip) {
9643
+ const resolved = t2.cc[code[gip + 1]];
9644
+ const ci = classes.push([resolved]) - 1;
9645
+ classPlan.push([code[gip + 1]]);
9646
+ const cls = hoist("cl", `CLS[${ci}][0]`);
9647
+ return isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`;
9648
+ }
9649
+ function lookaheadMiss(child, miss) {
9650
+ if (code[child] !== OP_GATE || cfg.tolerant || cfg.probe) return "";
9651
+ return `if(${gateMissTest(child)}){${miss}}
9652
+ `;
9653
+ }
9540
9654
  function skipFor(l) {
9541
9655
  if (l.tri < 0) return "_skipTrivia";
9542
9656
  const ki = l.tri;
@@ -9547,8 +9661,8 @@ return 1
9547
9661
  const nm = `_sk${skipPool.size}`;
9548
9662
  skipPool.set(key, nm);
9549
9663
  if (!hasScan) {
9550
- skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return commitTriviaScan(scanTriviaCompact(input,cur,ctx))}` : `function ${nm}(input,cur,ctx){
9551
- if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
9664
+ skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
9665
+ if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
9552
9666
  return advanceTrivia(input,cur,ctx)}`);
9553
9667
  return nm;
9554
9668
  }
@@ -9593,9 +9707,17 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9593
9707
  const target = resolveAlias(ip);
9594
9708
  const done = byIp.get(target);
9595
9709
  if (done !== void 0) return done;
9710
+ if (select !== void 0 && !select.has(target)) {
9711
+ const ext = `_px${target}`;
9712
+ byIp.set(target, ext);
9713
+ externals.push(target);
9714
+ return ext;
9715
+ }
9596
9716
  const fname = `_pf${target}`;
9597
9717
  byIp.set(target, fname);
9598
- bodies.push(lower(target, fname));
9718
+ const body = lower(target, fname);
9719
+ siteBytes.set(target, body.length);
9720
+ bodies.push(body);
9599
9721
  return fname;
9600
9722
  }
9601
9723
  function resolveAlias(ip) {
@@ -9735,14 +9857,28 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9735
9857
  return `${head}EC.e=pos;return ''}`;
9736
9858
  case OP_GATE: {
9737
9859
  const child = link(code[ip + 2]);
9738
- const resolved = t2.cc[code[ip + 1]];
9739
- const ci = classes.push([resolved]) - 1;
9740
- classPlan.push([code[ip + 1]]);
9741
- const cls = hoist("cl", `CLS[${ci}][0]`);
9742
9860
  const xf = fxRef(code[ip + 3]);
9743
9861
  return `${head}
9744
- if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9862
+ if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9745
9863
  return ${child}(input,pos,ctx)
9864
+ }`;
9865
+ }
9866
+ case OP_ARMGATE: {
9867
+ const pred = fnRef(code[ip + 1]);
9868
+ const child = link(code[ip + 2]);
9869
+ const xf = fxRef(code[ip + 3]);
9870
+ return `${head}
9871
+ if(!${pred}(ctx.state)){ctx._fc=false;ctx._fe=-1;ctx._fx=${xf};return FAIL}
9872
+ return ${child}(input,pos,ctx)
9873
+ }`;
9874
+ }
9875
+ case OP_WITHCTX: {
9876
+ const ki = code[ip + 1];
9877
+ const child = link(code[ip + 2]);
9878
+ return `${head}
9879
+ const saved=ctx.state
9880
+ ctx.state=${ki < 0 ? `${fnRef(~ki)}(saved)` : kRef(ki)}
9881
+ try{return ${child}(input,pos,ctx)}finally{ctx.state=saved}
9746
9882
  }`;
9747
9883
  }
9748
9884
  case OP_XFORM: {
@@ -9998,7 +10134,7 @@ return FAIL
9998
10134
  const xf = fxRef(code[ip + 2]);
9999
10135
  const p = tmp();
10000
10136
  return `${head}
10001
- ${emitMark(p, L.buf, L.raw, sinks)}
10137
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
10002
10138
  const v=${child}(input,pos,ctx)
10003
10139
  ${emitRollback(p, L.buf, L.raw, sinks)}
10004
10140
  if(v===FAIL){EC.e=pos;return null}
@@ -10012,7 +10148,7 @@ return FAIL
10012
10148
  const xf = fxRef(code[ip + 2]);
10013
10149
  const p = tmp();
10014
10150
  return `${head}
10015
- ${emitMark(p, L.buf, L.raw, sinks)}
10151
+ ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
10016
10152
  const v=${child}(input,pos,ctx)
10017
10153
  ${emitRollback(p, L.buf, L.raw, sinks)}
10018
10154
  if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
@@ -10025,7 +10161,7 @@ return null
10025
10161
  const clean = !REC && failureRollbackClean(prog, ip);
10026
10162
  const p = tmp();
10027
10163
  return `${head}
10028
- ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
10164
+ ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
10029
10165
  ctx._fc=false
10030
10166
  const v=${child}(input,pos,ctx)
10031
10167
  if(v===FAIL){
@@ -10106,7 +10242,7 @@ return v
10106
10242
  const asc = hoist("as", `DISP[${di}].ascii`);
10107
10243
  const hiArr = table.hi;
10108
10244
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
10109
- const directAscii = staticBuild && table.hi.length === 0;
10245
+ const directAscii = table.hi.length === 0;
10110
10246
  return `${head}
10111
10247
  const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10112
10248
  let arm=-1
@@ -10133,7 +10269,7 @@ return FAIL
10133
10269
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10134
10270
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10135
10271
  const maskable = n <= 32;
10136
- const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
10272
+ const directAsciiMask = maskable && gates.every(isAsciiOnlyClass);
10137
10273
  const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10138
10274
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10139
10275
  const pretests = Array.from({ length: n }, (_, i) => {
@@ -10175,7 +10311,7 @@ return FAIL
10175
10311
  if (choiceCannotCommit(prog, ip) && !startFailureExact) {
10176
10312
  const deepAt = Array.from({ length: n }, () => tmp());
10177
10313
  const deepFx = Array.from({ length: n }, () => tmp());
10178
- const remember = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
10314
+ const remember2 = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
10179
10315
  const lazyArms = (ascii) => arms.map((arm, i) => {
10180
10316
  const pretest = pretests[i];
10181
10317
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
@@ -10187,13 +10323,13 @@ return FAIL
10187
10323
  if(${decision}===0){
10188
10324
  ctx._fc=false
10189
10325
  {const at=_pfTokEnd
10190
- ${remember(i, "at", pretest.token.expected)}}
10326
+ ${remember2(i, "at", pretest.token.expected)}}
10191
10327
  }`;
10192
10328
  const sequenceMiss = pretest?.sequence === void 0 ? "" : `
10193
10329
  else if(${ascii ? `(bits&${1 << i})!==0&&` : ""}${decision}<0){
10194
10330
  ctx._fc=false
10195
10331
  {const at=_pfSeqEnd
10196
- ${remember(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
10332
+ ${remember2(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
10197
10333
  }`;
10198
10334
  return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10199
10335
  `}if(${gate}){
@@ -10201,7 +10337,7 @@ ctx._fc=false
10201
10337
  {const v=${arm}(input,pos,ctx)
10202
10338
  if(v!==FAIL)return v}
10203
10339
  {const at=ctx._fe??pos
10204
- ${remember(i, "at", "ctx._fx")}}
10340
+ ${remember2(i, "at", "ctx._fx")}}
10205
10341
  ${rollbackFor(i)}
10206
10342
  }${routeMiss}${sequenceMiss}`;
10207
10343
  }).join("\n");
@@ -10314,7 +10450,7 @@ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10314
10450
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10315
10451
  ${startFailureExact ? "" : "let prev=0"}
10316
10452
  ${maskArms}
10317
- ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${n},prev,acc)`}
10453
+ ${startFailureExact ? "" : `if(best===pos&&prev!==0)acc=${catchName}(${n},prev,acc)`}
10318
10454
  ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
10319
10455
  return FAIL
10320
10456
  }
@@ -10413,7 +10549,7 @@ return [key,v]
10413
10549
  const ci = classes.push([resolved]) - 1;
10414
10550
  classPlan.push([itemClassIndex]);
10415
10551
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10416
- itemAscii = staticBuild && isAsciiOnlyClass(resolved);
10552
+ itemAscii = isAsciiOnlyClass(resolved);
10417
10553
  }
10418
10554
  }
10419
10555
  const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
@@ -10639,7 +10775,7 @@ return nd
10639
10775
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
10640
10776
  const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
10641
10777
  const ty = q(type);
10642
- const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
10778
+ const stArg = "ctx.state";
10643
10779
  const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
10644
10780
  let value;
10645
10781
  if (proj >= 0) {
@@ -10700,7 +10836,7 @@ ctx.captureTrivia=sCap
10700
10836
  if(v===FAIL)return FAIL
10701
10837
  const end=EC.e
10702
10838
  const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
10703
- const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
10839
+ const st=${readsState ? "ctx.state" : "undefined"}
10704
10840
  let nd
10705
10841
  ${unwrap ? "if(kids.length===1)nd=unwrapChild(kids[0])\nelse " : ""}${collapse ? "if(kids.length===1)nd=kids[0]\nelse " : ""}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
10706
10842
  else ` : ""}{${value}}
@@ -10713,21 +10849,51 @@ return nd
10713
10849
  throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
10714
10850
  }
10715
10851
  }
10852
+ const served = (ip) => select === void 0 || select.has(resolveAlias(ip));
10716
10853
  const ruleEntries = [];
10717
10854
  for (const [rname, entryIp] of Object.entries(prog.rules)) {
10855
+ if (!served(entryIp)) continue;
10718
10856
  const target = link(entryIp);
10719
10857
  const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
10720
10858
  bodies.push(`const ${rn}=${target}`);
10721
10859
  ruleEntries.push(`${q(rname)}:${rn}`);
10722
10860
  }
10723
10861
  const extra = [];
10724
- for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
10862
+ const exported = /* @__PURE__ */ new Set();
10863
+ for (const ip of extraIps) {
10864
+ if (!served(ip)) continue;
10865
+ exported.add(ip);
10866
+ extra.push(`${ip}:${link(ip)}`);
10867
+ }
10868
+ if (select !== void 0) {
10869
+ const kids = [];
10870
+ for (const ip of reachable) {
10871
+ if (select.has(resolveAlias(ip))) continue;
10872
+ kids.length = 0;
10873
+ childSlots(code, ip, kids);
10874
+ for (const kid of kids) {
10875
+ const target = resolveAlias(kid);
10876
+ if (!select.has(target) || exported.has(target)) continue;
10877
+ exported.add(target);
10878
+ extra.push(`${target}:${link(target)}`);
10879
+ }
10880
+ }
10881
+ }
10882
+ const hybrid = select === void 0 ? "" : `,
10883
+ ext:[${externals.join(",")}],
10884
+ bind:function(xs,ps){_xScan=xs
10885
+ ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
10886
+ scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
10887
+ const externalDefs = select === void 0 ? "" : `let _xScan
10888
+ ${externals.map((ip) => `let _xp${ip}
10889
+ function _px${ip}(input,pos,ctx){const o=_xScan(_pfScan);const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
10890
+ `;
10725
10891
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10726
10892
  ${prelude.join("\n")}
10727
10893
  ${skipDefs.join("\n")}
10728
10894
  ${choiceDefs.join("\n")}
10729
10895
  ${bodies.join("\n")}
10730
- function _begin(ctx){
10896
+ ${externalDefs}function _begin(ctx){
10731
10897
  const host=ctx.build
10732
10898
  if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
10733
10899
  _pfDepth++
@@ -10754,7 +10920,7 @@ pieces:{${ruleEntries.join(",")}},
10754
10920
  byIp:{${extra.join(",")}},
10755
10921
  end:function(){return EC.e},
10756
10922
  begin:_begin,
10757
- finish:_finish
10923
+ finish:_finish${hybrid}
10758
10924
  }`;
10759
10925
  return {
10760
10926
  source,
@@ -10762,6 +10928,7 @@ finish:_finish
10762
10928
  masks,
10763
10929
  classes,
10764
10930
  armExpected,
10931
+ siteBytes,
10765
10932
  plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
10766
10933
  };
10767
10934
  }
@@ -11595,6 +11762,70 @@ function escapeClassChar(ch2) {
11595
11762
  return ch2.replace(/[\\\]^-]/g, "\\$&");
11596
11763
  }
11597
11764
 
11765
+ // src/table/trivia-gap.ts
11766
+ function skipDeferredTrivia(input, cur, ctx) {
11767
+ const triviaP = ctx.trivia;
11768
+ const plain2 = ctx.trackLines !== true && ctx.captureTrivia !== true;
11769
+ const gap = ctx._gap;
11770
+ if (plain2 && gap !== void 0 && cur === gap.at && input === gap.input && triviaP === gap.of && ctx._rootTriviaCapture === gap.root && ctx.state === gap.state && ctx._rootTriviaKindIndex === gap.rootKinds && ctx._triviaLog === gap.log) return gap.end;
11771
+ const end = clearRunEnd(input, cur, ctx, triviaP, plain2);
11772
+ if (end >= 0) {
11773
+ remember(cur, end, ctx, input, triviaP);
11774
+ return end;
11775
+ }
11776
+ const scan = scanTriviaCompact(input, cur, ctx);
11777
+ if (typeof scan !== "number") return commitTriviaScan(scan);
11778
+ if (plain2) remember(cur, scan, ctx, input, triviaP);
11779
+ return scan;
11780
+ }
11781
+ function clearRunEnd(input, cur, ctx, triviaP, plain2) {
11782
+ const rootKinds = ctx._rootTriviaKindIndex;
11783
+ const spec = triviaP?._meta.labeledTriviaSpec;
11784
+ if (!plain2 || triviaP === void 0 || spec == null || rootKinds === void 0 || ctx._triviaLog !== void 0) return -1;
11785
+ if (spec.rootKinds !== rootKinds) prime(spec, triviaP, rootKinds);
11786
+ const fast = spec.rootScan;
11787
+ if (fast === null) return -1;
11788
+ const end = fast(input, cur);
11789
+ return ctx._rootTriviaCapture === false || clearOf(spec.rootLeaders, input, cur, end) ? end : -1;
11790
+ }
11791
+ function remember(cur, end, ctx, input, triviaP) {
11792
+ const gap = ctx._gap;
11793
+ if (gap === void 0) {
11794
+ ctx._gap = { at: cur, end, input, of: triviaP, root: ctx._rootTriviaCapture, rootKinds: ctx._rootTriviaKindIndex, log: ctx._triviaLog, state: ctx.state };
11795
+ return;
11796
+ }
11797
+ gap.at = cur;
11798
+ gap.end = end;
11799
+ gap.input = input;
11800
+ gap.of = triviaP;
11801
+ gap.root = ctx._rootTriviaCapture;
11802
+ gap.rootKinds = ctx._rootTriviaKindIndex;
11803
+ gap.log = ctx._triviaLog;
11804
+ gap.state = ctx.state;
11805
+ }
11806
+ function prime(spec, triviaP, rootKinds) {
11807
+ const ranges = [];
11808
+ let bounded = true;
11809
+ for (const arm of spec.arms) {
11810
+ if (rootKinds[arm.label] === void 0) continue;
11811
+ const fs = arm.parser._meta.firstSet;
11812
+ if (fs.kind === "any") bounded = false;
11813
+ else if (fs.kind === "ranges") ranges.push(...fs.ranges);
11814
+ }
11815
+ const classified = triviaP._meta.triviaScanner;
11816
+ spec.rootKinds = rootKinds;
11817
+ spec.rootLeaders = ranges;
11818
+ spec.rootScan = !bounded ? null : classified === void 0 ? fastTriviaScanner(triviaP) : classified;
11819
+ }
11820
+ function clearOf(ranges, input, from, to) {
11821
+ for (let i = from; i < to; i++) {
11822
+ const c = input.charCodeAt(i);
11823
+ if (c >= 55296 && c <= 57343) return false;
11824
+ for (const r of ranges) if (c >= r.lo && c <= r.hi) return false;
11825
+ }
11826
+ return true;
11827
+ }
11828
+
11598
11829
  // src/table/run-support.ts
11599
11830
  function lineCol(ctx, offset) {
11600
11831
  const starts = ctx._lineStarts ?? [0];
@@ -11791,6 +12022,9 @@ function assemble(t2, prog, cfg) {
11791
12022
  const EC = newEndCell();
11792
12023
  const scalarRecognizers = [];
11793
12024
  const rawScalarSpecs = /* @__PURE__ */ new Set();
12025
+ function lookaheadClass(child) {
12026
+ return code[child] === OP_GATE && !cfg.tolerant && !cfg.probe ? cc[code[child + 1]] : null;
12027
+ }
11794
12028
  function scalarFor(child) {
11795
12029
  const spec = code[child + 1];
11796
12030
  let recognize = scalarRecognizers[spec];
@@ -11800,15 +12034,23 @@ function assemble(t2, prog, cfg) {
11800
12034
  }
11801
12035
  return recognize;
11802
12036
  }
11803
- const labelExtraIps = [];
11804
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) labelExtraIps.push(r[0]);
11805
- for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0]);
12037
+ const labelExtraIps = assemblyExtraIps(prog);
11806
12038
  const closureLabels = computeSiteLabels(
11807
12039
  code,
11808
12040
  [...Object.values(prog.rules), ...labelExtraIps],
11809
12041
  hostCst
11810
12042
  );
11811
12043
  let SCAN = null;
12044
+ let HYBRID;
12045
+ function hybridPiece(piece) {
12046
+ const setScan = HYBRID.scan;
12047
+ return (input, pos, ctx) => {
12048
+ const saved = setScan(SCAN);
12049
+ const value = piece(input, pos, ctx);
12050
+ setScan(saved);
12051
+ return value;
12052
+ };
12053
+ }
11812
12054
  const memo = /* @__PURE__ */ new Map();
11813
12055
  const reached = /* @__PURE__ */ new Set();
11814
12056
  function pushLeaf(ctx, value, s, e) {
@@ -12100,9 +12342,7 @@ function assemble(t2, prog, cfg) {
12100
12342
  return s(input, cur);
12101
12343
  }
12102
12344
  if (s !== null) return skipTriviaScanned(s, input, cur, ctx);
12103
- if (needsDeferredTriviaCommit(ctx)) {
12104
- return commitTriviaScan(scanTriviaCompact(input, cur, ctx));
12105
- }
12345
+ if (needsDeferredTriviaCommit(ctx)) return skipDeferredTrivia(input, cur, ctx);
12106
12346
  return advanceTrivia(input, cur, ctx);
12107
12347
  }
12108
12348
  let TERMV;
@@ -12272,7 +12512,7 @@ function assemble(t2, prog, cfg) {
12272
12512
  if (next !== void 0) {
12273
12513
  return next(input, pos, ctx, bits, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12274
12514
  }
12275
- if (best === pos) acc = through(total, prev, acc);
12515
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12276
12516
  ctx._fe = pos;
12277
12517
  ctx._fx = acc ?? choiceFx;
12278
12518
  return FAIL;
@@ -12355,7 +12595,7 @@ function assemble(t2, prog, cfg) {
12355
12595
  if (next !== void 0) {
12356
12596
  return next(input, pos, ctx, c, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot, acc, prev, best);
12357
12597
  }
12358
- if (best === pos) acc = through(total, prev, acc);
12598
+ if (best === pos && prev !== 0) acc = through(total, prev, acc);
12359
12599
  ctx._fe = pos;
12360
12600
  ctx._fx = acc ?? choiceFx;
12361
12601
  return FAIL;
@@ -12434,6 +12674,13 @@ function assemble(t2, prog, cfg) {
12434
12674
  if (done !== void 0) return done;
12435
12675
  const flight = inFlight.get(ip);
12436
12676
  if (flight !== void 0) return flight.fwd;
12677
+ const selected = HYBRID?.byIp[ip];
12678
+ if (selected !== void 0) {
12679
+ const piece2 = hybridPiece(selected);
12680
+ memo.set(ip, piece2);
12681
+ reached.add(ip);
12682
+ return piece2;
12683
+ }
12437
12684
  let target;
12438
12685
  const fwd = (input, pos, ctx) => target(input, pos, ctx);
12439
12686
  const holder = { fwd, set: (p) => {
@@ -12441,7 +12688,7 @@ function assemble(t2, prog, cfg) {
12441
12688
  } };
12442
12689
  inFlight.set(ip, holder);
12443
12690
  const op = code[ip];
12444
- const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : lower(ip);
12691
+ const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : countedPiece(lower(ip), ip);
12445
12692
  inFlight.delete(ip);
12446
12693
  holder.set(piece);
12447
12694
  memo.set(ip, piece);
@@ -12978,7 +13225,12 @@ function assemble(t2, prog, cfg) {
12978
13225
  }
12979
13226
  const child = link(code[ip + 1]);
12980
13227
  const xf = fx[code[ip + 2]];
13228
+ const gate = lookaheadClass(code[ip + 1]);
12981
13229
  return (input, pos, ctx) => {
13230
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
13231
+ EC.e = pos;
13232
+ return null;
13233
+ }
12982
13234
  const need = markCst(ctx);
12983
13235
  const mRaw = MRAW;
12984
13236
  const mTl = MTL;
@@ -13001,7 +13253,13 @@ function assemble(t2, prog, cfg) {
13001
13253
  case OP_PEEK: {
13002
13254
  const child = link(code[ip + 1]);
13003
13255
  const xf = fx[code[ip + 2]];
13256
+ const gate = lookaheadClass(code[ip + 1]);
13004
13257
  return (input, pos, ctx) => {
13258
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
13259
+ ctx._fe = pos;
13260
+ ctx._fx = xf;
13261
+ return FAIL;
13262
+ }
13005
13263
  const need = markCst(ctx);
13006
13264
  const mRaw = MRAW;
13007
13265
  const mTl = MTL;
@@ -13023,7 +13281,12 @@ function assemble(t2, prog, cfg) {
13023
13281
  }
13024
13282
  case OP_OPT: {
13025
13283
  const child = link(code[ip + 1]);
13284
+ const gate = lookaheadClass(code[ip + 1]);
13026
13285
  return (input, pos, ctx) => {
13286
+ if (gate !== null && !classHas2(gate, lead(input, pos))) {
13287
+ EC.e = pos;
13288
+ return null;
13289
+ }
13027
13290
  const need = markCst(ctx);
13028
13291
  const mRaw = MRAW;
13029
13292
  const mTl = MTL;
@@ -13830,6 +14093,11 @@ function assemble(t2, prog, cfg) {
13830
14093
  }
13831
14094
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13832
14095
  }
14096
+ if (prev === 0) {
14097
+ ctx._fe = pos;
14098
+ ctx._fx = choiceFx;
14099
+ return FAIL;
14100
+ }
13833
14101
  if (best === pos && prev < 1) acc = accSet(e0, acc);
13834
14102
  if (best === pos && prev < 2) acc = accSet(e1, acc);
13835
14103
  if (best === pos && n === 3 && prev < 3) acc = accSet(e2, acc);
@@ -14138,7 +14406,7 @@ function assemble(t2, prog, cfg) {
14138
14406
  return (input, pos, ctx) => {
14139
14407
  if (!pred(ctx.state)) {
14140
14408
  ctx._fc = false;
14141
- ctx._fe = pos;
14409
+ ctx._fe = -1;
14142
14410
  ctx._fx = xf;
14143
14411
  return FAIL;
14144
14412
  }
@@ -14544,7 +14812,7 @@ function assemble(t2, prog, cfg) {
14544
14812
  if (v === FAIL) return FAIL;
14545
14813
  const end = EC.e;
14546
14814
  const span = tracked ? spanLines(ctx, pos, end) : { start: pos, end };
14547
- const st = readsState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
14815
+ const st = readsState ? ctx.state : void 0;
14548
14816
  let nd;
14549
14817
  if (unwrap && kids.length === 1) {
14550
14818
  nd = unwrapChild(kids[0]);
@@ -14557,10 +14825,10 @@ function assemble(t2, prog, cfg) {
14557
14825
  ) {
14558
14826
  nd = kids[0];
14559
14827
  } else if (proj >= 0) {
14560
- nd = hostCst && host !== void 0 ? host(type, kids, fieldMap, span, rawKids, tlog, readsState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0, tags) : projectChild(kids, proj, type);
14828
+ nd = hostCst && host !== void 0 ? host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags) : projectChild(kids, proj, type);
14561
14829
  } else if (build !== void 0) {
14562
14830
  if (hostCst && host !== void 0) {
14563
- nd = host(type, kids, fieldMap, span, rawKids, tlog, readsState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0, tags);
14831
+ nd = host(type, kids, fieldMap, span, rawKids, tlog, ctx.state, tags);
14564
14832
  } else {
14565
14833
  nd = build(kids, fieldMap, span, rawKids, captureWide ? tlog : EMPTY_TL2, st);
14566
14834
  }
@@ -14611,9 +14879,7 @@ function assemble(t2, prog, cfg) {
14611
14879
  let emitRefusal;
14612
14880
  let emitReached;
14613
14881
  {
14614
- const extraIps = [];
14615
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
14616
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
14882
+ const extraIps = assemblyExtraIps(prog);
14617
14883
  const roots = [...Object.values(prog.rules), ...extraIps];
14618
14884
  for (const ip of reachableSites(code, roots)) {
14619
14885
  if (code[ip] === OP_DISPATCH) {
@@ -14706,9 +14972,11 @@ function assemble(t2, prog, cfg) {
14706
14972
  adjacencyHolds,
14707
14973
  t2.lexPrograms,
14708
14974
  LEAD,
14709
- triviaFieldCapture
14975
+ triviaFieldCapture,
14976
+ skipDeferredTrivia
14710
14977
  );
14711
14978
  emitReached = new Set(pre.reached);
14979
+ if (emitted.ext !== void 0) HYBRID = emitted;
14712
14980
  }
14713
14981
  try {
14714
14982
  if (emitted !== void 0) throw new ServedByBuild();
@@ -14790,7 +15058,8 @@ function assemble(t2, prog, cfg) {
14790
15058
  adjacencyHolds,
14791
15059
  t2.lexPrograms,
14792
15060
  LEAD,
14793
- triviaFieldCapture
15061
+ triviaFieldCapture,
15062
+ skipDeferredTrivia
14794
15063
  );
14795
15064
  emitReached = em.reached;
14796
15065
  } catch (e) {
@@ -14801,7 +15070,7 @@ function assemble(t2, prog, cfg) {
14801
15070
  }
14802
15071
  function pieceAt(ip) {
14803
15072
  const em = emitted;
14804
- if (em !== void 0) {
15073
+ if (em !== void 0 && HYBRID === void 0) {
14805
15074
  const p = em.byIp[ip];
14806
15075
  if (p === void 0) throw new Error(`table emitter: no emitted body for site ${ip}`);
14807
15076
  return p;
@@ -14831,6 +15100,37 @@ function assemble(t2, prog, cfg) {
14831
15100
  }
14832
15101
  const scans = scansArr;
14833
15102
  const scanSkip = (prog.scanSkip ?? []).map((set) => set.map((r) => subtreeComb(r)));
15103
+ if (HYBRID !== void 0) {
15104
+ const em = HYBRID;
15105
+ em.bind(
15106
+ (s) => {
15107
+ const saved = SCAN;
15108
+ SCAN = s;
15109
+ return saved;
15110
+ },
15111
+ em.ext.map((ip) => link(ip))
15112
+ );
15113
+ const pieces2 = {};
15114
+ for (const [name, entryIp] of Object.entries(prog.rules)) {
15115
+ pieces2[name] = em.pieces[name] ?? link(entryIp);
15116
+ }
15117
+ for (const ip of emitReached) reached.add(ip);
15118
+ return {
15119
+ pieces: pieces2,
15120
+ end: () => EC.e,
15121
+ begin: (ctx) => {
15122
+ begin(ctx);
15123
+ em.begin(ctx);
15124
+ },
15125
+ finish: () => {
15126
+ em.finish();
15127
+ finish();
15128
+ },
15129
+ scanSkip,
15130
+ reached,
15131
+ emitRefusal: void 0
15132
+ };
15133
+ }
14834
15134
  if (emitted !== void 0) {
14835
15135
  const em = emitted;
14836
15136
  return {
@@ -14866,6 +15166,15 @@ function assemble(t2, prog, cfg) {
14866
15166
  }
14867
15167
  return { pieces, end: () => EC.e, begin, finish, scanSkip, reached, emitRefusal };
14868
15168
  }
15169
+ var SITE_COUNTS;
15170
+ function countedPiece(piece, ip) {
15171
+ const counts = SITE_COUNTS;
15172
+ if (counts === void 0) return piece;
15173
+ return (input, pos, ctx) => {
15174
+ counts[ip]++;
15175
+ return piece(input, pos, ctx);
15176
+ };
15177
+ }
14869
15178
  var AssemblyCache = class {
14870
15179
  t;
14871
15180
  prog;
@@ -15068,9 +15377,7 @@ function emitDispatchSpec(d) {
15068
15377
  function emitAssemblies(prog, cfgs) {
15069
15378
  if (cfgs.length === 0) return ["a:[],"];
15070
15379
  const t2 = resolveTable(prog);
15071
- const extraIps = [];
15072
- for (const s of prog.scans ?? []) for (const r of scanRefs(s)) extraIps.push(r[0]);
15073
- for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
15380
+ const extraIps = assemblyExtraIps(prog);
15074
15381
  const out = [];
15075
15382
  const seen = /* @__PURE__ */ new Set();
15076
15383
  for (const cfg of cfgs) {
@@ -15079,7 +15386,7 @@ function emitAssemblies(prog, cfgs) {
15079
15386
  seen.add(key);
15080
15387
  let em;
15081
15388
  try {
15082
- em = emitAssemblySource(t2, prog, cfg, extraIps, true);
15389
+ em = emitAssemblySource(t2, prog, cfg, extraIps, true, cfg.select);
15083
15390
  } catch (e) {
15084
15391
  if (e instanceof Unemittable) continue;
15085
15392
  throw e;