parseman 0.49.0 → 0.50.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 (77) hide show
  1. package/dist/analysis/commitment.d.ts +2 -1
  2. package/dist/analysis/commitment.d.ts.map +1 -1
  3. package/dist/analysis/diagnostics.js +1931 -861
  4. package/dist/analysis/diagnostics.js.map +3 -3
  5. package/dist/analysis/rebuild.d.ts.map +1 -1
  6. package/dist/cli/index.js +1235 -164
  7. package/dist/cli/index.js.map +3 -3
  8. package/dist/combinators/trivia-skip.d.ts +1 -1
  9. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  10. package/dist/compiler/build-arity.d.ts +16 -0
  11. package/dist/compiler/build-arity.d.ts.map +1 -1
  12. package/dist/compiler/degradation.d.ts +0 -2
  13. package/dist/compiler/degradation.d.ts.map +1 -1
  14. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  15. package/dist/compiler/token-alphabet.d.ts +11 -0
  16. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  17. package/dist/compiler/token-capability.js +185 -20
  18. package/dist/compiler/token-capability.js.map +1 -1
  19. package/dist/cst/capture-buffer.d.ts +5 -1
  20. package/dist/cst/capture-buffer.d.ts.map +1 -1
  21. package/dist/index.js +1348 -279
  22. package/dist/index.js.map +3 -3
  23. package/dist/language-service/index.js +2 -1
  24. package/dist/language-service/index.js.map +1 -1
  25. package/dist/plugin/entry-supercompiler.d.ts +48 -0
  26. package/dist/plugin/entry-supercompiler.d.ts.map +1 -0
  27. package/dist/plugin/evaluator.d.ts.map +1 -1
  28. package/dist/plugin/index.d.ts.map +1 -1
  29. package/dist/plugin/index.js +1940 -385
  30. package/dist/plugin/index.js.map +3 -3
  31. package/dist/run/index.js +2 -1
  32. package/dist/run/index.js.map +1 -1
  33. package/dist/spec/index.js +28 -7
  34. package/dist/spec/index.js.map +1 -1
  35. package/dist/table/assemble.d.ts.map +1 -1
  36. package/dist/table/compile-rule-map.d.ts +6 -5
  37. package/dist/table/compile-rule-map.d.ts.map +1 -1
  38. package/dist/table/emit-assembly.d.ts +6 -1
  39. package/dist/table/emit-assembly.d.ts.map +1 -1
  40. package/dist/table/encode.d.ts.map +1 -1
  41. package/dist/table/index.js +1298 -231
  42. package/dist/table/index.js.map +3 -3
  43. package/dist/table/ops.d.ts +3 -2
  44. package/dist/table/ops.d.ts.map +1 -1
  45. package/dist/table/program.d.ts +15 -1
  46. package/dist/table/program.d.ts.map +1 -1
  47. package/dist/table/scalar-terminal.d.ts +30 -0
  48. package/dist/table/scalar-terminal.d.ts.map +1 -1
  49. package/dist/table/site-labels.d.ts +8 -0
  50. package/dist/table/site-labels.d.ts.map +1 -1
  51. package/dist/types.d.ts +2 -1
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/version.d.ts +1 -1
  54. package/package.json +1 -1
  55. package/src/analysis/commitment.ts +19 -8
  56. package/src/analysis/rebuild.ts +1 -0
  57. package/src/combinators/trivia-skip.ts +2 -2
  58. package/src/compiler/build-arity.ts +50 -0
  59. package/src/compiler/degradation.ts +0 -6
  60. package/src/compiler/ir-serialize.ts +6 -4
  61. package/src/compiler/token-alphabet.ts +322 -28
  62. package/src/cst/capture-buffer.ts +34 -11
  63. package/src/plugin/entry-supercompiler.ts +567 -0
  64. package/src/plugin/evaluator.ts +10 -0
  65. package/src/plugin/index.ts +7 -3
  66. package/src/table/assemble.ts +125 -42
  67. package/src/table/compile-rule-map.ts +8 -7
  68. package/src/table/compile.ts +7 -8
  69. package/src/table/emit-assembly.ts +646 -126
  70. package/src/table/emit.ts +1 -1
  71. package/src/table/encode.ts +132 -7
  72. package/src/table/ops.ts +3 -2
  73. package/src/table/program.ts +44 -3
  74. package/src/table/scalar-terminal.ts +213 -1
  75. package/src/table/site-labels.ts +22 -9
  76. package/src/types.ts +1 -1
  77. package/src/version.ts +1 -1
