parseman 0.61.4 → 0.61.5

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 (42) hide show
  1. package/dist/analysis/diagnostics.js +844 -522
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +846 -522
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/cst/capture-buffer.d.ts +3 -2
  6. package/dist/cst/capture-buffer.d.ts.map +1 -1
  7. package/dist/index.js +846 -520
  8. package/dist/index.js.map +3 -3
  9. package/dist/plugin/index.js +844 -518
  10. package/dist/plugin/index.js.map +3 -3
  11. package/dist/table/assemble.d.ts.map +1 -1
  12. package/dist/table/child-slots.d.ts.map +1 -1
  13. package/dist/table/emit-assembly.d.ts +1 -1
  14. package/dist/table/emit-assembly.d.ts.map +1 -1
  15. package/dist/table/encode.d.ts.map +1 -1
  16. package/dist/table/exec.d.ts.map +1 -1
  17. package/dist/table/fail-clean.d.ts.map +1 -1
  18. package/dist/table/hold-gap.d.ts.map +1 -1
  19. package/dist/table/index.js +368 -42
  20. package/dist/table/index.js.map +3 -3
  21. package/dist/table/late-frame.d.ts +18 -0
  22. package/dist/table/late-frame.d.ts.map +1 -0
  23. package/dist/table/ops.d.ts +17 -0
  24. package/dist/table/ops.d.ts.map +1 -1
  25. package/dist/table/select-hot.d.ts.map +1 -1
  26. package/dist/table/site-labels.d.ts +5 -1
  27. package/dist/table/site-labels.d.ts.map +1 -1
  28. package/dist/version.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/src/cst/capture-buffer.ts +20 -11
  31. package/src/table/assemble.ts +124 -4
  32. package/src/table/child-slots.ts +9 -1
  33. package/src/table/emit-assembly.ts +101 -14
  34. package/src/table/encode.ts +69 -6
  35. package/src/table/exec.ts +7 -1
  36. package/src/table/fail-clean.ts +8 -1
  37. package/src/table/hold-gap.ts +5 -1
  38. package/src/table/late-frame.ts +54 -0
  39. package/src/table/ops.ts +19 -0
  40. package/src/table/select-hot.ts +7 -1
  41. package/src/table/site-labels.ts +38 -14
  42. package/src/version.ts +1 -1
@@ -0,0 +1,18 @@
1
+ export type ContinuationGate = {
2
+ /** Class of the first character, past any trivia. */
3
+ readonly cls: number;
4
+ /** The regex row of a leading gap, or −1. */
5
+ readonly gapRow: number;
6
+ /** Class of the character after the gap. */
7
+ readonly follow: number;
8
+ /** Class of an arm that opens without the gap, or −1. */
9
+ readonly other: number;
10
+ };
11
+ export declare function continuationGate(code: ArrayLike<number>, ip: number): ContinuationGate | undefined;
12
+ /**
13
+ * Can this assembly decide at this `OP_CONT`? It needs the tail's test, and the
14
+ * trivia the label names: a scope it cannot name, or one with no scanner, would cost a
15
+ * hit more calls than the frame it saves on a miss.
16
+ */
17
+ export declare function canDecide(code: ArrayLike<number>, ip: number, tri: number, triviaScan: readonly unknown[]): boolean;
18
+ //# sourceMappingURL=late-frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"late-frame.d.ts","sourceRoot":"","sources":["../../src/table/late-frame.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAoBlG;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAGnH"}
@@ -508,6 +508,23 @@ export declare const OP_RGATE2 = 47;
508
508
  * assembly resolves it to one child; it has no body of its own.
509
509
  */
510
510
  export declare const OP_STRICT = 48;
511
+ /**
512
+ * `CONT corner wrapper tail` — a `collapse` node that is `sequence(corner, tail)`, with
513
+ * a tail that can take nothing and a corner that is one node. A strict assembly runs
514
+ * `corner` in the PARENT's collector and looks at the next token. Where `tail` cannot
515
+ * start there, the corner is the result: no frame, no children, no builder. Where it
516
+ * can, the corner's publication is taken back and `wrapper`'s frame opens around it and
517
+ * `tail`, in this one function. `tail` is read for the decision (`late-frame.ts`). Where
518
+ * no decision can be made, and under recovery, a probe or the reference driver, this
519
+ * is `wrapper`, the node as written.
520
+ */
521
+ export declare const OP_CONT = 49;
522
+ /**
523
+ * `SEED corner` — marks the first term of `wrapper`'s body. Run, it is `corner`. It
524
+ * exists so the labels can leave out the edge from a late frame to its corner, which
525
+ * never runs there.
526
+ */
527
+ export declare const OP_SEED = 50;
511
528
  /**
512
529
  * `DISPATCH sel d other otherRouted n a1 … an` — `dispatch()`.
513
530
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"select-hot.d.ts","sourceRoot":"","sources":["../../src/table/select-hot.ts"],"names":[],"mappings":"AAuBA;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,MAAM,EAAE,MAAM;AACd;iCACiC;AACjC,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAC1B,GAAG,CAAC,MAAM,CAAC,CAgBb;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;AACtC,2DAA2D;AAC3D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,MAAM,EACnD,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAC1B;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQ7E"}
1
+ {"version":3,"file":"select-hot.d.ts","sourceRoot":"","sources":["../../src/table/select-hot.ts"],"names":[],"mappings":"AAwBA;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,MAAM,EAAE,MAAM;AACd;iCACiC;AACjC,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAC1B,GAAG,CAAC,MAAM,CAAC,CAgBb;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;AACtC,2DAA2D;AAC3D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,MAAM,EACnD,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAC1B;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQ7E"}
@@ -69,6 +69,8 @@ export declare function gatedPassCollapse(code: Int32Array, ip: number, hostCst:
69
69
  /** A site's label, or `TOP` for anything the walk did not reach. */
