parseman 0.32.0 → 0.33.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.
package/dist/index.js CHANGED
@@ -2821,7 +2821,7 @@ function leaf(root, fn) {
2821
2821
  }
2822
2822
 
2823
2823
  // src/version.ts
2824
- var PARSEMAN_VERSION = "0.32.0";
2824
+ var PARSEMAN_VERSION = "0.33.0";
2825
2825
 
2826
2826
  // src/analysis/gating.ts
2827
2827
  var isAny = (fs) => fs.kind === "any";
@@ -7455,9 +7455,9 @@ function lazyTarget(c) {
7455
7455
  }
7456
7456
  var Unserializable = class extends Error {
7457
7457
  };
7458
- function serializeRuleMap(ruleMap) {
7458
+ function serializeRuleMap(ruleMap, scanSkip) {
7459
7459
  try {
7460
- return new Serializer(ruleMap).run();
7460
+ return new Serializer(ruleMap, scanSkip ?? []).run();
7461
7461
  } catch (e) {
7462
7462
  if (e instanceof Unserializable) {
7463
7463
  if (process.env.PARSEMAN_IR_DEBUG) console.error(`[ir] fallback: ${e.message}`);
@@ -7618,10 +7618,28 @@ var Serializer = class {
7618
7618
  decls = [];
7619
7619
  ruleValues = /* @__PURE__ */ new Set();
7620
7620
  ruleMap;
7621
- constructor(ruleMap) {
7621
+ scanSkip;
7622
+ constructor(ruleMap, scanSkip = []) {
7622
7623
  this.ruleMap = ruleMap;
7624
+ this.scanSkip = scanSkip;
7623
7625
  for (const [, c] of ruleMap) this.ruleValues.add(this.body(c));
7624
7626
  }
7627
+ /** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
7628
+ * bracket) — it must not reach a grammar-rule ref (`g[name]`), because the
7629
+ * serialized `scanSkip` array sits in the `rules({ scanSkip })` OPTIONS position,
7630
+ * outside the `(g) => …` factory where `g` is bound. A unit that does reference a
7631
+ * rule can't be carried in options; bail to the full-pieces fallback. */
7632
+ assertNoRuleRef(c, seen) {
7633
+ if (seen.has(c)) return;
7634
+ seen.add(c);
7635
+ if (c._def.tag === "lazy") {
7636
+ if (ruleNameOf2(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
7637
+ const target = lazyTarget(c);
7638
+ if (target) this.assertNoRuleRef(target, seen);
7639
+ return;
7640
+ }
7641
+ for (const child of childrenOf2(c._def)) this.assertNoRuleRef(child, seen);
7642
+ }
7625
7643
  /** A `rules()` map wraps each rule value in a named `lazy` proxy; the real body is
7626
7644
  * its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
7627
7645
  * `g[name]` ref — only the top-level entry is unwrapped. */
@@ -7630,21 +7648,38 @@ var Serializer = class {
7630
7648
  }
7631
7649
  run() {
7632
7650
  for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
7651
+ for (const c of this.scanSkip) {
7652
+ this.assertNoRuleRef(c, /* @__PURE__ */ new Set());
7653
+ this.analyze(c, /* @__PURE__ */ new Set());
7654
+ }
7633
7655
  let n = 0;
7634
7656
  for (const [c, count] of this.counts) {
7635
7657
  if (this.ruleValues.has(c)) continue;
7636
7658
  if (count >= 2 || this.selfRef.has(c)) this.constName.set(c, `_s${n++}`);
7637
7659
  }
7660
+ const outerDecls = [];
7661
+ const innerDecls = [];
7662
+ let optionsArg = "";
7663
+ if (this.scanSkip.length > 0) {
7664
+ this.decls = outerDecls;
7665
+ const units = this.scanSkip.map((c) => this.ref(c, null));
7666
+ optionsArg = `{ scanSkip: [${units.join(", ")}] }, `;
7667
+ }
7668
+ this.decls = innerDecls;
7638
7669
  const body = this.ruleMap.map(([name, c]) => ` ${JSON.stringify(name)}: ${this.wrap(this.body(c))}`).join(",\n");
7639
- if (this.decls.length === 0) return `rules((g) => ({
7670
+ const factory = innerDecls.length === 0 ? `(g) => ({
7640
7671
  ${body}
7641
- }))`;
7642
- return `rules((g) => {
7643
- ${this.decls.map((d) => " " + d).join("\n")}
7672
+ })` : `(g) => {
7673
+ ${innerDecls.map((d) => " " + d).join("\n")}
7644
7674
  return ({
7645
7675
  ${body}
7646
7676
  })
7647
- })`;
7677
+ }`;
7678
+ const call = `rules(${optionsArg}${factory})`;
7679
+ return outerDecls.length === 0 ? call : `(() => {
7680
+ ${outerDecls.map((d) => " " + d).join("\n")}
7681
+ return ${call}
7682
+ })()`;
7648
7683
  }
7649
7684
  /** Count identity references and flag self-referential subtrees. `active` is the
7650
7685
  * set of combinators on the current DFS path (to detect a lazy pointing back). */
@@ -7994,7 +8029,8 @@ function itemCarried(item, used, trivia2) {
7994
8029
  return false;
7995
8030
  }
7996
8031
  });
7997
- const ir = serializeRuleMap(entries);
8032
+ const scanSkip = entries.map(([, val]) => val._meta.grammarScanSkip).find(Boolean);
8033
+ const ir = serializeRuleMap(entries, scanSkip);
7998
8034
  return ir ? [{ ns, ir }] : [linkable(map, ns, trivia2)];
7999
8035
  }
8000
8036
  function composingTriviaOf(items) {