parseman 0.57.0 → 0.58.1

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 (69) hide show
  1. package/dist/analysis/diagnostics.js +1800 -962
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +1929 -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 +1017 -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 +1210 -236
  17. package/dist/plugin/index.js.map +3 -3
  18. package/dist/run/index.d.ts +2 -0
  19. package/dist/run/index.d.ts.map +1 -1
  20. package/dist/run/index.js +9 -0
  21. package/dist/run/index.js.map +1 -1
  22. package/dist/table/assemble.d.ts.map +1 -1
  23. package/dist/table/compile-rule-map.d.ts.map +1 -1
  24. package/dist/table/emit-assembly.d.ts +1 -1
  25. package/dist/table/emit-assembly.d.ts.map +1 -1
  26. package/dist/table/emit.d.ts.map +1 -1
  27. package/dist/table/encode.d.ts.map +1 -1
  28. package/dist/table/exec.d.ts.map +1 -1
  29. package/dist/table/factor-choice.d.ts +42 -0
  30. package/dist/table/factor-choice.d.ts.map +1 -0
  31. package/dist/table/fail-clean.d.ts +3 -0
  32. package/dist/table/fail-clean.d.ts.map +1 -0
  33. package/dist/table/hold-gap.d.ts +8 -0
  34. package/dist/table/hold-gap.d.ts.map +1 -0
  35. package/dist/table/index.js +1370 -259
  36. package/dist/table/index.js.map +3 -3
  37. package/dist/table/lex-program.d.ts +7 -3
  38. package/dist/table/lex-program.d.ts.map +1 -1
  39. package/dist/table/ops.d.ts +8 -0
  40. package/dist/table/ops.d.ts.map +1 -1
  41. package/dist/table/run-support.d.ts +19 -0
  42. package/dist/table/run-support.d.ts.map +1 -1
  43. package/dist/table/scalar-terminal.d.ts +2 -0
  44. package/dist/table/scalar-terminal.d.ts.map +1 -1
  45. package/dist/table/site-labels.d.ts +66 -0
  46. package/dist/table/site-labels.d.ts.map +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/package.json +1 -1
  49. package/src/combinators/dispatch.ts +12 -3
  50. package/src/compiler/token-alphabet.ts +57 -17
  51. package/src/cst/capture-buffer.ts +25 -0
  52. package/src/plugin/index.ts +230 -35
  53. package/src/run/index.ts +5 -0
  54. package/src/table/assemble.ts +252 -62
  55. package/src/table/child-slots.ts +2 -2
  56. package/src/table/compile-rule-map.ts +14 -5
  57. package/src/table/emit-assembly.ts +112 -23
  58. package/src/table/emit.ts +3 -1
  59. package/src/table/encode.ts +83 -14
  60. package/src/table/exec.ts +27 -8
  61. package/src/table/factor-choice.ts +173 -0
  62. package/src/table/fail-clean.ts +130 -0
  63. package/src/table/hold-gap.ts +68 -0
  64. package/src/table/lex-program.ts +197 -43
  65. package/src/table/ops.ts +9 -1
  66. package/src/table/run-support.ts +35 -0
  67. package/src/table/scalar-terminal.ts +8 -0
  68. package/src/table/site-labels.ts +135 -4
  69. 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,51 @@ 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 nextDef = next._def;