70
70
  export type SiteLabels = {
71
71
  at: (ip: number) => SiteLabel;
72
+ /** The `OP_CONT` sites whose corner runs in the parent's collector in every engine. */
73
+ late: ReadonlySet<number>;
72
74
  };
73
75
  /**
74
76
  * Compute a label for every site reachable from `roots`.
@@ -82,7 +84,9 @@ export type SiteLabels = {
82
84
  * The meet only ever moves a label toward `TOP`, and `TOP` is absorbing, so the
83
85
  * lattice has height three and the walk terminates.
84
86
  */
85
- export declare function computeSiteLabels(code: Int32Array, roots: Iterable<number>, hostCst: boolean): SiteLabels;
87
+ export declare function computeSiteLabels(code: Int32Array, roots: Iterable<number>, hostCst: boolean,
88
+ /** Does this assembly run this `OP_CONT` late, in EVERY engine it holds? Absent: none. */
89
+ late?: (ip: number, tri: number) => boolean): SiteLabels;
86
90
  /**
87
91
  * Does a piece entered at `ip` need the caller's INSTALLED trivia scanner handed
88
92
  * across an engine boundary?
@@ -1 +1 @@
1
- {"version":3,"file":"site-labels.d.ts","sourceRoot":"","sources":["../../src/table/site-labels.ts"],"names":[],"mappings":"AAqEA,iFAAiF;AACjF,eAAO,MAAM,WAAW,KAAK,CAAA;AAC7B,qDAAqD;AACrD,eAAO,MAAM,QAAQ,KAAK,CAAA;AAC1B,0EAA0E;AAE1E,qDAAqD;AACrD,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,yDAAyD;AACzD,eAAO,MAAM,OAAO,IAAI,CAAA;AACxB,uDAAuD;AACvD,eAAO,MAAM,MAAM,IAAI,CAAA;AAIvB,uCAAuC;AACvC,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,oDAAoD;AACpD,eAAO,MAAM,QAAQ,IAAI,CAAA;AAEzB,MAAM,MAAM,SAAS,GAAG;IACtB,mFAAmF;IACnF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wDAAwD;AACxD,eAAO,MAAM,GAAG,EAAE,SAAgF,CAAA;AAWlG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAarF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAYpF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAuB/I;AAqED,oEAAoE;AACpE,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,SAAS,CAAA;CAAE,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,OAAO,EAAE,OAAO,GACf,UAAU,CA6BZ;AAED;;;;;;;;;;;;;GAaG;AACH;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAKpF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAqB3F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;IAAE,KAAK,EAAE;QAAE,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,EAAE,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GAAG,SAAS,CAAC,EAAE,GACtI,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAS,CAOnD"}
1
+ {"version":3,"file":"site-labels.d.ts","sourceRoot":"","sources":["../../src/table/site-labels.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -13,5 +13,5 @@
13
13
  * Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
14
14
  * the build if this constant drifts from the published version.
15
15
  */
