parseman 0.57.0 → 0.58.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 (64) hide show
  1. package/dist/analysis/diagnostics.js +1799 -962
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +1928 -1091
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/dispatch.d.ts.map +1 -1
  6. package/dist/compiler/token-alphabet.d.ts +11 -1
  7. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  8. package/dist/compiler/token-capability.js +69 -16
  9. package/dist/compiler/token-capability.js.map +2 -2
  10. package/dist/cst/capture-buffer.d.ts +6 -0
  11. package/dist/cst/capture-buffer.d.ts.map +1 -1
  12. package/dist/index.js +1016 -177
  13. package/dist/index.js.map +3 -3
  14. package/dist/plugin/index.d.ts +25 -1
  15. package/dist/plugin/index.d.ts.map +1 -1
  16. package/dist/plugin/index.js +1209 -236
  17. package/dist/plugin/index.js.map +3 -3
  18. package/dist/table/assemble.d.ts.map +1 -1
  19. package/dist/table/compile-rule-map.d.ts.map +1 -1
  20. package/dist/table/emit-assembly.d.ts +1 -1
  21. package/dist/table/emit-assembly.d.ts.map +1 -1
  22. package/dist/table/emit.d.ts.map +1 -1
  23. package/dist/table/encode.d.ts.map +1 -1
  24. package/dist/table/exec.d.ts.map +1 -1
  25. package/dist/table/factor-choice.d.ts +42 -0
  26. package/dist/table/factor-choice.d.ts.map +1 -0
  27. package/dist/table/fail-clean.d.ts +3 -0
  28. package/dist/table/fail-clean.d.ts.map +1 -0
  29. package/dist/table/hold-gap.d.ts +8 -0
  30. package/dist/table/hold-gap.d.ts.map +1 -0
  31. package/dist/table/index.js +1369 -259
  32. package/dist/table/index.js.map +3 -3
  33. package/dist/table/lex-program.d.ts +7 -3
  34. package/dist/table/lex-program.d.ts.map +1 -1
  35. package/dist/table/ops.d.ts +8 -0
  36. package/dist/table/ops.d.ts.map +1 -1
  37. package/dist/table/run-support.d.ts +19 -0
  38. package/dist/table/run-support.d.ts.map +1 -1
  39. package/dist/table/scalar-terminal.d.ts +2 -0
  40. package/dist/table/scalar-terminal.d.ts.map +1 -1
  41. package/dist/table/site-labels.d.ts +66 -0
  42. package/dist/table/site-labels.d.ts.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/package.json +1 -1
  45. package/src/combinators/dispatch.ts +12 -3
  46. package/src/compiler/token-alphabet.ts +57 -17
  47. package/src/cst/capture-buffer.ts +25 -0
  48. package/src/plugin/index.ts +230 -35
  49. package/src/table/assemble.ts +252 -62
  50. package/src/table/child-slots.ts +2 -2
  51. package/src/table/compile-rule-map.ts +14 -5
  52. package/src/table/emit-assembly.ts +112 -23
  53. package/src/table/emit.ts +3 -1
  54. package/src/table/encode.ts +80 -14
  55. package/src/table/exec.ts +27 -8
  56. package/src/table/factor-choice.ts +173 -0
  57. package/src/table/fail-clean.ts +130 -0
  58. package/src/table/hold-gap.ts +68 -0
  59. package/src/table/lex-program.ts +197 -43
  60. package/src/table/ops.ts +9 -1
  61. package/src/table/run-support.ts +35 -0
  62. package/src/table/scalar-terminal.ts +8 -0
  63. package/src/table/site-labels.ts +135 -4
  64. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -465,6 +465,31 @@ function pushCstChild(ctx, built, rawEntry2) {
465
465
  else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
466
466
  if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry2);
467
467
  }
