parseman 0.48.1 → 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 (83) 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 +1236 -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/linker.d.ts.map +1 -1
  16. package/dist/compiler/token-alphabet.d.ts +11 -0
  17. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  18. package/dist/compiler/token-capability.js +185 -20
  19. package/dist/compiler/token-capability.js.map +1 -1
  20. package/dist/cst/capture-buffer.d.ts +5 -1
  21. package/dist/cst/capture-buffer.d.ts.map +1 -1
  22. package/dist/index.js +1354 -278
  23. package/dist/index.js.map +3 -3
  24. package/dist/language-service/index.js +2 -1
  25. package/dist/language-service/index.js.map +1 -1
  26. package/dist/plugin/direct-builder-static.d.ts +20 -0
  27. package/dist/plugin/direct-builder-static.d.ts.map +1 -1
  28. package/dist/plugin/entry-supercompiler.d.ts +48 -0
  29. package/dist/plugin/entry-supercompiler.d.ts.map +1 -0
  30. package/dist/plugin/evaluator.d.ts +13 -0
  31. package/dist/plugin/evaluator.d.ts.map +1 -1
  32. package/dist/plugin/index.d.ts.map +1 -1
  33. package/dist/plugin/index.js +2118 -376
  34. package/dist/plugin/index.js.map +3 -3
  35. package/dist/run/index.js +2 -1
  36. package/dist/run/index.js.map +1 -1
  37. package/dist/spec/index.js +29 -7
  38. package/dist/spec/index.js.map +1 -1
  39. package/dist/table/assemble.d.ts.map +1 -1
  40. package/dist/table/compile-rule-map.d.ts +6 -5
  41. package/dist/table/compile-rule-map.d.ts.map +1 -1
  42. package/dist/table/emit-assembly.d.ts +6 -1
  43. package/dist/table/emit-assembly.d.ts.map +1 -1
  44. package/dist/table/encode.d.ts.map +1 -1
  45. package/dist/table/index.js +1298 -231
  46. package/dist/table/index.js.map +3 -3
  47. package/dist/table/ops.d.ts +3 -2
  48. package/dist/table/ops.d.ts.map +1 -1
  49. package/dist/table/program.d.ts +15 -1
  50. package/dist/table/program.d.ts.map +1 -1
  51. package/dist/table/scalar-terminal.d.ts +30 -0
  52. package/dist/table/scalar-terminal.d.ts.map +1 -1
  53. package/dist/table/site-labels.d.ts +8 -0
  54. package/dist/table/site-labels.d.ts.map +1 -1
  55. package/dist/types.d.ts +8 -2
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/version.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/src/analysis/commitment.ts +19 -8
  60. package/src/analysis/rebuild.ts +1 -0
  61. package/src/combinators/trivia-skip.ts +2 -2
  62. package/src/compiler/build-arity.ts +50 -0
  63. package/src/compiler/degradation.ts +0 -6
  64. package/src/compiler/ir-serialize.ts +17 -3
  65. package/src/compiler/linker.ts +14 -1
  66. package/src/compiler/token-alphabet.ts +322 -28
  67. package/src/cst/capture-buffer.ts +34 -11
  68. package/src/plugin/direct-builder-static.ts +116 -12
  69. package/src/plugin/entry-supercompiler.ts +567 -0
  70. package/src/plugin/evaluator.ts +60 -2
  71. package/src/plugin/index.ts +147 -4
  72. package/src/table/assemble.ts +125 -42
  73. package/src/table/compile-rule-map.ts +8 -7
  74. package/src/table/compile.ts +7 -8
  75. package/src/table/emit-assembly.ts +646 -126
  76. package/src/table/emit.ts +1 -1
  77. package/src/table/encode.ts +132 -7
  78. package/src/table/ops.ts +3 -2
  79. package/src/table/program.ts +44 -3
  80. package/src/table/scalar-terminal.ts +213 -1
  81. package/src/table/site-labels.ts +22 -9
  82. package/src/types.ts +1 -1
  83. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -392,7 +392,7 @@ function beginCstNodeCapture(ctx) {
392
392
  function finishCstBuf(buf) {
393
393
  if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
394
394
  const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
395
- const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
395
+ const rawChildren = buf.noRaw === true ? EMPTY : buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
396
396
  const triviaLog = buf.tl ?? EMPTY_TL;
397
397
  return { children: children2, rawChildren, triviaLog };
398
398
  }
@@ -424,7 +424,8 @@ function pushCstChild(ctx, built, rawEntry2) {
424
424
  b.single = void 0;
425
425
  } else b.single = built;
426
426
  }
427
- if (b.raw) b.raw.push(rawEntry2);
427
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 0) + 1;
428
+ else if (b.raw) b.raw.push(rawEntry2);
428
429
  else if (b.rawSingle !== void 0) {
429
430
  b.raw = [b.rawSingle, rawEntry2];
430
431
  b.rawSingle = void 0;
@@ -438,6 +439,7 @@ function pushCstChild(ctx, built, rawEntry2) {
438
439
  function cstRawLen(ctx) {
439
440
  const b = ctx._cstBuf;
440
441
  if (b) {
442
+ if (b.noRaw === true) return b.rawLen ?? 0;
441
443
  if (b.raw) return b.raw.length;
442
444
  return b.rawSingle !== void 0 ? 1 : 0;
443
445
  }
@@ -497,19 +499,37 @@ function rollbackCstCaptureAt(ctx, raw, tlog, leaves, fields, errors) {
497
499
  if (ctx._errors && errors !== void 0 && ctx._errors.length !== errors) ctx._errors.length = errors;
498
500
  const b = ctx._cstBuf;
499
501
  if (b) {
500
- rollbackBufList(b, "raw", "rawSingle", raw);
501
- rollbackBufList(b, "ch", "single", leaves);
502
+ if (b.noRaw === true) {
503
+ if (b.rawLen !== raw) b.rawLen = raw;
504
+ } else {
505
+ const rawList = b.raw;
506
+ if (rawList) {
507
+ if (raw === 0) b.raw = void 0;
508
+ else if (raw === 1) {
509
+ b.rawSingle = rawList[0];
510
+ b.raw = void 0;
511
+ } else if (rawList.length !== raw) rawList.length = raw;
512
+ } else if (raw === 0) b.rawSingle = void 0;
513
+ }
514
+ const childList = b.ch;
515
+ if (childList) {
516
+ if (leaves === 0) b.ch = void 0;
517
+ else if (leaves === 1) {
518
+ b.single = childList[0];
519
+ b.ch = void 0;
520
+ } else if (childList.length !== leaves) childList.length = leaves;
521
+ } else if (leaves === 0) b.single = void 0;
502
522
  if (b.tl) {
503
523
  if (tlog === 0) b.tl = void 0;
504
524
  else if (b.tl.length !== tlog) b.tl.length = tlog;
505
525
  }
506
- if (ctx._fields && ctx._fields.length !== fields) ctx._fields.length = fields;
526
+ if (ctx._fields && fields !== void 0 && ctx._fields.length !== fields) ctx._fields.length = fields;
507
527
  return;
508
528
  }
509
529
  if (ctx._cstRawChildren && ctx._cstRawChildren.length !== raw) ctx._cstRawChildren.length = raw;
510
530
  if (ctx._cstTriviaLog && ctx._cstTriviaLog.length !== tlog) ctx._cstTriviaLog.length = tlog;
511
531
  if (ctx._cstLeaves && ctx._cstLeaves.length !== leaves) ctx._cstLeaves.length = leaves;
512
- if (ctx._fields && ctx._fields.length !== fields) ctx._fields.length = fields;
532
+ if (ctx._fields && fields !== void 0 && ctx._fields.length !== fields) ctx._fields.length = fields;
513
533
  }
514
534
  function pushCstTriviaEntry(ctx, start, end, kindIndex) {
515
535
  const insertIdx = cstRawLen(ctx);
@@ -981,6 +1001,13 @@ function canConsumeNewline(n) {
981
1001
  return n.parts.some(canConsumeNewline);
982
1002
  }
983
1003
  }
1004
+ function regexCanMatchEmpty(source) {
1005
+ try {
1006
+ return nullable(parseRegex(source));
1007
+ } catch {
1008
+ return true;
1009
+ }
1010
+ }
984
1011
  function firstSetFromRegex(source) {
985
1012
  let ast;
986
1013
  try {
@@ -4588,6 +4615,7 @@ function confirmedArityForDef(def) {
4588
4615
  }
4589
4616
  function buildReadsRaw(def) {
4590
4617
  if (!def.build) return true;
4618
+ if (def.buildRawUnused === true) return false;
4591
4619
  const arity = confirmedArityForDef(def);
4592
4620
  if (arity === null) return true;
4593
4621
  return arity >= 4;
@@ -5384,6 +5412,399 @@ function ruleDependencies(ruleMap) {
5384
5412
  return deps;
5385
5413
  }
5386
5414
 
5415
+ // src/analysis/commitment.ts
5416
+ function mayFail(p, seen = /* @__PURE__ */ new Set()) {
5417
+ if (seen.has(p)) return true;
5418
+ seen.add(p);
5419
+ const d = p._def;
5420
+ switch (d.tag) {
5421
+ case "literal":
5422
+ return d.value.length > 0;
5423
+ case "trivia":
5424
+ return false;
5425
+ // `optional`/`many`/a min-0 `sepBy` swallow an ORDINARY failure — zero
5426
+ // repetitions is a match. They do NOT swallow a COMMITTED one: a dispatch
5427
+ // that has selected an arm and then failed inside it breaks out past every
5428
+ // enclosing repeat, straight to the fallible boundary. So these are total
5429
+ // exactly when their body cannot commit. (Measured: treating them as
5430
+ // unconditionally total left an extra zero-width leaf in
5431
+ // `BareInterpolatedSelector` on benchmark.less — a rollback the legacy
5432
+ // build fired and this one had deleted.)
5433
+ case "optional":
5434
+ case "many":
5435
+ return mayCommitFailure(d.parser);
5436
+ case "sepBy":
5437
+ return d.min >= 1 ? mayFail(d.parser, seen) : mayCommitFailure(d.parser) || mayCommitFailure(d.separator);
5438
+ case "oneOrMore":
5439
+ return mayFail(d.parser, seen);
5440
+ case "sequence":
5441
+ return d.parsers.some((x) => mayFail(x, seen));
5442
+ // Delegating wrappers: as fallible as what they wrap.
5443
+ case "node":
5444
+ case "transform":
5445
+ case "label":
5446
+ case "field":
5447
+ case "expect":
5448
+ case "withCtx":
5449
+ case "grammar":
5450
+ case "token":
5451
+ case "leaf":
5452
+ return mayFail(d.parser, seen);
5453
+ case "lazy": {
5454
+ try {
5455
+ return mayFail(d.thunk(), seen);
5456
+ } catch {
5457
+ return true;
5458
+ }
5459
+ }
5460
+ // An adjacency assertion is a TEST — failing is its whole job.
5461
+ case "adjacency":
5462
+ return true;
5463
+ default:
5464
+ return true;
5465
+ }
5466
+ }
5467
+ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set(), triviaActive = true) {
5468
+ if (seen.has(p)) return false;
5469
+ seen.add(p);
5470
+ const d = p._def;
5471
+ switch (d.tag) {
5472
+ // Atomic / non-capturing-then-failing: a failure happens before any push.
5473
+ case "literal":
5474
+ case "regex":
5475
+ case "keywords":
5476
+ case "guard":
5477
+ // Adjacency probes with `_cap = 0` / no `commit()`: it cannot push anything.
5478
+ case "adjacency":
5479
+ case "not":
5480
+ // peek(): emitted under a non-capturing probe ctx and zero-width on both
5481
+ // outcomes, so it can never leave a partial capture behind.
5482
+ case "peek":
5483
+ case "trivia":
5484
+ case "token":
5485
+ case "leaf":
5486
+ case "scanTo":
5487
+ case "unknown":
5488
+ return false;
5489
+ // node() captures into its own private buffers and rolls them back on
5490
+ // failure (emitNode restores _ctx.* and never pushes on the !ok path).
5491
+ case "node":
5492
+ return false;
5493
+ // choice/firstMatch already roll back each failed arm; on overall failure
5494
+ // nothing committed remains.
5495
+ case "choice":
5496
+ return false;
5497
+ case "dispatch":
5498
+ return capturesLeaf(d.selector, new Set(seen)) || d.cases.some((x) => mayLeavePartialCapture(x.parser, new Set(seen), triviaActive) || capturesLeaf(x.parser, new Set(seen))) || (d.matchers ? d.matchers.some((x) => mayLeavePartialCapture(x.parser, new Set(seen), triviaActive) || capturesLeaf(x.parser, new Set(seen))) : false) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, new Set(seen), triviaActive) || capturesLeaf(d.otherwise, new Set(seen)) : false);
5499
+ case "attempt":
5500
+ return false;
5501
+ // optional never fails; many/oneOrMore only "fail" with zero captured items.
5502
+ case "optional":
5503
+ case "many":
5504
+ case "oneOrMore":
5505
+ return false;
5506
+ // sepBy emits its own per-iteration rollback in emitSepBy.
5507
+ case "sepBy":
5508
+ return false;
5509
+ // A sequence is the real case: an earlier capturing term followed by a term
5510
+ // that can fail leaves the earlier captures buffered.
5511
+ //
5512
+ // BOTH halves of that sentence are load-bearing, and the second half is what
5513
+ // this walk exists to exploit. "Some earlier term captures" alone was the old
5514
+ // test, and it is true of very nearly every sequence in a real grammar — a
5515
+ // sequence almost always opens with a literal or a node. The rollback is only
5516
+ // reachable if something AFTER the capture can still fail; once the remainder
5517
+ // is total (`optional`/`many`/trivia/a min-0 `sepBy`), the sequence has no
5518
+ // failure path left to roll back from, and the save+restore is dead code.
5519
+ //
5520
+ // `captured` tracks whether anything is in the buffers yet as the scan moves
5521
+ // left to right. Two things put it there:
5522
+ // - a term that captures (`capturesLeaf`/`hasNodeDef`), and
5523
+ // - the inter-term TRIVIA scan, which under `capturing` pushes into
5524
+ // `_cstRawChildren`/`_cstTriviaLog` BEFORE the term at each boundary
5525
+ // i >= 1. `emitSeqValues` only rewinds that push on the term's SUCCESS
5526
+ // path (the "matched empty, so leave the whitespace out of the span"
5527
+ // branch); a term that FAILS breaks straight out with the trivia still
5528
+ // buffered, so from boundary 1 onward the buffers are dirty regardless of
5529
+ // what the earlier terms did.
5530
+ // Each term is also asked about itself: a nested sequence can leave its own
5531
+ // partial capture behind, and its terms are emitted inline into this same
5532
+ // block with no boundary of their own to roll them back.
5533
+ case "sequence": {
5534
+ const parts = d.parsers;
5535
+ let captured = false;
5536
+ for (let i = 0; i < parts.length; i++) {
5537
+ const part = parts[i];
5538
+ if (i > 0 && triviaActive) captured = true;
5539
+ if (captured && mayFail(part)) return true;
5540
+ if (mayLeavePartialCapture(part, seen, triviaActive)) return true;
5541
+ if (capturesLeaf(part) || hasNodeDef(part)) captured = true;
5542
+ }
5543
+ return false;
5544
+ }
5545
+ // Delegating wrappers: defer to the wrapped parser.
5546
+ case "transform":
5547
+ case "label":
5548
+ case "field":
5549
+ case "expect":
5550
+ case "withCtx":
5551
+ case "grammar":
5552
+ return mayLeavePartialCapture(d.parser, seen, triviaActive);
5553
+ case "recover":
5554
+ return mayLeavePartialCapture(d.parser, seen, triviaActive);
5555
+ case "lazy": {
5556
+ try {
5557
+ return mayLeavePartialCapture(d.thunk(), seen, triviaActive);
5558
+ } catch {
5559
+ return true;
5560
+ }
5561
+ }
5562
+ // Unknown shapes: be safe and keep the rollback.
5563
+ default:
5564
+ return true;
5565
+ }
5566
+ }
5567
+ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
5568
+ if (seen.has(p)) return false;
5569
+ seen.add(p);
5570
+ const d = p._def;
5571
+ switch (d.tag) {
5572
+ case "literal":
5573
+ case "regex":
5574
+ case "keywords":
5575
+ case "node":
5576
+ case "token":
5577
+ case "routed":
5578
+ case "leaf":
5579
+ return true;
5580
+ case "not":
5581
+ case "peek":
5582
+ case "guard":
5583
+ case "adjacency":
5584
+ case "trivia":
5585
+ case "unknown":
5586
+ return false;
5587
+ case "sequence":
5588
+ case "choice":
5589
+ return d.parsers.some((x) => capturesLeaf(x, seen));
5590
+ case "dispatch":
5591
+ return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => capturesLeaf(entry.parser, seen)) : false) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
5592
+ case "sepBy":
5593
+ return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
5594
+ case "many":
5595
+ case "oneOrMore":
5596
+ case "optional":
5597
+ case "attempt":
5598
+ case "transform":
5599
+ case "label":
5600
+ case "field":
5601
+ case "expect":
5602
+ case "withCtx":
5603
+ case "grammar":
5604
+ case "recover":
5605
+ return capturesLeaf(d.parser, seen);
5606
+ case "scanTo":
5607
+ return true;
5608
+ case "lazy": {
5609
+ try {
5610
+ return capturesLeaf(d.thunk(), seen);
5611
+ } catch {
5612
+ return true;
5613
+ }
5614
+ }
5615
+ default:
5616
+ return true;
5617
+ }
5618
+ }
5619
+ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
5620
+ if (seen.has(p)) return false;
5621
+ seen.add(p);
5622
+ const d = p._def;
5623
+ switch (d.tag) {
5624
+ case "node":
5625
+ return true;
5626
+ case "lazy": {
5627
+ try {
5628
+ return hasNodeDef(d.thunk(), seen);
5629
+ } catch {
5630
+ return false;
5631
+ }
5632
+ }
5633
+ case "grammar":
5634
+ case "trivia":
5635
+ case "token":
5636
+ case "leaf":
5637
+ case "label":
5638
+ case "field":
5639
+ case "optional":
5640
+ case "many":
5641
+ case "oneOrMore":
5642
+ case "not":
5643
+ case "peek":
5644
+ case "transform":
5645
+ return hasNodeDef(d.parser, seen);
5646
+ case "sequence":
5647
+ case "choice":
5648
+ return d.parsers.some((x) => hasNodeDef(x, seen));
5649
+ case "dispatch":
5650
+ return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => hasNodeDef(entry.parser, seen)) : false) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
5651
+ case "sepBy":
5652
+ return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
5653
+ case "scanTo":
5654
+ return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
5655
+ case "recover":
5656
+ return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
5657
+ case "expect":
5658
+ return hasNodeDef(d.parser, seen);
5659
+ case "withCtx":
5660
+ return hasNodeDef(d.parser, seen);
5661
+ default:
5662
+ return false;
5663
+ }
5664
+ }
5665
+ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
5666
+ if (seen.has(p)) return false;
5667
+ seen.add(p);
5668
+ const d = p._def;
5669
+ switch (d.tag) {
5670
+ case "node":
5671
+ return d.build !== void 0 || hasDirectBuildDef(d.parser, seen);
5672
+ case "lazy": {
5673
+ try {
5674
+ return hasDirectBuildDef(d.thunk(), seen);
5675
+ } catch {
5676
+ return false;
5677
+ }
5678
+ }
5679
+ case "grammar":
5680
+ case "trivia":
5681
+ case "token":
5682
+ case "leaf":
5683
+ case "label":
5684
+ case "field":
5685
+ case "optional":
5686
+ case "many":
5687
+ case "oneOrMore":
5688
+ case "attempt":
5689
+ case "not":
5690
+ case "peek":
5691
+ case "withCtx":
5692
+ case "expect":
5693
+ case "transform":
5694
+ return hasDirectBuildDef(d.parser, seen);
5695
+ case "sequence":
5696
+ case "choice":
5697
+ return d.parsers.some((x) => hasDirectBuildDef(x, seen));
5698
+ case "dispatch":
5699
+ return hasDirectBuildDef(d.selector, seen) || d.cases.some((x) => hasDirectBuildDef(x.parser, seen)) || (d.matchers ? d.matchers.some((x) => hasDirectBuildDef(x.parser, seen)) : false) || (d.otherwise ? hasDirectBuildDef(d.otherwise, seen) : false);
5700
+ case "sepBy":
5701
+ return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.separator, seen);
5702
+ case "scanTo":
5703
+ return hasDirectBuildDef(d.sentinel, seen) || d.skip.some((x) => hasDirectBuildDef(x, seen));
5704
+ case "recover":
5705
+ return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.sentinel, seen);
5706
+ case "routed":
5707
+ return d.fallback ? hasDirectBuildDef(d.fallback, seen) : false;
5708
+ default:
5709
+ return false;
5710
+ }
5711
+ }
5712
+ function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
5713
+ if (seen.has(p)) return false;
5714
+ seen.add(p);
5715
+ const d = p._def;
5716
+ switch (d.tag) {
5717
+ case "dispatch":
5718
+ return true;
5719
+ case "choice":
5720
+ case "sequence":
5721
+ return d.parsers.some((x) => mayCommitFailure(x, seen, resolve));
5722
+ case "many":
5723
+ case "oneOrMore":
5724
+ case "optional":
5725
+ case "attempt":
5726
+ case "transform":
5727
+ case "label":
5728
+ case "field":
5729
+ case "grammar":
5730
+ case "node":
5731
+ return mayCommitFailure(d.parser, seen, resolve);
5732
+ case "sepBy":
5733
+ return mayCommitFailure(d.parser, seen, resolve) || mayCommitFailure(d.separator, seen, resolve);
5734
+ case "token":
5735
+ case "leaf":
5736
+ return mayCommitFailure(d.parser, seen, resolve);
5737
+ case "withCtx":
5738
+ return mayCommitFailure(d.parser, seen, resolve);
5739
+ case "scanTo":
5740
+ return mayCommitFailure(d.sentinel, seen, resolve) || d.skip.some((x) => mayCommitFailure(x, seen, resolve));
5741
+ case "lazy": {
5742
+ try {
5743
+ return mayCommitFailure(d.thunk(), seen, resolve);
5744
+ } catch {
5745
+ const name = p._ruleName;
5746
+ const target = name === void 0 ? void 0 : resolve?.(name);
5747
+ return target === void 0 ? true : mayCommitFailure(target, seen, resolve);
5748
+ }
5749
+ }
5750
+ case "unknown":
5751
+ return true;
5752
+ default:
5753
+ return false;
5754
+ }
5755
+ }
5756
+ function hasSemanticReduction(roots, externalRefs) {
5757
+ const seen = /* @__PURE__ */ new Set();
5758
+ const visit = (parser2) => {
5759
+ if (seen.has(parser2)) return false;
5760
+ seen.add(parser2);
5761
+ const def = parser2._def;
5762
+ if (def.tag === "transform" && !def.recognitionOnly) return true;
5763
+ if (def.tag === "choice" && def.gates.some(Boolean)) return true;
5764
+ if (def.tag === "guard" || def.tag === "withCtx") return true;
5765
+ if (def.tag === "node" && def.build !== void 0) return true;
5766
+ if (def.tag === "lazy") {
5767
+ if (externalRefs?.has(parser2)) return false;
5768
+ try {
5769
+ return visit(def.thunk());
5770
+ } catch {
5771
+ return true;
5772
+ }
5773
+ }
5774
+ return childrenOf2(def).some(visit);
5775
+ };
5776
+ return roots.some(visit);
5777
+ }
5778
+ function classifyRuleMap(ruleMap) {
5779
+ const externalRefs = /* @__PURE__ */ new Set();
5780
+ const scanned = /* @__PURE__ */ new Set();
5781
+ const scanExternal = (p) => {
5782
+ if (scanned.has(p)) return;
5783
+ scanned.add(p);
5784
+ const def = p._def;
5785
+ if (def.tag === "lazy") {
5786
+ let resolved;
5787
+ try {
5788
+ resolved = def.thunk();
5789
+ } catch {
5790
+ resolved = void 0;
5791
+ }
5792
+ if (resolved === void 0) {
5793
+ if (p._ruleName) externalRefs.add(p);
5794
+ return;
5795
+ }
5796
+ scanExternal(resolved);
5797
+ return;
5798
+ }
5799
+ for (const child of childrenOf2(def)) scanExternal(child);
5800
+ };
5801
+ for (const [, rule] of ruleMap) scanExternal(rule);
5802
+ return {
5803
+ hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
5804
+ isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule), externalRefs)
5805
+ };
5806
+ }
5807
+
5387
5808
  // src/table/ops.ts
