parseman 0.51.2 → 0.53.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 (98) hide show
  1. package/dist/analysis/commitment.d.ts.map +1 -1
  2. package/dist/analysis/diagnostics.js +411 -28
  3. package/dist/analysis/diagnostics.js.map +3 -3
  4. package/dist/cli/index.js +6162 -6372
  5. package/dist/cli/index.js.map +3 -3
  6. package/dist/combinators/attempt.d.ts +11 -1
  7. package/dist/combinators/attempt.d.ts.map +1 -1
  8. package/dist/combinators/map.d.ts.map +1 -1
  9. package/dist/combinators/node.d.ts +6 -2
  10. package/dist/combinators/node.d.ts.map +1 -1
  11. package/dist/combinators/parser.d.ts +34 -0
  12. package/dist/combinators/parser.d.ts.map +1 -1
  13. package/dist/combinators/ref.d.ts +0 -13
  14. package/dist/combinators/ref.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/grammar-coverage-ids.d.ts.map +1 -1
  19. package/dist/compiler/ir-serialize.d.ts +10 -4
  20. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  21. package/dist/compiler/linker.d.ts +48 -91
  22. package/dist/compiler/linker.d.ts.map +1 -1
  23. package/dist/compiler/token-capability.js +4 -0
  24. package/dist/compiler/token-capability.js.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-kinds.d.ts.map +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +470 -725
  32. package/dist/index.js.map +3 -3
  33. package/dist/language-service/index.js.map +1 -1
  34. package/dist/plugin/evaluator.d.ts +38 -2
  35. package/dist/plugin/evaluator.d.ts.map +1 -1
  36. package/dist/plugin/index.d.ts.map +1 -1
  37. package/dist/plugin/index.js +1127 -544
  38. package/dist/plugin/index.js.map +3 -3
  39. package/dist/plugin/ir-eval.d.ts +21 -0
  40. package/dist/plugin/ir-eval.d.ts.map +1 -0
  41. package/dist/plugin/reducer-resolver.d.ts +6 -0
  42. package/dist/plugin/reducer-resolver.d.ts.map +1 -1
  43. package/dist/spec/index.js +555 -6086
  44. package/dist/spec/index.js.map +3 -3
  45. package/dist/spec/railroad-lib.d.ts +7 -2
  46. package/dist/spec/railroad-lib.d.ts.map +1 -1
  47. package/dist/spec/railroad.d.ts.map +1 -1
  48. package/dist/table/assemble.d.ts.map +1 -1
  49. package/dist/table/compile-rule-map.d.ts +11 -4
  50. package/dist/table/compile-rule-map.d.ts.map +1 -1
  51. package/dist/table/compile.d.ts +16 -0
  52. package/dist/table/compile.d.ts.map +1 -1
  53. package/dist/table/emit-assembly.d.ts.map +1 -1
  54. package/dist/table/encode-baseline.d.ts.map +1 -1
  55. package/dist/table/exec.d.ts.map +1 -1
  56. package/dist/table/index.js +272 -102
  57. package/dist/table/index.js.map +2 -2
  58. package/dist/table/ops.d.ts +7 -5
  59. package/dist/table/ops.d.ts.map +1 -1
  60. package/dist/table/site-labels.d.ts.map +1 -1
  61. package/dist/types.d.ts +8 -1
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/version.d.ts +1 -1
  64. package/package.json +1 -1
  65. package/src/analysis/commitment.ts +3 -1
  66. package/src/analysis/rebuild.ts +1 -1
  67. package/src/combinators/attempt.ts +26 -3
  68. package/src/combinators/first-set.ts +5 -1
  69. package/src/combinators/map.ts +5 -1
  70. package/src/combinators/node.ts +12 -3
  71. package/src/combinators/parser.ts +133 -67
  72. package/src/combinators/ref.ts +10 -1
  73. package/src/compiler/borrowed-rules.ts +88 -0
  74. package/src/compiler/compile-linkable-table.ts +1 -1
  75. package/src/compiler/grammar-coverage-ids.ts +35 -6
  76. package/src/compiler/ir-serialize.ts +13 -119
  77. package/src/compiler/linker.ts +190 -666
  78. package/src/coverage.ts +7 -5
  79. package/src/cst/reflection.ts +6 -1
  80. package/src/cst/trivia-kinds.ts +6 -0
  81. package/src/index.ts +1 -0
  82. package/src/plugin/evaluator.ts +114 -14
  83. package/src/plugin/index.ts +588 -110
  84. package/src/plugin/ir-eval.ts +165 -0
  85. package/src/plugin/reducer-resolver.ts +20 -3
  86. package/src/spec/railroad-lib.ts +18 -8
  87. package/src/spec/railroad.ts +3 -4
  88. package/src/table/assemble.ts +22 -8
  89. package/src/table/compile-rule-map.ts +18 -8
  90. package/src/table/compile.ts +61 -0
  91. package/src/table/emit-assembly.ts +8 -3
  92. package/src/table/encode-baseline.ts +5 -1
  93. package/src/table/encode.ts +13 -13
  94. package/src/table/exec.ts +6 -2
  95. package/src/table/ops.ts +7 -5
  96. package/src/table/site-labels.ts +3 -1
  97. package/src/types.ts +8 -1
  98. package/src/version.ts +1 -1