468
+ function popCstChild(ctx) {
469
+ const b = ctx._cstBuf;
470
+ if (b) {
471
+ const ch2 = b.ch;
472
+ if (b.rawOnly !== true && ch2) {
473
+ ch2.pop();
474
+ if (ch2.length === 1) {
475
+ b.single = ch2[0];
476
+ b.ch = void 0;
477
+ }
478
+ }
479
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1;
480
+ else if (b.raw) {
481
+ b.raw.pop();
482
+ if (b.raw.length === 1) {
483
+ b.rawSingle = b.raw[0];
484
+ b.raw = void 0;
485
+ }
486
+ } else b.rawSingle = void 0;
487
+ return;
488
+ }
489
+ if (ctx._cstChildren) ctx._cstChildren.pop();
490
+ else if (ctx._cstLeaves) ctx._cstLeaves.pop();
491
+ if (ctx._cstRawChildren) ctx._cstRawChildren.pop();
492
+ }
468
493
  function cstRawLen(ctx) {
469
494
  const b = ctx._cstBuf;
470
495
  if (b) {
@@ -3398,10 +3423,16 @@ function branchUsesRouted(branch) {
3398
3423
  return branch.usesRouted === true || parserUsesRouted(branch.parser);
3399
3424
  }
3400
3425
  function asciiFoldKey(key) {
3401
- let out = "";
3402
- for (let i = 0; i < key.length; i++) {
3426
+ let i = 0;
3427
+ for (; i < key.length; i++) {
3428
+ const c = key.charCodeAt(i);
3429
+ if (c >= 65 && c <= 90) break;
3430
+ }
3431
+ if (i === key.length) return key;
3432
+ let out = key.slice(0, i);
3433
+ for (; i < key.length; i++) {
3403
3434
  const c = key.charCodeAt(i);
3404
- out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
3435
+ out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : key[i];
3405
3436
  }
3406
3437
  return out;
3407
3438
  }
@@ -5388,17 +5419,59 @@ function buildLexBodyRecognizer(spec, constants) {
5388
5419
  };
5389
5420
  }
5390
5421
 
5422
+ // src/table/run-support.ts
5423
+ function lineCol(ctx, offset) {
5424
+ const starts = ctx._lineStarts ?? [0];
5425
+ let lo = 0, hi = starts.length - 1;
5426
+ while (lo < hi) {
5427
+ const mid = lo + hi + 1 >> 1;
5428
+ if (starts[mid] <= offset) lo = mid;
5429
+ else hi = mid - 1;
5430
+ }
5431
+ return [lo + 1, offset - starts[lo] + 1];
5432
+ }
5433
+ function spanLines(ctx, start, end) {
5434
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
5435
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
5436
+ }
5437
+ function rawEntry(v, input, s, e) {
5438
+ if (typeof v === "object" && v !== null) {
5439
+ const tg = v._tag;
5440
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
5441
+ }
5442
+ return {
5443
+ _tag: "leaf",
5444
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
5445
+ span: { start: s, end: e }
5446
+ };
5447
+ }
5448
+ function lead(input, pos) {
5449
+ if (pos >= input.length) return -1;
5450
+ const c = input.charCodeAt(pos);
5451
+ if (c < 55296 || c > 56319) return c;
5452
+ return input.codePointAt(pos) ?? c;
5453
+ }
5454
+ var EMPTY_KIDS = Object.freeze([]);
5455
+ var EMPTY_TRIVIA = Object.freeze([]);
5456
+ function collapseEmpty(ctx, build, input, pos, end, readsRaw) {
5457
+ const collected = ctx._cstBuf !== void 0 || ctx._cstChildren !== void 0;
5458
+ if (collected) popCstChild(ctx);
5459
+ const raw = readsRaw ? [rawEntry(void 0, input, pos, end)] : EMPTY_KIDS;
5460
+ const nd = build(EMPTY_KIDS, void 0, { start: pos, end }, raw, EMPTY_TRIVIA, void 0);
5461
+ if (collected) pushCstChild(ctx, nd, ctx._cstBuf?.noRaw === true ? void 0 : rawEntry(nd, input, pos, end));
5462
+ return nd;
5463
+ }
5464
+
5391
5465
  // src/table/lex-program.ts
5392
5466
  var LEX_NODE_TERMINAL = 0;
5393
5467
  var LEX_NODE_SEQUENCE2 = 1;
5394
5468
  var LEX_NODE_SEQUENCE3 = 2;
5395
5469
  var LEX_NODE_SEQUENCE4 = 3;
5396
5470
  var LEX_NODE_SEQUENCE5 = 4;
5397
- var LEX_NODE_CHOICE2 = 5;
5398
- var LEX_NODE_CHOICE4 = 6;
5399
- var LEX_NODE_CHOICE8 = 7;
5471
+ var LEX_NODE_CHOICE = 5;
5400
5472
  var LEX_NODE_NOT = 8;
5401
5473
  var LEX_NODE_OPTIONAL = 9;
5474
+ var LEX_NODE_REPEAT = 10;
5402
5475
  function lexProgramDigest(words) {
5403
5476
  let hash = 2166136261;
5404
5477
  for (const word2 of words) {
@@ -5427,85 +5500,114 @@ function trackLexLines(ctx, input, end) {
5427
5500
  ctx._lineScannedTo = end;
5428
5501
  }
5429
5502
  function terminalNode(matcher, failure, tracksLines) {
5430
- const match = (input, pos) => {
5431
- const result = matcher(input, pos);
5432
- return result < 0 ? -1 : result / 2;
5433
- };
5434
5503
  return {
5435
- match,
5504
+ match: (input, pos) => {
5505
+ const result = matcher(input, pos);
5506
+ return result < 0 ? -1 : result / 2;
5507
+ },
5436
5508
  run: (input, pos, ctx) => {
5437
- const end = match(input, pos);
5438
- if (end < 0) {
5509
+ const result = matcher(input, pos);
5510
+ if (result < 0) {
5439
5511
  ctx._fe = pos;
5440
5512
  ctx._fx = failure;
5441
5513
  if (ctx._probe !== void 0) failAt(ctx, ctx._fx, pos);
5442
5514
  return -1;
5443
5515
  }
5516
+ const end = result / 2;
5444
5517
  if (tracksLines) trackLexLines(ctx, input, end);
5445
5518
  return end;
5446
5519
  }
5447
5520
  };
5448
5521
  }
5449
5522
  function sequence2(a, b) {
5523
+ const am = a.match, bm = b.match, ar = a.run, br = b.run;
5450
5524
  return {
5451
5525
  match: (input, pos) => {
5452
- const e0 = a.match(input, pos);
5453
- return e0 < 0 ? -1 : b.match(input, e0);
5526
+ const e0 = am(input, pos);
5527
+ return e0 < 0 ? -1 : bm(input, e0);
5454
5528
  },
5455
5529
  run: (input, pos, ctx) => {
5456
- const e0 = a.run(input, pos, ctx);
5530
+ const e0 = ar(input, pos, ctx);
5457
5531
  if (e0 < 0) return -1;
5458
5532
  ctx._fc = false;
5459
- return b.run(input, e0, ctx);
5533
+ return br(input, e0, ctx);
5460
5534
  }
5461
5535
  };
5462
5536
  }
5463
5537
  function sequence3(a, b, c) {
5538
+ const am = a.match, bm = b.match, cm = c.match, ar = a.run, br = b.run, cr = c.run;
5464
5539
  return {
5465
5540
  match: (input, pos) => {
5466
- const e0 = a.match(input, pos);
5541
+ const e0 = am(input, pos);
5467
5542
  if (e0 < 0) return -1;
5468
- const e1 = b.match(input, e0);
5469
- return e1 < 0 ? -1 : c.match(input, e1);
5543
+ const e1 = bm(input, e0);
5544
+ return e1 < 0 ? -1 : cm(input, e1);
5470
5545
  },
5471
5546
  run: (input, pos, ctx) => {
5472
- const e0 = a.run(input, pos, ctx);
5547
+ const e0 = ar(input, pos, ctx);
5473
5548
  if (e0 < 0) return -1;
5474
5549
  ctx._fc = false;
5475
- const e1 = b.run(input, e0, ctx);
5550
+ const e1 = br(input, e0, ctx);
5476
5551
  if (e1 < 0) return -1;
5477
5552
  ctx._fc = false;
5478
- return c.run(input, e1, ctx);
5553
+ return cr(input, e1, ctx);
5479
5554
  }
5480
5555
  };
5481
5556
  }
5482
5557
  function sequence4(a, b, c, d) {
5483
- const abc = sequence3(a, b, c);
5558
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match;
5559
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run;
5484
5560
  return {
5485
5561
  match: (input, pos) => {
5486
- const end = abc.match(input, pos);
5487
- return end < 0 ? -1 : d.match(input, end);
5562
+ const e0 = am(input, pos);
5563
+ if (e0 < 0) return -1;
5564
+ const e1 = bm(input, e0);
5565
+ if (e1 < 0) return -1;
5566
+ const e2 = cm(input, e1);
5567
+ return e2 < 0 ? -1 : dm(input, e2);
5488
5568
  },
5489
5569
  run: (input, pos, ctx) => {
5490
- const end = abc.run(input, pos, ctx);
5491
- if (end < 0) return -1;
5570
+ const e0 = ar(input, pos, ctx);
5571
+ if (e0 < 0) return -1;
5572
+ ctx._fc = false;
5573
+ const e1 = br(input, e0, ctx);
5574
+ if (e1 < 0) return -1;
5575
+ ctx._fc = false;
5576
+ const e2 = cr(input, e1, ctx);
5577
+ if (e2 < 0) return -1;
5492
5578
  ctx._fc = false;
5493
- return d.run(input, end, ctx);
5579
+ return dr(input, e2, ctx);
5494
5580
  }
5495
5581
  };
5496
5582
  }
5497
5583
  function sequence5(a, b, c, d, e) {
5498
- const abcd = sequence4(a, b, c, d);
5584
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match, em = e.match;
5585
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run, er = e.run;
5499
5586
  return {
5500
5587
  match: (input, pos) => {
5501
- const end = abcd.match(input, pos);
5502
- return end < 0 ? -1 : e.match(input, end);
5588
+ const e0 = am(input, pos);
5589
+ if (e0 < 0) return -1;
5590
+ const e1 = bm(input, e0);
5591
+ if (e1 < 0) return -1;
5592
+ const e2 = cm(input, e1);
5593
+ if (e2 < 0) return -1;
5594
+ const e3 = dm(input, e2);
5595
+ return e3 < 0 ? -1 : em(input, e3);
5503
5596
  },
5504
5597
  run: (input, pos, ctx) => {
5505
- const end = abcd.run(input, pos, ctx);
5506
- if (end < 0) return -1;
5598
+ const e0 = ar(input, pos, ctx);
5599
+ if (e0 < 0) return -1;
5600
+ ctx._fc = false;
5601
+ const e1 = br(input, e0, ctx);
5602
+ if (e1 < 0) return -1;
5603
+ ctx._fc = false;
5604
+ const e2 = cr(input, e1, ctx);
5605
+ if (e2 < 0) return -1;
5507
5606
  ctx._fc = false;
5508
- return e.run(input, end, ctx);
5607
+ const e3 = dr(input, e2, ctx);
5608
+ if (e3 < 0) return -1;
5609
+ ctx._fc = false;
5610
+ return er(input, e3, ctx);
5509
5611
  }
5510
5612
  };
5511
5613
  }
@@ -5518,9 +5620,9 @@ function appendExpected(acc, values) {
5518
5620
  function choiceNode(arms, classes, armExpected, choiceExpected) {
5519
5621
  let matchTail = () => -1;
5520
5622
  for (let i = arms.length - 1; i >= 0; i--) {
5521
- const arm = arms[i], next = matchTail;
5623
+ const armMatch = arms[i].match, next = matchTail;
5522
5624
  matchTail = (input, pos) => {
5523
- const end = arm.match(input, pos);
5625
+ const end = armMatch(input, pos);
5524
5626
  return end < 0 ? next(input, pos) : end;
5525
5627
  };
5526
5628
  }
@@ -5530,7 +5632,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5530
5632
  return -1;
5531
5633
  };
5532
5634
  for (let i = arms.length - 1; i >= 0; i--) {
5533
- const arm = arms[i], cls = classes[i], staticExpected = armExpected[i], next = tail;
5635
+ const armRun = arms[i].run, cls = classes[i], staticExpected = armExpected[i], next = tail;
5534
5636
  tail = (input, pos, ctx, lead2, acc, best) => {
5535
5637
  if (cls !== void 0 && !classHas(cls, lead2)) {
5536
5638
  return next(
@@ -5543,7 +5645,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5543
5645
  );
5544
5646
  }
5545
5647
  ctx._fc = false;
5546
- const end = arm.run(input, pos, ctx);
5648
+ const end = armRun(input, pos, ctx);
5547
5649
  if (end >= 0) return end;
5548
5650
  const at = ctx._fe ?? pos;
5549
5651
  if (at > best) {
@@ -5570,11 +5672,58 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
5570
5672
  )
5571
5673
  };
5572
5674
  }
5675
+ function exclusiveChoiceNode(arms, classes, choiceFx) {
5676
+ const ascii = (classes.length <= 128 ? new Int8Array(128) : new Int32Array(128)).fill(-1);
5677
+ const hi = [];
5678
+ for (let i = 0; i < classes.length; i++) {
5679
+ const cls = classes[i];
5680
+ for (let c = 0; c < 128; c++) if (cls.ascii[c] === 1) ascii[c] = i;
5681
+ for (let r = 0; r < cls.hi.length; r += 2) hi.push(cls.hi[r], cls.hi[r + 1], i);
5682
+ }
5683
+ const select = (code) => {
5684
+ if (code < 0) return -1;
5685
+ if (code < 128) return ascii[code];
5686
+ for (let r = 0; r < hi.length; r += 3) if (code >= hi[r] && code <= hi[r + 1]) return hi[r + 2];
5687
+ return -1;
5688
+ };
5689
+ let matchArm = () => -1;
5690
+ let selectRun = () => -1;
5691
+ for (let i = arms.length - 1; i >= 0; i--) {
5692
+ const armMatch = arms[i].match, armRun = arms[i].run, nextMatch = matchArm, nextRun = selectRun;
5693
+ matchArm = (selected, input, pos) => selected === i ? armMatch(input, pos) : nextMatch(selected, input, pos);
5694
+ selectRun = (selected, input, pos, ctx) => selected === i ? armRun(input, pos, ctx) : nextRun(selected, input, pos, ctx);
5695
+ }
5696
+ const runArm = (input, pos, ctx) => {
5697
+ const arm = select(lead(input, pos));
5698
+ if (arm >= 0) {
5699
+ ctx._fc = false;
5700
+ const end = selectRun(arm, input, pos, ctx);
5701
+ if (end >= 0) return end;
5702
+ if (committed(ctx)) return -1;
5703
+ const failed = ctx._fx;
5704
+ if (failed !== void 0 && failed.length > 0) {
5705
+ ctx._fe = pos;
5706
+ return -1;
5707
+ }
5708
+ }
5709
+ ctx._fe = pos;
5710
+ ctx._fx = choiceFx;
5711
+ return -1;
5712
+ };
5713
+ return {
5714
+ match: (input, pos) => {
5715
+ const arm = select(lead(input, pos));
5716
+ return arm < 0 ? -1 : matchArm(arm, input, pos);
5717
+ },
5718
+ run: runArm
5719
+ };
5720
+ }
5573
5721
  function notNode(body, failure) {
5722
+ const bodyMatch = body.match;
5574
5723
  return {
5575
- match: (input, pos) => body.match(input, pos) < 0 ? pos : -1,
5724
+ match: (input, pos) => bodyMatch(input, pos) < 0 ? pos : -1,
5576
5725
  run: (input, pos, ctx) => {
5577
- if (body.match(input, pos) < 0) return pos;
5726
+ if (bodyMatch(input, pos) < 0) return pos;
5578
5727
  ctx._fe = pos;
5579
5728
  ctx._fx = failure;
5580
5729
  return -1;
@@ -5582,18 +5731,57 @@ function notNode(body, failure) {
5582
5731
  };
5583
5732
  }
5584
5733
  function optionalNode(body) {
5734
+ const bodyMatch = body.match, bodyRun = body.run;
5585
5735
  return {
5586
5736
  match: (input, pos) => {
5587
- const end = body.match(input, pos);
5737
+ const end = bodyMatch(input, pos);
5588
5738
  return end < 0 ? pos : end;
5589
5739
  },
5590
5740
  run: (input, pos, ctx) => {
5591
5741
  ctx._fc = false;
5592
- const end = body.run(input, pos, ctx);
5742
+ const end = bodyRun(input, pos, ctx);
5593
5743
  return end < 0 && !committed(ctx) ? pos : end;
5594
5744
  }
5595
5745
  };
5596
5746
  }
5747
+ function repeatNode(item, min, max) {
5748
+ const itemMatch = item.match, itemRun = item.run;
5749
+ return {
5750
+ match: (input, pos) => {
5751
+ let cur = pos;
5752
+ let count = 0;
5753
+ for (; ; ) {
5754
+ if (max >= 0 && count >= max) break;
5755
+ const optional2 = count >= min && (count > 0 || min === 0);
5756
+ if (optional2 && cur >= input.length) break;
5757
+ const end = itemMatch(input, cur);
5758
+ if (end < 0 || optional2 && end === cur) break;
5759
+ cur = end;
5760
+ count++;
5761
+ }
5762
+ return count < min ? -1 : cur;
5763
+ },
5764
+ run: (input, pos, ctx) => {
5765
+ let cur = pos;
5766
+ let count = 0;
5767
+ for (; ; ) {
5768
+ if (max >= 0 && count >= max) break;
5769
+ const optional2 = count >= min && (count > 0 || min === 0);
5770
+ if (optional2 && cur >= input.length) break;
5771
+ ctx._fc = false;
5772
+ const end = itemRun(input, cur, ctx);
5773
+ if (end < 0) {
5774
+ if (committed(ctx)) return -1;
5775
+ break;
5776
+ }
5777
+ if (optional2 && end === cur) break;
5778
+ cur = end;
5779
+ count++;
5780
+ }
5781
+ return count < min ? -1 : cur;
5782
+ }
5783
+ };
5784
+ }
5597
5785
  function fixedTreeRunner(words, matchers, classes, expected) {
5598
5786
  const stack = [];
5599
5787
  const pop = () => {
@@ -5621,9 +5809,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5621
5809
  else stack.push(sequence5(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4]));
5622
5810
  continue;
5623
5811
  }
5624
- if (op >= LEX_NODE_CHOICE2 && op <= LEX_NODE_CHOICE8) {
5625
- const count = op === LEX_NODE_CHOICE2 ? 2 : op === LEX_NODE_CHOICE4 ? 4 : 8;
5812
+ if (op === LEX_NODE_CHOICE) {
5813
+ const count = words[at++];
5814
+ const exclusive = words[at++];
5815
+ if (exclusive !== 0 && exclusive !== 1) throw new TypeError("table lexical tree choice has an invalid dispatch mode");
5626
5816
  const choiceFx = expected[words[at++]];
5817
+ if (!Number.isInteger(count) || count < 2 || count > stack.length) {
5818
+ throw new TypeError("table lexical tree choice has an invalid arm count");
5819
+ }
5627
5820
  if (choiceFx === void 0) throw new TypeError("table lexical tree choice has an invalid expected set");
5628
5821
  const armClasses = [];
5629
5822
  const armFx = [];
@@ -5636,7 +5829,7 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5636
5829
  armFx.push(fx);
5637
5830
  }
5638
5831
  const arms = Array.from({ length: count }, pop).reverse();
5639
- stack.push(choiceNode(arms, armClasses, armFx, choiceFx));
5832
+ stack.push(exclusive === 1 ? exclusiveChoiceNode(arms, armClasses, choiceFx) : choiceNode(arms, armClasses, armFx, choiceFx));
5640
5833
  continue;
5641
5834
  }
5642
5835
  if (op === LEX_NODE_NOT) {
@@ -5649,6 +5842,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
5649
5842
  stack.push(optionalNode(pop()));
5650
5843
  continue;
5651
5844
  }
5845
+ if (op === LEX_NODE_REPEAT) {
5846
+ const min = words[at++], max = words[at++];
5847
+ if (!Number.isInteger(min) || min < 0 || !Number.isInteger(max) || max >= 0 && max < min) {
5848
+ throw new TypeError("table lexical tree repeat has invalid bounds");
5849
+ }
5850
+ stack.push(repeatNode(pop(), min, max));
5851
+ continue;
5852
+ }
5652
5853
  throw new TypeError("table lexical tree has an unknown fixed body");
5653
5854
  }
5654
5855
  if (stack.length !== 1) throw new TypeError("table lexical tree does not resolve to one root body");
@@ -6914,6 +7115,111 @@ function classifyRuleMap(ruleMap) {
6914
7115
  };
6915
7116
  }
6916
7117
 
7118
+ // src/table/factor-choice.ts
7119
+ var DERIVED = /* @__PURE__ */ new Set(["_tag", "_meta", "_def", "_parseScalar", "_stickyRegex", "parse"]);
7120
+ function isCombinator(v) {
7121
+ return typeof v === "object" && v !== null && "_def" in v && "_meta" in v;
7122
+ }
7123
+ function sameComb(a, b, depth) {
7124
+ if (a === b) return true;
7125
+ if (depth > 32 || a._tag !== b._tag) return false;
7126
+ for (const k of Object.keys(a)) if (!DERIVED.has(k)) return false;
7127
+ for (const k of Object.keys(b)) if (!DERIVED.has(k)) return false;
7128
+ return sameFields(a._def, b._def, depth, void 0);
7129
+ }
7130
+ function sameValue(u, v, depth) {
7131
+ if (u === v) return true;
7132
+ if (isCombinator(u) && isCombinator(v)) return sameComb(u, v, depth + 1);
7133
+ if (Array.isArray(u) && Array.isArray(v)) return u.length === v.length && u.every((x, i) => sameValue(x, v[i], depth));
7134
+ if (typeof u === "object" && u !== null && typeof v === "object" && v !== null && Object.getPrototypeOf(u) === Object.prototype && Object.getPrototypeOf(v) === Object.prototype) {
7135
+ return sameFields(u, v, depth, void 0);
7136
+ }
7137
+ return false;
7138
+ }
7139
+ function sameFields(x, y, depth, skip) {
7140
+ const kx = Object.keys(x).filter((k) => k !== skip && x[k] !== void 0);
7141
+ const ky = Object.keys(y).filter((k) => k !== skip && y[k] !== void 0);
7142
+ if (kx.length !== ky.length) return false;
7143
+ for (const k of kx) {
7144
+ if (!(k in y)) return false;
7145
+ const u = x[k];
7146
+ const v = y[k];
7147
+ if (k === "fn" && typeof u === "function" && typeof v === "function" && u !== v) {
7148
+ if (typeof x.fnSrc !== "string" || x.fnSrc === "" || x.fnSrc !== y.fnSrc) return false;
7149
+ continue;
7150
+ }
7151
+ if (!sameValue(u, v, depth)) return false;
7152
+ }
7153
+ return true;
7154
+ }
7155
+ function rewrap(w, body) {
7156
+ const d = w._def;
7157
+ let out;
7158
+ if (d.tag === "leaf") {
7159
+ out = d.cstValue === "source" ? sourceLeaf(body, d.fn) : leaf(body, d.fn);
7160
+ if (d.fnSrc !== void 0) out._def.fnSrc = d.fnSrc;
7161
+ } else if (d.tag === "grammar") {
7162
+ out = d.clearTrivia === true ? noTrivia(body) : parser({ trivia: d.triviaParser ?? null }, body);
7163
+ } else return void 0;
7164
+ return sameFields(d, out._def, 0, "parser") ? out : void 0;
7165
+ }
7166
+ function unusedOf(seq) {
7167
+ return seq._def.tag === "sequence" && seq._def.valueUnused === true;
7168
+ }
7169
+ function never(c) {
7170
+ const t = c._def.tag;
7171
+ return t === "optional" || t === "many";
7172
+ }
7173
+ function factorSharedEnds(d) {
7174
+ const arms = d.parsers;
7175
+ if (arms.length < 2) return void 0;
7176
+ if (d.strategy.tag !== "firstMatch" && d.strategy.tag !== "sharedPrefix") return void 0;
7177
+ if (d.gates.some((g) => g !== null) || d.autoNot.some((a) => a !== null)) return void 0;
7178
+ const shapes = [];
7179
+ for (const arm of arms) {
7180
+ const wrappers = [];
7181
+ let c = arm;
7182
+ while ((c._def.tag === "leaf" || c._def.tag === "grammar") && wrappers.length < 4) {
7183
+ wrappers.push(c);
7184
+ c = c._def.parser;
7185
+ }
7186
+ if (c._def.tag !== "sequence" || c._def.parsers.length < 2) return void 0;
7187
+ shapes.push({ wrappers, terms: c._def.parsers, seq: c });
7188
+ }
7189
+ const first = shapes[0];
7190
+ const n = first.terms.length;
7191
+ for (const s of shapes) {
7192
+ if (s.wrappers.length !== first.wrappers.length || s.terms.length !== n) return void 0;
7193
+ if (unusedOf(s.seq) !== unusedOf(first.seq)) return void 0;
7194
+ for (let j = 0; j < s.wrappers.length; j++) {
7195
+ const a = first.wrappers[j]._def;
7196
+ const b = s.wrappers[j]._def;
7197
+ if (a.tag !== b.tag || !sameFields(a, b, 0, "parser")) return void 0;
7198
+ }
7199
+ }
7200
+ let at = -1;
7201
+ for (let i = 0; i < n; i++) {
7202
+ if (shapes.every((s) => sameComb(s.terms[i], first.terms[i], 0))) continue;
7203
+ if (at >= 0) return void 0;
7204
+ at = i;
7205
+ }
7206
+ if (at < 0) return void 0;
7207
+ for (let i = at + 1; i < n; i++) if (!never(first.terms[i])) return void 0;
7208
+ if (arms.some((a) => mayCommitFailure(a))) return void 0;
7209
+ const middle = choice(...shapes.map((s) => s.terms[at]));
7210
+ if (middle._def.tag === "choice" && middle._def.autoNot.some((a) => a !== null)) return void 0;
7211
+ const st = middle._def.tag === "choice" ? middle._def.strategy : void 0;
7212
+ if (st === void 0 || st.tag !== "firstMatch" && st.tag !== "sharedPrefix" && !(st.tag === "literalsLongestFirst" && st.sortedIndices.every((x, i) => x === i))) return void 0;
7213
+ let out = sequence(
7214
+ ...[...first.terms.slice(0, at), middle, ...first.terms.slice(at + 1)]
7215
+ );
7216
+ if (unusedOf(first.seq)) {
7217
+ out._def.valueUnused = true;
7218
+ }
7219
+ for (let j = first.wrappers.length - 1; j >= 0 && out !== void 0; j--) out = rewrap(first.wrappers[j], out);
7220
+ return out === void 0 ? void 0 : attempt(out);
7221
+ }
7222
+
6917
7223
  // src/table/ops.ts
6918
7224
  var OP_LIT = 1;
6919
7225
  var OP_RX = 2;
@@ -6957,6 +7263,7 @@ var OP_SCOPE_PLAIN = 41;
6957
7263
  var OP_LEX_BODY = 42;
6958
7264
  var OP_LEX_PROGRAM = 43;
6959
7265
  var OP_SOURCE_LEAF = 44;
7266
+ var OP_RGATE = 45;
6960
7267
  var OP_DISPATCH = 25;
6961
7268
  var OP_ROUTED = 26;
6962
7269
  var OP_NAMES = {
@@ -6976,6 +7283,7 @@ var OP_NAMES = {
6976
7283
  [OP_PEEK]: "PEEK",
6977
7284
  [OP_LEAF]: "LEAF",
6978
7285
  [OP_SOURCE_LEAF]: "SOURCE_LEAF",
7286
+ [OP_RGATE]: "RGATE",
6979
7287
  [OP_EMPTY]: "EMPTY",
6980
7288
  [OP_LIT_TRACK]: "LIT_TRACK",
6981
7289
  [OP_RX_TRACK]: "RX_TRACK",
@@ -7056,7 +7364,10 @@ function selectOptionalSuffixLexBody(ir) {
7056
7364
  const token2 = { strategy: "token", estimatedOps: 2, body };
7057
7365
  return token2.estimatedOps < character.estimatedOps ? token2 : character;
7058
7366
  }
7059
- function directTokenBodyParser(parser2, resolve) {
7367
+ function reinstallsRuleTrivia(reference, target) {
7368
+ return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
7369
+ }
7370
+ function directTokenBodyParser(parser2, resolve, scope) {
7060
7371
  const outer = parser2._def;
7061
7372
  if (outer.tag !== "token") return void 0;
7062
7373
  let body = outer.parser;
@@ -7066,12 +7377,13 @@ function directTokenBodyParser(parser2, resolve) {
7066
7377
  const wrapper = body._def;
7067
7378
  if (wrapper.tag === "grammar") {
7068
7379
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
7380
+ if (scope !== void 0) scope.cleared = true;
7069
7381
  body = wrapper.parser;
7070
7382
  continue;
7071
7383
  }
7072
7384
  if (wrapper.tag === "lazy") {
7073
7385
  const target = resolvedLazyTarget(body, resolve);
7074
- if (target === void 0) return void 0;
7386
+ if (target === void 0 || reinstallsRuleTrivia(body, target)) return void 0;
7075
7387
  body = target;
7076
7388
  continue;
7077
7389
  }
@@ -7243,7 +7555,7 @@ function directNot2TokenBody(parser2, resolve) {
7243
7555
  terminal
7244
7556
  };
7245
7557
  }
7246
- function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
7558
+ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared = false) {
7247
7559
  let current = parser2;
7248
7560
  const wrappers = /* @__PURE__ */ new Set();
7249
7561
  while (!wrappers.has(current)) {
@@ -7251,7 +7563,7 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
7251
7563
  const def = current._def;
7252
7564
  if (def.tag === "lazy") {
7253
7565
  const target = resolvedLazyTarget(current, resolve);
7254
- if (target === void 0) return void 0;
7566
+ if (target === void 0 || reinstallsRuleTrivia(current, target)) return void 0;
7255
7567
  current = target;
7256
7568
  continue;
7257
7569
  }
@@ -7269,30 +7581,33 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
7269
7581
  if (terminal !== void 0) return { kind: "terminal", terminal };
7270
7582
  const def = current._def;
7271
7583
  if (def.tag === "grammar") {
7584
+ if (def.triviaParser === void 0 && def.captureTrivia !== true && def.rootCapture !== "opaque" && def.constructionCaptureTriviaKinds === void 0) {
7585
+ return directFixedLexNode(def.parser, resolve, active, pureOnly, cleared || def.clearTrivia === true);
7586
+ }
7272
7587
  if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
7273
- return directFixedLexNode(def.parser, resolve, active, true);
7588
+ return directFixedLexNode(def.parser, resolve, active, true, cleared);
7274
7589
  }
7275
7590
  if (def.tag === "sequence") {
7276
7591
  if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
7277
- const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly));
7592
+ const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly, cleared));
7278
7593
  if (parts.some((part) => part === void 0)) return void 0;
7279
7594
  return { kind: "sequence", parts };
7280
7595
  }
7281
7596
  if (def.tag === "choice") {
7282
- if (def.parsers.length !== 2 && def.parsers.length !== 4 && def.parsers.length !== 8 || def.strategy.tag !== "firstMatch" || def.gates.some((gate2) => gate2 !== null) || def.autoNot.some((check) => check !== null)) return void 0;
7283
- const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly));
7597
+ if (def.parsers.length < 2 || def.strategy.tag !== "firstMatch" || def.gates.some((gate2) => gate2 !== null) || def.autoNot.some((check) => check !== null)) return void 0;
7598
+ const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly, cleared));
7284
7599
  if (arms.some((arm) => arm === void 0)) return void 0;
7285
- const final = classifyFinalChoice(def.parsers, resolve);
7286
7600
  return {
7287
7601
  kind: "choice",
7288
7602
  arms,
7289
- firstSets: final.firstSets,
7603
+ parsers: def.parsers,
7604
+ cleared,
7290
7605
  armExpected: def.parsers.map(deriveExpected),
7291
7606
  expected: def.parsers.flatMap(deriveExpected)
7292
7607
  };
7293
7608
  }
7294
7609
  if (def.tag === "not") {
7295
- const body = directFixedLexNode(def.parser, resolve, active, true);
7610
+ const body = directFixedLexNode(def.parser, resolve, active, true, cleared);
7296
7611
  return body === void 0 ? void 0 : {
7297
7612
  kind: "not",
7298
7613
  body,
@@ -7300,18 +7615,28 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
7300
7615
  };
7301
7616
  }
7302
7617
  if (def.tag === "optional") {
7303
- const body = directFixedLexNode(def.parser, resolve, active, pureOnly);
7618
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
7304
7619
  return body === void 0 ? void 0 : { kind: "optional", body };
7305
7620
  }
7621
+ if (def.tag === "many" || def.tag === "oneOrMore") {
7622
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
7623
+ return body === void 0 ? void 0 : {
7624
+ kind: "repeat",
7625
+ body,
7626
+ min: def.tag === "many" ? 0 : def.min,
7627
+ max: def.max ?? -1
7628
+ };
7629
+ }
7306
7630
  return void 0;
7307
7631
  } finally {
7308
7632
  active.delete(current);
7309
7633
  }
7310
7634
  }
7311
7635
  function directFixedTokenBody(parser2, resolve) {
7312
- const body = directTokenBodyParser(parser2, resolve);
7636
+ const scope = { cleared: false };
7637
+ const body = directTokenBodyParser(parser2, resolve, scope);
7313
7638
  if (body === void 0) return void 0;
7314
- const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set());
7639
+ const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope.cleared);
7315
7640
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
7316
7641
  }
