parseman 0.42.0 → 0.43.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 (42) hide show
  1. package/dist/combinators/node.d.ts +21 -7
  2. package/dist/combinators/node.d.ts.map +1 -1
  3. package/dist/combinators/parser.d.ts +23 -2
  4. package/dist/combinators/parser.d.ts.map +1 -1
  5. package/dist/compiler/codegen.d.ts +6 -0
  6. package/dist/compiler/codegen.d.ts.map +1 -1
  7. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  8. package/dist/compiler/linker.d.ts +7 -1
  9. package/dist/compiler/linker.d.ts.map +1 -1
  10. package/dist/cst/reflection.d.ts +24 -0
  11. package/dist/cst/reflection.d.ts.map +1 -0
  12. package/dist/cst/types.d.ts +2 -0
  13. package/dist/cst/types.d.ts.map +1 -1
  14. package/dist/cst/walk.d.ts +27 -62
  15. package/dist/cst/walk.d.ts.map +1 -1
  16. package/dist/index.cjs +375 -195
  17. package/dist/index.cjs.map +4 -4
  18. package/dist/index.d.ts +4 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +375 -195
  21. package/dist/index.js.map +4 -4
  22. package/dist/language-service/index.cjs +25 -33
  23. package/dist/language-service/index.cjs.map +4 -4
  24. package/dist/language-service/index.d.ts +1 -1
  25. package/dist/language-service/index.d.ts.map +1 -1
  26. package/dist/language-service/index.js +25 -33
  27. package/dist/language-service/index.js.map +4 -4
  28. package/dist/plugin/evaluator.d.ts +1 -0
  29. package/dist/plugin/evaluator.d.ts.map +1 -1
  30. package/dist/plugin/index.cjs +654 -173
  31. package/dist/plugin/index.cjs.map +4 -4
  32. package/dist/plugin/index.d.ts.map +1 -1
  33. package/dist/plugin/index.js +654 -173
  34. package/dist/plugin/index.js.map +4 -4
  35. package/dist/spec/index.cjs +429 -313
  36. package/dist/spec/index.cjs.map +4 -4
  37. package/dist/spec/index.js +429 -313
  38. package/dist/spec/index.js.map +4 -4
  39. package/dist/types.d.ts +8 -1
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/version.d.ts +1 -1
  42. package/package.json +1 -1
@@ -2777,6 +2777,191 @@ function markUnusedValues(root) {
2777
2777
  visit(resolveRoot(root), true);
2778
2778
  }
2779
2779
 
2780
+ // src/combinators/grammar.ts
2781
+ function annotateResultLines(result, index) {
2782
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
2783
+ const errors = annotated.errors;
2784
+ if (errors) {
2785
+ ;
2786
+ annotated.errors = errors.map((error) => ({
2787
+ ...error,
2788
+ span: annotateSpan(error.span, index)
2789
+ }));
2790
+ }
2791
+ return annotated;
2792
+ }
2793
+ function createParseLineContext(input, pos) {
2794
+ const lineIndex = createLineIndex();
2795
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
2796
+ return { lineIndex, lineScannedTo: pos };
2797
+ }
2798
+ function parser(opts, root) {
2799
+ const clearTrivia = opts.trivia === null;
2800
+ return {
2801
+ _tag: "grammar",
2802
+ _meta: root._meta,
2803
+ _def: {
2804
+ tag: "grammar",
2805
+ parser: root,
2806
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2807
+ clearTrivia,
2808
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2809
+ trackLines: opts.trackLines ?? false
2810
+ },
2811
+ parse(input, pos, _ctx) {
2812
+ const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2813
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2814
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
2815
+ const ctx = {
2816
+ ..._ctx,
2817
+ trackLines,
2818
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
2819
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
2820
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2821
+ ...clearTrivia ? {
2822
+ trivia: void 0,
2823
+ triviaKindLabels: void 0
2824
+ } : opts.trivia != null ? {
2825
+ trivia: opts.trivia,
2826
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
2827
+ } : {},
2828
+ ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
2829
+ // Kind-filter for per-node capture. Resolve against this scope's trivia
2830
+ // labels — this parser's own trivia if it declares one, else the INHERITED
2831
+ // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2832
+ // trivia is inherited rather than re-declared here. No labels → undefined
2833
+ // (capture all).
2834
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2835
+ };
2836
+ const result = root.parse(input, pos ?? 0, ctx);
2837
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
2838
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
2839
+ }
2840
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
2841
+ }
2842
+ };
2843
+ }
2844
+ function noTrivia(root) {
2845
+ return parser({ trivia: null }, root);
2846
+ }
2847
+
2848
+ // src/cst/reflection.ts
2849
+ var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
2850
+ function childrenOf(def) {
2851
+ switch (def.tag) {
2852
+ case "sequence":
2853
+ case "choice":
2854
+ return def.parsers;
2855
+ case "dispatch":
2856
+ return [
2857
+ def.selector,
2858
+ ...def.cases.map((c) => c.parser),
2859
+ ...def.matchers ? def.matchers.map((c) => c.parser) : [],
2860
+ ...def.otherwise ? [def.otherwise] : []
2861
+ ];
2862
+ case "many":
2863
+ case "oneOrMore":
2864
+ case "optional":
2865
+ case "attempt":
2866
+ case "transform":
2867
+ case "trivia":
2868
+ case "token":
2869
+ case "leaf":
2870
+ case "label":
2871
+ case "field":
2872
+ case "not":
2873
+ case "peek":
2874
+ case "node":
2875
+ case "withCtx":
2876
+ case "recover":
2877
+ case "expect":
2878
+ return [def.parser];
2879
+ case "grammar":
2880
+ return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
2881
+ case "sepBy":
2882
+ return [def.parser, def.separator];
2883
+ case "skip":
2884
+ return [def.main, def.skipped];
2885
+ case "scanTo":
2886
+ return [def.sentinel, ...def.skip];
2887
+ case "literal":
2888
+ case "regex":
2889
+ case "keywords":
2890
+ case "routed":
2891
+ case "guard":
2892
+ case "lazy":
2893
+ case "unknown":
2894
+ return [];
2895
+ }
2896
+ }
2897
+ function addNode(out, def) {
2898
+ if (def.type === void 0) return;
2899
+ const existing = out.get(def.type);
2900
+ if (existing === void 0) {
2901
+ out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
2902
+ return;
2903
+ }
2904
+ if (def.tags === void 0) return;
2905
+ for (const tag of def.tags) {
2906
+ if (!existing.includes(tag)) existing.push(tag);
2907
+ }
2908
+ }
2909
+ function collectFromCombinator(parser2, out, seen, followLazy = true) {
2910
+ if (seen.has(parser2)) return;
2911
+ seen.add(parser2);
2912
+ const def = parser2._def;
2913
+ if (def.tag === "lazy") {
2914
+ if (followLazy) {
2915
+ try {
2916
+ collectFromCombinator(def.thunk(), out, seen, followLazy);
2917
+ } catch {
2918
+ }
2919
+ }
2920
+ return;
2921
+ }
2922
+ if (def.tag === "node") addNode(out, def);
2923
+ for (const child of childrenOf(def)) collectFromCombinator(child, out, seen, followLazy);
2924
+ }
2925
+ function collectGrammarReflection(ruleMap, opts) {
2926
+ const byType = /* @__PURE__ */ new Map();
2927
+ const followLazy = opts?.followLazy !== false;
2928
+ for (const [, rule] of ruleMap) {
2929
+ if (!followLazy && rule._def.tag === "lazy") {
2930
+ try {
2931
+ const resolved = rule._def.thunk();
2932
+ if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
2933
+ } catch {
2934
+ }
2935
+ continue;
2936
+ }
2937
+ collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
2938
+ }
2939
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
2940
+ }
2941
+ function mergeGrammarReflections(reflections) {
2942
+ const byType = /* @__PURE__ */ new Map();
2943
+ for (const reflection of reflections) {
2944
+ for (const node2 of reflection.nodes) {
2945
+ const tags = byType.get(node2.type);
2946
+ if (tags === void 0) {
2947
+ byType.set(node2.type, [...node2.tags]);
2948
+ continue;
2949
+ }
2950
+ for (const tag of node2.tags) {
2951
+ if (!tags.includes(tag)) tags.push(tag);
2952
+ }
2953
+ }
2954
+ }
2955
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
2956
+ }
2957
+ function attachGrammarReflection(grammar, reflection) {
2958
+ Object.defineProperty(grammar, GRAMMAR_REFLECTION, { value: reflection, enumerable: false, configurable: true });
2959
+ return grammar;
2960
+ }
2961
+ function grammarReflectionSource(reflection) {
2962
+ return `{ nodes: ${JSON.stringify(reflection.nodes)} }`;
2963
+ }
2964
+
2780
2965
  // src/combinators/parser.ts
2781
2966
  var RULE_ORDER = "__parsemanRuleOrder";
2782
2967
  function tagRule(r, key) {
@@ -2852,6 +3037,21 @@ function rules(a, b) {
2852
3037
  if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
2853
3038
  }
2854
3039
  }
3040
+ if (options?.trackLines === true) {
3041
+ for (const key of Object.keys(definitions)) {
3042
+ const rule = cache[key];
3043
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
3044
+ }
3045
+ for (const key of Object.keys(definitions)) {
3046
+ const rule = cache[key];
3047
+ if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
3048
+ const wrapped = parser({ trackLines: true }, rule);
3049
+ tagRule(wrapped, key);
3050
+ wrapped._meta.grammarTrackLines = true;
3051
+ cache[key] = wrapped;
3052
+ }
3053
+ }
3054
+ }
2855
3055
  for (const key of Object.keys(definitions)) {
2856
3056
  markUnusedValues(cache[key]);
2857
3057
  }
@@ -2860,6 +3060,7 @@ function rules(a, b) {
2860
3060
  enumerable: false,
2861
3061
  configurable: true
2862
3062
  });
3063
+ attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
2863
3064
  return cache;
2864
3065
  }
2865
3066
 
@@ -3180,13 +3381,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3180
3381
  const collapse = opts?.collapse === true;
3181
3382
  const captureTrivia = opts?.captureTrivia === true;
3182
3383
  const trailingTrivia = opts?.trailingTrivia === true;
3384
+ const tags = opts?.tags;
3183
3385
  if (unwrap && collapse) {
3184
3386
  throw new Error("node() options cannot set both unwrap and collapse");
3185
3387
  }
3186
3388
  if (project !== void 0 && (unwrap || collapse)) {
3187
3389
  throw new Error("node() options cannot combine project with unwrap or collapse");
3188
3390
  }
3189
- const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3391
+ const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
3190
3392
  const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3191
3393
  const clonesState = build ? buildReadsState(def) : project === void 0;
3192
3394
  const hasOwnFields = parserHasOwnFields(combinator);
@@ -3232,7 +3434,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3232
3434
  const cstOutput = cstOutputHost(ctx.build);
3233
3435
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
3234
3436
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3235
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3437
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3236
3438
  const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
3237
3439
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3238
3440
  pushCstChild(ctx, built, rawEntry);
@@ -3308,74 +3510,6 @@ function field(name, combinator) {
3308
3510
  };
