parseman 0.52.0 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/analysis/diagnostics.js +636 -126
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +6191 -6274
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/field-trivia.d.ts +40 -0
  6. package/dist/combinators/field-trivia.d.ts.map +1 -0
  7. package/dist/combinators/map.d.ts +19 -2
  8. package/dist/combinators/map.d.ts.map +1 -1
  9. package/dist/combinators/parser.d.ts +34 -0
  10. package/dist/combinators/parser.d.ts.map +1 -1
  11. package/dist/combinators/ref.d.ts +0 -13
  12. package/dist/combinators/ref.d.ts.map +1 -1
  13. package/dist/combinators/repeat.d.ts.map +1 -1
  14. package/dist/combinators/sequence.d.ts.map +1 -1
  15. package/dist/compiler/borrowed-rules.d.ts +30 -0
  16. package/dist/compiler/borrowed-rules.d.ts.map +1 -0
  17. package/dist/compiler/compile-linkable-table.d.ts +1 -1
  18. package/dist/compiler/fields.d.ts +2 -0
  19. package/dist/compiler/fields.d.ts.map +1 -1
  20. package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
  21. package/dist/compiler/ir-serialize.d.ts +10 -4
  22. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  23. package/dist/compiler/linker.d.ts +48 -91
  24. package/dist/compiler/linker.d.ts.map +1 -1
  25. package/dist/coverage.d.ts +1 -1
  26. package/dist/coverage.d.ts.map +1 -1
  27. package/dist/cst/reflection.d.ts.map +1 -1
  28. package/dist/cst/trivia-charscan.d.ts +11 -3
  29. package/dist/cst/trivia-charscan.d.ts.map +1 -1
  30. package/dist/cst/trivia-kinds.d.ts +11 -0
  31. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +764 -888
  35. package/dist/index.js.map +3 -3
  36. package/dist/language-service/index.js.map +1 -1
  37. package/dist/plugin/evaluator.d.ts +38 -2
  38. package/dist/plugin/evaluator.d.ts.map +1 -1
  39. package/dist/plugin/index.d.ts.map +1 -1
  40. package/dist/plugin/index.js +1443 -729
  41. package/dist/plugin/index.js.map +3 -3
  42. package/dist/plugin/ir-eval.d.ts +21 -0
  43. package/dist/plugin/ir-eval.d.ts.map +1 -0
  44. package/dist/plugin/reducer-resolver.d.ts +6 -0
  45. package/dist/plugin/reducer-resolver.d.ts.map +1 -1
  46. package/dist/spec/index.js +555 -6109
  47. package/dist/spec/index.js.map +3 -3
  48. package/dist/spec/railroad-lib.d.ts +7 -2
  49. package/dist/spec/railroad-lib.d.ts.map +1 -1
  50. package/dist/spec/railroad.d.ts.map +1 -1
  51. package/dist/table/assemble.d.ts +9 -0
  52. package/dist/table/assemble.d.ts.map +1 -1
  53. package/dist/table/compile-rule-map.d.ts +11 -4
  54. package/dist/table/compile-rule-map.d.ts.map +1 -1
  55. package/dist/table/compile.d.ts +16 -0
  56. package/dist/table/compile.d.ts.map +1 -1
  57. package/dist/table/emit-assembly.d.ts +1 -1
  58. package/dist/table/emit-assembly.d.ts.map +1 -1
  59. package/dist/table/emit.d.ts +6 -2
  60. package/dist/table/emit.d.ts.map +1 -1
  61. package/dist/table/encode.d.ts.map +1 -1
  62. package/dist/table/exec.d.ts.map +1 -1
  63. package/dist/table/field-spec.d.ts +13 -0
  64. package/dist/table/field-spec.d.ts.map +1 -0
  65. package/dist/table/index.js +480 -199
  66. package/dist/table/index.js.map +2 -2
  67. package/dist/table/scalar-terminal.d.ts +11 -0
  68. package/dist/table/scalar-terminal.d.ts.map +1 -1
  69. package/dist/types.d.ts +14 -0
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/version.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/src/analysis/duplication.ts +1 -1
  74. package/src/analysis/rebuild.ts +1 -1
  75. package/src/combinators/field-trivia.ts +44 -0
  76. package/src/combinators/map.ts +48 -6
  77. package/src/combinators/parser.ts +133 -67
  78. package/src/combinators/ref.ts +10 -1
  79. package/src/combinators/repeat.ts +6 -1
  80. package/src/combinators/sequence.ts +9 -1
  81. package/src/compiler/borrowed-rules.ts +88 -0
  82. package/src/compiler/compile-linkable-table.ts +1 -1
  83. package/src/compiler/fields.ts +5 -2
  84. package/src/compiler/grammar-coverage-ids.ts +35 -6
  85. package/src/compiler/ir-serialize.ts +19 -119
  86. package/src/compiler/linker.ts +190 -666
  87. package/src/coverage.ts +7 -5
  88. package/src/cst/reflection.ts +6 -1
  89. package/src/cst/trivia-charscan.ts +17 -56
  90. package/src/cst/trivia-kinds.ts +24 -8
  91. package/src/index.ts +1 -0
  92. package/src/plugin/evaluator.ts +114 -14
  93. package/src/plugin/index.ts +588 -110
  94. package/src/plugin/ir-eval.ts +165 -0
  95. package/src/plugin/reducer-resolver.ts +20 -3
  96. package/src/spec/railroad-lib.ts +18 -8
  97. package/src/spec/railroad.ts +3 -4
  98. package/src/table/assemble.ts +126 -22
  99. package/src/table/compile-rule-map.ts +18 -8
  100. package/src/table/compile.ts +61 -0
  101. package/src/table/emit-assembly.ts +38 -18
  102. package/src/table/emit.ts +15 -4
  103. package/src/table/encode.ts +18 -2
  104. package/src/table/exec.ts +15 -1
  105. package/src/table/field-spec.ts +17 -0
  106. package/src/table/scalar-terminal.ts +25 -0
  107. package/src/types.ts +12 -2
  108. package/src/version.ts +1 -1
@@ -1485,65 +1485,17 @@ function plainRegexSource(p) {
1485
1485
  const d = p._def;
1486
1486
  return d.tag === "regex" && d.flags === "" ? d.source : null;
1487
1487
  }
