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
package/dist/index.js CHANGED
@@ -2768,6 +2768,221 @@ function markUnusedValues(root) {
2768
2768
  visit(resolveRoot(root), true);
2769
2769
  }
2770
2770
 
2771
+ // src/combinators/grammar.ts
2772
+ function annotateResultLines(result, index) {
2773
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
2774
+ const errors = annotated.errors;
2775
+ if (errors) {
2776
+ ;
2777
+ annotated.errors = errors.map((error) => ({
2778
+ ...error,
2779
+ span: annotateSpan(error.span, index)
2780
+ }));
2781
+ }
2782
+ return annotated;
2783
+ }
2784
+ function createParseLineContext(input, pos) {
2785
+ const lineIndex = createLineIndex();
2786
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
2787
+ return { lineIndex, lineScannedTo: pos };
2788
+ }
2789
+ function parser(opts, root) {
2790
+ const clearTrivia = opts.trivia === null;
2791
+ return {
2792
+ _tag: "grammar",
2793
+ _meta: root._meta,
2794
+ _def: {
2795
+ tag: "grammar",
2796
+ parser: root,
2797
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2798
+ clearTrivia,
2799
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2800
+ trackLines: opts.trackLines ?? false
2801
+ },
2802
+ parse(input, pos, _ctx) {
2803
+ const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2804
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2805
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
2806
+ const ctx = {
2807
+ ..._ctx,
2808
+ trackLines,
2809
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
2810
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
2811
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2812
+ ...clearTrivia ? {
2813
+ trivia: void 0,
2814
+ triviaKindLabels: void 0
2815
+ } : opts.trivia != null ? {
2816
+ trivia: opts.trivia,
2817
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
2818
+ } : {},
2819
+ ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
2820
+ // Kind-filter for per-node capture. Resolve against this scope's trivia
2821
+ // labels — this parser's own trivia if it declares one, else the INHERITED
2822
+ // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2823
+ // trivia is inherited rather than re-declared here. No labels → undefined
2824
+ // (capture all).
2825
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2826
+ };
2827
+ const result = root.parse(input, pos ?? 0, ctx);
2828
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
2829
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
2830
+ }
2831
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
2832
+ }
2833
+ };
2834
+ }
2835
+ function noTrivia(root) {
2836
+ return parser({ trivia: null }, root);
2837
+ }
2838
+ var _analyzed = /* @__PURE__ */ new WeakSet();
2839
+ function parse(combinator, input, opts = {}) {
2840
+ if (!_analyzed.has(combinator)) {
2841
+ _analyzed.add(combinator);
2842
+ markUnusedValues(combinator);
2843
+ }
2844
+ const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
2845
+ const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
2846
+ const lineIndex = lineContext?.lineIndex;
2847
+ const _errors = opts.recover ? [] : void 0;
2848
+ const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
2849
+ const grammarTrivia = combinator._meta.grammarTrivia;
2850
+ const grammarScanSkip = combinator._meta.grammarScanSkip;
2851
+ const ctx = {
2852
+ trackLines,
2853
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
2854
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
2855
+ ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
2856
+ ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
2857
+ ..._errors !== void 0 ? { _errors } : {},
2858
+ ..._probe !== void 0 ? { _probe } : {}
2859
+ };
2860
+ const result = combinator.parse(input, 0, ctx);
2861
+ if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
2862
+ const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
2863
+ return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
2864
+ }
2865
+
2866
+ // src/cst/reflection.ts
2867
+ var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
2868
+ function childrenOf(def) {
2869
+ switch (def.tag) {
2870
+ case "sequence":
2871
+ case "choice":
2872
+ return def.parsers;
2873
+ case "dispatch":
2874
+ return [
2875
+ def.selector,
2876
+ ...def.cases.map((c) => c.parser),
2877
+ ...def.matchers ? def.matchers.map((c) => c.parser) : [],
2878
+ ...def.otherwise ? [def.otherwise] : []
2879
+ ];
2880
+ case "many":
2881
+ case "oneOrMore":
2882
+ case "optional":
2883
+ case "attempt":
2884
+ case "transform":
2885
+ case "trivia":
2886
+ case "token":
2887
+ case "leaf":
2888
+ case "label":
2889
+ case "field":
2890
+ case "not":
2891
+ case "peek":
2892
+ case "node":
2893
+ case "withCtx":
2894
+ case "recover":
2895
+ case "expect":
2896
+ return [def.parser];
2897
+ case "grammar":
2898
+ return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
2899
+ case "sepBy":
2900
+ return [def.parser, def.separator];
2901
+ case "skip":
2902
+ return [def.main, def.skipped];
2903
+ case "scanTo":
2904
+ return [def.sentinel, ...def.skip];
2905
+ case "literal":
2906
+ case "regex":
2907
+ case "keywords":
2908
+ case "routed":
2909
+ case "guard":
2910
+ case "lazy":
2911
+ case "unknown":
2912
+ return [];
2913
+ }
2914
+ }
2915
+ function addNode(out, def) {
2916
+ if (def.type === void 0) return;
2917
+ const existing = out.get(def.type);
2918
+ if (existing === void 0) {
2919
+ out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
2920
+ return;
2921
+ }
2922
+ if (def.tags === void 0) return;
2923
+ for (const tag of def.tags) {
2924
+ if (!existing.includes(tag)) existing.push(tag);
2925
+ }
2926
+ }
2927
+ function collectFromCombinator(parser2, out, seen, followLazy = true) {
2928
+ if (seen.has(parser2)) return;
2929
+ seen.add(parser2);
2930
+ const def = parser2._def;
2931
+ if (def.tag === "lazy") {
2932
+ if (followLazy) {
2933
+ try {
2934
+ collectFromCombinator(def.thunk(), out, seen, followLazy);
2935
+ } catch {
2936
+ }
2937
+ }
2938
+ return;
2939
+ }
2940
+ if (def.tag === "node") addNode(out, def);
2941
+ for (const child of childrenOf(def)) collectFromCombinator(child, out, seen, followLazy);
2942
+ }
2943
+ function collectGrammarReflection(ruleMap, opts) {
2944
+ const byType = /* @__PURE__ */ new Map();
2945
+ const followLazy = opts?.followLazy !== false;
2946
+ for (const [, rule] of ruleMap) {
2947
+ if (!followLazy && rule._def.tag === "lazy") {
2948
+ try {
2949
+ const resolved = rule._def.thunk();
2950
+ if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
2951
+ } catch {
2952
+ }
2953
+ continue;
2954
+ }
2955
+ collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
2956
+ }
2957
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
2958
+ }
2959
+ function mergeGrammarReflections(reflections) {
2960
+ const byType = /* @__PURE__ */ new Map();
2961
+ for (const reflection of reflections) {
2962
+ for (const node2 of reflection.nodes) {
2963
+ const tags = byType.get(node2.type);
2964
+ if (tags === void 0) {
2965
+ byType.set(node2.type, [...node2.tags]);
2966
+ continue;
2967
+ }
2968
+ for (const tag of node2.tags) {
2969
+ if (!tags.includes(tag)) tags.push(tag);
2970
+ }
2971
+ }
2972
+ }
2973
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
2974
+ }
2975
+ function attachGrammarReflection(grammar, reflection) {
2976
+ Object.defineProperty(grammar, GRAMMAR_REFLECTION, { value: reflection, enumerable: false, configurable: true });
2977
+ return grammar;
2978
+ }
2979
+ function grammarReflectionOf(grammar) {
2980
+ return grammar[GRAMMAR_REFLECTION];
2981
+ }
2982
+ function grammarReflectionSource(reflection) {
2983
+ return `{ nodes: ${JSON.stringify(reflection.nodes)} }`;
2984
+ }
2985
+
2771
2986
  // src/combinators/parser.ts