@@ -125,11 +125,12 @@ import {
125
125
  type SubtreeRef, type TableProgram, type TableRule,
126
126
  } from './program.ts'
127
127
  import { stampRuleMap } from './stamp.ts'
128
- import { reachableSites } from './site-labels.ts'
128
+ import { computeSiteLabels, reachableSites } from './site-labels.ts'
129
129
  import { refuseUnclassifiedRootScope } from '../cst/root-trivia-scope.ts'
130
130
  import { captureError, firstSetSentinel, matchesAt, orSentinel, recoverScan } from '../recovery/scan.ts'
131
131
  import {
132
- makeScalarRecognizer, scalarTerminalNodeChild, scalarTerminalNotChild, type ScalarRecognizer,
132
+ leadingLiteralFamily, leadingScalarSequence, leadingScalarTerminal, makeScalarRecognizer, scalarTerminalNodeChild,
133
+ scalarTerminalNotChild, type ScalarRecognizer,
133
134
  } from './scalar-terminal.ts'
134
135
 
135
136
  /**
@@ -482,6 +483,16 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
482
483
  return recognize
483
484
  }
484
485
 
486
+ const labelExtraIps: number[] = []
487
+ for (const s of prog.scans ?? []) {
488
+ for (const r of s.skip) labelExtraIps.push(r[0])
489
+ if (s.sentinel !== undefined) labelExtraIps.push(s.sentinel[0])
490
+ }
491
+ for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0])
492
+ const closureLabels = computeSiteLabels(
493
+ code, [...Object.values(prog.rules), ...labelExtraIps], hostCst,
494
+ )
495
+
485
496
  /**
486
497
  * The INSTALLED trivia scanner for the scope currently running.
487
498
  *
@@ -818,7 +829,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
818
829
  // has no single form. `rollbackNeeded` short-circuits true on a live buffer,
819
830
  // so the other seven sinks are not consulted — as before.
820
831
  const raw = b.raw
821
- MRAW = raw !== undefined ? raw.length : b.rawSingle !== undefined ? 1 : 0
832
+ MRAW = b.noRaw === true
833
+ ? b.rawLen ?? 0
834
+ : raw !== undefined ? raw.length : b.rawSingle !== undefined ? 1 : 0
822
835
  const ch = b.ch
823
836
  MLV = ch !== undefined ? ch.length : b.single !== undefined ? 1 : 0
824
837
  const tl = b.tl
@@ -1004,6 +1017,33 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1004
1017
  return cur
1005
1018
  }
1006
1019
 
1020
+ /** A non-first term at a site proven to run under an open node capture buffer. */
1021
+ function nextTermBuffered(child: Piece, input: string, cur: number, ctx: ParseContext): number {
1022
+ if (ctx.trivia === undefined) {
1023
+ const v = child(input, cur, ctx)
1024
+ if (v === FAIL) return -1
1025
+ TERMV = v
1026
+ return EC.e
1027
+ }
1028
+ const before = ctx._cstBuf!
1029
+ const beforeTl = before.tl
1030
+ const mTl = beforeTl === undefined ? 0 : beforeTl.length
1031
+ const mLog = ctx._triviaLog?.length ?? 0
1032
+ const mRoot = ctx._rootTriviaLog?.length ?? 0
1033
+ const scanEnd = skipTrivia(input, cur, ctx)
1034
+ const scanned = ctx._cstBuf!
1035
+ const scannedTl = scanned.tl
1036
+ const scanTl = scannedTl === undefined ? 0 : scannedTl.length
1037
+ const scanLog = ctx._triviaLog?.length ?? 0
1038
+ const scanRoot = ctx._rootTriviaLog?.length ?? 0
1039
+ const v = child(input, scanEnd, ctx)
1040
+ if (v === FAIL) return -1
1041
+ TERMV = v
1042
+ if (EC.e > scanEnd) return EC.e
1043
+ rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot)
1044
+ return cur
1045
+ }
1046
+
1007
1047
  function committed(c: ParseContext): boolean {
1008
1048
  return c._fc === true
1009
1049
  }
