Skip to content

Commit c8d04fe

Browse files
authored
Merge pull request #12598 from ziglang/autodoc-anonstruct-wip
Autodoc: anon_init_struct support
2 parents 583175d + b32e5a1 commit c8d04fe

File tree

2 files changed

+141
-48
lines changed

2 files changed

+141
-48
lines changed

lib/docs/main.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,20 +1430,24 @@ 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 field_value = exprName(fv.val.expr, opts);
1442+
// TODO: commented out because it seems not needed. if it deals
1443+
// with a corner case, please add a comment when re-enabling it.
1444+
// let field_value = exprArg[Object.keys(exprArg)[0]];
1445+
// if (field_value instanceof Object) {
1446+
// value_field = exprName(value_field)
1447+
// zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
1448+
// .name;
1449+
// }
1450+
struct_body += "." + field_name + " = " + field_value;
14471451
if (i !== expr.struct.length - 1) {
14481452
struct_body += ", ";
14491453
} else {

src/Autodoc.zig

Lines changed: 126 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+
.ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
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
}
@@ -1905,31 +1917,60 @@ fn walkInstruction(
19051917
const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
19061918

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

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

1950+
// If the lhs is a `call` instruction, it means that we're inside
1951+
// a function call and we're referring to one of its arguments.
1952+
// We can't just blindly analyze the instruction or we will
1953+
// start recursing forever.
1954+
// TODO: add proper resolution of the container type for `calls`
1955+
// TODO: we're like testing lhs as an instruction twice
1956+
// (above and below) this todo, maybe a cleaer solution woul
1957+
// avoid that.
19311958
// TODO: double check that we really don't need type info here
1932-
const wr = try self.walkInstruction(file, parent_scope, lhs, false);
1959+
1960+
const wr = blk: {
1961+
if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {
1962+
const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len;
1963+
if (tags[lhs_inst] == .call) {
1964+
break :blk DocData.WalkResult{
1965+
.expr = .{
1966+
.comptimeExpr = 0,
1967+
},
1968+
};
1969+
}
1970+
}
1971+
1972+
break :blk try self.walkRef(file, parent_scope, lhs_ref, false);
1973+
};
19331974
try path.append(self.arena, wr.expr);
19341975

19351976
// This way the data in `path` has the same ordering that the ref
@@ -1948,7 +1989,7 @@ fn walkInstruction(
19481989
// - (2) Paths can sometimes never resolve fully. This means that
19491990
// any value that depends on that will have to become a
19501991
// comptimeExpr.
1951-
try self.tryResolveRefPath(file, lhs, path.items);
1992+
try self.tryResolveRefPath(file, inst_index, path.items);
19521993
return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
19531994
},
19541995
.int_type => {
@@ -2053,6 +2094,33 @@ fn walkInstruction(
20532094
);
20542095
return self.cteTodo(@tagName(tags[inst_index]));
20552096
},
2097+
.struct_init_anon => {
2098+
const pl_node = data[inst_index].pl_node;
2099+
const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
2100+
2101+
const field_vals = try self.arena.alloc(
2102+
DocData.Expr.FieldVal,
2103+
extra.data.fields_len,
2104+
);
2105+
2106+
var idx = extra.end;
2107+
for (field_vals) |*fv| {
2108+
const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
2109+
const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
2110+
const value = try self.walkRef(
2111+
file,
2112+
parent_scope,
2113+
init_extra.data.init,
2114+
need_type,
2115+
);
2116+
fv.* = .{ .name = field_name, .val = value };
2117+
idx = init_extra.end;
2118+
}
2119+
2120+
return DocData.WalkResult{
2121+
.expr = .{ .@"struct" = field_vals },
2122+
};
2123+
},
20562124
.error_set_decl => {
20572125
const pl_node = data[inst_index].pl_node;
20582126
const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
@@ -3072,6 +3140,10 @@ fn tryResolveRefPath(
30723140
.{ @tagName(self.types.items[t_index]), resolved_parent },
30733141
);
30743142
},
3143+
.ComptimeExpr => {
3144+
// Same as the comptimeExpr branch above
3145+
break :outer;
3146+
},
30753147
.Unanalyzed => {
30763148
// This decl path is pending completion
30773149
{
@@ -3094,6 +3166,20 @@ fn tryResolveRefPath(
30943166

30953167
return;
30963168
},
3169+
.Array => {
3170+
if (std.mem.eql(u8, child_string, "len")) {
3171+
path[i + 1] = .{
3172+
.builtinField = .len,
3173+
};
3174+
} else {
3175+
panicWithContext(
3176+
file,
3177+
inst_index,
3178+
"TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
3179+
.{ child_string, resolved_parent },
3180+
);
3181+
}
3182+
},
30973183
.Enum => |t_enum| {
30983184
for (t_enum.pubDecls) |d| {
30993185
// TODO: this could be improved a lot
@@ -3820,9 +3906,12 @@ fn walkRef(
38203906
} else if (enum_value < Ref.typed_value_map.len) {
38213907
switch (ref) {
38223908
else => {
3823-
std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
3824-
@tagName(ref),
3825-
});
3909+
panicWithContext(
3910+
file,
3911+
0,
3912+
"TODO: handle {s} in walkRef",
3913+
.{@tagName(ref)},
3914+
);
38263915
},
38273916
.undef => {
38283917
return DocData.WalkResult{ .expr = .@"undefined" };

0 commit comments

Comments
 (0)