2772
2987
  var RULE_ORDER = "__parsemanRuleOrder";
2773
2988
  function tagRule(r, key) {
@@ -2843,6 +3058,21 @@ function rules(a, b) {
2843
3058
  if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
2844
3059
  }
2845
3060
  }
3061
+ if (options?.trackLines === true) {
3062
+ for (const key of Object.keys(definitions)) {
3063
+ const rule = cache[key];
3064
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
3065
+ }
3066
+ for (const key of Object.keys(definitions)) {
3067
+ const rule = cache[key];
3068
+ if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
3069
+ const wrapped = parser({ trackLines: true }, rule);
3070
+ tagRule(wrapped, key);
3071
+ wrapped._meta.grammarTrackLines = true;
3072
+ cache[key] = wrapped;
3073
+ }
3074
+ }
3075
+ }
2846
3076
  for (const key of Object.keys(definitions)) {
2847
3077
  markUnusedValues(cache[key]);
2848
3078
  }
@@ -2851,6 +3081,7 @@ function rules(a, b) {
2851
3081
  enumerable: false,
2852
3082
  configurable: true
2853
3083
  });
3084
+ attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
2854
3085
  return cache;
2855
3086
  }
2856
3087
 
@@ -3171,13 +3402,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3171
3402
  const collapse = opts?.collapse === true;
3172
3403
  const captureTrivia = opts?.captureTrivia === true;
3173
3404
  const trailingTrivia = opts?.trailingTrivia === true;
3405
+ const tags = opts?.tags;
3174
3406
  if (unwrap && collapse) {
3175
3407
  throw new Error("node() options cannot set both unwrap and collapse");
3176
3408
  }
3177
3409
  if (project !== void 0 && (unwrap || collapse)) {
3178
3410
  throw new Error("node() options cannot combine project with unwrap or collapse");
3179
3411
  }
3180
- 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;
3412
+ 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;
3181
3413
  const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3182
3414
  const clonesState = build ? buildReadsState(def) : project === void 0;
3183
3415
  const hasOwnFields = parserHasOwnFields(combinator);
@@ -3223,7 +3455,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3223
3455
  const cstOutput = cstOutputHost(ctx.build);
3224
3456
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
3225
3457
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3226
- 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 };
3458
+ 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 };
3227
3459
  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 };
3228
3460
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3229
3461
  pushCstChild(ctx, built, rawEntry);
@@ -3299,101 +3531,6 @@ function field(name, combinator) {
3299
3531
  };
3300
3532
  }
3301
3533
 
3302
- // src/combinators/grammar.ts
3303
- function annotateResultLines(result, index) {
3304
- const annotated = { ...result, span: annotateSpan(result.span, index) };
3305
- const errors = annotated.errors;
3306
- if (errors) {
3307
- ;
3308
- annotated.errors = errors.map((error) => ({
3309
- ...error,
3310
- span: annotateSpan(error.span, index)
3311
- }));
3312
- }
3313
- return annotated;
3314
- }
3315
- function createParseLineContext(input, pos) {
3316
- const lineIndex = createLineIndex();
3317
- if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3318
- return { lineIndex, lineScannedTo: pos };
3319
- }
3320
- function parser(opts, root) {
3321
- const clearTrivia = opts.trivia === null;
3322
- return {
3323
- _tag: "grammar",
3324
- _meta: root._meta,
3325
- _def: {
3326
- tag: "grammar",
3327
- parser: root,
3328
- triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
3329
- clearTrivia,
3330
- ...opts.captureTrivia ? { captureTrivia: true } : {},
3331
- trackLines: opts.trackLines ?? false
3332
- },
3333
- parse(input, pos, _ctx) {
3334
- const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3335
- const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3336
- const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
3337
- const ctx = {
3338
- ..._ctx,
3339
- trackLines,
3340
- ...lineIndex ? { _lineIndex: lineIndex } : {},
3341
- ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3342
- // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
3343
- ...clearTrivia ? {
3344
- trivia: void 0,
3345
- triviaKindLabels: void 0
3346
- } : opts.trivia != null ? {
3347
- trivia: opts.trivia,
3348
- ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
3349
- } : {},
3350
- ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
3351
- // Kind-filter for per-node capture. Resolve against this scope's trivia
3352
- // labels — this parser's own trivia if it declares one, else the INHERITED
3353
- // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
3354
- // trivia is inherited rather than re-declared here. No labels → undefined
3355
- // (capture all).
3356
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3357
- };
3358
- const result = root.parse(input, pos ?? 0, ctx);
3359
- if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3360
- _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
3361
- }
3362
- return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3363
- }
3364
- };
3365
- }
3366
- function noTrivia(root) {
3367
- return parser({ trivia: null }, root);
3368
- }
3369
- var _analyzed = /* @__PURE__ */ new WeakSet();
3370
- function parse(combinator, input, opts = {}) {
3371
- if (!_analyzed.has(combinator)) {
3372
- _analyzed.add(combinator);
3373
- markUnusedValues(combinator);
3374
- }
3375
- const trackLines = opts.trackLines ?? false;
3376
- const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
3377
- const lineIndex = lineContext?.lineIndex;
3378
- const _errors = opts.recover ? [] : void 0;
3379
- const _probe = opts.recover ? { offset: input.length, best: null } : void 0;
3380
- const grammarTrivia = combinator._meta.grammarTrivia;
3381
- const grammarScanSkip = combinator._meta.grammarScanSkip;
3382
- const ctx = {
3383
- trackLines,
3384
- ...lineIndex ? { _lineIndex: lineIndex } : {},
3385
- ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3386
- ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
3387
- ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
3388
- ..._errors !== void 0 ? { _errors } : {},
3389
- ..._probe !== void 0 ? { _probe } : {}
3390
- };
3391
- const result = combinator.parse(input, 0, ctx);
3392
- if (!result.ok) return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3393
- const withErrors = _errors !== void 0 ? { ...result, errors: _errors, furthestFail: _probe?.best ?? null } : result;
3394
- return lineIndex ? annotateResultLines(withErrors, normalizeLineIndex(lineIndex)) : withErrors;
3395
- }
3396
-
3397
3534
  // src/combinators/token.ts
