parseman 0.37.0 → 0.38.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.
@@ -8,6 +8,7 @@ export type KeywordsOptions = {
8
8
  */
9
9
  boundary?: string;
10
10
  };
11
+ export type WordOptions = Omit<KeywordsOptions, 'boundary'>;
11
12
  /**
12
13
  * Match a single keyword with an automatic word-boundary guard. Prevents
13
14
  * matching `true` inside `trueish`. The boundary defaults to `_0-9A-Za-z`,
@@ -24,21 +25,21 @@ export type KeywordsOptions = {
24
25
  * `regex(/media/i)` — which `analyzeGating` correctly flags as the `keyword-regex`
25
26
  * anti-pattern — or `keywords(['media'], …)` for a single word.
26
27
  */
27
- export declare function word(str: string, boundary?: string, opts?: Omit<KeywordsOptions, 'boundary'>): Combinator<string>;
28
- export declare function word(str: string, opts: Omit<KeywordsOptions, 'boundary'>): Combinator<string>;
28
+ export declare function word(str: string, boundary?: string, opts?: WordOptions): Combinator<string>;
29
+ export declare function word(str: string, opts: WordOptions): Combinator<string>;
29
30
  /**
30
31
  * Create a keyword factory with a fixed word-boundary class. Use when many
31
32
  * keywords share the same boundary (e.g. CSS identifiers). For a single keyword,
32
- * `word(str, boundary?)` is enough; you can also roll your own factory with
33
- * `(s) => word(s, boundary)`.
33
+ * `word(str, boundary?)` is enough.
34
34
  *
35
- * const kw = makeWord() // default: '_0-9A-Za-z'
36
- * const cssKw = makeWord('A-Za-z0-9_-') // dashes allowed in CSS idents
35
+ * const kw = makeWord() // default boundary
36
+ * const cssKw = makeWord('A-Za-z0-9_-', { caseInsensitive: true })
37
37
  *
38
38
  * const query = kw('query')
39
- * const color = cssKw('color') // matches "color" but not "color-scheme"
39
+ * const color = cssKw('color') // matches "COLOR" but not "color-scheme"
40
40
  */