@@ -265,6 +265,10 @@ function firstSetBody(p, seen, resolve3, activeTrivia) {
265
265
  case "node":
266
266
  case "sepBy":
267
267
  case "expect":
268
+ // A transaction accepts exactly what its inner accepts. Its own `_meta` is
269
+ // the inner's construction-time set, which reads `any` when the inner opens
270
+ // with a rule reference — resolve through it like any other wrapper.
271
+ case "attempt":
268
272
  return fs3(d.parser);
269
273
  case "grammar":
270
274
  return firstSetOf(
@@ -363,6 +367,7 @@ function withRuleTrivia(trivia2, ctx, run) {
363
367
  ctx.triviaKindLabels = savedLabels;
364
368
  }
365
369
  }
370
+ var UNDEFINED_REF = new Error("ref<T>() used before .define() was called");
366
371
  function ref() {
367
372
  let resolved = null;
368
373
  let resolvedScalar = null;
@@ -378,7 +383,7 @@ function ref() {
378
383
  _def: {
379
384
  tag: "lazy",
380
385
  thunk: () => {
381
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
386
+ if (!resolved) throw UNDEFINED_REF;
382
387
  return resolved;
383
388
  }
384
389
  },
@@ -1404,6 +1409,10 @@ function peelLabel(p) {
1404
1409
  return null;
1405
1410
  }
1406
1411
  function analyzeLabeledTrivia(trivia2) {
1412
+ if (trivia2._def.tag === "trivia") {
1413
+ const own = trivia2._meta.labeledTriviaSpec;
1414
+ if (own !== void 0) return own;
1415
+ }
1407
1416
  if (trivia2 === labeledTrivia0) return labeledSpec0;
1408
1417
  if (trivia2 === labeledTrivia1) return labeledSpec1;
1409
1418
  if (trivia2 === labeledTrivia2) return labeledSpec2;
@@ -1802,6 +1811,7 @@ function collectFromCombinator(parser2, out, seen, followLazy = true) {
1802
1811
  function collectGrammarReflection(ruleMap, opts) {
1803
1812
  const byType = /* @__PURE__ */ new Map();
1804
1813
  const followLazy = opts?.followLazy !== false;
1814
+ const seen = /* @__PURE__ */ new Set();
1805
1815
  for (const [, rule] of ruleMap) {
1806
1816
  if (!followLazy && rule._def.tag === "lazy") {
1807
1817
  try {
@@ -1811,7 +1821,7 @@ function collectGrammarReflection(ruleMap, opts) {
1811
1821
  }
1812
1822
  continue;
1813
1823
  }
1814
- collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
1824
+ collectFromCombinator(rule, byType, seen, followLazy);
1815
1825
  }
1816
1826
  return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
1817
1827
  }
@@ -1842,9 +1852,26 @@ function isNamedRuleRefForAnotherRule(r, key) {
1842
1852
  const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
1843
1853
  return name !== void 0 && name !== key;
1844
1854
  }
1855
+ var claimedRules = /* @__PURE__ */ new WeakSet();
1856
+ function ownRule(p, copies) {
1857
+ if (!claimedRules.has(p) || p._meta.isTrivia) return p;
1858
+ let own = copies.get(p);
1859
+ if (own === void 0) {
1860
+ const { grammarTrivia: _t, grammarScanSkip: _s, grammarHostMode: _h, grammarTrackLines: _l, ...meta } = p._meta;
1861
+ copies.set(p, own = { ...p, _meta: meta });
1862
+ }
1863
+ return own;
1864
+ }
1845
1865
  function rules(a, b) {
1846
1866
  const factory = typeof a === "function" ? a : b;
1847
1867
  const options = typeof a === "function" ? b : a;
1868
+ const recipe = { factory, options };
1869
+ const map = linkRules([recipe]);
1870
+ Object.defineProperty(map, RULES_RECIPE, { value: [recipe], enumerable: false });
1871
+ return map;
1872
+ }
1873
+ var RULES_RECIPE = /* @__PURE__ */ Symbol.for("parseman.rulesRecipe");
1874
+ function linkRules(recipes, link) {
1848
1875
  const cache = {};
1849
1876
  const proxy = new Proxy(cache, {
1850
1877
  get(target, key) {
@@ -1858,10 +1885,18 @@ function rules(a, b) {
1858
1885
  return record[key];
1859
1886
  }
1860
1887
  });
1861
- const definitions = factory(proxy);
1862
- for (const key of Object.keys(definitions)) {
1888
+ const winners = /* @__PURE__ */ new Map();
1889
+ for (const recipe of recipes) {
1890
+ const definitions = recipe.factory(proxy);
1891
+ for (const key of Object.keys(definitions)) {
1892
+ winners.set(key, { parser: definitions[key], options: recipe.options });
1893
+ }
1894
+ }
1895
+ const keys = [...winners.keys()];
1896
+ const copies = /* @__PURE__ */ new Map();
1897
+ for (const [key, { parser: defined }] of winners) {
1863
1898
  const placeholder = cache[key];
1864
- const parser2 = definitions[key];
1899
+ const parser2 = ownRule(defined, copies);
1865
1900
  if (placeholder === parser2) {
1866
1901
  throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
1867
1902
  }
@@ -1870,7 +1905,8 @@ function rules(a, b) {
1870
1905
  placeholder.define(parser2);
1871
1906
  placeholder._meta.firstSet = parser2._meta.firstSet;
1872
1907
  placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
1873
- } else if (isNamedRuleRefForAnotherRule(parser2, key)) {
1908
+ } else if (isNamedRuleRefForAnotherRule(parser2, key) || link !== void 0) {
1909
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
1874
1910
  const alias = ref();
1875
1911
  tagRule(alias, key);
1876
1912
  alias.define(parser2);
@@ -1882,48 +1918,34 @@ function rules(a, b) {
1882
1918
  cache[key] = parser2;
1883
1919
  }
1884
1920
  }
1885
- if (options?.trivia != null) {
1886
- for (const key of Object.keys(definitions)) {
1887
- const rule = cache[key];
1888
- if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
1889
- }
1890
- }
1891
- if (options?.scanSkip != null) {
1892
- for (const key of Object.keys(definitions)) {
1893
- const rule = cache[key];
1894
- if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
1895
- }
1896
- }
1897
- if (options?.hostMode === "cst") {
1898
- for (const key of Object.keys(definitions)) {
1899
- const rule = cache[key];
1900
- if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
1901
- }
1902
- }
1903
- if (options?.trackLines === true) {
1904
- for (const key of Object.keys(definitions)) {
1905
- const rule = cache[key];
1906
- if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
1907
- }
1908
- for (const key of Object.keys(definitions)) {
1909
- const rule = cache[key];
1910
- if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
1911
- const wrapped = parser({ trackLines: true }, rule);
1912
- tagRule(wrapped, key);
1913
- wrapped._meta.grammarTrackLines = true;
1914
- cache[key] = wrapped;
1921
+ for (const key of keys) {
1922
+ const options = winners.get(key).options;
1923
+ let rule = cache[key];
1924
+ if (!rule._meta.isTrivia) {
1925
+ const meta = rule._meta;
1926
+ const trivia2 = link !== void 0 ? link.trivia : options?.trivia;
1927
+ if (trivia2 != null) meta.grammarTrivia = trivia2;
1928
+ if (options?.scanSkip != null) meta.grammarScanSkip = options.scanSkip;
1929
+ if ((link?.hostMode ?? options?.hostMode) === "cst") meta.grammarHostMode = "cst";
1930
+ if (options?.trackLines === true) {
1931
+ meta.grammarTrackLines = true;
1932
+ if (rule._def.tag !== "grammar") {
1933
+ rule = parser({ trackLines: true }, rule);
1934
+ tagRule(rule, key);
1935
+ rule._meta.grammarTrackLines = true;
1936
+ cache[key] = rule;
1937
+ }
1915
1938
  }
1916
1939
  }
1917
- }
1918
- for (const key of Object.keys(definitions)) {
1919
- markUnusedValues(cache[key]);
1940
+ markUnusedValues(rule);
1941
+ claimedRules.add(winners.get(key).parser).add(rule);
1920
1942
  }
1921
1943
  Object.defineProperty(cache, RULE_ORDER, {
1922
- value: Object.keys(definitions),
1944
+ value: keys,
1923
1945
  enumerable: false,
1924
1946
  configurable: true
1925
1947
  });
1926
- attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
1948
+ attachGrammarReflection(cache, collectGrammarReflection(keys.map((key) => [key, cache[key]])));
1927
1949
  return cache;
1928
1950
  }
1929
1951
 
@@ -4061,13 +4083,24 @@ function dispatch(selector, ...arms) {
4061
4083
  }
4062
4084
 
4063
4085
  // src/combinators/attempt.ts
4064
- function attempt(parser2) {
4086
+ function containOption(options) {
4087
+ if (options === void 0) return false;
4088
+ for (const key of Object.keys(options)) {
4089
+ if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
4090
+ }
4091
+ if (options.contain !== void 0 && typeof options.contain !== "boolean") {
4092
+ throw new TypeError("attempt(): `contain` must be a boolean");
4093
+ }
4094
+ return options.contain === true;
4095
+ }
4096
+ function attempt(parser2, options) {
4097
+ const contain = containOption(options);
4065
4098
  const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
4066
4099
  let failExpected;
4067
4100
  return {
4068
4101
  _tag: "attempt",
4069
4102
  _meta: parser2._meta,
4070
- _def: { tag: "attempt", parser: parser2 },
4103
+ _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
4071
4104
  parse(input, pos, ctx) {
4072
4105
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
4073
4106
  if (failExpected === void 0) {
@@ -4084,7 +4117,7 @@ function attempt(parser2) {
4084
4117
  rollbackCstCapture(ctx, mark);
4085
4118
  if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
4086
4119
  if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
4087
- if (result.committed) return result;
4120
+ if (result.committed && !contain) return result;
4088
4121
  return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
4089
4122
  }
4090
4123
  };
@@ -4939,7 +4972,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4939
4972
  throw new Error("node() options cannot combine project with unwrap or collapse");
4940
4973
  }
4941
4974
  const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
4942
- const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
4975
+ const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
4943
4976
  const clonesState = build ? buildReadsState(def) : project === void 0;
4944
4977
  const hasOwnFields = parserHasOwnFields(combinator);
4945
4978
  const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
@@ -5053,13 +5086,17 @@ function transform(combinator, fn) {
5053
5086
  };
5054
5087
  }
5055
5088
  function trivia(combinator) {
5056
- const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
5089
+ const labeled = analyzeLabeledTrivia(combinator);
5090
+ const kindLabels = labeled?.labels;
5057
5091
  return {
5058
5092
  _tag: combinator._tag,
5059
5093
  _meta: {
5060
5094
  ...combinator._meta,
5061
5095
  isTrivia: true,
5062
5096
  triviaScanner: fastTriviaScanner(combinator),
5097
+ // Every labeled scan of this trivia reads its spec; the module's four-slot
5098
+ // memo alone thrashes on a grammar with more than four trivia tables.
5099
+ labeledTriviaSpec: labeled,
5063
5100
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5064
5101
  },
5065
5102
  _def: { tag: "trivia", parser: combinator },
@@ -5592,10 +5629,12 @@ function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve3) {
5592
5629
  case "choice":
5593
5630
  case "sequence":
5594
5631
  return d.parsers.some((x) => mayCommitFailure(x, seen, resolve3));
5632
+ // A contained transaction reports every failure uncommitted.
5633
+ case "attempt":
5634
+ return d.contain !== true && mayCommitFailure(d.parser, seen, resolve3);
5595
5635
  case "many":
5596
5636
  case "oneOrMore":
5597
5637
  case "optional":
5598
- case "attempt":
5599
5638
  case "transform":
5600
5639
  case "label":
5601
5640
  case "field":
@@ -7704,7 +7743,7 @@ var Encoder = class {
7704
7743
  const derivedState = d.build !== void 0 ? buildReadsState(d) : noBuildCaptures;
7705
7744
  const derivedFields = d.build !== void 0 ? buildReadsFields(d) : noBuildCaptures;
7706
7745
  const wantsFields = parserHasOwnFields(d.parser) && (cstOut || derivedFields);
7707
- const flags = (cstOut || d.captureTrivia === true || d.trailingTrivia === true || derivedTrivia ? 4 : 0) | (!cstOut && omitsRaw ? 2 : 0) | (cstOut || derivedState ? 8 : 0) | (wantsFields ? 16 : 0) | (d.collapse === true ? 32 : 0) | (d.unwrap === true ? 64 : 0) | (d.trailingTrivia === true ? 128 : 0) | (d.captureTrivia === true ? 1 : 0);
7746
+ const flags = (cstOut || d.captureTrivia === true || derivedTrivia ? 4 : 0) | (!cstOut && omitsRaw ? 2 : 0) | (cstOut || derivedState ? 8 : 0) | (wantsFields ? 16 : 0) | (d.collapse === true ? 32 : 0) | (d.unwrap === true ? 64 : 0) | (d.trailingTrivia === true ? 128 : 0) | (d.captureTrivia === true ? 1 : 0);
7708
7747
  const body = this.emit(
7709
7748
  this.track ? OP_NODE_TRACK : OP_NODE,
7710
7749
  d.build === void 0 ? -1 : this.fn(d.build, d.buildSrc ?? null),
@@ -7830,7 +7869,7 @@ var Encoder = class {
7830
7869
  // A TRANSACTION IS A ROW. See `OP_ATTEMPT` for why the transparent
7831
7870
  // lowering was correct only for a choice arm.
7832
7871
  case "attempt": {
7833
- const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
7872
+ const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip, d.contain === true ? 1 : 0);
7834
7873
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7835
7874
  const fs3 = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
7836
7875
  if (fs3.kind === "any" || matchesEmpty(d.parser)) return inner;
@@ -9223,7 +9262,7 @@ function transfer(code, ip, at, hostCst) {
9223
9262
  }
9224
9263
  if (op === OP_NODE || op === OP_NODE_TRACK) {
9225
9264
  const flags = code[ip + 3];
9226
- const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags === 2 || flags === 18 || flags === 34);
9265
+ const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
9227
9266
  if (directChildren) {
9228
9267
  return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9229
9268
  }
@@ -10427,7 +10466,7 @@ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
10427
10466
  const v=${child}(input,pos,ctx)
10428
10467
  if(v!==FAIL)return v
10429
10468
  ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
10430
- if(ctx._fc===true)return FAIL
10469
+ ${code[ip + 2] === 1 ? "ctx._fc=false" : "if(ctx._fc===true)return FAIL"}
10431
10470
  ctx._fe=pos
10432
10471
  return FAIL
10433
10472
  }`;
@@ -11016,7 +11055,8 @@ return nd
11016
11055
  const unwrap = (flags & 64) !== 0;
11017
11056
  const trailingTrivia = (flags & 128) !== 0;
11018
11057
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
11019
- if (!hostCst && !tracked && build !== void 0 && proj < 0 && (flags === 2 || flags === 18 || flags === 34)) {
11058
+ const leanFlags = flags & ~128;
11059
+ if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
11020
11060
  const fields = flags === 18;
11021
11061
  const collapseChildren = flags === 34;
11022
11062
  const publish = L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? `if(sBuf!==undefined){
@@ -11061,7 +11101,8 @@ ctx._cstTriviaLog=undefined
11061
11101
  ctx.captureTrivia=false
11062
11102
  ctx._fields=${fields ? "[]" : "undefined"}
11063
11103
  const v=${child}(input,pos,ctx)
11064
- const captured=_capturedFlatChildren(flat)
11104
+ ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
11105
+ ` : ""}const captured=_capturedFlatChildren(flat)
11065
11106
  ${fields ? "const fieldMap=buildFieldMap(ctx._fields)\n" : ""}ctx._fields=sFields
11066
11107
  ctx._cstBuf=sBuf
11067
11108
  ctx._cstChildren=sCh
@@ -11681,7 +11722,7 @@ function assemble(t, prog, cfg) {
11681
11722
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
11682
11723
  pushCstLeaf(ctx, lf);
11683
11724
  }
11684
- function plainBuildNode(child, build) {
11725
+ function plainBuildNode(child, build, trailing) {
11685
11726
  return (input, pos, ctx) => {
11686
11727
  const sCh = ctx._cstChildren;
11687
11728
  const sLv = ctx._cstLeaves;
@@ -11699,6 +11740,7 @@ function assemble(t, prog, cfg) {
11699
11740
  ctx.captureTrivia = false;
11700
11741
  ctx._fields = void 0;
11701
11742
  const value = child(input, pos, ctx);
11743
+ if (trailing && value !== FAIL && ctx.trivia !== void 0) EC.e = consumeTrivia(input, EC.e, ctx);
11702
11744
  const kids = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY_CH);
11703
11745
  const rawKids = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
11704
11746
  ctx._fields = savedFields;
@@ -11726,7 +11768,7 @@ function assemble(t, prog, cfg) {
11726
11768
  while (first < children3.length && children3[first] === void 0) first++;
11727
11769
  return first === children3.length ? EMPTY_CH : children3.slice(first);
11728
11770
  }
11729
- function childrenOnlyBuildNode(child, build) {
11771
+ function childrenOnlyBuildNode(child, build, trailing) {
11730
11772
  return (input, pos, ctx) => {
11731
11773
  const sCh = ctx._cstChildren;
11732
11774
  const sLv = ctx._cstLeaves;
@@ -11744,6 +11786,7 @@ function assemble(t, prog, cfg) {
11744
11786
  ctx.captureTrivia = false;
11745
11787
  ctx._fields = void 0;
11746
11788
  const value = child(input, pos, ctx);
11789
+ if (trailing && value !== FAIL && ctx.trivia !== void 0) EC.e = consumeTrivia(input, EC.e, ctx);
11747
11790
  const captured = capturedFlatChildren(kids);
11748
11791
  ctx._fields = savedFields;
11749
11792
  ctx._cstBuf = sBuf;
@@ -12768,6 +12811,7 @@ function assemble(t, prog, cfg) {
12768
12811
  /* ── transaction ─────────────────────────────────────────────────────── */
12769
12812
  case OP_ATTEMPT: {
12770
12813
  const child = link(code[ip + 1]);
12814
+ const contain = code[ip + 2] === 1;
12771
12815
  return (input, pos, ctx) => {
12772
12816
  const need = markCst(ctx);
12773
12817
  const mRaw = MRAW;
@@ -12780,7 +12824,10 @@ function assemble(t, prog, cfg) {
12780
12824
  const v = child(input, pos, ctx);
12781
12825
  if (v !== FAIL) return v;
12782
12826
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12783
- if (committed3(ctx)) return FAIL;
12827
+ if (committed3(ctx)) {
12828
+ if (!contain) return FAIL;
12829
+ ctx._fc = false;
12830
+ }
12784
12831
  ctx._fe = pos;
12785
12832
  return FAIL;
12786
12833
  };
@@ -14231,11 +14278,11 @@ function assemble(t, prog, cfg) {
14231
14278
  const trailingTrivia = (flags & 128) !== 0;
14232
14279
  const build = buildIdx >= 0 ? fns[buildIdx] : void 0;
14233
14280
  if (!hostCst && !tracked) {
14234
- if (build !== void 0 && proj < 0 && flags === 0) {
14235
- return plainBuildNode(child, build);
14281
+ if (build !== void 0 && proj < 0 && (flags & ~128) === 0) {
14282
+ return plainBuildNode(child, build, trailingTrivia);
14236
14283
  }
14237
- if (build !== void 0 && proj < 0 && flags === 2) {
14238
- return childrenOnlyBuildNode(child, build);
14284
+ if (build !== void 0 && proj < 0 && (flags & ~128) === 2) {
14285
+ return childrenOnlyBuildNode(child, build, trailingTrivia);
14239
14286
  }
14240
14287
  if (build !== void 0 && proj < 0 && flags === 18) {
14241
14288
  return childrenOnlyFieldsBuildNode(child, build);
@@ -14987,7 +15034,8 @@ function children(def, winners) {
14987
15034
  return [];
14988
15035
  }
14989
15036
  const name = resolved._ruleName;
14990
- return name && winners?.[name] ? [winners[name]] : [resolved];
15037
+ const winner = name ? winners?.[name] : void 0;
15038
+ return winner !== void 0 && winner._def !== def ? [winner] : [resolved];
14991
15039
  }
14992
15040
  default:
14993
15041
  return [];
@@ -15012,16 +15060,39 @@ function buildGrammarPlan(entry, winners) {
15012
15060
  }
15013
15061
  }
15014
15062
  }
15063
+ const selfWinnerBody = (parser2) => {
15064
+ if (parser2._def.tag !== "lazy" || winners === void 0) return void 0;
15065
+ const name = winnerNames.get(parser2);
15066
+ if (name === void 0 || winners[name] !== parser2) return void 0;
15067
+ try {
15068
+ return parser2._def.thunk();
15069
+ } catch {
15070
+ return void 0;
15071
+ }
15072
+ };
15073
+ const slotsPerBody = /* @__PURE__ */ new Map();
15074
+ if (winners) {
15075
+ for (const winner of Object.values(winners)) {
15076
+ const body = selfWinnerBody(winner);
15077
+ if (body !== void 0) slotsPerBody.set(body, (slotsPerBody.get(body) ?? 0) + 1);
15078
+ }
15079
+ }
15080
+ const sharedBody = (parser2) => (slotsPerBody.get(parser2) ?? 0) > 1;
15081
+ const ownRule2 = (parser2, rule) => {
15082
+ const id = `rule:${rule}`;
15083
+ definitions.set(id, { id, kind: "rule" });
15084
+ rules2.set(parser2, id);
15085
+ };
15015
15086
  const seen = /* @__PURE__ */ new Set();
15016
15087
  const visit = (parser2, path3) => {
15017
15088
  if (seen.has(parser2)) return;
15018
15089
  seen.add(parser2);
15019
15090
  const rule = winnerNames.get(parser2) ?? parser2._ruleName;
15020
- if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
15021
- const id = `rule:${rule}`;
15022
- definitions.set(id, { id, kind: "rule" });
15023
- rules2.set(parser2, id);
15091
+ const body = selfWinnerBody(parser2);
15092
+ if (rule && body === void 0 && !sharedBody(parser2) && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
15093
+ ownRule2(parser2, rule);
15024
15094
  }
15095
+ if (rule && body !== void 0 && sharedBody(body)) ownRule2(parser2, rule);
15025
15096
  if (parser2._def.tag === "choice") {
15026
15097
  const ids = parser2._def.parsers.map((_, index) => `choice:${path3}/arm:${index}`);
15027
15098
  choices.set(parser2, ids);
@@ -15042,7 +15113,13 @@ function buildGrammarPlan(entry, winners) {
15042
15113
  };
15043
15114
  const roots = Array.isArray(entry) ? entry : [entry];
15044
15115
  for (const root of roots) {
15045
- visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
15116
+ const name = winnerNames.get(root) ?? root._ruleName ?? "entry";
15117
+ const body = selfWinnerBody(root);
15118
+ if (body !== void 0 && sharedBody(body) && !seen.has(root)) {
15119
+ seen.add(root);
15120
+ ownRule2(root, name);
15121
+ }
15122
+ visit(body ?? root, name);
15046
15123
  }
15047
15124
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
15048
15125
  }
@@ -16348,6 +16425,183 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
16348
16425
  return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
16349
16426
  }
16350
16427
 
16428
+ // src/table/compile-rule-map.ts
16429
+ var DEFAULT_PRECOMPILE_MIN_WORDS = 1024;
16430
+ function resolveHostMode(ruleMap, explicit) {
16431
+ return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
16432
+ }
16433
+ function resolveTrackLines(ruleMap, explicit) {
16434
+ return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
16435
+ }
16436
+ function withAmbient(ruleMap, opts) {
16437
+ if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
16438
+ const wrappers = /* @__PURE__ */ new Map();
16439
+ return ruleMap.map(([name, rule]) => {
16440
+ if (rule._meta.isTrivia) return [name, rule];
16441
+ const addTrivia = opts.trivia !== void 0 && rule._meta.grammarTrivia === void 0;
16442
+ const addScanSkip = opts.scanSkip !== void 0 && rule._meta.grammarScanSkip === void 0;
16443
+ if (!addTrivia && !addScanSkip) return [name, rule];
16444
+ let wrapped = wrappers.get(rule);
16445
+ if (wrapped === void 0) {
16446
+ wrapped = {
16447
+ ...rule,
16448
+ _meta: {
16449
+ ...rule._meta,
16450
+ ...addTrivia ? { grammarTrivia: opts.trivia } : {},
16451
+ ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
16452
+ }
16453
+ };
16454
+ wrappers.set(rule, wrapped);
16455
+ }
16456
+ return [name, wrapped];
16457
+ });
16458
+ }
16459
+ function compileRuleMapRunnable(ruleMap, opts = {}) {
16460
+ const encoded = encodeForRun(ruleMap, opts);
16461
+ if (encoded === null) return null;
16462
+ const { prog, hostMode, plan } = encoded;
16463
+ const artifact = closureArtifact(prog);
16464
+ const reflection = collectGrammarReflection(ruleMap);
16465
+ return {
16466
+ keys: ruleMap.map(([key]) => key),
16467
+ hostMode,
16468
+ hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
16469
+ reflection,
16470
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16471
+ // Reflection rides on the map's metadata prototype from birth. Only `compile()`
16472
+ // asks to specialise; every other caller runs the closure artifact.
16473
+ rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
16474
+ prog: artifact
16475
+ };
16476
+ }
16477
+ function encodeForRun(ruleMap, opts) {
16478
+ runDuplicationDiagnosticRules(ruleMap, opts.duplication);
16479
+ const encodeMap = withAmbient(ruleMap, opts);
16480
+ const plan = opts.coverage === true ? buildGrammarPlan(
16481
+ encodeMap.map(([, rule]) => rule),
16482
+ Object.fromEntries(encodeMap.filter(([, rule]) => rule._def.tag !== "lazy"))
16483
+ ) : void 0;
16484
+ const hostMode = resolveHostMode(ruleMap, opts.hostMode);
16485
+ const settings = {
16486
+ hostMode,
16487
+ ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
16488
+ ...opts.recovery === true ? { recovery: true } : {},
16489
+ ...plan === void 0 ? {} : { coverage: plan }
16490
+ };
16491
+ try {
16492
+ const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
16493
+ return { prog, fnSrcs, hostMode, plan };
16494
+ } catch (e) {
16495
+ opts.refusals?.push(e instanceof Error ? e.message : String(e));
16496
+ return null;
16497
+ }
16498
+ }
16499
+ function compileRuleMap(ruleMap, opts = {}) {
16500
+ const encoded = encodeForRun(ruleMap, opts);
16501
+ if (encoded === null) return null;
16502
+ const { prog, fnSrcs, hostMode, plan } = encoded;
16503
+ const artifact = closureArtifact(prog);
16504
+ if (artifact.runtimeOnly !== void 0 && artifact.runtimeOnly.length > 0) {
16505
+ opts.refusals?.push(...artifact.runtimeOnly);
16506
+ return null;
16507
+ }
16508
+ const supplied = opts.fnSources;
16509
+ const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? null);
16510
+ if (sources.some((s) => s === null)) {
16511
+ const missing = sources.flatMap((s, i) => s === null ? [i] : []);
16512
+ opts.refusals?.push(
16513
+ `author reducer source missing for prog.fns[${missing.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`
16514
+ );
16515
+ return null;
16516
+ }
16517
+ if (supplied !== void 0 && supplied.length > fnSrcs.length) {
16518
+ throw new Error(
16519
+ `compileRuleMap: got ${supplied.length} fnSources for a pool of ${fnSrcs.length}. The list is positional, in prog.fns order, so a longer one means it belongs to a different encode \u2014 and the entries would be silently misassigned.`
16520
+ );
16521
+ }
16522
+ const replacementWithMetadata = (metadataSource, options = {}) => emitTableExpression(artifact, {
16523
+ entry: null,
16524
+ runtimeRef: opts.runtimeRef ?? "tableRules",
16525
+ fnSources: sources,
16526
+ ...options.precompileDefault === true && hostMode === "ast" && prog.lines !== 1 && prog.code.length >= DEFAULT_PRECOMPILE_MIN_WORDS ? { assemblies: defaultAssemblyCfgs(artifact).slice(0, 1) } : {},
16527
+ ...metadataSource === void 0 ? {} : { metadataSource }
16528
+ });
16529
+ const replacement = replacementWithMetadata();
16530
+ return {
16531
+ keys: ruleMap.map(([key]) => key),
16532
+ replacement,
16533
+ replacementWithMetadata,
16534
+ hostMode,
16535
+ // WHAT THE FLAG MEANS is "a DIRECT BUILDER's positioned-CST branch was
16536
+ // dropped", which is what the driver's `'ast' artifact + CST host` check keys
16537
+ // off. `mode === 'ast'` alone over-reports it: an all-STRUCTURAL grammar has no
16538
+ // direct builder, so there was no branch to drop and it stays usable with either
16539
+ // host — the long-standing `node(parser)` contract. Same predicate codegen uses
16540
+ // for its own `hasDirectBuilders` (both read `analysis/commitment.ts`), so the two
16541
+ // lowerings stamp the same artifact rather than disagreeing about it.
16542
+ hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
16543
+ reflection: collectGrammarReflection(ruleMap),
16544
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16545
+ rules: tableRules(artifact),
16546
+ prog: artifact
16547
+ };
16548
+ }
16549
+
16550
+ // src/compiler/borrowed-rules.ts
16551
+ var nameOf = (c) => c._ruleName;
16552
+ function deref(c) {
16553
+ const seen = /* @__PURE__ */ new Set();
16554
+ let current = c;
16555
+ while (current._def.tag === "lazy" && !seen.has(current)) {
16556
+ seen.add(current);
16557
+ try {
16558
+ current = current._def.thunk();
16559
+ } catch {
16560
+ return void 0;
16561
+ }
16562
+ }
16563
+ return current;
16564
+ }
16565
+ function borrowedRuleReference(map) {
16566
+ const seen = /* @__PURE__ */ new Set();
16567
+ for (const [rule, self] of Object.entries(map)) {
16568
+ let found;
16569
+ const visit = (c) => {
16570
+ if (found !== void 0) return;
16571
+ if (c._def.tag === "lazy") {
16572
+ if (!winnerWrapsReference(self, c)) {
16573
+ const name = nameOf(c);
16574
+ const winner = name !== void 0 && Object.hasOwn(map, name) ? map[name] : void 0;
16575
+ if (winner !== void 0) {
16576
+ if (winnerWrapsReference(winner, c) || deref(c) === deref(winner)) return;
16577
+ found = name;
16578
+ return;
16579
+ }
16580
+ }
16581
+ if (seen.has(c)) return;
16582
+ seen.add(c);
16583
+ let body;
16584
+ try {
16585
+ body = c._def.thunk();
16586
+ } catch {
16587
+ return;
16588
+ }
16589
+ visit(body);
16590
+ return;
16591
+ }
16592
+ if (seen.has(c)) return;
16593
+ seen.add(c);
16594
+ for (const child of childrenOf2(c._def)) visit(child);
16595
+ };
16596
+ visit(self);
16597
+ if (found !== void 0) return { rule, reference: found };
16598
+ }
16599
+ return void 0;
16600
+ }
16601
+ function borrowedRuleMessage(api, hit) {
16602
+ 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.`;
16603
+ }
16604
+
16351
16605
  // src/table/compile.ts
16352
16606
  var ENTRY = "Entry";
16353
16607
  function ownSource(fn) {
@@ -16357,7 +16611,47 @@ function ownSource(fn) {
16357
16611
  const name = fn.name;
16358
16612
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
16359
16613
  }
16360
- function compile(combinator, mapFnSources, opts = {}) {
16614
+ function compile(target, second, third) {
16615
+ if (!isCombinator(target)) return compileMap(target, second);
16616
+ return compileRoot(target, second, third);
16617
+ }
16618
+ function isCombinator(x) {
16619
+ return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
16620
+ }
16621
+ function compileMap(grammar, opts = {}) {
16622
+ const entries = [];
16623
+ for (const [key, value] of Object.entries(grammar)) {
16624
+ if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
16625
+ if (value._def.tag === "lazy") {
16626
+ try {
16627
+ value._def.thunk();
16628
+ } catch {
16629
+ continue;
16630
+ }
16631
+ }
16632
+ entries.push([key, value]);
16633
+ }
16634
+ const borrowed = borrowedRuleReference(Object.fromEntries(entries));
16635
+ if (borrowed !== void 0) throw new Error(borrowedRuleMessage("compile", borrowed));
16636
+ const drain = beginCompileDegradationDrain();
16637
+ let done = false;
16638
+ try {
16639
+ const refusals = [];
16640
+ const compiled = compileRuleMapRunnable(entries, {
16641
+ ...opts.hostMode ? { hostMode: opts.hostMode } : {},
16642
+ refusals,
16643
+ specialise: true
16644
+ });
16645
+ if (compiled === null) {
16646
+ throw new Error(`compile: this grammar could not be encoded to a table${refusals.length ? ` \u2014 ${refusals.join("; ")}` : ""}`);
16647
+ }
16648
+ done = true;
16649
+ return compiled.rules;
16650
+ } finally {
16651
+ drain(done);
16652
+ }
16653
+ }
16654
+ function compileRoot(combinator, mapFnSources, opts = {}) {
16361
16655
  runDuplicationDiagnostic(combinator, opts.duplication);
16362
16656
  const drain = beginCompileDegradationDrain();
16363
16657
  let compiled = false;
@@ -16427,29 +16721,6 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
16427
16721
  };
16428
16722
  }
16429
16723
 
16430
- // src/combinators/withCtx.ts
16431
- function withCtx(extra, combinator) {
16432
- const meta = {
16433
- firstSet: combinator._meta.firstSet,
16434
- canMatchNewline: combinator._meta.canMatchNewline,
16435
- isTrivia: false
16436
- };
16437
- return {
16438
- _tag: "withCtx",
16439
- _meta: meta,
16440
- _def: { tag: "withCtx", extra, parser: combinator },
16441
- parse(input, pos, ctx) {
16442
- const saved = ctx.state;
16443
- ctx.state = extra;
16444
- try {
16445
- return combinator.parse(input, pos, ctx);
16446
- } finally {
16447
- ctx.state = saved;
16448
- }
16449
- }
16450
- };
16451
- }
16452
-
16453
16724
  // src/compiler/ir-serialize.ts
16454
16725
  function childrenOf3(def) {
16455
16726
  switch (def.tag) {
@@ -16546,195 +16817,28 @@ function serializeRuleMap(ruleMap, scanSkip) {
16546
16817
  throw e;
16547
16818
  }
16548
16819
  }
16549
- function evalRuleMapIR(ir) {
16550
- const _tf = (child, src, recognitionOnly = false) => {
16551
- let fn2;
16552
- try {
16553
- fn2 = (0, eval)(`(${src})`);
16554
- } catch {
16555
- fn2 = () => {
16556
- throw new Error("IR transform fn not materialized");
16557
- };
16558
- }
16559
- const t = transform(child, fn2);
16560
- t._def.fnSrc = src;
16561
- if (recognitionOnly) t._def.recognitionOnly = true;
16562
- return t;
16563
- };
16564
- const _lf = (child, src, source = false) => {
16565
- let fn2;
16566
- try {
16567
- fn2 = (0, eval)(`(${src})`);
16568
- } catch {
16569
- fn2 = () => {
16570
- throw new Error("IR leaf fn not materialized");
16571
- };
16572
- }
16573
- const l = source ? sourceLeaf(child, fn2) : leaf(child, fn2);
16574
- l._def.fnSrc = src;
16575
- return l;
16576
- };
16577
- const _nd = (type, child, src, opts, staticError, sigSrc, buildImports, rawUnused) => {
16578
- if (staticError !== void 0 && staticError.length > 0) {
16579
- throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
16580
- }
16581
- const n = node(type, child, (() => {
16582
- throw new Error("IR node build requires static re-lowering");
16583
- }), opts);
16584
- n._def.buildSrc = src;
16585
- if (staticError !== void 0) n._def.buildStaticError = staticError;
16586
- if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
16587
- if (rawUnused === true) n._def.buildRawUnused = true;
16588
- if (buildImports !== void 0) n._def.buildImports = buildImports;
16589
- return n;
16590
- };
16591
- const _gch = (items) => {
16592
- const gateSrcs = [];
16593
- const arms = items.map((it) => {
16594
- if (Array.isArray(it)) {
16595
- const [src, comb] = it;
16596
- gateSrcs.push(src);
16597
- let gate2;
16598
- try {
16599
- gate2 = (0, eval)(`(${src})`);
16600
- } catch {
16601
- gate2 = () => {
16602
- throw new Error("IR gate fn not materialized");
16603
- };
16604
- }
16605
- return { gate: gate2, combinator: comb };
16606
- }
16607
- gateSrcs.push(null);
16608
- return it;
16609
- });
16610
- const c = choice(...arms);
16611
- const gates = c._def.gates;
16612
- if (gates && gates.length !== gateSrcs.length) {
16613
- throw new Error(`_gch: gateSrcs length ${gateSrcs.length} != choice gates length ${gates.length}`);
16614
- }
16615
- ;
16616
- c._def.gateSrcs = gateSrcs;
16617
- return c;
16618
- };
16619
- const _wc = (src, inner) => {
16620
- let extra;
16621
- try {
16622
- extra = (0, eval)(`(${src})`);
16623
- } catch {
16624
- extra = void 0;
16625
- }
16626
- const w = withCtx(extra, inner);
16627
- w._def.extraSrc = src;
16628
- return w;
16629
- };
16630
- const fn = new Function(
16631
- "rules",
16632
- "ref",
16633
- "regex",
16634
- "literal",
16635
- "keywords",
16636
- "sequence",
16637
- "choice",
16638
- "dispatch",
16639
- "when",
16640
- "startsWith",
16641
- "endsWith",
16642
- "matches",
16643
- "otherwise",
16644
- "routed",
16645
- "attempt",
16646
- "many",
16647
- "oneOrMore",
16648
- "optional",
16649
- "sepBy",
16650
- "keepSeparator",
16651
- "not",
16652
- "peek",
16653
- "node",
16654
- "parser",
16655
- "scanTo",
16656
- "balanced",
16657
- "token",
16658
- "leaf",
16659
- "transform",
16660
- "trivia",
16661
- "classifiedTrivia",
16662
- "label",
16663
- "field",
16664
- "expect",
16665
- "adjacent",
16666
- "notAdjacent",
16667
- "_tf",
16668
- "_lf",
16669
- "_nd",
16670
- "_gch",
16671
- "_wc",
16672
- `return (${ir})`
16673
- );
16674
- const map = fn(
16675
- rules,
16676
- ref,
16677
- regex,
16678
- literal,
16679
- keywords,
16680
- sequence,
16681
- choice,
16682
- dispatch,
16683
- when,
16684
- startsWith,
16685
- endsWith,
16686
- matches,
16687
- otherwise,
16688
- routed,
16689
- attempt,
16690
- many,
16691
- oneOrMore,
16692
- optional,
16693
- sepBy,
16694
- keepSeparator,
16695
- not,
16696
- peek,
16697
- node,
16698
- parser,
16699
- scanTo,
16700
- balanced,
16701
- token,
16702
- leaf,
16703
- transform,
16704
- trivia,
16705
- classifiedTrivia,
16706
- label,
16707
- field,
16708
- expect,
16709
- adjacent,
16710
- notAdjacent,
16711
- _tf,
16712
- _lf,
16713
- _nd,
16714
- _gch,
16715
- _wc
16716
- );
16717
- return Object.entries(map);
16718
- }
16719
- var Serializer = class {
16720
- counts = /* @__PURE__ */ new Map();
16721
- selfRef = /* @__PURE__ */ new Set();
16722
- // combinators reached by an unnamed lazy pointing back into their own subtree
16723
- cycleInterior = /* @__PURE__ */ new Set();
16724
- // combinators lying ON a self-reference cycle (strictly below its target)
16725
- constName = /* @__PURE__ */ new Map();
16726
- emitted = /* @__PURE__ */ new Set();
16727
- decls = [];
16728
- ruleValues = /* @__PURE__ */ new Set();
16729
- localRuleNames = /* @__PURE__ */ new Map();
16730
- ruleMap;
16731
- scanSkip;
16732
- constructor(ruleMap, scanSkip = []) {
16733
- this.ruleMap = ruleMap;
16734
- this.scanSkip = scanSkip;
16735
- for (const [name, c] of ruleMap) {
16736
- this.localRuleNames.set(c, name);
16737
- this.ruleValues.add(this.body(c));
16820
+ function serializeCombinator(c) {
16821
+ return serializeRuleMap([], [c]);
16822
+ }
16823
+ var Serializer = class {
16824
+ counts = /* @__PURE__ */ new Map();
16825
+ selfRef = /* @__PURE__ */ new Set();
16826
+ // combinators reached by an unnamed lazy pointing back into their own subtree
16827
+ cycleInterior = /* @__PURE__ */ new Set();
16828
+ // combinators lying ON a self-reference cycle (strictly below its target)
16829
+ constName = /* @__PURE__ */ new Map();
16830
+ emitted = /* @__PURE__ */ new Set();
16831
+ decls = [];
16832
+ ruleValues = /* @__PURE__ */ new Set();
16833
+ localRuleNames = /* @__PURE__ */ new Map();
16834
+ ruleMap;
16835
+ scanSkip;
16836
+ constructor(ruleMap, scanSkip = []) {
16837
+ this.ruleMap = ruleMap;
16838
+ this.scanSkip = scanSkip;
16839
+ for (const [name, c] of ruleMap) {
16840
+ this.localRuleNames.set(c, name);
16841
+ this.ruleValues.add(this.body(c));
16738
16842
  }
16739
16843
  }
16740
16844
  /** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
@@ -16954,7 +17058,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
16954
17058
  case "optional":
16955
17059
  return `optional(${kid(def.parser)})`;
16956
17060
  case "attempt":
16957
- return `attempt(${kid(def.parser)})`;
17061
+ return `attempt(${kid(def.parser)}${def.contain === true ? ", { contain: true }" : ""})`;
16958
17062
  // `keepSeparators` is an opt-in expressed at the SEPARATOR, not in the options
16959
17063
  // bag, so it must round-trip as `keepSeparator(sep)` — serializing it as an
16960
17064
  // option would reconstruct a grammar whose call site no longer states its own
@@ -17042,127 +17146,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
17042
17146
  }
17043
17147
  };
17044
17148
 
17045
- // src/table/compile-rule-map.ts
17046
- var DEFAULT_PRECOMPILE_MIN_WORDS = 1024;
17047
- function resolveHostMode(ruleMap, explicit) {
17048
- return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
17049
- }
17050
- function resolveTrackLines(ruleMap, explicit) {
17051
- return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
17052
- }
17053
- function withAmbient(ruleMap, opts) {
17054
- if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
17055
- const wrappers = /* @__PURE__ */ new Map();
17056
- return ruleMap.map(([name, rule]) => {
17057
- if (rule._meta.isTrivia) return [name, rule];
17058
- const addTrivia = opts.trivia !== void 0 && rule._meta.grammarTrivia === void 0;
17059
- const addScanSkip = opts.scanSkip !== void 0 && rule._meta.grammarScanSkip === void 0;
17060
- if (!addTrivia && !addScanSkip) return [name, rule];
17061
- let wrapped = wrappers.get(rule);
17062
- if (wrapped === void 0) {
17063
- wrapped = {
17064
- ...rule,
17065
- _meta: {
17066
- ...rule._meta,
17067
- ...addTrivia ? { grammarTrivia: opts.trivia } : {},
17068
- ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
17069
- }
17070
- };
17071
- wrappers.set(rule, wrapped);
17072
- }
17073
- return [name, wrapped];
17074
- });
17075
- }
17076
- function compileRuleMapRunnable(ruleMap, opts = {}) {
17077
- const encoded = encodeForRun(ruleMap, opts);
17078
- if (encoded === null) return null;
17079
- const { prog, hostMode, plan } = encoded;
17080
- const artifact = closureArtifact(prog);
17081
- return {
17082
- keys: ruleMap.map(([key]) => key),
17083
- hostMode,
17084
- hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
17085
- reflection: collectGrammarReflection(ruleMap),
17086
- ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
17087
- rules: tableRules(prog),
17088
- prog: artifact
17089
- };
17090
- }
17091
- function encodeForRun(ruleMap, opts) {
17092
- runDuplicationDiagnosticRules(ruleMap, opts.duplication);
17093
- const encodeMap = withAmbient(ruleMap, opts);
17094
- const plan = opts.coverage === true ? buildGrammarPlan(
17095
- encodeMap.map(([, rule]) => rule),
17096
- Object.fromEntries(encodeMap.filter(([, rule]) => rule._def.tag !== "lazy"))
17097
- ) : void 0;
17098
- const hostMode = resolveHostMode(ruleMap, opts.hostMode);
17099
- const settings = {
17100
- hostMode,
17101
- ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
17102
- ...opts.recovery === true ? { recovery: true } : {},
17103
- ...plan === void 0 ? {} : { coverage: plan }
17104
- };
17105
- try {
17106
- const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
17107
- return { prog, fnSrcs, hostMode, plan };
17108
- } catch (e) {
17109
- opts.refusals?.push(e instanceof Error ? e.message : String(e));
17110
- return null;
17111
- }
17112
- }
17113
- function compileRuleMap(ruleMap, opts = {}) {
17114
- const encoded = encodeForRun(ruleMap, opts);
17115
- if (encoded === null) return null;
17116
- const { prog, fnSrcs, hostMode, plan } = encoded;
17117
- const artifact = closureArtifact(prog);
17118
- if (artifact.runtimeOnly !== void 0 && artifact.runtimeOnly.length > 0) {
17119
- opts.refusals?.push(...artifact.runtimeOnly);
17120
- return null;
17121
- }
17122
- const supplied = opts.fnSources;
17123
- const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? null);
17124
- if (sources.some((s) => s === null)) {
17125
- const missing = sources.flatMap((s, i) => s === null ? [i] : []);
17126
- opts.refusals?.push(
17127
- `author reducer source missing for prog.fns[${missing.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`
17128
- );
17129
- return null;
17130
- }
17131
- if (supplied !== void 0 && supplied.length > fnSrcs.length) {
17132
- throw new Error(
17133
- `compileRuleMap: got ${supplied.length} fnSources for a pool of ${fnSrcs.length}. The list is positional, in prog.fns order, so a longer one means it belongs to a different encode \u2014 and the entries would be silently misassigned.`
17134
- );
17135
- }
17136
- const replacementWithMetadata = (metadataSource, options = {}) => emitTableExpression(artifact, {
17137
- entry: null,
17138
- runtimeRef: opts.runtimeRef ?? "tableRules",
17139
- fnSources: sources,
17140
- ...options.precompileDefault === true && hostMode === "ast" && prog.lines !== 1 && prog.code.length >= DEFAULT_PRECOMPILE_MIN_WORDS ? { assemblies: defaultAssemblyCfgs(artifact).slice(0, 1) } : {},
17141
- ...metadataSource === void 0 ? {} : { metadataSource }
17142
- });
17143
- const replacement = replacementWithMetadata();
17144
- return {
17145
- keys: ruleMap.map(([key]) => key),
17146
- replacement,
17147
- replacementWithMetadata,
17148
- hostMode,
17149
- // WHAT THE FLAG MEANS is "a DIRECT BUILDER's positioned-CST branch was
17150
- // dropped", which is what the driver's `'ast' artifact + CST host` check keys
17151
- // off. `mode === 'ast'` alone over-reports it: an all-STRUCTURAL grammar has no
17152
- // direct builder, so there was no branch to drop and it stays usable with either
17153
- // host — the long-standing `node(parser)` contract. Same predicate codegen uses
17154
- // for its own `hasDirectBuilders` (both read `analysis/commitment.ts`), so the two
17155
- // lowerings stamp the same artifact rather than disagreeing about it.
17156
- hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
17157
- reflection: collectGrammarReflection(ruleMap),
17158
- ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
17159
- rules: tableRules(prog),
17160
- prog: artifact
17161
- };
17162
- }
17163
-
17164
17149
  // src/version.ts
17165
- var PARSEMAN_VERSION = "0.51.2";
17150
+ var PARSEMAN_VERSION = "0.53.0";
17166
17151
 
17167
17152
  // src/compiler/compile-linkable-table.ts
17168
17153
  function isLocal(rule) {
@@ -17274,6 +17259,29 @@ function gate(predicate) {
17274
17259
  };
17275
17260
  }
17276
17261
 
17262
+ // src/combinators/withCtx.ts
17263
+ function withCtx(extra, combinator) {
17264
+ const meta = {
17265
+ firstSet: combinator._meta.firstSet,
17266
+ canMatchNewline: combinator._meta.canMatchNewline,
17267
+ isTrivia: false
17268
+ };
17269
+ return {
17270
+ _tag: "withCtx",
17271
+ _meta: meta,
17272
+ _def: { tag: "withCtx", extra, parser: combinator },
17273
+ parse(input, pos, ctx) {
17274
+ const saved = ctx.state;
17275
+ ctx.state = extra;
17276
+ try {
17277
+ return combinator.parse(input, pos, ctx);
17278
+ } finally {
17279
+ ctx.state = saved;
17280
+ }
17281
+ }
17282
+ };
17283
+ }
17284
+
17277
17285
  // src/plugin/direct-builder-static.ts
17278
17286
  import { parseSync } from "oxc-parser";
17279
17287
  var STATIC_BUILDER_GLOBALS = /* @__PURE__ */ new Set([
@@ -17559,6 +17567,41 @@ var _builderImports = null;
17559
17567
  function setBuilderImportResolver(r) {
17560
17568
  _builderImports = r;
17561
17569
  }
17570
+ var ModuleScope = class _ModuleScope extends Map {
17571
+ tried = /* @__PURE__ */ new Map();
17572
+ resolveFree;
17573
+ unresolved;
17574
+ constructor(resolveFree, unresolved) {
17575
+ super();
17576
+ this.resolveFree = resolveFree;
17577
+ this.unresolved = unresolved;
17578
+ }
17579
+ has(name) {
17580
+ return super.has(name) || this.resolve(name);
17581
+ }
17582
+ get(name) {
17583
+ if (super.has(name) || this.resolve(name)) return super.get(name);
17584
+ const why = this.tried.get(name);
17585
+ if (why !== void 0) this.unresolved.add(`\`${name}\` ${why}`);
17586
+ return void 0;
17587
+ }
17588
+ /** A child scope (a factory body) that keeps resolving this module's free names. */
17589
+ fork() {
17590
+ const child = new _ModuleScope(this.resolveFree, this.unresolved);
17591
+ for (const [k, v] of super.entries()) child.set(k, v);
17592
+ return child;
17593
+ }
17594
+ resolve(name) {
17595
+ if (this.tried.has(name)) return false;
17596
+ const r = this.resolveFree(name);
17597
+ if (r !== null && "value" in r) {
17598
+ super.set(name, r.value);
17599
+ return true;
17600
+ }
17601
+ if (r !== null) this.tried.set(name, r.unresolved);
17602
+ return false;
17603
+ }
17604
+ };
17562
17605
  function isWordFactory(v) {
17563
17606
  return !!v && typeof v === "object" && v.tag === "wordFactory";
17564
17607
  }
@@ -17611,7 +17654,7 @@ var SUPPORTED = {
17611
17654
  word: (...a) => word(a[0], a[1], a[2]),
17612
17655
  sequence: (...a) => sequence(...a),
17613
17656
  choice: (...a) => choice(...a),
17614
- attempt: (...a) => attempt(a[0]),
17657
+ attempt: (...a) => attempt(a[0], a[1]),
17615
17658
  optional: (...a) => optional(a[0]),
17616
17659
  trivia: (...a) => trivia(a[0]),
17617
17660
  classifiedTrivia: (...a) => classifiedTrivia(
@@ -17682,7 +17725,7 @@ function dispatchArmValue(node2, scope, code, mfs) {
17682
17725
  if (!keyArg || !parserArg || extraArg !== void 0 || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
17683
17726
  const key = anyValue(keyArg, scope, code, mfs);
17684
17727
  const parserValue = anyValue(parserArg, scope, code, mfs);
17685
- if (!isCombinator(parserValue)) return null;
17728
+ if (!isCombinator2(parserValue)) return null;
17686
17729
  const opts = { caseInsensitive: factory.caseInsensitive };
17687
17730
  if (typeof key === "string") return when(key, parserValue, opts);
17688
17731
  if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
@@ -17693,7 +17736,7 @@ function dispatchArmValue(node2, scope, code, mfs) {
17693
17736
  const [parserArg] = node2.arguments;
17694
17737
  if (!parserArg || parserArg.type === "SpreadElement") return null;
17695
17738
  const parserValue = anyValue(parserArg, scope, code, mfs);
17696
- if (!isCombinator(parserValue)) return null;
17739
+ if (!isCombinator2(parserValue)) return null;
17697
17740
  return otherwise(parserValue);
17698
17741
  }
17699
17742
  if (callee.name === "when") {
@@ -17703,24 +17746,24 @@ function dispatchArmValue(node2, scope, code, mfs) {
17703
17746
  const parserValue = anyValue(parserArg, scope, code, mfs);
17704
17747
  const opts = dispatchWhenOptions(optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs));
17705
17748
  if (opts === null) return null;
17706
- if (!isCombinator(parserValue)) return null;
17749
+ if (!isCombinator2(parserValue)) return null;
17707
17750
  if (typeof key === "string") return when(key, parserValue, opts);
17708
17751
  if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
17709
17752
  if (isDispatchMatcher(key)) return when(key, parserValue, opts);
17710
17753
  }
17711
17754
  return null;
17712
17755
  }
17713
- function isCombinator(v) {
17756
+ function isCombinator2(v) {
17714
17757
  return !!v && typeof v === "object" && "_def" in v;
17715
17758
  }
17716
17759
  function isDispatchArm(v) {
17717
17760
  if (!v || typeof v !== "object") return false;
17718
17761
  const rec = v;
17719
- if (rec.kind === "otherwise") return isCombinator(rec.parser);
17762
+ if (rec.kind === "otherwise") return isCombinator2(rec.parser);
17720
17763
  if (rec.kind === "whenMatcher") {
17721
- return isDispatchMatcher(rec.matcher) && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
17764
+ return isDispatchMatcher(rec.matcher) && typeof rec.caseInsensitive === "boolean" && isCombinator2(rec.parser);
17722
17765
  }
17723
- return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
17766
+ return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && typeof rec.caseInsensitive === "boolean" && isCombinator2(rec.parser);
17724
17767
  }
17725
17768
  function isDispatchMatcher(v) {
17726
17769
  if (!v || typeof v !== "object") return false;
@@ -17735,7 +17778,7 @@ function scopeGet(scope, name, mfs) {
17735
17778
  if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
17736
17779
  return entry.combi;
17737
17780
  }
17738
- if (isCombinator(entry)) return entry;
17781
+ if (isCombinator2(entry)) return entry;
17739
17782
  return null;
17740
17783
  }
17741
17784
  function unwrapStaticExpr(expr) {
@@ -17787,7 +17830,7 @@ function scopedStaticValue(expr, scope) {
17787
17830
  return { found: true, value };
17788
17831
  }
17789
17832
  function staticNodeOptionsFromValue(value) {
17790
- if (value === null || typeof value !== "object" || Array.isArray(value) || isCombinator(value)) return STATIC_NODE_OPTIONS_NOT_OPTIONS;
17833
+ if (value === null || typeof value !== "object" || Array.isArray(value) || isCombinator2(value)) return STATIC_NODE_OPTIONS_NOT_OPTIONS;
17791
17834
  const opts = {};
17792
17835
  const rec = value;
17793
17836
  for (const name of Object.keys(rec)) {
@@ -17839,6 +17882,13 @@ function staticNodeOptions(expr, scope) {
17839
17882
  }
17840
17883
  return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 || opts.buildArity !== void 0 ? opts : void 0;
17841
17884
  }
17885
+ var UNKNOWN_OPTIONS = /* @__PURE__ */ Symbol("parseman.unknownOptions");
17886
+ function scanOptions(optsArg, scope, code) {
17887
+ if (optsArg === void 0) return void 0;
17888
+ if (optsArg.type === "SpreadElement") return UNKNOWN_OPTIONS;
17889
+ const opts = anyValue(optsArg, scope, code, []);
17890
+ return isHole(optsArg, opts, scope) ? UNKNOWN_OPTIONS : opts;
17891
+ }
17842
17892
  function exprToCombi(node2, scope, code, mfs) {
17843
17893
  if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
17844
17894
  if (node2.type !== "CallExpression") return null;
@@ -17874,7 +17924,7 @@ function exprToCombi(node2, scope, code, mfs) {
17874
17924
  const [parserArg, fnArg] = node2.arguments;
17875
17925
  if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
17876
17926
  const inner = anyValue(parserArg, scope, code, mfs);
17877
- if (!isCombinator(inner)) return null;
17927
+ if (!isCombinator2(inner)) return null;
17878
17928
  const fnSrc = stripTsFromSource(fnArg, code);
17879
17929
  mfs.push(fnSrc);
17880
17930
  try {
@@ -17889,7 +17939,7 @@ function exprToCombi(node2, scope, code, mfs) {
17889
17939
  const [parserArg, fnArg] = node2.arguments;
17890
17940
  if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
17891
17941
  const inner = anyValue(parserArg, scope, code, mfs);
17892
- if (!isCombinator(inner)) return null;
17942
+ if (!isCombinator2(inner)) return null;
17893
17943
  const fnSrc = stripTsFromSource(fnArg, code);
17894
17944
  mfs.push(fnSrc);
17895
17945
  try {
@@ -17910,7 +17960,7 @@ function exprToCombi(node2, scope, code, mfs) {
17910
17960
  const optsArg = explicitType !== void 0 ? fourthArg : thirdArg;
17911
17961
  if (!parserArg || parserArg.type === "SpreadElement") return null;
17912
17962
  const inner = anyValue(parserArg, scope, code, mfs);
17913
- if (!isCombinator(inner)) return null;
17963
+ if (!isCombinator2(inner)) return null;
17914
17964
  const be = buildArg;
17915
17965
  const buildExpr = be === void 0 || be.type === "SpreadElement" ? void 0 : unwrapStaticExpr(be);
17916
17966
  const buildArgOptions = be !== void 0 && be.type !== "SpreadElement" ? staticNodeOptions(buildArg, scope) : STATIC_NODE_OPTIONS_NOT_OPTIONS;
@@ -17984,7 +18034,7 @@ function exprToCombi(node2, scope, code, mfs) {
17984
18034
  const opts = anyValue(optsArg, scope, code, []);
17985
18035
  if (!opts || typeof opts !== "object") return null;
17986
18036
  const root = anyValue(rootArg, scope, code, mfs);
17987
- if (!isCombinator(root)) return null;
18037
+ if (!isCombinator2(root)) return null;
17988
18038
  try {
17989
18039
  return parser(opts, root);
17990
18040
  } catch {
@@ -17996,10 +18046,10 @@ function exprToCombi(node2, scope, code, mfs) {
17996
18046
  if (!itemArg || !sepArg || itemArg.type === "SpreadElement" || sepArg.type === "SpreadElement") return null;
17997
18047
  const itemMfs = [];
17998
18048
  const itemCombi = anyValue(itemArg, scope, code, itemMfs);
17999
- if (!isCombinator(itemCombi)) return null;
18049
+ if (!isCombinator2(itemCombi)) return null;
18000
18050
  const sepMfs = [];
18001
18051
  const sepCombi = anyValue(sepArg, scope, code, sepMfs);
18002
- if (!isCombinator(sepCombi)) return null;
18052
+ if (!isCombinator2(sepCombi)) return null;
18003
18053
  let opts;
18004
18054
  if (optsArg) {
18005
18055
  if (optsArg.type === "SpreadElement") return null;
@@ -18019,7 +18069,7 @@ function exprToCombi(node2, scope, code, mfs) {
18019
18069
  if (!itemArg || itemArg.type === "SpreadElement") return null;
18020
18070
  const itemMfs = [];
18021
18071
  const itemCombi = anyValue(itemArg, scope, code, itemMfs);
18022
- if (!isCombinator(itemCombi)) return null;
18072
+ if (!isCombinator2(itemCombi)) return null;
18023
18073
  let opts;
18024
18074
  if (optsArg) {
18025
18075
  if (optsArg.type === "SpreadElement") return null;
@@ -18041,7 +18091,7 @@ function exprToCombi(node2, scope, code, mfs) {
18041
18091
  const [innerArg] = node2.arguments;
18042
18092
  if (!innerArg || innerArg.type === "SpreadElement") return null;
18043
18093
  const inner = anyValue(innerArg, scope, code, mfs);
18044
- if (!isCombinator(inner)) return null;
18094
+ if (!isCombinator2(inner)) return null;
18045
18095
  try {
18046
18096
  return not(inner);
18047
18097
  } catch {
@@ -18052,7 +18102,7 @@ function exprToCombi(node2, scope, code, mfs) {
18052
18102
  const [innerArg] = node2.arguments;
18053
18103
  if (!innerArg || innerArg.type === "SpreadElement") return null;
18054
18104
  const inner = anyValue(innerArg, scope, code, mfs);
18055
- if (!isCombinator(inner)) return null;
18105
+ if (!isCombinator2(inner)) return null;
18056
18106
  try {
18057
18107
  return peek(inner);
18058
18108
  } catch {
@@ -18065,7 +18115,8 @@ function exprToCombi(node2, scope, code, mfs) {
18065
18115
  const open = anyValue(openArg, scope, code, []);
18066
18116
  const close = anyValue(closeArg, scope, code, []);
18067
18117
  if (typeof open !== "string" || typeof close !== "string") return null;
18068
- const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
18118
+ const opts = scanOptions(optsArg, scope, code);
18119
+ if (opts === UNKNOWN_OPTIONS) return null;
18069
18120
  try {
18070
18121
  return balanced(open, close, opts);
18071
18122
  } catch {
@@ -18076,8 +18127,9 @@ function exprToCombi(node2, scope, code, mfs) {
18076
18127
  const [sentinelArg, optsArg] = node2.arguments;
18077
18128
  if (!sentinelArg || sentinelArg.type === "SpreadElement") return null;
18078
18129
  const sentinel = anyValue(sentinelArg, scope, code, []);
18079
- if (!isCombinator(sentinel)) return null;
18080
- const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
18130
+ if (!isCombinator2(sentinel)) return null;
18131
+ const opts = scanOptions(optsArg, scope, code);
18132
+ if (opts === UNKNOWN_OPTIONS) return null;
18081
18133
  try {
18082
18134
  return scanTo(sentinel, opts);
18083
18135
  } catch {
@@ -18106,7 +18158,7 @@ function exprToCombi(node2, scope, code, mfs) {
18106
18158
  const extraSrc = stripTsFromSource(extraArg, code);
18107
18159
  mfs.push(extraSrc);
18108
18160
  const inner = anyValue(innerArg, scope, code, mfs);
18109
- if (!isCombinator(inner)) return null;
18161
+ if (!isCombinator2(inner)) return null;
18110
18162
  try {
18111
18163
  const evaluated = anyValue(extraArg, scope, code, []);
18112
18164
  const usable = typeof evaluated === "object" && evaluated !== null && !Array.isArray(evaluated) && Object.getPrototypeOf(evaluated) === Object.prototype;
@@ -18122,7 +18174,7 @@ function exprToCombi(node2, scope, code, mfs) {
18122
18174
  const [selectorArg, ...armArgs] = node2.arguments;
18123
18175
  if (!selectorArg || selectorArg.type === "SpreadElement") return null;
18124
18176
  const selector = anyValue(selectorArg, scope, code, mfs);
18125
- if (!isCombinator(selector)) return null;
18177
+ if (!isCombinator2(selector)) return null;
18126
18178
  const arms = [];
18127
18179
  for (const arg of armArgs) {
18128
18180
  if (arg.type === "SpreadElement") return null;
@@ -18149,12 +18201,12 @@ function exprToCombi(node2, scope, code, mfs) {
18149
18201
  const gateSrc = stripTsFromSource(parts.gate, code);
18150
18202
  mfs.push(gateSrc);
18151
18203
  const combi = anyValue(parts.combinator, scope, code, mfs);
18152
- if (!isCombinator(combi)) return null;
18204
+ if (!isCombinator2(combi)) return null;
18153
18205
  arms.push({ gate: () => true, combinator: combi });
18154
18206
  gateSrcs.push(gateSrc);
18155
18207
  } else {
18156
18208
  const combi = anyValue(argNode, scope, code, mfs);
18157
- if (!isCombinator(combi)) return null;
18209
+ if (!isCombinator2(combi)) return null;
18158
18210
  arms.push(combi);
18159
18211
  gateSrcs.push(null);
18160
18212
  }
@@ -18184,6 +18236,12 @@ function exprToCombi(node2, scope, code, mfs) {
18184
18236
  return null;
18185
18237
  }
18186
18238
  }
18239
+ function isHole(node2, value, scope) {
18240
+ if (value !== null) return false;
18241
+ const n = unwrapStaticExpr(node2);
18242
+ if (n.type === "Identifier") return !scope.has(n.name);
18243
+ return !(n.type === "Literal" && n.value === null) && n.type !== "ArrowFunctionExpression" && n.type !== "FunctionExpression";
18244
+ }
18187
18245
  function anyValue(node2, scope, code, mfs) {
18188
18246
  if (node2.type === "TSAsExpression" || node2.type === "TSSatisfiesExpression" || node2.type === "TSNonNullExpression" || node2.type === "TSTypeAssertion" || node2.type === "TSInstantiationExpression" || node2.type === "ParenthesizedExpression") {
18189
18247
  const inner = node2.expression;
@@ -18204,7 +18262,9 @@ function anyValue(node2, scope, code, mfs) {
18204
18262
  continue;
18205
18263
  }
18206
18264
  if (el.type === "SpreadElement") return null;
18207
- out.push(anyValue(el, scope, code, mfs));
18265
+ const v = anyValue(el, scope, code, mfs);
18266
+ if (isHole(el, v, scope)) return null;
18267
+ out.push(v);
18208
18268
  }
18209
18269
  return out;
18210
18270
  }
@@ -18213,7 +18273,10 @@ function anyValue(node2, scope, code, mfs) {
18213
18273
  for (const prop of node2.properties) {
18214
18274
  const key = propName(prop);
18215
18275
  if (key === null) return null;
18216
- obj[key] = anyValue(prop.value, scope, code, mfs);
18276
+ const valueNode = prop.value;
18277
+ const v = anyValue(valueNode, scope, code, mfs);
18278
+ if (isHole(valueNode, v, scope)) return null;
18279
+ obj[key] = v;
18217
18280
  }
18218
18281
  return obj;
18219
18282
  }
@@ -18289,10 +18352,9 @@ function evaluateExpr(node2, scope, code, mapFnSources) {
18289
18352
  return exprToCombi(node2, scope, code, mapFnSources);
18290
18353
  }
18291
18354
  function evaluateCombinatorArray(node2, scope, code) {
18292
- if (node2.type !== "ArrayExpression") return null;
18293
18355
  const val = anyValue(node2, scope, code, []);
18294
18356
  if (!Array.isArray(val) || val.length === 0) return null;
18295
- if (!val.every(isCombinator)) return null;
18357
+ if (!val.every(isCombinator2)) return null;
18296
18358
  return val;
18297
18359
  }
18298
18360
  function collectRuleKeys(retObj) {
@@ -18370,7 +18432,7 @@ function evalBodyStatements(statements, scope, code, out) {
18370
18432
  return false;
18371
18433
  }
18372
18434
  const thisDeclMfSrcs = bodyMfs.slice(before);
18373
- if (isCombinator(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
18435
+ if (isCombinator2(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
18374
18436
  else if (isDispatchArm(val)) scope.set(name, { value: val, mfSrcs: thisDeclMfSrcs });
18375
18437
  else scope.set(name, val);
18376
18438
  }
@@ -18415,7 +18477,7 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources, out, opti
18415
18477
  let built;
18416
18478
  try {
18417
18479
  built = rules(options ?? {}, (g) => {
18418
- const localScope = new Map(scope);
18480
+ const localScope = scope instanceof ModuleScope ? scope.fork() : new Map(scope);
18419
18481
  localScope.set(proxyName, g);
18420
18482
  if (!evalBodyStatements(statements, localScope, code, out)) throw ABORT;
18421
18483
  const entries = flattenRuleEntries(retObj, localScope, code);
@@ -18425,7 +18487,7 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources, out, opti
18425
18487
  const definitions = {};
18426
18488
  for (const [key, e] of finalByKey) {
18427
18489
  const val = anyValue(e.value, e.scope, e.code, mapFnSources);
18428
- if (!isCombinator(val)) throw ABORT;
18490
+ if (!isCombinator2(val)) throw ABORT;
18429
18491
  definitions[key] = val;
18430
18492
  }
18431
18493
  return definitions;
@@ -18440,7 +18502,7 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources, out, opti
18440
18502
  return map;
18441
18503
  }
18442
18504
  function isDefinableRef2(v) {
18443
- return isCombinator(v) && typeof v.define === "function" && v._def.tag === "lazy";
18505
+ return isCombinator2(v) && typeof v.define === "function" && v._def.tag === "lazy";
18444
18506
  }
18445
18507
  function evaluateRefDeclaration(init, name, scope) {
18446
18508
  if (init.type !== "CallExpression") return null;
@@ -18460,12 +18522,12 @@ function applyDefineStatement(callExpr, scope, code) {
18460
18522
  if (mem.property.type !== "Identifier" || mem.property.name !== "define") return false;
18461
18523
  if (mem.object.type !== "Identifier" || !mem.object.name) return false;
18462
18524
  const target = scope.get(mem.object.name);
18463
- const refCombi = isScopeEntry(target) ? target.combi : isCombinator(target) ? target : null;
18525
+ const refCombi = isScopeEntry(target) ? target.combi : isCombinator2(target) ? target : null;
18464
18526
  if (!refCombi || !isDefinableRef2(refCombi)) return false;
18465
18527
  const args = callExpr.arguments;
18466
18528
  if (args.length !== 1 || args[0].type === "SpreadElement") return false;
18467
18529
  const inner = anyValue(args[0], scope, code, []);
18468
- if (!isCombinator(inner)) return false;
18530
+ if (!isCombinator2(inner)) return false;
18469
18531
  try {
18470
18532
  refCombi.define(inner);
18471
18533
  } catch {
@@ -18475,7 +18537,7 @@ function applyDefineStatement(callExpr, scope, code) {
18475
18537
  }
18476
18538
  function referencesAny(node2, names, scope) {
18477
18539
  if (node2.type === "Identifier") {
18478
- return names.has(node2.name) || scope.has(node2.name);
18540
+ return names.has(node2.name) || Map.prototype.has.call(scope, node2.name);
18479
18541
  }
18480
18542
  for (const key of Object.keys(node2)) {
18481
18543
  const child = node2[key];
@@ -18536,7 +18598,9 @@ function patternNames(pat, out) {
18536
18598
  }
18537
18599
  }
18538
18600
  function declare(scope, name, b) {
18539
- if (!scope.bindings.has(name)) scope.bindings.set(name, b);
18601
+ const prev = scope.bindings.get(name);
18602
+ if (prev) prev.reassigned = true;
18603
+ else scope.bindings.set(name, b);
18540
18604
  }
18541
18605
  function functionScope(scope) {
18542
18606
  let s = scope;
@@ -18636,7 +18700,8 @@ function markReassignments(body, root) {
18636
18700
  }
18637
18701
  const node2 = n;
18638
18702
  if (typeof node2.type !== "string") return;
18639
- if (node2.type === "AssignmentExpression" || node2.type === "UpdateExpression") {
18703
+ const loopWrite = (node2.type === "ForOfStatement" || node2.type === "ForInStatement") && node2.left?.type !== "VariableDeclaration";
18704
+ if (node2.type === "AssignmentExpression" || node2.type === "UpdateExpression" || loopWrite) {
18640
18705
  const target = node2.type === "UpdateExpression" ? node2.argument : node2.left;
18641
18706
  const names = [];
18642
18707
  if (target) patternNames(target, names);
@@ -18652,6 +18717,11 @@ function markReassignments(body, root) {
18652
18717
  };
18653
18718
  for (const stmt of body) walk(stmt);
18654
18719
  }
18720
+ function topLevelIsStable(body, moduleEnd) {
18721
+ const root = buildScopeTree(body, moduleEnd);
18722
+ markReassignments(body, root);
18723
+ return (name) => root.bindings.get(name)?.reassigned !== true;
18724
+ }
18655
18725
  function functionArity(fn) {
18656
18726
  const params = fn.params ?? [];
18657
18727
  let count = 0;
@@ -19104,7 +19174,7 @@ function ast(value) {
19104
19174
  function nodes(value) {
19105
19175
  return Array.isArray(value) ? value.filter((v) => ast(v) !== void 0) : [];
19106
19176
  }
19107
- function nameOf(node2) {
19177
+ function nameOf2(node2) {
19108
19178
  return node2?.type === "Identifier" && typeof node2.name === "string" ? node2.name : void 0;
19109
19179
  }
19110
19180
  function range(node2) {
@@ -19137,7 +19207,7 @@ function isDirectCallUse(call, parent, statement) {
19137
19207
  return declarations.length === 1 && declarations[0] === parent && parent.init === call;
19138
19208
  }
19139
19209
  if (parent.type === "AssignmentExpression") {
19140
- return statement.type === "ExpressionStatement" && statement.expression === parent && nameOf(ast(parent.left)) !== void 0 && parent.right === call && parent.operator === "=";
19210
+ return statement.type === "ExpressionStatement" && statement.expression === parent && nameOf2(ast(parent.left)) !== void 0 && parent.right === call && parent.operator === "=";
19141
19211
  }
19142
19212
  if (parent.type === "ReturnStatement") return statement === parent && parent.argument === call;
19143
19213
  return false;
@@ -19155,7 +19225,7 @@ function hasInlineScopeHazard(fn) {
19155
19225
  if (node2.type === "Identifier" && node2.name === "arguments") hazard = true;
19156
19226
  else if (node2.type === "ThisExpression") hazard = true;
19157
19227
  else if (node2.type === "VariableDeclaration" && node2.kind === "var") hazard = true;
19158
- else if (node2.type === "MetaProperty" && nameOf(ast(node2.meta)) === "new" && nameOf(ast(node2.property)) === "target") hazard = true;
19228
+ else if (node2.type === "MetaProperty" && nameOf2(ast(node2.meta)) === "new" && nameOf2(ast(node2.property)) === "target") hazard = true;
19159
19229
  else for (const child of children2(node2)) walk(child);
19160
19230
  };
19161
19231
  walk(fn.body);
@@ -19163,7 +19233,7 @@ function hasInlineScopeHazard(fn) {
19163
19233
  }
19164
19234
  function hasInlineSignature(fn) {
19165
19235
  const params = nodes(fn.node.params);
19166
- return params.length === 3 && nameOf(params[0]) === "input" && nameOf(params[1]) === "pos" && nameOf(params[2]) === "ctx";
19236
+ return params.length === 3 && nameOf2(params[0]) === "input" && nameOf2(params[1]) === "pos" && nameOf2(params[2]) === "ctx";
19167
19237
  }
19168
19238
  function render2(source, start, end, edits) {
19169
19239
  const ordered = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
@@ -19256,7 +19326,7 @@ function supercompileRuleMapReplacement(prog, replacement) {
19256
19326
  const call = ast(declarator?.init);
19257
19327
  const table = nodes(call?.arguments)[0];
19258
19328
  if (declaration?.type !== "VariableDeclaration" || declarator?.type !== "VariableDeclarator" || call?.type !== "CallExpression" || table?.type !== "ObjectExpression") return replacement;
19259
- const property = (object, key) => nodes(object.properties).find((prop) => prop.type === "Property" && nameOf(ast(prop.key)) === key);
19329
+ const property = (object, key) => nodes(object.properties).find((prop) => prop.type === "Property" && nameOf2(ast(prop.key)) === key);
19260
19330
  const assembliesProp = property(table, "a");
19261
19331
  const assemblies = nodes(ast(assembliesProp?.value)?.elements);
19262
19332
  if (assembliesProp === void 0 || assemblies.length !== 1 || assemblies[0]?.type !== "ObjectExpression") return replacement;
@@ -19289,7 +19359,7 @@ function supercompileEmittedAssembly(prog, _cfg, extraIps, emitted) {
19289
19359
  const fns = /* @__PURE__ */ new Map();
19290
19360
  for (const statement of nodes(wrapperBody.body)) {
19291
19361
  if (statement.type !== "FunctionDeclaration") continue;
19292
- const name = nameOf(ast(statement.id));
19362
+ const name = nameOf2(ast(statement.id));
19293
19363
  const hit = name === void 0 ? void 0 : PIECE.exec(name);
19294
19364
  const body = ast(statement.body);
19295
19365
  if (hit !== void 0 && hit !== null && body?.type === "BlockStatement") {
@@ -19302,7 +19372,7 @@ function supercompileEmittedAssembly(prog, _cfg, extraIps, emitted) {
19302
19372
  const allCalls = [];
19303
19373
  const walk = (node2, current, parent, statement, statementParent) => {
19304
19374
  if (isFunction(node2) && node2 !== current?.node) {
19305
- const own = node2.type === "FunctionDeclaration" ? nameOf(ast(node2.id)) : void 0;
19375
+ const own = node2.type === "FunctionDeclaration" ? nameOf2(ast(node2.id)) : void 0;
19306
19376
  const hit = own === void 0 ? void 0 : PIECE.exec(own);
19307
19377
  if (hit !== void 0 && hit !== null) {
19308
19378
  const fn = fns.get(Number(hit[1]));
@@ -19326,12 +19396,12 @@ function supercompileEmittedAssembly(prog, _cfg, extraIps, emitted) {
19326
19396
  ownerParent = parent;
19327
19397
  }
19328
19398
  if (node2.type === "CallExpression") {
19329
- const calleeName = nameOf(ast(node2.callee));
19399
+ const calleeName = nameOf2(ast(node2.callee));
19330
19400
  const hit = calleeName === void 0 ? void 0 : PIECE.exec(calleeName);
19331
19401
  if (hit !== void 0 && hit !== null) {
19332
19402
  const callee = Number(hit[1]);
19333
19403
  const args = nodes(node2.arguments);
19334
- const transformable = current !== void 0 && owner2 !== void 0 && args.length === 3 && nameOf(args[0]) === "input" && nameOf(args[2]) === "ctx" && isDirectCallUse(node2, parent, owner2) && isListStatement(owner2, ownerParent);
19404
+ const transformable = current !== void 0 && owner2 !== void 0 && args.length === 3 && nameOf2(args[0]) === "input" && nameOf2(args[2]) === "ctx" && isDirectCallUse(node2, parent, owner2) && isListStatement(owner2, ownerParent);
19335
19405
  if (current === void 0 || owner2 === void 0) externalRefs.add(callee);
19336
19406
  else {
19337
19407
  const call = { caller: current.ip, callee, node: node2, statement: owner2, args, transformable };
@@ -19506,7 +19576,7 @@ ${nested}
19506
19576
  const referenced = /* @__PURE__ */ new Set();
19507
19577
  const checkRefs = (node2, parent) => {
19508
19578
  if (node2.type === "FunctionDeclaration") {
19509
- const name = nameOf(ast(node2.id));
19579
+ const name = nameOf2(ast(node2.id));
19510
19580
  if (name !== void 0 && PIECE.test(name)) declared.add(name);
19511
19581
  }
19512
19582
  if (node2.type === "Identifier" && typeof node2.name === "string" && PIECE.test(node2.name)) {
@@ -19515,32 +19585,210 @@ ${nested}
19515
19585
  }
19516
19586
  for (const child of children2(node2)) checkRefs(child, node2);
19517
19587
  };
19518
- checkRefs(checked.program);
19519
- if (declared.size !== functionsAfter || [...referenced].some((name) => !declared.has(name))) {
19520
- return fallback(emitted, "deleted piece body remains reachable after structured relinking", before);
19521
- }
19522
- const largestRegion = [...regionSizes].sort((a, b) => b[1] - a[1])[0];
19523
- const protocolRegions = {
19524
- node: [...regionProtocol.values()].filter((bits) => (bits & 1) !== 0).length,
19525
- repv: [...regionProtocol.values()].filter((bits) => (bits & 2) !== 0).length,
19526
- nodeAndRepv: [...regionProtocol.values()].filter((bits) => bits === 3).length
19588
+ checkRefs(checked.program);
19589
+ if (declared.size !== functionsAfter || [...referenced].some((name) => !declared.has(name))) {
19590
+ return fallback(emitted, "deleted piece body remains reachable after structured relinking", before);
19591
+ }
19592
+ const largestRegion = [...regionSizes].sort((a, b) => b[1] - a[1])[0];
19593
+ const protocolRegions = {
19594
+ node: [...regionProtocol.values()].filter((bits) => (bits & 1) !== 0).length,
19595
+ repv: [...regionProtocol.values()].filter((bits) => (bits & 2) !== 0).length,
19596
+ nodeAndRepv: [...regionProtocol.values()].filter((bits) => bits === 3).length
19597
+ };
19598
+ return {
19599
+ ...emitted,
19600
+ source: candidate,
19601
+ supercompile: {
19602
+ ...before,
19603
+ activated: removed > 0,
19604
+ ...removed > 0 ? {} : { reason: "no uniquely-owned region bodies" },
19605
+ functionsAfter,
19606
+ pieceCallsAfter: pieceCallsBefore - removed,
19607
+ sourceAfter: candidate.length,
19608
+ regions: roots.length,
19609
+ largestRegionSource: Math.max(0, ...regionSizes.values()),
19610
+ ...largestRegion === void 0 ? {} : { largestRegionIp: largestRegion[0] },
19611
+ protocolRegions
19612
+ }
19613
+ };
19614
+ }
19615
+
19616
+ // src/plugin/ir-eval.ts
19617
+ function evalRulesIR(ir) {
19618
+ return evalIR(ir, rules);
19619
+ }
19620
+ function evalCombinatorIR(ir) {
19621
+ const units = evalIR(ir, (opts) => opts.scanSkip);
19622
+ return units?.length === 1 ? units[0] : null;
19623
+ }
19624
+ function evalIR(ir, rulesImpl) {
19625
+ const _tf = (child, src, recognitionOnly = false) => {
19626
+ let fn2;
19627
+ try {
19628
+ fn2 = (0, eval)(`(${src})`);
19629
+ } catch {
19630
+ fn2 = () => {
19631
+ throw new Error("IR transform fn not materialized");
19632
+ };
19633
+ }
19634
+ const t = transform(child, fn2);
19635
+ t._def.fnSrc = src;
19636
+ if (recognitionOnly) t._def.recognitionOnly = true;
19637
+ return t;
19638
+ };
19639
+ const _lf = (child, src, source = false) => {
19640
+ let fn2;
19641
+ try {
19642
+ fn2 = (0, eval)(`(${src})`);
19643
+ } catch {
19644
+ fn2 = () => {
19645
+ throw new Error("IR leaf fn not materialized");
19646
+ };
19647
+ }
19648
+ const l = source ? sourceLeaf(child, fn2) : leaf(child, fn2);
19649
+ l._def.fnSrc = src;
19650
+ return l;
19651
+ };
19652
+ const _nd = (type, child, src, opts, staticError, sigSrc, buildImports, rawUnused) => {
19653
+ if (staticError !== void 0 && staticError.length > 0) {
19654
+ throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
19655
+ }
19656
+ const n = node(type, child, (() => {
19657
+ throw new Error("IR node build requires static re-lowering");
19658
+ }), opts);
19659
+ n._def.buildSrc = src;
19660
+ if (staticError !== void 0) n._def.buildStaticError = staticError;
19661
+ if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
19662
+ if (rawUnused === true) n._def.buildRawUnused = true;
19663
+ if (buildImports !== void 0) n._def.buildImports = buildImports;
19664
+ return n;
19665
+ };
19666
+ const _gch = (items) => {
19667
+ const gateSrcs = [];
19668
+ const arms = items.map((it) => {
19669
+ if (Array.isArray(it)) {
19670
+ const [src, comb] = it;
19671
+ gateSrcs.push(src);
19672
+ let gate2;
19673
+ try {
19674
+ gate2 = (0, eval)(`(${src})`);
19675
+ } catch {
19676
+ gate2 = () => {
19677
+ throw new Error("IR gate fn not materialized");
19678
+ };
19679
+ }
19680
+ return { gate: gate2, combinator: comb };
19681
+ }
19682
+ gateSrcs.push(null);
19683
+ return it;
19684
+ });
19685
+ const c = choice(...arms);
19686
+ const gates = c._def.gates;
19687
+ if (gates && gates.length !== gateSrcs.length) {
19688
+ throw new Error(`_gch: gateSrcs length ${gateSrcs.length} != choice gates length ${gates.length}`);
19689
+ }
19690
+ ;
19691
+ c._def.gateSrcs = gateSrcs;
19692
+ return c;
19527
19693
  };
19528
- return {
19529
- ...emitted,
19530
- source: candidate,
19531
- supercompile: {
19532
- ...before,
19533
- activated: removed > 0,
19534
- ...removed > 0 ? {} : { reason: "no uniquely-owned region bodies" },
19535
- functionsAfter,
19536
- pieceCallsAfter: pieceCallsBefore - removed,
19537
- sourceAfter: candidate.length,
19538
- regions: roots.length,
19539
- largestRegionSource: Math.max(0, ...regionSizes.values()),
19540
- ...largestRegion === void 0 ? {} : { largestRegionIp: largestRegion[0] },
19541
- protocolRegions
19694
+ const _wc = (src, inner) => {
19695
+ let extra;
19696
+ try {
19697
+ extra = (0, eval)(`(${src})`);
19698
+ } catch {
19699
+ extra = void 0;
19542
19700
  }
19701
+ const w = withCtx(extra, inner);
19702
+ w._def.extraSrc = src;
19703
+ return w;
19543
19704
  };
19705
+ const fn = new Function(
19706
+ "rules",
19707
+ "ref",
19708
+ "regex",
19709
+ "literal",
19710
+ "keywords",
19711
+ "sequence",
19712
+ "choice",
19713
+ "dispatch",
19714
+ "when",
19715
+ "startsWith",
19716
+ "endsWith",
19717
+ "matches",
19718
+ "otherwise",
19719
+ "routed",
19720
+ "attempt",
19721
+ "many",
19722
+ "oneOrMore",
19723
+ "optional",
19724
+ "sepBy",
19725
+ "keepSeparator",
19726
+ "not",
19727
+ "peek",
19728
+ "node",
19729
+ "parser",
19730
+ "scanTo",
19731
+ "balanced",
19732
+ "token",
19733
+ "leaf",
19734
+ "transform",
19735
+ "trivia",
19736
+ "classifiedTrivia",
19737
+ "label",
19738
+ "field",
19739
+ "expect",
19740
+ "adjacent",
19741
+ "notAdjacent",
19742
+ "_tf",
19743
+ "_lf",
19744
+ "_nd",
19745
+ "_gch",
19746
+ "_wc",
19747
+ `return (${ir})`
19748
+ );
19749
+ return fn(
19750
+ rulesImpl,
19751
+ ref,
19752
+ regex,
19753
+ literal,
19754
+ keywords,
19755
+ sequence,
19756
+ choice,
19757
+ dispatch,
19758
+ when,
19759
+ startsWith,
19760
+ endsWith,
19761
+ matches,
19762
+ otherwise,
19763
+ routed,
19764
+ attempt,
19765
+ many,
19766
+ oneOrMore,
19767
+ optional,
19768
+ sepBy,
19769
+ keepSeparator,
19770
+ not,
19771
+ peek,
19772
+ node,
19773
+ parser,
19774
+ scanTo,
19775
+ balanced,
19776
+ token,
19777
+ leaf,
19778
+ transform,
19779
+ trivia,
19780
+ classifiedTrivia,
19781
+ label,
19782
+ field,
19783
+ expect,
19784
+ adjacent,
19785
+ notAdjacent,
19786
+ _tf,
19787
+ _lf,
19788
+ _nd,
19789
+ _gch,
19790
+ _wc
19791
+ );
19544
19792
  }
19545
19793
 
19546
19794
  // src/plugin/index.ts
@@ -19705,13 +19953,30 @@ function topLevelInit(body, name) {
19705
19953
  }
19706
19954
  return null;
19707
19955
  }
19708
- function isComposedPiecesSymbol(n) {
19956
+ function isSymbolFor(n, key) {
19709
19957
  if (!n || n.type !== "CallExpression") return false;
19710
19958
  const callee = n.callee;
19711
19959
  const obj = callee?.object?.name;
19712
19960
  const prop = callee?.property?.name;
19713
19961
  const arg0 = n.arguments?.[0];
19714
- return obj === "Symbol" && prop === "for" && arg0?.value === "parseman.composedPieces";
19962
+ return obj === "Symbol" && prop === "for" && arg0?.value === key;
19963
+ }
19964
+ var isComposedPiecesSymbol = (n) => isSymbolFor(n, "parseman.composedPieces");
19965
+ var COMBINATOR_IR_KEY = "parseman.combinatorIR";
19966
+ function carriedCombinatorIR(init) {
19967
+ let n = init;
19968
+ while (n.type === "ParenthesizedExpression") n = n.expression;
19969
+ if (n.type !== "CallExpression") return null;
19970
+ const callee = n.callee;
19971
+ const args = n.arguments;
19972
+ if (callee.object?.name !== "Object" || callee.property?.name !== "defineProperty" || !isSymbolFor(args[1], COMBINATOR_IR_KEY)) return null;
19973
+ for (const p of args[2]?.properties ?? []) {
19974
+ const v = p.value;
19975
+ if (propName(p) !== "value") continue;
19976
+ if (v?.type === "Literal" && typeof v.value === "string") return v.value;
19977
+ if (v?.type === "TemplateLiteral" && v.expressions?.length === 0) return v.quasis?.[0]?.value.cooked ?? null;
19978
+ }
19979
+ return null;
19715
19980
  }
19716
19981
  function findCarriedPiecesLiteral(root) {
19717
19982
  let found = null;
@@ -19727,7 +19992,7 @@ function findCarriedPiecesLiteral(root) {
19727
19992
  const obj = callee?.object?.name;
19728
19993
  const prop = callee?.property?.name;
19729
19994
  const args = node2.arguments;
19730
- if (callee?.type === "Identifier" && callee.name === "tableRules" && args?.[1]?.type === "ObjectExpression") {
19995
+ if (callee?.type === "Identifier" && args?.[1]?.type === "ObjectExpression") {
19731
19996
  for (const p of args[1].properties ?? []) {
19732
19997
  if (p.computed && isComposedPiecesSymbol(p.key) && p.value) {
19733
19998
  found = { start: p.value.start, end: p.value.end };
@@ -19827,13 +20092,14 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19827
20092
  const allNames = /* @__PURE__ */ new Set();
19828
20093
  const importBindings = /* @__PURE__ */ new Map();
19829
20094
  const ordinaryImports = [];
20095
+ const isMacroImport = (s) => s.attributes.some((a) => {
20096
+ const key = a.key.type === "Identifier" ? a.key.name : String(a.key.value);
20097
+ return key === "type" && a.value.value === "macro";
20098
+ });
19830
20099
  for (const stmt of body) {
19831
20100
  if (stmt.type !== "ImportDeclaration") continue;
19832
20101
  const s = stmt;
19833
- const isMacro = moduleAliases.has(s.source.value) && s.attributes.some((a) => {
19834
- const key = a.key.type === "Identifier" ? a.key.name : String(a.key.value);
19835
- return key === "type" && a.value.value === "macro";
19836
- });
20102
+ const isMacro = moduleAliases.has(s.source.value) && isMacroImport(s);
19837
20103
  if (!isMacro) {
19838
20104
  const specifiers = [];
19839
20105
  for (const spec of s.specifiers) {
@@ -19876,7 +20142,209 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19876
20142
  }
19877
20143
  const reducerResolver = createReducerResolver(id, body, code);
19878
20144
  setReducerResolver(reducerResolver, code);
19879
- setBuilderImportResolver((name) => importBindings.get(name) ?? null);
20145
+ let builderImports = (name) => importBindings.get(name) ?? null;
20146
+ setBuilderImportResolver((name) => builderImports(name));
20147
+ const ownRoot = nearestPackageRoot(id);
20148
+ let ownDir = path2.dirname(id);
20149
+ try {
20150
+ ownDir = fs2.realpathSync(ownDir);
20151
+ } catch {
20152
+ }
20153
+ const rebaseSpecifier = (from, spec) => {
20154
+ if (!spec.startsWith(".")) return spec;
20155
+ const target = path2.resolve(path2.dirname(from), spec);
20156
+ if (ownRoot === null || nearestPackageRoot(target) !== ownRoot) return null;
20157
+ const rel = path2.relative(ownDir, target).split(path2.sep).join("/");
20158
+ return rel.startsWith("../") ? rel : `./${rel}`;
20159
+ };
20160
+ const unresolvedImports = /* @__PURE__ */ new Set();
20161
+ const valueModules = /* @__PURE__ */ new Map();
20162
+ const OPAQUE_IMPORT = "is a default or namespace import, which the macro does not resolve \u2014 import the binding by name";
20163
+ const opaqueImportsOf = (moduleBody) => {
20164
+ const out = /* @__PURE__ */ new Set();
20165
+ for (const st of moduleBody) {
20166
+ if (st.type !== "ImportDeclaration") continue;
20167
+ for (const sp of st.specifiers) {
20168
+ if (sp.type !== "ImportSpecifier") out.add(sp.local.name);
20169
+ }
20170
+ }
20171
+ return out;
20172
+ };
20173
+ const valueModule = (file) => {
20174
+ if (valueModules.has(file)) return valueModules.get(file);
20175
+ const mod = parseModuleCached(file);
20176
+ let out = null;
20177
+ if (mod) {
20178
+ const consts = /* @__PURE__ */ new Map();
20179
+ let stable;
20180
+ for (const st of mod.body) {
20181
+ const vd = unwrapVd(st);
20182
+ if (!vd) continue;
20183
+ const isConst = vd.kind === "const";
20184
+ for (const d of vd.declarations) {
20185
+ const idn = d.id;
20186
+ if (idn.type !== "Identifier" || !idn.name || !d.init) continue;
20187
+ if (isConst || (stable ??= topLevelIsStable(mod.body, mod.src.length))(idn.name)) consts.set(idn.name, d.init);
20188
+ }
20189
+ }
20190
+ out = {
20191
+ file,
20192
+ src: mod.src,
20193
+ body: mod.body,
20194
+ consts,
20195
+ imports: extractImportBindings(mod.body),
20196
+ opaqueImports: opaqueImportsOf(mod.body)
20197
+ };
20198
+ }
20199
+ valueModules.set(file, out);
20200
+ return out;
20201
+ };
20202
+ const resolveValueFile = (from, specifier) => {
20203
+ const source = resolvePrivateSourceModule(from, specifier);
20204
+ if (source) return source;
20205
+ try {
20206
+ return getCompiledResolver().resolveFileSync(from, specifier).path ?? null;
20207
+ } catch {
20208
+ return null;
20209
+ }
20210
+ };
20211
+ const evaluatingConsts = /* @__PURE__ */ new Set();
20212
+ const rebaseCarriedBuilderImports = (combi, from) => {
20213
+ const seen = /* @__PURE__ */ new Set();
20214
+ const walk = (v) => {
20215
+ if (v === null || typeof v !== "object" || seen.has(v)) return null;
20216
+ seen.add(v);
20217
+ const def = v._def;
20218
+ if (def?.buildImports) {
20219
+ const out = [];
20220
+ for (const bi of def.buildImports) {
20221
+ const source = rebaseSpecifier(from, bi.source);
20222
+ if (source === null) return bi;
20223
+ out.push({ ...bi, source });
20224
+ }
20225
+ def.buildImports = out;
20226
+ }
20227
+ for (const child of Object.values(v)) {
20228
+ for (const c of Array.isArray(child) ? child : [child]) {
20229
+ const stuck = walk(c);
20230
+ if (stuck) return stuck;
20231
+ }
20232
+ }
20233
+ return null;
20234
+ };
20235
+ return walk(combi);
20236
+ };
20237
+ const moduleConstValue = (m, name) => {
20238
+ const key = `${m.file}\0${name}`;
20239
+ if (evaluatingConsts.has(key)) return { unresolved: `is part of a declaration cycle in ${m.file}` };
20240
+ evaluatingConsts.add(key);
20241
+ const outerBuilderImports = builderImports;
20242
+ try {
20243
+ const init = m.consts.get(name);
20244
+ const ir = carriedCombinatorIR(init);
20245
+ if (ir !== null) {
20246
+ let combi2 = null;
20247
+ let why = "";
20248
+ try {
20249
+ combi2 = evalCombinatorIR(ir);
20250
+ } catch (e) {
20251
+ why = `: ${e.message}`;
20252
+ }
20253
+ if (!combi2) return { unresolved: `carries combinator IR that does not evaluate (${m.file})${why}` };
20254
+ const stuck = rebaseCarriedBuilderImports(combi2, m.file);
20255
+ return stuck ? { unresolved: `has a node() builder reading \`${stuck.local}\` from '${stuck.source}' inside ${m.file}, which this module cannot import \u2014 import it there by package name` } : { value: { combi: combi2, mfSrcs: [] } };
20256
+ }
20257
+ const scope2 = moduleValueScope(m);
20258
+ reducerResolver.register(m.file);
20259
+ builderImports = (name2) => {
20260
+ const b = m.imports.get(name2);
20261
+ const source = b ? rebaseSpecifier(m.file, b.source) : null;
20262
+ return b && source !== null ? { source, imported: b.imported } : null;
20263
+ };
20264
+ const mfs = [];
20265
+ const combi = evaluateExpr(init, scope2, m.src, mfs);
20266
+ if (combi) return { value: { combi, mfSrcs: mfs } };
20267
+ const factory = evaluateWordFactory(init, scope2, m.src) ?? evaluateWhenFactory(init, scope2, m.src);
20268
+ if (factory) return { value: factory };
20269
+ const value = evaluateStaticValue(init, scope2, m.src);
20270
+ if (value !== null && value !== void 0 || isStaticNullishExpression(init)) return { value };
20271
+ return {
20272
+ unresolved: /\btableRules\b/.test(m.src.slice(init.start, init.end)) ? `is a compiled parser in ${m.file} that carries no combinator IR \u2014 rebuild that module with parseman v${PARSEMAN_VERSION}` : `is not a statically-known combinator or value (${m.file})`
20273
+ };
20274
+ } finally {
20275
+ evaluatingConsts.delete(key);
20276
+ builderImports = outerBuilderImports;
20277
+ }
20278
+ };
20279
+ const moduleValueScope = (m) => m.scope ??= new ModuleScope((name) => {
20280
+ if (m.consts.has(name)) return moduleConstValue(m, name);
20281
+ const binding = m.imports.get(name);
20282
+ if (binding) return importedValue(m.file, binding);
20283
+ return m.opaqueImports.has(name) ? { unresolved: OPAQUE_IMPORT } : null;
20284
+ }, unresolvedImports);
20285
+ const exportedValue = (m, name, depth) => {
20286
+ for (const st of m.body) {
20287
+ if (st.type !== "ExportNamedDeclaration" || !st.source) continue;
20288
+ for (const sp of st.specifiers ?? []) {
20289
+ if (sp.exported.name !== name) continue;
20290
+ const source = st.source.value;
20291
+ const file = depth < 16 ? resolveValueFile(m.file, source) : null;
20292
+ const next = file ? valueModule(file) : null;
20293
+ if (!next) return { unresolved: `is re-exported from '${source}', which does not resolve from ${m.file}` };
20294
+ return exportedValue(next, sp.local.name, depth + 1);
20295
+ }
20296
+ }
20297
+ const local = exportLocalName(m.body, name);
20298
+ if (local === null) {
20299
+ for (const st of m.body) {
20300
+ if (st.type !== "ExportAllDeclaration" || st.exported) continue;
20301
+ const file = depth < 16 ? resolveValueFile(m.file, st.source.value) : null;
20302
+ const next = file ? valueModule(file) : null;
20303
+ if (!next) continue;
20304
+ const r = exportedValue(next, name, depth + 1);
20305
+ if (r !== null && "unresolved" in r && r.unresolved.startsWith("is not exported by ")) continue;
20306
+ return r;
20307
+ }
20308
+ return { unresolved: `is not exported by ${m.file}` };
20309
+ }
20310
+ const scope2 = moduleValueScope(m);
20311
+ if (!scope2.has(local)) {
20312
+ scope2.get(local);
20313
+ return { unresolved: `could not be resolved in ${m.file}` };
20314
+ }
20315
+ return { value: scope2.get(local) };
20316
+ };
20317
+ const importedValue = (from, binding) => {
20318
+ const file = resolveValueFile(from, binding.source);
20319
+ const m = file ? valueModule(file) : null;
20320
+ if (!m) return { unresolved: `is imported from '${binding.source}', which does not resolve from ${from}` };
20321
+ return exportedValue(m, binding.imported, 0);
20322
+ };
20323
+ const deferredLocals = /* @__PURE__ */ new Map();
20324
+ const deferredResults = /* @__PURE__ */ new Map();
20325
+ const mainOpaqueImports = opaqueImportsOf(body);
20326
+ const resolveMainFree = (name) => {
20327
+ const done = deferredResults.get(name);
20328
+ if (done !== void 0) return done;
20329
+ const deferred = deferredLocals.get(name);
20330
+ if (deferred !== void 0) {
20331
+ deferredLocals.delete(name);
20332
+ const outer = [...unresolvedImports];
20333
+ unresolvedImports.clear();
20334
+ const value = evaluateStaticValue(deferred, scope, code);
20335
+ const why = [...unresolvedImports];
20336
+ unresolvedImports.clear();
20337
+ for (const n of outer) unresolvedImports.add(n);
20338
+ const result2 = value !== null && value !== void 0 || isStaticNullishExpression(deferred) ? { value } : why.length > 0 ? { unresolved: `could not be evaluated at build time, because: ${why.join("; ")}` } : null;
20339
+ deferredResults.set(name, result2);
20340
+ return result2;
20341
+ }
20342
+ const binding = importBindings.get(name);
20343
+ if (!binding) return mainOpaqueImports.has(name) ? { unresolved: OPAQUE_IMPORT } : null;
20344
+ const resolved = importedValue(id, binding);
20345
+ if (resolved !== null && "value" in resolved) usedImportedFactories.add(name);
20346
+ return resolved;
20347
+ };
19880
20348
  const topLevelFunction = (moduleBody, name) => {
19881
20349
  for (const st of moduleBody) {
19882
20350
  const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
@@ -19885,19 +20353,17 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19885
20353
  }
19886
20354
  return null;
19887
20355
  };
19888
- const isParsemanMacroImport = (stmt) => {
19889
- if (stmt.type !== "ImportDeclaration") return false;
19890
- const s = stmt;
19891
- return moduleAliases.has(s.source.value) && s.attributes.some((a) => {
19892
- const key = a.key.type === "Identifier" ? a.key.name : String(a.key.value);
19893
- return key === "type" && a.value.value === "macro";
19894
- });
19895
- };
19896
- const sourceScopeUntil = (moduleBody, source, until) => {
19897
- const out = /* @__PURE__ */ new Map();
20356
+ const sourceScopeUntil = (file, moduleBody, source, until) => {
20357
+ const imports = extractImportBindings(moduleBody);
20358
+ const opaque = opaqueImportsOf(moduleBody);
20359
+ const out = new ModuleScope((name) => {
20360
+ const binding = imports.get(name);
20361
+ if (binding) return importedValue(file, binding);
20362
+ return opaque.has(name) ? { unresolved: OPAQUE_IMPORT } : null;
20363
+ }, unresolvedImports);
19898
20364
  for (const stmt of moduleBody) {
19899
20365
  if (stmt.type === "ImportDeclaration") {
19900
- if (!isParsemanMacroImport(stmt)) return null;
20366
+ if (moduleAliases.has(stmt.source.value) && !isMacroImport(stmt)) return null;
19901
20367
  continue;
19902
20368
  }
19903
20369
  if (stmt.type === "FunctionDeclaration") continue;
@@ -19950,6 +20416,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19950
20416
  }
19951
20417
  return out;
19952
20418
  };
20419
+ const factoryFailures = /* @__PURE__ */ new Map();
19953
20420
  const usedImportedFactories = /* @__PURE__ */ new Set();
19954
20421
  const markUsedImportedFactories = (names) => {
19955
20422
  for (const name of names ?? []) usedImportedFactories.add(name);
@@ -19962,8 +20429,13 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19962
20429
  const localFor = exportLocalName(mod.body, binding.imported);
19963
20430
  const init = localFor ? topLevelInit(mod.body, localFor) ?? topLevelFunction(mod.body, localFor) : null;
19964
20431
  if (!init || init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression" && init.type !== "FunctionDeclaration") continue;
19965
- const factoryScope = sourceScopeUntil(mod.body, mod.src, init.start);
19966
- if (!factoryScope) continue;
20432
+ unresolvedImports.clear();
20433
+ const factoryScope = sourceScopeUntil(file, mod.body, mod.src, init.start);
20434
+ if (!factoryScope) {
20435
+ if (unresolvedImports.size > 0) factoryFailures.set(localName, [...unresolvedImports]);
20436
+ unresolvedImports.clear();
20437
+ continue;
20438
+ }
19967
20439
  factoryDecls.set(localName, {
19968
20440
  fn: init,
19969
20441
  declaredAt: -1,
@@ -19973,7 +20445,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19973
20445
  });
19974
20446
  reducerResolver.register(file);
19975
20447
  }
19976
- const scope = /* @__PURE__ */ new Map();
20448
+ const scope = new ModuleScope(resolveMainFree, unresolvedImports);
19977
20449
  const replacements = [];
19978
20450
  const warnings = [];
19979
20451
  beginDegradationCapture();
@@ -19993,6 +20465,12 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
19993
20465
  m = /* @__PURE__ */ new Map();
19994
20466
  pendingBuilderImports.set(bi.source, m);
19995
20467
  }
20468
+ const prev = m.get(bi.local);
20469
+ if (prev !== void 0 && prev !== bi.imported) {
20470
+ throw new Error(
20471
+ `${id} \u2014 parseman will not emit this module: inlined builders read \`${bi.local}\` as both \`${prev}\` and \`${bi.imported}\` from ${JSON.stringify(bi.source)}. The builder source names \`${bi.local}\` verbatim, so one import cannot bind both; import them under different names.`
20472
+ );
20473
+ }
19996
20474
  m.set(bi.local, bi.imported);
19997
20475
  }
19998
20476
  if (def?.tag === "lazy" && v._ruleName === void 0 && typeof def.thunk === "function") {
@@ -20034,6 +20512,41 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20034
20512
  anyUnresolved = true;
20035
20513
  warnings.push(`${id}:${lineOf(pos)} \u2014 ${msg} (running via the interpreter; add the plugin or simplify the declaration to compile it)`);
20036
20514
  };
20515
+ const unevaluable = (pos, what) => {
20516
+ const names = [...unresolvedImports];
20517
+ unresolvedImports.clear();
20518
+ throw new Error(
20519
+ `${id}:${lineOf(pos)} \u2014 ${what} can't be evaluated at build time` + (names.length > 0 ? `; unresolved binding(s):
20520
+ ${names.map((n) => ` - ${n}`).join("\n")}` : " (it is not a static combinator/value expression)") + `
20521
+ parseman will not emit this module rather than drop it silently.`
20522
+ );
20523
+ };
20524
+ const requiredOption = (label2, name, value, evaluate) => {
20525
+ if (value === void 0 || isStaticNullishExpression(value)) return void 0;
20526
+ unresolvedImports.clear();
20527
+ const out = evaluate(value);
20528
+ if (out === null) {
20529
+ const id2 = value.type === "Identifier" ? value.name : null;
20530
+ if (id2 !== null && scope.has(id2) && scope.get(id2) == null) return void 0;
20531
+ return unevaluable(value.start, `${label2}: rules({ ${name} })`);
20532
+ }
20533
+ unresolvedImports.clear();
20534
+ return out;
20535
+ };
20536
+ const RULES_OPTIONS = /* @__PURE__ */ new Set(["trivia", "scanSkip", "hostMode", "trackLines"]);
20537
+ const assertPlainOptions = (optExpr, label2) => {
20538
+ for (const p of optExpr?.type === "ObjectExpression" ? optExpr.properties : []) {
20539
+ if (propName(p) !== null) continue;
20540
+ const key = p.type === "Property" ? evaluateStaticValue(p.key, scope, code) : null;
20541
+ if (typeof key !== "string" || RULES_OPTIONS.has(key)) {
20542
+ unevaluable(p.start, `${label2}: an options ${p.type === "Property" ? "computed key" : "spread"}`);
20543
+ }
20544
+ }
20545
+ };
20546
+ const triviaOption = (optExpr, label2) => {
20547
+ assertPlainOptions(optExpr, label2);
20548
+ return requiredOption(label2, "trivia", optionProp(optExpr, "trivia"), (v) => evaluateExpr(v, scope, code, []));
20549
+ };
20037
20550
  const evaluateRulesFactory = (init, label2) => {
20038
20551
  const args = init.arguments;
20039
20552
  const arg0 = args[0];
@@ -20049,7 +20562,15 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20049
20562
  const factoryScope = namedFactory?.scope ?? scope;
20050
20563
  const factoryCode = namedFactory?.code ?? code;
20051
20564
  const importedFactory = namedFactory?.imported === true && factoryArg === namedFactory.fn ? factoryArgRaw.name : void 0;
20565
+ const failedFactory = factoryArgRaw.type === "Identifier" ? factoryFailures.get(factoryArgRaw.name) : void 0;
20566
+ if (failedFactory) {
20567
+ for (const n of failedFactory) unresolvedImports.add(n);
20568
+ unevaluable(init.start, `${label2}: the imported rules() factory \`${factoryArgRaw.name}\``);
20569
+ }
20052
20570
  const optionsArg = optionsFirst ? arg0 : arg1;
20571
+ if (optionsArg !== void 0 && optionsArg.type !== "ObjectExpression" && !isStaticNullishExpression(optionsArg)) {
20572
+ unevaluable(optionsArg.start, `${label2}: rules() options`);
20573
+ }
20053
20574
  const optionValue = (name) => optionProp(optionsArg, name);
20054
20575
  const hostModeValue = optionValue("hostMode");
20055
20576
  const gHostMode = hostModeValue?.type === "Literal" ? hostModeValue.value : void 0;
@@ -20063,11 +20584,16 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20063
20584
  warn(init.start, `${label2}: rules({ trackLines }) must be a boolean literal`);
20064
20585
  return null;
20065
20586
  }
20066
- const triviaValue = optionValue("trivia");
20067
- const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
20068
- const scanSkipValue = optionValue("scanSkip");
20069
- const gScanSkip = scanSkipValue ? evaluateCombinatorArray(scanSkipValue, scope, code) ?? void 0 : void 0;
20587
+ const gTrivia = triviaOption(optionsArg, label2);
20588
+ const scanSkipArray = requiredOption(label2, "scanSkip", optionValue("scanSkip"), (v) => {
20589
+ const units = evaluateCombinatorArray(v, scope, code);
20590
+ if (units) return units;
20591
+ const value = evaluateStaticValue(v, scope, code);
20592
+ return Array.isArray(value) && value.length === 0 ? [] : null;
20593
+ });
20594
+ const gScanSkip = scanSkipArray?.length ? scanSkipArray : void 0;
20070
20595
  const why = {};
20596
+ unresolvedImports.clear();
20071
20597
  const ruleMap = evaluateParserFactory(factoryArg, factoryScope, factoryCode, [], why, {
20072
20598
  ...gTrivia ? { trivia: gTrivia } : {},
20073
20599
  ...gScanSkip ? { scanSkip: gScanSkip } : {},
@@ -20075,6 +20601,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20075
20601
  ...gTrackLines === true ? { trackLines: true } : {}
20076
20602
  });
20077
20603
  if (!ruleMap) {
20604
+ if (unresolvedImports.size > 0) unevaluable(init.start, `${label2}: rules(...) factory`);
20078
20605
  warn(init.start, why.reason === void 0 ? `${label2}: rules(...) factory isn't statically evaluable` : `${label2}: rules(...) factory isn't statically evaluable \u2014 ${why.reason}`);
20079
20606
  return null;
20080
20607
  }
@@ -20091,6 +20618,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20091
20618
  if (!evaluated) return null;
20092
20619
  const refusals = [];
20093
20620
  const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}, ...evaluated.trackLines ? { trackLines: true } : {}, recovery, coverage: grammarCoverage, refusals });
20621
+ if (compiled !== null) collectBuilderImports([...evaluated.ruleMap]);
20094
20622
  if (compiled !== null) usedTableRuntime = true;
20095
20623
  return {
20096
20624
  replacement: compiled?.replacement ?? null,
@@ -20152,49 +20680,63 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20152
20680
  };
20153
20681
  const localComposedCarried = /* @__PURE__ */ new Map();
20154
20682
  const importedPiecesCache = /* @__PURE__ */ new Map();
20155
- const resolveModulePieces = (module, exportName, seen) => {
20683
+ const resolveModulePieces = (module, exportName, seen, unresolved, local = false) => {
20156
20684
  const { file } = module;
20157
20685
  const mod = module.source ? lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recovery) : parseModuleCached(file);
20158
20686
  if (!mod) return null;
20159
- const localFor = exportLocalName(mod.body, exportName);
20687
+ const localFor = local ? exportName : exportLocalName(mod.body, exportName);
20160
20688
  const initNode = localFor ? topLevelInit(mod.body, localFor) : null;
20161
20689
  const literalRange = initNode ? findCarriedPiecesLiteral(initNode) : null;
20162
20690
  if (!literalRange) return null;
20163
20691
  const literal2 = mod.src.slice(literalRange.start, literalRange.end);
20692
+ const fail = (why) => {
20693
+ unresolved.why ??= `${exportName} in ${file}: ${why}`;
20694
+ return null;
20695
+ };
20164
20696
  const imports = extractImportBindings(mod.body);
20165
20697
  const stubNames = [];
20166
20698
  const stubVals = [];
20167
- const spreadRe = /\.\.\.\s*\(?\s*([A-Za-z_$][\w$]*)\s*\[\s*Symbol\s*\.\s*for\s*\(\s*['"]parseman\.composedPieces['"]/g;
20699
+ const spreadRe = /\.\.\.\s*\(?\s*([A-Za-z_$][\w$]*)\s*\[\s*(?:\/\*[^]*?\*\/\s*)*Symbol\s*\.\s*for\s*\(\s*['"]parseman\.composedPieces['"]/g;
20168
20700
  const done = /* @__PURE__ */ new Set();
20169
20701
  for (let m; m = spreadRe.exec(literal2); ) {
20170
- const local = m[1];
20171
- if (done.has(local)) continue;
20172
- done.add(local);
20173
- const b = imports.get(local);
20702
+ const local2 = m[1];
20703
+ if (done.has(local2)) continue;
20704
+ done.add(local2);
20705
+ const b = imports.get(local2);
20174
20706
  let subPieces = [];
20175
20707
  if (b) {
20176
20708
  const subModule = resolveGrammarModule(file, b.source);
20177
- if (subModule && !seen.has(subModule.file)) {
20178
- subPieces = resolveModulePieces(subModule, b.imported, new Set(seen).add(subModule.file)) ?? [];
20709
+ if (subModule === null) return fail(`its carried pieces spread \`${local2}\` from '${b.source}', a module that could not be found`);
20710
+ if (!seen.has(subModule.file)) {
20711
+ subPieces = resolveModulePieces(subModule, b.imported, new Set(seen).add(subModule.file), unresolved);
20712
+ if (subPieces === null) return fail(`its carried pieces spread \`${local2}\` from '${b.source}', which could not be resolved`);
20179
20713
  }
20714
+ } else if (topLevelInit(mod.body, local2) !== null && !seen.has(`${file}#${local2}`)) {
20715
+ subPieces = resolveModulePieces(module, local2, new Set(seen).add(`${file}#${local2}`), unresolved, true);
20716
+ if (subPieces === null) return fail(`its carried pieces spread the inlined binding \`${local2}\`, which carries none`);
20717
+ } else {
20718
+ return fail(`its carried pieces spread \`${local2}\`, which is neither an import nor a top-level binding of the module`);
20180
20719
  }
20181
- stubNames.push(local);
20720
+ stubNames.push(local2);
20182
20721
  stubVals.push({ [COMPOSED_PIECES]: subPieces });
20183
20722
  }
20184
20723
  try {
20185
20724
  const list = new Function(...stubNames, `return (${literal2})`)(...stubVals);
20186
20725
  return list;
20187
- } catch {
20188
- return null;
20726
+ } catch (e) {
20727
+ return fail(`its carried pieces literal did not evaluate (${e.message})`);
20189
20728
  }
20190
20729
  };
20730
+ const unresolvedCompiled = /* @__PURE__ */ new Map();
20191
20731
  const importedPieces = (localName) => {
20192
20732
  if (importedPiecesCache.has(localName)) return importedPiecesCache.get(localName);
20193
20733
  let result2 = null;
20194
20734
  const binding = importBindings.get(localName);
20195
20735
  if (binding) {
20196
20736
  const module = resolveGrammarModule(id, binding.source);
20197
- result2 = module ? resolveModulePieces(module, binding.imported, /* @__PURE__ */ new Set([module.file])) : null;
20737
+ const unresolved = {};
20738
+ result2 = module ? resolveModulePieces(module, binding.imported, /* @__PURE__ */ new Set([module.file]), unresolved) : null;
20739
+ if (result2 === null && unresolved.why !== void 0) unresolvedCompiled.set(localName, unresolved.why);
20198
20740
  }
20199
20741
  importedPiecesCache.set(localName, result2);
20200
20742
  return result2;
@@ -20205,7 +20747,8 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20205
20747
  const add = (item) => {
20206
20748
  if (!isIR(item)) return false;
20207
20749
  if (item.trackLines === true) trackLines = true;
20208
- pieces.push({ ns: item.ns, rules: evalRuleMapIR(item.ir) });
20750
+ const map = evalRulesIR(item.ir);
20751
+ pieces.push({ ns: item.ns, rules: Object.entries(map), recipes: map[RULES_RECIPE] });
20209
20752
  return true;
20210
20753
  };
20211
20754
  for (const item of items) {
@@ -20232,10 +20775,20 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20232
20775
  }
20233
20776
  return [...winners];
20234
20777
  };
20235
- const mergedCarriedRules = (items) => {
20778
+ const mergedCarriedRules = (items, link) => {
20236
20779
  const carriedMaps = carriedRuleMaps(items);
20237
20780
  if (carriedMaps === null) return null;
20238
- return { rules: mergeRuleMaps(carriedMaps.pieces.map((p) => p.rules)), trackLines: carriedMaps.trackLines };
20781
+ const linked = linkRules(carriedMaps.pieces.flatMap((p) => p.recipes), link);
20782
+ const rules2 = Object.entries(linked).filter(([, rule]) => {
20783
+ if (rule._def.tag !== "lazy") return true;
20784
+ try {
20785
+ rule._def.thunk();
20786
+ return true;
20787
+ } catch {
20788
+ return false;
20789
+ }
20790
+ });
20791
+ return { rules: rules2, trackLines: carriedMaps.trackLines };
20239
20792
  };
20240
20793
  const applyComposingTrivia = (ruleMap, composing) => {
20241
20794
  for (const [, rule] of ruleMap) {
@@ -20275,9 +20828,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20275
20828
  const a0 = rulesArgs[0];
20276
20829
  const a1 = rulesArgs[1];
20277
20830
  const optExpr = a0?.type === "ObjectExpression" ? a0 : a1?.type === "ObjectExpression" ? a1 : void 0;
20278
- const triviaValue = optionProp(optExpr, "trivia");
20279
- if (!triviaValue) return void 0;
20280
- return evaluateExpr(triviaValue, scope, code, []) ?? void 0;
20831
+ return triviaOption(optExpr, "compose() element");
20281
20832
  };
20282
20833
  const composingTrivia = (elements) => {
20283
20834
  for (let i = elements.length - 1; i >= 0; i--) {
@@ -20304,6 +20855,8 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20304
20855
  }
20305
20856
  const elements = arr.elements;
20306
20857
  const cOptions = init.arguments[1];
20858
+ if (cOptions !== void 0 && cOptions.type !== "ObjectExpression") unevaluable(cOptions.start, "compose() options");
20859
+ assertPlainOptions(cOptions, "compose()");
20307
20860
  const cHostModeValue = optionProp(cOptions, "hostMode");
20308
20861
  const cHostMode = cHostModeValue?.type === "Literal" ? cHostModeValue.value : void 0;
20309
20862
  if (cHostModeValue !== void 0 && cHostMode !== "ast" && cHostMode !== "cst") {
@@ -20316,15 +20869,25 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20316
20869
  for (let i = 0; i < elements.length; i++) {
20317
20870
  const r = argPieces(elements[i], `compose${init.start}_${i}`, composing);
20318
20871
  if (!r) {
20872
+ const el = elements[i];
20873
+ const name = el.type === "Identifier" ? el.name : void 0;
20874
+ const why = name === void 0 ? void 0 : unresolvedCompiled.get(name);
20875
+ if (why !== void 0) {
20876
+ throw new Error(
20877
+ `${id}:${lineOf(init.start)} \u2014 compose(): argument ${i} (\`${name}\` from '${importBindings.get(name)?.source}') is a build-compiled grammar whose carried pieces could not be resolved: ${why}. A runtime compose() cannot link a build-compiled grammar, so this would throw at import. The usual cause is a bundler rewriting the upstream module (inlining or renaming an ancestor grammar it composes, or reprinting its carried-pieces literal); keep upstream grammar packages external to the bundle.`
20878
+ );
20879
+ }
20319
20880
  warn(init.start, `compose(): argument ${i} isn't a build-resolvable grammar; falling back to runtime`);
20320
20881
  return null;
20321
20882
  }
20322
20883
  carried.push(...r.carried);
20323
20884
  importedFactories.push(...r.importedFactories ?? []);
20324
20885
  }
20325
- const merged = mergedCarriedRules(carried);
20886
+ const merged = mergedCarriedRules(carried, {
20887
+ trivia: composing,
20888
+ ...cHostMode ? { hostMode: cHostMode } : {}
20889
+ });
20326
20890
  if (merged !== null) {
20327
- if (composing) applyComposingTrivia(merged.rules, composing);
20328
20891
  collectBuilderImports(merged.rules);
20329
20892
  const refusals = [];
20330
20893
  const compiled = compileRuleMap(merged.rules, {
@@ -20519,11 +21082,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20519
21082
  if (d.id.type === "Identifier") {
20520
21083
  const varName = d.id.name;
20521
21084
  if (!referencesAny(init, allNames, scope)) {
20522
- const staticValue = evaluateStaticValue(init, scope, code);
20523
- if (staticValue !== null && staticValue !== void 0 || isStaticNullishExpression(init)) {
20524
- ;
20525
- scope.set(varName, staticValue);
20526
- }
21085
+ deferredLocals.set(varName, init);
20527
21086
  continue;
20528
21087
  }
20529
21088
  if (refNames.has(varName)) {
@@ -20610,6 +21169,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20610
21169
  continue;
20611
21170
  }
20612
21171
  const mapFnSources = [];
21172
+ unresolvedImports.clear();
20613
21173
  const parser2 = evaluateExpr(init, scope, code, mapFnSources);
20614
21174
  if (parser2 === null) {
20615
21175
  const wordFactory = evaluateWordFactory(init, scope, code);
@@ -20642,6 +21202,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20642
21202
  if (exportPrefix) exportedFactories.push({ name: varName, pos: init.start });
20643
21203
  continue;
20644
21204
  }
21205
+ if (unresolvedImports.size > 0) unevaluable(init.start, `"${varName}"`);
20645
21206
  warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
20646
21207
  continue;
20647
21208
  }
@@ -20654,7 +21215,8 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
20654
21215
  replacements.push({
20655
21216
  start: init.start,
20656
21217
  end: init.end,
20657
- replacement: compiled.inlineExpression
21218
+ replacement: compiled.inlineExpression,
21219
+ carry: { name: varName, combi: parser2, exported: exportPrefix !== "" }
20658
21220
  });
20659
21221
  scope.set(varName, { combi: parser2, mfSrcs: mapFnSources });
20660
21222
  } else if (d.id.type === "ObjectPattern") {
@@ -20721,37 +21283,58 @@ ${which}
20721
21283
  Drop the \`export\`. The factory is macro-only; \`rules(${exportedFactories[0].name})\` is lowered in place and needs no runtime value.`
20722
21284
  );
20723
21285
  }
21286
+ const withCombinatorIR = (r) => {
21287
+ if (!r.carry || !r.carry.exported && !referencedNames().live.has(r.carry.name)) return r;
21288
+ let ir = null;
21289
+ try {
21290
+ ir = serializeCombinator(r.carry.combi);
21291
+ } catch {
21292
+ }
21293
+ return ir === null ? r : {
21294
+ ...r,
21295
+ replacement: `/* @__PURE__ */ Object.defineProperty(${r.replacement}, Symbol.for('${COMBINATOR_IR_KEY}'), { value: ${JSON.stringify(ir)}, enumerable: false })`
21296
+ };
21297
+ };
20724
21298
  const ms = new MagicString(code);
20725
21299
  const replacementRanges = runtimeComposeFallback ? [] : replacements.map(({ start, end }) => ({ start, end }));
20726
21300
  const isInsideReplacement = (start, end) => replacementRanges.some((r) => start >= r.start && end <= r.end);
20727
- const importedBindingStillReferenced = (local) => {
20728
- const walk = (node2, parent, parentKey) => {
20729
- if (!node2 || typeof node2 !== "object") return false;
21301
+ let referenced = null;
21302
+ const referencedNames = () => {
21303
+ if (referenced !== null) return referenced;
21304
+ const all = /* @__PURE__ */ new Set();
21305
+ const live = /* @__PURE__ */ new Set();
21306
+ const deadRanges = [...[...factoryDecls.values()].filter((f) => !f.imported).map((f) => f.fn), ...anyUnresolved ? [] : defineRemovals];
21307
+ const walk = (node2, inFactory, parent, parentKey) => {
21308
+ if (!node2 || typeof node2 !== "object") return;
20730
21309
  const rec = node2;
20731
- if (rec.type === "ImportDeclaration") return false;
20732
- if (typeof rec.start === "number" && typeof rec.end === "number" && isInsideReplacement(rec.start, rec.end)) return false;
20733
- if ((rec.type === "Identifier" || rec.type === "BindingIdentifier") && rec.name === local) {
20734
- if (parentKey === "key" && (parent?.type === "ObjectProperty" || parent?.type === "Property" || parent?.type === "PropertyDefinition") && parent.computed !== true) return false;
20735
- if (parentKey === "property" && parent?.type === "StaticMemberExpression") return false;
20736
- if (parentKey === "property" && parent?.type === "MemberExpression" && parent.computed !== true) return false;
20737
- return true;
21310
+ if (rec.type === "ImportDeclaration") return;
21311
+ if (typeof rec.start === "number" && typeof rec.end === "number") {
21312
+ if (isInsideReplacement(rec.start, rec.end)) return;
21313
+ inFactory ||= deadRanges.some((f) => rec.start >= f.start && rec.end <= f.end);
21314
+ }
21315
+ if (rec.type === "Identifier" || rec.type === "BindingIdentifier") {
21316
+ const isKey = parentKey === "key" && (parent?.type === "ObjectProperty" || parent?.type === "Property" || parent?.type === "PropertyDefinition") && parent.computed !== true;
21317
+ const isMember = parentKey === "property" && (parent?.type === "StaticMemberExpression" || parent?.type === "MemberExpression" && parent.computed !== true);
21318
+ const isDeclared = parentKey === "id" && parent?.type === "VariableDeclarator";
21319
+ if (!isKey && !isMember && !isDeclared) {
21320
+ all.add(rec.name);
21321
+ if (!inFactory) live.add(rec.name);
21322
+ }
21323
+ return;
20738
21324
  }
20739
21325
  for (const key of Object.keys(rec)) {
20740
21326
  if (key === "type" || key === "start" || key === "end") continue;
20741
21327
  const value = rec[key];
20742
- if (Array.isArray(value)) {
20743
- if (value.some((child) => walk(child, rec, key))) return true;
20744
- } else if (walk(value, rec, key)) {
20745
- return true;
20746
- }
21328
+ if (Array.isArray(value)) for (const child of value) walk(child, inFactory, rec, key);
21329
+ else walk(value, inFactory, rec, key);
20747
21330
  }
20748
- return false;
20749
21331
  };
20750
- return body.some((stmt) => walk(stmt));
21332
+ for (const stmt of body) walk(stmt, false);
21333
+ return referenced = { all, live };
20751
21334
  };
20752
21335
  for (const imp of ordinaryImports) {
20753
21336
  if (!runtimeComposeFallback && imp.specifiers.length > 0 && imp.specifiers.every(
20754
- (spec) => spec.type === "ImportSpecifier" && usedImportedFactories.has(spec.local) && !importedBindingStillReferenced(spec.local)
21337
+ (spec) => spec.type === "ImportSpecifier" && usedImportedFactories.has(spec.local) && !referencedNames().all.has(spec.local)
20755
21338
  )) {
20756
21339
  ms.remove(imp.start, imp.end);
20757
21340
  }
@@ -20768,7 +21351,7 @@ ${which}
20768
21351
  ms.overwrite(imp.start, imp.end, stripped);
20769
21352
  }
20770
21353
  }
20771
- const applied = runtimeComposeFallback ? [] : replacements;
21354
+ const applied = runtimeComposeFallback ? [] : replacements.map((r) => withCombinatorIR(r));
20772
21355
  for (const { start, end, replacement } of applied.slice().sort((a, b) => b.start - a.start)) {
20773
21356
  ms.overwrite(start, end, replacement);
20774
21357
  }