5388
5809
  var OP_LIT = 1;
5389
5810
  var OP_RX = 2;
@@ -5939,8 +6360,26 @@ function validateDispatchSpec(spec, arity, fallbackRouted) {
5939
6360
  }
5940
6361
  }
5941
6362
  var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
5942
- function ownTableProgram(prog, resolved) {
5943
- return { ...prog, [TABLE_RUNTIME]: { resolved } };
6363
+ function ownTableProgram(prog, resolved, caches = {}) {
6364
+ const runtime = prog[TABLE_RUNTIME];
6365
+ return {
6366
+ ...prog,
6367
+ [TABLE_RUNTIME]: {
6368
+ resolved,
6369
+ choiceRollbackMasks: caches.choiceRollbackMasks ?? runtime?.choiceRollbackMasks,
6370
+ nonCommittingChoiceSites: caches.nonCommittingChoiceSites ?? runtime?.nonCommittingChoiceSites,
6371
+ failureRollbackCleanSites: caches.failureRollbackCleanSites ?? runtime?.failureRollbackCleanSites
6372
+ }
6373
+ };
6374
+ }
6375
+ function choiceRollbackMask(prog, ip) {
6376
+ return prog[TABLE_RUNTIME]?.choiceRollbackMasks?.get(ip);
6377
+ }
6378
+ function choiceCannotCommit(prog, ip) {
6379
+ return prog[TABLE_RUNTIME]?.nonCommittingChoiceSites?.has(ip) === true;
6380
+ }
6381
+ function failureRollbackClean(prog, ip) {
6382
+ return prog[TABLE_RUNTIME]?.failureRollbackCleanSites?.has(ip) === true;
5944
6383
  }
5945
6384
  var WIDE_CLASS_PREFIX_LO = 65535;
5946
6385
  var WIDE_CLASS_PREFIX_HI = 0;
@@ -6115,7 +6554,6 @@ function directArrayProjection(fn, fnSrc, arity) {
6115
6554
 
6116
6555
  // src/table/encode.ts
6117
6556
  import {
6118
- assertLexicalCapabilityClosure,
6119
6557
  collectLexicalCapabilities,
6120
6558
  winnerWrapsReference as winnerWrapsReference2
6121
6559
  } from "./compiler/token-capability.js";
@@ -6497,6 +6935,9 @@ var Encoder = class {
6497
6935
  lexIndex = /* @__PURE__ */ new Map();
6498
6936
  lexPrograms = [];
6499
6937
  lexProgramIndex = /* @__PURE__ */ new Map();
6938
+ choiceRollbackMasks = /* @__PURE__ */ new Map();
6939
+ nonCommittingChoiceSites = /* @__PURE__ */ new Set();
6940
+ failureRollbackCleanSites = /* @__PURE__ */ new Set();
6500
6941
  labels = void 0;
6501
6942
  /** Trivia table in scope at the row being encoded — codegen's `ctx.activeTrivia`. */
6502
6943
  activeTrivia = void 0;
@@ -6907,6 +7348,71 @@ var Encoder = class {
6907
7348
  const w = this.winners;
6908
7349
  return w === void 0 ? void 0 : (name) => w[name];
6909
7350
  }
7351
+ /**
7352
+ * Whether a failed ordered-choice arm can leave state that the enclosing
7353
+ * choice must restore before trying its successor.
7354
+ *
7355
+ * `mayLeavePartialCapture` is the existing sound CST/trivia proof. The extra
7356
+ * writer census covers the side sinks that proof deliberately does not model:
7357
+ * fields, recovered errors, and interpreted scanners. Strict assemblies do
7358
+ * not run repeat recovery, but these rows can still publish through a caller's
7359
+ * context. Cycles are safe to stop: revisiting the same combinator cannot
7360
+ * discover a writer the first traversal did not already reach.
7361
+ */
7362
+ failureNeedsRollback(p, autoNot) {
7363
+ const refName = p._ruleName;
7364
+ const winner = refName === void 0 ? void 0 : this.winners?.[refName];
7365
+ const root = winner !== void 0 && !winnerWrapsReference2(winner, p) ? winner : p;
7366
+ const sideWriterMemo = /* @__PURE__ */ new Map();
7367
+ const hasSideWriter = (current, seen = /* @__PURE__ */ new Set()) => {
7368
+ const cached = sideWriterMemo.get(current);
7369
+ if (cached !== void 0) return { found: cached, complete: true };
7370
+ if (seen.has(current)) return { found: false, complete: false };
7371
+ const next = new Set(seen);
7372
+ next.add(current);
7373
+ const def = current._def;
7374
+ let result;
7375
+ switch (def.tag) {
7376
+ case "field":
7377
+ case "expect":
7378
+ case "recover":
7379
+ case "scanTo":
7380
+ case "unknown":
7381
+ result = { found: true, complete: true };
7382
+ break;
7383
+ case "lazy": {
7384
+ const name = current._ruleName;
7385
+ const resolvedWinner = name === void 0 ? void 0 : this.winners?.[name];
7386
+ if (resolvedWinner !== void 0 && !winnerWrapsReference2(resolvedWinner, current)) {
7387
+ result = hasSideWriter(resolvedWinner, next);
7388
+ break;
7389
+ }
7390
+ try {
7391
+ result = hasSideWriter(def.thunk(), next);
7392
+ } catch {
7393
+ result = { found: true, complete: true };
7394
+ }
7395
+ break;
7396
+ }
7397
+ default: {
7398
+ let complete = true;
7399
+ result = { found: false, complete: true };
7400
+ for (const child of childrenOf2(def)) {
7401
+ const childResult = hasSideWriter(child, next);
7402
+ if (childResult.found) {
7403
+ result = { found: true, complete: true };
7404
+ break;
7405
+ }
7406
+ complete &&= childResult.complete;
7407
+ }
7408
+ if (!result.found) result = { found: false, complete };
7409
+ }
7410
+ }
7411
+ if (result.found || result.complete) sideWriterMemo.set(current, result.found);
7412
+ return result;
7413
+ };
7414
+ return mayLeavePartialCapture(root, /* @__PURE__ */ new Set(), true) || hasSideWriter(root).found || (autoNot?.length ?? 0) > 0 && capturesLeaf(root);
7415
+ }
6910
7416
  /** A first set becomes a char class string, or −1 for `any`. */
6911
7417
  charClass(fs) {
6912
7418
  if (fs.kind !== "ranges" || fs.ranges.length === 0) return -1;
@@ -7192,9 +7698,39 @@ var Encoder = class {
7192
7698
  });
7193
7699
  const rr = this.refResolver();
7194
7700
  const finalChoice = classifyFinalChoice(arms, rr);
7195
- const classes = arms.map((_, i) => finalChoice.nullable[i] ? -1 : this.charClass(finalChoice.firstSets[i]));
7701
+ const transactionalFirst = arms.map((arm, i) => {
7702
+ if (!finalChoice.nullable[i]) return void 0;
7703
+ const def = arm._def;
7704
+ if (def.tag !== "attempt" || matchesEmpty(def.parser, /* @__PURE__ */ new Set(), rr)) return void 0;
7705
+ return firstSetOf(def.parser, /* @__PURE__ */ new Set(), rr);
7706
+ });
7707
+ const gateFirst = finalChoice.firstSets.map((first, i) => transactionalFirst[i] ?? first);
7708
+ const classes = gateFirst.map((first, i) => finalChoice.nullable[i] && transactionalFirst[i] === void 0 ? -1 : this.charClass(first));
7709
+ if (transactionalFirst.some((first) => first !== void 0) && classes.every((cls) => cls >= 0)) {
7710
+ let overlap = false;
7711
+ for (let i = 0; i < gateFirst.length && !overlap; i++) {
7712
+ for (let j = i + 1; j < gateFirst.length; j++) {
7713
+ if (intersects(gateFirst[i], gateFirst[j])) {
7714
+ overlap = true;
7715
+ break;
7716
+ }
7717
+ }
7718
+ }
7719
+ if (!overlap) for (let i = 0; i < classes.length; i++) {
7720
+ if (transactionalFirst[i] !== void 0) classes[i] = -1;
7721
+ }
7722
+ }
7196
7723
  const dispIdx = this.disp.length;
7197
7724
  this.disp.push(classes);
7725
+ let rollbackMask = kids.length > 31 ? -1 : 0;
7726
+ if (rollbackMask === 0) {
7727
+ for (let i = 0; i < arms.length; i++) {
7728
+ const src = order[i];
7729
+ if (this.failureNeedsRollback(arms[i], d.autoNot[src])) {
7730
+ rollbackMask |= 1 << i;
7731
+ }
7732
+ }
7733
+ }
7198
7734
  const head = this.emitHead(OP_CHOICE, 3 + 2 * kids.length);
7199
7735
  this.code[head + 1] = dispIdx;
7200
7736
  this.code[head + 2] = kids.length;
@@ -7203,6 +7739,10 @@ var Encoder = class {
7203
7739
  this.code[head + 4 + i] = kids[i];
7204
7740
  this.code[head + 4 + kids.length + i] = this.expected(deriveExpected(arms[i]));
7205
7741
  }
7742
+ this.choiceRollbackMasks.set(head, rollbackMask);
7743
+ if (arms.every((arm) => !mayCommitFailure(arm, /* @__PURE__ */ new Set(), rr))) {
7744
+ this.nonCommittingChoiceSites.add(head);
7745
+ }
7206
7746
  return head;
7207
7747
  }
7208
7748
  case "many":
@@ -7232,8 +7772,11 @@ var Encoder = class {
7232
7772
  }
7233
7773
  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);
7234
7774
  }