1488
- var visitSpec0;
1489
- var visitSpec1;
1490
- var visitSpec2;
1491
- var visitSpec3;
1492
- var visitValue0;
1493
- var visitValue1;
1494
- var visitValue2;
1495
- var visitValue3;
1496
1488
  function commonLabeledTriviaVisitor(spec) {
1497
- if (spec === visitSpec0) return visitValue0;
1498
- if (spec === visitSpec1) return visitValue1;
1499
- if (spec === visitSpec2) return visitValue2;
1500
- if (spec === visitSpec3) return visitValue3;
1501
- const sources = spec.minRepeats <= 1 ? spec.arms.map((arm) => plainRegexSource(arm.parser)) : [];
1502
- const visitor = commonCssTriviaVisitor(sources);
1503
- visitSpec3 = visitSpec2;
1504
- visitValue3 = visitValue2;
1505
- visitSpec2 = visitSpec1;
1506
- visitValue2 = visitValue1;
1507
- visitSpec1 = visitSpec0;
1508
- visitValue1 = visitValue0;
1509
- visitSpec0 = spec;
1510
- visitValue0 = visitor;
1511
- return visitor;
1512
- }
1513
- var armSpec0;
1514
- var armSpec1;
1515
- var armSpec2;
1516
- var armSpec3;
1517
- var armValue0;
1518
- var armValue1;
1519
- var armValue2;
1520
- var armValue3;
1489
+ return commonCssTriviaVisitor(spec.minRepeats <= 1 ? spec.arms.map((arm) => plainRegexSource(arm.parser)) : []);
1490
+ }
1521
1491
  function charArmsFor(spec) {
1522
- if (spec === armSpec0) return armValue0;
1523
- if (spec === armSpec1) return armValue1;
1524
- if (spec === armSpec2) return armValue2;
1525
- if (spec === armSpec3) return armValue3;
1526
- let arms = [];
1527
- if (spec.minRepeats > 1) {
1528
- arms = null;
1529
- } else {
1530
- for (const arm of spec.arms) {
1531
- const c = classifyParser(arm.parser);
1532
- if (!c) {
1533
- arms = null;
1534
- break;
1535
- }
1536
- arms.push(c);
1537
- }
1492
+ if (spec.minRepeats > 1) return null;
1493
+ const arms = [];
1494
+ for (const arm of spec.arms) {
1495
+ const c = classifyParser(arm.parser);
1496
+ if (!c) return null;
1497
+ arms.push(c);
1538
1498
  }
1539
- armSpec3 = armSpec2;
1540
- armValue3 = armValue2;
1541
- armSpec2 = armSpec1;
1542
- armValue2 = armValue1;
1543
- armSpec1 = armSpec0;
1544
- armValue1 = armValue0;
1545
- armSpec0 = spec;
1546
- armValue0 = arms;
1547
1499
  return arms;
1548
1500
  }
1549
1501
  function charTriviaEnd(input, cur, arms) {
@@ -1659,12 +1611,16 @@ function analyzeLabeledTrivia(trivia2) {
1659
1611
  }
1660
1612
  arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1661
1613
  }
1662
- const spec = {
1614
+ return cacheLabeledTrivia(trivia2, labeledTriviaSpec(arms, minRepeats));
1615
+ }
1616
+ function labeledTriviaSpec(arms, minRepeats) {
1617
+ return {
1663
1618
  labels: arms.map((a) => a.label),
1664
1619
  arms,
1665
- minRepeats
1620
+ minRepeats,
1621
+ visitor: commonLabeledTriviaVisitor({ arms, minRepeats }),
1622
+ charArms: charArmsFor({ arms, minRepeats })
1666
1623
  };
1667
- return cacheLabeledTrivia(trivia2, spec);
1668
1624
  }
1669
1625
  function matchArmAt(input, pos, arm, state) {
1670
1626
  if (!startsFirstSet(arm, input, pos)) return null;
@@ -1694,7 +1650,7 @@ function scanLabeledTriviaChunks(input, cur, spec, state) {
1694
1650
  return { end: pos, chunks };
1695
1651
  }
1696
1652
  function scanLabeledTriviaEnd(input, cur, spec, state) {
1697
- const chars = charArmsFor(spec);
1653
+ const chars = spec.charArms;
1698
1654
  if (chars !== null) return charTriviaEnd(input, cur, chars);
1699
1655
  let pos = cur;
1700
1656
  let count = 0;
@@ -1712,9 +1668,9 @@ function scanLabeledTriviaEnd(input, cur, spec, state) {
1712
1668
  }
1713
1669
  function visitLabeledTrivia(input, cur, spec, state, visit) {
1714
1670
  if (spec.minRepeats > 1) return void 0;
1715
- const common = commonLabeledTriviaVisitor(spec);
1671
+ const common = spec.visitor;
1716
1672
  if (common !== null) return common(input, cur, visit);
1717
- const chars = charArmsFor(spec);
1673
+ const chars = spec.charArms;
1718
1674
  if (chars !== null) return charTriviaVisit(input, cur, chars, visit);
1719
1675
  let pos = cur;
1720
1676
  let count = 0;
@@ -1781,7 +1737,7 @@ function resolveAdjacencyKindMask(trivia2, kinds) {
1781
1737
  return mask;
1782
1738
  }
1783
1739
  function triviaKindMaskAt(input, pos, spec, state) {
1784
- const chars = charArmsFor(spec);
1740
+ const chars = spec.charArms;
1785
1741
  if (chars !== null) return charTriviaKindMask(input, pos, chars);
1786
1742
  let cur = pos;
1787
1743
  let mask = 0;
@@ -2494,6 +2450,23 @@ function scalarOf(combinator) {
2494
2450
  return combinator._parseScalar;
2495
2451
  }
2496
2452
 
2453
+ // src/combinators/field-trivia.ts
2454
+ var LEAD = { at: -1 };
2455
+ var FIELD_LEADING_TRIVIA = 1;
2456
+ var FIELD_TRAILING_TRIVIA = 2;
2457
+ function triviaFieldCapture(name, value, input, start, end, leadFrom, trailEnd) {
2458
+ return {
2459
+ name,
2460
+ value,
2461
+ span: { start, end },
2462
+ leading: leadFrom >= 0 && leadFrom < start ? input.slice(leadFrom, start) : "",
2463
+ trailing: trailEnd > end ? input.slice(end, trailEnd) : ""
2464
+ };
2465
+ }
2466
+ function leadsTrivia(p) {
2467
+ return p._def.tag === "field" && p._def.leadingTrivia === true;
2468
+ }
2469
+
2497
2470
  // src/combinators/sequence.ts
2498
2471
  function sequence(...parsers) {
2499
2472
  let adjacency = null;
@@ -2509,6 +2482,10 @@ function sequence(...parsers) {
2509
2482
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
2510
2483
  }
2511
2484
  const hasAdjacency = adjacency !== null;
2485
+ let leading = null;
2486
+ for (let i = 1; i < parsers.length; i++) {
2487
+ if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
2488
+ }
2512
2489
  const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
2513
2490
  const meta = {
2514
2491
  // Union through the nullable prefix — a leading optional()/many() lets a later
@@ -2556,7 +2533,7 @@ function sequence(...parsers) {
2556
2533
  _tag: "sequence",
2557
2534
  _meta: meta,
2558
2535
  _def: def,
2559
- _parseScalar: hasAdjacency ? void 0 : parseScalar,
2536
+ _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
2560
2537
  parse(input, pos, ctx) {
2561
2538
  const tolerant = ctx._tolerant === true;
2562
2539
  if (tolerant) {
@@ -2590,6 +2567,7 @@ function sequence(...parsers) {
2590
2567
  const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
2591
2568
  const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
2592
2569
  const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
2570
+ if (leading?.[i] === true) LEAD.at = cur;
2593
2571
  const result = parsers[i].parse(input, termPos, ctx);
2594
2572
  if (!result.ok) return result;
2595
2573
  if (values !== void 0) values.push(result.value);
@@ -3392,6 +3370,7 @@ function withRuleTrivia(trivia2, ctx, run) {
3392
3370
  ctx.triviaKindLabels = savedLabels;
3393
3371
  }
3394
3372
  }
3373
+ var UNDEFINED_REF = new Error("ref<T>() used before .define() was called");
3395
3374
  function ref() {
3396
3375
  let resolved = null;
3397
3376
  let resolvedScalar = null;
@@ -3407,7 +3386,7 @@ function ref() {
3407
3386
  _def: {
3408
3387
  tag: "lazy",
3409
3388
  thunk: () => {
3410
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
3389
+ if (!resolved) throw UNDEFINED_REF;
3411
3390
  return resolved;
3412
3391
  }
3413
3392
  },
@@ -4069,7 +4048,7 @@ function buildFieldMap(captures) {
4069
4048
  if (!captures?.length) return void 0;
4070
4049
  const out = {};
4071
4050
  for (const cap of captures) {
4072
- const entry = { value: cap.value, span: cap.span };
4051
+ const entry = cap.leading === void 0 ? { value: cap.value, span: cap.span } : { value: cap.value, span: cap.span, leading: cap.leading, trailing: cap.trailing };
4073
4052
  const current = out[cap.name];
4074
4053
  if (current === void 0) out[cap.name] = entry;
4075
4054
  else if (Array.isArray(current)) current.push(entry);
@@ -6395,6 +6374,26 @@ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
6395
6374
  };
6396
6375
  return walk(ip, 0);
6397
6376
  }
6377
+ function largeChoiceLiteralPretest(code, constants, armIp) {
6378
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
6379
+ if (child >= 0) {
6380
+ const spec = constants[code[child + 1]];
6381
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) return [child];
6382
+ }
6383
+ const family = leadingLiteralFamily(code, constants, armIp);
6384
+ return family !== void 0 && family.length >= 2 && family.every((terminal) => {
6385
+ const value = constants[code[terminal + 1]];
6386
+ return typeof value === "string" && value.length >= 2;
6387
+ }) ? family : void 0;
6388
+ }
6389
+
6390
+ // src/table/field-spec.ts
6391
+ function fieldSpec(slot) {
6392
+ return Array.isArray(slot) ? { name: slot[0], bits: slot[1] } : { name: slot, bits: 0 };
6393
+ }
6394
+ function leadingTriviaFieldAt(code, k, ip) {
6395
+ return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
6396
+ }
6398
6397
 
6399
6398
  // src/table/emit-assembly.ts
6400
6399
  var Unemittable = class extends Error {
@@ -6469,7 +6468,11 @@ var EMITTED_PARAMS = [
6469
6468
  // Appended for old precompiled-factory ABI: old factories ignore it.
6470
6469
  "adjacencyHolds",
6471
6470
  // Appended for selected composite lexical programs; old factories ignore it.
6472
- "LEXPROG"
6471
+ "LEXPROG",
6472
+ // Appended for trivia-attributing fields (`field(…, { leadingTrivia })`);
6473
+ // old factories ignore them.
6474
+ "LEAD",
6475
+ "triviaFieldCapture"
6473
6476
  ];
6474
6477
  var RUNTIME_PRELUDE = `
6475
6478
  let _pfScan=null
@@ -6729,20 +6732,12 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
6729
6732
  if (child >= 0) scalarSpecs.add(code[child + 1]);
6730
6733
  continue;
6731
6734
  }
6732
- if (child >= 0) {
6733
- const spec = k[code[child + 1]];
6734
- if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
6735
- largeChoiceScalarSpecs.add(code[child + 1]);
6736
- continue;
6737
- }
6738
- }
6739
- const family = leadingLiteralFamily(code, k, armIp);
6740
- if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
6741
- const value = k[code[terminal + 1]];
6742
- return typeof value === "string" && value.length >= 2;
6743
- })) {
6744
- largeChoiceLiteralFamilies.set(armIp, family);
6735
+ const literals = largeChoiceLiteralPretest(code, k, armIp);
6736
+ if (literals !== void 0 && literals.length === 1 && literals[0] === child) {
6737
+ largeChoiceScalarSpecs.add(code[child + 1]);
6738
+ continue;
6745
6739
  }
6740
+ if (literals !== void 0) largeChoiceLiteralFamilies.set(armIp, literals);
6746
6741
  const sequence6 = leadingScalarSequence(code, armIp);
6747
6742
  if (sequence6 !== void 0 && (sequence6.trivia < 0 || swapLegal && t.triviaScan[sequence6.trivia] != null)) {
6748
6743
  largeChoiceScalarSequences.set(armIp, sequence6);
@@ -7166,14 +7161,31 @@ return v
7166
7161
  }`;
7167
7162
  }
7168
7163
  case OP_FIELD: {
7169
- const name = q(k[code[ip + 1]]);
7164
+ const spec = fieldSpec(k[code[ip + 1]]);
7165
+ const name = q(spec.name);
7170
7166
  const child = link(code[ip + 2]);
7171
- return `${head}
7167
+ if (spec.bits === 0) {
7168
+ return `${head}
7172
7169
  const v=${child}(input,pos,ctx)
7173
7170
  if(v===FAIL)return FAIL
7174
7171
  const f=ctx._fields
7175
7172
  if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
7176
7173
  return v
7174
+ }`;
7175
+ }
7176
+ const leading = (spec.bits & FIELD_LEADING_TRIVIA) !== 0;
7177
+ const trailing = (spec.bits & FIELD_TRAILING_TRIVIA) !== 0;
7178
+ return `${head}
7179
+ const lf=${leading ? "LEAD.at" : "-1"}
7180
+ LEAD.at=-1
7181
+ const v=${child}(input,pos,ctx)
7182
+ if(v===FAIL)return FAIL
7183
+ const e=EC.e
7184
+ const te=${trailing ? "ctx.trivia!==undefined?consumeTrivia(input,e,ctx):e" : "e"}
7185
+ const f=ctx._fields
7186
+ if(f!==undefined)f.push(triviaFieldCapture(${name},v,input,pos,e,lf,te))
7187
+ EC.e=te
7188
+ return v
7177
7189
  }`;
7178
7190
  }
7179
7191
  case OP_EXPECT: {
@@ -7469,7 +7481,10 @@ return v
7469
7481
  `if(!adjacencyHolds(input,cur,ctx,${negated ? "true" : "false"},${kinds})){ctx._fe=cur;ctx._fx=${expected};return FAIL}`,
7470
7482
  `${vn}=null`
7471
7483
  );
7472
- } else parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
7484
+ } else {
7485
+ const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
7486
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
7487
+ }
7473
7488
  names.push(vn);
7474
7489
  }
7475
7490
  parts.push("EC.e=cur");
@@ -7869,7 +7884,7 @@ let sp=cur
7869
7884
  ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
7870
7885
  ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
7871
7886
  `}ctx._fc=false
7872
- const sv=${sep}(input,sp,ctx)
7887
+ ${sepIp >= 0 && leadingTriviaFieldAt(code, k, sepIp) ? "LEAD.at=cur\n" : ""}const sv=${sep}(input,sp,ctx)
7873
7888
  if(sv===FAIL){
7874
7889
  ${rb}
7875
7890
  if(ctx._fc===true)return FAIL
@@ -8742,6 +8757,12 @@ function assemble(t, prog, cfg) {
8742
8757
  rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
8743
8758
  return cur;
8744
8759
  }
8760
+ function leadingFieldTerm(step, child, input, cur, ctx) {
8761
+ return step((i, p, c) => {
8762
+ LEAD.at = cur;
8763
+ return child(i, p, c);
8764
+ }, input, cur, ctx);
8765
+ }
8745
8766
  function committed3(c) {
8746
8767
  return c._fc === true;
8747
8768
  }
@@ -9379,12 +9400,27 @@ function assemble(t, prog, cfg) {
9379
9400
  };
9380
9401
  }
9381
9402
  case OP_FIELD: {
9382
- const name = k[code[ip + 1]];
9403
+ const { name, bits } = fieldSpec(k[code[ip + 1]]);
9383
9404
  const child = link(code[ip + 2]);
9405
+ if (bits === 0) {
9406
+ return (input, pos, ctx) => {
9407
+ const v = child(input, pos, ctx);
9408
+ if (v === FAIL) return FAIL;
9409
+ ctx._fields?.push({ name, value: v, span: { start: pos, end: EC.e } });
9410
+ return v;
9411
+ };
9412
+ }
9413
+ const leading = (bits & FIELD_LEADING_TRIVIA) !== 0;
9414
+ const trailing = (bits & FIELD_TRAILING_TRIVIA) !== 0;
9384
9415
  return (input, pos, ctx) => {
9416
+ const leadFrom = leading ? LEAD.at : -1;
9417
+ LEAD.at = -1;
9385
9418
  const v = child(input, pos, ctx);
9386
9419
  if (v === FAIL) return FAIL;
9387
- ctx._fields?.push({ name, value: v, span: { start: pos, end: EC.e } });
9420
+ const end = EC.e;
9421
+ const trailEnd = trailing && ctx.trivia !== void 0 ? consumeTrivia(input, end, ctx) : end;
9422
+ ctx._fields?.push(triviaFieldCapture(name, v, input, pos, end, leadFrom, trailEnd));
9423
+ EC.e = trailEnd;
9388
9424
  return v;
9389
9425
  };
9390
9426
  }
@@ -9818,6 +9854,12 @@ function assemble(t, prog, cfg) {
9818
9854
  const kidIp = code[base + i];
9819
9855
  if (code[kidIp] !== OP_ADJ) {
9820
9856
  const kid = link(kidIp);
9857
+ if (leadingTriviaFieldAt(code, k, kidIp)) {
9858
+ return (input, cur, ctx, inherited) => {
9859
+ ctx._sync = sync ?? inherited;
9860
+ return leadingFieldTerm(step, kid, input, cur, ctx);
9861
+ };
9862
+ }
9821
9863
  return (input, cur, ctx, inherited) => {
9822
9864
  ctx._sync = sync ?? inherited;
9823
9865
  return step(kid, input, cur, ctx);
@@ -9895,9 +9937,12 @@ function assemble(t, prog, cfg) {
9895
9937
  };
9896
9938
  }
9897
9939
  let hasAdj = false;
9898
- for (let i = 1; i < n; i++) if (code[code[base + i]] === OP_ADJ) {
9899
- hasAdj = true;
9900
- break;
9940
+ for (let i = 1; i < n; i++) {
9941
+ const kidIp = code[base + i];
9942
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
9943
+ hasAdj = true;
9944
+ break;
9945
+ }
9901
9946
  }
9902
9947
  if (hasAdj) {
9903
9948
  const first2 = link(code[base]);
@@ -9905,6 +9950,9 @@ function assemble(t, prog, cfg) {
9905
9950
  const kidIp = code[base + i];
9906
9951
  if (code[kidIp] !== OP_ADJ) {
9907
9952
  const kid = link(kidIp);
9953
+ if (leadingTriviaFieldAt(code, k, kidIp)) {
9954
+ return (input, cur, ctx) => leadingFieldTerm(step, kid, input, cur, ctx);
9955
+ }
9908
9956
  return (input, cur, ctx) => step(kid, input, cur, ctx);
9909
9957
  }
9910
9958
  const negated = code[kidIp + 1] === 1;
@@ -10267,7 +10315,7 @@ function assemble(t, prog, cfg) {
10267
10315
  if (n === 2 || n === 3) {
10268
10316
  const a0 = link(code[base]), a1 = link(code[base + 1]);
10269
10317
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
10270
- const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
10318
+ const predecide = !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
10271
10319
  const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
10272
10320
  const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
10273
10321
  const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
@@ -10490,6 +10538,75 @@ function assemble(t, prog, cfg) {
10490
10538
  );
10491
10539
  };
10492
10540
  const masked = bindMasked(0, EMPTY_EXPECTED_PREFIX);
10541
+ const pBit = [];
10542
+ const pRec = [];
10543
+ if (!REC && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
10544
+ for (let i = 0; i < n; i++) {
10545
+ for (const terminal of largeChoiceLiteralPretest(code, k, code[base + i]) ?? []) {
10546
+ pBit.push(1 << i);
10547
+ pRec.push(scalarFor(terminal));
10548
+ }
10549
+ }
10550
+ }
10551
+ const pn = pBit.length;
10552
+ if (pn !== 0) {
10553
+ return (input, pos, ctx) => {
10554
+ const c = lead(input, pos);
10555
+ const need = markCst(ctx);
10556
+ const mRaw = MRAW;
10557
+ const mTl = MTL;
10558
+ const mLv = MLV;
10559
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
10560
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
10561
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
10562
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
10563
+ if (c < 128) {
10564
+ const bits = mask[c < 0 ? 128 : c];
10565
+ let tested = 0;
10566
+ let hit = 0;
10567
+ for (let i = 0; i < pn; i++) {
10568
+ const b = pBit[i];
10569
+ if ((bits & b) === 0 || (hit & b) !== 0) continue;
10570
+ tested |= b;
10571
+ if (pRec[i](input, pos) >= 0) hit |= b;
10572
+ }
10573
+ return masked(
10574
+ input,
10575
+ pos,
10576
+ ctx,
10577
+ bits & (~tested | hit),
10578
+ need,
10579
+ mRaw,
10580
+ mTl,
10581
+ mLv,
10582
+ mFl,
10583
+ mEr,
10584
+ mLog,
10585
+ mRoot,
10586
+ void 0,
10587
+ 0,
10588
+ pos
10589
+ );
10590
+ }
10591
+ return general(
10592
+ input,
10593
+ pos,
10594
+ ctx,
10595
+ c,
10596
+ need,
10597
+ mRaw,
10598
+ mTl,
10599
+ mLv,
10600
+ mFl,
10601
+ mEr,
10602
+ mLog,
10603
+ mRoot,
10604
+ void 0,
10605
+ 0,
10606
+ pos
10607
+ );
10608
+ };
10609
+ }
10493
10610
  return (input, pos, ctx) => {
10494
10611
  const c = lead(input, pos);
10495
10612
  const need = markCst(ctx);
@@ -10651,6 +10768,7 @@ function assemble(t, prog, cfg) {
10651
10768
  const max = code[ip + 3];
10652
10769
  const sepIp = code[ip + 4];
10653
10770
  const sep = sepIp >= 0 ? link(sepIp) : void 0;
10771
+ const sepLeads = sepIp >= 0 && leadingTriviaFieldAt(code, k, sepIp);
10654
10772
  const flags = code[ip + 5];
10655
10773
  const keepSeparators = (flags & 2) !== 0;
10656
10774
  const trailingAllowed = (flags & 1) !== 0;
@@ -10690,6 +10808,7 @@ function assemble(t, prog, cfg) {
10690
10808
  let sp = cur;
10691
10809
  if (hasTrivia) sp = skipTrivia(input, sp, ctx);
10692
10810
  ctx._fc = false;
10811
+ if (sepLeads) LEAD.at = cur;
10693
10812
  const sv = sep(input, sp, ctx);
10694
10813
  if (sv === FAIL) {
10695
10814
  if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
@@ -10779,6 +10898,7 @@ function assemble(t, prog, cfg) {
10779
10898
  let sp = cur;
10780
10899
  if (hasTrivia) sp = skipTrivia(input, sp, ctx);
10781
10900
  ctx._fc = false;
10901
+ if (sepLeads) LEAD.at = cur;
10782
10902
  const sv = sep(input, sp, ctx);
10783
10903
  if (sv === FAIL) {
10784
10904
  if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
@@ -11101,20 +11221,9 @@ function assemble(t, prog, cfg) {
11101
11221
  if (child >= 0) scalarFor(child);
11102
11222
  continue;
11103
11223
  }
11104
- if (child >= 0) {
11105
- const spec = k[code[child + 1]];
11106
- if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
11107
- scalarFor(child);
11108
- continue;
11109
- }
11110
- }
11111
- const family = leadingLiteralFamily(code, k, armIp);
11112
- if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
11113
- const value = k[code[terminal + 1]];
11114
- return typeof value === "string" && value.length >= 2;
11115
- })) {
11116
- for (const terminal of family) scalarFor(terminal);
11117
- }
11224
+ const literals = largeChoiceLiteralPretest(code, k, armIp);
11225
+ if (literals !== void 0) for (const terminal of literals) scalarFor(terminal);
11226
+ if (literals !== void 0 && literals.length === 1 && literals[0] === child) continue;
11118
11227
  const sequence6 = leadingScalarSequence(code, armIp);
11119
11228
  if (sequence6 !== void 0 && (sequence6.trivia < 0 || triviaScan[sequence6.trivia] != null)) {
11120
11229
  for (const terminal of sequence6.terminals) scalarFor(terminal);
@@ -11180,7 +11289,9 @@ function assemble(t, prog, cfg) {
11180
11289
  scanTriviaCompact,
11181
11290
  t.lex,
11182
11291
  adjacencyHolds,
11183
- t.lexPrograms
11292
+ t.lexPrograms,
11293
+ LEAD,
11294
+ triviaFieldCapture
11184
11295
  );
11185
11296
  emitReached = new Set(pre.reached);
11186
11297
  }
@@ -11262,7 +11373,9 @@ function assemble(t, prog, cfg) {
11262
11373
  scanTriviaCompact,
11263
11374
  t.lex,
11264
11375
  adjacencyHolds,
11265
- t.lexPrograms
11376
+ t.lexPrograms,
11377
+ LEAD,
11378
+ triviaFieldCapture
11266
11379
  );
11267
11380
  emitReached = em.reached;
11268
11381
  } catch (e) {
@@ -11438,7 +11551,9 @@ var AssemblyCache = class {
11438
11551
  return made;
11439
11552
  }
11440
11553
  };
11441
- function tableRules(source, artifactMetadata = {}) {
11554
+ function tableRules(source, metadataOrEntry = {}) {
11555
+ const entry = typeof metadataOrEntry === "string" ? metadataOrEntry : void 0;
11556
+ const artifactMetadata = typeof metadataOrEntry === "string" ? {} : metadataOrEntry;
11442
11557
  const prog = expandCompact(source);
11443
11558
  const resolved = resolveTable(prog);
11444
11559
  const cache = new AssemblyCache(prog, resolved);
@@ -11446,7 +11561,7 @@ function tableRules(source, artifactMetadata = {}) {
11446
11561
  const skipOf = prog.scanSkipOf;
11447
11562
  let last;
11448
11563
  let selected;
11449
- return stampRuleMap(prog, {
11564
+ const map = stampRuleMap(prog, {
11450
11565
  runRule: (ri, input, pos, ctx) => {
11451
11566
  const a = selected ?? cache.forCtx(ctx);
11452
11567
  selected = void 0;
@@ -11467,6 +11582,9 @@ function tableRules(source, artifactMetadata = {}) {
11467
11582
  return a.scanSkip[skipOf?.[ri] ?? -1];
11468
11583
  }
11469
11584
  }, artifactMetadata, resolved);
11585
+ if (entry === void 0) return map;
11586
+ if (!Object.hasOwn(map, entry)) throw new Error(`tableRules: the program has no rule ${JSON.stringify(entry)}`);
11587
+ return map[entry];
11470
11588
  }
11471
11589
 
11472
11590
  // src/analysis/gating.ts
@@ -12643,6 +12761,16 @@ var Encoder = class {
12643
12761
  this.kIndex.set(key, i);
12644
12762
  return i;
12645
12763
  }
12764
+ fieldSpecIndex = /* @__PURE__ */ new Map();
12765
+ fieldSpecSlot(name, bits) {
12766
+ const key = JSON.stringify([name, bits]);
12767
+ const hit = this.fieldSpecIndex.get(key);
12768
+ if (hit !== void 0) return hit;
12769
+ const i = this.k.length;
12770
+ this.k.push([name, bits]);
12771
+ this.fieldSpecIndex.set(key, i);
12772
+ return i;
12773
+ }
12646
12774
  /**
12647
12775
  * A `notAdjacent({ kinds })` filter, pooled by its CONTENTS.
12648
12776
  *
@@ -13263,8 +13391,10 @@ var Encoder = class {
13263
13391
  for (let i = 0; i < arms.length; i++) this.code[head + 6 + i] = arms[i];
13264
13392
  return head;
13265
13393
  }
13266
- case "field":
13267
- return this.emit(OP_FIELD, this.constant(d.name), this.node(d.parser).ip);
13394
+ case "field": {
13395
+ const bits = (d.leadingTrivia === true ? FIELD_LEADING_TRIVIA : 0) | (d.trailingTrivia === true ? FIELD_TRAILING_TRIVIA : 0);
13396
+ return this.emit(OP_FIELD, bits === 0 ? this.constant(d.name) : this.fieldSpecSlot(d.name, bits), this.node(d.parser).ip);
13397
+ }
13268
13398
  case "lazy": {
13269
13399
  const refName = p._ruleName;
13270
13400
  const winner = refName === void 0 ? void 0 : this.winners?.[refName];
@@ -13702,11 +13832,15 @@ function emitTableExpression(prog, opts = {}) {
13702
13832
  const entry = opts.entry === void 0 ? "grammar" : opts.entry;
13703
13833
  const ref2 = opts.runtimeRef ?? "tableRules";
13704
13834
  const fns = opts.fnSources ?? prog.fns.map(() => "() => {}");
13705
- const close = `}${opts.metadataSource === void 0 ? "" : `,${opts.metadataSource}`})`;
13835
+ const meta = opts.metadataSource;
13836
+ if (entry !== null && meta !== void 0) {
13837
+ throw new Error("emitTableExpression: metadataSource is for the rule-map form (entry: null); a single entry carries none");
13838
+ }
13839
+ const tail = entry !== null ? `,${jsString(entry)}` : meta === void 0 ? "" : `,${meta}`;
13706
13840
  return [
13707
13841
  `/* @__PURE__ */ ${ref2}({`,
13708
13842
  ...programFields(prog, fns, opts),
13709
- entry === null ? close : `${close}[${jsString(entry)}]`
13843
+ `}${tail})`
13710
13844
  ].join("\n");
13711
13845
  }
13712
13846
  function emitFoldedModule(folded, opts = {}) {
@@ -13801,7 +13935,8 @@ function children(def, winners) {
13801
13935
  return [];
13802
13936
  }
13803
13937
  const name = resolved._ruleName;
13804
- return name && winners?.[name] ? [winners[name]] : [resolved];
13938
+ const winner = name ? winners?.[name] : void 0;
13939
+ return winner !== void 0 && winner._def !== def ? [winner] : [resolved];
13805
13940
  }
13806
13941
  default:
13807
13942
  return [];
@@ -13826,16 +13961,39 @@ function buildGrammarPlan(entry, winners) {
13826
13961
  }
13827
13962
  }
13828
13963
  }
13964
+ const selfWinnerBody = (parser) => {
13965
+ if (parser._def.tag !== "lazy" || winners === void 0) return void 0;
13966
+ const name = winnerNames.get(parser);
13967
+ if (name === void 0 || winners[name] !== parser) return void 0;
13968
+ try {
13969
+ return parser._def.thunk();
13970
+ } catch {
13971
+ return void 0;
13972
+ }
13973
+ };
13974
+ const slotsPerBody = /* @__PURE__ */ new Map();
13975
+ if (winners) {
13976
+ for (const winner of Object.values(winners)) {
13977
+ const body = selfWinnerBody(winner);
13978
+ if (body !== void 0) slotsPerBody.set(body, (slotsPerBody.get(body) ?? 0) + 1);
13979
+ }
13980
+ }
13981
+ const sharedBody = (parser) => (slotsPerBody.get(parser) ?? 0) > 1;
13982
+ const ownRule = (parser, rule) => {
13983
+ const id = `rule:${rule}`;
13984
+ definitions.set(id, { id, kind: "rule" });
13985
+ rules.set(parser, id);
13986
+ };
13829
13987
  const seen = /* @__PURE__ */ new Set();
13830
13988
  const visit = (parser, path) => {
13831
13989
  if (seen.has(parser)) return;
13832
13990
  seen.add(parser);
13833
13991
  const rule = winnerNames.get(parser) ?? parser._ruleName;
13834
- if (rule && (winnerNames.has(parser) || parser._def.tag !== "lazy")) {
13835
- const id = `rule:${rule}`;
13836
- definitions.set(id, { id, kind: "rule" });
13837
- rules.set(parser, id);
13992
+ const body = selfWinnerBody(parser);
13993
+ if (rule && body === void 0 && !sharedBody(parser) && (winnerNames.has(parser) || parser._def.tag !== "lazy")) {
13994
+ ownRule(parser, rule);
13838
13995
  }
13996
+ if (rule && body !== void 0 && sharedBody(body)) ownRule(parser, rule);
13839
13997
  if (parser._def.tag === "choice") {
13840
13998
  const ids = parser._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
13841
13999
  choices.set(parser, ids);
@@ -13856,7 +14014,13 @@ function buildGrammarPlan(entry, winners) {
13856
14014
  };
13857
14015
  const roots = Array.isArray(entry) ? entry : [entry];
13858
14016
  for (const root of roots) {
13859
- visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
14017
+ const name = winnerNames.get(root) ?? root._ruleName ?? "entry";
14018
+ const body = selfWinnerBody(root);
14019
+ if (body !== void 0 && sharedBody(body) && !seen.has(root)) {
14020
+ seen.add(root);
14021
+ ownRule(root, name);
14022
+ }
14023
+ visit(body ?? root, name);
13860
14024
  }
13861
14025
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules };
13862
14026
  }
@@ -13880,7 +14044,7 @@ function payloadKey(p, d) {
13880
14044
  case "label":
13881
14045
  return `label\0${d.label}`;
13882
14046
  case "field":
13883
- return `field\0${d.name}`;
14047
+ return `field\0${d.name}\0${d.leadingTrivia === true}\0${d.trailingTrivia === true}`;
13884
14048
  case "node":
13885
14049
  return `node\0${d.type ?? ""}\0${d.unwrap === true}\0${d.collapse === true}\0${fnKey(d.buildSrc, d.build)}`;
13886
14050
  case "transform":
@@ -15162,84 +15326,8 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
15162
15326
  return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
15163
15327
  }
15164
15328
 
15165
- // src/table/compile.ts
15166
- var ENTRY = "Entry";
15167
- function ownSource(fn) {
15168
- if (typeof fn !== "function") return null;
15169
- const text = Function.prototype.toString.call(fn);
15170
- if (!text.includes("[native code]")) return text;
15171
- const name = fn.name;
15172
- return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
15173
- }
15174
- function compile(combinator, mapFnSources, opts = {}) {
15175
- runDuplicationDiagnostic(combinator, opts.duplication);
15176
- const drain = beginCompileDegradationDrain();
15177
- let compiled = false;
15178
- try {
15179
- const out = compileImpl(combinator, mapFnSources, opts);
15180
- compiled = true;
15181
- return out;
15182
- } finally {
15183
- drain(compiled);
15184
- }
15185
- }
15186
- function compileImpl(combinator, mapFnSources, opts = {}) {
15187
- const plan = opts.coverage === true ? buildGrammarPlan(combinator) : void 0;
15188
- const settings = {
15189
- ...opts.hostMode === void 0 ? {} : { hostMode: opts.hostMode },
15190
- ...opts.trackLines === void 0 ? {} : { trackLines: opts.trackLines },
15191
- ...plan === void 0 ? {} : { coverage: plan }
15192
- };
15193
- const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
15194
- const artifact = closureArtifact(prog);
15195
- const entry = tableRules(prog)[ENTRY];
15196
- const offered = opts.fnSources ?? mapFnSources;
15197
- const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
15198
- const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
15199
- const unsourced = sources.reduce((acc, s, i) => s === null ? [...acc, i] : acc, []);
15200
- const runtimeOnly = [
15201
- ...prog.runtimeOnly ?? [],
15202
- ...unsourced.length === 0 ? [] : [`author reducer source missing for prog.fns[${unsourced.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`]
15203
- ];
15204
- const printable = runtimeOnly.length === 0;
15205
- const emitOpts = { fnSources: sources };
15206
- const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
15207
- const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
15208
- const runOnce = (input, pos, ctx) => entry(input, pos, ctx);
15209
- return {
15210
- source,
15211
- inlineExpression,
15212
- ...printable ? {} : { runtimeOnly },
15213
- // The DENOMINATOR, handed back rather than scraped out of the emitted text.
15214
- // `plugin/index.ts` prefers a compiler-supplied `coverageDefinitions` and only
15215
- // falls back to regex-scanning generated hooks; a table has no hooks to scan,
15216
- // so this is the channel.
15217
- ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
15218
- parse(input, pos = 0) {
15219
- return runOnce(input, pos, createParseContext());
15220
- },
15221
- parseWithContext(input, parseCtx, pos = 0) {
15222
- return runOnce(input, pos, parseCtx);
15223
- },
15224
- /**
15225
- * NO LONGER REFUSES. It used to throw unless the caller passed
15226
- * `{ recovery: true }`, because setting `_tolerant` on a table with no
15227
- * recovery rows would report a clean parse with an empty error list whatever
15228
- * the input — refusing was the right answer to that, and OPTIONAL RECOVERY
15229
- * was the wrong question. `compile()` requires no such flag, so the refusal
15230
- * was a `CompiledParser` contract break; recovery is now always lowered and
15231
- * there is nothing left to refuse.
15232
- */
15233
- parseWithErrors(input, pos = 0) {
15234
- const ctx = createParseContext();
15235
- const errors = [];
15236
- ctx._errors = errors;
15237
- ctx._tolerant = true;
15238
- const r = runOnce(input, pos, ctx);
15239
- return { ...r, errors };
15240
- }
15241
- };
15242
- }
15329
+ // src/cst/reflection-symbols.ts
15330
+ var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
15243
15331
 
15244
15332
  // src/cst/reflection.ts
15245
15333
  function childrenOf2(def) {
@@ -15326,6 +15414,7 @@ function collectFromCombinator(parser, out, seen, followLazy = true) {
15326
15414
  function collectGrammarReflection(ruleMap, opts) {
15327
15415
  const byType = /* @__PURE__ */ new Map();
15328
15416
  const followLazy = opts?.followLazy !== false;
15417
+ const seen = /* @__PURE__ */ new Set();
15329
15418
  for (const [, rule] of ruleMap) {
15330
15419
  if (!followLazy && rule._def.tag === "lazy") {
15331
15420
  try {
@@ -15335,7 +15424,7 @@ function collectGrammarReflection(ruleMap, opts) {
15335
15424
  }
15336
15425
  continue;
15337
15426
  }
15338
- collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
15427
+ collectFromCombinator(rule, byType, seen, followLazy);
15339
15428
  }
15340
15429
  return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
15341
15430
  }
@@ -15371,6 +15460,24 @@ function withAmbient(ruleMap, opts) {
15371
15460
  return [name, wrapped];
15372
15461
  });
15373
15462
  }
15463
+ function compileRuleMapRunnable(ruleMap, opts = {}) {
15464
+ const encoded = encodeForRun(ruleMap, opts);
15465
+ if (encoded === null) return null;
15466
+ const { prog, hostMode, plan } = encoded;
15467
+ const artifact = closureArtifact(prog);
15468
+ const reflection = collectGrammarReflection(ruleMap);
15469
+ return {
15470
+ keys: ruleMap.map(([key]) => key),
15471
+ hostMode,
15472
+ hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
15473
+ reflection,
15474
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
15475
+ // Reflection rides on the map's metadata prototype from birth. Only `compile()`
15476
+ // asks to specialise; every other caller runs the closure artifact.
15477
+ rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
15478
+ prog: artifact
15479
+ };
15480
+ }
15374
15481
  function encodeForRun(ruleMap, opts) {
15375
15482
  runDuplicationDiagnosticRules(ruleMap, opts.duplication);
15376
15483
  const encodeMap = withAmbient(ruleMap, opts);
@@ -15439,11 +15546,185 @@ function compileRuleMap(ruleMap, opts = {}) {
15439
15546
  hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
15440
15547
  reflection: collectGrammarReflection(ruleMap),
15441
15548
  ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
15442
- rules: tableRules(prog),
15549
+ rules: tableRules(artifact),
15443
15550
  prog: artifact
15444
15551
  };
15445
15552
  }
15446
15553
 
15554
+ // src/compiler/borrowed-rules.ts
15555
+ var nameOf = (c) => c._ruleName;
15556
+ function deref(c) {
15557
+ const seen = /* @__PURE__ */ new Set();
15558
+ let current = c;
15559
+ while (current._def.tag === "lazy" && !seen.has(current)) {
15560
+ seen.add(current);
15561
+ try {
15562
+ current = current._def.thunk();
15563
+ } catch {
15564
+ return void 0;
15565
+ }
15566
+ }
15567
+ return current;
15568
+ }
15569
+ function borrowedRuleReference(map) {
15570
+ const seen = /* @__PURE__ */ new Set();
15571
+ for (const [rule, self] of Object.entries(map)) {
15572
+ let found;
15573
+ const visit = (c) => {
15574
+ if (found !== void 0) return;
15575
+ if (c._def.tag === "lazy") {
15576
+ if (!winnerWrapsReference(self, c)) {
15577
+ const name = nameOf(c);
15578
+ const winner = name !== void 0 && Object.hasOwn(map, name) ? map[name] : void 0;
15579
+ if (winner !== void 0) {
15580
+ if (winnerWrapsReference(winner, c) || deref(c) === deref(winner)) return;
15581
+ found = name;
15582
+ return;
15583
+ }
15584
+ }
15585
+ if (seen.has(c)) return;
15586
+ seen.add(c);
15587
+ let body;
15588
+ try {
15589
+ body = c._def.thunk();
15590
+ } catch {
15591
+ return;
15592
+ }
15593
+ visit(body);
15594
+ return;
15595
+ }
15596
+ if (seen.has(c)) return;
15597
+ seen.add(c);
15598
+ for (const child of childrenOf(c._def)) visit(child);
15599
+ };
15600
+ visit(self);
15601
+ if (found !== void 0) return { rule, reference: found };
15602
+ }
15603
+ return void 0;
15604
+ }
15605
+ function borrowedRuleMessage(api, hit) {
15606
+ return `${api}: rule "${hit.rule}" is a rule object borrowed from another grammar, and its graph references "${hit.reference}", which this grammar also defines. The interpreter would keep the other grammar's "${hit.reference}" while a compiled table binds this grammar's, so the two would accept different input. Compose the grammar that defines "${hit.rule}" instead of borrowing its rule object, so its references resolve to this grammar's rules.`;
15607
+ }
15608
+
15609
+ // src/table/compile.ts
15610
+ var ENTRY = "Entry";
15611
+ function ownSource(fn) {
15612
+ if (typeof fn !== "function") return null;
15613
+ const text = Function.prototype.toString.call(fn);
15614
+ if (!text.includes("[native code]")) return text;
15615
+ const name = fn.name;
15616
+ return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
15617
+ }
15618
+ function compile(target, second, third) {
15619
+ if (!isCombinator(target)) return compileMap(target, second);
15620
+ return compileRoot(target, second, third);
15621
+ }
15622
+ function isCombinator(x) {
15623
+ return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
15624
+ }
15625
+ function compileMap(grammar, opts = {}) {
15626
+ const entries = [];
15627
+ for (const [key, value] of Object.entries(grammar)) {
15628
+ if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
15629
+ if (value._def.tag === "lazy") {
15630
+ try {
15631
+ value._def.thunk();
15632
+ } catch {
15633
+ continue;
15634
+ }
15635
+ }
15636
+ entries.push([key, value]);
15637
+ }
15638
+ const borrowed = borrowedRuleReference(Object.fromEntries(entries));
15639
+ if (borrowed !== void 0) throw new Error(borrowedRuleMessage("compile", borrowed));
15640
+ const drain = beginCompileDegradationDrain();
15641
+ let done = false;
15642
+ try {
15643
+ const refusals = [];
15644
+ const compiled = compileRuleMapRunnable(entries, {
15645
+ ...opts.hostMode ? { hostMode: opts.hostMode } : {},
15646
+ refusals,
15647
+ specialise: true
15648
+ });
15649
+ if (compiled === null) {
15650
+ throw new Error(`compile: this grammar could not be encoded to a table${refusals.length ? ` \u2014 ${refusals.join("; ")}` : ""}`);
15651
+ }
15652
+ done = true;
15653
+ return compiled.rules;
15654
+ } finally {
15655
+ drain(done);
15656
+ }
15657
+ }
15658
+ function compileRoot(combinator, mapFnSources, opts = {}) {
15659
+ runDuplicationDiagnostic(combinator, opts.duplication);
15660
+ const drain = beginCompileDegradationDrain();
15661
+ let compiled = false;
15662
+ try {
15663
+ const out = compileImpl(combinator, mapFnSources, opts);
15664
+ compiled = true;
15665
+ return out;
15666
+ } finally {
15667
+ drain(compiled);
15668
+ }
15669
+ }
15670
+ function compileImpl(combinator, mapFnSources, opts = {}) {
15671
+ const plan = opts.coverage === true ? buildGrammarPlan(combinator) : void 0;
15672
+ const settings = {
15673
+ ...opts.hostMode === void 0 ? {} : { hostMode: opts.hostMode },
15674
+ ...opts.trackLines === void 0 ? {} : { trackLines: opts.trackLines },
15675
+ ...plan === void 0 ? {} : { coverage: plan }
15676
+ };
15677
+ const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
15678
+ const artifact = closureArtifact(prog);
15679
+ const entry = tableRules(prog)[ENTRY];
15680
+ const offered = opts.fnSources ?? mapFnSources;
15681
+ const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
15682
+ const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
15683
+ const unsourced = sources.reduce((acc, s, i) => s === null ? [...acc, i] : acc, []);
15684
+ const runtimeOnly = [
15685
+ ...prog.runtimeOnly ?? [],
15686
+ ...unsourced.length === 0 ? [] : [`author reducer source missing for prog.fns[${unsourced.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`]
15687
+ ];
15688
+ const printable = runtimeOnly.length === 0;
15689
+ const emitOpts = { fnSources: sources };
15690
+ const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
15691
+ const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
15692
+ const runOnce = (input, pos, ctx) => entry(input, pos, ctx);
15693
+ return {
15694
+ source,
15695
+ inlineExpression,
15696
+ ...printable ? {} : { runtimeOnly },
15697
+ // The DENOMINATOR, handed back rather than scraped out of the emitted text.
15698
+ // `plugin/index.ts` prefers a compiler-supplied `coverageDefinitions` and only
15699
+ // falls back to regex-scanning generated hooks; a table has no hooks to scan,
15700
+ // so this is the channel.
15701
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
15702
+ parse(input, pos = 0) {
15703
+ return runOnce(input, pos, createParseContext());
15704
+ },
15705
+ parseWithContext(input, parseCtx, pos = 0) {
15706
+ return runOnce(input, pos, parseCtx);
15707
+ },
15708
+ /**
15709
+ * NO LONGER REFUSES. It used to throw unless the caller passed
15710
+ * `{ recovery: true }`, because setting `_tolerant` on a table with no
15711
+ * recovery rows would report a clean parse with an empty error list whatever
15712
+ * the input — refusing was the right answer to that, and OPTIONAL RECOVERY
15713
+ * was the wrong question. `compile()` requires no such flag, so the refusal
15714
+ * was a `CompiledParser` contract break; recovery is now always lowered and
15715
+ * there is nothing left to refuse.
15716
+ */
15717
+ parseWithErrors(input, pos = 0) {
15718
+ const ctx = createParseContext();
15719
+ const errors = [];
15720
+ ctx._errors = errors;
15721
+ ctx._tolerant = true;
15722
+ const r = runOnce(input, pos, ctx);
15723
+ return { ...r, errors };
15724
+ }
15725
+ };
15726
+ }
15727
+
15447
15728
  // src/table/fold.ts
15448
15729
  function tableVariants(source, name) {
15449
15730
  const folded = "base" in source ? source : expandCompactFolded(source);