7317
7642
  function directBalancedTokenBody(parser2, resolve) {
@@ -7558,13 +7883,16 @@ var Encoder = class {
7558
7883
  }
7559
7884
  case "choice": {
7560
7885
  for (const arm of node2.arms) if (!emitNode(arm)) return false;
7561
- const op = node2.arms.length === 2 ? LEX_NODE_CHOICE2 : node2.arms.length === 4 ? LEX_NODE_CHOICE4 : node2.arms.length === 8 ? LEX_NODE_CHOICE8 : -1;
7562
- if (op < 0) return false;
7563
- words.push(op, this.expected(node2.expected));
7886
+ const final = classifyFinalChoice(
7887
+ node2.parsers,
7888
+ this.refResolver(),
7889
+ node2.cleared ? void 0 : this.activeTrivia
7890
+ );
7891
+ const classes = final.firstSets.map((first, i) => final.nullable[i] ? -1 : this.charClass(first));
7892
+ const exclusive = final.exclusive && classes.every((cls) => cls >= 0);
7893
+ words.push(LEX_NODE_CHOICE, node2.arms.length, exclusive ? 1 : 0, this.expected(node2.expected));
7564
7894
  for (let i = 0; i < node2.arms.length; i++) {
7565
- const first = node2.firstSets[i];
7566
- words.push(first.kind === "ranges" ? this.charClass(first) : -1);
7567
- words.push(this.expected(node2.armExpected[i]));
7895
+ words.push(classes[i], this.expected(node2.armExpected[i]));
7568
7896
  }
7569
7897
  return true;
7570
7898
  }
@@ -7576,6 +7904,10 @@ var Encoder = class {
7576
7904
  if (!emitNode(node2.body)) return false;
7577
7905
  words.push(LEX_NODE_OPTIONAL);
7578
7906
  return true;
7907
+ case "repeat":
7908
+ if (!emitNode(node2.body)) return false;
7909
+ words.push(LEX_NODE_REPEAT, node2.min, node2.max);
7910
+ return true;
7579
7911
  }
7580
7912
  };