7235
- case "optional":
7236
- return this.emit(OP_OPT, this.node(d.parser).ip);
7775
+ case "optional": {
7776
+ const head = this.emit(OP_OPT, this.node(d.parser).ip);
7777
+ if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(head);
7778
+ return head;
7779
+ }
7237
7780
  case "transform": {
7238
7781
  const inner = d.parser._def;
7239
7782
  if (inner.tag === "sequence" && !this.memo.has(d.parser) && !this.pending.has(d.parser)) {
@@ -7392,6 +7935,7 @@ var Encoder = class {
7392
7935
  // lowering was correct only for a choice arm.
7393
7936
  case "attempt": {
7394
7937
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
7938
+ if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7395
7939
  const fs = d.parser._meta.firstSet;
7396
7940
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
7397
7941
  const cls = this.charClass(fs);
@@ -7560,6 +8104,10 @@ var Encoder = class {
7560
8104
  ...this.rec ? { rec: 1 } : {},
7561
8105
  ...this.cov === void 0 ? {} : { cov: this.cov },
7562
8106
  lines: this.track ? 1 : 0
8107
+ }, void 0, {
8108
+ choiceRollbackMasks: this.choiceRollbackMasks,
8109
+ failureRollbackCleanSites: this.failureRollbackCleanSites,
8110
+ nonCommittingChoiceSites: this.nonCommittingChoiceSites
7563
8111
  });
7564
8112
  }
7565
8113
  };
@@ -7607,7 +8155,6 @@ function encodeTableProgram(ruleMap, settings = {}) {
7607
8155
  const lexicalRoots = [...names].sort().map((name) => ruleMap[name]);
7608
8156
  const resolveLexical = (name) => ruleMap[name];
7609
8157
  const capabilities = collectLexicalCapabilities(lexicalRoots, resolveLexical);
7610
- assertLexicalCapabilityClosure(lexicalRoots, capabilities, resolveLexical);
7611
8158
  const enc = new Encoder(resolvedSettings, capabilities.capabilityComplete);
7612
8159
  enc.winners = ruleMap;
7613
8160
  for (const name of names) enc.encodeRule(name, ruleMap[name]);
@@ -8740,13 +9287,17 @@ var TRI_NONE = -1;
8740
9287
  var CAP_UNKNOWN = 0;
8741
9288
  var CAP_OFF = 1;
8742
9289
  var CAP_ON = 2;
8743
- var TOP = { tri: TRI_UNKNOWN, buf: false, cap: CAP_UNKNOWN };
9290
+ var RAW_UNKNOWN = 0;
9291
+ var RAW_CAPTURE = 1;
9292
+ var RAW_OMIT = 2;
9293
+ var TOP = { tri: TRI_UNKNOWN, buf: false, raw: RAW_UNKNOWN, cap: CAP_UNKNOWN };
8744
9294
  function meet(a, b) {
8745
9295
  const tri = a.tri === b.tri ? a.tri : TRI_UNKNOWN;
8746
9296
  const buf = a.buf && b.buf;
9297
+ const raw = a.raw === b.raw ? a.raw : RAW_UNKNOWN;
8747
9298
  const cap = a.cap === b.cap ? a.cap : CAP_UNKNOWN;
8748
- if (tri === a.tri && buf === a.buf && cap === a.cap) return a;
8749
- return { tri, buf, cap };
9299
+ if (tri === a.tri && buf === a.buf && raw === a.raw && cap === a.cap) return a;
9300
+ return { tri, buf, raw, cap };
8750
9301
  }
8751
9302
  function reachableSites(code, roots) {
8752
9303
  const seen = /* @__PURE__ */ new Set();
@@ -8769,25 +9320,26 @@ function transfer(code, ip, at, hostCst) {
8769
9320
  const tri = ki < 0 ? TRI_NONE : ki;
8770
9321
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
8771
9322
  if (tri === at.tri && cap === at.cap) return at;
8772
- return { tri, buf: at.buf, cap };
9323
+ return { tri, buf: at.buf, raw: at.raw, cap };
8773
9324
  }
8774
9325
  if (op === OP_NODE || op === OP_NODE_TRACK) {
8775
9326
  const flags = code[ip + 3];
8776
9327
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags === 2 || flags === 18 || flags === 34);
8777
9328
  if (directChildren) {
8778
- return { tri: at.tri, buf: false, cap: CAP_OFF };
9329
+ return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
8779
9330
  }
8780
9331
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
8781
- if (at.buf && cap === at.cap) return at;
8782
- return { tri: at.tri, buf: true, cap };
9332
+ const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
9333
+ if (at.buf && raw === at.raw && cap === at.cap) return at;
9334
+ return { tri: at.tri, buf: true, raw, cap };
8783
9335
  }
8784
9336
  if (op === OP_TOKEN) {
8785
9337
  if (at.tri === TRI_NONE && !at.buf) return at;
8786
- return { tri: TRI_NONE, buf: false, cap: at.cap };
9338
+ return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
8787
9339
  }
8788
9340
  if (op === OP_LEAF) {
8789
9341
  if (!at.buf) return at;
8790
- return { tri: at.tri, buf: false, cap: at.cap };
9342
+ return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
8791
9343
  }
8792
9344
  return at;
8793
9345
  }
@@ -8854,6 +9406,162 @@ function scalarTerminalNotChild(code, ip) {
8854
9406
  const op = code[child];
8855
9407
  return op === OP_RX || op === OP_LIT ? child : -1;
8856
9408
  }
9409
+ function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
9410
+ const seen = /* @__PURE__ */ new Set();
9411
+ let at = ip;
9412
+ let depth = 0;
9413
+ while (!seen.has(at)) {
9414
+ seen.add(at);
9415
+ const op = code[at];
9416
+ if (op === OP_LIT || op === OP_RX) return depth >= minDepth ? at : -1;
9417
+ if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || throughAttempt && op === OP_ATTEMPT) {
9418
+ at = code[at + 1];
9419
+ depth++;
9420
+ continue;
9421
+ }
9422
+ if (throughPeek && op === OP_PEEK) {
9423
+ at = code[at + 1];
9424
+ depth++;
9425
+ continue;
9426
+ }
9427
+ if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
9428
+ at = code[at + 2];
9429
+ depth++;
9430
+ continue;
9431
+ }
9432
+ if (op === OP_SEQ || op === OP_SEQV) {
9433
+ if (code[at + 1] < 1) return -1;
9434
+ at = code[at + 2];
9435
+ depth++;
9436
+ continue;
9437
+ }
9438
+ if (op === OP_SEQX) {
9439
+ if (code[at + 2] < 1) return -1;
9440
+ at = code[at + 3];
9441
+ depth++;
9442
+ continue;
9443
+ }
9444
+ return -1;
9445
+ }
9446
+ return -1;
9447
+ }
9448
+ function leadingScalarSequence(code, ip) {
9449
+ const wholeScalar = (start) => {
9450
+ const seen2 = /* @__PURE__ */ new Set();
9451
+ let at2 = start;
9452
+ while (!seen2.has(at2)) {
9453
+ seen2.add(at2);
9454
+ const op = code[at2];
9455
+ if (op === OP_LIT || op === OP_RX) return at2;
9456
+ if (op === OP_RULE || op === OP_TOKEN || op === OP_ATTEMPT) {
9457
+ at2 = code[at2 + 1];
9458
+ continue;
9459
+ }
9460
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
9461
+ at2 = code[at2 + 2];
9462
+ continue;
9463
+ }
9464
+ if (op === OP_SEQ || op === OP_SEQV) {
9465
+ if (code[at2 + 1] !== 1) return -1;
9466
+ at2 = code[at2 + 2];
9467
+ continue;
9468
+ }
9469
+ if (op === OP_SEQX) {
9470
+ if (code[at2 + 2] !== 1) return -1;
9471
+ at2 = code[at2 + 3];
9472
+ continue;
9473
+ }
9474
+ return -1;
9475
+ }
9476
+ return -1;
9477
+ };
9478
+ const seen = /* @__PURE__ */ new Set();
9479
+ let at = ip;
9480
+ let ambientTrivia;
9481
+ while (!seen.has(at)) {
9482
+ seen.add(at);
9483
+ const op = code[at];
9484
+ if (op === OP_RULE) {
9485
+ at = code[at + 1];
9486
+ continue;
9487
+ }
9488
+ if (op === OP_SCOPE_PLAIN) {
9489
+ ambientTrivia = code[at + 1];
9490
+ at = code[at + 2];
9491
+ continue;
9492
+ }
9493
+ if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
9494
+ at = code[at + 2];
9495
+ continue;
9496
+ }
9497
+ const n = op === OP_SEQ || op === OP_SEQV ? code[at + 1] : op === OP_SEQX ? code[at + 2] : 0;
9498
+ if (n < 3 || ambientTrivia === void 0) return void 0;
9499
+ const base = op === OP_SEQX ? at + 3 : at + 2;
9500
+ const terminals = [
9501
+ wholeScalar(code[base]),
9502
+ wholeScalar(code[base + 1]),
9503
+ wholeScalar(code[base + 2])
9504
+ ];
9505
+ return terminals.every((terminal) => terminal >= 0) ? { terminals, trivia: ambientTrivia } : void 0;
9506
+ }
9507
+ return void 0;
9508
+ }
9509
+ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
9510
+ const active = /* @__PURE__ */ new Set();
9511
+ const walk = (at, depth) => {
9512
+ if (active.has(at)) return void 0;
9513
+ active.add(at);
9514
+ try {
9515
+ const op = code[at];
9516
+ if (op === OP_LIT) {
9517
+ const value = constants[code[at + 1]];
9518
+ return depth >= minDepth && typeof value === "string" && value.length > 0 ? [at] : void 0;
9519
+ }
9520
+ if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || op === OP_ATTEMPT || op === OP_PEEK) {
9521
+ return walk(code[at + 1], depth + 1);
9522
+ }
9523
+ if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
9524
+ return walk(code[at + 2], depth + 1);
9525
+ }
9526
+ if (op === OP_SEQ || op === OP_SEQV) {
9527
+ return code[at + 1] < 1 ? void 0 : walk(code[at + 2], depth + 1);
9528
+ }
9529
+ if (op === OP_SEQX) {
9530
+ return code[at + 2] < 1 ? void 0 : walk(code[at + 3], depth + 1);
9531
+ }
9532
+ if (op !== OP_CHOICE) return void 0;
9533
+ const n = code[at + 2];
9534
+ if (n < 1) return void 0;
9535
+ const out = [];
9536
+ for (let i = 0; i < n; i++) {
9537
+ const branch = walk(code[at + 4 + i], depth + 1);
9538
+ if (branch === void 0) return void 0;
9539
+ for (const terminal of branch) {
9540
+ const value = constants[code[terminal + 1]];
9541
+ let covered = false;
9542
+ for (let j = 0; j < out.length; j++) {
9543
+ const prior = constants[code[out[j] + 1]];
9544
+ if (value.startsWith(prior)) {
9545
+ covered = true;
9546
+ break;
9547
+ }
9548
+ }
9549
+ if (covered) continue;
9550
+ for (let j = out.length - 1; j >= 0; j--) {
9551
+ const prior = constants[code[out[j] + 1]];
9552
+ if (prior.startsWith(value)) out.splice(j, 1);
9553
+ }
9554
+ out.push(terminal);
9555
+ if (out.length > limit) return void 0;
9556
+ }
9557
+ }
9558
+ return out;
9559
+ } finally {
9560
+ active.delete(at);
9561
+ }
9562
+ };
9563
+ return walk(ip, 0);
9564
+ }
8857
9565
 
8858
9566
  // src/table/emit-assembly.ts
