Skip to content

Commit 16426ee

Browse files
committed
feat(meta): defmacro vars ride the same wire meta channel (D-563b residual)
Smell-audited: 1: mirrors analyzeDef's def_meta_expr exactly (merged doc/attr/arglists + compiler line/column/file, wholesale-quoted, one composite constant); macro docstrings now survive cljw build artifacts (round-trip verified: [macro doc true]).
1 parent 3e3bf0d commit 16426ee

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

‎.dev/debt.yaml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ active:
8080
` (file:line)` suffix restored from the deftest var's meta — AD-041
8181
NARROWED (deftest-line vs clj's assertion-stack-line residual).
8282
e2e phase15_var_source_meta (8) + diff case + the narrowed pin.
83-
Residual: defmacro's def_node has no meta_expr yet (macro vars keep
84-
analyze-time meta only; small follow-up on the same channel).
83+
Residual DISCHARGED 2026-07-17: defmacro's def_node now mints the
84+
same wire-riding meta_expr (doc/arglists/line/column/file; macro
85+
docstrings survive AOT artifacts — verified round-trip).
8586
(c) **var-existence gaps mainline completion surfaced**:
8687
`default-data-readers` (needs reader fns exposed as vars) and
8788
`defstruct`/`create-struct`/`struct-map`/`accessor` (legacy

‎src/eval/analyzer/special_forms.zig‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,49 @@ pub fn analyzeDefmacro(
491491
const meta_map: Form = .{ .data = .{ .map = try arena.dupe(Form, meta_items.items) }, .location = form.location };
492492
placeholder_var.meta = try analyzer_mod.formToValue(rt, env, try unquoteMetaValues(arena, meta_map));
493493
}
494+
// D-563(b): the wire-riding meta EXPRESSION for macro Vars — the same
495+
// merged map plus the compiler-minted :line/:column/:file, wholesale-
496+
// quoted to one composite constant (mirrors analyzeDef's def_meta_expr;
497+
// macro docstrings now survive AOT artifacts too).
498+
const macro_meta_expr: ?*const Node = blk: {
499+
const src_loc = items[1].location;
500+
if (src_loc.line == 0) break :blk null;
501+
var meta_items: std.ArrayList(Form) = .empty;
502+
if (items[1].meta) |mf| try meta_items.appendSlice(arena, mf.data.map);
503+
if (attr_form) |a| try meta_items.appendSlice(arena, a.data.map);
504+
if (doc_form) |d| {
505+
try meta_items.append(arena, .{ .data = .{ .keyword = .{ .name = "doc" } }, .location = form.location });
506+
try meta_items.append(arena, d);
507+
}
508+
const arglists_inner2 = if (multi_arity) blk2: {
509+
const clauses = items[head..];
510+
const av = try arena.alloc(Form, clauses.len);
511+
for (clauses, 0..) |c, j| av[j] = c.data.list[0];
512+
break :blk2 av;
513+
} else blk2: {
514+
const av = try arena.alloc(Form, 1);
515+
av[0] = items[head];
516+
break :blk2 av;
517+
};
518+
try meta_items.append(arena, .{ .data = .{ .keyword = .{ .name = "arglists" } }, .location = form.location });
519+
try meta_items.append(arena, .{ .data = .{ .list = arglists_inner2 }, .location = form.location });
520+
const kws = [_]struct { name: []const u8, v: i64 }{
521+
.{ .name = "line", .v = @intCast(src_loc.line) },
522+
.{ .name = "column", .v = @intCast(src_loc.column) },
523+
};
524+
for (kws) |kv| {
525+
try meta_items.append(arena, .{ .data = .{ .keyword = .{ .name = kv.name } }, .location = form.location });
526+
try meta_items.append(arena, .{ .data = .{ .integer = kv.v }, .location = form.location });
527+
}
528+
try meta_items.append(arena, .{ .data = .{ .keyword = .{ .name = "file" } }, .location = form.location });
529+
try meta_items.append(arena, .{ .data = .{ .string = src_loc.file }, .location = form.location });
530+
const meta_map2: Form = .{ .data = .{ .map = try arena.dupe(Form, meta_items.items) }, .location = form.location };
531+
const quote_items = try arena.alloc(Form, 2);
532+
quote_items[0] = macro_dispatch.makeSymbol("quote", form.location);
533+
quote_items[1] = try unquoteMetaValues(arena, meta_map2);
534+
const quoted: Form = .{ .data = .{ .list = quote_items }, .location = form.location };
535+
break :blk try analyzer_mod.analyze(arena, rt, env, scope, quoted, macro_table);
536+
};
494537

495538
// Build the synthetic `fn` Form, then analyse it through the regular path
496539
// so multi-arity / closure / arg checks all ride existing FnNode
@@ -538,6 +581,7 @@ pub fn analyzeDefmacro(
538581
.value_expr = value_node,
539582
.is_macro = true,
540583
.is_private = is_private,
584+
.meta_expr = macro_meta_expr,
541585
.loc = form.location,
542586
} };
543587
return n;

0 commit comments

Comments
 (0)