@@ -1288,7 +1328,16 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1288
1328
  const holder = { fwd, set: (p: Piece) => { target = p } }
1289
1329
  inFlight.set(ip, holder)
1290
1330
 
1291
- const piece = lower(ip)
1331
+ const op = code[ip]
1332
+ // Match the emitted assembly's label-proven scope alias: rule entries in a
1333
+ // single ambient trivia scope otherwise reinstall and restore the exact
1334
+ // same trivia, labels and scanner on every call. Install the forwarding
1335
+ // holder first so a recursive child can still link back through this site.
1336
+ const piece = (op === OP_SCOPE_PLAIN || (op === OP_SCOPE && code[ip + 3]! === 0))
1337
+ && code[ip + 1]! >= 0
1338
+ && closureLabels.at(ip).tri === code[ip + 1]!
1339
+ ? link(code[ip + 2]!)
1340
+ : lower(ip)
1292
1341
 
1293
1342
  inFlight.delete(ip)
1294
1343
  holder.set(piece)
@@ -2148,6 +2197,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2148
2197
  const fn = fused && projection < 0
2149
2198
  ? fns[reducer] as (value: unknown, span: { start: number; end: number }) => unknown
2150
2199
  : undefined
2200
+ const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm
2151
2201
 
2152
2202
  const runnerBlock = (
2153
2203
  count: number,
@@ -2255,7 +2305,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2255
2305
  const kid = link(kidIp)
2256
2306
  return (input, cur, ctx, inherited) => {
2257
2307
  ctx._sync = sync ?? inherited
2258
- return nextTerm(kid, input, cur, ctx)
2308
+ return step(kid, input, cur, ctx)
2259
2309
  }
2260
2310
  }
2261
2311
  const negated = code[kidIp + 1] === 1
@@ -2328,7 +2378,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2328
2378
  const kidIp = code[base + i]!
2329
2379
  if (code[kidIp] !== OP_ADJ) {
2330
2380
  const kid = link(kidIp)
2331
- return (input, cur, ctx) => nextTerm(kid, input, cur, ctx)
2381
+ return (input, cur, ctx) => step(kid, input, cur, ctx)
2332
2382
  }
2333
2383
  const negated = code[kidIp + 1] === 1
2334
2384
  const ki = code[kidIp + 2]!