8859
9567
  var Unemittable = class extends Error {
@@ -8935,6 +9643,16 @@ let _pfScan=null
8935
9643
  let _pfHost
8936
9644
  let _pfDepth=0
8937
9645
  const _pfFrames=[]
9646
+ let _pfTokInput
9647
+ let _pfTokPos=-1
9648
+ let _pfTokBody=-1
9649
+ let _pfTokPacked=-1
9650
+ let _pfTokValue
9651
+ let _pfTokDispatch=-1
9652
+ let _pfTokArm=-1
9653
+ let _pfTokEnd=-1
9654
+ let _pfSeqEnd=-1
9655
+ function _asciiFoldCode(c){return c>=65&&c<=90?c+32:c}
8938
9656
  function _skipTrivia(input,cur,ctx){
8939
9657
  const s=_pfScan
8940
9658
  if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
@@ -8974,17 +9692,51 @@ if(starts===undefined)return
8974
9692
  for(let i=from;i<end;i++)if(input.charCodeAt(i)===10)starts.push(i+1)
8975
9693
  ctx._lineScannedTo=end
8976
9694
  }
8977
- function _rollbackNeeded(ctx){
8978
- return ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined||ctx._cstRawChildren!==undefined||ctx._cstTriviaLog!==undefined||ctx._fields!==undefined||ctx._errors!==undefined||ctx._triviaLog!==undefined||ctx._rootTriviaLog!==undefined
9695
+ function _rollbackNeeded(ctx){
9696
+ return ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined||ctx._cstRawChildren!==undefined||ctx._cstTriviaLog!==undefined||ctx._fields!==undefined||ctx._errors!==undefined||ctx._triviaLog!==undefined||ctx._rootTriviaLog!==undefined
9697
+ }
9698
+ function _rbBuf(ctx,raw,tl,lv,lg,rt){
9699
+ const b=ctx._cstBuf
9700
+ const ra=b.raw
9701
+ if(ra!==undefined){
9702
+ if(raw===0)b.raw=undefined
9703
+ else if(raw===1){b.rawSingle=ra[0];b.raw=undefined}
9704
+ else if(ra.length!==raw)ra.length=raw
9705
+ }else if(raw===0)b.rawSingle=undefined
9706
+ const ch=b.ch
9707
+ if(ch!==undefined){
9708
+ if(lv===0)b.ch=undefined
9709
+ else if(lv===1){b.single=ch[0];b.ch=undefined}
9710
+ else if(ch.length!==lv)ch.length=lv
9711
+ }else if(lv===0)b.single=undefined
9712
+ const bt=b.tl
9713
+ if(bt!==undefined){
9714
+ if(tl===0)b.tl=undefined
9715
+ else if(bt.length!==tl)bt.length=tl
9716
+ }
9717
+ if(ctx._triviaLog!==undefined&&ctx._triviaLog.length!==lg)ctx._triviaLog.length=lg
9718
+ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTriviaLog.length=rt
9719
+ }
9720
+ `;
9721
+ var NO_RAW_RUNTIME_PRELUDE = `
9722
+ function _pushLeafNoRawBuf(ctx,value,s,e){
9723
+ const l={_tag:'leaf',value,span:{start:s,end:e}}
9724
+ const b=ctx._cstBuf
9725
+ if(b.ch!==undefined)b.ch.push(l)
9726
+ else if(b.single!==undefined){b.ch=[b.single,l];b.single=undefined}
9727
+ else b.single=l
9728
+ b.rawLen++
9729
+ }
9730
+ function _pushNodeNoRawBuf(ctx,value){
9731
+ const b=ctx._cstBuf
9732
+ if(b.ch!==undefined)b.ch.push(value)
9733
+ else if(b.single!==undefined){b.ch=[b.single,value];b.single=undefined}
9734
+ else b.single=value
9735
+ b.rawLen++
8979
9736
  }
8980
- function _rbBuf(ctx,raw,tl,lv,lg,rt){
9737
+ function _rbNoRawBuf(ctx,raw,tl,lv,lg,rt){
8981
9738
  const b=ctx._cstBuf
8982
- const ra=b.raw
8983
- if(ra!==undefined){
8984
- if(raw===0)b.raw=undefined
8985
- else if(raw===1){b.rawSingle=ra[0];b.raw=undefined}
8986
- else if(ra.length!==raw)ra.length=raw
8987
- }else if(raw===0)b.rawSingle=undefined
9739
+ if(b.rawLen!==raw)b.rawLen=raw
8988
9740
  const ch=b.ch
8989
9741
  if(ch!==undefined){
8990
9742
  if(lv===0)b.ch=undefined
@@ -9012,11 +9764,12 @@ function sinkReads(t, s) {
9012
9764
  ${t}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${s.er ? `
9013
9765
  ${t}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
9014
9766
  }
9015
- function emitMark(t, buf, s = NO_SINKS, decl = true) {
9767
+ function emitMark(t, buf, rawMode, s = NO_SINKS, decl = true) {
9016
9768
  if (buf) {
9769
+ const raw = rawMode === RAW_OMIT ? `${t}raw=b.rawLen` : rawMode === RAW_CAPTURE ? `const r=b.raw;${t}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0` : `const r=b.raw;${t}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)`;
9017
9770
  return `${decl ? `let ${t}raw=0,${t}tl=0,${t}lv=0,${t}lg=0,${t}rt=0${sinkSlots(t, s)}
9018
9771
  ` : ""}{const b=ctx._cstBuf
9019
- const r=b.raw;${t}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
9772
+ ${raw}
9020
9773
  const h=b.ch;${t}lv=h!==undefined?h.length:b.single!==undefined?1:0
9021
9774
  const l=b.tl;${t}tl=l!==undefined?l.length:0
9022
9775
  ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
@@ -9026,7 +9779,7 @@ ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${sinkReads(t,
9026
9779
  ` : `${t}n=false
9027
9780
  `}{const b=ctx._cstBuf
9028
9781
  if(b!==undefined){
9029
- const r=b.raw;${t}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
9782
+ const r=b.raw;${t}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)
9030
9783
  const h=b.ch;${t}lv=h!==undefined?h.length:b.single!==undefined?1:0
9031
9784
  const l=b.tl;${t}tl=l!==undefined?l.length:0
9032
9785
  ${t}n=true
@@ -9041,14 +9794,16 @@ ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
9041
9794
  ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${sinkReads(t, s)}
9042
9795
  }}`;
9043
9796
  }
9044
- function emitRollback(t, buf, s = NO_SINKS) {
9797
+ function emitRollback(t, buf, rawMode, s = NO_SINKS) {
9045
9798
  const fd = s.fd ? `
9046
9799
  if(ctx._fields!==undefined&&ctx._fields.length!==${t}fd)ctx._fields.length=${t}fd` : "";
9047
9800
  const er = s.er ? `
9048
9801
  if(ctx._errors!==undefined&&ctx._errors.length!==${t}er)ctx._errors.length=${t}er` : "";
9049
- if (buf) return `_rbBuf(ctx,${t}raw,${t}tl,${t}lv,${t}lg,${t}rt)${fd}${er}`;
9050
- if (!s.fd && !s.er) return `if(${t}n)rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,0,undefined,${t}lg,${t}rt)`;
9051
- return `if(${t}n){rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,${s.fd ? `${t}fd` : "0"},${s.er ? `${t}er` : "undefined"},${t}lg,${t}rt)}`;
9802
+ if (buf && rawMode === RAW_OMIT) return `_rbNoRawBuf(ctx,${t}raw,${t}tl,${t}lv,${t}lg,${t}rt)${fd}${er}`;
9803
+ if (buf && rawMode === RAW_CAPTURE) return `_rbBuf(ctx,${t}raw,${t}tl,${t}lv,${t}lg,${t}rt)${fd}${er}`;
9804
+ if (buf) return `rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,${s.fd ? `${t}fd` : "undefined"},${s.er ? `${t}er` : "undefined"},${t}lg,${t}rt)`;
9805
+ if (!s.fd && !s.er) return `if(${t}n)rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,undefined,undefined,${t}lg,${t}rt)`;
9806
+ return `if(${t}n){rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,${s.fd ? `${t}fd` : "undefined"},${s.er ? `${t}er` : "undefined"},${t}lg,${t}rt)}`;
9052
9807
  }
9053
9808
  function emitTerm(callee, dst, t, l, skip) {
9054
9809
  const fast = `const ${t}v=${callee}(input,cur,ctx)
@@ -9106,37 +9861,111 @@ function rebuildPools(cc, fx, disp, plan) {
9106
9861
  })
9107
9862
  };
9108
9863
  }
9109
- function emitAssemblySource(t, prog, cfg, extraIps = []) {
9110
- const { code, k, disp, dsp, triviaLabelled } = t;
9864
+ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
9865
+ const { code, k, fx, disp, dsp, triviaLabelled } = t;
9111
9866
  const swapLegal = !cfg.trackLines;
9112
9867
  const hostCst = cfg.hostCst;
9113
9868
  const REC2 = prog.rec === 1 && cfg.tolerant;
9114
9869
  if (cfg.coverage) throw new Unemittable("a coverage assembly");
9115
9870
  const roots = [...Object.values(prog.rules), ...extraIps];
9871
+ const reachable = [...reachableSites(code, roots)];
9116
9872
  const labels = computeSiteLabels(code, roots, hostCst);
9117
9873
  const scalarSpecs = /* @__PURE__ */ new Set();
9874
+ const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
9875
+ const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
9876
+ const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
9877
+ const tokenChoiceCandidates = /* @__PURE__ */ new Map();
9878
+ const tokenChoiceDispatches = /* @__PURE__ */ new Set();
9879
+ const tokenChoiceBodies = /* @__PURE__ */ new Set();
9118
9880
  if (!hostCst && !cfg.tolerant && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
9119
- for (const ip of reachableSites(code, roots)) {
9120
- if (code[ip] !== OP_NODE) continue;
9121
- const child = scalarTerminalNodeChild(code, ip);
9122
- if (child >= 0) scalarSpecs.add(code[child + 1]);
9881
+ for (const ip of reachable) {
9882
+ if (code[ip] === OP_NODE) {
9883
+ const child = scalarTerminalNodeChild(code, ip);
9884
+ if (child >= 0) scalarSpecs.add(code[child + 1]);
9885
+ continue;
9886
+ }
9887
+ if (code[ip] !== OP_CHOICE || disp[code[ip + 1]].exclusive) continue;
9888
+ const n = code[ip + 2];
9889
+ for (let i = 0; i < n; i++) {
9890
+ const armIp = code[ip + 4 + i];
9891
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
9892
+ if (n === 2 || n === 3) {
9893
+ if (child >= 0) scalarSpecs.add(code[child + 1]);
9894
+ continue;
9895
+ }
9896
+ if (child >= 0) {
9897
+ const spec = k[code[child + 1]];
9898
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
9899
+ largeChoiceScalarSpecs.add(code[child + 1]);
9900
+ continue;
9901
+ }
9902
+ }
9903
+ const family = leadingLiteralFamily(code, k, armIp);
9904
+ if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
9905
+ const value = k[code[terminal + 1]];
9906
+ return typeof value === "string" && value.length >= 2;
9907
+ })) {
9908
+ largeChoiceLiteralFamilies.set(armIp, family);
9909
+ }
9910
+ const sequence6 = leadingScalarSequence(code, armIp);
9911
+ if (sequence6 !== void 0 && (sequence6.trivia < 0 || swapLegal && t.triviaScan[sequence6.trivia] != null)) {
9912
+ largeChoiceScalarSequences.set(armIp, sequence6);
9913
+ }
9914
+ }
9915
+ let candidate;
9916
+ let ambiguous = false;
9917
+ for (let i = 0; i < n; i++) {
9918
+ const armIp = code[ip + 4 + i];
9919
+ if (code[armIp] !== OP_XFORM) continue;
9920
+ const dispatchIp = code[armIp + 2];
9921
+ if (code[dispatchIp] !== OP_DISPATCH) continue;
9922
+ const selectorIp = code[dispatchIp + 1];
9923
+ if (code[selectorIp] !== OP_LEX_BODY) continue;
9924
+ if (candidate !== void 0) {
9925
+ ambiguous = true;
9926
+ break;
9927
+ }
9928
+ candidate = { arm: i, dispatchIp };
9929
+ }
9930
+ if (!ambiguous && candidate !== void 0) {
9931
+ tokenChoiceCandidates.set(ip, candidate);
9932
+ tokenChoiceDispatches.add(candidate.dispatchIp);
9933
+ tokenChoiceBodies.add(code[code[candidate.dispatchIp + 1] + 1]);
9934
+ }
9123
9935
  }
9124
9936
  }
9125
- const sinks = (() => {
9126
- let fd = false;
9127
- let er = REC2;
9128
- for (const ip of reachableSites(code, roots)) {
9129
- const op = code[ip];
9130
- if (op === OP_SCAN) {
9131
- fd = true;
9132
- er = true;
9133
- break;
9937
+ const needsNoRawPrelude = !hostCst && reachable.some((ip) => {
9938
+ const op = code[ip];
9939
+ return (op === OP_NODE || op === OP_NODE_TRACK) && code[ip + 1] >= 0 && code[ip + 4] < 0 && (code[ip + 3] & 2) !== 0;
9940
+ });
9941
+ const sinkSites = reachable;
9942
+ const sinkBits = /* @__PURE__ */ new Map();
9943
+ for (const ip of sinkSites) {
9944
+ const op = code[ip];
9945
+ sinkBits.set(
9946
+ ip,
9947
+ op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC2 && (op === OP_REP || op === OP_REPV) ? 2 : 0)
9948
+ );
9949
+ }
9950
+ const sinkKids = [];
9951
+ let sinkChanged = true;
9952
+ while (sinkChanged) {
9953
+ sinkChanged = false;
9954
+ for (const ip of sinkSites) {
9955
+ let bits = sinkBits.get(ip) ?? 0;
9956
+ sinkKids.length = 0;
9957
+ childSlots(code, ip, sinkKids);
9958
+ for (let i = 0; i < sinkKids.length; i++) bits |= sinkBits.get(sinkKids[i]) ?? 0;
9959
+ if (bits !== sinkBits.get(ip)) {
9960
+ sinkBits.set(ip, bits);
9961
+ sinkChanged = true;
9134
9962
  }
9135
- if (op === OP_FIELD) fd = true;
9136
- else if (op === OP_EXPECT) er = true;
9137
9963
  }
9138
- return { fd, er };
9139
- })();
9964
+ }
9965
+ const sinksAt = (ip) => {
9966
+ const bits = sinkBits.get(ip) ?? 0;
9967
+ return bits === 0 ? NO_SINKS : { fd: (bits & 1) !== 0, er: (bits & 2) !== 0 };
9968
+ };
9140
9969
  const bodies = [];
9141
9970
  const byIp = /* @__PURE__ */ new Map();
9142
9971
  const reached = /* @__PURE__ */ new Set();
@@ -9163,9 +9992,117 @@ function emitAssemblySource(t, prog, cfg, extraIps = []) {
9163
9992
  const fxRef = (i) => hoist("fx", `FX[${i}]`);
9164
9993
  const fnRef = (i) => hoist("fn", `FNS[${i}]`);
9165
9994
  const recognizerRef = (i) => hoist("rec", `RECOG[${i}]`);
9995
+ const scalarSequenceRefs = /* @__PURE__ */ new Map();
9996
+ const scalarSequenceRef = (sequence6) => {
9997
+ const key = `${sequence6.trivia}:${sequence6.terminals.map((terminal) => code[terminal + 1]).join(",")}`;
9998
+ const prior = scalarSequenceRefs.get(key);
9999
+ if (prior !== void 0) return prior;
10000
+ const recognizers = sequence6.terminals.map((terminal) => recognizerRef(code[terminal + 1]));
10001
+ const expected = sequence6.terminals.map((terminal) => fxRef(code[terminal + 2]));
10002
+ const scan = sequence6.trivia < 0 ? void 0 : hoist("ts", `TRIVIASCAN[${sequence6.trivia}]`);
10003
+ const name = `_sd${scalarSequenceRefs.size}_`;
10004
+ const steps = recognizers.map((recognize, i) => `${i === 0 ? "let " : ""}at=${i === 0 ? "pos" : scan === void 0 ? "cur" : `${scan}(input,cur)`}
10005
+ ${i === 0 ? "let " : ""}cur=${recognize}(input,at)
10006
+ if(cur<0){_pfSeqEnd=at;return ${~i}}`).join("\n");
10007
+ choiceDefs.push(`function ${name}(input,pos){
10008
+ ${steps}
10009
+ return cur
10010
+ }`);
10011
+ const made = { name, expected };
10012
+ scalarSequenceRefs.set(key, made);
10013
+ return made;
10014
+ };
9166
10015
  const sentRef = (cls) => cls < 0 ? "undefined" : hoist("sent", `SENTS[${cls}]`);
9167
10016
  let uid = 0;
9168
10017
  const tmp = () => `_t${uid++}_`;
10018
+ const dispatchClaim = (m) => {
10019
+ switch (m[0]) {
10020
+ case 0:
10021
+ return `key.startsWith(${q(m[1])})`;
10022
+ case 1:
10023
+ return `key.endsWith(${q(m[1])})`;
10024
+ case 3:
10025
+ return `asciiFoldKey(key).startsWith(${q(m[1])})`;
10026
+ case 4:
10027
+ return `asciiFoldKey(key).endsWith(${q(m[1])})`;
10028
+ default: {
10029
+ if (!m[2].includes("g") && !m[2].includes("y")) {
10030
+ try {
10031
+ new RegExp(m[1], m[2]);
10032
+ return `${hoist("dm", `new RegExp(${q(m[1])},${q(m[2])})`)}.test(key)`;
10033
+ } catch {
10034
+ }
10035
+ }
10036
+ return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
10037
+ }
10038
+ }
10039
+ };
10040
+ const tokenDecisionRefs = /* @__PURE__ */ new Map();
10041
+ function tokenDecisionFor(dispatchIp) {
10042
+ const prior = tokenDecisionRefs.get(dispatchIp);
10043
+ if (prior !== void 0) return prior;
10044
+ const selectorIp = code[dispatchIp + 1];
10045
+ const body = code[selectorIp + 1];
10046
+ const lineFlags = code[selectorIp + 4];
10047
+ const hasSuffix = (lineFlags & 4) !== 0;
10048
+ const di = code[dispatchIp + 2];
10049
+ const spec = dsp[di];
10050
+ const n = code[dispatchIp + 5];
10051
+ validateDispatchSpec(spec, n, code[dispatchIp + 4]);
10052
+ const recognize = hoist("lex", `LEX[${body}]`);
10053
+ const bk = hoist("bk", `DSP[${di}].byKey`);
10054
+ const expected = hoist("dx", `DSP[${di}].expected`);
10055
+ const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
10056
+ ` : "";
10057
+ const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
10058
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${dispatchClaim(m)})arm=${m[3]}`).join("\n")}
10059
+ }
10060
+ `;
10061
+ const foldedEntries = [...spec.byFold.entries()];
10062
+ const fixedFunctionChoice = spec.byKey.size === 0 && foldedEntries.length === 1 && spec.match.length === 1 && spec.match[0][0] === 2 && spec.match[0][1] === "^(?!(?:url|calc)\\($).+\\($" && spec.match[0][2] === "i" && code[dispatchIp + 3] < 0;
10063
+ const foldedRangeEquals = (value) => {
10064
+ const folded = value.replace(/[A-Z]/g, (c) => c.toLowerCase());
10065
+ return `e-pos===${folded.length}&&${[...folded].map((c, i) => {
10066
+ const cc = c.charCodeAt(0);
10067
+ return `_asciiFoldCode(input.charCodeAt(pos+${i}))===${cc}`;
10068
+ }).join("&&")}`;
10069
+ };
10070
+ const classify = fixedFunctionChoice ? (() => {
10071
+ const [exact, exactArm] = foldedEntries[0];
10072
+ const genericArm = spec.match[0][3];
10073
+ return `let arm
10074
+ if(${foldedRangeEquals(exact)})arm=${exactArm}
10075
+ else if(sm&&e>pos+1){
10076
+ let clean=true
10077
+ for(let i=pos;i<e;i++){const c=input.charCodeAt(i);if(c===10||c===13||c===0x2028||c===0x2029){clean=false;break}}
10078
+ if(clean&&!(${foldedRangeEquals("url(")})&&!(${foldedRangeEquals("calc(")}))arm=${genericArm}
10079
+ }`;
10080
+ })() : `const key=input.slice(pos,e)
10081
+ let arm=${bk}.get(key)
10082
+ ${fold}${chain}`;
10083
+ const name = `_td${tokenDecisionRefs.size}_`;
10084
+ choiceDefs.push(`function ${name}(input,pos){
10085
+ const r=${recognize}(input,pos)
10086
+ if(r<0)return -1
10087
+ const sm=${hasSuffix ? "r%2===1" : "false"},e=(r-(sm?1:0))/2
10088
+ ${classify}
10089
+ if(arm===undefined){
10090
+ ${code[dispatchIp + 3] < 0 ? "_pfTokEnd=e;return 0" : `arm=${n}`}
10091
+ }
10092
+ ${fixedFunctionChoice ? "const key=input.slice(pos,e)" : ""}
10093
+ _pfTokInput=input
10094
+ _pfTokPos=pos
10095
+ _pfTokBody=${body}
10096
+ _pfTokPacked=r
10097
+ _pfTokValue=key
10098
+ _pfTokDispatch=${dispatchIp}
10099
+ _pfTokArm=arm
10100
+ return 1
10101
+ }`);
10102
+ const made = { name, expected };
10103
+ tokenDecisionRefs.set(dispatchIp, made);
10104
+ return made;
10105
+ }
9169
10106
  function skipFor(l) {
9170
10107
  if (l.tri < 0) return "_skipTrivia";
9171
10108
  const ki = l.tri;
@@ -9253,7 +10190,8 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9253
10190
  const op = code[ip];
9254
10191
  const head = `function ${fname}(input,pos,ctx){`;
9255
10192
  const L = labels.at(ip);
9256
- const pushLeaf = L.buf && !cfg.trackLines ? "_pushLeafBuf" : "_pushLeaf";
10193
+ const sinks = sinksAt(ip);
10194
+ const pushLeaf = L.buf && !cfg.trackLines ? L.raw === RAW_OMIT ? "_pushLeafNoRawBuf" : L.raw === RAW_CAPTURE ? "_pushLeafBuf" : "_pushLeaf" : "_pushLeaf";
9257
10195
  const captureLeaf = (value) => {
9258
10196
  const call = `${pushLeaf}(ctx,${value},pos,e)`;
9259
10197
  return L.buf ? call : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${call}`;
@@ -9504,20 +10442,24 @@ return out
9504
10442
  }`;
9505
10443
  }
9506
10444
  case OP_LEX_BODY: {
9507
- const recognize = hoist("lex", `LEX[${code[ip + 1]}]`);
10445
+ const body = code[ip + 1];
10446
+ const recognize = hoist("lex", `LEX[${body}]`);
9508
10447
  const expected = fxRef(code[ip + 2]);
9509
10448
  const suffixExpected = fxRef(code[ip + 3]);
9510
10449
  const lineFlags = code[ip + 4];
9511
10450
  const hasSuffix = (lineFlags & 4) !== 0;
10451
+ const pending = tokenChoiceBodies.has(body);
9512
10452
  return `${head}
9513
- const r=${recognize}(input,pos)
10453
+ ${pending ? `const tp=_pfTokBody===${body}&&_pfTokInput===input&&_pfTokPos===pos
10454
+ const r=tp?_pfTokPacked:${recognize}(input,pos)` : `const r=${recognize}(input,pos)`}
9514
10455
  if(r<0){ctx._fe=pos;ctx._fx=${expected};if(ctx._probe!==undefined)failAt(ctx,${expected},pos);return FAIL}
9515
10456
  const sm=${hasSuffix ? "r%2===1" : "false"},e=(r-(sm?1:0))/2
9516
10457
  ${(lineFlags & 1) !== 0 ? "_trackLines(ctx,input,sm?e-1:e)" : ""}
9517
10458
  ${hasSuffix ? "ctx._fc=false" : ""}
9518
10459
  ${hasSuffix && (lineFlags & 2) !== 0 ? "if(sm)_trackLines(ctx,input,e)" : ""}
9519
10460
  ${hasSuffix ? `if(!sm){ctx._fe=e;ctx._fx=${suffixExpected};if(ctx._probe!==undefined)failAt(ctx,${suffixExpected},e)}` : ""}
9520
- const v=input.slice(pos,e)
10461
+ const v=${pending ? "tp?_pfTokValue:" : ""}input.slice(pos,e)
10462
+ ${pending ? "if(tp){_pfTokBody=-1;_pfTokValue=undefined}" : ""}
9521
10463
  if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
9522
10464
  EC.e=e
9523
10465
  return v
@@ -9573,12 +10515,13 @@ return v
9573
10515
  /* ── transaction ─────────────────────────────────────────────────────── */
9574
10516
  case OP_ATTEMPT: {
9575
10517
  const child = link(code[ip + 1]);
10518
+ const clean = !REC2 && failureRollbackClean(prog, ip);
9576
10519
  const p = tmp();
9577
10520
  return `${head}
9578
- ${emitMark(p, L.buf, sinks)}
10521
+ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
9579
10522
  const v=${child}(input,pos,ctx)
9580
10523
  if(v!==FAIL)return v
9581
- ${emitRollback(p, L.buf, sinks)}
10524
+ ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
9582
10525
  if(ctx._fc===true)return FAIL
9583
10526
  ctx._fe=pos
9584
10527
  return FAIL
@@ -9601,9 +10544,9 @@ return FAIL
9601
10544
  const xf = fxRef(code[ip + 2]);
9602
10545
  const p = tmp();
9603
10546
  return `${head}
9604
- ${emitMark(p, L.buf, sinks)}
10547
+ ${emitMark(p, L.buf, L.raw, sinks)}
9605
10548
  const v=${child}(input,pos,ctx)
9606
- ${emitRollback(p, L.buf, sinks)}
10549
+ ${emitRollback(p, L.buf, L.raw, sinks)}
9607
10550
  if(v===FAIL){EC.e=pos;return null}
9608
10551
  ctx._fe=pos
9609
10552
  ctx._fx=${xf}
@@ -9615,9 +10558,9 @@ return FAIL
9615
10558
  const xf = fxRef(code[ip + 2]);
9616
10559
  const p = tmp();
9617
10560
  return `${head}
9618
- ${emitMark(p, L.buf, sinks)}
10561
+ ${emitMark(p, L.buf, L.raw, sinks)}
9619
10562
  const v=${child}(input,pos,ctx)
9620
- ${emitRollback(p, L.buf, sinks)}
10563
+ ${emitRollback(p, L.buf, L.raw, sinks)}
9621
10564
  if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9622
10565
  EC.e=pos
9623
10566
  return null
@@ -9625,14 +10568,15 @@ return null
9625
10568
  }
9626
10569
  case OP_OPT: {
9627
10570
  const child = link(code[ip + 1]);
10571
+ const clean = !REC2 && failureRollbackClean(prog, ip);
9628
10572
  const p = tmp();
9629
10573
  return `${head}
9630
- ${emitMark(p, L.buf, sinks)}
10574
+ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
9631
10575
  ctx._fc=false
9632
10576
  const v=${child}(input,pos,ctx)
9633
10577
  if(v===FAIL){
9634
10578
  if(ctx._fc===true)return FAIL
9635
- ${emitRollback(p, L.buf, sinks)}
10579
+ ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
9636
10580
  EC.e=pos
9637
10581
  return null
9638
10582
  }
@@ -9731,57 +10675,193 @@ return FAIL
9731
10675
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
9732
10676
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
9733
10677
  const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10678
+ const tokenCandidate = tokenChoiceCandidates.get(ip);
10679
+ const pretests = Array.from({ length: n }, (_, i) => {
10680
+ if (tokenCandidate?.arm === i) {
10681
+ return { token: tokenDecisionFor(tokenCandidate.dispatchIp) };
10682
+ }
10683
+ const terminal = leadingScalarTerminal(code, code[base + i], 2, true, true);
10684
+ if (terminal >= 0) {
10685
+ const spec = code[terminal + 1];
10686
+ if ((n === 2 || n === 3 ? scalarSpecs : largeChoiceScalarSpecs).has(spec)) {
10687
+ return { scalar: [recognizerRef(spec)] };
10688
+ }
10689
+ }
10690
+ const family = largeChoiceLiteralFamilies.get(code[base + i]);
10691
+ if (family !== void 0) {
10692
+ return { scalar: family.map((member) => recognizerRef(code[member + 1])) };
10693
+ }
10694
+ const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10695
+ return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10696
+ });
9734
10697
  const maskable = n <= 32;
9735
10698
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
9736
10699
  if (maskable) maskPlan.push(~di);
9737
10700
  const p = tmp();
9738
- const catchName = maskable ? `_cx${uid++}_` : "";
9739
- if (maskable) {
10701
+ const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
10702
+ const rollbackMask = REC2 ? -1 : encodedRollbackMask;
10703
+ const hasRollback = rollbackMask !== 0;
10704
+ const startFailureExact = arms.every((_arm, i) => {
10705
+ const terminal = leadingScalarTerminal(code, code[base + i], 0, false);
10706
+ if (terminal < 0) return false;
10707
+ const op2 = code[terminal];
10708
+ const spec = k[code[terminal + 1]];
10709
+ const terminalFx = fx[code[terminal + 2]];
10710
+ const armFx = fx[code[base + n + i]];
10711
+ if (terminalFx.length !== armFx.length || terminalFx.some((expected2, at) => expected2 !== armFx[at])) return false;
10712
+ if (op2 === OP_LIT) return typeof spec === "string" && spec.length > 0;
10713
+ return op2 === OP_RX && spec instanceof RegExp && !regexCanMatchEmpty(spec.source);
10714
+ });
10715
+ const rollbackFor = (i) => rollbackMask === -1 || (rollbackMask & 1 << i) !== 0 ? emitRollback(p, L.buf, L.raw, sinks) : "";
10716
+ if (choiceCannotCommit(prog, ip) && !startFailureExact) {
10717
+ const deepAt = Array.from({ length: n }, () => tmp());
10718
+ const deepFx = Array.from({ length: n }, () => tmp());
10719
+ const remember = (i, at, expectedSet) => `${deepAt[i]}=${at};${deepFx[i]}=${expectedSet}`;
10720
+ const lazyArms = (ascii) => arms.map((arm, i) => {
10721
+ const pretest = pretests[i];
10722
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10723
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
10724
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
10725
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
10726
+ const gate2 = ascii ? `(bits&${1 << i})!==0${condition}` : `(${gateRefs[i]}===null||classHas(${gateRefs[i]},c))${condition}`;
10727
+ const routeMiss = pretest?.token === void 0 ? "" : `
10728
+ if(${decision}===0){
10729
+ ctx._fc=false
10730
+ {const at=_pfTokEnd
10731
+ ${remember(i, "at", pretest.token.expected)}}
10732
+ }`;
10733
+ const sequenceMiss = pretest?.sequence === void 0 ? "" : `
10734
+ else if(${ascii ? `(bits&${1 << i})!==0&&` : ""}${decision}<0){
10735
+ ctx._fc=false
10736
+ {const at=_pfSeqEnd
10737
+ ${remember(i, "at", pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("") + pretest.sequence.expected.at(-1))}}
10738
+ }`;
10739
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10740
+ `}if(${gate2}){
10741
+ ctx._fc=false
10742
+ {const v=${arm}(input,pos,ctx)
10743
+ if(v!==FAIL)return v}
10744
+ {const at=ctx._fe??pos
10745
+ ${remember(i, "at", "ctx._fx")}}
10746
+ ${rollbackFor(i)}
10747
+ }${routeMiss}${sequenceMiss}`;
10748
+ }).join("\n");
10749
+ const merge2 = deepAt.map((at, i) => `{const at=${at}??pos
10750
+ const ex=${at}===undefined?${expected[i]}:${deepFx[i]}
10751
+ if(at>best){best=at;acc=_accSet(ex,undefined)}
10752
+ else if(at===best)acc=_accSet(ex,acc)
10753
+ }`).join("\n");
10754
+ const finish = `let best=pos,acc
10755
+ ${merge2}
10756
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
10757
+ return FAIL`;
10758
+ return `${head}
10759
+ const c=lead(input,pos)
10760
+ ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10761
+ ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10762
+ ${maskable ? `if(c<128){
10763
+ const bits=${maskName}[c<0?128:c]
10764
+ if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10765
+ ${lazyArms(true)}
10766
+ }else{
10767
+ ${lazyArms(false)}
10768
+ }
10769
+ ` : lazyArms(false)}
10770
+ ${finish}
10771
+ }`;
10772
+ }
10773
+ const needsCatch = maskable || startFailureExact;
10774
+ const catchName = needsCatch ? `_cx${uid++}_` : "";
10775
+ if (needsCatch) {
9740
10776
  const catchCases = expected.map((e, i) => `case ${i}:if(target<=${i})return acc;acc=_accSet(${e},acc)`).join("\n");
9741
10777
  choiceDefs.push(`function ${catchName}(target,prev,acc){switch(prev){
9742
10778
  ${catchCases}
9743
10779
  }return acc}`);
9744
10780
  }
9745
10781
  const maskArms = maskable ? arms.map((arm, i) => {
9746
- return `if((bits&${1 << i})!==0){
10782
+ const pretest = pretests[i];
10783
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10784
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
10785
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
10786
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
10787
+ const routeMiss = pretest?.token === void 0 ? "" : `
10788
+ if(${decision}===0){
10789
+ ctx._fc=false
10790
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
10791
+ prev=${i + 1}`}
10792
+ {const at=_pfTokEnd
10793
+ if(at>best){best=at;acc=undefined}
10794
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.token.expected},acc)}
10795
+ }`;
10796
+ const sequenceMiss = pretest?.sequence === void 0 ? "" : `
10797
+ else if((bits&${1 << i})!==0&&${decision}<0){
10798
+ ctx._fc=false
10799
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
10800
+ prev=${i + 1}`}
10801
+ {const at=_pfSeqEnd
10802
+ if(at>best){best=at;acc=undefined}
10803
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("")}${pretest.sequence.expected.at(-1)},acc)}
10804
+ }`;
10805
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10806
+ `}if((bits&${1 << i})!==0${condition}){
9747
10807
  ctx._fc=false
9748
10808
  {const v=${arm}(input,pos,ctx)
9749
10809
  if(v!==FAIL)return v}
9750
- if(best===pos)acc=${catchName}(${i},prev,acc)
9751
- prev=${i + 1}
10810
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${i},prev,acc)
10811
+ prev=${i + 1}`}
9752
10812
  {const at=ctx._fe??pos
9753
10813
  if(at>best){best=at;acc=undefined}
9754
- if(at===best)acc=_accSet(ctx._fx,acc)}
9755
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
9756
- ${emitRollback(p, L.buf, sinks)}
9757
- }`;
10814
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(ctx._fx,acc)}
10815
+ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0,undefined);acc=_accSet(ctx._fx,acc)}` : ""}if(acc!==undefined)ctx._fx=acc;return FAIL}
10816
+ ${rollbackFor(i)}
10817
+ }${routeMiss}${sequenceMiss}`;
9758
10818
  }).join("\n") : "";
9759
- const generalArms = arms.map((arm, i) => `if(${gateRefs[i]}===null||classHas(${gateRefs[i]},c)){
10819
+ const generalArms = arms.map((arm, i) => {
10820
+ const pretest = pretests[i];
10821
+ const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10822
+ const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
10823
+ const sequenceCondition = pretest?.sequence === void 0 ? "" : `&&(${decision}=${pretest.sequence.name}(input,pos))>=0`;
10824
+ const condition = pretest?.token !== void 0 ? `&&(${decision}=${pretest.token.name}(input,pos))>0` : scalarCondition || sequenceCondition;
10825
+ const miss = pretest?.sequence !== void 0 ? `else if(${decision}<0){
10826
+ ctx._fc=false
10827
+ const at=_pfSeqEnd
10828
+ if(at>best){best=at;acc=undefined}
10829
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.sequence.expected.map((value, at) => `${decision}===${~at}?${value}:`).join("")}${pretest.sequence.expected.at(-1)},acc)
10830
+ }${startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)`}` : pretest?.token === void 0 ? startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)` : `else if(${decision}===0){
10831
+ ctx._fc=false
10832
+ const at=_pfTokEnd
10833
+ if(at>best){best=at;acc=undefined}
10834
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(${pretest.token.expected},acc)
10835
+ }${startFailureExact ? "" : `else if(best===pos)acc=_accSet(${expected[i]},acc)`}`;
10836
+ return `${decision === "" ? "" : `let ${decision}=${pretest?.sequence === void 0 ? -1 : 0}
10837
+ `}if((${gateRefs[i]}===null||classHas(${gateRefs[i]},c))${condition}){
9760
10838
  ctx._fc=false
9761
10839
  {const v=${arm}(input,pos,ctx)
9762
10840
  if(v!==FAIL)return v}
9763
10841
  {const at=ctx._fe??pos
9764
10842
  if(at>best){best=at;acc=undefined}
9765
- if(at===best)acc=_accSet(ctx._fx,acc)}
9766
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
9767
- ${emitRollback(p, L.buf, sinks)}
9768
- }else if(best===pos)acc=_accSet(${expected[i]},acc)`).join("\n");
10843
+ if(at===best${startFailureExact ? "&&at>pos" : ""})acc=_accSet(ctx._fx,acc)}
10844
+ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0,undefined);acc=_accSet(ctx._fx,acc)}` : ""}if(acc!==undefined)ctx._fx=acc;return FAIL}
10845
+ ${rollbackFor(i)}
10846
+ }${miss}`;
10847
+ }).join("\n");
9769
10848
  return `${head}
9770
10849
  const c=lead(input,pos)
9771
- ${emitMark(p, L.buf, sinks)}
10850
+ ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9772
10851
  let acc
9773
10852
  let best=pos
9774
10853
  ${maskable ? `if(c<128){
9775
10854
  const bits=${maskName}[c<0?128:c]
9776
- let prev=0
10855
+ if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10856
+ ${startFailureExact ? "" : "let prev=0"}
9777
10857
  ${maskArms}
9778
- if(best===pos)acc=${catchName}(${n},prev,acc)
9779
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
10858
+ ${startFailureExact ? "" : `if(best===pos)acc=${catchName}(${n},prev,acc)`}
10859
+ ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
9780
10860
  return FAIL
9781
10861
  }