3309
3511
  }
3310
3512
 
3311
- // src/combinators/grammar.ts
3312
- function annotateResultLines(result, index) {
3313
- const annotated = { ...result, span: annotateSpan(result.span, index) };
3314
- const errors = annotated.errors;
3315
- if (errors) {
3316
- ;
3317
- annotated.errors = errors.map((error) => ({
3318
- ...error,
3319
- span: annotateSpan(error.span, index)
3320
- }));
3321
- }
3322
- return annotated;
3323
- }
3324
- function createParseLineContext(input, pos) {
3325
- const lineIndex = createLineIndex();
3326
- if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3327
- return { lineIndex, lineScannedTo: pos };
3328
- }
3329
- function parser(opts, root) {
3330
- const clearTrivia = opts.trivia === null;
3331
- return {
3332
- _tag: "grammar",
3333
- _meta: root._meta,
3334
- _def: {
3335
- tag: "grammar",
3336
- parser: root,
3337
- triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
3338
- clearTrivia,
3339
- ...opts.captureTrivia ? { captureTrivia: true } : {},
3340
- trackLines: opts.trackLines ?? false
3341
- },
3342
- parse(input, pos, _ctx) {
3343
- const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3344
- const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3345
- const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
3346
- const ctx = {
3347
- ..._ctx,
3348
- trackLines,
3349
- ...lineIndex ? { _lineIndex: lineIndex } : {},
3350
- ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3351
- // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
3352
- ...clearTrivia ? {
3353
- trivia: void 0,
3354
- triviaKindLabels: void 0
3355
- } : opts.trivia != null ? {
3356
- trivia: opts.trivia,
3357
- ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
3358
- } : {},
3359
- ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
3360
- // Kind-filter for per-node capture. Resolve against this scope's trivia
3361
- // labels — this parser's own trivia if it declares one, else the INHERITED
3362
- // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
3363
- // trivia is inherited rather than re-declared here. No labels → undefined
3364
- // (capture all).
3365
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3366
- };
3367
- const result = root.parse(input, pos ?? 0, ctx);
3368
- if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3369
- _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
3370
- }
3371
- return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3372
- }
3373
- };
3374
- }
3375
- function noTrivia(root) {
3376
- return parser({ trivia: null }, root);
3377
- }
3378
-
3379
3513
  // src/combinators/token.ts