7581
7913
  if (!emitNode(body.root)) return void 0;
@@ -8081,6 +8413,50 @@ var Encoder = class {
8081
8413
  if (!hasOwnTriviaBoundary(target)) return ip;
8082
8414
  return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
8083
8415
  }
8416
+ /**
8417
+ * The `OP_RGATE` operands of a choice arm that opens with `routed()`, or
8418
+ * `undefined`. Through `node()`/scope wrappers and first sequence terms, the
8419
+ * arm's next term after the routed token is found; the gate is that term's
8420
+ * first characters, with the trivia in force at the boundary before it, so
8421
+ * the arm is entered only where it can get past the token. The term must be
8422
+ * unable to match empty or to commit, so a miss is exactly that term failing
8423
+ * at the token's end with its own set.
8424
+ */
8425
+ routedArmGate(arm) {
8426
+ const walk = (p, trivia2, depth) => {
8427
+ if (depth > 16) return void 0;
8428
+ const d = p._def;
8429
+ switch (d.tag) {
8430
+ case "routed":
8431
+ return "end";
8432
+ case "node":
8433
+ return walk(d.parser, trivia2, depth + 1);
8434
+ case "grammar":
8435
+ return walk(d.parser, d.clearTrivia === true ? void 0 : d.triviaParser ?? trivia2, depth + 1);
8436
+ case "sequence": {
8437
+ const head = d.parsers[0];
8438
+ if (head === void 0) return void 0;
8439
+ const r = walk(head, trivia2, depth + 1);
8440
+ if (r !== "end") return r;
8441
+ const next2 = d.parsers[1];
8442
+ return next2 === void 0 ? "end" : { next: next2, boundary: trivia2 };
8443
+ }
8444
+ default:
8445
+ return void 0;
8446
+ }
8447
+ };
8448
+ const follow = walk(arm, this.activeTrivia, 0);
8449
+ if (follow === void 0 || follow === "end") return void 0;
8450
+ const rr = this.refResolver();
8451
+ const { next, boundary } = follow;
8452
+ if (matchesEmpty(next, /* @__PURE__ */ new Set(), rr) || mayCommitFailure(next, rr, this.commitFailureMemo)) return void 0;
8453
+ const nextTag = next._def.tag;
8454
+ if (nextTag !== "literal" && nextTag !== "regex" && nextTag !== "keywords" && nextTag !== "label") return void 0;
8455
+ const first = firstSetOf(next, /* @__PURE__ */ new Set(), rr, boundary);
8456
+ const cls = this.charClass(boundary === void 0 ? first : union(first, firstSetOf(boundary, /* @__PURE__ */ new Set(), rr)));
8457
+ if (cls < 0) return void 0;
8458
+ return { cls, fx: this.expected(deriveExpected(next)) };
8459
+ }
8084
8460
  node(p) {
8085
8461
  const lazyRef = p._def.tag === "lazy";
8086
8462
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -8205,6 +8581,10 @@ var Encoder = class {
8205
8581
  return head;
8206
8582
  }
8207
8583
  case "choice": {
8584
+ if (this.plan === void 0) {
8585
+ const factored = factorSharedEnds(d);
8586
+ if (factored !== void 0) return this.node(factored).ip;
8587
+ }
8208
8588
  if (d.strategy.tag === "greedyClassify") {
8209
8589
  const superIndex = d.strategy.superIndex;
8210
8590
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -8228,9 +8608,12 @@ var Encoder = class {
8228
8608
  const kids = arms.map((c, k) => {
8229
8609
  const src = order[k];
8230
8610
  const checks = d.autoNot[src];
8231
- const inner = this.node(c).ip;
8232
- const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
8233
8611
  const gate2 = d.gates[src];
8612
+ const plain = (checks === null || checks === void 0 || checks.length === 0) && (gate2 === null || gate2 === void 0);
8613
+ const routedGate = plain ? this.routedArmGate(c) : void 0;
8614
+ const body = this.node(c).ip;
8615
+ const inner = routedGate === void 0 ? body : this.emit(OP_RGATE, routedGate.cls, body, routedGate.fx);
8616
+ const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
8234
8617
  const gated = gate2 === null || gate2 === void 0 ? ip : this.emit(OP_ARMGATE, this.fn(gate2, d.gateSrcs?.[src] ?? null), ip, this.expected(deriveExpected(c)));
8235
8618
  return this.covWrap(gated, armCovIds?.[src], 1);
8236
8619
  });
@@ -8554,6 +8937,7 @@ var Encoder = class {
8554
8937
  const slots = (ip) => {
8555
8938
  switch (this.code[ip]) {
8556
8939
  case OP_GATE:
8940
+ case OP_RGATE:
8557
8941
  return [ip + 2];
8558
8942
  case OP_RULE:
8559
8943
  case OP_OPT:
@@ -9784,6 +10168,7 @@ function childSlots(code, ip, out) {
9784
10168
  case OP_LEAF:
9785
10169
  case OP_SOURCE_LEAF:
9786
10170
  case OP_ARMGATE:
10171
+ case OP_RGATE:
9787
10172
  out.push(code[ip + 2]);
9788
10173
  return true;
9789
10174
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -9867,6 +10252,42 @@ function reachableSites(code, roots) {
9867
10252
  }
9868
10253
  return seen;
9869
10254
  }
10255
+ function passCollapse(code, ip, hostCst) {
10256
+ const flags = code[ip + 3];
10257
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
10258
+ if (flags !== 32 && flags !== 34) return false;
10259
+ let at = code[ip + 2];
10260
+ for (let n = 0; n < 8; n++) {
10261
+ const op = code[at];
10262
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
10263
+ else if (op === OP_RULE) at = code[at + 1];
10264
+ else break;
10265
+ }
10266
+ return code[at] === OP_NODE;
10267
+ }
10268
+ function gatedPassCollapse(code, ip, hostCst) {
10269
+ const flags = code[ip + 3];
10270
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
10271
+ if (flags !== 32 && flags !== 34) return void 0;
10272
+ const seq = code[ip + 2];
10273
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
10274
+ const n = code[seq + 1];
10275
+ if (n < 2) return void 0;
10276
+ const leads = [];
10277
+ const lits = [];
10278
+ for (let i = 0; i < n - 1; i++) {
10279
+ const t = code[seq + 2 + i];
10280
+ if (code[t] !== OP_OPT && code[t] !== OP_NOT) return void 0;
10281
+ const g = code[t + 1];
10282
+ if (code[g] === OP_GATE) leads.push(g);
10283
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
10284
+ else return void 0;
10285
+ }
10286
+ const last = code[seq + 2 + n - 1];
10287
+ let at = last;
10288
+ for (let k = 0; k < 8 && (code[at] === OP_GATE || code[at] === OP_RULE); k++) at = code[at] === OP_RULE ? code[at + 1] : code[at + 2];
10289
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
10290
+ }
9870
10291
  function transfer(code, ip, at, hostCst) {
9871
10292
  const op = code[ip];
9872
10293
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -9878,14 +10299,18 @@ function transfer(code, ip, at, hostCst) {
9878
10299
  }
9879
10300
  if (op === OP_NODE || op === OP_NODE_TRACK) {
9880
10301
  const flags = code[ip + 3];
10302
+ if (passCollapse(code, ip, hostCst)) return at;
10303
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
9881
10304
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
9882
10305
  if (directChildren) {
9883
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
10306
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
10307
+ return gated ? meet(at, framed2) : framed2;
9884
10308
  }
9885
10309
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
9886
10310
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
9887
10311
  if (at.buf && raw === at.raw && cap === at.cap) return at;
9888
- return { tri: at.tri, buf: true, raw, cap };
10312
+ const framed = { tri: at.tri, buf: true, raw, cap };
10313
+ return gated ? meet(at, framed) : framed;
9889
10314
  }
9890
10315
  if (op === OP_TOKEN) {
9891
10316
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -9923,6 +10348,40 @@ function computeSiteLabels(code, roots, hostCst) {
9923
10348
  }
9924
10349
  return { at: (ip) => labels.get(ip) ?? TOP };
9925
10350
  }
10351
+ function scopeIsIdentity(code, ip, at) {
10352
+ const op = code[ip];
10353
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
10354
+ const ki = code[ip + 1];
10355
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
10356
+ }
10357
+ function scanHandoffNeeded(code, ip, labels) {
10358
+ const seen = /* @__PURE__ */ new Set();
10359
+ const stack = [ip];
10360
+ const kids = [];
10361
+ while (stack.length > 0) {
10362
+ const at = stack.pop();
10363
+ if (seen.has(at)) continue;
10364
+ seen.add(at);
10365
+ const l = labels.at(at);
10366
+ if (l.tri === TRI_UNKNOWN) return true;
10367
+ const op = code[at];
10368
+ if (op === OP_SCAN) return true;
10369
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue;
10370
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1] >= 0 && l.tri === code[at + 1] && (op === OP_SCOPE_PLAIN || code[at + 3] === 0))) continue;
10371
+ kids.length = 0;
10372
+ if (!childSlots(code, at, kids)) return true;
10373
+ for (const c of kids) stack.push(c);
10374
+ }
10375
+ return false;
10376
+ }
10377
+ function triviaLeadRanges(tri, trivia2) {
10378
+ if (tri === TRI_NONE) return [];
10379
+ if (tri < 0) return void 0;
10380
+ const fs = trivia2[tri]?._meta.firstSet;
10381
+ if (fs === void 0) return void 0;
10382
+ if (fs.kind === "empty") return [];
10383
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
10384
+ }
9926
10385
 
9927
10386
  // src/table/scalar-terminal.ts
9928
10387
  function makeScalarRecognizer(op, spec) {
@@ -9960,6 +10419,12 @@ function scalarTerminalNotChild(code, ip) {
9960
10419
  const op = code[child];
9961
10420
  return op === OP_RX || op === OP_LIT ? child : -1;
9962
10421
  }
10422
+ function scalarTerminalPeekChild(code, ip) {
10423
+ if (code[ip] !== OP_PEEK) return -1;
10424
+ const child = code[ip + 1];
10425
+ const op = code[child];
10426
+ return op === OP_RX || op === OP_LIT ? child : -1;
10427
+ }
9963
10428
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
9964
10429
  const seen = /* @__PURE__ */ new Set();
9965
10430
  let at = ip;
@@ -10137,6 +10602,59 @@ function leadingTriviaFieldAt(code, k, ip) {
10137
10602
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
10138
10603
  }
10139
10604
 
10605
+ // src/table/hold-gap.ts
10606
+ var WRAPPERS = /* @__PURE__ */ new Set([
10607
+ OP_NODE,
10608
+ OP_XFORM,
10609
+ OP_LEAF,
10610
+ OP_SOURCE_LEAF,
10611
+ OP_TOKEN,
10612
+ OP_SCOPE,
10613
+ OP_SCOPE_CAP,
10614
+ OP_SCOPE_PLAIN,
10615
+ OP_FIELD,
10616
+ OP_LABEL,
10617
+ OP_EXPECT,
10618
+ OP_WITHCTX,
10619
+ OP_RULE,
10620
+ OP_ATTEMPT,
10621
+ OP_COV
10622
+ ]);
10623
+ function rowNullable(code, k, ip, memo) {
10624
+ const hit = memo.get(ip);
10625
+ if (hit !== void 0) return hit;
10626
+ memo.set(ip, true);
10627
+ const op = code[ip];
10628
+ const kids = [];
10629
+ let out = true;
10630
+ if (op === OP_GATE) out = false;
10631
+ else if (op === OP_LIT || op === OP_LIT_CI) out = k[code[ip + 1]].length === 0;
10632
+ else if (op === OP_RX) {
10633
+ const re = k[code[ip + 1]];
10634
+ out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
10635
+ } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
10636
+ childSlots(code, ip, kids);
10637
+ out = kids.every((c) => rowNullable(code, k, c, memo));
10638
+ } else if (op === OP_CHOICE) {
10639
+ childSlots(code, ip, kids);
10640
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
10641
+ } else if (op === OP_REP || op === OP_REPV) {
10642
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
10643
+ } else if (WRAPPERS.has(op)) {
10644
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
10645
+ }
10646
+ memo.set(ip, out);
10647
+ return out;
10648
+ }
10649
+ function holdsGap(code, k, base, n, i, memo) {
10650
+ if (i < 1 || i + 1 >= n) return false;
10651
+ const term = code[base + i];
10652
+ if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
10653
+ const next = code[base + i + 1];
10654
+ if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
10655
+ return !rowNullable(code, k, next, memo);
10656
+ }
10657
+
10140
10658
  // src/table/emit-assembly.ts
10141
10659
  var Unemittable = class extends Error {
10142
10660
  construct;
@@ -10217,7 +10735,10 @@ var EMITTED_PARAMS = [
10217
10735
  "triviaFieldCapture",
10218
10736
  // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
10219
10737
  // factories ignore it.
10220
- "skipDeferredTrivia"
10738
+ "skipDeferredTrivia",
10739
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
10740
+ // ignore it.
10741
+ "collapseEmpty"
10221
10742
  ];
10222
10743
  var RUNTIME_PRELUDE = `
10223
10744
  let _pfScan=null
@@ -10414,6 +10935,24 @@ ${fast}
10414
10935
  ${scanned}
10415
10936
  }`;
10416
10937
  }
10938
+ function emitHoldTerm(callee, dst, t, l, skip) {
10939
+ const fast = `const ${t}v=${callee}(input,cur,ctx)
10940
+ if(${t}v===FAIL)return FAIL
10941
+ ${dst}=${t}v
10942
+ cur=EC.e`;
10943
+ if (l.tri === TRI_NONE) return fast;
10944
+ const held = `const ${t}s=${skip}(input,cur,ctx)
10945
+ const ${t}v=${callee}(input,${t}s,ctx)
10946
+ if(${t}v===FAIL)return FAIL
10947
+ ${dst}=${t}v
10948
+ cur=${t}s`;
10949
+ if (l.tri !== TRI_UNKNOWN) return held;
10950
+ return `if(ctx.trivia===undefined){
10951
+ ${fast}
10952
+ }else{
10953
+ ${held}
10954
+ }`;
10955
+ }
10417
10956
  function leadSkip(hasTrivia, leadTrivia, skip) {
10418
10957
  if (hasTrivia === "false") return "{}";
10419
10958
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -10455,6 +10994,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false, se
10455
10994
  const reachable = [...reachableSites(code, roots)];
10456
10995
  const labels = computeSiteLabels(code, roots, hostCst);
10457
10996
  const scalarSpecs = /* @__PURE__ */ new Set();
10997
+ const nullable2 = /* @__PURE__ */ new Map();
10458
10998
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
10459
10999
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
10460
11000
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -10779,9 +11319,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10779
11319
  const op = code[ip];
10780
11320
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
10781
11321
  if (op === OP_RULE) return code[ip + 1];
10782
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
10783
- return code[ip + 2];
10784
- }
11322
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
10785
11323
  return void 0;
10786
11324
  }
10787
11325
  function lower(ip, fname) {
@@ -10903,6 +11441,22 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10903
11441
  return `${head}
10904
11442
  if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10905
11443
  return ${child}(input,pos,ctx)
11444
+ }`;
11445
+ }
11446
+ case OP_RGATE: {
11447
+ const child = link(code[ip + 2]);
11448
+ if (cfg.tolerant || cfg.probe) return `${head}
11449
+ return ${child}(input,pos,ctx)
11450
+ }`;
11451
+ const resolved = t.cc[code[ip + 1]];
11452
+ const ci = classes.push([resolved]) - 1;
11453
+ classPlan.push([code[ip + 1]]);
11454
+ const cls = hoist("cl", `CLS[${ci}][0]`);
11455
+ const xf = fxRef(code[ip + 3]);
11456
+ return `${head}
11457
+ const it=ctx._routed
11458
+ if(it!==undefined&&it.span.start===pos&&!classHas(${cls},lead(input,it.span.end))){ctx._fe=it.span.end;ctx._fx=${xf};return FAIL}
11459
+ return ${child}(input,pos,ctx)
10906
11460
  }`;
10907
11461
  }
10908
11462
  case OP_ARMGATE: {
@@ -11177,23 +11731,33 @@ return FAIL
11177
11731
  const p = tmp();
11178
11732
  return `${head}
11179
11733
  ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
11180
- const v=${child}(input,pos,ctx)
11734
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
11181
11735
  ${emitRollback(p, L.buf, L.raw, sinks)}
11182
- if(v===FAIL){EC.e=pos;return null}
11736
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){EC.e=pos;return null}
11183
11737
  ctx._fe=pos
11184
11738
  ctx._fx=${xf}
11185
11739
  return FAIL
11186
11740
  }`;
11187
11741
  }
11188
11742
  case OP_PEEK: {
11743
+ const scalarChild = scalarTerminalPeekChild(code, ip);
11744
+ if (scalarChild >= 0) {
11745
+ const recognize = recognizerRef(code[scalarChild + 1]);
11746
+ const xf2 = fxRef(code[ip + 2]);
11747
+ return `${head}
11748
+ if(${recognize}(input,pos)<0){ctx._fe=pos;ctx._fx=${xf2};return FAIL}
11749
+ EC.e=pos
11750
+ return null
11751
+ }`;
11752
+ }
11189
11753
  const child = link(code[ip + 1]);
11190
11754
  const xf = fxRef(code[ip + 2]);
11191
11755
  const p = tmp();
11192
11756
  return `${head}
11193
11757
  ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
11194
- const v=${child}(input,pos,ctx)
11758
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
11195
11759
  ${emitRollback(p, L.buf, L.raw, sinks)}
11196
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11760
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11197
11761
  EC.e=pos
11198
11762
  return null
11199
11763
  }`;
@@ -11264,7 +11828,7 @@ return v
11264
11828
  );
11265
11829
  } else {
11266
11830
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
11267
- parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
11831
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
11268
11832
  }
11269
11833
  names.push(vn);
11270
11834
  }
@@ -11747,6 +12311,26 @@ return nd
11747
12311
  const trailingTrivia = (flags & 128) !== 0;
11748
12312
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
11749
12313
  const leanFlags = flags & ~128;
12314
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
12315
+ return `${head}
12316
+ const v=${child}(input,pos,ctx)
12317
+ if(v!==undefined)return v
12318
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
12319
+ }`;
12320
+ }
12321
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
12322
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t.trivia);
12323
+ const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
12324
+ if(!(${[
12325
+ ...gated.leads.map((g) => `!(${gateMissTest(g)})`),
12326
+ ...gated.lits.map((i) => `gc===${k[i].codePointAt(0)}`),
12327
+ ...triviaLead.map((r) => r.lo === r.hi ? `gc===${r.lo}` : `(gc>=${r.lo}&&gc<=${r.hi})`)
12328
+ ].join("||") || "false"})){
12329
+ const gv=${link(gated.last)}(input,pos,ctx)
12330
+ if(gv!==undefined)return gv
12331
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
12332
+ }
12333
+ ` : "";
11750
12334
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
11751
12335
  const fields = flags === 18;
11752
12336
  const collapseChildren = flags === 34;
@@ -11781,7 +12365,7 @@ sCh.push(nd)
11781
12365
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
11782
12366
  }`;
