Skip to content

Commit 102c28a

Browse files
committed
autodoc: initial support for struct_init_anon
1 parent be2bd58 commit 102c28a

File tree

2 files changed

+129
-48
lines changed

2 files changed

+129
-48
lines changed

lib/docs/main.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,20 +1430,25 @@ var zigAnalysis;
14301430
return lhs + "!" + rhs;
14311431
}
14321432
case "struct": {
1433-
const struct_name =
1434-
zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1433+
// const struct_name =
1434+
// zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1435+
const struct_name = ".";
14351436
let struct_body = "";
14361437
struct_body += struct_name + "{ ";
14371438
for (let i = 0; i < expr.struct.length; i++) {
1438-
const val = expr.struct[i].name;
1439-
const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
1440-
let value_field = exprArg[Object.keys(exprArg)[0]];
1441-
if (value_field instanceof Object) {
1442-
value_field =
1443-
zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
1444-
.name;
1445-
}
1446-
struct_body += "." + val + " = " + value_field;
1439+
const fv = expr.struct[i];
1440+
const field_name = fv.name;
1441+
const exprArg = zigAnalysis.exprs[fv.val.expr.as.exprArg];
1442+
let field_value = exprName(exprArg, opts);
1443+
// TODO: commented out because it seems not needed. if it deals
1444+
// with a corner case, please add a comment when re-enabling it.
1445+
// let field_value = exprArg[Object.keys(exprArg)[0]];
1446+
// if (field_value instanceof Object) {
1447+
// value_field = exprName(value_field)
1448+
// zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
1449+
// .name;
1450+
// }
1451+
struct_body += "." + field_name + " = " + field_value;
14471452
if (i !== expr.struct.length - 1) {
14481453
struct_body += ", ";
14491454
} else {

src/Autodoc.zig

Lines changed: 113 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
6969
}
7070
}
7171

72+
log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
73+
7274
const root_src_dir = self.module.main_pkg.root_src_directory;
7375
const root_src_path = self.module.main_pkg.root_src_path;
7476
const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
@@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
159161
.void_type => .{
160162
.Void = .{ .name = tmpbuf.toOwnedSlice() },
161163
},
164+
.type_info_type => .{
165+
.Unanalyzed = .{},
166+
},
162167
.type_type => .{
163168
.Type = .{ .name = tmpbuf.toOwnedSlice() },
164169
},
@@ -608,6 +613,7 @@ const DocData = struct {
608613
type: usize, // index in `types`
609614
this: usize, // index in `types`
610615
declRef: usize, // index in `decls`
616+
builtinField: enum { len, ptr },
611617
fieldRef: FieldRef,
612618
refPath: []Expr,
613619
int: struct {
@@ -697,20 +703,26 @@ const DocData = struct {
697703
var jsw = std.json.writeStream(w, 15);
698704
try jsw.beginObject();
699705
try jsw.objectField(@tagName(active_tag));
700-
inline for (comptime std.meta.fields(Expr)) |case| {
701-
if (@field(Expr, case.name) == active_tag) {
702-
switch (active_tag) {
703-
.int => {
704-
if (self.int.negated) try w.writeAll("-");
705-
try jsw.emitNumber(self.int.value);
706-
},
707-
.int_big => {
706+
switch (self) {
707+
.int => {
708+
if (self.int.negated) try w.writeAll("-");
709+
try jsw.emitNumber(self.int.value);
710+
},
711+
.int_big => {
708712

709-
//@panic("TODO: json serialization of big ints!");
710-
//if (v.negated) try w.writeAll("-");
711-
//try jsw.emitNumber(v.value);
712-
},
713-
else => {
713+
//@panic("TODO: json serialization of big ints!");
714+
//if (v.negated) try w.writeAll("-");
715+
//try jsw.emitNumber(v.value);
716+
},
717+
.builtinField => {
718+
try jsw.emitString(@tagName(self.builtinField));
719+
},
720+
else => {
721+
inline for (comptime std.meta.fields(Expr)) |case| {
722+
// TODO: this is super ugly, fix once `inline else` is a thing
723+
if (comptime std.mem.eql(u8, case.name, "builtinField"))
724+
continue;
725+
if (@field(Expr, case.name) == active_tag) {
714726
try std.json.stringify(@field(self, case.name), opt, w);
715727
jsw.state_index -= 1;
716728
// TODO: we should not reach into the state of the
@@ -719,9 +731,9 @@ const DocData = struct {
719731
// would be nice to have a proper integration
720732
// between the json writer and the generic
721733
// std.json.stringify implementation
722-
},
734+
}
723735
}
724-
}
736+
},
725737
}
726738
try jsw.endObject();
727739
}
@@ -1907,31 +1919,38 @@ fn walkInstruction(
19071919
const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
19081920

19091921
var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
1910-
var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1911-
19121922
try path.append(self.arena, .{
19131923
.string = file.zir.nullTerminatedString(extra.data.field_name_start),
19141924
});
1925+
19151926
// Put inside path the starting index of each decl name that
1916-
// we encounter as we navigate through all the field_vals
1917-
while (tags[lhs] == .field_val or
1918-
tags[lhs] == .field_call_bind or
1919-
tags[lhs] == .field_ptr or
1920-
tags[lhs] == .field_type)
1921-
{
1922-
const lhs_extra = file.zir.extraData(
1923-
Zir.Inst.Field,
1924-
data[lhs].pl_node.payload_index,
1925-
);
1927+
// we encounter as we navigate through all the field_*s
1928+
const lhs_ref = blk: {
1929+
var lhs_extra = extra;
1930+
while (true) {
1931+
if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
1932+
break :blk lhs_extra.data.lhs;
1933+
}
19261934

1927-
try path.append(self.arena, .{
1928-
.string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
1929-
});
1930-
lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1931-
}
1935+
const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
1936+
if (tags[lhs] != .field_val and
1937+
tags[lhs] != .field_call_bind and
1938+
tags[lhs] != .field_ptr and
1939+
tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
1940+
1941+
lhs_extra = file.zir.extraData(
1942+
Zir.Inst.Field,
1943+
data[lhs].pl_node.payload_index,
1944+
);
1945+
1946+
try path.append(self.arena, .{
1947+
.string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
1948+
});
1949+
}
1950+
};
19321951

19331952
// TODO: double check that we really don't need type info here
1934-
const wr = try self.walkInstruction(file, parent_scope, lhs, false);
1953+
const wr = try self.walkRef(file, parent_scope, lhs_ref, false);
19351954
try path.append(self.arena, wr.expr);
19361955

19371956
// This way the data in `path` has the same ordering that the ref
@@ -1950,7 +1969,7 @@ fn walkInstruction(
19501969
// - (2) Paths can sometimes never resolve fully. This means that
19511970
// any value that depends on that will have to become a
19521971
// comptimeExpr.
1953-
try self.tryResolveRefPath(file, lhs, path.items);
1972+
try self.tryResolveRefPath(file, inst_index, path.items);
19541973
return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
19551974
},
19561975
.int_type => {
@@ -2055,6 +2074,46 @@ fn walkInstruction(
20552074
);
20562075
return self.cteTodo(@tagName(tags[inst_index]));
20572076
},
2077+
.struct_init_anon => {
2078+
const pl_node = data[inst_index].pl_node;
2079+
const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
2080+
2081+
const field_vals = try self.arena.alloc(
2082+
DocData.Expr.FieldVal,
2083+
extra.data.fields_len,
2084+
);
2085+
2086+
log.debug("number of fields: {}", .{extra.data.fields_len});
2087+
var idx = extra.end;
2088+
for (field_vals) |*fv| {
2089+
const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
2090+
const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
2091+
fv.* = .{
2092+
.name = field_name,
2093+
.val = DocData.WalkResult{
2094+
.expr = .{ .comptimeExpr = 0 },
2095+
},
2096+
};
2097+
// printWithContext(
2098+
// file,
2099+
// inst_index,
2100+
// "analyzing field [{}] %{} `{s}`",
2101+
// .{ i, init_extra.data.init, field_name },
2102+
// );
2103+
// const value = try self.walkRef(
2104+
// file,
2105+
// parent_scope,
2106+
// init_extra.data.init,
2107+
// need_type,
2108+
// );
2109+
// fv.* = .{ .name = field_name, .val = value };
2110+
// idx = init_extra.end;
2111+
}
2112+
2113+
return DocData.WalkResult{
2114+
.expr = .{ .@"struct" = field_vals },
2115+
};
2116+
},
20582117
.error_set_decl => {
20592118
const pl_node = data[inst_index].pl_node;
20602119
const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
@@ -3096,6 +3155,20 @@ fn tryResolveRefPath(
30963155

30973156
return;
30983157
},
3158+
.Array => {
3159+
if (std.mem.eql(u8, child_string, "len")) {
3160+
path[i + 1] = .{
3161+
.builtinField = .len,
3162+
};
3163+
} else {
3164+
panicWithContext(
3165+
file,
3166+
inst_index,
3167+
"TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
3168+
.{ child_string, resolved_parent },
3169+
);
3170+
}
3171+
},
30993172
.Enum => |t_enum| {
31003173
for (t_enum.pubDecls) |d| {
31013174
// TODO: this could be improved a lot
@@ -3822,9 +3895,12 @@ fn walkRef(
38223895
} else if (enum_value < Ref.typed_value_map.len) {
38233896
switch (ref) {
38243897
else => {
3825-
std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
3826-
@tagName(ref),
3827-
});
3898+
panicWithContext(
3899+
file,
3900+
0,
3901+
"TODO: handle {s} in walkRef",
3902+
.{@tagName(ref)},
3903+
);
38283904
},
38293905
.undef => {
38303906
return DocData.WalkResult{ .expr = .@"undefined" };

0 commit comments

Comments
 (0)