9782
10862
  ` : ""}
9783
10863
  ${generalArms}
9784
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
10864
+ ctx._fe=pos;ctx._fx=${startFailureExact ? `best===pos?${choiceFx}:acc??${choiceFx}` : `acc??${choiceFx}`}
9785
10865
  return FAIL
9786
10866
  }`;
9787
10867
  }
@@ -9800,30 +10880,8 @@ return FAIL
9800
10880
  for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
9801
10881
  const bk = hoist("bk", `DSP[${di}].byKey`);
9802
10882
  const dx = hoist("dx", `DSP[${di}].expected`);
9803
- const claims = (m) => {
9804
- switch (m[0]) {
9805
- case 0:
9806
- return `key.startsWith(${q(m[1])})`;
9807
- case 1:
9808
- return `key.endsWith(${q(m[1])})`;
9809
- case 3:
9810
- return `asciiFoldKey(key).startsWith(${q(m[1])})`;
9811
- case 4:
9812
- return `asciiFoldKey(key).endsWith(${q(m[1])})`;
9813
- default: {
9814
- if (!m[2].includes("g") && !m[2].includes("y")) {
9815
- try {
9816
- new RegExp(m[1], m[2]);
9817
- return `${hoist("dm", `new RegExp(${q(m[1])},${q(m[2])})`)}.test(key)`;
9818
- } catch {
9819
- }
9820
- }
9821
- return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
9822
- }
9823
- }
9824
- };
9825
10883
  const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