41
- export declare function makeWord(boundary?: string): (str: string) => Combinator<string>;
41
+ export declare function makeWord(boundary?: string, opts?: WordOptions): (str: string) => Combinator<string>;
42
+ export declare function makeWord(opts: WordOptions): (str: string) => Combinator<string>;
42
43
  /**
43
44
  * Match any one of a set of fixed keywords, longest-first (so `border` wins over
44
45
  * `bord`), with an optional trailing word-boundary guard. Compiles to a single
@@ -1 +1 @@
1
- {"version":3,"file":"keywords.d.ts","sourceRoot":"","sources":["../../src/combinators/keywords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAmD,MAAM,aAAa,CAAA;AAM9F,MAAM,MAAM,eAAe,GAAG;IAC5B,gCAAgC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAClH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAW9F;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAe,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC,MAAM,CAAC,CAErF;AAMD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,eAAoB,GAAG,UAAU,CAAC,MAAM,CAAC,CA8DjG"}
1
+ {"version":3,"file":"keywords.d.ts","sourceRoot":"","sources":["../../src/combinators/keywords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAmD,MAAM,aAAa,CAAA;AAM9F,MAAM,MAAM,eAAe,GAAG;IAC5B,gCAAgC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;AAE3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAC5F,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAWxE;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC,MAAM,CAAC,CAAA;AACpG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC,MAAM,CAAC,CAAA;AAchF;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,eAAoB,GAAG,UAAU,CAAC,MAAM,CAAC,CA8DjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/combinators/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAItD;;;;GAIG;AACH,eAAO,MAAM,UAAU,wBAAwB,CAAA;AAO/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;8EAC0E;IAC1E,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAA;IACvC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,CAAA;AAKD,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AAClG,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/combinators/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAItD;;;;GAIG;AACH,eAAO,MAAM,UAAU,wBAAwB,CAAA;AA0B/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;8EAC0E;IAC1E,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAA;IACvC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,CAAA;AAKD,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AAClG,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA"}
package/dist/index.cjs CHANGED
@@ -1036,8 +1036,10 @@ function word(str, boundaryOrOpts, opts) {
1036
1036
  const rest = typeof boundaryOrOpts === "object" && boundaryOrOpts !== null ? boundaryOrOpts : opts;
1037
1037
  return keywords([str], { ...rest, boundary });
1038
1038
  }
1039
- function makeWord(boundary = "_0-9A-Za-z") {
1040
- return (str) => keywords([str], { boundary });
1039
+ function makeWord(boundaryOrOpts = "_0-9A-Za-z", opts) {
1040
+ const boundary = typeof boundaryOrOpts === "string" ? boundaryOrOpts : "_0-9A-Za-z";
1041
+ const rest = typeof boundaryOrOpts === "object" && boundaryOrOpts !== null ? boundaryOrOpts : opts;
1042
+ return (str) => keywords([str], { ...rest, boundary });
1041
1043
  }
1042
1044
  function escapeRe(s) {
1043
1045
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -2474,6 +2476,16 @@ function tagRule(r, key) {
2474
2476
  r._ruleName = key;
2475
2477
  if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
2476
2478
  }
2479
+ function isDefinableRef(v2) {
2480
+ return !!v2 && typeof v2 === "object" && "_def" in v2 && v2._def.tag === "lazy" && typeof v2.define === "function";
2481
+ }
2482
+ function ruleNameOf(r) {
2483
+ return r._ruleName;
2484
+ }
2485
+ function isNamedRuleRefForAnotherRule(r, key) {
2486
+ const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
2487
+ return name !== void 0 && name !== key;
2488
+ }
2477
2489
  function rules(a, b) {
2478
2490
  const factory = typeof a === "function" ? a : b;
2479
2491
  const options = typeof a === "function" ? b : a;
@@ -2494,11 +2506,21 @@ function rules(a, b) {
2494
2506
  for (const key of Object.keys(definitions)) {
2495
2507
  const placeholder = cache[key];
2496
2508
  const parser2 = definitions[key];
2497
- if (placeholder !== void 0 && typeof placeholder.define === "function") {
2498
- tagRule(parser2, key);
2509
+ if (placeholder === parser2) {
2510
+ throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
2511
+ }
2512
+ if (isDefinableRef(placeholder)) {
2513
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
2499
2514
  placeholder.define(parser2);
2500
2515
  placeholder._meta.firstSet = parser2._meta.firstSet;
2501
2516
  placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
2517
+ } else if (isNamedRuleRefForAnotherRule(parser2, key)) {
2518
+ const alias = ref();
2519
+ tagRule(alias, key);
2520
+ alias.define(parser2);
2521
+ alias._meta.firstSet = parser2._meta.firstSet;
2522
+ alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
2523
+ cache[key] = alias;
2502
2524
  } else {
2503
2525
  tagRule(parser2, key);
2504
2526
  cache[key] = parser2;
@@ -3151,7 +3173,7 @@ function leaf(root, fn) {
3151
3173
  }
3152
3174
 
3153
3175
  // src/version.ts
3154
- var PARSEMAN_VERSION = "0.37.0";
3176
+ var PARSEMAN_VERSION = "0.38.0";
3155
3177
 
3156
3178
  // src/cst/host-mode.ts
3157
3179
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -3205,7 +3227,7 @@ function firstSetToString(fs) {
3205
3227
  if (fs.kind === "empty") return "(empty)";
3206
3228
  return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
3207
3229
  }
3208
- var ruleNameOf = (p) => p._ruleName;
3230
+ var ruleNameOf2 = (p) => p._ruleName;
3209
3231
  var SUGGESTIONS = {
3210
3232
  "broad-recognizer": "if this arm leads with a keyword regex, use word('kw', boundary) / keywords([...]) \u2014 they expose an EXACT, gating first-set and lower to the same charCodeAt scan. A genuine scanTo fallback is fine; accept it in the gating snapshot if intentional.",
3211
3233
  "leading-not": "let the arm lead with its actual consuming terminal (first-sets gate it automatically); keep not(...) only as a TRAILING boundary. Do not hand-roll not(not(...)) to fake gating \u2014 use peek(X), which is zero-width AND carries X first-set.",
@@ -3363,7 +3385,7 @@ function detectAntiPatterns(rule, arms) {
3363
3385
  return out;
3364
3386
  }
3365
3387
  function analyzeGating(entry, opts) {
3366
- return analyzeGatingRules([[ruleNameOf(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
3388
+ return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
3367
3389
  }
3368
3390
  function analyzeGatingRules(ruleMap, opts) {
3369
3391
  const raw = [];
@@ -3396,7 +3418,7 @@ function analyzeGatingRules(ruleMap, opts) {
3396
3418
  return;
3397
3419
  }
3398
3420
  const d = def;
3399
- const rule = ruleNameOf(p) ?? enclosingRule;
3421
+ const rule = ruleNameOf2(p) ?? enclosingRule;
3400
3422
  if (d.tag === "choice") {
3401
3423
  raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
3402
3424
  antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
@@ -3415,7 +3437,7 @@ function analyzeGatingRules(ruleMap, opts) {
3415
3437
  }
3416
3438
  for (const k of kids) visit(k, rule);
3417
3439
  };
3418
- for (const [name, root] of ruleMap) visit(root, ruleNameOf(root) ?? name);
3440
+ for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
3419
3441
  const perRule = /* @__PURE__ */ new Map();