3380
3514
  function token(root) {
3381
3515
  const meta = {
@@ -3472,7 +3606,7 @@ function leaf(root, fn) {
3472
3606
  }
3473
3607
 
3474
3608
  // src/version.ts
3475
- var PARSEMAN_VERSION = "0.42.0";
3609
+ var PARSEMAN_VERSION = "0.43.0";
3476
3610
 
3477
3611
  // src/cst/host-mode.ts
3478
3612
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -3538,7 +3672,7 @@ var SUGGESTIONS = {
3538
3672
  function classifyBroadArm(arm, resolve2) {
3539
3673
  const seen = /* @__PURE__ */ new Set();
3540
3674
  const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
3541
- const walk2 = (p) => {
3675
+ const walk = (p) => {
3542
3676
  if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
3543
3677
  seen.add(p);
3544
3678
  const d = p._def;
@@ -3552,7 +3686,7 @@ function classifyBroadArm(arm, resolve2) {
3552
3686
  // peek() CARRIES its body's first-set, so it is only broad when the body is
3553
3687
  // (or the body is nullable) — walk in for the real cause.
3554
3688
  case "peek":
3555
- return walk2(d.parser);
3689
+ return walk(d.parser);
3556
3690
  case "scanTo":
3557
3691
  return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
3558
3692
  // `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
@@ -3566,7 +3700,7 @@ function classifyBroadArm(arm, resolve2) {
3566
3700
  case "attempt":
3567
3701
  case "withCtx":
3568
3702
  case "recover":
3569
- return walk2(d.parser);
3703
+ return walk(d.parser);
3570
3704
  case "lazy": {
3571
3705
  const name = p._ruleName;
3572
3706
  let target;
@@ -3578,13 +3712,13 @@ function classifyBroadArm(arm, resolve2) {
3578
3712
  return { cause: "cross-artifact-ref", detail: `unresolved ref${name ? ` g.${name}` : ""}`, unresolvedExternal: name !== void 0 };
3579
3713
  target = bound;
3580
3714
  }
3581
- const inner = walk2(target);
3715
+ const inner = walk(target);
3582
3716
  if (name !== void 0) return inner ? relabel(inner, "cross-artifact-ref", `via ref g.${name} \u2192 ${inner.detail}`) : null;
3583
3717
  return inner;
3584
3718
  }
3585
3719
  case "optional":
3586
3720
  case "many": {
3587
- const inner = walk2(d.parser);
3721
+ const inner = walk(d.parser);
3588
3722
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3589
3723
  }
3590
3724
  case "oneOrMore":
@@ -3597,9 +3731,9 @@ function classifyBroadArm(arm, resolve2) {
3597
3731
  case "node":
3598
3732
  case "grammar":
3599
3733
  case "expect":
3600
- return walk2(d.parser);
3734
+ return walk(d.parser);
3601
3735
  case "skip":
3602
- return walk2(d.main);
3736
+ return walk(d.main);
3603
3737
  case "sequence": {
3604
3738
  let sawNullablePrefix = false;
3605
3739
  for (const t of d.parsers) {
@@ -3608,7 +3742,7 @@ function classifyBroadArm(arm, resolve2) {
3608
3742
  continue;
3609
3743
  }
3610
3744
  if (isAny(firstSetOf(t, /* @__PURE__ */ new Set(), resolve2))) {
3611
- const inner = walk2(t);
3745
+ const inner = walk(t);
3612
3746
  if (sawNullablePrefix)
3613
3747
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3614
3748
  return inner ?? { cause: "broad-recognizer", detail: "sequence leading term is broad" };
@@ -3623,18 +3757,18 @@ function classifyBroadArm(arm, resolve2) {
3623
3757
  }
3624
3758
  case "choice": {
3625
3759
  for (const a of d.parsers) {
3626
- const r = walk2(a);
3760
+ const r = walk(a);
3627
3761
  if (r) return relabel(r, r.cause, `choice arm \u2192 ${r.detail}`);
3628
3762
  }
3629
3763
  return null;
3630
3764
  }
3631
3765
  case "dispatch":
3632
- return walk2(d.selector);
3766
+ return walk(d.selector);
3633
3767
  default:
3634
3768
  return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
3635
3769
  }
3636
3770
  };
3637
- return walk2(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
3771
+ return walk(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
3638
3772
  }
3639
3773
  function peelToLeading(arm) {
3640
3774
  let d = arm._def;
@@ -3836,7 +3970,7 @@ function formatGatingWarnings(report) {
3836
3970
 
3837
3971
  // src/analysis/duplication.ts
3838
3972
  var siteToString = (s) => s.path === "" ? s.rule : `${s.rule} \u203A ${s.path}`;
3839
- function childrenOf(d) {
3973
+ function childrenOf2(d) {
3840
3974
  switch (d.tag) {
3841
3975
  case "sequence":
3842
3976
  case "choice":
@@ -3970,7 +4104,7 @@ function render(p, depth = 3) {
3970
4104
  break;
3971
4105
  }
3972
4106
  if (depth <= 0) return `${d.tag}(\u2026)`;
3973
- const kids = childrenOf(d).map((k) => render(k, depth - 1));
4107
+ const kids = childrenOf2(d).map((k) => render(k, depth - 1));
3974
4108
  switch (d.tag) {
3975
4109
  case "sequence":
3976
4110
  return `sequence(${kids.join(", ")})`;
@@ -4165,7 +4299,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4165
4299
  if (hit !== void 0) return hit;
4166
4300
  const d = p._def;
4167
4301
  shapeCache.set(p, interner.hole);
4168
- const kids = childrenOf(d);
4302
+ const kids = childrenOf2(d);
4169
4303
  const id = interner.of(`${payloadKey(p, d)}|${kids.map(shapeOf).join(",")}`);
4170
4304
  shapeCache.set(p, id);
4171
4305
  return id;
@@ -4175,7 +4309,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4175
4309
  if (hit !== void 0) return hit;
4176
4310
  sizeCache.set(p, 1);
4177
4311
  let n = 1;
4178
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4312
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4179
4313
  sizeCache.set(p, n);
4180
4314
  return n;
4181
4315
  };
@@ -4188,7 +4322,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4188
4322
  visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
4189
4323
  const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
4190
4324
  const innerReducer = enclosingReducer || d.tag === "node" && (d.build !== void 0 || d.buildSrc !== void 0) || d.tag === "transform" || d.tag === "leaf";
4191
- const kids = childrenOf(d);
4325
+ const kids = childrenOf2(d);
4192
4326
  kids.forEach((k, i) => {
4193
4327
  const seg = segment(d, i);
4194
4328
  visit(k, here.rule, here.path === "" ? seg : `${here.path} \u203A ${seg}`, inner, innerReducer);
@@ -4248,7 +4382,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4248
4382
  function markSubtree(p, into) {
4249
4383
  if (into.has(p)) return;
4250
4384
  into.add(p);
4251
- for (const k of childrenOf(p._def)) markSubtree(k, into);
4385
+ for (const k of childrenOf2(p._def)) markSubtree(k, into);
4252
4386
  }
4253
4387
  var stripMembers = (f) => {
4254
4388
  const { _members, ...rest } = f;
@@ -4288,7 +4422,7 @@ function findNearDuplicates(visited, interner, shapeOf, minSize) {
4288
4422
  if (hit !== void 0) return hit;
4289
4423
  holeCache.set(p, []);
4290
4424
  const d = p._def;
4291
- const kids = childrenOf(d);
4425
+ const kids = childrenOf2(d);
4292
4426
  const kidShapes = kids.map(shapeOf);
4293
4427
  const payload = payloadKey(p, d);
4294
4428
  const out2 = [];
@@ -4349,7 +4483,7 @@ function findDivergentSlot(members, shapeOf) {
4349
4483
  let cur = [...members];
4350
4484
  for (let guard2 = 0; guard2 < 64; guard2++) {
4351
4485
  const d0 = cur[0]._def;
4352
- const kidLists = cur.map((c) => childrenOf(c._def));
4486
+ const kidLists = cur.map((c) => childrenOf2(c._def));
4353
4487
  const arity = kidLists[0].length;
4354
4488
  if (kidLists.some((k) => k.length !== arity) || arity === 0) break;
4355
4489
  const diff = [];
@@ -4362,7 +4496,7 @@ function findDivergentSlot(members, shapeOf) {
4362
4496
  path2.push(i);
4363
4497
  defs.push(d0);
4364
4498
  cur = kidLists.map((k) => k[i]);
4365
- const nextArity = childrenOf(cur[0]._def).length;
4499
+ const nextArity = childrenOf2(cur[0]._def).length;
4366
4500
  const samePayload = cur.every((c) => payloadKey(c, c._def) === payloadKey(cur[0], cur[0]._def));
4367
4501
  if (!samePayload || nextArity === 0) break;
4368
4502
  }
@@ -4370,7 +4504,7 @@ function findDivergentSlot(members, shapeOf) {
4370
4504
  let slotSize = 0;
4371
4505
  const sizeOf = (p) => {
4372
4506
  let n = 1;
4373
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4507
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4374
4508
  return n;
4375
4509
  };
4376
4510
  for (const c of cur) slotSize = Math.max(slotSize, sizeOf(c));
@@ -4379,7 +4513,7 @@ function findDivergentSlot(members, shapeOf) {
4379
4513
  function renderWithHole(p, path2, depth = 0) {
4380
4514
  if (depth === path2.length) return "\u2039slot\u203A";
4381
4515
  const d = p._def;
4382
- const kids = childrenOf(d);
4516
+ const kids = childrenOf2(d);
4383
4517
  const idx = path2[depth];
4384
4518
  const parts = kids.map((k, i) => i === idx ? renderWithHole(k, path2, depth + 1) : render(k, 2));
4385
4519
  switch (d.tag) {
@@ -4837,7 +4971,7 @@ function capturesPositionally(p, seen = /* @__PURE__ */ new Set()) {
4837
4971
  seen.add(p);
4838
4972
  const d = p._def;
4839
4973
  if (d.tag === "field" || d.tag === "label") return true;
4840
- for (const k of childrenOf(d)) if (capturesPositionally(k, seen)) return true;
4974
+ for (const k of childrenOf2(d)) if (capturesPositionally(k, seen)) return true;
4841
4975
  return false;
4842
4976
  }
4843
4977
  function detectHandRolledSepBy(terms, shapeOf) {
@@ -4943,7 +5077,7 @@ function nestedNodeTypes(root, out, seen, isRoot) {
4943
5077
  }
4944
5078
  return;
4945
5079
  }
4946
- for (const k of childrenOf(d)) nestedNodeTypes(k, out, seen, false);
5080
+ for (const k of childrenOf2(d)) nestedNodeTypes(k, out, seen, false);
4947
5081
  }
4948
5082
  var MAX_LOST_TYPES = 8;
4949
5083
  function findStructureLoss(visited, resolve2) {
@@ -6840,13 +6974,16 @@ function reindentStmts(stmts, targetLevels) {
6840
6974
  const targetPrefix = " ".repeat(targetLevels);
6841
6975
  return stmts.map((s) => s.trim().length === 0 ? "" : targetPrefix + s.slice(minLeading));
6842
6976
  }
6843
- function failReturn(expected, posExpr) {
6977
+ function failReturn(ctx, expected, posExpr) {
6978
+ if (ctx.lineTracking) return `return { ok: false, expected: [${expected}], span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6844
6979
  return `return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6845
6980
  }
6846
- function failReturnArr(expectedArr, posExpr) {
6981
+ function failReturnArr(ctx, expectedArr, posExpr) {
6982
+ if (ctx.lineTracking) return `return { ok: false, expected: ${expectedArr}, span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6847
6983
  return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
6848
6984
  }
6849
- function committedReturnArr(expectedArr, posExpr) {
6985
+ function committedReturnArr(ctx, expectedArr, posExpr) {
6986
+ if (ctx.lineTracking) return `return { ok: false, expected: [...${expectedArr}], span: ${emitSpanExpr(ctx, posExpr, posExpr)}, committed: true }`;
6850
6987
  return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
6851
6988
  }
6852
6989
  function hoistExpected(ctx, constArrSource) {
@@ -6871,7 +7008,7 @@ function failBody(ctx, expected, posExpr) {
6871
7008
  if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
6872
7009
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
6873
7010
  }
6874
- return probe + trace + failReturn(expected, posExpr);
7011
+ return probe + trace + failReturn(ctx, expected, posExpr);
6875
7012
  }
6876
7013
  function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6877
7014
  const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
@@ -6881,18 +7018,19 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6881
7018
  const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
6882
7019
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
6883
7020
  }
6884
- if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6885
- return probe + trace + failReturnArr(expectedArr, posExpr);
7021
+ if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: ${ctx.lineTracking ? emitSpanExpr(ctx, posExpr, posExpr) : `{ start: ${posExpr}, end: ${posExpr} }`} }`;
7022
+ return probe + trace + failReturnArr(ctx, expectedArr, posExpr);
6886
7023
  }
6887
- function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
6888
- return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
7024
+ function resultFromRecorded(ctx, feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
7025
+ const spanExpr = ctx.lineTracking ? emitSpanExpr(ctx, feExpr, feExpr) : `{ start: ${feExpr}, end: ${feExpr} }`;
7026
+ return `return { ok: false, expected: [...${fxExpr}], span: ${spanExpr}, ...(_ctx._fc ? { committed: true } : {}) }`;
6889
7027
  }
6890
7028
  function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
6891
7029
  if (ctx.failLabel) {
6892
7030
  if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
6893
7031
  return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
6894
7032
  }
6895
- return committedReturnArr(expectedArr, posExpr);
7033
+ return committedReturnArr(ctx, expectedArr, posExpr);
6896
7034
  }
6897
7035
  function propagateFailBody(ctx, srcCtx = "_ctx") {
6898
7036
  if (srcCtx !== "_ctx") {
@@ -6900,10 +7038,10 @@ function propagateFailBody(ctx, srcCtx = "_ctx") {
6900
7038
  if (!ctx.recordFail) return `break ${ctx.failLabel}`;
6901
7039
  return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
6902
7040
  }
6903
- return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
7041
+ return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded(ctx)} }`;
6904
7042
  }
6905
7043
  if (ctx.failLabel) return `break ${ctx.failLabel}`;
6906
- return resultFromRecorded();
7044
+ return resultFromRecorded(ctx);
6907
7045
  }
6908
7046
  function emitIfFail(ctx, cond, body) {
6909
7047
  return [
@@ -8134,7 +8272,7 @@ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8134
8272
  const d = p._def;
8135
8273
  if (d.tag === "dispatch") return false;
8136
8274
  if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8137
- return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8275
+ return childrenOf3(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8138
8276
  }
8139
8277
  function armReplayInScope(arm, ctx) {
8140
8278
  let p = arm;
@@ -8336,7 +8474,7 @@ function emitAttempt(p, def, ctx, pos) {
8336
8474
  if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
8337
8475
  const gcV = v(ctx, "_agc");
8338
8476
  const gExp = armStaticExpected(ctx, def.parser);
8339
- const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
8477
+ const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(ctx, gExp, pos)} }`;
8340
8478
  preGuard.push(
8341
8479
  `${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8342
8480
  `${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -8835,7 +8973,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8835
8973
  if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
8836
8974
  const gcV = v(ctx, "_ngc");
8837
8975
  const gExp = armStaticExpected(ctx, def.parser);
8838
- const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
8976
+ const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
8839
8977
  preGuard.push(
8840
8978
  `${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8841
8979
  `${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -8897,7 +9035,8 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8897
9035
  const nodeSpanV = ctx.lineTracking ? v(ctx, "_nspan") : nodeSpanExpr;
8898
9036
  if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
8899
9037
  const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: ${nodeSpanV}, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, nodeSpanV, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
8900
- const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
9038
+ const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
9039
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${hostBuildArgs})`;
8901
9040
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8902
9041
  const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
8903
9042
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
@@ -9351,6 +9490,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9351
9490
  if (seen.has(p)) return false;
9352
9491
  seen.add(p);
9353
9492
  const d = p._def;
9493
+ if (p._meta.grammarTrackLines) return true;
9354
9494
  if (d.tag === "grammar" && d.trackLines) return true;
9355
9495
  if (d.tag === "lazy") {
9356
9496
  try {
@@ -9359,7 +9499,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9359
9499
  return false;
9360
9500
  }
9361
9501
  }
9362
- return childrenOf2(d).some((child) => hasLineTrackingDef(child, seen));
9502
+ return childrenOf3(d).some((child) => hasLineTrackingDef(child, seen));
9363
9503
  }
9364
9504
  function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9365
9505
  if (seen.has(p)) return false;
@@ -9378,7 +9518,7 @@ function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9378
9518
  case "dispatch":
9379
9519
  return false;
9380
9520
  default:
9381
- return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
9521
+ return childrenOf3(d).some((child) => parserUsesRouted2(child, seen));
9382
9522
  }
9383
9523
  }
9384
9524
  function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
@@ -9393,9 +9533,9 @@ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
9393
9533
  return false;
9394
9534
  }
9395
9535
  }
9396
- return childrenOf2(d).some((child) => hasDirectBuildDef(child, seen));
9536
+ return childrenOf3(d).some((child) => hasDirectBuildDef(child, seen));
9397
9537
  }
9398
- function childrenOf2(def) {
9538
+ function childrenOf3(def) {
9399
9539
  switch (def.tag) {
9400
9540
  case "sequence":
9401
9541
  case "choice":
@@ -9470,7 +9610,7 @@ function subtreeSizes(roots) {
9470
9610
  const def = p._def;
9471
9611
  let s = 1;
9472
9612
  if (def.tag !== "lazy") {
9473
- for (const child of childrenOf2(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
9613
+ for (const child of childrenOf3(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
9474
9614
  }
9475
9615
  sizes.set(p, s);
9476
9616
  return s;
@@ -9491,7 +9631,7 @@ function subtreeSizes(roots) {
9491
9631
  return;
9492
9632
  }
9493
9633
  sz(p);
9494
- for (const child of childrenOf2(def)) visit(child);
9634
+ for (const child of childrenOf3(def)) visit(child);
9495
9635
  };
9496
9636
  for (const root of roots) visit(root);
9497
9637
  return sizes;
@@ -9501,7 +9641,7 @@ function analyzeLazyUsageMulti(roots) {
9501
9641
  const recursive = /* @__PURE__ */ new Set();
9502
9642
  const descended = /* @__PURE__ */ new Set();
9503
9643
  const active = /* @__PURE__ */ new Set();
9504
- function walk2(p) {
9644
+ function walk(p) {
9505
9645
  const def = p._def;
9506
9646
  if (def.tag === "lazy") {
9507
9647
  counts.set(p, (counts.get(p) ?? 0) + 1);
@@ -9518,17 +9658,17 @@ function analyzeLazyUsageMulti(roots) {
9518
9658
  return;
9519
9659
  }
9520
9660
  active.add(p);
9521
- walk2(resolved);
9661
+ walk(resolved);
9522
9662
  active.delete(p);
9523
9663
  return;
9524
9664
  }
9525
9665
  if (isHoistableTag(def.tag)) {
9526
9666
  counts.set(p, (counts.get(p) ?? 0) + 1);
9527
9667
  }
9528
- for (const child of childrenOf2(def)) walk2(child);
9668
+ for (const child of childrenOf3(def)) walk(child);
9529
9669
  }
9530
9670
  const rootsArr = [...roots];
9531
- for (const root of rootsArr) walk2(root);
9671
+ for (const root of rootsArr) walk(root);
9532
9672
  return { counts, recursive, sizes: subtreeSizes(rootsArr) };
9533
9673
  }
9534
9674
  function ruleDependencies(ruleMap) {
@@ -9538,7 +9678,7 @@ function ruleDependencies(ruleMap) {
9538
9678
  for (const [name, comb] of ruleMap) {
9539
9679
  const found = /* @__PURE__ */ new Set();
9540
9680
  const seen = /* @__PURE__ */ new Set();
9541
- const walk2 = (p, isRoot) => {
9681
+ const walk = (p, isRoot) => {
9542
9682
  const def = p._def;
9543
9683
  const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
9544
9684
  if (!isRoot && boundary !== void 0) {
@@ -9554,12 +9694,12 @@ function ruleDependencies(ruleMap) {
9554
9694
  } catch {
9555
9695
  return;
9556
9696
  }
9557
- walk2(resolved, false);
9697
+ walk(resolved, false);
9558
9698
  return;
9559
9699
  }
9560
- for (const child of childrenOf2(def)) walk2(child, false);
9700
+ for (const child of childrenOf3(def)) walk(child, false);
9561
9701
  };
9562
- walk2(comb, true);
9702
+ walk(comb, true);
9563
9703
  deps.set(name, [...found]);
9564
9704
  }
9565
9705
  return deps;
@@ -9708,6 +9848,7 @@ function compile(combinator, mapFnSources, opts) {
9708
9848
  const grammarTrivia = combinator._meta.grammarTrivia;
9709
9849
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9710
9850
  const grammarHostMode = combinator._meta.grammarHostMode;
9851
+ const grammarTrackLines = combinator._meta.grammarTrackLines;
9711
9852
  const ctx = {
9712
9853
  vars: 0,
9713
9854
  indent: 1,
@@ -9728,7 +9869,7 @@ function compile(combinator, mapFnSources, opts) {
9728
9869
  capturing: hasNodeDef(combinator),
9729
9870
  recovery: opts?.recovery ?? false,
9730
9871
  hostMode: opts?.hostMode ?? grammarHostMode ?? "ast",
9731
- lineTracking: opts?.trackLines === true || hasLineTrackingDef(combinator),
9872
+ lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9732
9873
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9733
9874
  lazyUsage: analyzeLazyUsage(combinator),
9734
9875
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9892,6 +10033,7 @@ function compileRuleMap(ruleMap, opts) {
9892
10033
  const grammarTrivia = opts?.trivia;
9893
10034
  const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
9894
10035
  const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10036
+ const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
9895
10037
  const ctx = {
9896
10038
  vars: 0,
9897
10039
  indent: 1,
@@ -9912,6 +10054,7 @@ function compileRuleMap(ruleMap, opts) {
9912
10054
  capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
9913
10055
  recovery: opts?.recovery ?? false,
9914
10056
  hostMode: grammarHostMode ?? "ast",
10057
+ lineTracking: grammarTrackLines,
9915
10058
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
9916
10059
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
9917
10060
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9945,6 +10088,10 @@ function compileRuleMap(ruleMap, opts) {
9945
10088
  const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
9946
10089
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
9947
10090
  if (!canInline) return null;
10091
+ if (ctx.lineTracking) {
10092
+ ctx.needsLineTrack = true;
10093
+ ctx.needsLineSpan = true;
10094
+ }
9948
10095
  const mfDecl = derivedSrcs?.length ? ` const ${mfRef(ctx)} = [${derivedSrcs.join(", ")}]` : "";
9949
10096
  const buildDecl = buildSources?.length ? ` const ${buildRef(ctx)} = [${buildSources.join(", ")}]` : "";
9950
10097
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
@@ -9974,15 +10121,23 @@ function compileRuleMap(ruleMap, opts) {
9974
10121
  };
9975
10122
  const entryFnText = (r, rule) => {
9976
10123
  const ruleId = entryRuleId(rule);
10124
+ const linePreamble = ctx.lineTracking ? [
10125
+ ` if (_ctx._lineStarts === undefined) _ctx = { ..._ctx, trackLines: true, _lineStarts: [0], _lineScannedTo: 0 }`,
10126
+ ` else _ctx.trackLines = true`,
10127
+ ` if (_pos > (_ctx._lineScannedTo ?? 0)) _trackLines(_ctx, input, 0, _pos)`
10128
+ ] : [];
10129
+ const resultSpan = ctx.lineTracking ? `_spanLines(_ctx, _pos, ${r.endVar})` : `{ start: _pos, end: ${r.endVar} }`;
9977
10130
  const body = ruleId === void 0 ? [
10131
+ ...linePreamble,
9978
10132
  ` let pos = _pos`,
9979
10133
  ...r.stmts,
9980
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
10134
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`
9981
10135
  ] : [
10136
+ ...linePreamble,
9982
10137
  ` const _coverageResult = (() => {`,
9983
10138
  ` let pos = _pos`,
9984
10139
  ...r.stmts,
9985
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
10140
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
9986
10141
  ` })()`,
9987
10142
  ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
9988
10143
  ` return _coverageResult`
@@ -10009,6 +10164,7 @@ function compileRuleMap(ruleMap, opts) {
10009
10164
  // host check passes vacuously — see `withHostMode` in the plugin.
10010
10165
  hostMode: ctx.hostMode ?? "ast",
10011
10166
  hostBranchElided: !!ctx.hostBranchElided,
10167
+ reflection: collectGrammarReflection(ruleMap),
10012
10168
  ...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
10013
10169
  };
10014
10170
  }
@@ -10020,6 +10176,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10020
10176
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
10021
10177
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
10022
10178
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10179
+ const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
10023
10180
  const ruleMap = ruleMapArg.filter(([, val]) => {
10024
10181
  const d = val._def;
10025
10182
  if (d.tag !== "lazy") return true;
@@ -10030,6 +10187,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10030
10187
  return false;
10031
10188
  }
10032
10189
  });
10190
+ const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
10033
10191
  const ctx = {
10034
10192
  vars: 0,
10035
10193
  indent: 1,
@@ -10054,6 +10212,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10054
10212
  capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
10055
10213
  recovery: opts?.recovery ?? false,
10056
10214
  hostMode: grammarHostMode ?? "ast",
10215
+ lineTracking: grammarTrackLines,
10057
10216
  ...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
10058
10217
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10059
10218
  ns,
@@ -10104,7 +10263,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10104
10263
  scanExternal(resolved);
10105
10264
  return;
10106
10265
  }
10107
- for (const child of childrenOf2(def)) scanExternal(child);
10266
+ for (const child of childrenOf3(def)) scanExternal(child);
10108
10267
  };
10109
10268
  for (const [, rule] of ruleMap) scanExternal(rule);
10110
10269
  }
@@ -10150,6 +10309,10 @@ function compileLinkable(ruleMapArg, ns, opts) {
10150
10309
  perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
10151
10310
  }
10152
10311
  if (ctx.runtimeParsers.length !== 0) return null;
10312
+ if (ctx.lineTracking) {
10313
+ ctx.needsLineTrack = true;
10314
+ ctx.needsLineSpan = true;
10315
+ }
10153
10316
  const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
10154
10317
  const buildSrcs = ctx.buildFns.length > 0 && ctx.buildSrcs.every((s) => s !== null) ? ctx.buildSrcs : null;
10155
10318
  const ruleFns = /* @__PURE__ */ new Map();
@@ -10163,6 +10326,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
10163
10326
  const mfDecl = ctx.mapFns.length === 0 ? "" : mfSrcs ? `const ${mfRef(ctx)} = [${mfSrcs.join(", ")}]` : `const ${mfRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "mf")}]`;
10164
10327
  const buildDecl = ctx.buildFns.length === 0 ? "" : buildSrcs ? `const ${buildRef(ctx)} = [${buildSrcs.join(", ")}]` : `const ${buildRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "build")}]`;
10165
10328
  const prelude = [
10329
+ ctx.needsLineTrack ? LINE_TRACK_DECL : "",
10330
+ ctx.needsLineSpan ? LINE_SPAN_DECL : "",
10166
10331
  ...ctx.regexDecls,
10167
10332
  ...ctx.expectedDecls,
10168
10333
  mfDecl,
@@ -10171,11 +10336,18 @@ function compileLinkable(ruleMapArg, ns, opts) {
10171
10336
  ].filter(Boolean);
10172
10337
  const wrappers = /* @__PURE__ */ new Map();
10173
10338
  for (const { key, rule, r } of perEntry) {
10339
+ const linePreamble = ctx.lineTracking ? [
10340
+ ` if (_ctx._lineStarts === undefined) _ctx = { ..._ctx, trackLines: true, _lineStarts: [0], _lineScannedTo: 0 }`,
10341
+ ` else _ctx.trackLines = true`,
10342
+ ` if (_pos > (_ctx._lineScannedTo ?? 0)) _trackLines(_ctx, input, 0, _pos)`
10343
+ ] : [];
10344
+ const resultSpan = ctx.lineTracking ? `_spanLines(_ctx, _pos, ${r.endVar})` : `{ start: _pos, end: ${r.endVar} }`;
10174
10345
  wrappers.set(key, publicRuleWrapperSource(rule, [
10175
10346
  `function(input, _pos, _ctx) {`,
10347
+ ...linePreamble,
10176
10348
  ` let pos = _pos`,
10177
10349
  ...r.stmts,
10178
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
10350
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10179
10351
  `}`
10180
10352
  ].join("\n"), ctx.triviaKindLabels));
10181
10353
  }
@@ -10213,6 +10385,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10213
10385
  hostBranchElided: !!ctx.hostBranchElided,
10214
10386
  hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
10215
10387
  isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule), externalRefs),
10388
+ nodeMeta,
10216
10389
  mfFns: mfSrcs ? [] : ctx.mapFns,
10217
10390
  buildFns: buildSrcs ? [] : ctx.buildFns
10218
10391
  };
@@ -10233,7 +10406,7 @@ function hasExternalRuleRef(ruleMap) {
10233
10406
  if (resolved === void 0) return p._ruleName !== void 0;
10234
10407
  return visit(resolved);
10235
10408
  }
10236
- return childrenOf2(def).some(visit);
10409
+ return childrenOf3(def).some(visit);
10237
10410
  };
10238
10411
  return ruleMap.some(([, rule]) => visit(rule));
10239
10412
  }
@@ -10255,7 +10428,7 @@ function hasSemanticReduction(roots, externalRefs) {
10255
10428
  return true;
10256
10429
  }
10257
10430
  }
10258
- return childrenOf2(def).some(visit);
10431
+ return childrenOf3(def).some(visit);
10259
10432
  };
10260
10433
  return roots.some(visit);
10261
10434
  }
@@ -10328,7 +10501,7 @@ function withCtx(extra, combinator) {
10328
10501
  }
10329
10502
 
10330
10503
  // src/compiler/ir-serialize.ts
10331
- function childrenOf3(def) {
10504
+ function childrenOf4(def) {
10332
10505
  switch (def.tag) {
10333
10506
  case "sequence":
10334
10507
  case "choice":
@@ -10392,6 +10565,10 @@ function projectOpt(project) {
10392
10565
  if (project === void 0) return void 0;
10393
10566
  return `project: ${project}`;
10394
10567
  }
10568
+ function tagsOpt(tags) {
10569
+ if (tags === void 0 || tags.length === 0) return void 0;
10570
+ return `tags: ${JSON.stringify(tags)}`;
10571
+ }
10395
10572
  function matcherExpr(entry) {
10396
10573
  switch (entry.kind) {
10397
10574
  case "startsWith":
@@ -10605,7 +10782,7 @@ var Serializer = class {
10605
10782
  if (target) this.assertNoRuleRef(target, seen);
10606
10783
  return;
10607
10784
  }
10608
- for (const child of childrenOf3(c._def)) this.assertNoRuleRef(child, seen);
10785
+ for (const child of childrenOf4(c._def)) this.assertNoRuleRef(child, seen);
10609
10786
  }
10610
10787
  /** A `rules()` map wraps each rule value in a named `lazy` proxy; the real body is
10611
10788
  * its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
@@ -10669,7 +10846,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10669
10846
  this.counts.set(c, (this.counts.get(c) ?? 0) + 1);
10670
10847
  if ((this.counts.get(c) ?? 0) > 1) return;
10671
10848
  active.add(c);
10672
- for (const child of childrenOf3(def)) this.analyze(child, active);
10849
+ for (const child of childrenOf4(def)) this.analyze(child, active);
10673
10850
  active.delete(c);
10674
10851
  }
10675
10852
  /** Reference `c`: a const var if it has one (emitting its decl first), else inline.
@@ -10786,12 +10963,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10786
10963
  case "node": {
10787
10964
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10788
10965
  const projectEntry = projectOpt(def.project);
10966
+ const tagEntry = tagsOpt(def.tags);
10789
10967
  const optEntries = [
10790
10968
  ...def.unwrap ? ["unwrap: true"] : [],
10791
10969
  ...def.collapse ? ["collapse: true"] : [],
10792
10970
  ...projectEntry === void 0 ? [] : [projectEntry],
10793
10971
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10794
- ...def.trailingTrivia ? ["trailingTrivia: true"] : []
10972
+ ...def.trailingTrivia ? ["trailingTrivia: true"] : [],
10973
+ ...tagEntry === void 0 ? [] : [tagEntry]
10795
10974
  ];
10796
10975
  const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
10797
10976
  if (def.type === void 0) {
@@ -10829,15 +11008,16 @@ function normalizeCstCollapse(collapse) {
10829
11008
  }
10830
11009
  return typeof collapse === "function" ? collapse : void 0;
10831
11010
  }
10832
- function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
10833
- return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
11011
+ function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state, tags) {
11012
+ return tags !== void 0 && tags.length > 0 ? { _tag: "node", type, tags, span: { ...span }, state: state ?? null, children: [...children2] } : { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
10834
11013
  }
10835
- function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
11014
+ function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state, _tags) {
10836
11015
  if (typeof typeOrOptions === "string") {
10837
11016
  return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
10838
11017
  }
10839
11018
  const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
10840
- const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2);
11019
+ const materializeTags = typeOrOptions?.tags === true;
11020
+ const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
10841
11021
  host._parsemanCstOutput = true;
10842
11022
  if (collapse) host._parsemanCstCollapse = collapse;
10843
11023
  return host;
@@ -10858,7 +11038,7 @@ function pickPieces(pieces, names) {
10858
11038
  };
10859
11039
  for (const n of names) visit(n);
10860
11040
  const filt = (m, pc) => new Map([...m].filter(([k]) => keep.has(k) && winner.get(k) === pc));
10861
- return pieces.map((pc) => ({ ...pc, keys: pc.keys.filter((k) => keep.has(k) && winner.get(k) === pc), ruleFns: filt(pc.ruleFns, pc), wrappers: filt(pc.wrappers, pc), deps: filt(pc.deps, pc) })).filter((pc) => pc.keys.length > 0);
11041
+ return pieces.map((pc) => ({ ...pc, keys: pc.keys.filter((k) => keep.has(k) && winner.get(k) === pc), ruleFns: filt(pc.ruleFns, pc), wrappers: filt(pc.wrappers, pc), deps: filt(pc.deps, pc), nodeMeta: filt(pc.nodeMeta, pc) })).filter((pc) => pc.keys.length > 0);
10862
11042
  }
10863
11043
  function fusedBody(pieces) {
10864
11044
  for (const p of pieces) {
@@ -10896,6 +11076,7 @@ function fusedBody(pieces) {
10896
11076
  ...[...winner].map(([k, p]) => p.ruleFns.get(k))
10897
11077
  ];
10898
11078
  const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
11079
+ const reflection = mergeGrammarReflections([...winner].map(([k, p]) => p.nodeMeta.get(k) ?? { nodes: [] }));
10899
11080
  const { mode, elided } = hostModeOfPieces(pieces);
10900
11081
  const rawBody = [
10901
11082
  ...lines,
@@ -10904,6 +11085,7 @@ function fusedBody(pieces) {
10904
11085
  "}",
10905
11086
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_MODE.description)}), { value: ${JSON.stringify(mode)}, enumerable: false })`,
10906
11087
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_ELIDED.description)}), { value: ${JSON.stringify(elided)}, enumerable: false })`,
11088
+ `Object.defineProperty(_map, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`,
10907
11089
  // …and on each rule FUNCTION, because `run(map.Rule, …)` is handed the rule, not the
10908
11090
  // map, and would otherwise have nothing to check against. Done once at fuse time,
10909
11091
  // before any rule has been called, so it costs nothing per parse.
@@ -11009,7 +11191,8 @@ function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
11009
11191
  const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
11010
11192
  ...trivia2 ? { trivia: trivia2 } : {},
11011
11193
  ...captureTerminals ? { captureTerminals: true } : {},
11012
- ...hostMode ? { hostMode } : {}
11194
+ ...hostMode ? { hostMode } : {},
11195
+ ...p.trackLines ? { trackLines: true } : {}
11013
11196
  });
11014
11197
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
11015
11198
  return pieces;
@@ -11193,19 +11376,19 @@ function directBuilderUnsupportedBindings(src) {
11193
11376
  // src/plugin/evaluator.ts
11194
11377
  function stripTsFromSource(node2, code) {
11195
11378
  const cuts = [];
11196
- const walk2 = (n) => {
11379
+ const walk = (n) => {
11197
11380
  if (!n || typeof n !== "object") return;
11198
11381
  const rec = n;
11199
11382
  if (typeof rec.type === "string" && rec.type.startsWith("TS") && typeof rec.start === "number" && typeof rec.end === "number") {
11200
11383
  const ex = rec.expression;
11201
11384
  if ((rec.type === "TSAsExpression" || rec.type === "TSSatisfiesExpression" || rec.type === "TSNonNullExpression" || rec.type === "TSInstantiationExpression") && ex && typeof ex.end === "number") {
11202
11385
  cuts.push([ex.end, rec.end]);
11203
- walk2(rec.expression);
11386
+ walk(rec.expression);
11204
11387
  return;
11205
11388
  }
11206
11389
  if (rec.type === "TSTypeAssertion" && ex && typeof ex.start === "number") {
11207
11390
  cuts.push([rec.start, ex.start]);
11208
- walk2(rec.expression);
11391
+ walk(rec.expression);
11209
11392
  return;
11210
11393
  }
11211
11394
  cuts.push([rec.start, rec.end]);
@@ -11215,11 +11398,11 @@ function stripTsFromSource(node2, code) {
11215
11398
  if (key === "type" || key === "start" || key === "end") continue;
11216
11399
  const v2 = rec[key];
11217
11400
  if (Array.isArray(v2)) {
11218
- for (const item of v2) walk2(item);
11219
- } else if (v2 && typeof v2 === "object") walk2(v2);
11401
+ for (const item of v2) walk(item);
11402
+ } else if (v2 && typeof v2 === "object") walk(v2);
11220
11403
  }
11221
11404
  };
11222
- walk2(node2);
11405
+ walk(node2);
11223
11406
  const start = node2.start;
11224
11407
  const end = node2.end;
11225
11408
  if (cuts.length === 0) return code.slice(start, end);
@@ -11398,10 +11581,38 @@ function scopeGet(scope, name, mfs) {
11398
11581
  if (isCombinator(entry)) return entry;
11399
11582
  return null;
11400
11583
  }
11584
+ function unwrapStaticExpr(expr) {
11585
+ let cur = expr;
11586
+ while (cur.type === "TSAsExpression" || cur.type === "TSSatisfiesExpression" || cur.type === "TSNonNullExpression" || cur.type === "TSTypeAssertion" || cur.type === "TSInstantiationExpression" || cur.type === "ParenthesizedExpression") {
11587
+ if (!cur.expression) break;
11588
+ cur = cur.expression;
11589
+ }
11590
+ return cur;
11591
+ }
11401
11592
  function staticLiteralValue(expr) {
11402
- const val = expr;
11593
+ const val = unwrapStaticExpr(expr);
11403
11594
  return val.type === "Literal" || val.type === "BooleanLiteral" || val.type === "NumericLiteral" ? val.value : void 0;
11404
11595
  }
11596
+ function staticStringArray(expr, scope) {
11597
+ const id = unwrapStaticExpr(expr);
11598
+ if (id.type === "Identifier" && scope !== void 0 && id.name !== void 0) {
11599
+ const scoped = scope.get(id.name);
11600
+ const value = isStaticValueEntry(scoped) ? scoped.value : scoped;
11601
+ return Array.isArray(value) && value.every((v2) => typeof v2 === "string") ? value : void 0;
11602
+ }
11603
+ const arr = id;
11604
+ if (arr.type !== "ArrayExpression" || !Array.isArray(arr.elements)) return void 0;
11605
+ const out = [];
11606
+ for (const el of arr.elements) {
11607
+ if (!el || el.type === "SpreadElement") return void 0;
11608
+ const value = staticLiteralValue(el);
11609
+ if (typeof value !== "string") return void 0;
11610
+ out.push(value);
11611
+ }
11612
+ return out;
11613
+ }
11614
+ var STATIC_NODE_OPTIONS_FAILED = /* @__PURE__ */ Symbol("parseman.staticNodeOptions.failed");
11615
+ var STATIC_NODE_OPTIONS_NOT_OPTIONS = /* @__PURE__ */ Symbol("parseman.staticNodeOptions.notOptions");
11405
11616
  function staticNodeProject(expr) {
11406
11617
  const literalValue = staticLiteralValue(expr);
11407
11618
  if (typeof literalValue === "number" && Number.isInteger(literalValue) && literalValue >= 0) {
@@ -11410,23 +11621,60 @@ function staticNodeProject(expr) {
11410
11621
  if (typeof literalValue === "number" || literalValue !== void 0) return { ok: false };
11411
11622
  return { ok: false };
11412
11623
  }
11413
- function staticNodeOptions(expr) {
11414
- if (expr.type !== "ObjectExpression") return void 0;
11624
+ function scopedStaticValue(expr, scope) {
11625
+ const unwrapped = unwrapStaticExpr(expr);
11626
+ if (unwrapped.type !== "Identifier" || unwrapped.name === "undefined") return { found: false };
11627
+ if (!scope.has(unwrapped.name)) return { found: false };
11628
+ const scoped = scope.get(unwrapped.name);
11629
+ const value = isStaticValueEntry(scoped) ? scoped.value : scoped;
11630
+ return { found: true, value };
11631
+ }
11632
+ function staticNodeOptionsFromValue(value) {
11633
+ if (value === null || typeof value !== "object" || Array.isArray(value) || isCombinator(value)) return STATIC_NODE_OPTIONS_NOT_OPTIONS;
11634
+ const opts = {};
11635
+ const rec = value;
11636
+ for (const name of Object.keys(rec)) {
11637
+ const v2 = rec[name];
11638
+ if (name === "unwrap" || name === "collapse" || name === "captureTrivia" || name === "trailingTrivia") {
11639
+ if (v2 === true) opts[name] = true;
11640
+ else if (v2 !== false && v2 !== void 0) return STATIC_NODE_OPTIONS_FAILED;
11641
+ } else if (name === "project") {
11642
+ if (typeof v2 !== "number" || !Number.isInteger(v2) || v2 < 0) return STATIC_NODE_OPTIONS_FAILED;
11643
+ opts.project = v2;
11644
+ } else if (name === "tags") {
11645
+ if (!Array.isArray(v2) || !v2.every((item) => typeof item === "string")) return STATIC_NODE_OPTIONS_FAILED;
11646
+ opts.tags = v2;
11647
+ }
11648
+ }
11649
+ return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
11650
+ }
11651
+ function staticNodeOptions(expr, scope) {
11652
+ const unwrapped = unwrapStaticExpr(expr);
11653
+ const scoped = scopedStaticValue(unwrapped, scope);
11654
+ if (scoped.found) return staticNodeOptionsFromValue(scoped.value);
11655
+ if (unwrapped.type !== "ObjectExpression") return STATIC_NODE_OPTIONS_NOT_OPTIONS;
11415
11656
  const opts = {};
11416
- for (const prop of expr.properties) {
11657
+ for (const prop of unwrapped.properties) {
11658
+ if (prop.type !== "Property") return STATIC_NODE_OPTIONS_FAILED;
11417
11659
  const p = prop;
11418
- if (p.computed) continue;
11660
+ if (p.computed) return STATIC_NODE_OPTIONS_FAILED;
11419
11661
  const key = p.key;
11420
11662
  const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
11421
11663
  if (name === "unwrap" || name === "collapse" || name === "captureTrivia" || name === "trailingTrivia") {
11422
- if (staticLiteralValue(p.value) === true) opts[name] = true;
11664
+ const value = staticLiteralValue(p.value);
11665
+ if (value === true) opts[name] = true;
11666
+ else if (value !== false && value !== void 0) return STATIC_NODE_OPTIONS_FAILED;
11423
11667
  } else if (name === "project") {
11424
11668
  const project = staticNodeProject(p.value);
11425
- if (project?.ok === false) return { project: -1 };
11669
+ if (project?.ok === false) return STATIC_NODE_OPTIONS_FAILED;
11426
11670
  if (project !== void 0) opts.project = project.value;
11671
+ } else if (name === "tags") {
11672
+ const tags = staticStringArray(p.value, scope);
11673
+ if (tags === void 0) return STATIC_NODE_OPTIONS_FAILED;
11674
+ opts.tags = tags;
11427
11675
  }
11428
11676
  }
11429
- return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
11677
+ return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
11430
11678
  }
11431
11679
  function exprToCombi(node2, scope, code, mfs) {
11432
11680
  if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
@@ -11501,10 +11749,23 @@ function exprToCombi(node2, scope, code, mfs) {
11501
11749
  const inner = anyValue(parserArg, scope, code, mfs);
11502
11750
  if (!isCombinator(inner)) return null;
11503
11751
  const be = buildArg;
11504
- const hasBuild = be !== void 0 && be.type !== "SpreadElement" && be.type !== "ObjectExpression" && !(be.type === "Identifier" && be.name === "undefined");
11752
+ const buildExpr = be === void 0 || be.type === "SpreadElement" ? void 0 : unwrapStaticExpr(be);
11753
+ const buildArgOptions = be !== void 0 && be.type !== "SpreadElement" ? staticNodeOptions(buildArg, scope) : STATIC_NODE_OPTIONS_NOT_OPTIONS;
11754
+ if (buildArgOptions === STATIC_NODE_OPTIONS_FAILED) return null;
11755
+ const buildArgIsOptions = buildArgOptions !== STATIC_NODE_OPTIONS_NOT_OPTIONS;
11756
+ const scopedBuild = buildExpr === void 0 ? { found: false } : scopedStaticValue(buildExpr, scope);
11757
+ const absentBuild = buildExpr?.type === "Identifier" && buildExpr.name === "undefined" || buildExpr !== void 0 && staticLiteralValue(buildExpr) === null || scopedBuild.found && (scopedBuild.value === void 0 || scopedBuild.value === null);
11758
+ const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !buildArgIsOptions && !absentBuild;
11505
11759
  const buildSrc = hasBuild ? stripTsFromSource(be, code) : void 0;
11506
- const optionsArg = hasBuild ? optsArg : be?.type === "ObjectExpression" ? buildArg : optsArg;
11507
- const opts = optionsArg !== void 0 && optionsArg.type !== "SpreadElement" ? staticNodeOptions(optionsArg) : void 0;
11760
+ let opts;
11761
+ if (buildArgIsOptions) {
11762
+ opts = buildArgOptions;
11763
+ } else if (optsArg !== void 0) {
11764
+ if (optsArg.type === "SpreadElement") return null;
11765
+ const optsResult = staticNodeOptions(optsArg, scope);
11766
+ if (optsResult === STATIC_NODE_OPTIONS_FAILED || optsResult === STATIC_NODE_OPTIONS_NOT_OPTIONS) return null;
11767
+ opts = optsResult;
11768
+ }
11508
11769
  try {
11509
11770
  const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
11510
11771
  if (combi._def.tag === "node" && buildSrc !== void 0) {
@@ -11727,6 +11988,10 @@ function exprToCombi(node2, scope, code, mfs) {
11727
11988
  }
11728
11989
  }
11729
11990
  function anyValue(node2, scope, code, mfs) {
11991
+ if (node2.type === "TSAsExpression" || node2.type === "TSSatisfiesExpression" || node2.type === "TSNonNullExpression" || node2.type === "TSTypeAssertion" || node2.type === "TSInstantiationExpression" || node2.type === "ParenthesizedExpression") {
11992
+ const inner = node2.expression;
11993
+ return inner ? anyValue(inner, scope, code, mfs) : null;
11994
+ }
11730
11995
  if (node2.type === "Literal") {
11731
11996
  if ("regex" in node2 && node2.regex !== null && node2.regex !== void 0) {
11732
11997
  return new RegExp(node2.regex.pattern, node2.regex.flags);
@@ -11850,6 +12115,9 @@ function collectRuleKeys(retObj) {
11850
12115
  }
11851
12116
  return out;
11852
12117
  }
12118
+ function evaluateStaticValue(node2, scope, code) {
12119
+ return anyValue(node2, scope, code, []);
12120
+ }
11853
12121
  function flattenRuleEntries(retObj, scope, code) {
11854
12122
  const out = [];
11855
12123
  for (const prop of retObj.properties) {
@@ -12015,6 +12283,18 @@ function referencesAny(node2, names, scope) {
12015
12283
  // src/plugin/index.ts
12016
12284
  var import_node_crypto = require("node:crypto");
12017
12285
  var PARSEMAN_MODULE = "parseman";
12286
+ function unwrapStaticExpression(expr) {
12287
+ let cur = expr;
12288
+ while (cur.type === "TSAsExpression" || cur.type === "TSSatisfiesExpression" || cur.type === "TSNonNullExpression" || cur.type === "TSTypeAssertion" || cur.type === "TSInstantiationExpression" || cur.type === "ParenthesizedExpression") {
12289
+ if (!cur.expression) break;
12290
+ cur = cur.expression;
12291
+ }
12292
+ return cur;
12293
+ }
12294
+ function isStaticNullishExpression(expr) {
12295
+ const unwrapped = unwrapStaticExpression(expr);
12296
+ return unwrapped.type === "Identifier" && unwrapped.name === "undefined" || unwrapped.type === "Literal" && unwrapped.value === null;
12297
+ }
12018
12298
  var _compiledResolver = null;
12019
12299
  function getCompiledResolver() {
12020
12300
  return _compiledResolver ??= new import_oxc_resolver.ResolverFactory({
@@ -12256,6 +12536,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12256
12536
  const macroImports = [];
12257
12537
  const allNames = /* @__PURE__ */ new Set();
12258
12538
  const importBindings = /* @__PURE__ */ new Map();
12539
+ const ordinaryImports = [];
12259
12540
  for (const stmt of body) {
12260
12541
  if (stmt.type !== "ImportDeclaration") continue;
12261
12542
  const s = stmt;
@@ -12264,12 +12545,17 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12264
12545
  return key === "type" && a.value.value === "macro";
12265
12546
  });
12266
12547
  if (!isMacro) {
12548
+ const specifiers = [];
12267
12549
  for (const spec of s.specifiers) {
12268
12550
  if (spec.type === "ImportSpecifier") {
12269
12551
  const imported = spec.imported.name ?? spec.local.name;
12270
12552
  importBindings.set(spec.local.name, { source: s.source.value, imported });
12553
+ specifiers.push({ type: spec.type, local: spec.local.name, start: spec.start, end: spec.end });
12554
+ } else {
12555
+ specifiers.push({ type: spec.type, local: spec.local.name, start: spec.start, end: spec.end });
12271
12556
  }
12272
12557
  }
12558
+ ordinaryImports.push({ start: s.start, end: s.end, specifiers });
12273
12559
  continue;
12274
12560
  }
12275
12561
  const names = /* @__PURE__ */ new Set();
@@ -12280,6 +12566,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12280
12566
  for (const n of names) allNames.add(n);
12281
12567
  }
12282
12568
  if (macroImports.length === 0) return null;
12569
+ const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
12283
12570
  const factoryDecls = /* @__PURE__ */ new Map();
12284
12571
  for (const stmt of body) {
12285
12572
  const decl = stmt.type === "ExportNamedDeclaration" ? stmt.declaration : stmt;
@@ -12297,6 +12584,101 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12297
12584
  }
12298
12585
  }
12299
12586
  }
12587
+ const topLevelFunction = (moduleBody, name) => {
12588
+ for (const st of moduleBody) {
12589
+ const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
12590
+ const idn = decl?.type === "FunctionDeclaration" ? decl.id : void 0;
12591
+ if (idn?.name === name) return decl ?? null;
12592
+ }
12593
+ return null;
12594
+ };
12595
+ const isParsemanMacroImport = (stmt) => {
12596
+ if (stmt.type !== "ImportDeclaration") return false;
12597
+ const s = stmt;
12598
+ return moduleAliases.has(s.source.value) && s.attributes.some((a) => {
12599
+ const key = a.key.type === "Identifier" ? a.key.name : String(a.key.value);
12600
+ return key === "type" && a.value.value === "macro";
12601
+ });
12602
+ };
12603
+ const sourceScopeUntil = (moduleBody, source, until) => {
12604
+ const out = /* @__PURE__ */ new Map();
12605
+ for (const stmt of moduleBody) {
12606
+ if (stmt.type === "ImportDeclaration") {
12607
+ if (!isParsemanMacroImport(stmt)) return null;
12608
+ continue;
12609
+ }
12610
+ if (stmt.type === "FunctionDeclaration") continue;
12611
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "FunctionDeclaration") continue;
12612
+ if (stmt.type === "ExportNamedDeclaration" && !stmt.declaration) {
12613
+ if (stmt.source) return null;
12614
+ continue;
12615
+ }
12616
+ const vd = unwrapVd(stmt);
12617
+ if (!vd || vd.kind !== "const") return null;
12618
+ for (const decl of vd.declarations) {
12619
+ const d = decl;
12620
+ const idn = d.id;
12621
+ const init = d.init;
12622
+ if (idn.type !== "Identifier" && idn.type !== "BindingIdentifier" || !idn.name || !init) return null;
12623
+ if (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression") continue;
12624
+ const mapFnSources = [];
12625
+ const combi = evaluateExpr(init, out, source, mapFnSources);
12626
+ if (combi) {
12627
+ if (stmt.start < until) out.set(idn.name, { combi, mfSrcs: mapFnSources });
12628
+ continue;
12629
+ }
12630
+ const wordFactory = evaluateWordFactory(init, out, source);
12631
+ if (wordFactory) {
12632
+ if (stmt.start < until) {
12633
+ ;
12634
+ out.set(idn.name, wordFactory);
12635
+ }
12636
+ continue;
12637
+ }
12638
+ const whenFactory = evaluateWhenFactory(init, out, source);
12639
+ if (whenFactory) {
12640
+ if (stmt.start < until) {
12641
+ ;
12642
+ out.set(idn.name, whenFactory);
12643
+ }
12644
+ continue;
12645
+ }
12646
+ const combiArray = evaluateCombinatorArray(init, out, source);
12647
+ if (combiArray) {
12648
+ if (stmt.start < until) {
12649
+ ;
12650
+ out.set(idn.name, combiArray);
12651
+ }
12652
+ continue;
12653
+ }
12654
+ return null;
12655
+ }
12656
+ continue;
12657
+ }
12658
+ return out;
12659
+ };
12660
+ const usedImportedFactories = /* @__PURE__ */ new Set();
12661
+ const markUsedImportedFactories = (names) => {
12662
+ for (const name of names ?? []) usedImportedFactories.add(name);
12663
+ };
12664
+ for (const [localName, binding] of importBindings) {
12665
+ const file = resolvePrivateSourceModule(id, binding.source);
12666
+ if (!file) continue;
12667
+ const mod = parseModuleCached(file);
12668
+ if (!mod) continue;
12669
+ const localFor = exportLocalName(mod.body, binding.imported);
12670
+ const init = localFor ? topLevelInit(mod.body, localFor) ?? topLevelFunction(mod.body, localFor) : null;
12671
+ if (!init || init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression" && init.type !== "FunctionDeclaration") continue;
12672
+ const factoryScope = sourceScopeUntil(mod.body, mod.src, init.start);
12673
+ if (!factoryScope) continue;
12674
+ factoryDecls.set(localName, {
12675
+ fn: init,
12676
+ declaredAt: -1,
12677
+ code: mod.src,
12678
+ scope: factoryScope,
12679
+ imported: true
12680
+ });
12681
+ }
12300
12682
  const scope = /* @__PURE__ */ new Map();
12301
12683
  const replacements = [];
12302
12684
  const warnings = [];
@@ -12326,6 +12708,9 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12326
12708
  }
12327
12709
  const namedFactory = factoryArgRaw.type === "Identifier" ? factoryDecls.get(factoryArgRaw.name) : void 0;
12328
12710
  const factoryArg = namedFactory !== void 0 && namedFactory.declaredAt <= init.start ? namedFactory.fn : factoryArgRaw;
12711
+ const factoryScope = namedFactory?.scope ?? scope;
12712
+ const factoryCode = namedFactory?.code ?? code;
12713
+ const importedFactory = namedFactory?.imported === true && factoryArg === namedFactory.fn ? factoryArgRaw.name : void 0;
12329
12714
  const optionsArg = optionsFirst ? arg0 : arg1;
12330
12715
  const optionValue = (name) => optionsArg?.type === "ObjectExpression" ? (optionsArg.properties ?? []).find(
12331
12716
  (p) => p.key?.name === name
@@ -12336,7 +12721,13 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12336
12721
  warn(init.start, `${label2}: rules({ hostMode }) must be the literal 'ast' or 'cst'`);
12337
12722
  return null;
12338
12723
  }
12339
- const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
12724
+ const trackLinesValue = optionValue("trackLines");
12725
+ const gTrackLines = trackLinesValue?.type === "Literal" ? trackLinesValue.value : void 0;
12726
+ if (trackLinesValue !== void 0 && typeof gTrackLines !== "boolean") {
12727
+ warn(init.start, `${label2}: rules({ trackLines }) must be a boolean literal`);
12728
+ return null;
12729
+ }
12730
+ const ruleMap = evaluateParserFactory(factoryArg, factoryScope, factoryCode, []);
12340
12731
  if (!ruleMap) {
12341
12732
  warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
12342
12733
  return null;
@@ -12361,20 +12752,37 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12361
12752
  }
12362
12753
  }
12363
12754
  }
12364
- return { ruleMap, ...gTrivia ? { trivia: gTrivia } : {}, ...gScanSkip ? { scanSkip: gScanSkip } : {} };
12755
+ if (gTrackLines === true) {
12756
+ for (const rule of ruleMap.values()) {
12757
+ if (rule && !rule._meta.isTrivia) {
12758
+ ;
12759
+ rule._meta.grammarTrackLines = true;
12760
+ }
12761
+ }
12762
+ }
12763
+ return {
12764
+ ruleMap,
12765
+ ...gTrivia ? { trivia: gTrivia } : {},
12766
+ ...gScanSkip ? { scanSkip: gScanSkip } : {},
12767
+ ...gTrackLines === true ? { trackLines: true } : {},
12768
+ ...importedFactory ? { importedFactory } : {}
12769
+ };
12365
12770
  };
12366
12771
  const compileRulesFactory = (init, label2) => {
12367
12772
  const evaluated = evaluateRulesFactory(init, label2);
12368
12773
  if (!evaluated) return null;
12369
- const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}, recovery, coverage: grammarCoverage });
12774
+ const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}, ...evaluated.trackLines ? { trackLines: true } : {}, recovery, coverage: grammarCoverage });
12370
12775
  return {
12371
12776
  replacement: compiled?.replacement ?? null,
12372
12777
  ruleMap: evaluated.ruleMap,
12373
12778
  hostMode: compiled?.hostMode ?? "ast",
12374
12779
  hostBranchElided: compiled?.hostBranchElided ?? false,
12780
+ reflection: compiled?.reflection ?? { nodes: [] },
12375
12781
  ...compiled?.coverageDefinitions ? { coverageDefinitions: compiled.coverageDefinitions } : {},
12376
12782
  ...evaluated.trivia ? { trivia: evaluated.trivia } : {},
12377
- ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}
12783
+ ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {},
12784
+ ...evaluated.trackLines ? { trackLines: true } : {},
12785
+ ...evaluated.importedFactory ? { importedFactory: evaluated.importedFactory } : {}
12378
12786
  };
12379
12787
  };
12380
12788
  const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
@@ -12390,15 +12798,16 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12390
12798
  const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
12391
12799
  ([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
12392
12800
  ).join(", ")}])`;
12393
- return `{ v: ${JSON.stringify(p.v)}, ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, nullable: ${p.nullable ? mapLit(p.nullable) : "new Map()"}, firstSetRecipes: ${p.firstSetRecipes ? mapLit(p.firstSetRecipes) : "new Map()"}, deps: ${mapLit(p.deps)}, hostMode: ${JSON.stringify(p.hostMode ?? "ast")}, hostBranchElided: ${p.hostBranchElided === true}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
12801
+ return `{ v: ${JSON.stringify(p.v)}, ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, nullable: ${p.nullable ? mapLit(p.nullable) : "new Map()"}, firstSetRecipes: ${p.firstSetRecipes ? mapLit(p.firstSetRecipes) : "new Map()"}, deps: ${mapLit(p.deps)}, nodeMeta: ${mapLit(p.nodeMeta)}, hostMode: ${JSON.stringify(p.hostMode ?? "ast")}, hostBranchElided: ${p.hostBranchElided === true}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
12394
12802
  };
12395
12803
  const isSpread = (it) => "__spreadLocal" in it;
12396
12804
  const isIR = (it) => "ir" in it && !("ruleFns" in it);
12397
- const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)} }` : serializePieces(it);
12805
+ const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)}${it.trackLines ? ", trackLines: true" : ""} }` : serializePieces(it);
12398
12806
  const serializeList = (list) => `[${list.map(serializeItem).join(", ")}]`;
12399
12807
  const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)}, enumerable: false })`;
12400
12808
  const withLeafMarker = (grammarExpr) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.leafComposed'), { value: true, enumerable: false })`;
12401
12809
  const withHostMode = (grammarExpr, mode, elided) => `/* @__PURE__ */ (m => { for (const k of Object.keys(m)) { Object.defineProperty(m[k], Symbol.for('parseman.fusedHostMode'), { value: ${JSON.stringify(mode)}, enumerable: false }); Object.defineProperty(m[k], Symbol.for('parseman.fusedHostElided'), { value: ${JSON.stringify(elided)}, enumerable: false }) } Object.defineProperty(m, Symbol.for('parseman.fusedHostMode'), { value: ${JSON.stringify(mode)}, enumerable: false }); Object.defineProperty(m, Symbol.for('parseman.fusedHostElided'), { value: ${JSON.stringify(elided)}, enumerable: false }); return m })(${grammarExpr})`;
12810
+ const withGrammarReflection = (grammarExpr, reflection) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`;
12402
12811
  const withCoverageDefinitions = (grammarExpr, definitions) => !grammarCoverage ? grammarExpr : `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.grammarCoverageDefinitions'), { value: Object.freeze(${JSON.stringify(definitions)}.map(Object.freeze)), enumerable: false })`;
12403
12812
  const emittedCoverageDefinitions = (source) => {
12404
12813
  const ids = /* @__PURE__ */ new Set();
@@ -12525,10 +12934,11 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12525
12934
  const localCarried = (rm, label2, composing, scanSkip) => {
12526
12935
  const entries = [...rm];
12527
12936
  const ns = nsFor(label2);
12937
+ const trackLines = entries.some(([, rule]) => rule?._meta?.grammarTrackLines === true);
12528
12938
  const ir = serializeRuleMap(entries, scanSkip);
12529
- if (ir) return { carried: [{ ns, ir }] };
12939
+ if (ir) return { carried: [{ ns, ir, ...trackLines ? { trackLines: true } : {} }] };
12530
12940
  warn(0, `${label2}: rule map could not be serialized to IR; carrying FULL pieces instead. The artifact is correct but larger, and a downstream compose cannot re-lower it. Re-run with PARSEMAN_IR_DEBUG=1 to print the exact combinator that blocked serialization.`);
12531
- const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, ...scanSkip ? { scanSkip } : {}, recovery });
12941
+ const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, ...scanSkip ? { scanSkip } : {}, ...trackLines ? { trackLines: true } : {}, recovery });
12532
12942
  return p ? { carried: [p] } : null;
12533
12943
  };
12534
12944
  const argPieces = (arg, label2, composing) => {
@@ -12546,7 +12956,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12546
12956
  const innerArg = argPieces(inner, `${label2}_pick`);
12547
12957
  if (!innerArg) return null;
12548
12958
  try {
12549
- return { carried: pickPieces(materializeCarried(innerArg.carried, ownTrivia(inner)), names) };
12959
+ return {
12960
+ carried: pickPieces(materializeCarried(innerArg.carried, ownTrivia(inner)), names),
12961
+ ...innerArg.importedFactories ? { importedFactories: innerArg.importedFactories } : {}
12962
+ };
12550
12963
  } catch (e) {
12551
12964
  warn(arg.start, `pick(): ${e.message}`);
12552
12965
  return null;
@@ -12554,7 +12967,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12554
12967
  }
12555
12968
  if (isRulesCall(arg)) {
12556
12969
  const evaluated = evaluateRulesFactory(arg, label2);
12557
- return evaluated ? localCarried(evaluated.ruleMap, label2, composing, evaluated.scanSkip) : null;
12970
+ const carried = evaluated ? localCarried(evaluated.ruleMap, label2, composing, evaluated.scanSkip) : null;
12971
+ return carried ? { ...carried, ...evaluated?.importedFactory ? { importedFactories: [evaluated.importedFactory] } : {} } : null;
12558
12972
  }
12559
12973
  if (arg.type === "Identifier") {
12560
12974
  const name = arg.name;
@@ -12626,6 +13040,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12626
13040
  }
12627
13041
  const composing = composingTrivia(elements);
12628
13042
  const carried = [];
13043
+ const importedFactories = [];
12629
13044
  for (let i = 0; i < elements.length; i++) {
12630
13045
  const r = argPieces(elements[i], `compose${init.start}_${i}`, composing);
12631
13046
  if (!r) {
@@ -12633,6 +13048,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12633
13048
  return null;
12634
13049
  }
12635
13050
  carried.push(...r.carried);
13051
+ importedFactories.push(...r.importedFactories ?? []);
12636
13052
  }
12637
13053
  const detailed = once(() => carriedRuleMapsDetailed(carried));
12638
13054
  runFusedGatingDiagnostic(
@@ -12642,7 +13058,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12642
13058
  );
12643
13059
  const pieces = materializeCarried(carried, composing, false, cHostMode);
12644
13060
  try {
12645
- return { replacement: emitFusedSource(pieces), carried, ...composing ? { trivia: composing } : {} };
13061
+ return {
13062
+ replacement: emitFusedSource(pieces),
13063
+ carried,
13064
+ ...composing ? { trivia: composing } : {},
13065
+ ...importedFactories.length ? { importedFactories } : {}
13066
+ };
12646
13067
  } catch (e) {
12647
13068
  warn(init.start, `compose(): ${e.message}; falling back to runtime`);
12648
13069
  return null;
@@ -12663,10 +13084,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12663
13084
  const localArg = elements[elements.length - 1];
12664
13085
  let localRules = null;
12665
13086
  let localScanSkip;
13087
+ const importedFactories = [];
12666
13088
  if (isRulesCall(localArg)) {
12667
13089
  const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`);
12668
13090
  localRules = evaluated?.ruleMap ?? null;
12669
13091
  localScanSkip = evaluated?.scanSkip;
13092
+ if (evaluated?.importedFactory) importedFactories.push(evaluated.importedFactory);
12670
13093
  } else if (localArg.type === "Identifier") {
12671
13094
  const name = localArg.name;
12672
13095
  localRules = localRuleMaps.get(name) ?? null;
@@ -12685,6 +13108,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12685
13108
  return null;
12686
13109
  }
12687
13110
  carried.push(...r.carried);
13111
+ importedFactories.push(...r.importedFactories ?? []);
12688
13112
  }
12689
13113
  try {
12690
13114
  const localNs = nsFor(`composeLeaf${init.start}`);
@@ -12710,13 +13134,15 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12710
13134
  return null;
12711
13135
  }
12712
13136
  const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
12713
- return { replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) };
13137
+ return {
13138
+ replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)),
13139
+ ...importedFactories.length ? { importedFactories } : {}
13140
+ };
12714
13141
  } catch (e) {
12715
13142
  warn(init.start, `composeLeaf(): ${e.message}`);
12716
13143
  return null;
12717
13144
  }
12718
13145
  };
12719
- const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
12720
13146
  const refNames = /* @__PURE__ */ new Set();
12721
13147
  for (const stmt of body) {
12722
13148
  const innerVd = unwrapVd(stmt);
@@ -12777,7 +13203,14 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12777
13203
  const kind = vd.kind ?? "const";
12778
13204
  if (d.id.type === "Identifier") {
12779
13205
  const varName = d.id.name;
12780
- if (!referencesAny(init, allNames, scope)) continue;
13206
+ if (!referencesAny(init, allNames, scope)) {
13207
+ const staticValue = evaluateStaticValue(init, scope, code);
13208
+ if (staticValue !== null && staticValue !== void 0 || isStaticNullishExpression(init)) {
13209
+ ;
13210
+ scope.set(varName, staticValue);
13211
+ }
13212
+ continue;
13213
+ }
12781
13214
  if (refNames.has(varName)) {
12782
13215
  const refEntry = scope.get(varName);
12783
13216
  const refCombi = refEntry?.combi ?? null;
@@ -12800,6 +13233,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12800
13233
  const ns = nsFor(varName);
12801
13234
  const pieces = exportPrefix || compiledRules.replacement === null ? compileLinkable([...compiledRules.ruleMap], ns, {
12802
13235
  ...compiledRules.scanSkip ? { scanSkip: compiledRules.scanSkip } : {},
13236
+ ...compiledRules.trackLines ? { trackLines: true } : {},
12803
13237
  recovery
12804
13238
  }) : null;
12805
13239
  if (compiledRules.replacement === null) {
@@ -12816,12 +13250,16 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12816
13250
  );
12817
13251
  if (compiledRules.replacement !== null) {
12818
13252
  replacement = withHostMode(replacement, compiledRules.hostMode, compiledRules.hostBranchElided);
13253
+ replacement = withGrammarReflection(replacement, compiledRules.reflection);
12819
13254
  }
12820
13255
  if (exportPrefix && pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
12821
13256
  const ir = serializeRuleMap([...compiledRules.ruleMap], compiledRules.scanSkip);
12822
- replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
13257
+ replacement = withCarriedPieces(replacement, [ir ? { ns, ir, ...compiledRules.trackLines ? { trackLines: true } : {} } : pieces]);
12823
13258
  }
12824
13259
  replacements.push({ start: init.start, end: init.end, replacement });
13260
+ if (compiledRules.replacement !== null) {
13261
+ markUsedImportedFactories(compiledRules.importedFactory ? [compiledRules.importedFactory] : void 0);
13262
+ }
12825
13263
  continue;
12826
13264
  }
12827
13265
  if (isComposeCall(init)) {
@@ -12834,6 +13272,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12834
13272
  if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
12835
13273
  const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
12836
13274
  replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
13275
+ markUsedImportedFactories(fused.importedFactories);
12837
13276
  continue;
12838
13277
  }
12839
13278
  if (isComposeLeafCall(init)) {
@@ -12842,6 +13281,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12842
13281
  throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
12843
13282
  }
12844
13283
  replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
13284
+ markUsedImportedFactories(fused.importedFactories);
12845
13285
  continue;
12846
13286
  }
12847
13287
  const mapFnSources = [];
@@ -12867,6 +13307,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12867
13307
  scope.set(varName, combiArray);
12868
13308
  continue;
12869
13309
  }
13310
+ const staticValue = evaluateStaticValue(init, scope, code);
13311
+ if (staticValue !== null && staticValue !== void 0 || isStaticNullishExpression(init)) {
13312
+ ;
13313
+ scope.set(varName, staticValue);
13314
+ continue;
13315
+ }
12870
13316
  if (factoryDecls.has(varName)) continue;
12871
13317
  warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
12872
13318
  continue;
@@ -12930,6 +13376,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12930
13376
  end: stmtEnd,
12931
13377
  replacement: lines.join("\n")
12932
13378
  });
13379
+ markUsedImportedFactories(compiledRules.importedFactory ? [compiledRules.importedFactory] : void 0);
12933
13380
  }
12934
13381
  }
12935
13382
  }
@@ -12938,6 +13385,40 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12938
13385
  imp.fullyResolved = !anyUnresolved && !keepMacroImport;
12939
13386
  }
12940
13387
  const ms = new import_magic_string.default(code);
13388
+ const replacementRanges = runtimeComposeFallback ? [] : replacements.map(({ start, end }) => ({ start, end }));
13389
+ const isInsideReplacement = (start, end) => replacementRanges.some((r) => start >= r.start && end <= r.end);
13390
+ const importedBindingStillReferenced = (local) => {
13391
+ const walk = (node2, parent, parentKey) => {
13392
+ if (!node2 || typeof node2 !== "object") return false;
13393
+ const rec = node2;
13394
+ if (rec.type === "ImportDeclaration") return false;
13395
+ if (typeof rec.start === "number" && typeof rec.end === "number" && isInsideReplacement(rec.start, rec.end)) return false;
13396
+ if ((rec.type === "Identifier" || rec.type === "BindingIdentifier") && rec.name === local) {
13397
+ if (parentKey === "key" && (parent?.type === "ObjectProperty" || parent?.type === "Property" || parent?.type === "PropertyDefinition") && parent.computed !== true) return false;
13398
+ if (parentKey === "property" && parent?.type === "StaticMemberExpression") return false;
13399
+ if (parentKey === "property" && parent?.type === "MemberExpression" && parent.computed !== true) return false;
13400
+ return true;
13401
+ }
13402
+ for (const key of Object.keys(rec)) {
13403
+ if (key === "type" || key === "start" || key === "end") continue;
13404
+ const value = rec[key];
13405
+ if (Array.isArray(value)) {
13406
+ if (value.some((child) => walk(child, rec, key))) return true;
13407
+ } else if (walk(value, rec, key)) {
13408
+ return true;
13409
+ }
13410
+ }
13411
+ return false;
13412
+ };
13413
+ return body.some((stmt) => walk(stmt));
13414
+ };
13415
+ for (const imp of ordinaryImports) {
13416
+ if (!runtimeComposeFallback && imp.specifiers.length > 0 && imp.specifiers.every(
13417
+ (spec) => spec.type === "ImportSpecifier" && usedImportedFactories.has(spec.local) && !importedBindingStillReferenced(spec.local)
13418
+ )) {
13419
+ ms.remove(imp.start, imp.end);
13420
+ }
13421
+ }
12941
13422
  if (!anyUnresolved) {
12942
13423
  for (const { start, end } of defineRemovals) ms.remove(start, end);
12943
13424
  }