9826
- ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
10884
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${dispatchClaim(m)})arm=${m[3]}`).join("\n")}
9827
10885
  }
9828
10886
  `;
9829
10887
  const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
@@ -9831,33 +10889,43 @@ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}
9831
10889
  const m1 = tmp();
9832
10890
  const m2 = tmp();
9833
10891
  const routedCall = (target) => `{const savedRouted=ctx._routed
9834
- ${emitRollback(m1, L.buf, sinks)}
9835
- ${emitMark(m2, L.buf, sinks, false)}
10892
+ ${emitRollback(m1, L.buf, L.raw, sinks)}
10893
+ ${emitMark(m2, L.buf, L.raw, sinks, false)}
9836
10894
  ctx._routed={value:key,span:{start:pos,end:selEnd}}
9837
10895
  try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
9838
10896
  break}`;
9839
10897
  const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
9840
10898
  const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
9841
10899
  const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
10900
+ const armSelection = tokenChoiceDispatches.has(ip) ? `const tp=_pfTokDispatch===${ip}&&_pfTokInput===input&&_pfTokPos===pos
10901
+ let arm
10902
+ if(tp){
10903
+ arm=_pfTokArm
10904
+ _pfTokDispatch=-1
10905
+ _pfTokInput=undefined
10906
+ if(arm===${n})arm=undefined
10907
+ }else{
10908
+ arm=${bk}.get(key)
10909
+ ${fold}${chain}}` : `let arm=${bk}.get(key)
10910
+ ${fold}${chain}`;
9842
10911
  return `${head}
9843
- ${emitMark(m1, L.buf, sinks)}
10912
+ ${emitMark(m1, L.buf, L.raw, sinks)}
9844
10913
  const sv=${selector}(input,pos,ctx)
9845
10914
  if(sv===FAIL)return FAIL
9846
10915
  const selEnd=EC.e
9847
10916
  const key=sv
9848
- let arm=${bk}.get(key)
9849
- ${fold}${chain}
10917
+ ${armSelection}
9850
10918
  if(arm===undefined){
9851
10919
  ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
9852
10920
  }
9853
- ${emitMark(m2, L.buf, sinks)}
10921
+ ${emitMark(m2, L.buf, L.raw, sinks)}
9854
10922
  let v
9855
10923
  switch(arm){
9856
10924
  ${armCases}
9857
10925
  ${fallbackCase}
9858
10926
  }
9859
10927
  if(v===FAIL){
9860
- ${emitRollback(m2, L.buf, sinks)}
10928
+ ${emitRollback(m2, L.buf, L.raw, sinks)}
9861
10929
  ctx._fc=true
9862
10930
  return FAIL
9863
10931
  }
@@ -9893,23 +10961,25 @@ return [key,v]
9893
10961
  const skip = skipFor(L);
9894
10962
  const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
9895
10963
  const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
9896
- const pfd = sinks.fd ? `${p}fd` : "0";
10964
+ const pfd = sinks.fd ? `${p}fd` : "undefined";
9897
10965
  const per = sinks.er ? `${p}er` : "undefined";
9898
- const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
10966
+ const rbHelper = L.raw === RAW_OMIT ? "_rbNoRawBuf" : "_rbBuf";
10967
+ const rb = L.buf && L.raw !== 0 ? `${rbHelper}(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
9899
10968
  if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
9900
- if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
10969
+ if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : L.buf ? `rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
9901
10970
  const markSinks = `${sinks.fd ? `
9902
10971
  ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
9903
10972
  ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
10973
+ const markRaw = L.raw === RAW_OMIT ? `${p}raw=b.rawLen` : L.raw === RAW_CAPTURE ? `const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0` : `const r=b.raw;${p}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)`;
9904
10974
  const markBody = L.buf ? `const b=ctx._cstBuf
9905
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
10975
+ ${markRaw}
9906
10976
  const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
9907
10977
  const l=b.tl;${p}tl=l!==undefined?l.length:0
9908
10978
  ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
9909
10979
  ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
9910
10980
  const b=ctx._cstBuf
9911
10981
  if(b!==undefined){
9912
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
10982
+ const r=b.raw;${p}raw=b.noRaw===true?b.rawLen:(r!==undefined?r.length:b.rawSingle!==undefined?1:0)
9913
10983
  const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
9914
10984
  const l=b.tl;${p}tl=l!==undefined?l.length:0
9915
10985
  }else{
@@ -10016,7 +11086,7 @@ const leaf={_tag:'leaf',value,span:{start:pos,end}}
10016
11086
  const kids=[leaf],rawKids=[leaf],span={start:pos,end}
10017
11087
  EC.e=end
10018
11088
  const nd=${build2}(kids,undefined,span,rawKids,EMPTY_TL,undefined)
10019
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
11089
+ ${L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : staticBuild ? "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,ctx._cstBuf!==undefined&&ctx._cstBuf.noRaw===true?undefined:ctx._cstBuf!==undefined||ctx._cstRawChildren!==undefined?rawEntry(nd,input,pos,end):undefined)" : "if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
10020
11090
  EC.e=end
10021
11091
  return nd
10022
11092
  }`;
@@ -10038,7 +11108,22 @@ return nd
10038
11108
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (flags === 2 || flags === 18 || flags === 34)) {
10039
11109
  const fields = flags === 18;
10040
11110
  const collapseChildren = flags === 34;
10041
- const publish = `if(sBuf!==undefined){
11111
+ const publish = L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? `if(sBuf!==undefined){
11112
+ if(sBuf.rawOnly!==true){
11113
+ if(sBuf.ch!==undefined)sBuf.ch.push(nd)
11114
+ else if(sBuf.single!==undefined){sBuf.ch=[sBuf.single,nd];sBuf.single=undefined}
11115
+ else sBuf.single=nd
11116
+ }
11117
+ const rawNd=rawEntry(nd,input,pos,end)
11118
+ if(sBuf.raw!==undefined)sBuf.raw.push(rawNd)
11119
+ else if(sBuf.rawSingle!==undefined){sBuf.raw=[sBuf.rawSingle,rawNd];sBuf.rawSingle=undefined}
11120
+ else sBuf.rawSingle=rawNd
11121
+ }else if(sCh!==undefined){
11122
+ sCh.push(nd)
11123
+ if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
11124
+ }` : `if(sBuf!==undefined){
11125
+ if(sBuf.noRaw===true)_pushNodeNoRawBuf(ctx,nd)
11126
+ else{
10042
11127
  if(sBuf.rawOnly!==true){
10043
11128
  if(sBuf.ch!==undefined)sBuf.ch.push(nd)
10044
11129
  else if(sBuf.single!==undefined){sBuf.ch=[sBuf.single,nd];sBuf.single=undefined}
@@ -10048,6 +11133,7 @@ const rawNd=rawEntry(nd,input,pos,end)
10048
11133
  if(sBuf.raw!==undefined)sBuf.raw.push(rawNd)
10049
11134
  else if(sBuf.rawSingle!==undefined){sBuf.raw=[sBuf.rawSingle,rawNd];sBuf.rawSingle=undefined}
10050
11135
  else sBuf.rawSingle=rawNd
11136
+ }
10051
11137
  }else if(sCh!==undefined){
10052
11138
  sCh.push(nd)
10053
11139
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
@@ -10086,6 +11172,7 @@ return nd
10086
11172
  const wantFields = hasFields || hostCst;
10087
11173
  const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
10088
11174
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
11175
+ const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
10089
11176
  const ty = q(type);
10090
11177
  const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
10091
11178
  const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
@@ -10099,7 +11186,12 @@ return nd
10099
11186
  value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
10100
11187
  }
10101
11188
  const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
10102
- const openCapture = keepChildren ? `const buf={}
11189
+ const openCapture = omitsRaw ? `const buf={noRaw:true,rawLen:0}
11190
+ ctx._cstBuf=buf
11191
+ ctx._cstChildren=undefined
11192
+ ctx._cstLeaves=undefined
11193
+ ctx._cstRawChildren=undefined
11194
+ ctx._cstTriviaLog=undefined` : keepChildren ? `const buf={}
10103
11195
  ctx._cstBuf=buf
10104
11196
  ctx._cstChildren=undefined
10105
11197
  ctx._cstLeaves=undefined
@@ -10110,7 +11202,10 @@ ctx._cstChildren=undefined
10110
11202
  ctx._cstLeaves=undefined
10111
11203
  ctx._cstRawChildren=undefined
10112
11204
  ctx._cstTriviaLog=undefined`;
10113
- const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
11205
+ const finishCapture = omitsRaw ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
11206
+ const hostKids=kids
11207
+ const rawKids=EMPTY_CH
11208
+ const tlog=buf.tl??EMPTY_TLOG` : keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
10114
11209
  const hostKids=kids
10115
11210
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
10116
11211
  const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
@@ -10144,7 +11239,7 @@ const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):unde
10144
11239
  let nd
10145
11240
  ${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]
10146
11241
  else ` : ""}{${value}}
10147
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
11242
+ ${L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : staticBuild ? "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,sBuf!==undefined?(sBuf.noRaw===true?undefined:rawEntry(nd,input,pos,end)):sRaw!==undefined?rawEntry(nd,input,pos,end):undefined)" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
10148
11243
  EC.e=end
10149
11244
  return nd
10150
11245
  }`;
@@ -10162,7 +11257,7 @@ return nd
10162
11257
  }
10163
11258
  const extra = [];
10164
11259
  for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
10165
- const source = `${RUNTIME_PRELUDE}
11260
+ const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10166
11261
  ${prelude.join("\n")}
10167
11262
  ${skipDefs.join("\n")}
10168
11263
  ${choiceDefs.join("\n")}
@@ -10177,7 +11272,13 @@ _pfHost=host
10177
11272
  function _finish(){
10178
11273
  if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
10179
11274
  _pfDepth--
10180
- if(_pfDepth===0)return
11275
+ if(_pfDepth===0){
11276
+ _pfTokInput=undefined
11277
+ _pfTokBody=-1
11278
+ _pfTokValue=undefined
11279
+ _pfTokDispatch=-1
11280
+ return
11281
+ }
10181
11282
  const prior=_pfFrames.pop()
10182
11283
  _pfScan=prior[0]
10183
11284
  _pfHost=prior[1]
@@ -10552,6 +11653,17 @@ function assemble(t, prog, cfg) {
10552
11653
  }
10553
11654
  return recognize;
10554
11655
  }
11656
+ const labelExtraIps = [];
11657
+ for (const s of prog.scans ?? []) {
11658
+ for (const r of s.skip) labelExtraIps.push(r[0]);
11659
+ if (s.sentinel !== void 0) labelExtraIps.push(s.sentinel[0]);
11660
+ }
11661
+ for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0]);
11662
+ const closureLabels = computeSiteLabels(
11663
+ code,
11664
+ [...Object.values(prog.rules), ...labelExtraIps],
11665
+ hostCst
11666
+ );
10555
11667
  let SCAN = null;