8454
+ if (nextDef.tag !== "literal" && nextDef.tag !== "regex" && nextDef.tag !== "keywords" && nextDef.tag !== "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
+ const miss = nextDef.tag === "label" ? deriveExpected(next) : directTerminalFailureExpected(nextDef);
8459
+ return { cls, fx: this.expected(miss) };
8460
+ }
8084
8461
  node(p) {
8085
8462
  const lazyRef = p._def.tag === "lazy";
8086
8463
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -8205,6 +8582,10 @@ var Encoder = class {
8205
8582
  return head;
8206
8583
  }
8207
8584
  case "choice": {
8585
+ if (this.plan === void 0) {
8586
+ const factored = factorSharedEnds(d);
8587
+ if (factored !== void 0) return this.node(factored).ip;
8588
+ }
8208
8589
  if (d.strategy.tag === "greedyClassify") {
8209
8590
  const superIndex = d.strategy.superIndex;
8210
8591
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -8228,9 +8609,12 @@ var Encoder = class {
8228
8609
  const kids = arms.map((c, k) => {
8229
8610
  const src = order[k];
8230
8611
  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
8612
  const gate2 = d.gates[src];
8613
+ const plain = (checks === null || checks === void 0 || checks.length === 0) && (gate2 === null || gate2 === void 0);
8614
+ const routedGate = plain ? this.routedArmGate(c) : void 0;
8615
+ const body = this.node(c).ip;
8616
+ const inner = routedGate === void 0 ? body : this.emit(OP_RGATE, routedGate.cls, body, routedGate.fx);
8617
+ const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
8234
8618
  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
8619
  return this.covWrap(gated, armCovIds?.[src], 1);
8236
8620
  });
@@ -8554,6 +8938,7 @@ var Encoder = class {
8554
8938
  const slots = (ip) => {
8555
8939
  switch (this.code[ip]) {
8556
8940
  case OP_GATE:
8941
+ case OP_RGATE:
8557
8942
  return [ip + 2];
8558
8943
  case OP_RULE:
8559
8944
  case OP_OPT:
@@ -9784,6 +10169,7 @@ function childSlots(code, ip, out) {
9784
10169
  case OP_LEAF:
9785
10170
  case OP_SOURCE_LEAF:
9786
10171
  case OP_ARMGATE:
10172
+ case OP_RGATE:
9787
10173
  out.push(code[ip + 2]);
9788
10174
  return true;
9789
10175
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -9867,6 +10253,42 @@ function reachableSites(code, roots) {
9867
10253
  }
9868
10254
  return seen;
9869
10255
  }
10256
+ function passCollapse(code, ip, hostCst) {
10257
+ const flags = code[ip + 3];
10258
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
10259
+ if (flags !== 32 && flags !== 34) return false;
10260
+ let at = code[ip + 2];
10261
+ for (let n = 0; n < 8; n++) {
10262
+ const op = code[at];
10263
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
10264
+ else if (op === OP_RULE) at = code[at + 1];
10265
+ else break;
10266
+ }
10267
+ return code[at] === OP_NODE;
10268
+ }
10269
+ function gatedPassCollapse(code, ip, hostCst) {
10270
+ const flags = code[ip + 3];
10271
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
10272
+ if (flags !== 32 && flags !== 34) return void 0;
10273
+ const seq = code[ip + 2];
10274
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
10275
+ const n = code[seq + 1];
10276
+ if (n < 2) return void 0;
10277
+ const leads = [];
10278
+ const lits = [];
10279
+ for (let i = 0; i < n - 1; i++) {
10280
+ const t = code[seq + 2 + i];
10281
+ if (code[t] !== OP_OPT && code[t] !== OP_NOT) return void 0;
10282
+ const g = code[t + 1];
10283
+ if (code[g] === OP_GATE) leads.push(g);
10284
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
10285
+ else return void 0;
10286
+ }
10287
+ const last = code[seq + 2 + n - 1];
10288
+ let at = last;
10289
+ 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];
10290
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
10291
+ }
9870
10292
  function transfer(code, ip, at, hostCst) {
9871
10293
  const op = code[ip];
9872
10294
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -9878,14 +10300,18 @@ function transfer(code, ip, at, hostCst) {
9878
10300
  }
9879
10301
  if (op === OP_NODE || op === OP_NODE_TRACK) {
9880
10302
  const flags = code[ip + 3];
10303
+ if (passCollapse(code, ip, hostCst)) return at;
10304
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
9881
10305
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
9882
10306
  if (directChildren) {
9883
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
10307
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
10308
+ return gated ? meet(at, framed2) : framed2;
9884
10309
  }
9885
10310
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
9886
10311
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
9887
10312
  if (at.buf && raw === at.raw && cap === at.cap) return at;
9888
- return { tri: at.tri, buf: true, raw, cap };
10313
+ const framed = { tri: at.tri, buf: true, raw, cap };
10314
+ return gated ? meet(at, framed) : framed;
9889
10315
  }
9890
10316
  if (op === OP_TOKEN) {
9891
10317
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -9923,6 +10349,40 @@ function computeSiteLabels(code, roots, hostCst) {
9923
10349
  }
9924
10350
  return { at: (ip) => labels.get(ip) ?? TOP };
9925
10351
  }
10352
+ function scopeIsIdentity(code, ip, at) {
10353
+ const op = code[ip];
10354
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
10355
+ const ki = code[ip + 1];
10356
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
10357
+ }
10358
+ function scanHandoffNeeded(code, ip, labels) {
10359
+ const seen = /* @__PURE__ */ new Set();
10360
+ const stack = [ip];
10361
+ const kids = [];
10362
+ while (stack.length > 0) {
10363
+ const at = stack.pop();
10364
+ if (seen.has(at)) continue;
10365
+ seen.add(at);
10366
+ const l = labels.at(at);
10367
+ if (l.tri === TRI_UNKNOWN) return true;
10368
+ const op = code[at];
10369
+ if (op === OP_SCAN) return true;
10370
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue;
10371
+ 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;
10372
+ kids.length = 0;
10373
+ if (!childSlots(code, at, kids)) return true;
10374
+ for (const c of kids) stack.push(c);
10375
+ }
10376
+ return false;
10377
+ }
10378
+ function triviaLeadRanges(tri, trivia2) {
10379
+ if (tri === TRI_NONE) return [];
10380
+ if (tri < 0) return void 0;
10381
+ const fs = trivia2[tri]?._meta.firstSet;
10382
+ if (fs === void 0) return void 0;
10383
+ if (fs.kind === "empty") return [];
10384
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
10385
+ }
9926
10386
 
9927
10387
  // src/table/scalar-terminal.ts
9928
10388
  function makeScalarRecognizer(op, spec) {
@@ -9960,6 +10420,12 @@ function scalarTerminalNotChild(code, ip) {
9960
10420
  const op = code[child];
9961
10421
  return op === OP_RX || op === OP_LIT ? child : -1;
9962
10422
  }
10423
+ function scalarTerminalPeekChild(code, ip) {
10424
+ if (code[ip] !== OP_PEEK) return -1;
10425
+ const child = code[ip + 1];
10426
+ const op = code[child];
10427
+ return op === OP_RX || op === OP_LIT ? child : -1;
10428
+ }
9963
10429
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
9964
10430
  const seen = /* @__PURE__ */ new Set();
9965
10431
  let at = ip;
@@ -10137,6 +10603,59 @@ function leadingTriviaFieldAt(code, k, ip) {
10137
10603
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
10138
10604
  }
10139
10605
 
10606
+ // src/table/hold-gap.ts
10607
+ var WRAPPERS = /* @__PURE__ */ new Set([
10608
+ OP_NODE,
10609
+ OP_XFORM,
10610
+ OP_LEAF,
10611
+ OP_SOURCE_LEAF,
10612
+ OP_TOKEN,
10613
+ OP_SCOPE,
10614
+ OP_SCOPE_CAP,
10615
+ OP_SCOPE_PLAIN,
10616
+ OP_FIELD,
10617
+ OP_LABEL,
10618
+ OP_EXPECT,
10619
+ OP_WITHCTX,
10620
+ OP_RULE,
10621
+ OP_ATTEMPT,
10622
+ OP_COV
10623
+ ]);
10624
+ function rowNullable(code, k, ip, memo) {
10625
+ const hit = memo.get(ip);
10626
+ if (hit !== void 0) return hit;
10627
+ memo.set(ip, true);
10628
+ const op = code[ip];
10629
+ const kids = [];
10630
+ let out = true;
10631
+ if (op === OP_GATE) out = false;
10632
+ else if (op === OP_LIT || op === OP_LIT_CI) out = k[code[ip + 1]].length === 0;
10633
+ else if (op === OP_RX) {
10634
+ const re = k[code[ip + 1]];
10635
+ out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
10636
+ } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
10637
+ childSlots(code, ip, kids);
10638
+ out = kids.every((c) => rowNullable(code, k, c, memo));
10639
+ } else if (op === OP_CHOICE) {
10640
+ childSlots(code, ip, kids);
10641
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
10642
+ } else if (op === OP_REP || op === OP_REPV) {
10643
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
10644
+ } else if (WRAPPERS.has(op)) {
10645
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
10646
+ }
10647
+ memo.set(ip, out);
10648
+ return out;
10649
+ }
10650
+ function holdsGap(code, k, base, n, i, memo) {
10651
+ if (i < 1 || i + 1 >= n) return false;
10652
+ const term = code[base + i];
10653
+ if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
10654
+ const next = code[base + i + 1];
10655
+ if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
10656
+ return !rowNullable(code, k, next, memo);
10657
+ }
10658
+
10140
10659
  // src/table/emit-assembly.ts
10141
10660
  var Unemittable = class extends Error {
10142
10661
  construct;
@@ -10217,7 +10736,10 @@ var EMITTED_PARAMS = [
10217
10736
  "triviaFieldCapture",
10218
10737
  // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
10219
10738
  // factories ignore it.
10220
- "skipDeferredTrivia"
10739
+ "skipDeferredTrivia",
10740
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
10741
+ // ignore it.
10742
+ "collapseEmpty"
10221
10743
  ];
10222
10744
  var RUNTIME_PRELUDE = `
10223
10745
  let _pfScan=null
@@ -10414,6 +10936,24 @@ ${fast}
10414
10936
  ${scanned}
10415
10937
  }`;
10416
10938
  }
10939
+ function emitHoldTerm(callee, dst, t, l, skip) {
10940
+ const fast = `const ${t}v=${callee}(input,cur,ctx)
10941
+ if(${t}v===FAIL)return FAIL
10942
+ ${dst}=${t}v
10943
+ cur=EC.e`;
10944
+ if (l.tri === TRI_NONE) return fast;
10945
+ const held = `const ${t}s=${skip}(input,cur,ctx)
10946
+ const ${t}v=${callee}(input,${t}s,ctx)
10947
+ if(${t}v===FAIL)return FAIL
10948
+ ${dst}=${t}v
10949
+ cur=${t}s`;
10950
+ if (l.tri !== TRI_UNKNOWN) return held;
10951
+ return `if(ctx.trivia===undefined){
10952
+ ${fast}
10953
+ }else{
10954
+ ${held}
10955
+ }`;
10956
+ }
10417
10957
  function leadSkip(hasTrivia, leadTrivia, skip) {
10418
10958
  if (hasTrivia === "false") return "{}";
10419
10959
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -10455,6 +10995,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false, se
10455
10995
  const reachable = [...reachableSites(code, roots)];
10456
10996
  const labels = computeSiteLabels(code, roots, hostCst);
10457
10997
  const scalarSpecs = /* @__PURE__ */ new Set();
10998
+ const nullable2 = /* @__PURE__ */ new Map();
10458
10999
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
10459
11000
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
10460
11001
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -10779,9 +11320,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10779
11320
  const op = code[ip];
10780
11321
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
10781
11322
  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
- }
11323
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
10785
11324
  return void 0;
10786
11325
  }
10787
11326
  function lower(ip, fname) {
@@ -10903,6 +11442,22 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10903
11442
  return `${head}
10904
11443
  if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10905
11444
  return ${child}(input,pos,ctx)
11445
+ }`;
11446
+ }
11447
+ case OP_RGATE: {
11448
+ const child = link(code[ip + 2]);
11449
+ if (cfg.tolerant || cfg.probe) return `${head}
11450
+ return ${child}(input,pos,ctx)
11451
+ }`;
11452
+ const resolved = t.cc[code[ip + 1]];
11453
+ const ci = classes.push([resolved]) - 1;
11454
+ classPlan.push([code[ip + 1]]);
11455
+ const cls = hoist("cl", `CLS[${ci}][0]`);
11456
+ const xf = fxRef(code[ip + 3]);
11457
+ return `${head}
11458
+ const it=ctx._routed
11459
+ if(it!==undefined&&it.span.start===pos&&!classHas(${cls},lead(input,it.span.end))){ctx._fe=it.span.end;ctx._fx=${xf};return FAIL}
11460
+ return ${child}(input,pos,ctx)
10906
11461
  }`;
10907
11462
  }
10908
11463
  case OP_ARMGATE: {
@@ -11177,23 +11732,33 @@ return FAIL
11177
11732
  const p = tmp();
11178
11733
  return `${head}
11179
11734
  ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
11180
- const v=${child}(input,pos,ctx)
11735
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
11181
11736
  ${emitRollback(p, L.buf, L.raw, sinks)}
11182
- if(v===FAIL){EC.e=pos;return null}
11737
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){EC.e=pos;return null}
11183
11738
  ctx._fe=pos
11184
11739
  ctx._fx=${xf}
11185
11740
  return FAIL
11186
11741
  }`;
11187
11742
  }
11188
11743
  case OP_PEEK: {
11744
+ const scalarChild = scalarTerminalPeekChild(code, ip);
11745
+ if (scalarChild >= 0) {
11746
+ const recognize = recognizerRef(code[scalarChild + 1]);
11747
+ const xf2 = fxRef(code[ip + 2]);
11748
+ return `${head}
11749
+ if(${recognize}(input,pos)<0){ctx._fe=pos;ctx._fx=${xf2};return FAIL}
11750
+ EC.e=pos
11751
+ return null
11752
+ }`;
11753
+ }
11189
11754
  const child = link(code[ip + 1]);
11190
11755
  const xf = fxRef(code[ip + 2]);
11191
11756
  const p = tmp();
11192
11757
  return `${head}
11193
11758
  ${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)
11759
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
11195
11760
  ${emitRollback(p, L.buf, L.raw, sinks)}
11196
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11761
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11197
11762
  EC.e=pos
11198
11763
  return null
11199
11764
  }`;
@@ -11264,7 +11829,7 @@ return v
11264
11829
  );
11265
11830
  } else {
11266
11831
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
11267
- parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
11832
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
11268
11833
  }
11269
11834
  names.push(vn);
11270
11835
  }
@@ -11747,6 +12312,26 @@ return nd
11747
12312
  const trailingTrivia = (flags & 128) !== 0;
11748
12313
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
11749
12314
  const leanFlags = flags & ~128;
12315
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
12316
+ return `${head}
12317
+ const v=${child}(input,pos,ctx)
12318
+ if(v!==undefined)return v
12319
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
12320
+ }`;
12321
+ }
12322
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
12323
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t.trivia);
12324
+ const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
12325
+ if(!(${[
12326
+ ...gated.leads.map((g) => `!(${gateMissTest(g)})`),
12327
+ ...gated.lits.map((i) => `gc===${k[i].codePointAt(0)}`),
12328
+ ...triviaLead.map((r) => r.lo === r.hi ? `gc===${r.lo}` : `(gc>=${r.lo}&&gc<=${r.hi})`)
12329
+ ].join("||") || "false"})){
12330
+ const gv=${link(gated.last)}(input,pos,ctx)
12331
+ if(gv!==undefined)return gv
12332
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
12333
+ }
12334
+ ` : "";
11750
12335
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
11751
12336
  const fields = flags === 18;
11752
12337
  const collapseChildren = flags === 34;
@@ -11781,7 +12366,7 @@ sCh.push(nd)
11781
12366
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
11782
12367
  }`;
11783
12368
  return `${head}
11784
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12369
+ ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11785
12370
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
11786
12371
  const flat=[]
11787
12372
  ctx._cstBuf=undefined
@@ -11856,7 +12441,7 @@ const hostKids=kids
11856
12441
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
11857
12442
  const tlog=buf.tl??EMPTY_TLOG`;
11858
12443
  return `${head}
11859
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
12444
+ ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11860
12445
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
11861
12446
  ${openCapture}
11862
12447
  ctx.captureTrivia=${captureWide}
@@ -11926,9 +12511,15 @@ ext:[${externals.join(",")}],
11926
12511
  bind:function(xs,ps){_xScan=xs
11927
12512
  ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
11928
12513
  scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
12514
+ const scannerFor = (ip) => {
12515
+ const ki = labels.at(ip).tri;
12516
+ if (ki === TRI_UNKNOWN) return "_pfScan";
12517
+ if (ki === TRI_NONE) return "null";
12518
+ return swapLegal && !triviaLabelled[ki] && t.triviaScan[ki] != null ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
12519
+ };
11929
12520
  const externalDefs = select === void 0 ? "" : `let _xScan
11930
12521
  ${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")}
12522
+ 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
12523
  `;
11933
12524
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
11934
12525
  ${prelude.join("\n")}
@@ -12465,37 +13056,120 @@ function clearOf(ranges, input, from, to) {
12465
13056
  return true;
12466
13057
  }
12467
13058
 
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;
13059
+ // src/table/fail-clean.ts
13060
+ function passChild(code, ip) {
13061
+ switch (code[ip]) {
13062
+ case OP_RULE:
13063
+ case OP_LABEL:
13064
+ case OP_COV:
13065
+ case OP_TOKEN:
13066
+ return code[ip + 1];
13067
+ case OP_GATE:
13068
+ case OP_NODE:
13069
+ case OP_NODE_TRACK:
13070
+ case OP_XFORM:
13071
+ case OP_FIELD:
13072
+ case OP_SCOPE:
13073
+ case OP_SCOPE_CAP:
13074
+ case OP_SCOPE_PLAIN:
13075
+ case OP_WITHCTX:
13076
+ case OP_LEAF:
13077
+ case OP_SOURCE_LEAF:
13078
+ return code[ip + 2];
13079
+ default:
13080
+ return -1;
12476
13081
  }
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
13082
  }
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 }
13083
+ function seqCount(code, ip) {
13084
+ const op = code[ip];
13085
+ return op === OP_SEQ || op === OP_SEQV ? ip + 1 : op === OP_SEQX ? ip + 2 : -1;
13086
+ }
13087
+ function failCleanAnalysis(code) {
13088
+ const cleanAt = new Uint8Array(code.length);
13089
+ const neverAt = new Uint8Array(code.length);
13090
+ const neverFails = (ip) => {
13091
+ const hit = neverAt[ip];
13092
+ if (hit !== 0) return hit === 1;
13093
+ neverAt[ip] = 3;
13094
+ let out = false;
13095
+ const op = code[ip];
13096
+ if (op === OP_OPT || op === OP_EMPTY || op === OP_EXPECT) out = true;
13097
+ else if (op === OP_REP || op === OP_REPV) out = code[ip + 2] === 0;
13098
+ else {
13099
+ const at = seqCount(code, ip);
13100
+ if (at >= 0) {
13101
+ out = true;
13102
+ for (let i = 1, n = code[at]; out && i <= n; i++) out = neverFails(code[at + i]);
13103
+ } else if (op !== OP_GATE) {
13104
+ const c = passChild(code, ip);
13105
+ out = c >= 0 && neverFails(c);
13106
+ }
13107
+ }
13108
+ neverAt[ip] = out ? 1 : 2;
13109
+ return out;
12492
13110
  };
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;
13111
+ const clean = (ip) => {
13112
+ const hit = cleanAt[ip];
13113
+ if (hit !== 0) return hit === 1;
13114
+ cleanAt[ip] = 3;
13115
+ let out = false;
13116
+ switch (code[ip]) {
13117
+ // A terminal pushes its leaf only on a match; NOT/PEEK/ATTEMPT restore
13118
+ // their own mark; OPT, EMPTY and EXPECT do not fail uncommitted.
13119
+ case OP_LIT:
13120
+ case OP_RX:
13121
+ case OP_LIT_TRACK:
13122
+ case OP_RX_TRACK:
13123
+ case OP_LIT_CI:
13124
+ case OP_LIT_CI_TRACK:
13125
+ case OP_GUARD:
13126
+ case OP_NOT:
13127
+ case OP_PEEK:
13128
+ case OP_ATTEMPT:
13129
+ case OP_EMPTY:
13130
+ case OP_OPT:
13131
+ case OP_EXPECT:
13132
+ out = true;
13133
+ break;
13134
+ // Min 0 does not fail uncommitted; min 1 fails only with no item kept, and
13135
+ // restores the failed item itself.
13136
+ case OP_REP:
13137
+ case OP_REPV:
13138
+ out = code[ip + 2] <= 1;
13139
+ break;
13140
+ // Only the first term may fail: a later one fails after the terms before it
13141
+ // wrote, and after the trivia scanned in front of it.
13142
+ case OP_SEQ:
13143
+ case OP_SEQV:
13144
+ case OP_SEQX: {
13145
+ const at = seqCount(code, ip);
13146
+ const n = code[at];
13147
+ out = n > 0 && clean(code[at + 1]);
13148
+ for (let i = 2; out && i <= n; i++) out = neverFails(code[at + i]);
13149
+ break;
13150
+ }
13151
+ case OP_CHOICE: {
13152
+ out = true;
13153
+ for (let i = 0, n = code[ip + 2]; out && i < n; i++) out = clean(code[ip + 4 + i]);
13154
+ break;
13155
+ }
13156
+ case OP_ROUTED:
13157
+ out = code[ip + 1] < 0 || clean(code[ip + 1]);
13158
+ break;
13159
+ // An arm's failure and the fallback's are committed; only the selector's is
13160
+ // not, and without a fallback an unknown key fails after the selector wrote.
13161
+ case OP_DISPATCH:
13162
+ out = code[ip + 3] >= 0 && clean(code[ip + 1]);
13163
+ break;
13164
+ default: {
13165
+ const c = passChild(code, ip);
13166
+ out = c >= 0 && clean(c);
13167
+ }
13168
+ }
13169
+ cleanAt[ip] = out ? 1 : 2;
13170
+ return out;
13171
+ };
13172
+ return clean;
12499
13173
  }
12500
13174
 
12501
13175
  // src/cst/host-mode.ts
@@ -12660,6 +13334,7 @@ function assemble(t, prog, cfg) {
12660
13334
  const swapLegal = !cfg.trackLines;
12661
13335
  const hostCst = cfg.hostCst;
12662
13336
  const REC2 = prog.rec === 1 && cfg.tolerant;
13337
+ const PROBE = cfg.probe;
12663
13338
  const sentinels = /* @__PURE__ */ new Map();
12664
13339
  function sentinelFor(cls) {
12665
13340
  if (cls < 0) return void 0;
@@ -12705,6 +13380,8 @@ function assemble(t, prog, cfg) {
12705
13380
  }
12706
13381
  const memo = /* @__PURE__ */ new Map();
12707
13382
  const reached = /* @__PURE__ */ new Set();
13383
+ const NULLABLE = /* @__PURE__ */ new Map();
13384
+ const CLEAN = REC2 ? () => false : failCleanAnalysis(code);
12708
13385
  function pushLeaf(ctx, value, s, e) {
12709
13386
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
12710
13387
  pushCstLeaf(ctx, lf);
@@ -12903,6 +13580,22 @@ function assemble(t, prog, cfg) {
12903
13580
  return node2;
12904
13581
  };
12905
13582
  }
13583
+ function passCollapseNode(child, build, readsRaw) {
13584
+ return (input, pos, ctx) => {
13585
+ const v = child(input, pos, ctx);
13586
+ if (v !== void 0) return v;
13587
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13588
+ };
13589
+ }
13590
+ function gatedPassCollapseNode(blockers, last, classic, build, readsRaw) {
13591
+ return (input, pos, ctx) => {
13592
+ const c = lead(input, pos);
13593
+ for (let i = 0; i < blockers.length; i++) if (classHas2(blockers[i], c)) return classic(input, pos, ctx);
13594
+ const v = last(input, pos, ctx);
13595
+ if (v !== void 0) return v;
13596
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
13597
+ };
13598
+ }
12906
13599
  function plainProjectNode(child, projection, type) {
12907
13600
  return (input, pos, ctx) => {
12908
13601
  const sCh = ctx._cstChildren;
@@ -13273,21 +13966,27 @@ function assemble(t, prog, cfg) {
13273
13966
  }
13274
13967
  function dispatchBranch(child, usesRouted) {
13275
13968
  if (!usesRouted) {
13276
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
13277
- const mark = saveTriviaMark(ctx);
13969
+ return (input, _pos, selEnd, key, ctx) => {
13970
+ const need = markCst(ctx);
13971
+ const mRaw = MRAW;
13972
+ const mTl = MTL;
13973
+ const mLv = MLV;
13974
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13975
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13976
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13977
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
13278
13978
  const v = child(input, selEnd, ctx);
13279
13979
  if (v === FAIL) {
13280
- rollbackTrivia(ctx, mark);
13980
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13281
13981
  ctx._fc = true;
13282
13982
  return FAIL;
13283
13983
  }
13284
13984
  return [key, v];
13285
13985
  };
13286
13986
  }
13287
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13987
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
13288
13988
  const savedRouted = ctx._routed;
13289
- rollbackTrivia(ctx, selectorMark);
13290
- const mark = saveTriviaMark(ctx);
13989
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13291
13990
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
13292
13991
  let v;
13293
13992
  try {
@@ -13296,7 +13995,7 @@ function assemble(t, prog, cfg) {
13296
13995
  ctx._routed = savedRouted;
13297
13996
  }
13298
13997
  if (v === FAIL) {
13299
- rollbackTrivia(ctx, mark);
13998
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13300
13999
  ctx._fc = true;
13301
14000
  return FAIL;
13302
14001
  }
@@ -13304,12 +14003,12 @@ function assemble(t, prog, cfg) {
13304
14003
  };
13305
14004
  }
13306
14005
  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);
14006
+ return (arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
14007
+ if (arm === start) return a0(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14008
+ if (arm === start + 1) return a1(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14009
+ if (arm === start + 2) return a2(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14010
+ if (arm === start + 3) return a3(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14011
+ return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13313
14012
  };
13314
14013
  }
13315
14014
  function trackLinesInto(ctx, input, end) {
@@ -13328,7 +14027,7 @@ function assemble(t, prog, cfg) {
13328
14027
  if (flight !== void 0) return flight.fwd;
13329
14028
  const selected = HYBRID?.byIp[ip];
13330
14029
  if (selected !== void 0) {
13331
- const piece2 = hybridPiece(selected);
14030
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
13332
14031
  memo.set(ip, piece2);
13333
14032
  reached.add(ip);
13334
14033
  return piece2;
@@ -13339,14 +14038,55 @@ function assemble(t, prog, cfg) {
13339
14038
  target = p;
13340
14039
  } };
13341
14040
  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);
14041
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
13344
14042
  inFlight.delete(ip);
13345
14043
  holder.set(piece);
13346
14044
  memo.set(ip, piece);
13347
14045
  reached.add(ip);
13348
14046
  return piece;
13349
14047
  }
14048
+ let FIRST_DECIDED;
14049
+ let NODE_BODY;
14050
+ const DECIDED = (_input, pos) => {
14051
+ EC.e = pos;
14052
+ return null;
14053
+ };
14054
+ function lookaheadLedNode(ip) {
14055
+ const op = code[ip];
14056
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC2 || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
14057
+ if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
14058
+ const body = code[ip + 2];
14059
+ const bop = code[body];
14060
+ if (bop !== OP_SEQ && bop !== OP_SEQV && bop !== OP_SEQX) return void 0;
14061
+ const base = bop === OP_SEQX ? body + 3 : body + 2;
14062
+ if (code[bop === OP_SEQX ? body + 2 : body + 1] < 2) return void 0;
14063
+ const first = code[base];
14064
+ const negative = code[first] === OP_NOT;
14065
+ const terminal = negative ? scalarTerminalNotChild(code, first) : code[first] === OP_PEEK ? scalarTerminalPeekChild(code, first) : -1;
14066
+ if (terminal < 0) return void 0;
14067
+ const recognize = scalarFor(terminal);
14068
+ const xf = fx[code[first + 2]];
14069
+ FIRST_DECIDED = DECIDED;
14070
+ NODE_BODY = lower(body);
14071
+ const node2 = lower(ip);
14072
+ NODE_BODY = void 0;
14073
+ return negative ? (input, pos, ctx) => {
14074
+ if (recognize(input, pos) >= 0) {
14075
+ ctx._fe = pos;
14076
+ ctx._fx = xf;
14077
+ EC.e = pos;
14078
+ return FAIL;
14079
+ }
14080
+ return node2(input, pos, ctx);
14081
+ } : (input, pos, ctx) => {
14082
+ if (recognize(input, pos) < 0) {
14083
+ ctx._fe = pos;
14084
+ ctx._fx = xf;
14085
+ return FAIL;
14086
+ }
14087
+ return node2(input, pos, ctx);
14088
+ };
14089
+ }
13350
14090
  function lower(ip) {
13351
14091
  const op = code[ip];
13352
14092
  switch (op) {
@@ -13891,8 +14631,10 @@ function assemble(t, prog, cfg) {
13891
14631
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13892
14632
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13893
14633
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14634
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13894
14635
  const v = child(input, pos, ctx);
13895
14636
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14637
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13896
14638
  if (v === FAIL) {
13897
14639
  EC.e = pos;
13898
14640
  return null;
@@ -13903,6 +14645,20 @@ function assemble(t, prog, cfg) {
13903
14645
  };
13904
14646
  }
13905
14647
  case OP_PEEK: {
14648
+ const scalarChild = scalarTerminalPeekChild(code, ip);
14649
+ if (scalarChild >= 0) {
14650
+ const recognize = scalarFor(scalarChild);
14651
+ const xf2 = fx[code[ip + 2]];
14652
+ return (input, pos, ctx) => {
14653
+ if (recognize(input, pos) < 0) {
14654
+ ctx._fe = pos;
14655
+ ctx._fx = xf2;
14656
+ return FAIL;
14657
+ }
14658
+ EC.e = pos;
14659
+ return null;
14660
+ };
14661
+ }
13906
14662
  const child = link(code[ip + 1]);
13907
14663
  const xf = fx[code[ip + 2]];
13908
14664
  const gate2 = lookaheadClass(code[ip + 1]);
@@ -13920,8 +14676,10 @@ function assemble(t, prog, cfg) {
13920
14676
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13921
14677
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13922
14678
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14679
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13923
14680
  const v = child(input, pos, ctx);
13924
14681
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14682
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13925
14683
  if (v === FAIL) {
13926
14684
  ctx._fe = pos;
13927
14685
  ctx._fx = xf;
@@ -13934,12 +14692,13 @@ function assemble(t, prog, cfg) {
13934
14692
  case OP_OPT: {
13935
14693
  const child = link(code[ip + 1]);
13936
14694
  const gate2 = lookaheadClass(code[ip + 1]);
14695
+ const childClean = CLEAN(code[ip + 1]);
13937
14696
  return (input, pos, ctx) => {
13938
14697
  if (gate2 !== null && !classHas2(gate2, lead(input, pos))) {
13939
14698
  EC.e = pos;
13940
14699
  return null;
13941
14700
  }
13942
- const need = markCst(ctx);
14701
+ const need = !childClean && markCst(ctx);
13943
14702
  const mRaw = MRAW;
13944
14703
  const mTl = MTL;
13945
14704
  const mLv = MLV;
@@ -14137,6 +14896,9 @@ function assemble(t, prog, cfg) {
14137
14896
  const projection = reducer < 0 ? ~reducer : -1;
14138
14897
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
14139
14898
  const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
14899
+ const decided = FIRST_DECIDED;
14900
+ FIRST_DECIDED = void 0;
14901
+ const linkFirst = () => decided ?? link(code[base]);
14140
14902
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
14141
14903
  if (count === 1) return (input, cur, ctx, values, inherited) => {
14142
14904
  cur = r0(input, cur, ctx, inherited);
@@ -14182,7 +14944,7 @@ function assemble(t, prog, cfg) {
14182
14944
  };
14183
14945
  };
14184
14946
  if (REC2) {
14185
- const first2 = link(code[base]);
14947
+ const first2 = linkFirst();
14186
14948
  const firstSync = sentinelFor(code[base + n]);
14187
14949
  const runnerAt = (i) => {
14188
14950
  const sync = sentinelFor(code[base + n + i]);
@@ -14218,13 +14980,13 @@ function assemble(t, prog, cfg) {
14218
14980
  const bindRunners = (start) => {
14219
14981
  const count = Math.min(4, n - start);
14220
14982
  const at = (offset) => runnerAt(start + offset);
14221
- const never = () => -1;
14983
+ const never2 = () => -1;
14222
14984
  return runnerBlock(
14223
14985
  count,
14224
14986
  at(0),
14225
- count > 1 ? at(1) : never,
14226
- count > 2 ? at(2) : never,
14227
- count > 3 ? at(3) : never,
14987
+ count > 1 ? at(1) : never2,
14988
+ count > 2 ? at(2) : never2,
14989
+ count > 3 ? at(3) : never2,
14228
14990
  start + count < n ? bindRunners(start + count) : void 0
14229
14991
  );
14230
14992
  };
@@ -14274,15 +15036,31 @@ function assemble(t, prog, cfg) {
14274
15036
  let hasAdj = false;
14275
15037
  for (let i = 1; i < n; i++) {
14276
15038
  const kidIp = code[base + i];
14277
- if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
15039
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp) || holdsGap(code, k, base, n, i, NULLABLE)) {
14278
15040
  hasAdj = true;
14279
15041
  break;
14280
15042
  }
14281
15043
  }
14282
15044
  if (hasAdj) {
14283
- const first2 = link(code[base]);
15045
+ const first2 = linkFirst();
14284
15046
  const runnerAt = (i) => {
14285
15047
  const kidIp = code[base + i];
15048
+ if (holdsGap(code, k, base, n, i, NULLABLE)) {
15049
+ const kid = link(kidIp);
15050
+ return (input, cur, ctx) => {
15051
+ if (ctx.trivia === void 0) {
15052
+ const v2 = kid(input, cur, ctx);
15053
+ if (v2 === FAIL) return -1;
15054
+ TERMV = v2;
15055
+ return EC.e;
15056
+ }
15057
+ const scanEnd = skipTrivia(input, cur, ctx);
15058
+ const v = kid(input, scanEnd, ctx);
15059
+ if (v === FAIL) return -1;
15060
+ TERMV = v;
15061
+ return scanEnd;
15062
+ };
15063
+ }
14286
15064
  if (code[kidIp] !== OP_ADJ) {
14287
15065
  const kid = link(kidIp);
14288
15066
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -14307,13 +15085,13 @@ function assemble(t, prog, cfg) {
14307
15085
  const bindRunners = (start) => {
14308
15086
  const count = Math.min(4, n - start);
14309
15087
  const at = (offset) => runnerAt(start + offset);
14310
- const never = () => -1;
15088
+ const never2 = () => -1;
14311
15089
  return runnerBlock(
14312
15090
  count,
14313
15091
  at(0),
14314
- count > 1 ? at(1) : never,
14315
- count > 2 ? at(2) : never,
14316
- count > 3 ? at(3) : never,
15092
+ count > 1 ? at(1) : never2,
15093
+ count > 2 ? at(2) : never2,
15094
+ count > 3 ? at(3) : never2,
14317
15095
  start + count < n ? bindRunners(start + count) : void 0
14318
15096
  );
14319
15097
  };
@@ -14350,7 +15128,7 @@ function assemble(t, prog, cfg) {
14350
15128
  };
14351
15129
  }
14352
15130
  if (n === 1) {
14353
- const k0 = link(code[base]);
15131
+ const k0 = linkFirst();
14354
15132
  if (fused) {
14355
15133
  return (input, pos, ctx) => {
14356
15134
  const v = k0(input, pos, ctx);
@@ -14372,7 +15150,7 @@ function assemble(t, prog, cfg) {
14372
15150
  };
14373
15151
  }
14374
15152
  if (n === 2) {
14375
- const k0 = link(code[base]), k1 = link(code[base + 1]);
15153
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
14376
15154
  if (fused) {
14377
15155
  return (input, pos, ctx) => {
14378
15156
  const v0 = k0(input, pos, ctx);
@@ -14403,7 +15181,7 @@ function assemble(t, prog, cfg) {
14403
15181
  };
14404
15182
  }
14405
15183
  if (n === 3) {
14406
- const k0 = link(code[base]), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
15184
+ const k0 = linkFirst(), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
14407
15185
  if (fused) {
14408
15186
  return (input, pos, ctx) => {
14409
15187
  const v0 = k0(input, pos, ctx);
@@ -14497,7 +15275,7 @@ function assemble(t, prog, cfg) {
14497
15275
  start + count < n ? bind(start + count) : void 0
14498
15276
  );
14499
15277
  };
14500
- const first = link(code[base]);
15278
+ const first = linkFirst();
14501
15279
  const tail = bind(1);
14502
15280
  const runDirectTerms = (input, pos, ctx, values) => {
14503
15281
  const v0 = first(input, pos, ctx);
@@ -14536,6 +15314,8 @@ function assemble(t, prog, cfg) {
14536
15314
  const n = code[ip + 2];
14537
15315
  const choiceFx = fx[code[ip + 3]];
14538
15316
  const base = ip + 4;
15317
+ for (let i = 0; i < n; i++) link(code[base + i]);
15318
+ const armsClean = CLEAN(ip);
14539
15319
  if (table.exclusive) {
14540
15320
  const ascii = table.ascii;
14541
15321
  const hi = table.hi;
@@ -14675,7 +15455,7 @@ function assemble(t, prog, cfg) {
14675
15455
  if (n === 3) addGate(g2, 4);
14676
15456
  return (input, pos, ctx) => {
14677
15457
  const c = lead(input, pos);
14678
- const need = markCst(ctx);
15458
+ const need = !armsClean && markCst(ctx);
14679
15459
  const mRaw = MRAW;
14680
15460
  const mTl = MTL;
14681
15461
  const mLv = MLV;
@@ -14892,7 +15672,7 @@ function assemble(t, prog, cfg) {
14892
15672
  if (pn !== 0) {
14893
15673
  return (input, pos, ctx) => {
14894
15674
  const c = lead(input, pos);
14895
- const need = markCst(ctx);
15675
+ const need = !armsClean && markCst(ctx);
14896
15676
  const mRaw = MRAW;
14897
15677
  const mTl = MTL;
14898
15678
  const mLv = MLV;
@@ -14949,7 +15729,7 @@ function assemble(t, prog, cfg) {
14949
15729
  }
14950
15730
  return (input, pos, ctx) => {
14951
15731
  const c = lead(input, pos);
14952
- const need = markCst(ctx);
15732
+ const need = !armsClean && markCst(ctx);
14953
15733
  const mRaw = MRAW;
14954
15734
  const mTl = MTL;
14955
15735
  const mLv = MLV;
@@ -14997,7 +15777,7 @@ function assemble(t, prog, cfg) {
14997
15777
  }
14998
15778
  return (input, pos, ctx) => {
14999
15779
  const c = lead(input, pos);
15000
- const need = markCst(ctx);
15780
+ const need = !armsClean && markCst(ctx);
15001
15781
  const mRaw = MRAW;
15002
15782
  const mTl = MTL;
15003
15783
  const mLv = MLV;
@@ -15051,6 +15831,21 @@ function assemble(t, prog, cfg) {
15051
15831
  return lit(input, pos, ctx);
15052
15832
  };
15053
15833
  }
15834
+ case OP_RGATE: {
15835
+ const cls = cc[code[ip + 1]];
15836
+ const xf = fx[code[ip + 3]];
15837
+ const child = link(code[ip + 2]);
15838
+ if (cfg.tolerant || cfg.probe) return child;
15839
+ return (input, pos, ctx) => {
15840
+ const item = ctx._routed;
15841
+ if (item !== void 0 && item.span.start === pos && !classHas2(cls, lead(input, item.span.end))) {
15842
+ ctx._fe = item.span.end;
15843
+ ctx._fx = xf;
15844
+ return FAIL;
15845
+ }
15846
+ return child(input, pos, ctx);
15847
+ };
15848
+ }
15054
15849
  case OP_ARMGATE: {
15055
15850
  const pred = fns[code[ip + 1]];
15056
15851
  const child = link(code[ip + 2]);
@@ -15119,6 +15914,7 @@ function assemble(t, prog, cfg) {
15119
15914
  const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
15120
15915
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
15121
15916
  const skipBeforeFirst = sepIp < 0 && min === 0;
15917
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
15122
15918
  if (REC2) {
15123
15919
  const itemFx2 = fx[code[ip + 6]];
15124
15920
  const sepSent = sentinelFor(code[ip + 7]);
@@ -15215,6 +16011,8 @@ function assemble(t, prog, cfg) {
15215
16011
  const out = collect ? [] : void 0;
15216
16012
  const hasTrivia = ctx.trivia !== void 0;
15217
16013
  const needMark = rollbackNeeded(ctx);
16014
+ const markLater = needMark && (!itemClean || hasTrivia);
16015
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
15218
16016
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
15219
16017
  let cur = pos;
15220
16018
  let count = 0;
@@ -15222,14 +16020,15 @@ function assemble(t, prog, cfg) {
15222
16020
  if (max >= 0 && count >= max) break;
15223
16021
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
15224
16022
  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;
16023
+ const markIt = count > 0 ? markLater : markFirst;
16024
+ if (markIt) markCst(ctx);
16025
+ const mRaw = markIt ? MRAW : 0;
16026
+ const mTl = markIt ? MTL : 0;
16027
+ const mLv = markIt ? MLV : 0;
16028
+ const mFl = markIt ? ctx._fields?.length ?? 0 : 0;
16029
+ const mEr = markIt ? ctx._errors?.length ?? 0 : 0;
16030
+ const mLog = markIt ? ctx._triviaLog?.length ?? 0 : 0;
16031
+ const mRoot = markIt ? ctx._rootTriviaLog?.length ?? 0 : 0;
15233
16032
  let itemStart = cur;
15234
16033
  let sepEnd = -1;
15235
16034
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -15241,7 +16040,7 @@ function assemble(t, prog, cfg) {
15241
16040
  if (sepLeads) LEAD.at = cur;
15242
16041
  const sv = sep(input, sp, ctx);
15243
16042
  if (sv === FAIL) {
15244
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16043
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15245
16044
  if (committed3(ctx)) return FAIL;
15246
16045
  break;
15247
16046
  }
@@ -15252,25 +16051,25 @@ function assemble(t, prog, cfg) {
15252
16051
  itemStart = skipTrivia(input, itemStart, ctx);
15253
16052
  }
15254
16053
  if (itemStart >= input.length && viaRepItem) {
15255
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16054
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15256
16055
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15257
16056
  break;
15258
16057
  }
15259
16058
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
15260
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16059
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15261
16060
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15262
16061
  break;
15263
16062
  }
15264
16063
  ctx._fc = false;
15265
16064
  const v = child(input, itemStart, ctx);
15266
16065
  if (v === FAIL) {
15267
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16066
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15268
16067
  if (committed3(ctx)) return FAIL;
15269
16068
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
15270
16069
  break;
15271
16070
  }
15272
16071
  if (EC.e === itemStart && viaRepItem) {
15273
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
16072
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15274
16073
  break;
15275
16074
  }
15276
16075
  if (out !== void 0) out.push(v);
@@ -15344,7 +16143,14 @@ function assemble(t, prog, cfg) {
15344
16143
  const runArm = n === 0 ? void 0 : bindArms(0);
15345
16144
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
15346
16145
  return (input, pos, ctx) => {
15347
- const selectorMark = saveTriviaMark(ctx);
16146
+ const need = markCst(ctx);
16147
+ const mRaw = MRAW;
16148
+ const mTl = MTL;
16149
+ const mLv = MLV;
16150
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
16151
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
16152
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
16153
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
15348
16154
  const selVal = selector(input, pos, ctx);
15349
16155
  if (selVal === FAIL) return FAIL;
15350
16156
  const selEnd = EC.e;
@@ -15356,9 +16162,9 @@ function assemble(t, prog, cfg) {
15356
16162
  ctx._fx = expected;
15357
16163
  return FAIL;
15358
16164
  }
15359
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
16165
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15360
16166
  }
15361
- return runArm(arm, input, pos, selEnd, key, selectorMark, ctx);
16167
+ return runArm(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15362
16168
  };
15363
16169
  }
15364
16170
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -15394,7 +16200,8 @@ function assemble(t, prog, cfg) {
15394
16200
  return nd;
15395
16201
  };
15396
16202
  }
15397
- const child = link(code[ip + 2]);
16203
+ const child = NODE_BODY ?? link(code[ip + 2]);
16204
+ NODE_BODY = void 0;
15398
16205
  const proj = code[ip + 4];
15399
16206
  const buildIdx = code[ip + 1];
15400
16207
  const type = k[code[ip + 5]];
@@ -15418,6 +16225,30 @@ function assemble(t, prog, cfg) {
15418
16225
  if (build !== void 0 && proj < 0 && flags === 18) {
15419
16226
  return childrenOnlyFieldsBuildNode(child, build);
15420
16227
  }
16228
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
16229
+ return passCollapseNode(child, build, flags === 32);
16230
+ }
16231
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
16232
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(closureLabels.at(code[ip + 2]).tri, trivia2);
16233
+ if (build !== void 0 && gated !== void 0 && triviaLead !== void 0) {
16234
+ const classic = flags === 32 ? collapseBuildNode(child, build) : childrenOnlyCollapseBuildNode(child, build);
16235
+ return gatedPassCollapseNode(
16236
+ [
16237
+ ...gated.leads.map((g) => cc[code[g + 1]]),
16238
+ resolveClass(encodeClassSpec([
16239
+ ...triviaLead,
16240
+ ...gated.lits.map((i) => {
16241
+ const c = k[i].codePointAt(0);
16242
+ return { lo: c, hi: c };
16243
+ })
16244
+ ]))
16245
+ ],
16246
+ link(gated.last),
16247
+ classic,
16248
+ build,
16249
+ flags === 32
16250
+ );
16251
+ }
15421
16252
  if (build !== void 0 && proj < 0 && flags === 32) {
15422
16253
  return collapseBuildNode(child, build);
15423
16254
  }
@@ -15566,6 +16397,8 @@ function assemble(t, prog, cfg) {
15566
16397
  }
15567
16398
  const notChild = scalarTerminalNotChild(code, ip);
15568
16399
  if (notChild >= 0) scalarFor(notChild);
16400
+ const peekChild = scalarTerminalPeekChild(code, ip);
16401
+ if (peekChild >= 0) scalarFor(peekChild);
15569
16402
  }
15570
16403
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
15571
16404
  if (pre !== void 0) {
@@ -15625,7 +16458,8 @@ function assemble(t, prog, cfg) {
15625
16458
  t.lexPrograms,
15626
16459
  LEAD,
15627
16460
  triviaFieldCapture,
15628
- skipDeferredTrivia
16461
+ skipDeferredTrivia,
16462
+ collapseEmpty
15629
16463
  );
15630
16464
  emitReached = new Set(pre.reached);
15631
16465
  if (emitted.ext !== void 0) HYBRID = emitted;
@@ -15711,7 +16545,8 @@ function assemble(t, prog, cfg) {
15711
16545
  t.lexPrograms,
15712
16546
  LEAD,
15713
16547
  triviaFieldCapture,
15714
- skipDeferredTrivia
16548
+ skipDeferredTrivia,
16549
+ collapseEmpty
15715
16550
  );
15716
16551
  emitReached = em.reached;
15717
16552
  } catch (e) {
@@ -15978,7 +16813,7 @@ function emitClassPool(classes) {
15978
16813
  if (classes.length < 2) return array;
15979
16814
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
15980
16815
  if (delimiter === void 0) return array;
15981
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16816
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
15982
16817
  return split.length < array.length ? split : array;
15983
16818
  }
15984
16819
  function emitConst(v) {
@@ -17761,15 +18596,20 @@ function compileRuleMap(ruleMap, opts = {}) {
17761
18596
  throw e;
17762
18597
  }
17763
18598
  const ceiling = budget / SUPERCOMPILE_GROWTH;
18599
+ if (ceiling <= fixed) return none;
17764
18600
  let target = ceiling;
17765
- for (let attempt2 = 0; attempt2 < 16; attempt2++) {
18601
+ for (; ; ) {
17766
18602
  const sites = selectHotSites(artifact.code, Object.values(artifact.rules), siteBytes, target - fixed, profile);
17767
- if (sites.size === 0) return none;
18603
+ if (sites.size === 0) {
18604
+ return {
18605
+ ...none,
18606
+ refusal: `a site within its ${Math.floor(ceiling)} B selection ceiling (the prelude alone is ${fixed} B)`
18607
+ };
18608
+ }
17768
18609
  const bytes2 = emitAssemblySource(table, artifact, cfg, roots, true, sites).source.length;
17769
18610
  if (bytes2 <= ceiling) return { sites, bytes: Math.ceil(bytes2 * SUPERCOMPILE_GROWTH) };
17770
18611
  target *= Math.min(ceiling / bytes2, 0.99);
17771
18612
  }
17772
- return none;
17773
18613
  };
17774
18614
  return {
17775
18615
  keys: ruleMap.map(([key]) => key),
@@ -17857,16 +18697,16 @@ function ownSource(fn) {
17857
18697
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
17858
18698
  }
17859
18699
  function compile(target, second, third) {
17860
- if (!isCombinator(target)) return compileMap(target, second);
18700
+ if (!isCombinator2(target)) return compileMap(target, second);
17861
18701
  return compileRoot(target, second, third);
17862
18702
  }
17863
- function isCombinator(x) {
18703
+ function isCombinator2(x) {
17864
18704
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
17865
18705
  }
17866
18706
  function compileMap(grammar, opts = {}) {
17867
18707
  const entries = [];
17868
18708
  for (const [key, value] of Object.entries(grammar)) {
17869
- if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
18709
+ if (!isCombinator2(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
17870
18710
  if (value._def.tag === "lazy") {
17871
18711
  try {
17872
18712
  value._def.thunk();
@@ -18408,7 +19248,7 @@ function fieldOptionsSrc(def) {
18408
19248
  }
18409
19249
 
18410
19250
  // src/version.ts
18411
- var PARSEMAN_VERSION = "0.57.0";
19251
+ var PARSEMAN_VERSION = "0.58.1";
18412
19252
 
18413
19253
  // src/compiler/compile-linkable-table.ts
18414
19254
  function isLocal(rule) {
@@ -18677,7 +19517,7 @@ function analyzeGrammarGating(grammar, opts) {
18677
19517
  }
18678
19518
 
18679
19519
  // src/analysis/diagnose.ts
18680
- var isCombinator2 = (g) => typeof g === "object" && g !== null && "_def" in g;
19520
+ var isCombinator3 = (g) => typeof g === "object" && g !== null && "_def" in g;
18681
19521
  var isRuleEntries = (g) => Array.isArray(g);
18682
19522
  function diagnoseGrammar(grammar, opts) {
18683
19523
  const depth = degradationCaptureDepth();
@@ -18721,7 +19561,7 @@ function formatGrammarDiagnosis(d) {
18721
19561
  return lines2;
18722
19562
  }
18723
19563
  function runAnalysis(grammar, opts) {
18724
- if (isCombinator2(grammar)) return analyzeGating(grammar, opts);
19564
+ if (isCombinator3(grammar)) return analyzeGating(grammar, opts);
18725
19565
  if (isRuleEntries(grammar)) return analyzeGatingRules(grammar, opts);
18726
19566
  return analyzeGrammarGating(grammar, opts);
18727
19567
  }
@@ -21028,13 +21868,13 @@ function buildTriviaIndex(root, input = "", opts) {
21028
21868
  }
21029
21869
 
21030
21870
  // src/cst/walk.ts
21031
- function isCombinator3(value) {
21871
+ function isCombinator4(value) {
21032
21872
  return !!value && typeof value === "object" && "_def" in value && "_meta" in value && typeof value.parse === "function";
21033
21873
  }
21034
21874
  function reflectionFor(grammar) {
21035
21875
  const stamped = grammarReflectionOf(grammar);
21036
21876
  if (stamped) return stamped;
21037
- const entries = Object.entries(grammar).filter((entry) => isCombinator3(entry[1]));
21877
+ const entries = Object.entries(grammar).filter((entry) => isCombinator4(entry[1]));
21038
21878
  return collectGrammarReflection(entries);
21039
21879
  }
21040
21880
  function createVisitor(grammar, spec) {