3420
3442
  for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
3421
3443
  const seenInRule = /* @__PURE__ */ new Map();
@@ -3539,7 +3561,7 @@ function childrenOf(d) {
3539
3561
  }
3540
3562
  }
3541
3563
  }
3542
- var ruleNameOf2 = (p) => p._ruleName;
3564
+ var ruleNameOf3 = (p) => p._ruleName;
3543
3565
  var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
3544
3566
  function payloadKey(p, d) {
3545
3567
  switch (d.tag) {
@@ -3550,7 +3572,7 @@ function payloadKey(p, d) {
3550
3572
  case "keywords":
3551
3573
  return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
3552
3574
  case "lazy": {
3553
- const n = ruleNameOf2(p);
3575
+ const n = ruleNameOf3(p);
3554
3576
  return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
3555
3577
  }
3556
3578
  case "label":
@@ -3617,7 +3639,7 @@ var Interner = class {
3617
3639
  var MAX_RENDER = 160;
3618
3640
  function render(p, depth = 3) {
3619
3641
  const d = p._def;
3620
- const name = ruleNameOf2(p);
3642
+ const name = ruleNameOf3(p);
3621
3643
  switch (d.tag) {
3622
3644
  case "literal":
3623
3645
  return `literal('${d.value}')`;
@@ -3796,7 +3818,7 @@ function keywordAlternationHazards(words, boundary) {
3796
3818
  return out;
3797
3819
  }
3798
3820
  function analyzeDuplication(entry, opts) {
3799
- return analyzeDuplicationRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
3821
+ return analyzeDuplicationRules([[ruleNameOf3(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
3800
3822
  }
3801
3823
  function assertAnalyzable(ruleMap) {
3802
3824
  for (const [name, rule] of ruleMap) {
@@ -3837,7 +3859,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
3837
3859
  const visit = (p, rule, path, enclosingNode, enclosingReducer) => {
3838
3860
  if (visited.has(p)) return;
3839
3861
  const d = p._def;
3840
- const own = ruleNameOf2(p);
3862
+ const own = ruleNameOf3(p);
3841
3863
  const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path };
3842
3864
  visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
3843
3865
  const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
@@ -3850,12 +3872,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
3850
3872
  if (d.tag === "lazy") {
3851
3873
  try {
3852
3874
  const target = d.thunk();
3853
- visit(target, ruleNameOf2(target) ?? ruleNameOf2(p) ?? here.rule, "", null, false);
3875
+ visit(target, ruleNameOf3(target) ?? ruleNameOf3(p) ?? here.rule, "", null, false);
3854
3876
  } catch {
3855
3877
  }
3856
3878
  }
3857
3879
  };
3858
- for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name, "", null, false);
3880
+ for (const [name, root] of ruleMap) visit(root, ruleNameOf3(root) ?? name, "", null, false);
3859
3881
  const accept = new Set(opts?.accept ?? []);
3860
3882
  const used = /* @__PURE__ */ new Set();
3861
3883
  const keep = (f) => {
@@ -8702,7 +8724,7 @@ function ruleDependencies(ruleMap) {
8702
8724
  const seen = /* @__PURE__ */ new Set();
8703
8725
  const walk2 = (p, isRoot) => {
8704
8726
  const def = p._def;
8705
- const boundary = def.tag === "lazy" ? p._ruleName ?? nameOf.get(p) : nameOf.get(p);
8727
+ const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
8706
8728
  if (!isRoot && boundary !== void 0) {
8707
8729
  found.add(boundary);
8708
8730
  return;
@@ -9341,7 +9363,7 @@ function childrenOf3(def) {
9341
9363
  return [];
9342
9364
  }
9343
9365
  }
9344
- var ruleNameOf3 = (c) => c._ruleName;
9366
+ var ruleNameOf4 = (c) => c._ruleName;
9345
9367
  function lazyTarget(c) {
9346
9368
  if (c._def.tag !== "lazy") return null;
9347
9369
  try {
@@ -9523,12 +9545,16 @@ var Serializer = class {
9523
9545
  emitted = /* @__PURE__ */ new Set();
9524
9546
  decls = [];
9525
9547
  ruleValues = /* @__PURE__ */ new Set();
9548
+ localRuleNames = /* @__PURE__ */ new Map();
9526
9549
  ruleMap;
9527
9550
  scanSkip;
9528
9551
  constructor(ruleMap, scanSkip = []) {
9529
9552
  this.ruleMap = ruleMap;
9530
9553
  this.scanSkip = scanSkip;
9531
- for (const [, c] of ruleMap) this.ruleValues.add(this.body(c));
9554
+ for (const [name, c] of ruleMap) {
9555
+ this.localRuleNames.set(c, name);
9556
+ this.ruleValues.add(this.body(c));
9557
+ }
9532
9558
  }
9533
9559
  /** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
9534
9560
  * bracket) — it must not reach a grammar-rule ref (`g[name]`), because the
@@ -9539,7 +9565,7 @@ var Serializer = class {
9539
9565
  if (seen.has(c)) return;
9540
9566
  seen.add(c);
9541
9567
  if (c._def.tag === "lazy") {
9542
- if (ruleNameOf3(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
9568
+ if (ruleNameOf4(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
9543
9569
  const target = lazyTarget(c);
9544
9570
  if (target) this.assertNoRuleRef(target, seen);
9545
9571
  return;
@@ -9550,7 +9576,7 @@ var Serializer = class {
9550
9576
  * its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
9551
9577
  * `g[name]` ref — only the top-level entry is unwrapped. */
9552
9578
  body(c) {
9553
- return c._def.tag === "lazy" && ruleNameOf3(c) !== void 0 ? lazyTarget(c) ?? c : c;
9579
+ return c._def.tag === "lazy" && ruleNameOf4(c) !== void 0 ? lazyTarget(c) ?? c : c;
9554
9580
  }
9555
9581
  run() {
9556
9582
  for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
@@ -9592,7 +9618,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
9592
9618
  analyze(c, active) {
9593
9619
  const def = c._def;
9594
9620
  if (def.tag === "lazy") {
9595
- if (ruleNameOf3(c) !== void 0) return;
9621
+ if (ruleNameOf4(c) !== void 0) return;
9596
9622
  const target = lazyTarget(c);
9597
9623
  if (!target) throw new Unserializable("unresolved unnamed ref");
9598
9624
  if (active.has(target)) {
@@ -9644,7 +9670,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
9644
9670
  const kid = (x) => this.ref(x, selfOf);
9645
9671
  switch (def.tag) {
9646
9672
  case "lazy": {
9647
- if (ruleNameOf3(c) !== void 0) return `g[${JSON.stringify(ruleNameOf3(c))}]`;
9673
+ const name = this.localRuleNames.get(c) ?? ruleNameOf4(c);
9674
+ if (name !== void 0) return `g[${JSON.stringify(name)}]`;
9648
9675
  const target = lazyTarget(c);
9649
9676
  if (selfOf && target === selfOf.comb) return selfOf.var;
9650
9677
  return this.ref(target, selfOf);