16
- export declare const PARSEMAN_VERSION = "0.61.4";
16
+ export declare const PARSEMAN_VERSION = "0.61.5";
17
17
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parseman",
3
- "version": "0.61.4",
3
+ "version": "0.61.5",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "engines": {
6
6
  "node": "^20.19.0 || >=22.13.0"
@@ -122,26 +122,35 @@ export function pushCstChild(ctx: ParseContext, built: unknown, rawEntry: unknow
122
122
  /**
123
123
  * Undo the LAST `pushCstChild` into the active collector, whichever form it took:
124
124
  * a child the lazy buffer's empty sentinel dropped (`undefined` first) leaves no
125
- * semantic entry to remove, only its raw one.
125
+ * semantic entry to remove, only its raw one. Returns that raw entry, or `undefined`
126
+ * when this collector keeps none.
126
127
  */
127
- export function popCstChild(ctx: ParseContext): void {
128
+ export function popCstChild(ctx: ParseContext): unknown {
128
129
  const b = ctx._cstBuf
129
130
  if (b) {
130
131
  const ch = b.ch
131
- if (b.rawOnly !== true && ch) {
132
- ch.pop()
133
- if (ch.length === 1) { b.single = ch[0]; b.ch = undefined }
132
+ if (b.rawOnly !== true) {
133
+ if (ch) {
134
+ ch.pop()
135
+ if (ch.length === 1) { b.single = ch[0]; b.ch = undefined }
136
+ } else b.single = undefined
137
+ }
138
+ if (b.noRaw === true) {
139
+ b.rawLen = (b.rawLen ?? 1) - 1
140
+ return undefined
134
141
  }
135
- if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1
136
- else if (b.raw) {
137
- b.raw.pop()
142
+ if (b.raw) {
143
+ const entry = b.raw.pop()
138
144
  if (b.raw.length === 1) { b.rawSingle = b.raw[0]; b.raw = undefined }
139
- } else b.rawSingle = undefined
140
- return
145
+ return entry
146
+ }
147
+ const entry = b.rawSingle
148
+ b.rawSingle = undefined
149
+ return entry
141
150
  }
142
151
  if (ctx._cstChildren) ctx._cstChildren.pop()
143
152
  else if (ctx._cstLeaves) ctx._cstLeaves.pop()
144
- if (ctx._cstRawChildren) ctx._cstRawChildren.pop()
153
+ return ctx._cstRawChildren?.pop()
145
154
  }
146
155
 
147
156
  export function cstRawLen(ctx: ParseContext): number {
@@ -83,6 +83,7 @@ import {
83
83
  cstCaptureActive, cstLeavesLen, cstTlLen,
84
84
  demoteCapturedToRaw, pushCstChild, pushCstLeaf,
85
85
  type CstCaptureBuf,
86
+ popCstChild,
86
87
  } from '../cst/capture-buffer.ts'
87
88
  import { PlainBuf, PlainField, PlainLeaf, PlainNode, PlainSpan } from '../cst/plain.js'
88
89
  import {
@@ -91,7 +92,7 @@ import {
91
92
  OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_EXPECT, OP_SEQX, OP_SCAN,
92
93
  OP_LIVE,
93
94
  OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
94
- OP_COV, OP_GAPGATE, OP_STRICT,
95
+ OP_COV, OP_GAPGATE, OP_STRICT, OP_CONT, OP_SEED,
95
96
  OP_ADJ, OP_GREEDY, OP_REJECT, OP_ARMGATE, OP_RGATE, OP_RGATE2,
96
97
  OP_LEX_BODY, OP_LEX_PROGRAM,
97
98
  } from './ops.ts'
@@ -110,6 +111,7 @@ import {
110
111
  type EmittedAssembly, type EmittedFactory,
111
112
  } from './emit-assembly.ts'
112
113
  import { collapseEmpty, lead, rawEntry, spanLines } from './run-support.ts'
114
+ import { canDecide, continuationGate } from './late-frame.ts'
113
115
  import { holdsGap, rowNullable } from './hold-gap.ts'
114
116
  import { gapRows, newGapSlot } from './gap-gate.ts'
115
117
  import { failCleanAnalysis } from './fail-clean.ts'
@@ -133,7 +135,7 @@ import {
133
135
  type SubtreeRef, type TableProgram, type TableRule,
134
136
  } from './program.ts'
135
137
  import { stampRuleMap } from './stamp.ts'
136
- import { computeSiteLabels, gatedPassCollapse, passCollapse, reachableSites, scanHandoffNeeded, scopeIsIdentity, triviaLeadRanges } from './site-labels.ts'
138
+ import { CAP_OFF, CAP_ON, type SiteLabel, computeSiteLabels, gatedPassCollapse, passCollapse, reachableSites, scanHandoffNeeded, scopeIsIdentity, triviaLeadRanges, TRI_NONE } from './site-labels.ts'
137
139
  import { refuseUnclassifiedRootScope } from '../cst/root-trivia-scope.ts'
138
140
  import { captureError, firstSetSentinel, matchesAt, orSentinel, recoverScan } from '../recovery/scan.ts'
139
141
  import {
@@ -544,6 +546,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
544
546
  const GAP = newGapSlot()
545
547
  const closureLabels = computeSiteLabels(
546
548
  code, [...Object.values(prog.rules), ...labelExtraIps], hostCst,
549
+ cfg.tolerant || cfg.probe ? undefined : (ip, tri) => canDecide(code, ip, tri, t.triviaScan),
547
550
  )
548
551
 
549
552
  /**
@@ -1177,6 +1180,41 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1177
1180
  return cur
1178
1181
  }
1179
1182
 
1183
+ /** Whether `cls` admits the character at `at`, without a call for the ASCII answer. */
1184
+ function startsTail(cls: ResolvedClass, input: string, at: number): boolean {
1185
+ const c = input.charCodeAt(at)
1186
+ return c < 128 ? cls.ascii[c] === 1 : classHas(cls, lead(input, at))
1187
+ }
1188
+
1189
+ /**
1190
+ * The tail of a late frame. The gap was scanned to decide, so with no gap there is
1191
+ * nothing to record or undo, and with nothing recording it is not scanned again.
1192
+ */
1193
+ function lateTail(tail: Piece, input: string, end: number, at: number, ctx: ParseContext, frame: SiteLabel): unknown {
1194
+ if (at === end) return tail(input, end, ctx)
1195
+ if (ctx._triviaLog === undefined && ctx._rootTriviaLog === undefined
1196
+ && (frame.cap === CAP_OFF || !((frame.cap === CAP_ON || ctx.captureTrivia === true)
1197
+ && (frame.buf || ctx._cstBuf !== undefined || ctx._cstTriviaLog !== undefined)))) {
1198
+ const v = tail(input, at, ctx)
1199
+ if (v !== FAIL && EC.e <= at) EC.e = end
1200
+ return v
1201
+ }
1202
+ const need = rollbackNeeded(ctx)
1203
+ const mTl = need ? cstTlLen(ctx) : 0
1204
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0
1205
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
1206
+ const scanEnd = skipTrivia(input, end, ctx)
1207
+ const scanTl = need ? cstTlLen(ctx) : 0
1208
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0
1209
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
1210
+ const v = tail(input, scanEnd, ctx)
1211
+ if (v !== FAIL && EC.e <= scanEnd) {
1212
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot)
1213
+ EC.e = end
1214
+ }
1215
+ return v
1216
+ }
1217
+
1180
1218
  /** A non-first term at a site proven to run under an open node capture buffer. */
1181
1219
  function nextTermBuffered(child: Piece, input: string, cur: number, ctx: ParseContext): number {
1182
1220
  const t = ctx.trivia
@@ -1846,6 +1884,88 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1846
1884
  case OP_EMPTY:
1847
1885
  return (_input, pos) => { EC.e = pos; return '' }
1848
1886
 
1887
+ case OP_SEED:
1888
+ return link(code[ip + 1]!)
1889
+
1890
+ case OP_CONT: {
1891
+ const wrapper = code[ip + 2]!
1892
+ if (!closureLabels.late.has(ip)) return lower(wrapper)
1893
+ const corner = link(code[ip + 1]!)
1894
+ const tail = link(code[ip + 3]!)
1895
+ const g = continuationGate(code, code[ip + 3]!)!
1896
+ const tri = closureLabels.at(ip).tri
1897
+ // The gap the tail would start past, read without recording anything: no scan
1898
+ // at a character no trivia can start.
1899
+ const scan = tri === TRI_NONE ? undefined : t.triviaScan[tri]!
1900
+ const leads = tri === TRI_NONE ? null : LEAD_TABLES[tri]!
1901
+ const cls = cc[g.cls]!
1902
+ const gapRe = g.gapRow < 0 ? undefined : k[code[g.gapRow + 1]!] as RegExp
1903
+ const follow = g.follow < 0 ? undefined : cc[g.follow]!
1904
+ const other = g.other < 0 ? undefined : cc[g.other]!
1905
+ const mayStartPastGap = (input: string, at: number): boolean => {
1906
+ gapRe!.lastIndex = at
1907
+ const q = gapRe!.test(input) ? gapRe!.lastIndex : -1
1908
+ return (q >= 0 && classHas(follow!, lead(input, q))) || (other !== undefined && classHas(other, lead(input, at)))
1909
+ }
1910
+ const frame = closureLabels.at(code[wrapper + 2]!)
1911
+ const flags = code[wrapper + 3]!
1912
+ const buildIdx = code[wrapper + 1]!
1913
+ // The seed for this frame, handed over before anything can parse.
1914
+ let held: unknown
1915
+ let heldRaw: unknown
1916
+ let heldEnd = 0
1917
+ let heldAt = 0
1918
+ const omitsRaw = !hostCst && buildIdx >= 0 && code[wrapper + 4]! < 0 && (flags & 2) !== 0
1919
+ const body: Piece = omitsRaw
1920
+ ? (input, _pos, ctx) => {
1921
+ const b = ctx._cstBuf
1922
+ if (b !== undefined) {
1923
+ b.single = held
1924
+ b.rawLen = 1
1925
+ } else ctx._cstChildren!.push(held)
1926
+ held = undefined
1927
+ heldRaw = undefined
1928
+ return lateTail(tail, input, heldEnd, heldAt, ctx, frame)
1929
+ }
1930
+ : (input, pos, ctx) => {
1931
+ const b = ctx._cstBuf
1932
+ if (b !== undefined) {
1933
+ b.single = held
1934
+ b.rawSingle = heldRaw ?? rawEntry(held, input, pos, heldEnd)
1935
+ } else ctx._cstChildren!.push(held)
1936
+ held = undefined
1937
+ heldRaw = undefined
1938
+ return lateTail(tail, input, heldEnd, heldAt, ctx, frame)
1939
+ }
1940
+ let open: Piece
1941
+ // An AST reducer: the frame is one of the two lean bodies. Any other frame is
1942
+ // the node's own closure, with `body` for its child.
1943
+ if (!hostCst && !cfg.trackLines && code[wrapper] === OP_NODE && code[wrapper + 4]! < 0 && (flags === 32 || flags === 34)) {
1944
+ const build = fns[buildIdx] as NodeBuilder
1945
+ open = flags === 34 ? childrenOnlyCollapseBuildNode(body, build) : collapseBuildNode(body, build)
1946
+ } else {
1947
+ NODE_BODY = body
1948
+ open = lower(wrapper)
1949
+ }
1950
+ return (input, pos, ctx) => {
1951
+ const v = corner(input, pos, ctx)
1952
+ if (v === FAIL) return FAIL
1953
+ const end = EC.e
1954
+ let at = end
1955
+ if (scan !== undefined) {
1956
+ const c = input.charCodeAt(end)
1957
+ if (leads === null || !(c < 128) || leads[c] !== 0) at = scan(input, end)
1958
+ }
1959
+ if (v !== undefined && !(gapRe === undefined ? startsTail(cls, input, at) : mayStartPastGap(input, at))) return v
1960
+ if (ctx._cstBuf === undefined && ctx._cstRawChildren === undefined && ctx._cstChildren !== undefined) ctx._cstChildren.pop()
1961
+ else if (ctx._cstBuf !== undefined || ctx._cstChildren !== undefined) heldRaw = popCstChild(ctx)
1962
+ held = v
1963
+ heldEnd = end
1964
+ heldAt = at
1965
+ return open(input, pos, ctx)
1966
+ }
1967
+ }
1968
+
1849
1969
  /* ── transparent / structural ────────────────────────────────────────── */
1850
1970
 
1851
1971
  case OP_GUARD: {
@@ -4290,7 +4410,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
4290
4410
  matchesAt, recoverScan, orSentinel, captureError,
4291
4411
  scalarRecognizers, t.lex, adjacencyHolds, t.lexPrograms,
4292
4412
  LEAD, triviaFieldCapture, skipDeferredTrivia,
4293
- collapseEmpty,
4413
+ collapseEmpty, popCstChild,
4294
4414
  PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf, GAP,
4295
4415
  )
4296
4416
  emitReached = new Set(pre.reached)
@@ -4375,7 +4495,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
4375
4495
  matchesAt, recoverScan, orSentinel, captureError,
4376
4496
  scalarRecognizers, t.lex, adjacencyHolds, t.lexPrograms,
4377
4497
  LEAD, triviaFieldCapture, skipDeferredTrivia,
4378
- collapseEmpty,
4498
+ collapseEmpty, popCstChild,
4379
4499
  PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf, GAP,
4380
4500
  )
4381
4501
  emitReached = em.reached
@@ -4,7 +4,7 @@ import {
4
4
  OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_LIVE, OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT,
5
5
  OP_PEEK, OP_REJECT, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX, OP_RX_TRACK, OP_SCAN,
6
6
  OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
7
- OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_RGATE2, OP_STRICT,
7
+ OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_RGATE2, OP_STRICT, OP_CONT, OP_SEED,
8
8
  } from './ops.ts'
9
9
 
10
10
  /**
@@ -73,6 +73,14 @@ export function childSlotOffsets(code: ArrayLike<number>, ip: number, out: numbe
73
73
  out.push(ip + 2)
74
74
  return true
75
75
 
76
+ // `CONT corner wrapper tail`: `tail` is reached through `wrapper`.
77
+ case OP_CONT:
78
+ out.push(ip + 1, ip + 2)
79
+ return true
80
+ case OP_SEED:
81
+ out.push(ip + 1)
82
+ return true
83
+
76
84
  // `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
77
85
  case OP_STRICT:
78
86
  out.push(ip + 1, ip + 2)
@@ -51,7 +51,7 @@ import {
51
51
  OP_LABEL, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_LIT_CI, OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_NAMES,
52
52
  OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX,
53
53
  OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
54
- OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_STRICT,
54
+ OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_STRICT, OP_CONT, OP_SEED,
55
55
  } from './ops.ts'
56
56
  import {
57
57
  choiceCannotCommit, choiceLogRollbackMask, choiceRollbackMask, failureLogRollback, failureRollbackClean, validateDispatchSpec,
@@ -67,6 +67,7 @@ import {
67
67
  scalarTerminalNodeChild, scalarTerminalNotChild, scalarTerminalPeekChild, type LeadingScalarSequence,
68
68
  } from './scalar-terminal.ts'
69
69
  import { childSlots } from './child-slots.ts'
70
+ import { canDecide, continuationGate } from './late-frame.ts'
70
71
  import { holdsGap, rowNullable } from './hold-gap.ts'
71
72
  import { gapRows } from './gap-gate.ts'
72
73
  import { fieldSpec, leadingTriviaFieldAt } from './field-spec.ts'
@@ -139,7 +140,7 @@ export const EMITTED_PARAMS = [
139
140
  // The deferred-commit trivia skip (`trivia-gap.ts`).
140
141
  'skipDeferredTrivia',
141
142
  // The pass-through collapse (`run-support.ts`).
142
- 'collapseEmpty',
143
+ 'collapseEmpty', 'popCstChild',
143
144
  // Constructor-built tree objects (`cst/plain.d.ts`): a `new` call has no
144
145
  // allocation site, so V8 cannot pretenure them.
145
146
  '_SP', '_LF', '_ND', '_FC', '_BUF',
@@ -674,7 +675,8 @@ export function emitAssemblySource(
674
675
  // less than reading the slot costs; only a gap matched by its RegExp takes the
675
676
  // slot (`gapRegexLowers`).
676
677
  const GAP_ROWS = gapNeutral ? new Set<number>() : new Set([...gapRows(code, roots)].filter(row => !gapRegexLowers(k[code[row + 1]!])))
677
- const labels = computeSiteLabels(code, roots, hostCst)
678
+ const labels = computeSiteLabels(code, roots, hostCst,
679
+ cfg.tolerant || cfg.probe ? undefined : (ip, tri) => canDecide(code, ip, tri, t.triviaScan))
678
680
  // Eligibility is pooled by the terminal's existing constant operand, matching
679
681
  // the closure recognizer pool: distinct terminal rows sharing one spec share
680
682
  // both the recognizer and the ordinary-terminal lowering.
@@ -1037,6 +1039,17 @@ return 1
1037
1039
  return c => `${c}<55296&&!(${leads.map(r => r.lo === r.hi ? `${c}===${r.lo}` : `(${c}>=${r.lo}&&${c}<=${r.hi})`).join('||')})`
1038
1040
  }
1039
1041
 
1042
+ /** `ctx.captureTrivia === true && (a sink is open)`, as far as the label resolves it. */
1043
+ function skipCapturing(l: SiteLabel): string {
1044
+ if (l.tri < 0 || !swapLegal || triviaLabelled[l.tri]! || t.triviaScan[l.tri] == null) return 'true'
1045
+ return capturesHere(l)
1046
+ }
1047
+
1048
+ function capturesHere(l: SiteLabel): string {
1049
+ const sink = l.buf ? 'true' : '(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)'
1050
+ return l.cap === CAP_OFF ? 'false' : l.cap === CAP_ON ? sink : `(ctx.captureTrivia===true&&${sink})`
1051
+ }
1052
+
1040
1053
  function skipFor(l: SiteLabel): string {
1041
1054
  if (l.tri < 0) return '_skipTrivia'
1042
1055
  const ki = l.tri
@@ -1205,6 +1218,8 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
1205
1218
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2]!
1206
1219
  if (op === OP_RULE || op === OP_GAPGATE) return code[ip + 1]!
1207
1220
  if (op === OP_STRICT) return code[cfg.tolerant || cfg.probe ? ip + 2 : ip + 1]!
1221
+ if (op === OP_CONT && !labels.late.has(ip)) return code[ip + 2]!
1222
+ if (op === OP_SEED) return code[ip + 1]!
1208
1223
  // A SCOPE THAT INSTALLS WHAT IS ALREADY INSTALLED. `encode.ts:520` wraps
1209
1224
  // EVERY rule of a `rules({ trivia }, …)` map in its own `OP_SCOPE_PLAIN`, so a
1210
1225
  // grammar with one ambient trivia re-installs the same slot at every rule
@@ -1220,6 +1235,9 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
1220
1235
  return undefined
1221
1236
  }
1222
1237
 
1238
+ /** Set by `OP_CONT` for the `OP_NODE` it lowers in its own function. */
1239
+ let LATE: { prefix: string; body: string } | undefined
1240
+
1223
1241
  function lower(ip: number, fname: string): string {
1224
1242
  const op = code[ip]
1225
1243
  const head = `function ${fname}(input,pos,ctx){`
@@ -1428,6 +1446,70 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
1428
1446
  // hand-built-program idiom this file's driver tests use.
1429
1447
  return `${head}EC.e=pos;return ''}`
1430
1448
 
1449
+ case OP_CONT: {
1450
+ const tri = L.tri
1451
+ const g = continuationGate(code, code[ip + 3]!)!
1452
+ const missAt = (idx: number, at: string): string => {
1453
+ const resolved = t.cc[idx]!
1454
+ const ci = classes.push([resolved]) - 1
1455
+ classPlan.push([idx])
1456
+ const ref = hoist('cg', `CLS[${ci}][0]`)
1457
+ return isAsciiOnlyClass(resolved) ? `${ref}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${ref},lead(input,${at}))`
1458
+ }
1459
+ // The gap the tail would start past, read without recording anything: no scan
1460
+ // at a character no trivia can start.
1461
+ let scanned = ''
1462
+ if (tri >= 0) {
1463
+ const scan = hoist('cs', `TRIVIASCAN[${tri}]`)
1464
+ const miss = triviaMiss(tri)
1465
+ scanned = miss === undefined
1466
+ ? `const q0=${scan}(input,c1)\n`
1467
+ : `const cc=input.charCodeAt(c1)\nconst q0=${miss('cc')}?c1:${scan}(input,c1)\n`
1468
+ }
1469
+ const at = tri >= 0 ? 'q0' : 'c1'
1470
+ let test: string
1471
+ if (g.gapRow < 0) test = `if(c0!==undefined&&${missAt(g.cls, at)})return c0\n`
1472
+ else {
1473
+ const re = hoist('cr', `K[${code[g.gapRow + 1]!}]`)
1474
+ const other = g.other >= 0 ? missAt(g.other, at) : 'true'
1475
+ test = `${re}.lastIndex=${at}\nconst gq=${re}.test(input)?${re}.lastIndex:-1\nif(c0!==undefined&&(gq<0||${missAt(g.follow, 'gq')})&&${other})return c0\n`
1476
+ }
1477
+ const seq = code[code[ip + 2]! + 2]!
1478
+ const seqLabel = labels.at(seq)
1479
+ const tail = link(code[ip + 3]!)
1480
+ const recorded = tri === TRI_NONE ? '' : `const tl0=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
1481
+ const lg0=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
1482
+ const rt0=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
1483
+ const s0=${skipFor(seqLabel)}(input,c1,ctx)
1484
+ const tl1=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
1485
+ const lg1=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
1486
+ const rt1=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
1487
+ v=${tail}(input,s0,ctx)
1488
+ if(v!==FAIL&&EC.e<=s0){rollbackScannedTriviaAt(ctx,tl0,tl1,lg0,lg1,rt0,rt1);EC.e=c1}`
1489
+ const quiet = `v=${tail}(input,${at},ctx)
1490
+ if(v!==FAIL&&EC.e<=${at})EC.e=c1`
1491
+ const capture = capturesHere(seqLabel)
1492
+ // No gap: nothing to record, keep or take back. Nothing recording: not scanned again.
1493
+ const body = `let v
1494
+ ${tri === TRI_NONE ? `v=${tail}(input,c1,ctx)`
1495
+ : `if(q0===c1)v=${tail}(input,c1,ctx)
1496
+ else ${capture === 'true' ? `{\n${recorded}\n}`
1497
+ : `if(ctx._triviaLog===undefined&&ctx._rootTriviaLog===undefined${capture === 'false' ? '' : `&&!${capture}`}){
1498
+ ${quiet}
1499
+ }else{
1500
+ ${recorded}
1501
+ }`}`}`
1502
+ const wrapperIp = code[ip + 2]!
1503
+ LATE = {
1504
+ prefix: `const c0=${link(code[ip + 1]!)}(input,pos,ctx)
1505
+ if(c0===FAIL)return FAIL
1506
+ const c1=EC.e
1507
+ ${scanned}${test}`,
1508
+ body,
1509
+ }
1510
+ return lower(wrapperIp, fname)
1511
+ }
1512
+
1431
1513
  case OP_GATE: {
1432
1514
  const child = link(code[ip + 2]!)
1433
1515
  const xf = fxRef(code[ip + 3]!)
@@ -2661,7 +2743,9 @@ return out
2661
2743
  case OP_NODE:
2662
2744
  case OP_NODE_TRACK: {
2663
2745
  const flags = code[ip + 3]!
2664
- const scalarChild = scalarTerminalNodeChild(code, ip)
2746
+ const late = LATE
2747
+ LATE = undefined
2748
+ const scalarChild = late === undefined ? scalarTerminalNodeChild(code, ip) : -1
2665
2749
  if (scalarChild >= 0 && scalarSpecs.has(code[scalarChild + 1]!)) {
2666
2750
  const recognize = recognizerRef(code[scalarChild + 1]!)
2667
2751
  const spec = code[scalarChild] === OP_RX ? null : k[code[scalarChild + 1]!] as string
@@ -2687,7 +2771,9 @@ EC.e=end
2687
2771
  return nd
2688
2772
  }`
2689
2773
  }
2690
- const child = link(code[ip + 2]!)
2774
+ const child = late === undefined ? link(code[ip + 2]!) : ''
2775
+ const runBody = late === undefined ? `const v=${child}(input,pos,ctx)` : late.body
2776
+ const takeBack = late === undefined ? '' : 'let c0Raw\nif(sBuf===undefined&&sRaw===undefined&&sCh!==undefined)sCh.pop()\nelse if(sBuf!==undefined||sCh!==undefined)c0Raw=popCstChild(ctx)\n'
2691
2777
  const proj = code[ip + 4]!
2692
2778
  const buildIdx = code[ip + 1]!
2693
2779
  const type = k[code[ip + 5]!] as string
@@ -2714,7 +2800,7 @@ return nd
2714
2800
  // THE PASS-THROUGH COLLAPSE (`run-support.ts` `collapseEmpty`): a
2715
2801
  // collapse over one node is that node. `passCollapse` is the closure
2716
2802
  // engine's test too.
2717
- if (build !== undefined && passCollapse(code, ip, hostCst)) {
2803
+ if (late === undefined && build !== undefined && passCollapse(code, ip, hostCst)) {
2718
2804
  return `${head}
2719
2805
  const v=${child}(input,pos,ctx)
2720
2806
  if(v!==undefined)return v
@@ -2725,7 +2811,7 @@ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
2725
2811
  // character at `pos` opens none of the body's optional terms and no
2726
2812
  // trivia, the body is its node term, run as a pass-through collapse.
2727
2813
  // Not under recovery or a probe: there a gated-out term still runs.
2728
- const gated = build !== undefined && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : undefined
2814
+ const gated = late === undefined && build !== undefined && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : undefined
2729
2815
  const triviaLead = gated === undefined ? undefined : triviaLeadRanges(labels.at(code[ip + 2]!).tri, t.trivia)
2730
2816
  const gp = gated !== undefined && triviaLead !== undefined && triviaLead.length <= 16
2731
2817
  ? `const gc=lead(input,pos)
@@ -2777,9 +2863,9 @@ sCh.push(nd)
2777
2863
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
2778
2864
  }`
2779
2865
  return `${head}
2780
- ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
2866
+ ${late?.prefix ?? ''}${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
2781
2867
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
2782
- const flat=[]
2868
+ ${takeBack}const flat=${late === undefined ? '[]' : '[c0]'}
2783
2869
  ctx._cstBuf=undefined
2784
2870
  ctx._cstChildren=flat
2785
2871
  ctx._cstLeaves=flat
@@ -2787,7 +2873,7 @@ ctx._cstRawChildren=undefined
2787
2873
  ctx._cstTriviaLog=undefined
2788
2874
  ctx.captureTrivia=false
2789
2875
  ctx._fields=${fields ? '[]' : 'undefined'}
2790
- const v=${child}(input,pos,ctx)
2876
+ ${runBody}
2791
2877
  ${trailingTrivia && L.tri !== TRI_NONE
2792
2878
  ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? '&&ctx.trivia!==undefined' : ''})EC.e=consumeTrivia(input,EC.e,ctx)\n`
2793
2879
  : ''}const captured=_capturedFlatChildren(flat)
@@ -2871,16 +2957,17 @@ const tlog=buf.tl??EMPTY_TLOG`
2871
2957
  const hostKids=kids
2872
2958
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
2873
2959
  const tlog=buf.tl??EMPTY_TLOG`
2960
+ const seedCapture = late === undefined ? '' : omitsRaw ? 'buf.single=c0\nbuf.rawLen=1\n' : 'buf.single=c0\nbuf.rawSingle=c0Raw!==undefined?c0Raw:rawEntry(c0,input,pos,c1)\n'
2874
2961
  return `${head}
2875
- ${!hostCst && !tracked ? gp : ''}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
2962
+ ${late?.prefix ?? ''}${!hostCst && !tracked ? gp : ''}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
2876
2963
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
2877
- ${openCapture}
2878
- ctx.captureTrivia=${captureWide}
2964
+ ${takeBack}${openCapture}
2965
+ ${seedCapture}ctx.captureTrivia=${captureWide}
2879
2966
  const savedFields=ctx._fields
2880
2967
  ctx._fields=${wantFields ? '[]' : 'undefined'}
2881
2968
  ${structural ? `const savedMask=ctx._triviaCaptureMask
2882
2969
  if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
2883
- ` : ''}const v=${child}(input,pos,ctx)
2970
+ ` : ''}${runBody}
2884
2971
  ${trailingTrivia && L.tri !== TRI_NONE
2885
2972
  ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? '&&ctx.trivia!==undefined' : ''})EC.e=consumeTrivia(input,EC.e,ctx)\n`
2886
2973
  : ''}const fieldMap=${wantFields ? 'buildFieldMap(ctx._fields)' : 'undefined'}