@@ -2436,7 +2486,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2436
2486
  return (input, pos, ctx) => {
2437
2487
  const v0 = k0(input, pos, ctx)
2438
2488
  if (v0 === FAIL) return FAIL
2439
- const cur = nextTerm(k1, input, EC.e, ctx)
2489
+ const cur = step(k1, input, EC.e, ctx)
2440
2490
  if (cur < 0) return FAIL
2441
2491
  EC.e = cur
2442
2492
  return projection === 0 ? v0
@@ -2448,7 +2498,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2448
2498
  return (input, pos, ctx) => {
2449
2499
  const v0 = k0(input, pos, ctx)
2450
2500
  if (v0 === FAIL) return FAIL
2451
- const cur = nextTerm(k1, input, EC.e, ctx)
2501
+ const cur = step(k1, input, EC.e, ctx)
2452
2502
  if (cur < 0) return FAIL
2453
2503
  EC.e = cur
2454
2504
  return [v0, TERMV]
@@ -2457,7 +2507,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2457
2507
  return (input, pos, ctx) => {
2458
2508
  const v0 = k0(input, pos, ctx)
2459
2509
  if (v0 === FAIL) return FAIL
2460
- const cur = nextTerm(k1, input, EC.e, ctx)
2510
+ const cur = step(k1, input, EC.e, ctx)
2461
2511
  if (cur < 0) return FAIL
2462
2512
  EC.e = cur
2463
2513
  return undefined
@@ -2470,10 +2520,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2470
2520
  return (input, pos, ctx) => {
2471
2521
  const v0 = k0(input, pos, ctx)
2472
2522
  if (v0 === FAIL) return FAIL
2473
- let cur = nextTerm(k1, input, EC.e, ctx)
2523
+ let cur = step(k1, input, EC.e, ctx)
2474
2524
  if (cur < 0) return FAIL
2475
2525
  const v1 = TERMV
2476
- cur = nextTerm(k2, input, cur, ctx)
2526
+ cur = step(k2, input, cur, ctx)
2477
2527
  if (cur < 0) return FAIL
2478
2528
  EC.e = cur
2479
2529
  return projection === 0 ? v0
@@ -2486,10 +2536,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2486
2536
  return (input, pos, ctx) => {
2487
2537
  const v0 = k0(input, pos, ctx)
2488
2538
  if (v0 === FAIL) return FAIL
2489
- let cur = nextTerm(k1, input, EC.e, ctx)
2539
+ let cur = step(k1, input, EC.e, ctx)
2490
2540
  if (cur < 0) return FAIL
2491
2541
  const v1 = TERMV
2492
- cur = nextTerm(k2, input, cur, ctx)
2542
+ cur = step(k2, input, cur, ctx)
2493
2543
  if (cur < 0) return FAIL
2494
2544
  EC.e = cur
2495
2545
  return [v0, v1, TERMV]
@@ -2498,9 +2548,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2498
2548
  return (input, pos, ctx) => {
2499
2549
  const v0 = k0(input, pos, ctx)
2500
2550
  if (v0 === FAIL) return FAIL
2501
- let cur = nextTerm(k1, input, EC.e, ctx)
2551
+ let cur = step(k1, input, EC.e, ctx)
2502
2552
  if (cur < 0) return FAIL
2503
- cur = nextTerm(k2, input, cur, ctx)
2553
+ cur = step(k2, input, cur, ctx)
2504
2554
  if (cur < 0) return FAIL
2505
2555
  EC.e = cur
2506
2556
  return undefined
@@ -2516,43 +2566,43 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2516
2566
  next: SequenceTermBlock | undefined,
2517
2567
  ): SequenceTermBlock => {
2518
2568
  if (count === 1) return (input, cur, ctx, values) => {
2519
- cur = nextTerm(k0, input, cur, ctx)
2569
+ cur = step(k0, input, cur, ctx)
2520
2570
  if (cur < 0) return -1
2521
2571
  if (values !== undefined) values.push(TERMV)
2522
2572
  return next === undefined ? cur : next(input, cur, ctx, values)
2523
2573
  }
2524
2574
  if (count === 2) return (input, cur, ctx, values) => {
2525
- cur = nextTerm(k0, input, cur, ctx)
2575
+ cur = step(k0, input, cur, ctx)
2526
2576
  if (cur < 0) return -1
2527
2577
  if (values !== undefined) values.push(TERMV)
2528
- cur = nextTerm(k1, input, cur, ctx)
2578
+ cur = step(k1, input, cur, ctx)
2529
2579
  if (cur < 0) return -1
2530
2580
  if (values !== undefined) values.push(TERMV)
2531
2581
  return next === undefined ? cur : next(input, cur, ctx, values)
2532
2582
  }
2533
2583
  if (count === 3) return (input, cur, ctx, values) => {
2534
- cur = nextTerm(k0, input, cur, ctx)
2584
+ cur = step(k0, input, cur, ctx)
2535
2585
  if (cur < 0) return -1
2536
2586
  if (values !== undefined) values.push(TERMV)
2537
- cur = nextTerm(k1, input, cur, ctx)
2587
+ cur = step(k1, input, cur, ctx)
2538
2588
  if (cur < 0) return -1
2539
2589
  if (values !== undefined) values.push(TERMV)
2540
- cur = nextTerm(k2, input, cur, ctx)
2590
+ cur = step(k2, input, cur, ctx)
2541
2591
  if (cur < 0) return -1
2542
2592
  if (values !== undefined) values.push(TERMV)
2543
2593
  return next === undefined ? cur : next(input, cur, ctx, values)
2544
2594
  }
2545
2595
  return (input, cur, ctx, values) => {
2546
- cur = nextTerm(k0, input, cur, ctx)
2596
+ cur = step(k0, input, cur, ctx)
2547
2597
  if (cur < 0) return -1
2548
2598
  if (values !== undefined) values.push(TERMV)
2549
- cur = nextTerm(k1, input, cur, ctx)
2599
+ cur = step(k1, input, cur, ctx)
2550
2600
  if (cur < 0) return -1
2551
2601
  if (values !== undefined) values.push(TERMV)
2552
- cur = nextTerm(k2, input, cur, ctx)
2602
+ cur = step(k2, input, cur, ctx)
2553
2603
  if (cur < 0) return -1
2554
2604
  if (values !== undefined) values.push(TERMV)
2555
- cur = nextTerm(k3, input, cur, ctx)
2605
+ cur = step(k3, input, cur, ctx)
2556
2606
  if (cur < 0) return -1
2557
2607
  if (values !== undefined) values.push(TERMV)
2558
2608
  return next === undefined ? cur : next(input, cur, ctx, values)
@@ -2722,6 +2772,13 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2722
2772
  if (n === 2 || n === 3) {
2723
2773
  const a0 = link(code[base]!), a1 = link(code[base + 1]!)
2724
2774
  const a2 = n === 3 ? link(code[base + 2]!) : undefined
2775
+ const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines
2776
+ const p0ip = predecide ? leadingScalarTerminal(code, code[base]!, 2, true, true) : -1
2777
+ const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1]!, 2, true, true) : -1
2778
+ const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2]!, 2, true, true) : -1
2779
+ const p0 = p0ip < 0 ? undefined : scalarFor(p0ip)
2780
+ const p1 = p1ip < 0 ? undefined : scalarFor(p1ip)
2781
+ const p2 = p2ip < 0 ? undefined : scalarFor(p2ip)
2725
2782
  const e0 = fx[code[base + n]!] as string[]
2726
2783
  const e1 = fx[code[base + n + 1]!] as string[]
2727
2784
  const e2 = n === 3 ? fx[code[base + n + 2]!] as string[] : undefined
@@ -2751,7 +2808,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2751
2808
  let acc: string[] | undefined
2752
2809
  let best = pos
2753
2810
  if (c < 128) {
2754
- const bits = mask[c < 0 ? 128 : c]!
2811
+ let bits = mask[c < 0 ? 128 : c]!
2812
+ if ((bits & 1) !== 0 && p0 !== undefined && p0(input, pos) < 0) bits &= ~1
2813
+ if ((bits & 2) !== 0 && p1 !== undefined && p1(input, pos) < 0) bits &= ~2
2814
+ if ((bits & 4) !== 0 && p2 !== undefined && p2(input, pos) < 0) bits &= ~4
2755
2815
  let prev = 0
2756
2816
  if ((bits & 1) !== 0) {
2757
2817
  ctx._fc = false
@@ -2796,7 +2856,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2796
2856
  return FAIL
2797
2857
  }
2798
2858
 
2799
- if (g0 === null || classHas(g0, c)) {
2859
+ if ((g0 === null || classHas(g0, c)) && (p0 === undefined || p0(input, pos) >= 0)) {
2800
2860
  ctx._fc = false
2801
2861
  const v = a0(input, pos, ctx)
2802
2862
  if (v !== FAIL) return v
@@ -2806,7 +2866,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2806
2866
  if (committed(ctx)) { if (acc !== undefined) ctx._fx = acc; return FAIL }
2807
2867
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
2808
2868
  } else if (best === pos) acc = accSet(e0, acc)
2809
- if (g1 === null || classHas(g1, c)) {
2869
+ if ((g1 === null || classHas(g1, c)) && (p1 === undefined || p1(input, pos) >= 0)) {
2810
2870
  ctx._fc = false
2811
2871
  const v = a1(input, pos, ctx)
2812
2872
  if (v !== FAIL) return v
@@ -2817,7 +2877,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2817
2877
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
2818
2878
  } else if (best === pos) acc = accSet(e1, acc)
2819
2879
  if (n === 3) {
2820
- if (g2 === null || classHas(g2, c)) {
2880
+ if ((g2 === null || classHas(g2, c)) && (p2 === undefined || p2(input, pos) >= 0)) {
2821
2881
  ctx._fc = false
2822
2882
  const v = a2!(input, pos, ctx)
2823
2883
  if (v !== FAIL) return v
@@ -3432,6 +3492,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3432
3492
  // grammar collapse form and the host collapse predicate.
3433
3493
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap
3434
3494
  const rawOnly = !keepChildren
3495
+ const omitsRaw = !hostCst && build !== undefined && proj < 0 && (flags & 2) !== 0
3435
3496
  return (input, pos, ctx) => {
3436
3497
  const host = HOST
3437
3498
  // `beginCstNodeCapture`/`endCstNodeCapture` INLINED, and the two objects
@@ -3444,17 +3505,12 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3444
3505
  // allocations a parse that the compiled engine (which inlines its own
3445
3506
  // capture prologue and epilogue) never makes.
3446
3507
  const sCh = ctx._cstChildren
3447
- const sLv = ctx._cstLeaves
3448
- const sRaw = ctx._cstRawChildren
3449
- const sTl = ctx._cstTriviaLog
3450
3508
  const sCap = ctx.captureTrivia
3451
3509
  const sBuf = ctx._cstBuf
3452
- const buf: CstCaptureBuf = rawOnly ? { rawOnly: true } : {}
3510
+ const buf: CstCaptureBuf = rawOnly
3511
+ ? { rawOnly: true }
3512
+ : omitsRaw ? { noRaw: true, rawLen: 0 } : {}
3453
3513
  ctx._cstBuf = buf
3454
- ctx._cstChildren = undefined
3455
- ctx._cstLeaves = undefined
3456
- ctx._cstRawChildren = undefined
3457
- ctx._cstTriviaLog = undefined
3458
3514
  // `begin` sets this true and the caller immediately cleared it when the
3459
3515
  // node does not capture wide. Net: the flag IS `captureWide`, a const.
3460
3516
  ctx.captureTrivia = captureWide
@@ -3476,13 +3532,11 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3476
3532
  if (structural) ctx._triviaCaptureMask = savedMask
3477
3533
  const kids = rawOnly ? EMPTY_CH : buf.ch ?? (buf.single !== undefined ? [buf.single] : EMPTY_CH)
3478
3534
  const hostKids = kids
3479
- const rawKids = buf.raw ?? (buf.rawSingle !== undefined ? [buf.rawSingle] : EMPTY_CH)
3535
+ const rawKids = omitsRaw
3536
+ ? EMPTY_CH
3537
+ : buf.raw ?? (buf.rawSingle !== undefined ? [buf.rawSingle] : EMPTY_CH)
3480
3538
  const tlog = buf.tl ?? EMPTY_TLOG
3481
3539
  ctx._cstBuf = sBuf
3482
- ctx._cstChildren = sCh
3483
- ctx._cstLeaves = sLv
3484
- ctx._cstRawChildren = sRaw
3485
- ctx._cstTriviaLog = sTl
3486
3540
  ctx.captureTrivia = sCap
3487
3541
  if (v === FAIL) return FAIL
3488
3542
  const end = EC.e
@@ -3620,6 +3674,35 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3620
3674
  rawScalarSpecs.add(code[child + 1]!)
3621
3675
  scalarFor(child)
3622
3676
  }
3677
+ } else if (code[ip] === OP_CHOICE && !disp[code[ip + 1]!]!.exclusive) {
3678
+ const n = code[ip + 2]!
3679
+ for (let i = 0; i < n; i++) {
3680
+ const armIp = code[ip + 4 + i]!
3681
+ const child = leadingScalarTerminal(code, armIp, 2, true, true)
3682
+ if (n === 2 || n === 3) {
3683
+ if (child >= 0) scalarFor(child)
3684
+ continue
3685
+ }
3686
+ if (child >= 0) {
3687
+ const spec = k[code[child + 1]!]
3688
+ if (code[child] === OP_LIT && typeof spec === 'string' && spec.length >= 2) {
3689
+ scalarFor(child)
3690
+ continue
3691
+ }
3692
+ }
3693
+ const family = leadingLiteralFamily(code, k, armIp)
3694
+ if (family !== undefined && family.length >= 2 && family.every(terminal => {
3695
+ const value = k[code[terminal + 1]!]
3696
+ return typeof value === 'string' && value.length >= 2
3697
+ })) {
3698
+ for (const terminal of family) scalarFor(terminal)
3699
+ }
3700
+ const sequence = leadingScalarSequence(code, armIp)
3701
+ if (sequence !== undefined && (sequence.trivia < 0
3702
+ || triviaScan[sequence.trivia] != null)) {
3703
+ for (const terminal of sequence.terminals) scalarFor(terminal)
3704
+ }
3705
+ }
3623
3706
  }
3624
3707
  }
3625
3708
  const notChild = scalarTerminalNotChild(code, ip)
@@ -116,16 +116,17 @@ export type CompiledRuleMapTable = {
116
116
  hostBranchElided: boolean
117
117
  reflection: GrammarReflection
118
118
  /**
119
- * The RUNNABLE map, which the source lowering has no counterpart for — it
119
+ * The LIVE RUNNABLE map, which the source lowering has no counterpart for — it
120
120
  * hands back text and nothing else, because its artifact only exists once the
121
121
  * emitted source is evaluated. A table exists as data before it is printed, so
122
122
  * the same call that produces the replacement can also hand back the parser.
123
- * That is what makes a differential against the interpreter possible without
124
- * `eval`, and it is why the table-vs-interpreter test can compare `expected`
125
- * sets rather than only accept/reject.
123
+ * It may use runtime assembly specialisation; `prog` and `replacement` remain
124
+ * serialized closure artifacts. That is what makes a differential against the
125
+ * interpreter possible without `eval`, and it is why the table-vs-interpreter
126
+ * test can compare `expected` sets rather than only accept/reject.
126
127
  */
127
128
  rules: Record<string, TableRule>
128
- /** The encoded program, for a caller that wants to fold or inspect it. */
129
+ /** The closure-stamped wire program, for a caller that wants to fold or inspect it. */
129
130
  prog: TableProgram
130
131
  /**
131
132
  * The coverage DENOMINATOR — every id this map can hit — present only under
@@ -237,7 +238,7 @@ export function compileRuleMapRunnable(
237
238
  hostBranchElided: hostMode === 'ast' && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
238
239
  reflection: collectGrammarReflection(ruleMap),
239
240
  ...(plan === undefined ? {} : { coverageDefinitions: plan.definitions }),
240
- rules: tableRules(artifact),
241
+ rules: tableRules(prog),
241
242
  prog: artifact,
242
243
  }
243
244
  }
@@ -348,7 +349,7 @@ export function compileRuleMap(
348
349
  hostBranchElided: hostMode === 'ast' && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
349
350
  reflection: collectGrammarReflection(ruleMap),
350
351
  ...(plan === undefined ? {} : { coverageDefinitions: plan.definitions }),
351
- rules: tableRules(artifact),
352
+ rules: tableRules(prog),
352
353
  prog: artifact,
353
354
  }
354
355
  }
@@ -156,17 +156,16 @@ function compileImpl<T>(
156
156
  // this is the same guard on the single-root entry point.
157
157
  const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator as Combinator<unknown> }, settings)
158
158
  /**
159
- * `compile()` and the macro must hand the driver the SAME artifact shape.
159
+ * LIVE parsers may assemble the encoded program into specialised functions.
160
+ * `tableRules` falls back to closure assembly when dynamic construction is not
161
+ * available, so this remains runnable under a restrictive CSP.
160
162
  *
161
- * An absent `asm` previously selected runtime `new Function` emission while
162
- * macro output printed `a:[]` and selected closure assembly. That made one
163
- * grammar have two normal execution paths. The compact table artifact is now
164
- * canonical: both paths carry an explicit empty inventory and use the shared
165
- * closure assembler. Static factories remain an opt-in experiment until they
166
- * can satisfy both semantic identity and the size budget.
163
+ * PRINTED artifacts are different: they must not require `new Function` after
164
+ * import. Give the emitters the canonical explicit-empty assembly inventory,
165
+ * while the parser returned by this call runs the raw program's fast path.
167
166
  */
168
167
  const artifact = closureArtifact(prog)
169
- const entry = tableRules(artifact)[ENTRY]!
168
+ const entry = tableRules(prog)[ENTRY]!
170
169
 
171
170
  // Captured-first, supplied-as-fill-in. The encoder records a source per author
172
171
  // callback from the def (`fnSrc` / `buildSrc` / `predSrc` / `gateSrcs`), which the