11783
12367
  return `${head}
11784
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12368
+ ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11785
12369
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
11786
12370
  const flat=[]
11787
12371
  ctx._cstBuf=undefined
@@ -11856,7 +12440,7 @@ const hostKids=kids
11856
12440
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
11857
12441
  const tlog=buf.tl??EMPTY_TLOG`;
11858
12442
  return `${head}
11859
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12443
+ ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11860
12444
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
11861
12445
  ${openCapture}
11862
12446
  ctx.captureTrivia=${captureWide}
@@ -11926,9 +12510,15 @@ ext:[${externals.join(",")}],
11926
12510
  bind:function(xs,ps){_xScan=xs
11927
12511
  ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
11928
12512
  scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
12513
+ const scannerFor = (ip) => {
12514
+ const ki = labels.at(ip).tri;
12515
+ if (ki === TRI_UNKNOWN) return "_pfScan";
12516
+ if (ki === TRI_NONE) return "null";
12517
+ return swapLegal && !triviaLabelled[ki] && t.triviaScan[ki] != null ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
12518
+ };
11929
12519
  const externalDefs = select === void 0 ? "" : `let _xScan
11930
12520
  ${externals.map((ip) => `let _xp${ip}
11931
- function _px${ip}(input,pos,ctx){const o=_xScan(_pfScan);const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
12521
+ function _px${ip}(input,pos,ctx){const o=_xScan(${scannerFor(ip)});const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
11932
12522
  `;
11933
12523
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
11934
12524
  ${prelude.join("\n")}
@@ -12465,37 +13055,120 @@ function clearOf(ranges, input, from, to) {
12465
13055
  return true;
12466
13056
  }
12467
13057
 
12468
- // src/table/run-support.ts
12469
- function lineCol(ctx, offset) {
12470
- const starts = ctx._lineStarts ?? [0];
12471
- let lo = 0, hi = starts.length - 1;
12472
- while (lo < hi) {
12473
- const mid = lo + hi + 1 >> 1;
12474
- if (starts[mid] <= offset) lo = mid;
12475
- else hi = mid - 1;
13058
+ // src/table/fail-clean.ts
13059
+ function passChild(code, ip) {
13060
+ switch (code[ip]) {
13061
+ case OP_RULE:
13062
+ case OP_LABEL:
13063
+ case OP_COV:
13064
+ case OP_TOKEN:
13065
+ return code[ip + 1];
13066
+ case OP_GATE:
13067
+ case OP_NODE:
13068
+ case OP_NODE_TRACK:
13069
+ case OP_XFORM:
13070
+ case OP_FIELD:
13071
+ case OP_SCOPE:
13072
+ case OP_SCOPE_CAP:
13073
+ case OP_SCOPE_PLAIN:
13074
+ case OP_WITHCTX:
13075
+ case OP_LEAF:
13076
+ case OP_SOURCE_LEAF:
13077
+ return code[ip + 2];
13078
+ default:
13079
+ return -1;
12476
13080
  }
12477
- return [lo + 1, offset - starts[lo] + 1];
12478
- }
12479
- function spanLines(ctx, start, end) {
12480
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
12481
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
12482
13081
  }
12483
- function rawEntry(v, input, s, e) {
12484
- if (typeof v === "object" && v !== null) {
12485
- const tg = v._tag;
12486
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
12487
- }
12488
- return {
12489
- _tag: "leaf",
12490
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
12491
- span: { start: s, end: e }
13082
+ function seqCount(code, ip) {
13083
+ const op = code[ip];
13084
+ return op === OP_SEQ || op === OP_SEQV ? ip + 1 : op === OP_SEQX ? ip + 2 : -1;
13085
+ }
13086
+ function failCleanAnalysis(code) {
13087
+ const cleanAt = new Uint8Array(code.length);
13088
+ const neverAt = new Uint8Array(code.length);
13089
+ const neverFails = (ip) => {
13090
+ const hit = neverAt[ip];
13091
+ if (hit !== 0) return hit === 1;
13092
+ neverAt[ip] = 3;
13093
+ let out = false;
13094
+ const op = code[ip];
13095
+ if (op === OP_OPT || op === OP_EMPTY || op === OP_EXPECT) out = true;
13096
+ else if (op === OP_REP || op === OP_REPV) out = code[ip + 2] === 0;
13097
+ else {
13098
+ const at = seqCount(code, ip);
13099
+ if (at >= 0) {
13100
+ out = true;
13101
+ for (let i = 1, n = code[at]; out && i <= n; i++) out = neverFails(code[at + i]);
13102
+ } else if (op !== OP_GATE) {
13103
+ const c = passChild(code, ip);
13104
+ out = c >= 0 && neverFails(c);
13105
+ }
13106
+ }
13107
+ neverAt[ip] = out ? 1 : 2;
13108
+ return out;
12492
13109
  };
12493
- }
12494
- function lead(input, pos) {
12495
- if (pos >= input.length) return -1;
12496
- const c = input.charCodeAt(pos);
12497
- if (c < 55296 || c > 56319) return c;
12498
- return input.codePointAt(pos) ?? c;
13110
+ const clean = (ip) => {
13111
+ const hit = cleanAt[ip];
13112
+ if (hit !== 0) return hit === 1;
13113
+ cleanAt[ip] = 3;
13114
+ let out = false;
13115
+ switch (code[ip]) {
13116
+ // A terminal pushes its leaf only on a match; NOT/PEEK/ATTEMPT restore
13117
+ // their own mark; OPT, EMPTY and EXPECT do not fail uncommitted.
13118
+ case OP_LIT:
13119
+ case OP_RX:
13120
+ case OP_LIT_TRACK:
13121
+ case OP_RX_TRACK:
13122
+ case OP_LIT_CI:
13123
+ case OP_LIT_CI_TRACK:
13124
+ case OP_GUARD:
13125
+ case OP_NOT:
13126
+ case OP_PEEK:
13127
+ case OP_ATTEMPT:
13128
+ case OP_EMPTY:
13129
+ case OP_OPT:
13130
+ case OP_EXPECT:
13131
+ out = true;
13132
+ break;
13133
+ // Min 0 does not fail uncommitted; min 1 fails only with no item kept, and
13134
+ // restores the failed item itself.
13135
+ case OP_REP:
13136
+ case OP_REPV:
13137
+ out = code[ip + 2] <= 1;
13138
+ break;
13139
+ // Only the first term may fail: a later one fails after the terms before it
13140
+ // wrote, and after the trivia scanned in front of it.
13141
+ case OP_SEQ:
13142
+ case OP_SEQV:
13143
+ case OP_SEQX: {
13144
+ const at = seqCount(code, ip);
13145
+ const n = code[at];
13146
+ out = n > 0 && clean(code[at + 1]);
13147
+ for (let i = 2; out && i <= n; i++) out = neverFails(code[at + i]);
13148
+ break;
13149
+ }
13150
+ case OP_CHOICE: {
13151
+ out = true;
13152
+ for (let i = 0, n = code[ip + 2]; out && i < n; i++) out = clean(code[ip + 4 + i]);
13153
+ break;
13154
+ }
13155
+ case OP_ROUTED:
13156
+ out = code[ip + 1] < 0 || clean(code[ip + 1]);
13157
+ break;
13158
+ // An arm's failure and the fallback's are committed; only the selector's is
13159
+ // not, and without a fallback an unknown key fails after the selector wrote.
13160
+ case OP_DISPATCH:
13161
+ out = code[ip + 3] >= 0 && clean(code[ip + 1]);
13162
+ break;
13163
+ default: {
13164
+ const c = passChild(code, ip);
13165
+ out = c >= 0 && clean(c);
13166
+ }
13167
+ }
13168
+ cleanAt[ip] = out ? 1 : 2;
13169
+ return out;
13170
+ };
13171
+ return clean;
12499
13172
  }
12500
13173
 
12501
13174
  // src/cst/host-mode.ts
@@ -12660,6 +13333,7 @@ function assemble(t, prog, cfg) {
12660
13333
  const swapLegal = !cfg.trackLines;
12661
13334
  const hostCst = cfg.hostCst;
12662
13335
  const REC2 = prog.rec === 1 && cfg.tolerant;
13336
+ const PROBE = cfg.probe;
12663
13337
  const sentinels = /* @__PURE__ */ new Map();
12664
13338
  function sentinelFor(cls) {
12665
13339
  if (cls < 0) return void 0;
@@ -12705,6 +13379,8 @@ function assemble(t, prog, cfg) {
12705
13379
  }
12706
13380
  const memo = /* @__PURE__ */ new Map();
12707
13381
  const reached = /* @__PURE__ */ new Set();
13382
+ const NULLABLE = /* @__PURE__ */ new Map();
13383
+ const CLEAN = REC2 ? () => false : failCleanAnalysis(code);
12708
13384
  function pushLeaf(ctx, value, s, e) {
12709
13385
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
12710
13386
  pushCstLeaf(ctx, lf);
@@ -12903,6 +13579,22 @@ function assemble(t, prog, cfg) {
12903
13579
  return node2;
12904
13580
  };
12905
13581
  }
13582
+ function passCollapseNode(child, build, readsRaw) {
13583
+ return (input, pos, ctx) => {
13584
+ const v = child(input, pos, ctx);
13585
+ if (v !== void 0) return v;
13586
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13587
+ };
13588
+ }
13589
+ function gatedPassCollapseNode(blockers, last, classic, build, readsRaw) {
13590
+ return (input, pos, ctx) => {
13591
+ const c = lead(input, pos);
13592
+ for (let i = 0; i < blockers.length; i++) if (classHas2(blockers[i], c)) return classic(input, pos, ctx);
13593
+ const v = last(input, pos, ctx);
13594
+ if (v !== void 0) return v;
13595
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13596
+ };
13597
+ }
12906
13598
  function plainProjectNode(child, projection, type) {
12907
13599
  return (input, pos, ctx) => {
12908
13600
  const sCh = ctx._cstChildren;
@@ -13273,21 +13965,27 @@ function assemble(t, prog, cfg) {
13273
13965
  }
13274
13966
  function dispatchBranch(child, usesRouted) {
13275
13967
  if (!usesRouted) {
13276
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
13277
- const mark = saveTriviaMark(ctx);
13968
+ return (input, _pos, selEnd, key, ctx) => {
13969
+ const need = markCst(ctx);
13970
+ const mRaw = MRAW;
13971
+ const mTl = MTL;
13972
+ const mLv = MLV;
13973
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13974
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13975
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13976
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
13278
13977
  const v = child(input, selEnd, ctx);
13279
13978
  if (v === FAIL) {
13280
- rollbackTrivia(ctx, mark);
13979
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13281
13980
  ctx._fc = true;
13282
13981
  return FAIL;
13283
13982
  }
13284
13983
  return [key, v];
13285
13984
  };
13286
13985
  }
13287
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13986
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
13288
13987
  const savedRouted = ctx._routed;
13289
- rollbackTrivia(ctx, selectorMark);
13290
- const mark = saveTriviaMark(ctx);
13988
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13291
13989
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
13292
13990
  let v;
13293
13991
  try {
@@ -13296,7 +13994,7 @@ function assemble(t, prog, cfg) {
13296
13994
  ctx._routed = savedRouted;
13297
13995
  }
13298
13996
  if (v === FAIL) {
13299
- rollbackTrivia(ctx, mark);
13997
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13300
13998
  ctx._fc = true;
13301
13999
  return FAIL;
13302
14000
  }
@@ -13304,12 +14002,12 @@ function assemble(t, prog, cfg) {
13304
14002
  };
13305
14003
  }
13306
14004
  function dispatchArmBlock(start, a0, a1, a2, a3, next) {
13307
- return (arm, input, pos, selEnd, key, selectorMark, ctx) => {
13308
- if (arm === start) return a0(input, pos, selEnd, key, selectorMark, ctx);
13309
- if (arm === start + 1) return a1(input, pos, selEnd, key, selectorMark, ctx);
13310
- if (arm === start + 2) return a2(input, pos, selEnd, key, selectorMark, ctx);
13311
- if (arm === start + 3) return a3(input, pos, selEnd, key, selectorMark, ctx);
13312
- return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, selectorMark, ctx);
14005
+ return (arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
14006
+ if (arm === start) return a0(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14007
+ if (arm === start + 1) return a1(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14008
+ if (arm === start + 2) return a2(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14009
+ if (arm === start + 3) return a3(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14010
+ return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13313
14011
  };
13314
14012
  }
13315
14013
  function trackLinesInto(ctx, input, end) {
@@ -13328,7 +14026,7 @@ function assemble(t, prog, cfg) {
13328
14026
  if (flight !== void 0) return flight.fwd;
13329
14027
  const selected = HYBRID?.byIp[ip];
13330
14028
  if (selected !== void 0) {
13331
- const piece2 = hybridPiece(selected);
14029
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
13332
14030
  memo.set(ip, piece2);
13333
14031
  reached.add(ip);
13334
14032
  return piece2;
@@ -13339,14 +14037,55 @@ function assemble(t, prog, cfg) {
13339
14037
  target = p;
13340
14038
  } };
13341
14039
  inFlight.set(ip, holder);
13342
- const op = code[ip];
13343
- const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : countedPiece(lower(ip), ip);
14040
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
13344
14041
  inFlight.delete(ip);
13345
14042
  holder.set(piece);
13346
14043
  memo.set(ip, piece);
13347
14044
  reached.add(ip);
13348
14045
  return piece;
13349
14046
  }
14047
+ let FIRST_DECIDED;
14048
+ let NODE_BODY;
14049
+ const DECIDED = (_input, pos) => {
14050
+ EC.e = pos;
14051
+ return null;
14052
+ };
14053
+ function lookaheadLedNode(ip) {
14054
+ const op = code[ip];
14055
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC2 || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
14056
+ if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
14057
+ const body = code[ip + 2];
14058
+ const bop = code[body];
14059
+ if (bop !== OP_SEQ && bop !== OP_SEQV && bop !== OP_SEQX) return void 0;
14060
+ const base = bop === OP_SEQX ? body + 3 : body + 2;
14061
+ if (code[bop === OP_SEQX ? body + 2 : body + 1] < 2) return void 0;
14062
+ const first = code[base];
14063
+ const negative = code[first] === OP_NOT;
14064
+ const terminal = negative ? scalarTerminalNotChild(code, first) : code[first] === OP_PEEK ? scalarTerminalPeekChild(code, first) : -1;
14065
+ if (terminal < 0) return void 0;
14066
+ const recognize = scalarFor(terminal);
14067
+ const xf = fx[code[first + 2]];
14068
+ FIRST_DECIDED = DECIDED;
14069
+ NODE_BODY = lower(body);
14070
+ const node2 = lower(ip);
14071
+ NODE_BODY = void 0;
14072
+ return negative ? (input, pos, ctx) => {
14073
+ if (recognize(input, pos) >= 0) {
14074
+ ctx._fe = pos;
14075
+ ctx._fx = xf;
14076
+ EC.e = pos;
14077
+ return FAIL;
14078
+ }
14079
+ return node2(input, pos, ctx);
14080
+ } : (input, pos, ctx) => {
14081
+ if (recognize(input, pos) < 0) {
14082
+ ctx._fe = pos;
14083
+ ctx._fx = xf;
14084
+ return FAIL;
14085
+ }
14086
+ return node2(input, pos, ctx);
14087
+ };
14088
+ }
13350
14089
  function lower(ip) {
13351
14090
  const op = code[ip];
13352
14091
  switch (op) {
@@ -13891,8 +14630,10 @@ function assemble(t, prog, cfg) {
13891
14630
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13892
14631
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13893
14632
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14633
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13894
14634
  const v = child(input, pos, ctx);
13895
14635
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14636
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13896
14637
  if (v === FAIL) {
13897
14638
  EC.e = pos;
13898
14639
  return null;
@@ -13903,6 +14644,20 @@ function assemble(t, prog, cfg) {
13903
14644
  };
13904
14645
  }
13905
14646
  case OP_PEEK: {
14647
+ const scalarChild = scalarTerminalPeekChild(code, ip);
14648
+ if (scalarChild >= 0) {
14649
+ const recognize = scalarFor(scalarChild);
14650
+ const xf2 = fx[code[ip + 2]];
14651
+ return (input, pos, ctx) => {
14652
+ if (recognize(input, pos) < 0) {
14653
+ ctx._fe = pos;
14654
+ ctx._fx = xf2;
14655
+ return FAIL;
14656
+ }
14657
+ EC.e = pos;
14658
+ return null;
14659
+ };
14660
+ }
13906
14661
  const child = link(code[ip + 1]);
13907
14662
  const xf = fx[code[ip + 2]];
13908
14663
  const gate2 = lookaheadClass(code[ip + 1]);
@@ -13920,8 +14675,10 @@ function assemble(t, prog, cfg) {
13920
14675
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13921
14676
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13922
14677
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14678
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13923
14679
  const v = child(input, pos, ctx);
13924
14680
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14681
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13925
14682
  if (v === FAIL) {
13926
14683
  ctx._fe = pos;
13927
14684
  ctx._fx = xf;
@@ -13934,12 +14691,13 @@ function assemble(t, prog, cfg) {
13934
14691
  case OP_OPT: {
13935
14692
  const child = link(code[ip + 1]);
13936
14693
  const gate2 = lookaheadClass(code[ip + 1]);
14694
+ const childClean = CLEAN(code[ip + 1]);
13937
14695
  return (input, pos, ctx) => {
13938
14696
  if (gate2 !== null && !classHas2(gate2, lead(input, pos))) {
13939
14697
  EC.e = pos;
13940
14698
  return null;
13941
14699
  }
13942
- const need = markCst(ctx);
14700
+ const need = !childClean && markCst(ctx);
13943
14701
  const mRaw = MRAW;
13944
14702
  const mTl = MTL;
13945
14703
  const mLv = MLV;
@@ -14137,6 +14895,9 @@ function assemble(t, prog, cfg) {
14137
14895
  const projection = reducer < 0 ? ~reducer : -1;
14138
14896
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
14139
14897
  const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
14898
+ const decided = FIRST_DECIDED;
14899
+ FIRST_DECIDED = void 0;
14900
+ const linkFirst = () => decided ?? link(code[base]);
14140
14901
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
14141
14902
  if (count === 1) return (input, cur, ctx, values, inherited) => {
14142
14903
  cur = r0(input, cur, ctx, inherited);
@@ -14182,7 +14943,7 @@ function assemble(t, prog, cfg) {
14182
14943
  };
14183
14944
  };
14184
14945
  if (REC2) {
14185
- const first2 = link(code[base]);
14946
+ const first2 = linkFirst();
14186
14947
  const firstSync = sentinelFor(code[base + n]);
14187
14948
  const runnerAt = (i) => {
14188
14949
  const sync = sentinelFor(code[base + n + i]);
@@ -14218,13 +14979,13 @@ function assemble(t, prog, cfg) {
14218
14979
  const bindRunners = (start) => {
14219
14980
  const count = Math.min(4, n - start);
14220
14981
  const at = (offset) => runnerAt(start + offset);
14221
- const never = () => -1;
14982
+ const never2 = () => -1;
14222
14983
  return runnerBlock(
14223
14984
  count,
14224
14985
  at(0),
14225
- count > 1 ? at(1) : never,
14226
- count > 2 ? at(2) : never,
14227
- count > 3 ? at(3) : never,
14986
+ count > 1 ? at(1) : never2,
14987
+ count > 2 ? at(2) : never2,
14988
+ count > 3 ? at(3) : never2,
14228
14989
  start + count < n ? bindRunners(start + count) : void 0
14229
14990
  );
14230
14991
  };
@@ -14274,15 +15035,31 @@ function assemble(t, prog, cfg) {
14274
15035
  let hasAdj = false;
14275
15036
  for (let i = 1; i < n; i++) {
14276
15037
  const kidIp = code[base + i];
14277
- if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
15038
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp) || holdsGap(code, k, base, n, i, NULLABLE)) {
14278
15039
  hasAdj = true;
14279
15040
  break;
14280
15041
  }
14281
15042
  }
14282
15043
  if (hasAdj) {
14283
- const first2 = link(code[base]);
15044
+ const first2 = linkFirst();
14284
15045
  const runnerAt = (i) => {
14285
15046
  const kidIp = code[base + i];
15047
+ if (holdsGap(code, k, base, n, i, NULLABLE)) {
15048
+ const kid = link(kidIp);
15049
+ return (input, cur, ctx) => {
15050
+ if (ctx.trivia === void 0) {
15051
+ const v2 = kid(input, cur, ctx);
15052
+ if (v2 === FAIL) return -1;
15053
+ TERMV = v2;
15054
+ return EC.e;
15055
+ }
15056
+ const scanEnd = skipTrivia(input, cur, ctx);
15057
+ const v = kid(input, scanEnd, ctx);
15058
+ if (v === FAIL) return -1;
15059
+ TERMV = v;
15060
+ return scanEnd;
15061
+ };
15062
+ }
14286
15063
  if (code[kidIp] !== OP_ADJ) {
14287
15064
  const kid = link(kidIp);
14288
15065
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -14307,13 +15084,13 @@ function assemble(t, prog, cfg) {
14307
15084
  const bindRunners = (start) => {
14308
15085
  const count = Math.min(4, n - start);
14309
15086
  const at = (offset) => runnerAt(start + offset);
14310
- const never = () => -1;
15087
+ const never2 = () => -1;
14311
15088
  return runnerBlock(
14312
15089
  count,
14313
15090
  at(0),
14314
- count > 1 ? at(1) : never,
14315
- count > 2 ? at(2) : never,
14316
- count > 3 ? at(3) : never,
15091
+ count > 1 ? at(1) : never2,
15092
+ count > 2 ? at(2) : never2,
15093
+ count > 3 ? at(3) : never2,
14317
15094
  start + count < n ? bindRunners(start + count) : void 0
14318
15095
  );
14319
15096
  };
@@ -14350,7 +15127,7 @@ function assemble(t, prog, cfg) {
14350
15127
  };
14351
15128
  }
14352
15129
  if (n === 1) {
14353
- const k0 = link(code[base]);
15130
+ const k0 = linkFirst();
14354
15131
  if (fused) {
14355
15132
  return (input, pos, ctx) => {
14356
15133
  const v = k0(input, pos, ctx);
@@ -14372,7 +15149,7 @@ function assemble(t, prog, cfg) {
14372
15149
  };
14373
15150
  }
14374
15151
  if (n === 2) {
14375
- const k0 = link(code[base]), k1 = link(code[base + 1]);
15152
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
14376
15153
  if (fused) {
14377
15154
  return (input, pos, ctx) => {
14378
15155
  const v0 = k0(input, pos, ctx);
@@ -14403,7 +15180,7 @@ function assemble(t, prog, cfg) {
14403
15180
  };
14404
15181
  }
14405
15182
  if (n === 3) {
14406
- const k0 = link(code[base]), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
15183
+ const k0 = linkFirst(), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
14407
15184
  if (fused) {
14408
15185
  return (input, pos, ctx) => {
14409
15186
  const v0 = k0(input, pos, ctx);
@@ -14497,7 +15274,7 @@ function assemble(t, prog, cfg) {
14497
15274
  start + count < n ? bind(start + count) : void 0
14498
15275
  );
14499
15276
  };
14500
- const first = link(code[base]);
15277
+ const first = linkFirst();
14501
15278
  const tail = bind(1);
14502
15279
  const runDirectTerms = (input, pos, ctx, values) => {
14503
15280
  const v0 = first(input, pos, ctx);
@@ -14536,6 +15313,8 @@ function assemble(t, prog, cfg) {
14536
15313
  const n = code[ip + 2];
14537
15314
  const choiceFx = fx[code[ip + 3]];
14538
15315
  const base = ip + 4;
15316
+ for (let i = 0; i < n; i++) link(code[base + i]);
15317
+ const armsClean = CLEAN(ip);
14539
15318
  if (table.exclusive) {
14540
15319
  const ascii = table.ascii;
14541
15320
  const hi = table.hi;
@@ -14675,7 +15454,7 @@ function assemble(t, prog, cfg) {
14675
15454
  if (n === 3) addGate(g2, 4);
14676
15455
  return (input, pos, ctx) => {
14677
15456
  const c = lead(input, pos);
14678
- const need = markCst(ctx);
15457
+ const need = !armsClean && markCst(ctx);
14679
15458
  const mRaw = MRAW;
14680
15459
  const mTl = MTL;
14681
15460
  const mLv = MLV;
@@ -14892,7 +15671,7 @@ function assemble(t, prog, cfg) {
14892
15671
  if (pn !== 0) {
14893
15672
  return (input, pos, ctx) => {
14894
15673
  const c = lead(input, pos);
14895
- const need = markCst(ctx);
15674
+ const need = !armsClean && markCst(ctx);
14896
15675
  const mRaw = MRAW;
14897
15676
  const mTl = MTL;
14898
15677
  const mLv = MLV;
@@ -14949,7 +15728,7 @@ function assemble(t, prog, cfg) {
14949
15728
  }
14950
15729
  return (input, pos, ctx) => {
14951
15730
  const c = lead(input, pos);
14952
- const need = markCst(ctx);
15731
+ const need = !armsClean && markCst(ctx);
14953
15732
  const mRaw = MRAW;
14954
15733
  const mTl = MTL;
14955
15734
  const mLv = MLV;
@@ -14997,7 +15776,7 @@ function assemble(t, prog, cfg) {
14997
15776
  }
14998
15777
  return (input, pos, ctx) => {
14999
15778
  const c = lead(input, pos);
15000
- const need = markCst(ctx);
15779
+ const need = !armsClean && markCst(ctx);
15001
15780
  const mRaw = MRAW;
15002
15781
  const mTl = MTL;
15003
15782
  const mLv = MLV;
@@ -15051,6 +15830,21 @@ function assemble(t, prog, cfg) {
15051
15830
  return lit(input, pos, ctx);
15052
15831
  };
15053
15832
  }
15833
+ case OP_RGATE: {
15834
+ const cls = cc[code[ip + 1]];
15835
+ const xf = fx[code[ip + 3]];
15836
+ const child = link(code[ip + 2]);
15837
+ if (cfg.tolerant || cfg.probe) return child;
15838
+ return (input, pos, ctx) => {
15839
+ const item = ctx._routed;
15840
+ if (item !== void 0 && item.span.start === pos && !classHas2(cls, lead(input, item.span.end))) {
15841
+ ctx._fe = item.span.end;
15842
+ ctx._fx = xf;
15843
+ return FAIL;
15844
+ }
15845
+ return child(input, pos, ctx);
15846
+ };
15847
+ }
15054
15848
  case OP_ARMGATE: {
15055
15849
  const pred = fns[code[ip + 1]];
15056
15850
  const child = link(code[ip + 2]);
@@ -15119,6 +15913,7 @@ function assemble(t, prog, cfg) {
15119
15913
  const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
15120
15914
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
15121
15915
  const skipBeforeFirst = sepIp < 0 && min === 0;
15916
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
15122
15917
  if (REC2) {
15123
15918
  const itemFx2 = fx[code[ip + 6]];
15124
15919
  const sepSent = sentinelFor(code[ip + 7]);
@@ -15215,6 +16010,8 @@ function assemble(t, prog, cfg) {
15215
16010
  const out = collect ? [] : void 0;
15216
16011
  const hasTrivia = ctx.trivia !== void 0;
15217
16012
  const needMark = rollbackNeeded(ctx);
16013
+ const markLater = needMark && (!itemClean || hasTrivia);
16014
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
15218
16015
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
15219
16016
  let cur = pos;
15220
16017
  let count = 0;
@@ -15222,14 +16019,15 @@ function assemble(t, prog, cfg) {
15222
16019
  if (max >= 0 && count >= max) break;
15223
16020
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
15224
16021
  if (count >= min && sep === void 0 && !hasTrivia && gateItems && !itemMayStart(input, cur)) break;
15225
- if (needMark) markCst(ctx);
15226
- const mRaw = needMark ? MRAW : 0;
15227
- const mTl = needMark ? MTL : 0;
15228
- const mLv = needMark ? MLV : 0;
15229
- const mFl = needMark ? ctx._fields?.length ?? 0 : 0;
15230
- const mEr = needMark ? ctx._errors?.length ?? 0 : 0;
15231
- const mLog = needMark ? ctx._triviaLog?.length ?? 0 : 0;
15232
- const mRoot = needMark ? ctx._rootTriviaLog?.length ?? 0 : 0;
16022
+ const markIt = count > 0 ? markLater : markFirst;
16023
+ if (markIt) markCst(ctx);
16024
+ const mRaw = markIt ? MRAW : 0;
16025
+ const mTl = markIt ? MTL : 0;
16026
+ const mLv = markIt ? MLV : 0;
16027
+ const mFl = markIt ? ctx._fields?.length ?? 0 : 0;
16028
+ const mEr = markIt ? ctx._errors?.length ?? 0 : 0;
16029
+ const mLog = markIt ? ctx._triviaLog?.length ?? 0 : 0;
16030
+ const mRoot = markIt ? ctx._rootTriviaLog?.length ?? 0 : 0;
15233
16031
  let itemStart = cur;
15234
16032
  let sepEnd = -1;
15235
16033
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -15241,7 +16039,7 @@ function assemble(t, prog, cfg) {
15241
16039
  if (sepLeads) LEAD.at = cur;
15242
16040
  const sv = sep(input, sp, ctx);
15243
16041
  if (sv === FAIL) {
15244
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16042
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15245
16043
  if (committed3(ctx)) return FAIL;
15246
16044
  break;
15247
16045
  }
@@ -15252,25 +16050,25 @@ function assemble(t, prog, cfg) {
15252
16050
  itemStart = skipTrivia(input, itemStart, ctx);
15253
16051
  }
15254
16052
  if (itemStart >= input.length && viaRepItem) {
15255
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16053
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15256
16054
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15257
16055
  break;
15258
16056
  }
15259
16057
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
15260
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16058
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15261
16059
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15262
16060
  break;
15263
16061
  }
15264
16062
  ctx._fc = false;
15265
16063
  const v = child(input, itemStart, ctx);
15266
16064
  if (v === FAIL) {
15267
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16065
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15268
16066
  if (committed3(ctx)) return FAIL;
15269
16067
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15270
16068
  break;
15271
16069
  }
15272
16070
  if (EC.e === itemStart && viaRepItem) {
15273
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16071
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15274
16072
  break;
15275
16073
  }
15276
16074
  if (out !== void 0) out.push(v);
@@ -15344,7 +16142,14 @@ function assemble(t, prog, cfg) {
15344
16142
  const runArm = n === 0 ? void 0 : bindArms(0);
15345
16143
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
15346
16144
  return (input, pos, ctx) => {
15347
- const selectorMark = saveTriviaMark(ctx);
16145
+ const need = markCst(ctx);
16146
+ const mRaw = MRAW;
16147
+ const mTl = MTL;
16148
+ const mLv = MLV;
16149
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
16150
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
16151
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
16152
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
15348
16153
  const selVal = selector(input, pos, ctx);
15349
16154
  if (selVal === FAIL) return FAIL;
15350
16155
  const selEnd = EC.e;
@@ -15356,9 +16161,9 @@ function assemble(t, prog, cfg) {
15356
16161
  ctx._fx = expected;
15357
16162
  return FAIL;
15358
16163
  }
15359
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
16164
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15360
16165
  }
15361
- return runArm(arm, input, pos, selEnd, key, selectorMark, ctx);
16166
+ return runArm(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15362
16167
  };
15363
16168
  }
15364
16169
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -15394,7 +16199,8 @@ function assemble(t, prog, cfg) {
15394
16199
  return nd;
15395
16200
  };
15396
16201
  }
15397
- const child = link(code[ip + 2]);
16202
+ const child = NODE_BODY ?? link(code[ip + 2]);
16203
+ NODE_BODY = void 0;
15398
16204
  const proj = code[ip + 4];
15399
16205
  const buildIdx = code[ip + 1];
15400
16206
  const type = k[code[ip + 5]];
@@ -15418,6 +16224,30 @@ function assemble(t, prog, cfg) {
15418
16224
  if (build !== void 0 && proj < 0 && flags === 18) {
15419
16225
  return childrenOnlyFieldsBuildNode(child, build);
15420
16226
  }
16227
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
16228
+ return passCollapseNode(child, build, flags === 32);
16229
+ }
16230
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
16231
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(closureLabels.at(code[ip + 2]).tri, trivia2);
16232
+ if (build !== void 0 && gated !== void 0 && triviaLead !== void 0) {
16233
+ const classic = flags === 32 ? collapseBuildNode(child, build) : childrenOnlyCollapseBuildNode(child, build);
16234
+ return gatedPassCollapseNode(
16235
+ [
16236
+ ...gated.leads.map((g) => cc[code[g + 1]]),
16237
+ resolveClass(encodeClassSpec([
16238
+ ...triviaLead,
16239
+ ...gated.lits.map((i) => {
16240
+ const c = k[i].codePointAt(0);
16241
+ return { lo: c, hi: c };
16242
+ })
16243
+ ]))
16244
+ ],
16245
+ link(gated.last),
16246
+ classic,
16247
+ build,
16248
+ flags === 32
16249
+ );
16250
+ }
15421
16251
  if (build !== void 0 && proj < 0 && flags === 32) {
15422
16252
  return collapseBuildNode(child, build);
15423
16253
  }
@@ -15566,6 +16396,8 @@ function assemble(t, prog, cfg) {
15566
16396
  }
15567
16397
  const notChild = scalarTerminalNotChild(code, ip);
15568
16398
  if (notChild >= 0) scalarFor(notChild);
16399
+ const peekChild = scalarTerminalPeekChild(code, ip);
16400
+ if (peekChild >= 0) scalarFor(peekChild);
15569
16401
  }
15570
16402
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
15571
16403
  if (pre !== void 0) {
@@ -15625,7 +16457,8 @@ function assemble(t, prog, cfg) {
15625
16457
  t.lexPrograms,
15626
16458
  LEAD,
15627
16459
  triviaFieldCapture,
15628
- skipDeferredTrivia
16460
+ skipDeferredTrivia,
16461
+ collapseEmpty
15629
16462
  );
15630
16463
  emitReached = new Set(pre.reached);
15631
16464
  if (emitted.ext !== void 0) HYBRID = emitted;
@@ -15711,7 +16544,8 @@ function assemble(t, prog, cfg) {
15711
16544
  t.lexPrograms,
15712
16545
  LEAD,
15713
16546
  triviaFieldCapture,
15714
- skipDeferredTrivia
16547
+ skipDeferredTrivia,
16548
+ collapseEmpty
15715
16549
  );
15716
16550
  emitReached = em.reached;
15717
16551
  } catch (e) {
@@ -15978,7 +16812,7 @@ function emitClassPool(classes) {
15978
16812
  if (classes.length < 2) return array;
15979
16813
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
15980
16814
  if (delimiter === void 0) return array;
15981
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16815
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
15982
16816
  return split.length < array.length ? split : array;
15983
16817
  }
15984
16818
  function emitConst(v) {
@@ -17761,15 +18595,20 @@ function compileRuleMap(ruleMap, opts = {}) {
17761
18595
  throw e;
17762
18596
  }
17763
18597
  const ceiling = budget / SUPERCOMPILE_GROWTH;
18598
+ if (ceiling <= fixed) return none;
17764
18599
  let target = ceiling;
17765
- for (let attempt2 = 0; attempt2 < 16; attempt2++) {
18600
+ for (; ; ) {
17766
18601
  const sites = selectHotSites(artifact.code, Object.values(artifact.rules), siteBytes, target - fixed, profile);
17767
- if (sites.size === 0) return none;
18602
+ if (sites.size === 0) {
18603
+ return {
18604
+ ...none,
18605
+ refusal: `a site within its ${Math.floor(ceiling)} B selection ceiling (the prelude alone is ${fixed} B)`
18606
+ };
18607
+ }
17768
18608
  const bytes2 = emitAssemblySource(table, artifact, cfg, roots, true, sites).source.length;
17769
18609
  if (bytes2 <= ceiling) return { sites, bytes: Math.ceil(bytes2 * SUPERCOMPILE_GROWTH) };
17770
18610
  target *= Math.min(ceiling / bytes2, 0.99);
17771
18611
  }
17772
- return none;
17773
18612
  };
17774
18613
  return {
17775
18614
  keys: ruleMap.map(([key]) => key),
@@ -17857,16 +18696,16 @@ function ownSource(fn) {
17857
18696
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
17858
18697
  }
17859
18698
  function compile(target, second, third) {
17860
- if (!isCombinator(target)) return compileMap(target, second);
18699
+ if (!isCombinator2(target)) return compileMap(target, second);
17861
18700
  return compileRoot(target, second, third);
17862
18701
  }
17863
- function isCombinator(x) {
18702
+ function isCombinator2(x) {
17864
18703
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
17865
18704
  }
17866
18705
  function compileMap(grammar, opts = {}) {
17867
18706
  const entries = [];
17868
18707
  for (const [key, value] of Object.entries(grammar)) {
17869
- if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
18708
+ if (!isCombinator2(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
17870
18709
  if (value._def.tag === "lazy") {
17871
18710
  try {
17872
18711
  value._def.thunk();
@@ -18408,7 +19247,7 @@ function fieldOptionsSrc(def) {
18408
19247
  }
18409
19248
 
18410
19249
  // src/version.ts
18411
- var PARSEMAN_VERSION = "0.57.0";
19250
+ var PARSEMAN_VERSION = "0.58.0";
18412
19251
 
18413
19252
  // src/compiler/compile-linkable-table.ts
18414
19253
  function isLocal(rule) {
@@ -18677,7 +19516,7 @@ function analyzeGrammarGating(grammar, opts) {
18677
19516
  }
18678
19517
 
18679
19518
  // src/analysis/diagnose.ts
18680
- var isCombinator2 = (g) => typeof g === "object" && g !== null && "_def" in g;
19519
+ var isCombinator3 = (g) => typeof g === "object" && g !== null && "_def" in g;
18681
19520
  var isRuleEntries = (g) => Array.isArray(g);
18682
19521
  function diagnoseGrammar(grammar, opts) {
18683
19522
  const depth = degradationCaptureDepth();
@@ -18721,7 +19560,7 @@ function formatGrammarDiagnosis(d) {
18721
19560
  return lines2;
18722
19561
  }
18723
19562
  function runAnalysis(grammar, opts) {
18724
- if (isCombinator2(grammar)) return analyzeGating(grammar, opts);
19563
+ if (isCombinator3(grammar)) return analyzeGating(grammar, opts);
18725
19564
  if (isRuleEntries(grammar)) return analyzeGatingRules(grammar, opts);
18726
19565
  return analyzeGrammarGating(grammar, opts);
18727
19566
  }
@@ -21028,13 +21867,13 @@ function buildTriviaIndex(root, input = "", opts) {
21028
21867
  }
21029
21868
 
21030
21869
  // src/cst/walk.ts
21031
- function isCombinator3(value) {
21870
+ function isCombinator4(value) {
21032
21871
  return !!value && typeof value === "object" && "_def" in value && "_meta" in value && typeof value.parse === "function";
21033
21872
  }
21034
21873
  function reflectionFor(grammar) {
21035
21874
  const stamped = grammarReflectionOf(grammar);
21036
21875
  if (stamped) return stamped;
21037
- const entries = Object.entries(grammar).filter((entry) => isCombinator3(entry[1]));
21876
+ const entries = Object.entries(grammar).filter((entry) => isCombinator4(entry[1]));
21038
21877
  return collectGrammarReflection(entries);
21039
21878
  }
21040
21879
  function createVisitor(grammar, spec) {