10556
11668
  const memo = /* @__PURE__ */ new Map();
10557
11669
  const reached = /* @__PURE__ */ new Set();
@@ -10797,7 +11909,7 @@ function assemble(t, prog, cfg) {
10797
11909
  const b = ctx._cstBuf;
10798
11910
  if (b !== void 0) {
10799
11911
  const raw = b.raw;
10800
- MRAW = raw !== void 0 ? raw.length : b.rawSingle !== void 0 ? 1 : 0;
11912
+ MRAW = b.noRaw === true ? b.rawLen ?? 0 : raw !== void 0 ? raw.length : b.rawSingle !== void 0 ? 1 : 0;
10801
11913
  const ch2 = b.ch;
10802
11914
  MLV = ch2 !== void 0 ? ch2.length : b.single !== void 0 ? 1 : 0;
10803
11915
  const tl = b.tl;
@@ -10881,6 +11993,31 @@ function assemble(t, prog, cfg) {
10881
11993
  if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
10882
11994
  return cur;
10883
11995
  }
11996
+ function nextTermBuffered(child, input, cur, ctx) {
11997
+ if (ctx.trivia === void 0) {
11998
+ const v2 = child(input, cur, ctx);
11999
+ if (v2 === FAIL) return -1;
12000
+ TERMV = v2;
12001
+ return EC.e;
12002
+ }
12003
+ const before = ctx._cstBuf;
12004
+ const beforeTl = before.tl;
12005
+ const mTl = beforeTl === void 0 ? 0 : beforeTl.length;
12006
+ const mLog = ctx._triviaLog?.length ?? 0;
12007
+ const mRoot = ctx._rootTriviaLog?.length ?? 0;
12008
+ const scanEnd = skipTrivia(input, cur, ctx);
12009
+ const scanned = ctx._cstBuf;
12010
+ const scannedTl = scanned.tl;
12011
+ const scanTl = scannedTl === void 0 ? 0 : scannedTl.length;
12012
+ const scanLog = ctx._triviaLog?.length ?? 0;
12013
+ const scanRoot = ctx._rootTriviaLog?.length ?? 0;
12014
+ const v = child(input, scanEnd, ctx);
12015
+ if (v === FAIL) return -1;
12016
+ TERMV = v;
12017
+ if (EC.e > scanEnd) return EC.e;
12018
+ rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
12019
+ return cur;
12020
+ }
10884
12021
  function committed3(c) {
10885
12022
  return c._fc === true;
10886
12023
  }
@@ -11151,7 +12288,8 @@ function assemble(t, prog, cfg) {
11151
12288
  target = p;
11152
12289
  } };
11153
12290
  inFlight.set(ip, holder);
11154
- const piece = lower(ip);
12291
+ const op = code[ip];
12292
+ 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);
11155
12293
  inFlight.delete(ip);
11156
12294
  holder.set(piece);
11157
12295
  memo.set(ip, piece);