3398
3535
  function token(root) {
3399
3536
  const meta = {
@@ -3490,7 +3627,7 @@ function leaf(root, fn) {
3490
3627
  }
3491
3628
 
3492
3629
  // src/version.ts
3493
- var PARSEMAN_VERSION = "0.42.0";
3630
+ var PARSEMAN_VERSION = "0.43.0";
3494
3631
 
3495
3632
  // src/cst/host-mode.ts
3496
3633
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -3556,7 +3693,7 @@ var SUGGESTIONS = {
3556
3693
  function classifyBroadArm(arm, resolve) {
3557
3694
  const seen = /* @__PURE__ */ new Set();
3558
3695
  const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
3559
- const walk2 = (p) => {
3696
+ const walk = (p) => {
3560
3697
  if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
3561
3698
  seen.add(p);
3562
3699
  const d = p._def;
@@ -3570,7 +3707,7 @@ function classifyBroadArm(arm, resolve) {
3570
3707
  // peek() CARRIES its body's first-set, so it is only broad when the body is
3571
3708
  // (or the body is nullable) — walk in for the real cause.
3572
3709
  case "peek":
3573
- return walk2(d.parser);
3710
+ return walk(d.parser);
3574
3711
  case "scanTo":
3575
3712
  return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
3576
3713
  // `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
@@ -3584,7 +3721,7 @@ function classifyBroadArm(arm, resolve) {
3584
3721
  case "attempt":
3585
3722
  case "withCtx":
3586
3723
  case "recover":
3587
- return walk2(d.parser);
3724
+ return walk(d.parser);
3588
3725
  case "lazy": {
3589
3726
  const name = p._ruleName;
3590
3727
  let target;
@@ -3596,13 +3733,13 @@ function classifyBroadArm(arm, resolve) {
3596
3733
  return { cause: "cross-artifact-ref", detail: `unresolved ref${name ? ` g.${name}` : ""}`, unresolvedExternal: name !== void 0 };
3597
3734
  target = bound;
3598
3735
  }
3599
- const inner = walk2(target);
3736
+ const inner = walk(target);
3600
3737
  if (name !== void 0) return inner ? relabel(inner, "cross-artifact-ref", `via ref g.${name} \u2192 ${inner.detail}`) : null;
3601
3738
  return inner;
3602
3739
  }
3603
3740
  case "optional":
3604
3741
  case "many": {
3605
- const inner = walk2(d.parser);
3742
+ const inner = walk(d.parser);
3606
3743
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3607
3744
  }
3608
3745
  case "oneOrMore":
@@ -3615,9 +3752,9 @@ function classifyBroadArm(arm, resolve) {
3615
3752
  case "node":
3616
3753
  case "grammar":
3617
3754
  case "expect":
3618
- return walk2(d.parser);
3755
+ return walk(d.parser);
3619
3756
  case "skip":
3620
- return walk2(d.main);
3757
+ return walk(d.main);
3621
3758
  case "sequence": {
3622
3759
  let sawNullablePrefix = false;
3623
3760
  for (const t of d.parsers) {
@@ -3626,7 +3763,7 @@ function classifyBroadArm(arm, resolve) {
3626
3763
  continue;
3627
3764
  }
3628
3765
  if (isAny(firstSetOf(t, /* @__PURE__ */ new Set(), resolve))) {
3629
- const inner = walk2(t);
3766
+ const inner = walk(t);
3630
3767
  if (sawNullablePrefix)
3631
3768
  return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
3632
3769
  return inner ?? { cause: "broad-recognizer", detail: "sequence leading term is broad" };
@@ -3641,18 +3778,18 @@ function classifyBroadArm(arm, resolve) {
3641
3778
  }
3642
3779
  case "choice": {
3643
3780
  for (const a of d.parsers) {
3644
- const r = walk2(a);
3781
+ const r = walk(a);
3645
3782
  if (r) return relabel(r, r.cause, `choice arm \u2192 ${r.detail}`);
3646
3783
  }
3647
3784
  return null;
3648
3785
  }
3649
3786
  case "dispatch":
3650
- return walk2(d.selector);
3787
+ return walk(d.selector);
3651
3788
  default:
3652
3789
  return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
3653
3790
  }
3654
3791
  };
3655
- return walk2(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
3792
+ return walk(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
3656
3793
  }
3657
3794
  function peelToLeading(arm) {
3658
3795
  let d = arm._def;
@@ -3854,7 +3991,7 @@ function formatGatingWarnings(report) {
3854
3991
 
3855
3992
  // src/analysis/duplication.ts
3856
3993
  var siteToString = (s) => s.path === "" ? s.rule : `${s.rule} \u203A ${s.path}`;
3857
- function childrenOf(d) {
3994
+ function childrenOf2(d) {
3858
3995
  switch (d.tag) {
3859
3996
  case "sequence":
3860
3997
  case "choice":
@@ -3988,7 +4125,7 @@ function render(p, depth = 3) {
3988
4125
  break;
3989
4126
  }
3990
4127
  if (depth <= 0) return `${d.tag}(\u2026)`;
3991
- const kids = childrenOf(d).map((k) => render(k, depth - 1));
4128
+ const kids = childrenOf2(d).map((k) => render(k, depth - 1));
3992
4129
  switch (d.tag) {
3993
4130
  case "sequence":
3994
4131
  return `sequence(${kids.join(", ")})`;
@@ -4183,7 +4320,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4183
4320
  if (hit !== void 0) return hit;
4184
4321
  const d = p._def;
4185
4322
  shapeCache.set(p, interner.hole);
4186
- const kids = childrenOf(d);
4323
+ const kids = childrenOf2(d);
4187
4324
  const id = interner.of(`${payloadKey(p, d)}|${kids.map(shapeOf).join(",")}`);
4188
4325
  shapeCache.set(p, id);
4189
4326
  return id;
@@ -4193,7 +4330,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4193
4330
  if (hit !== void 0) return hit;
4194
4331
  sizeCache.set(p, 1);
4195
4332
  let n = 1;
4196
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4333
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4197
4334
  sizeCache.set(p, n);
4198
4335
  return n;
4199
4336
  };
@@ -4206,7 +4343,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4206
4343
  visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
4207
4344
  const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
4208
4345
  const innerReducer = enclosingReducer || d.tag === "node" && (d.build !== void 0 || d.buildSrc !== void 0) || d.tag === "transform" || d.tag === "leaf";
4209
- const kids = childrenOf(d);
4346
+ const kids = childrenOf2(d);
4210
4347
  kids.forEach((k, i) => {
4211
4348
  const seg = segment(d, i);
4212
4349
  visit(k, here.rule, here.path === "" ? seg : `${here.path} \u203A ${seg}`, inner, innerReducer);
@@ -4266,7 +4403,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
4266
4403
  function markSubtree(p, into) {
4267
4404
  if (into.has(p)) return;
4268
4405
  into.add(p);
4269
- for (const k of childrenOf(p._def)) markSubtree(k, into);
4406
+ for (const k of childrenOf2(p._def)) markSubtree(k, into);
4270
4407
  }
4271
4408
  var stripMembers = (f) => {
4272
4409
  const { _members, ...rest } = f;
@@ -4306,7 +4443,7 @@ function findNearDuplicates(visited, interner, shapeOf, minSize) {
4306
4443
  if (hit !== void 0) return hit;
4307
4444
  holeCache.set(p, []);
4308
4445
  const d = p._def;
4309
- const kids = childrenOf(d);
4446
+ const kids = childrenOf2(d);
4310
4447
  const kidShapes = kids.map(shapeOf);
4311
4448
  const payload = payloadKey(p, d);
4312
4449
  const out2 = [];
@@ -4367,7 +4504,7 @@ function findDivergentSlot(members, shapeOf) {
4367
4504
  let cur = [...members];
4368
4505
  for (let guard2 = 0; guard2 < 64; guard2++) {
4369
4506
  const d0 = cur[0]._def;
4370
- const kidLists = cur.map((c) => childrenOf(c._def));
4507
+ const kidLists = cur.map((c) => childrenOf2(c._def));
4371
4508
  const arity = kidLists[0].length;
4372
4509
  if (kidLists.some((k) => k.length !== arity) || arity === 0) break;
4373
4510
  const diff = [];
@@ -4380,7 +4517,7 @@ function findDivergentSlot(members, shapeOf) {
4380
4517
  path.push(i);
4381
4518
  defs.push(d0);
4382
4519
  cur = kidLists.map((k) => k[i]);
4383
- const nextArity = childrenOf(cur[0]._def).length;
4520
+ const nextArity = childrenOf2(cur[0]._def).length;
4384
4521
  const samePayload = cur.every((c) => payloadKey(c, c._def) === payloadKey(cur[0], cur[0]._def));
4385
4522
  if (!samePayload || nextArity === 0) break;
4386
4523
  }
@@ -4388,7 +4525,7 @@ function findDivergentSlot(members, shapeOf) {
4388
4525
  let slotSize = 0;
4389
4526
  const sizeOf = (p) => {
4390
4527
  let n = 1;
4391
- for (const k of childrenOf(p._def)) n += sizeOf(k);
4528
+ for (const k of childrenOf2(p._def)) n += sizeOf(k);
4392
4529
  return n;
4393
4530
  };
4394
4531
  for (const c of cur) slotSize = Math.max(slotSize, sizeOf(c));
@@ -4397,7 +4534,7 @@ function findDivergentSlot(members, shapeOf) {
4397
4534
  function renderWithHole(p, path, depth = 0) {
4398
4535
  if (depth === path.length) return "\u2039slot\u203A";
4399
4536
  const d = p._def;
4400
- const kids = childrenOf(d);
4537
+ const kids = childrenOf2(d);
4401
4538
  const idx = path[depth];
4402
4539
  const parts = kids.map((k, i) => i === idx ? renderWithHole(k, path, depth + 1) : render(k, 2));
4403
4540
  switch (d.tag) {
@@ -4855,7 +4992,7 @@ function capturesPositionally(p, seen = /* @__PURE__ */ new Set()) {
4855
4992
  seen.add(p);
4856
4993
  const d = p._def;
4857
4994
  if (d.tag === "field" || d.tag === "label") return true;
4858
- for (const k of childrenOf(d)) if (capturesPositionally(k, seen)) return true;
4995
+ for (const k of childrenOf2(d)) if (capturesPositionally(k, seen)) return true;
4859
4996
  return false;
4860
4997
  }
4861
4998
  function detectHandRolledSepBy(terms, shapeOf) {
@@ -4961,7 +5098,7 @@ function nestedNodeTypes(root, out, seen, isRoot) {
4961
5098
  }
4962
5099
  return;
4963
5100
  }
4964
- for (const k of childrenOf(d)) nestedNodeTypes(k, out, seen, false);
5101
+ for (const k of childrenOf2(d)) nestedNodeTypes(k, out, seen, false);
4965
5102
  }
4966
5103
  var MAX_LOST_TYPES = 8;
4967
5104
  function findStructureLoss(visited, resolve) {
@@ -6850,13 +6987,16 @@ function reindentStmts(stmts, targetLevels) {
6850
6987
  const targetPrefix = " ".repeat(targetLevels);
6851
6988
  return stmts.map((s) => s.trim().length === 0 ? "" : targetPrefix + s.slice(minLeading));
6852
6989
  }
6853
- function failReturn(expected, posExpr) {
6990
+ function failReturn(ctx, expected, posExpr) {
6991
+ if (ctx.lineTracking) return `return { ok: false, expected: [${expected}], span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6854
6992
  return `return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6855
6993
  }
6856
- function failReturnArr(expectedArr, posExpr) {
6994
+ function failReturnArr(ctx, expectedArr, posExpr) {
6995
+ if (ctx.lineTracking) return `return { ok: false, expected: ${expectedArr}, span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6857
6996
  return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
6858
6997
  }
6859
- function committedReturnArr(expectedArr, posExpr) {
6998
+ function committedReturnArr(ctx, expectedArr, posExpr) {
6999
+ if (ctx.lineTracking) return `return { ok: false, expected: [...${expectedArr}], span: ${emitSpanExpr(ctx, posExpr, posExpr)}, committed: true }`;
6860
7000
  return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
6861
7001
  }
6862
7002
  function hoistExpected(ctx, constArrSource) {
@@ -6881,7 +7021,7 @@ function failBody(ctx, expected, posExpr) {
6881
7021
  if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
6882
7022
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
6883
7023
  }
6884
- return probe + trace + failReturn(expected, posExpr);
7024
+ return probe + trace + failReturn(ctx, expected, posExpr);
6885
7025
  }
6886
7026
  function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6887
7027
  const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
@@ -6891,18 +7031,19 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6891
7031
  const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
6892
7032
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
6893
7033
  }
6894
- if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6895
- return probe + trace + failReturnArr(expectedArr, posExpr);
7034
+ if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: ${ctx.lineTracking ? emitSpanExpr(ctx, posExpr, posExpr) : `{ start: ${posExpr}, end: ${posExpr} }`} }`;
7035
+ return probe + trace + failReturnArr(ctx, expectedArr, posExpr);
6896
7036
  }
6897
- function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
6898
- return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
7037
+ function resultFromRecorded(ctx, feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
7038
+ const spanExpr = ctx.lineTracking ? emitSpanExpr(ctx, feExpr, feExpr) : `{ start: ${feExpr}, end: ${feExpr} }`;
7039
+ return `return { ok: false, expected: [...${fxExpr}], span: ${spanExpr}, ...(_ctx._fc ? { committed: true } : {}) }`;
6899
7040
  }
6900
7041
  function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
6901
7042
  if (ctx.failLabel) {
6902
7043
  if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
6903
7044
  return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
6904
7045
  }
6905
- return committedReturnArr(expectedArr, posExpr);
7046
+ return committedReturnArr(ctx, expectedArr, posExpr);
6906
7047
  }
6907
7048
  function propagateFailBody(ctx, srcCtx = "_ctx") {
6908
7049
  if (srcCtx !== "_ctx") {
@@ -6910,10 +7051,10 @@ function propagateFailBody(ctx, srcCtx = "_ctx") {
6910
7051
  if (!ctx.recordFail) return `break ${ctx.failLabel}`;
6911
7052
  return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
6912
7053
  }
6913
- return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
7054
+ return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded(ctx)} }`;
6914
7055
  }
6915
7056
  if (ctx.failLabel) return `break ${ctx.failLabel}`;
6916
- return resultFromRecorded();
7057
+ return resultFromRecorded(ctx);
6917
7058
  }
6918
7059
  function emitIfFail(ctx, cond, body) {
6919
7060
  return [
@@ -8144,7 +8285,7 @@ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
8144
8285
  const d = p._def;
8145
8286
  if (d.tag === "dispatch") return false;
8146
8287
  if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
8147
- return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8288
+ return childrenOf3(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
8148
8289
  }
8149
8290
  function armReplayInScope(arm, ctx) {
8150
8291
  let p = arm;
@@ -8346,7 +8487,7 @@ function emitAttempt(p, def, ctx, pos) {
8346
8487
  if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
8347
8488
  const gcV = v(ctx, "_agc");
8348
8489
  const gExp = armStaticExpected(ctx, def.parser);
8349
- const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
8490
+ const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(ctx, gExp, pos)} }`;
8350
8491
  preGuard.push(
8351
8492
  `${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8352
8493
  `${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -8845,7 +8986,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8845
8986
  if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
8846
8987
  const gcV = v(ctx, "_ngc");
8847
8988
  const gExp = armStaticExpected(ctx, def.parser);
8848
- const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
8989
+ const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
8849
8990
  preGuard.push(
8850
8991
  `${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8851
8992
  `${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -8907,7 +9048,8 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8907
9048
  const nodeSpanV = ctx.lineTracking ? v(ctx, "_nspan") : nodeSpanExpr;
8908
9049
  if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
8909
9050
  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})`;
8910
- const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
9051
+ const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
9052
+ const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${hostBuildArgs})`;
8911
9053
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8912
9054
  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;
8913
9055
  const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
@@ -9361,6 +9503,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9361
9503
  if (seen.has(p)) return false;
9362
9504
  seen.add(p);
9363
9505
  const d = p._def;
9506
+ if (p._meta.grammarTrackLines) return true;
9364
9507
  if (d.tag === "grammar" && d.trackLines) return true;
9365
9508
  if (d.tag === "lazy") {
9366
9509
  try {
@@ -9369,7 +9512,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9369
9512
  return false;
9370
9513
  }
9371
9514
  }
9372
- return childrenOf2(d).some((child) => hasLineTrackingDef(child, seen));
9515
+ return childrenOf3(d).some((child) => hasLineTrackingDef(child, seen));
9373
9516
  }
9374
9517
  function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9375
9518
  if (seen.has(p)) return false;
@@ -9388,7 +9531,7 @@ function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
9388
9531
  case "dispatch":
9389
9532
  return false;
9390
9533
  default:
9391
- return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
9534
+ return childrenOf3(d).some((child) => parserUsesRouted2(child, seen));
9392
9535
  }
9393
9536
  }
9394
9537
  function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
@@ -9403,9 +9546,9 @@ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
9403
9546
  return false;
9404
9547
  }
9405
9548
  }
9406
- return childrenOf2(d).some((child) => hasDirectBuildDef(child, seen));
9549
+ return childrenOf3(d).some((child) => hasDirectBuildDef(child, seen));
9407
9550
  }
9408
- function childrenOf2(def) {
9551
+ function childrenOf3(def) {
9409
9552
  switch (def.tag) {
9410
9553
  case "sequence":
9411
9554
  case "choice":
@@ -9480,7 +9623,7 @@ function subtreeSizes(roots) {
9480
9623
  const def = p._def;
9481
9624
  let s = 1;
9482
9625
  if (def.tag !== "lazy") {
9483
- for (const child of childrenOf2(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
9626
+ for (const child of childrenOf3(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
9484
9627
  }
9485
9628
  sizes.set(p, s);
9486
9629
  return s;
@@ -9501,7 +9644,7 @@ function subtreeSizes(roots) {
9501
9644
  return;
9502
9645
  }
9503
9646
  sz(p);
9504
- for (const child of childrenOf2(def)) visit(child);
9647
+ for (const child of childrenOf3(def)) visit(child);
9505
9648
  };
9506
9649
  for (const root of roots) visit(root);
9507
9650
  return sizes;
@@ -9511,7 +9654,7 @@ function analyzeLazyUsageMulti(roots) {
9511
9654
  const recursive = /* @__PURE__ */ new Set();
9512
9655
  const descended = /* @__PURE__ */ new Set();
9513
9656
  const active = /* @__PURE__ */ new Set();
9514
- function walk2(p) {
9657
+ function walk(p) {
9515
9658
  const def = p._def;
9516
9659
  if (def.tag === "lazy") {
9517
9660
  counts.set(p, (counts.get(p) ?? 0) + 1);
@@ -9528,17 +9671,17 @@ function analyzeLazyUsageMulti(roots) {
9528
9671
  return;
9529
9672
  }
9530
9673
  active.add(p);
9531
- walk2(resolved);
9674
+ walk(resolved);
9532
9675
  active.delete(p);
9533
9676
  return;
9534
9677
  }
9535
9678
  if (isHoistableTag(def.tag)) {
9536
9679
  counts.set(p, (counts.get(p) ?? 0) + 1);
9537
9680
  }
9538
- for (const child of childrenOf2(def)) walk2(child);
9681
+ for (const child of childrenOf3(def)) walk(child);
9539
9682
  }
9540
9683
  const rootsArr = [...roots];
9541
- for (const root of rootsArr) walk2(root);
9684
+ for (const root of rootsArr) walk(root);
9542
9685
  return { counts, recursive, sizes: subtreeSizes(rootsArr) };
9543
9686
  }
9544
9687
  function ruleDependencies(ruleMap) {
@@ -9548,7 +9691,7 @@ function ruleDependencies(ruleMap) {
9548
9691
  for (const [name, comb] of ruleMap) {
9549
9692
  const found = /* @__PURE__ */ new Set();
9550
9693
  const seen = /* @__PURE__ */ new Set();
9551
- const walk2 = (p, isRoot) => {
9694
+ const walk = (p, isRoot) => {
9552
9695
  const def = p._def;
9553
9696
  const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
9554
9697
  if (!isRoot && boundary !== void 0) {
@@ -9564,12 +9707,12 @@ function ruleDependencies(ruleMap) {
9564
9707
  } catch {
9565
9708
  return;
9566
9709
  }
9567
- walk2(resolved, false);
9710
+ walk(resolved, false);
9568
9711
  return;
9569
9712
  }
9570
- for (const child of childrenOf2(def)) walk2(child, false);
9713
+ for (const child of childrenOf3(def)) walk(child, false);
9571
9714
  };
9572
- walk2(comb, true);
9715
+ walk(comb, true);
9573
9716
  deps.set(name, [...found]);
9574
9717
  }
9575
9718
  return deps;
@@ -9718,6 +9861,7 @@ function compile(combinator, mapFnSources, opts) {
9718
9861
  const grammarTrivia = combinator._meta.grammarTrivia;
9719
9862
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9720
9863
  const grammarHostMode = combinator._meta.grammarHostMode;
9864
+ const grammarTrackLines = combinator._meta.grammarTrackLines;
9721
9865
  const ctx = {
9722
9866
  vars: 0,
9723
9867
  indent: 1,
@@ -9738,7 +9882,7 @@ function compile(combinator, mapFnSources, opts) {
9738
9882
  capturing: hasNodeDef(combinator),
9739
9883
  recovery: opts?.recovery ?? false,
9740
9884
  hostMode: opts?.hostMode ?? grammarHostMode ?? "ast",
9741
- lineTracking: opts?.trackLines === true || hasLineTrackingDef(combinator),
9885
+ lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9742
9886
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9743
9887
  lazyUsage: analyzeLazyUsage(combinator),
9744
9888
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9902,6 +10046,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9902
10046
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
9903
10047
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
9904
10048
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10049
+ const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
9905
10050
  const ruleMap = ruleMapArg.filter(([, val]) => {
9906
10051
  const d = val._def;
9907
10052
  if (d.tag !== "lazy") return true;
@@ -9912,6 +10057,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9912
10057
  return false;
9913
10058
  }
9914
10059
  });
10060
+ const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
9915
10061
  const ctx = {
9916
10062
  vars: 0,
9917
10063
  indent: 1,
@@ -9936,6 +10082,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9936
10082
  capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
9937
10083
  recovery: opts?.recovery ?? false,
9938
10084
  hostMode: grammarHostMode ?? "ast",
10085
+ lineTracking: grammarTrackLines,
9939
10086
  ...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
9940
10087
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
9941
10088
  ns,
@@ -9986,7 +10133,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9986
10133
  scanExternal(resolved);
9987
10134
  return;
9988
10135
  }
9989
- for (const child of childrenOf2(def)) scanExternal(child);
10136
+ for (const child of childrenOf3(def)) scanExternal(child);
9990
10137
  };
9991
10138
  for (const [, rule] of ruleMap) scanExternal(rule);
9992
10139
  }
@@ -10032,6 +10179,10 @@ function compileLinkable(ruleMapArg, ns, opts) {
10032
10179
  perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
10033
10180
  }
10034
10181
  if (ctx.runtimeParsers.length !== 0) return null;
10182
+ if (ctx.lineTracking) {
10183
+ ctx.needsLineTrack = true;
10184
+ ctx.needsLineSpan = true;
10185
+ }
10035
10186
  const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
10036
10187
  const buildSrcs = ctx.buildFns.length > 0 && ctx.buildSrcs.every((s) => s !== null) ? ctx.buildSrcs : null;
10037
10188
  const ruleFns = /* @__PURE__ */ new Map();
@@ -10045,6 +10196,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
10045
10196
  const mfDecl = ctx.mapFns.length === 0 ? "" : mfSrcs ? `const ${mfRef(ctx)} = [${mfSrcs.join(", ")}]` : `const ${mfRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "mf")}]`;
10046
10197
  const buildDecl = ctx.buildFns.length === 0 ? "" : buildSrcs ? `const ${buildRef(ctx)} = [${buildSrcs.join(", ")}]` : `const ${buildRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "build")}]`;
10047
10198
  const prelude = [
10199
+ ctx.needsLineTrack ? LINE_TRACK_DECL : "",
10200
+ ctx.needsLineSpan ? LINE_SPAN_DECL : "",
10048
10201
  ...ctx.regexDecls,
10049
10202
  ...ctx.expectedDecls,
10050
10203
  mfDecl,
@@ -10053,11 +10206,18 @@ function compileLinkable(ruleMapArg, ns, opts) {
10053
10206
  ].filter(Boolean);
10054
10207
  const wrappers = /* @__PURE__ */ new Map();
10055
10208
  for (const { key, rule, r } of perEntry) {
10209
+ const linePreamble = ctx.lineTracking ? [
10210
+ ` if (_ctx._lineStarts === undefined) _ctx = { ..._ctx, trackLines: true, _lineStarts: [0], _lineScannedTo: 0 }`,
10211
+ ` else _ctx.trackLines = true`,
10212
+ ` if (_pos > (_ctx._lineScannedTo ?? 0)) _trackLines(_ctx, input, 0, _pos)`
10213
+ ] : [];
10214
+ const resultSpan = ctx.lineTracking ? `_spanLines(_ctx, _pos, ${r.endVar})` : `{ start: _pos, end: ${r.endVar} }`;
10056
10215
  wrappers.set(key, publicRuleWrapperSource(rule, [
10057
10216
  `function(input, _pos, _ctx) {`,
10217
+ ...linePreamble,
10058
10218
  ` let pos = _pos`,
10059
10219
  ...r.stmts,
10060
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
10220
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10061
10221
  `}`
10062
10222
  ].join("\n"), ctx.triviaKindLabels));
10063
10223
  }
@@ -10095,6 +10255,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10095
10255
  hostBranchElided: !!ctx.hostBranchElided,
10096
10256
  hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
10097
10257
  isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule), externalRefs),
10258
+ nodeMeta,
10098
10259
  mfFns: mfSrcs ? [] : ctx.mapFns,
10099
10260
  buildFns: buildSrcs ? [] : ctx.buildFns
10100
10261
  };
@@ -10115,7 +10276,7 @@ function hasExternalRuleRef(ruleMap) {
10115
10276
  if (resolved === void 0) return p._ruleName !== void 0;
10116
10277
  return visit(resolved);
10117
10278
  }
10118
- return childrenOf2(def).some(visit);
10279
+ return childrenOf3(def).some(visit);
10119
10280
  };
10120
10281
  return ruleMap.some(([, rule]) => visit(rule));
10121
10282
  }
@@ -10137,7 +10298,7 @@ function hasSemanticReduction(roots, externalRefs) {
10137
10298
  return true;
10138
10299
  }
10139
10300
  }
10140
- return childrenOf2(def).some(visit);
10301
+ return childrenOf3(def).some(visit);
10141
10302
  };
10142
10303
  return roots.some(visit);
10143
10304
  }
@@ -10210,7 +10371,7 @@ function withCtx(extra, combinator) {
10210
10371
  }
10211
10372
 
10212
10373
  // src/compiler/ir-serialize.ts
10213
- function childrenOf3(def) {
10374
+ function childrenOf4(def) {
10214
10375
  switch (def.tag) {
10215
10376
  case "sequence":
10216
10377
  case "choice":
@@ -10274,6 +10435,10 @@ function projectOpt(project) {
10274
10435
  if (project === void 0) return void 0;
10275
10436
  return `project: ${project}`;
10276
10437
  }
10438
+ function tagsOpt(tags) {
10439
+ if (tags === void 0 || tags.length === 0) return void 0;
10440
+ return `tags: ${JSON.stringify(tags)}`;
10441
+ }
10277
10442
  function matcherExpr(entry) {
10278
10443
  switch (entry.kind) {
10279
10444
  case "startsWith":
@@ -10487,7 +10652,7 @@ var Serializer = class {
10487
10652
  if (target) this.assertNoRuleRef(target, seen);
10488
10653
  return;
10489
10654
  }
10490
- for (const child of childrenOf3(c._def)) this.assertNoRuleRef(child, seen);
10655
+ for (const child of childrenOf4(c._def)) this.assertNoRuleRef(child, seen);
10491
10656
  }
10492
10657
  /** A `rules()` map wraps each rule value in a named `lazy` proxy; the real body is
10493
10658
  * its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
@@ -10551,7 +10716,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10551
10716
  this.counts.set(c, (this.counts.get(c) ?? 0) + 1);
10552
10717
  if ((this.counts.get(c) ?? 0) > 1) return;
10553
10718
  active.add(c);
10554
- for (const child of childrenOf3(def)) this.analyze(child, active);
10719
+ for (const child of childrenOf4(def)) this.analyze(child, active);
10555
10720
  active.delete(c);
10556
10721
  }
10557
10722
  /** Reference `c`: a const var if it has one (emitting its decl first), else inline.
@@ -10668,12 +10833,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10668
10833
  case "node": {
10669
10834
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10670
10835
  const projectEntry = projectOpt(def.project);
10836
+ const tagEntry = tagsOpt(def.tags);
10671
10837
  const optEntries = [
10672
10838
  ...def.unwrap ? ["unwrap: true"] : [],
10673
10839
  ...def.collapse ? ["collapse: true"] : [],
10674
10840
  ...projectEntry === void 0 ? [] : [projectEntry],
10675
10841
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10676
- ...def.trailingTrivia ? ["trailingTrivia: true"] : []
10842
+ ...def.trailingTrivia ? ["trailingTrivia: true"] : [],
10843
+ ...tagEntry === void 0 ? [] : [tagEntry]
10677
10844
  ];
10678
10845
  const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
10679
10846
  if (def.type === void 0) {
@@ -10721,15 +10888,16 @@ function normalizeCstCollapse(collapse) {
10721
10888
  }
10722
10889
  return typeof collapse === "function" ? collapse : void 0;
10723
10890
  }
10724
- function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
10725
- return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
10891
+ function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state, tags) {
10892
+ 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] };
10726
10893
  }
10727
- function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
10894
+ function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state, _tags) {
10728
10895
  if (typeof typeOrOptions === "string") {
10729
10896
  return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
10730
10897
  }
10731
10898
  const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
10732
- const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2);
10899
+ const materializeTags = typeOrOptions?.tags === true;
10900
+ const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
10733
10901
  host._parsemanCstOutput = true;
10734
10902
  if (collapse) host._parsemanCstCollapse = collapse;
10735
10903
  return host;
@@ -10771,6 +10939,7 @@ function fusedBody(pieces) {
10771
10939
  ...[...winner].map(([k, p]) => p.ruleFns.get(k))
10772
10940
  ];
10773
10941
  const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
10942
+ const reflection = mergeGrammarReflections([...winner].map(([k, p]) => p.nodeMeta.get(k) ?? { nodes: [] }));
10774
10943
  const { mode, elided } = hostModeOfPieces(pieces);
10775
10944
  const rawBody = [
10776
10945
  ...lines,
@@ -10779,6 +10948,7 @@ function fusedBody(pieces) {
10779
10948
  "}",
10780
10949
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_MODE.description)}), { value: ${JSON.stringify(mode)}, enumerable: false })`,
10781
10950
  `Object.defineProperty(_map, Symbol.for(${JSON.stringify(FUSED_HOST_ELIDED.description)}), { value: ${JSON.stringify(elided)}, enumerable: false })`,
10951
+ `Object.defineProperty(_map, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`,
10782
10952
  // …and on each rule FUNCTION, because `run(map.Rule, …)` is handed the rule, not the
10783
10953
  // map, and would otherwise have nothing to check against. Done once at fuse time,
10784
10954
  // before any rule has been called, so it costs nothing per parse.
@@ -10945,7 +11115,8 @@ function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
10945
11115
  const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
10946
11116
  ...trivia2 ? { trivia: trivia2 } : {},
10947
11117
  ...captureTerminals ? { captureTerminals: true } : {},
10948
- ...hostMode ? { hostMode } : {}
11118
+ ...hostMode ? { hostMode } : {},
11119
+ ...p.trackLines ? { trackLines: true } : {}
10949
11120
  });
10950
11121
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
10951
11122
  return pieces;
@@ -12206,38 +12377,48 @@ function buildTriviaIndex(root, input = "", opts) {
12206
12377
  }
12207
12378
 
12208
12379
  // src/cst/walk.ts
12209
- function walk(root, visitor, ctx = void 0) {
12210
- const go = (node2, parent) => {
12211
- const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
12212
- const children2 = node2.children;
12213
- if (descend !== false && Array.isArray(children2)) {
12214
- for (const child of children2) go(child, node2);
12215
- }
12216
- visitor.leave?.(node2, parent, ctx);
12217
- };
12218
- go(root, null);
12219
- }
12220
- function createVisitor(handlers) {
12221
- const api = {
12222
- visit(node2) {
12223
- const handler = node2.type !== void 0 ? handlers[node2.type] : void 0;
12224
- if (handler) return handler(node2, api);
12225
- api.visitChildren(node2);
12226
- return void 0;
12227
- },
12228
- visitChildren(node2) {
12229
- const out = [];
12230
- const children2 = node2.children;
12231
- if (Array.isArray(children2)) {
12232
- for (const child of children2) {
12233
- const r = api.visit(child);
12234
- if (r !== void 0) out.push(r);
12380
+ function isCombinator(value) {
12381
+ return !!value && typeof value === "object" && "_def" in value && "_meta" in value && typeof value.parse === "function";
12382
+ }
12383
+ function reflectionFor(grammar) {
12384
+ const stamped = grammarReflectionOf(grammar);
12385
+ if (stamped) return stamped;
12386
+ const entries = Object.entries(grammar).filter((entry) => isCombinator(entry[1]));
12387
+ return collectGrammarReflection(entries);
12388
+ }
12389
+ function createVisitor(grammar, spec) {
12390
+ const reflection = reflectionFor(grammar);
12391
+ const typeHandlers = spec.type;
12392
+ const tagSpec = spec.tag;
12393
+ const tagHandlersByType = /* @__PURE__ */ new Map();
12394
+ if (tagSpec !== void 0) {
12395
+ for (const node2 of reflection.nodes) {
12396
+ const handlers = [];
12397
+ for (const tag of node2.tags) {
12398
+ const handler = tagSpec[tag];
12399
+ if (handler) handlers.push(handler);
12400
+ }
12401
+ if (handlers.length > 0) tagHandlersByType.set(node2.type, handlers);
12402
+ }
12403
+ }
12404
+ return (root, ctx = void 0) => {
12405
+ const go = (node2, parent) => {
12406
+ const descend = spec.enter ? spec.enter(node2, parent, ctx) : void 0;
12407
+ if (node2._tag === "node" && node2.type !== void 0) {
12408
+ typeHandlers?.[node2.type]?.(node2, parent, ctx);
12409
+ const tagHandlers = tagHandlersByType.get(node2.type);
12410
+ if (tagHandlers !== void 0) {
12411
+ for (const handler of tagHandlers) handler(node2, parent, ctx);
12235
12412
  }
12236
12413
  }
12237
- return out;
12238
- }
12414
+ const children2 = node2.children;
12415
+ if (descend !== false && Array.isArray(children2)) {
12416
+ for (const child of children2) go(child, node2);
12417
+ }
12418
+ spec.leave?.(node2, parent, ctx);
12419
+ };
12420
+ go(root, null);
12239
12421
  };
12240
- return (node2) => api.visit(node2);
12241
12422
  }
12242
12423
 
12243
12424
  // src/cst/offset-model.ts
@@ -12534,7 +12715,6 @@ export {
12534
12715
  trivia,
12535
12716
  triviaEntries,
12536
12717
  triviaKindMask,
12537
- walk,
12538
12718
  when,
12539
12719
  withCtx,
12540
12720
  word