@@ -11894,6 +13032,7 @@ function assemble(t, prog, cfg) {
11894
13032
  const reducer = fused ? code[ip + 1] : -1;
11895
13033
  const projection = reducer < 0 ? ~reducer : -1;
11896
13034
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
13035
+ const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
11897
13036
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
11898
13037
  if (count === 1) return (input, cur, ctx, values, inherited) => {
11899
13038
  cur = r0(input, cur, ctx, inherited);
@@ -11948,7 +13087,7 @@ function assemble(t, prog, cfg) {
11948
13087
  const kid = link(kidIp);
11949
13088
  return (input, cur, ctx, inherited) => {
11950
13089
  ctx._sync = sync ?? inherited;
11951
- return nextTerm(kid, input, cur, ctx);
13090
+ return step(kid, input, cur, ctx);
11952
13091
  };
11953
13092
  }
11954
13093
  const negated = code[kidIp + 1] === 1;
@@ -12033,7 +13172,7 @@ function assemble(t, prog, cfg) {
12033
13172
  const kidIp = code[base + i];
12034
13173
  if (code[kidIp] !== OP_ADJ) {
12035
13174
  const kid = link(kidIp);
12036
- return (input, cur, ctx) => nextTerm(kid, input, cur, ctx);
13175
+ return (input, cur, ctx) => step(kid, input, cur, ctx);
12037
13176
  }
12038
13177
  const negated = code[kidIp + 1] === 1;
12039
13178
  const ki = code[kidIp + 2];
@@ -12122,7 +13261,7 @@ function assemble(t, prog, cfg) {
12122
13261
  return (input, pos, ctx) => {
12123
13262
  const v0 = k0(input, pos, ctx);
12124
13263
  if (v0 === FAIL) return FAIL;
12125
- const cur = nextTerm(k1, input, EC.e, ctx);
13264
+ const cur = step(k1, input, EC.e, ctx);
12126
13265
  if (cur < 0) return FAIL;
12127
13266
  EC.e = cur;
12128
13267
  return projection === 0 ? v0 : projection === 1 ? TERMV : fn([v0, TERMV], { start: pos, end: cur });
@@ -12132,7 +13271,7 @@ function assemble(t, prog, cfg) {
12132
13271
  return (input, pos, ctx) => {
12133
13272
  const v0 = k0(input, pos, ctx);
12134
13273
  if (v0 === FAIL) return FAIL;
12135
- const cur = nextTerm(k1, input, EC.e, ctx);
13274
+ const cur = step(k1, input, EC.e, ctx);
12136
13275
  if (cur < 0) return FAIL;
12137
13276
  EC.e = cur;
12138
13277
  return [v0, TERMV];
@@ -12141,7 +13280,7 @@ function assemble(t, prog, cfg) {
12141
13280
  return (input, pos, ctx) => {
12142
13281
  const v0 = k0(input, pos, ctx);
12143
13282
  if (v0 === FAIL) return FAIL;
12144
- const cur = nextTerm(k1, input, EC.e, ctx);
13283
+ const cur = step(k1, input, EC.e, ctx);
12145
13284
  if (cur < 0) return FAIL;
12146
13285
  EC.e = cur;
12147
13286
  return void 0;
@@ -12153,10 +13292,10 @@ function assemble(t, prog, cfg) {
12153
13292
  return (input, pos, ctx) => {
12154
13293
  const v0 = k0(input, pos, ctx);
12155
13294
  if (v0 === FAIL) return FAIL;
12156
- let cur = nextTerm(k1, input, EC.e, ctx);
13295
+ let cur = step(k1, input, EC.e, ctx);
12157
13296
  if (cur < 0) return FAIL;
12158
13297
  const v1 = TERMV;
12159
- cur = nextTerm(k2, input, cur, ctx);
13298
+ cur = step(k2, input, cur, ctx);
12160
13299
  if (cur < 0) return FAIL;
12161
13300
  EC.e = cur;
12162
13301
  return projection === 0 ? v0 : projection === 1 ? v1 : projection === 2 ? TERMV : fn([v0, v1, TERMV], { start: pos, end: cur });
@@ -12166,10 +13305,10 @@ function assemble(t, prog, cfg) {
12166
13305
  return (input, pos, ctx) => {
12167
13306
  const v0 = k0(input, pos, ctx);
12168
13307
  if (v0 === FAIL) return FAIL;
12169
- let cur = nextTerm(k1, input, EC.e, ctx);
13308
+ let cur = step(k1, input, EC.e, ctx);
12170
13309
  if (cur < 0) return FAIL;
12171
13310
  const v1 = TERMV;
12172
- cur = nextTerm(k2, input, cur, ctx);
13311
+ cur = step(k2, input, cur, ctx);
12173
13312
  if (cur < 0) return FAIL;
12174
13313
  EC.e = cur;
12175
13314
  return [v0, v1, TERMV];
@@ -12178,9 +13317,9 @@ function assemble(t, prog, cfg) {
12178
13317
  return (input, pos, ctx) => {
12179
13318
  const v0 = k0(input, pos, ctx);
12180
13319
  if (v0 === FAIL) return FAIL;
12181
- let cur = nextTerm(k1, input, EC.e, ctx);
13320
+ let cur = step(k1, input, EC.e, ctx);
12182
13321
  if (cur < 0) return FAIL;
12183
- cur = nextTerm(k2, input, cur, ctx);
13322
+ cur = step(k2, input, cur, ctx);
12184
13323
  if (cur < 0) return FAIL;
12185
13324
  EC.e = cur;
12186
13325
  return void 0;
@@ -12188,43 +13327,43 @@ function assemble(t, prog, cfg) {
12188
13327
  }
12189
13328
  const block = (count, k0, k1, k2, k3, next) => {
12190
13329
  if (count === 1) return (input, cur, ctx, values) => {
12191
- cur = nextTerm(k0, input, cur, ctx);
13330
+ cur = step(k0, input, cur, ctx);
12192
13331
  if (cur < 0) return -1;
12193
13332
  if (values !== void 0) values.push(TERMV);
12194
13333
  return next === void 0 ? cur : next(input, cur, ctx, values);
12195
13334
  };
12196
13335
  if (count === 2) return (input, cur, ctx, values) => {
12197
- cur = nextTerm(k0, input, cur, ctx);
13336
+ cur = step(k0, input, cur, ctx);
12198
13337
  if (cur < 0) return -1;
12199
13338
  if (values !== void 0) values.push(TERMV);
12200
- cur = nextTerm(k1, input, cur, ctx);
13339
+ cur = step(k1, input, cur, ctx);
12201
13340
  if (cur < 0) return -1;
12202
13341
  if (values !== void 0) values.push(TERMV);
12203
13342
  return next === void 0 ? cur : next(input, cur, ctx, values);
12204
13343
  };
12205
13344
  if (count === 3) return (input, cur, ctx, values) => {
12206
- cur = nextTerm(k0, input, cur, ctx);
13345
+ cur = step(k0, input, cur, ctx);
12207
13346
  if (cur < 0) return -1;
12208
13347
  if (values !== void 0) values.push(TERMV);
12209
- cur = nextTerm(k1, input, cur, ctx);
13348
+ cur = step(k1, input, cur, ctx);
12210
13349
  if (cur < 0) return -1;
12211
13350
  if (values !== void 0) values.push(TERMV);
12212
- cur = nextTerm(k2, input, cur, ctx);
13351
+ cur = step(k2, input, cur, ctx);
12213
13352
  if (cur < 0) return -1;
12214
13353
  if (values !== void 0) values.push(TERMV);
12215
13354
  return next === void 0 ? cur : next(input, cur, ctx, values);
12216
13355
  };
12217
13356
  return (input, cur, ctx, values) => {
12218
- cur = nextTerm(k0, input, cur, ctx);
13357
+ cur = step(k0, input, cur, ctx);
12219
13358
  if (cur < 0) return -1;
12220
13359
  if (values !== void 0) values.push(TERMV);
12221
- cur = nextTerm(k1, input, cur, ctx);
13360
+ cur = step(k1, input, cur, ctx);
12222
13361
  if (cur < 0) return -1;
12223
13362
  if (values !== void 0) values.push(TERMV);
12224
- cur = nextTerm(k2, input, cur, ctx);
13363
+ cur = step(k2, input, cur, ctx);
12225
13364
  if (cur < 0) return -1;
12226
13365
  if (values !== void 0) values.push(TERMV);
12227
- cur = nextTerm(k3, input, cur, ctx);
13366
+ cur = step(k3, input, cur, ctx);
12228
13367
  if (cur < 0) return -1;
12229
13368
  if (values !== void 0) values.push(TERMV);
12230
13369
  return next === void 0 ? cur : next(input, cur, ctx, values);
@@ -12395,6 +13534,13 @@ function assemble(t, prog, cfg) {
12395
13534
  if (n === 2 || n === 3) {
12396
13535
  const a0 = link(code[base]), a1 = link(code[base + 1]);
12397
13536
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
13537
+ const predecide = !hostCst && !REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13538
+ const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
13539
+ const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
13540
+ const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
13541
+ const p0 = p0ip < 0 ? void 0 : scalarFor(p0ip);
13542
+ const p1 = p1ip < 0 ? void 0 : scalarFor(p1ip);
13543
+ const p2 = p2ip < 0 ? void 0 : scalarFor(p2ip);
12398
13544
  const e0 = fx[code[base + n]];
12399
13545
  const e1 = fx[code[base + n + 1]];
12400
13546
  const e2 = n === 3 ? fx[code[base + n + 2]] : void 0;
@@ -12424,7 +13570,10 @@ function assemble(t, prog, cfg) {
12424
13570
  let acc;
12425
13571
  let best = pos;
12426
13572
  if (c < 128) {
12427
- const bits = mask[c < 0 ? 128 : c];
13573
+ let bits = mask[c < 0 ? 128 : c];
13574
+ if ((bits & 1) !== 0 && p0 !== void 0 && p0(input, pos) < 0) bits &= ~1;
13575
+ if ((bits & 2) !== 0 && p1 !== void 0 && p1(input, pos) < 0) bits &= ~2;
13576
+ if ((bits & 4) !== 0 && p2 !== void 0 && p2(input, pos) < 0) bits &= ~4;
12428
13577
  let prev = 0;
12429
13578
  if ((bits & 1) !== 0) {
12430
13579
  ctx._fc = false;
@@ -12487,7 +13636,7 @@ function assemble(t, prog, cfg) {
12487
13636
  ctx._fx = acc ?? choiceFx;
12488
13637
  return FAIL;
12489
13638
  }
12490
- if (g0 === null || classHas2(g0, c)) {
13639
+ if ((g0 === null || classHas2(g0, c)) && (p0 === void 0 || p0(input, pos) >= 0)) {
12491
13640
  ctx._fc = false;
12492
13641
  const v = a0(input, pos, ctx);
12493
13642
  if (v !== FAIL) return v;
@@ -12503,7 +13652,7 @@ function assemble(t, prog, cfg) {
12503
13652
  }
12504
13653
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12505
13654
  } else if (best === pos) acc = accSet(e0, acc);
12506
- if (g1 === null || classHas2(g1, c)) {
13655
+ if ((g1 === null || classHas2(g1, c)) && (p1 === void 0 || p1(input, pos) >= 0)) {
12507
13656
  ctx._fc = false;
12508
13657
  const v = a1(input, pos, ctx);
12509
13658
  if (v !== FAIL) return v;
@@ -12520,7 +13669,7 @@ function assemble(t, prog, cfg) {
12520
13669
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12521
13670
  } else if (best === pos) acc = accSet(e1, acc);
12522
13671
  if (n === 3) {
12523
- if (g2 === null || classHas2(g2, c)) {
13672
+ if ((g2 === null || classHas2(g2, c)) && (p2 === void 0 || p2(input, pos) >= 0)) {
12524
13673
  ctx._fc = false;
12525
13674
  const v = a2(input, pos, ctx);
12526
13675
  if (v !== FAIL) return v;
@@ -13093,20 +14242,14 @@ function assemble(t, prog, cfg) {
13093
14242
  const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
13094
14243
  const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
13095
14244
  const rawOnly = !keepChildren;
14245
+ const omitsRaw = !hostCst && build !== void 0 && proj < 0 && (flags & 2) !== 0;
13096
14246
  return (input, pos, ctx) => {
13097
14247
  const host = HOST;
13098
14248
  const sCh = ctx._cstChildren;
13099
- const sLv = ctx._cstLeaves;
13100
- const sRaw = ctx._cstRawChildren;
13101
- const sTl = ctx._cstTriviaLog;
13102
14249
  const sCap = ctx.captureTrivia;
13103
14250
  const sBuf = ctx._cstBuf;
13104
- const buf = rawOnly ? { rawOnly: true } : {};
14251
+ const buf = rawOnly ? { rawOnly: true } : omitsRaw ? { noRaw: true, rawLen: 0 } : {};
13105
14252
  ctx._cstBuf = buf;
13106
- ctx._cstChildren = void 0;
13107
- ctx._cstLeaves = void 0;
13108
- ctx._cstRawChildren = void 0;
13109
- ctx._cstTriviaLog = void 0;
13110
14253
  ctx.captureTrivia = captureWide;
13111
14254
  const savedFields = ctx._fields;
13112
14255
  ctx._fields = wantFields ? [] : void 0;
@@ -13121,13 +14264,9 @@ function assemble(t, prog, cfg) {
13121
14264
  if (structural) ctx._triviaCaptureMask = savedMask;
13122
14265
  const kids = rawOnly ? EMPTY_CH : buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY_CH);
13123
14266
  const hostKids = kids;
13124
- const rawKids = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
14267
+ const rawKids = omitsRaw ? EMPTY_CH : buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
13125
14268
  const tlog = buf.tl ?? EMPTY_TLOG;
13126
14269
  ctx._cstBuf = sBuf;
13127
- ctx._cstChildren = sCh;
13128
- ctx._cstLeaves = sLv;
13129
- ctx._cstRawChildren = sRaw;
13130
- ctx._cstTriviaLog = sTl;
13131
14270
  ctx.captureTrivia = sCap;
13132
14271
  if (v === FAIL) return FAIL;
13133
14272
  const end = EC.e;
@@ -13218,6 +14357,34 @@ function assemble(t, prog, cfg) {
13218
14357
  rawScalarSpecs.add(code[child + 1]);
13219
14358
  scalarFor(child);
13220
14359
  }
14360
+ } else if (code[ip] === OP_CHOICE && !disp[code[ip + 1]].exclusive) {
14361
+ const n = code[ip + 2];
14362
+ for (let i = 0; i < n; i++) {
14363
+ const armIp = code[ip + 4 + i];
14364
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
14365
+ if (n === 2 || n === 3) {
14366
+ if (child >= 0) scalarFor(child);
14367
+ continue;
14368
+ }
14369
+ if (child >= 0) {
14370
+ const spec = k[code[child + 1]];
14371
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
14372
+ scalarFor(child);
14373
+ continue;
14374
+ }
14375
+ }
14376
+ const family = leadingLiteralFamily(code, k, armIp);
14377
+ if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
14378
+ const value = k[code[terminal + 1]];
14379
+ return typeof value === "string" && value.length >= 2;
14380
+ })) {
14381
+ for (const terminal of family) scalarFor(terminal);
14382
+ }
14383
+ const sequence6 = leadingScalarSequence(code, armIp);
14384
+ if (sequence6 !== void 0 && (sequence6.trivia < 0 || triviaScan[sequence6.trivia] != null)) {
14385
+ for (const terminal of sequence6.terminals) scalarFor(terminal);
14386
+ }
14387
+ }
13221
14388
  }
13222
14389
  }
13223
14390
  const notChild = scalarTerminalNotChild(code, ip);
@@ -13639,7 +14806,7 @@ function emitAssemblies(prog, cfgs) {
13639
14806
  seen.add(key);
13640
14807
  let em;
13641
14808
  try {
13642
- em = emitAssemblySource(t, prog, cfg, extraIps);
14809
+ em = emitAssemblySource(t, prog, cfg, extraIps, true);
13643
14810
  } catch (e) {
13644
14811
  if (e instanceof Unemittable) continue;
13645
14812
  throw e;
@@ -15175,7 +16342,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
15175
16342
  };
15176
16343
  const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
15177
16344
  const artifact = closureArtifact(prog);
15178
- const entry = tableRules(artifact)[ENTRY];
16345
+ const entry = tableRules(prog)[ENTRY];
15179
16346
  const offered = opts.fnSources ?? mapFnSources;
15180
16347
  const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
15181
16348
  const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
@@ -15224,106 +16391,6 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
15224
16391
  };
15225
16392
  }
15226
16393
 
15227
- // src/analysis/commitment.ts
15228
- function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
15229
- if (seen.has(p)) return false;
15230
- seen.add(p);
15231
- const d = p._def;
15232
- switch (d.tag) {
15233
- case "node":
15234
- return d.build !== void 0 || hasDirectBuildDef(d.parser, seen);
15235
- case "lazy": {
15236
- try {
15237
- return hasDirectBuildDef(d.thunk(), seen);
15238
- } catch {
15239
- return false;
15240
- }
15241
- }
15242
- case "grammar":
15243
- case "trivia":
15244
- case "token":
15245
- case "leaf":
15246
- case "label":
15247
- case "field":
15248
- case "optional":
15249
- case "many":
15250
- case "oneOrMore":
15251
- case "attempt":
15252
- case "not":
15253
- case "peek":
15254
- case "withCtx":
15255
- case "expect":
15256
- case "transform":
15257
- return hasDirectBuildDef(d.parser, seen);
15258
- case "sequence":
15259
- case "choice":
15260
- return d.parsers.some((x) => hasDirectBuildDef(x, seen));
15261
- case "dispatch":
15262
- return hasDirectBuildDef(d.selector, seen) || d.cases.some((x) => hasDirectBuildDef(x.parser, seen)) || (d.matchers ? d.matchers.some((x) => hasDirectBuildDef(x.parser, seen)) : false) || (d.otherwise ? hasDirectBuildDef(d.otherwise, seen) : false);
15263
- case "sepBy":
15264
- return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.separator, seen);
15265
- case "scanTo":
15266
- return hasDirectBuildDef(d.sentinel, seen) || d.skip.some((x) => hasDirectBuildDef(x, seen));
15267
- case "recover":
15268
- return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.sentinel, seen);
15269
- case "routed":
15270
- return d.fallback ? hasDirectBuildDef(d.fallback, seen) : false;
15271
- default:
15272
- return false;
15273
- }
15274
- }
15275
- function hasSemanticReduction(roots, externalRefs) {
15276
- const seen = /* @__PURE__ */ new Set();
15277
- const visit = (parser2) => {
15278
- if (seen.has(parser2)) return false;
15279
- seen.add(parser2);
15280
- const def = parser2._def;
15281
- if (def.tag === "transform" && !def.recognitionOnly) return true;
15282
- if (def.tag === "choice" && def.gates.some(Boolean)) return true;
15283
- if (def.tag === "guard" || def.tag === "withCtx") return true;
15284
- if (def.tag === "node" && def.build !== void 0) return true;
15285
- if (def.tag === "lazy") {
15286
- if (externalRefs?.has(parser2)) return false;
15287
- try {
15288
- return visit(def.thunk());
15289
- } catch {
15290
- return true;
15291
- }
15292
- }
15293
- return childrenOf2(def).some(visit);
15294
- };
15295
- return roots.some(visit);
15296
- }
15297
- function classifyRuleMap(ruleMap) {
15298
- const externalRefs = /* @__PURE__ */ new Set();
15299
- const scanned = /* @__PURE__ */ new Set();
15300
- const scanExternal = (p) => {
15301
- if (scanned.has(p)) return;
15302
- scanned.add(p);
15303
- const def = p._def;
15304
- if (def.tag === "lazy") {
15305
- let resolved;
15306
- try {
15307
- resolved = def.thunk();
15308
- } catch {
15309
- resolved = void 0;
15310
- }
15311
- if (resolved === void 0) {
15312
- if (p._ruleName) externalRefs.add(p);
15313
- return;
15314
- }
15315
- scanExternal(resolved);
15316
- return;
15317
- }
15318
- for (const child of childrenOf2(def)) scanExternal(child);
15319
- };
15320
- for (const [, rule] of ruleMap) scanExternal(rule);
15321
- return {
15322
- hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
15323
- isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule), externalRefs)
15324
- };
15325
- }
15326
-
15327
16394
  // src/combinators/withCtx.ts
15328
16395
  function withCtx(extra, combinator) {
15329
16396
  const meta = {
@@ -15466,7 +16533,7 @@ function evalRuleMapIR(ir) {
15466
16533
  l._def.fnSrc = src;
15467
16534
  return l;
15468
16535
  };
15469
- const _nd = (type, child, src, opts, staticError, sigSrc) => {
16536
+ const _nd = (type, child, src, opts, staticError, sigSrc, buildImports, rawUnused) => {
15470
16537
  if (staticError !== void 0 && staticError.length > 0) {
15471
16538
  throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
15472
16539
  }
@@ -15476,6 +16543,8 @@ function evalRuleMapIR(ir) {
15476
16543
  n._def.buildSrc = src;
15477
16544
  if (staticError !== void 0) n._def.buildStaticError = staticError;
15478
16545
  if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
16546
+ if (rawUnused === true) n._def.buildRawUnused = true;
16547
+ if (buildImports !== void 0) n._def.buildImports = buildImports;
15479
16548
  return n;
15480
16549
  };
15481
16550
  const _gch = (items) => {
@@ -15867,11 +16936,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
15867
16936
  }
15868
16937
  if (def.buildSrc !== void 0) {
15869
16938
  const tail = [];
15870
- if (def.buildStaticError !== void 0 || def.buildSigSrc !== void 0) {
16939
+ if (def.buildStaticError !== void 0 || def.buildSigSrc !== void 0 || def.buildImports !== void 0 || def.buildRawUnused === true) {
15871
16940
  if (!opts) tail.push("undefined");
15872
16941
  tail.push(def.buildStaticError === void 0 ? "undefined" : JSON.stringify(def.buildStaticError));
15873
16942
  }
15874
- if (def.buildSigSrc !== void 0) tail.push(JSON.stringify(def.buildSigSrc));
16943
+ if (def.buildSigSrc !== void 0 || def.buildImports !== void 0 || def.buildRawUnused === true) tail.push(def.buildSigSrc === void 0 ? "undefined" : JSON.stringify(def.buildSigSrc));
16944
+ if (def.buildImports !== void 0 || def.buildRawUnused === true) tail.push(def.buildImports === void 0 ? "undefined" : JSON.stringify(def.buildImports));
16945
+ if (def.buildRawUnused === true) tail.push("true");
15875
16946
  const trailing = tail.length > 0 ? `, ${tail.join(", ")}` : "";
15876
16947
  return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${trailing})`;
15877
16948
  }
@@ -15940,7 +17011,7 @@ function compileRuleMapRunnable(ruleMap, opts = {}) {
15940
17011
  hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
15941
17012
  reflection: collectGrammarReflection(ruleMap),
15942
17013
  ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
15943
- rules: tableRules(artifact),
17014
+ rules: tableRules(prog),
15944
17015
  prog: artifact
15945
17016
  };
15946
17017
  }
@@ -16012,13 +17083,13 @@ function compileRuleMap(ruleMap, opts = {}) {
16012
17083
  hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
16013
17084
  reflection: collectGrammarReflection(ruleMap),
16014
17085
  ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16015
- rules: tableRules(artifact),
17086
+ rules: tableRules(prog),
16016
17087
  prog: artifact
16017
17088
  };
16018
17089
  }
16019
17090
 
16020
17091
  // src/version.ts
16021
- var PARSEMAN_VERSION = "0.48.1";
17092
+ var PARSEMAN_VERSION = "0.50.0";
16022
17093
 
16023
17094
  // src/compiler/compile-linkable-table.ts
16024
17095
  function isLocal(rule) {
@@ -16174,6 +17245,11 @@ function materializeDirectBuilders(ruleMap) {
16174
17245
  seen.add(p);
16175
17246
  const d = p._def;
16176
17247
  if (d.tag === "node" && typeof d.buildSrc === "string") {
17248
+ if (d.buildImports !== void 0 && d.buildImports.length > 0) {
17249
+ throw new Error(
17250
+ `IR direct node builder for ${d.type ?? "<anonymous>"} references module import(s) ${d.buildImports.map((bi) => bi.local).join(", ")} that a runtime compose() cannot supply; compose at build time via the parseman macro plugin, which re-emits the imports.`
17251
+ );
17252
+ }
16177
17253
  try {
16178
17254
  const fn = (0, eval)(`(${d.buildSrc})`);
16179
17255
  if (typeof fn === "function") d.build = fn;