autodoc: initial support for struct_init_anon
This commit is contained in:
@@ -1430,20 +1430,25 @@ var zigAnalysis;
|
||||
return lhs + "!" + rhs;
|
||||
}
|
||||
case "struct": {
|
||||
const struct_name =
|
||||
zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
|
||||
// const struct_name =
|
||||
// zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
|
||||
const struct_name = ".";
|
||||
let struct_body = "";
|
||||
struct_body += struct_name + "{ ";
|
||||
for (let i = 0; i < expr.struct.length; i++) {
|
||||
const val = expr.struct[i].name;
|
||||
const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
|
||||
let value_field = exprArg[Object.keys(exprArg)[0]];
|
||||
if (value_field instanceof Object) {
|
||||
value_field =
|
||||
zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
|
||||
.name;
|
||||
}
|
||||
struct_body += "." + val + " = " + value_field;
|
||||
const fv = expr.struct[i];
|
||||
const field_name = fv.name;
|
||||
const exprArg = zigAnalysis.exprs[fv.val.expr.as.exprArg];
|
||||
let field_value = exprName(exprArg, opts);
|
||||
// TODO: commented out because it seems not needed. if it deals
|
||||
// with a corner case, please add a comment when re-enabling it.
|
||||
// let field_value = exprArg[Object.keys(exprArg)[0]];
|
||||
// if (field_value instanceof Object) {
|
||||
// value_field = exprName(value_field)
|
||||
// zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
|
||||
// .name;
|
||||
// }
|
||||
struct_body += "." + field_name + " = " + field_value;
|
||||
if (i !== expr.struct.length - 1) {
|
||||
struct_body += ", ";
|
||||
} else {
|
||||
|
||||
152
src/Autodoc.zig
152
src/Autodoc.zig
@@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
|
||||
|
||||
const root_src_dir = self.module.main_pkg.root_src_directory;
|
||||
const root_src_path = self.module.main_pkg.root_src_path;
|
||||
const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
|
||||
@@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
|
||||
.void_type => .{
|
||||
.Void = .{ .name = tmpbuf.toOwnedSlice() },
|
||||
},
|
||||
.type_info_type => .{
|
||||
.Unanalyzed = .{},
|
||||
},
|
||||
.type_type => .{
|
||||
.Type = .{ .name = tmpbuf.toOwnedSlice() },
|
||||
},
|
||||
@@ -608,6 +613,7 @@ const DocData = struct {
|
||||
type: usize, // index in `types`
|
||||
this: usize, // index in `types`
|
||||
declRef: usize, // index in `decls`
|
||||
builtinField: enum { len, ptr },
|
||||
fieldRef: FieldRef,
|
||||
refPath: []Expr,
|
||||
int: struct {
|
||||
@@ -697,20 +703,26 @@ const DocData = struct {
|
||||
var jsw = std.json.writeStream(w, 15);
|
||||
try jsw.beginObject();
|
||||
try jsw.objectField(@tagName(active_tag));
|
||||
inline for (comptime std.meta.fields(Expr)) |case| {
|
||||
if (@field(Expr, case.name) == active_tag) {
|
||||
switch (active_tag) {
|
||||
.int => {
|
||||
if (self.int.negated) try w.writeAll("-");
|
||||
try jsw.emitNumber(self.int.value);
|
||||
},
|
||||
.int_big => {
|
||||
switch (self) {
|
||||
.int => {
|
||||
if (self.int.negated) try w.writeAll("-");
|
||||
try jsw.emitNumber(self.int.value);
|
||||
},
|
||||
.int_big => {
|
||||
|
||||
//@panic("TODO: json serialization of big ints!");
|
||||
//if (v.negated) try w.writeAll("-");
|
||||
//try jsw.emitNumber(v.value);
|
||||
},
|
||||
else => {
|
||||
//@panic("TODO: json serialization of big ints!");
|
||||
//if (v.negated) try w.writeAll("-");
|
||||
//try jsw.emitNumber(v.value);
|
||||
},
|
||||
.builtinField => {
|
||||
try jsw.emitString(@tagName(self.builtinField));
|
||||
},
|
||||
else => {
|
||||
inline for (comptime std.meta.fields(Expr)) |case| {
|
||||
// TODO: this is super ugly, fix once `inline else` is a thing
|
||||
if (comptime std.mem.eql(u8, case.name, "builtinField"))
|
||||
continue;
|
||||
if (@field(Expr, case.name) == active_tag) {
|
||||
try std.json.stringify(@field(self, case.name), opt, w);
|
||||
jsw.state_index -= 1;
|
||||
// TODO: we should not reach into the state of the
|
||||
@@ -719,9 +731,9 @@ const DocData = struct {
|
||||
// would be nice to have a proper integration
|
||||
// between the json writer and the generic
|
||||
// std.json.stringify implementation
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
try jsw.endObject();
|
||||
}
|
||||
@@ -1905,31 +1917,38 @@ fn walkInstruction(
|
||||
const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
|
||||
|
||||
var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
|
||||
var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
|
||||
|
||||
try path.append(self.arena, .{
|
||||
.string = file.zir.nullTerminatedString(extra.data.field_name_start),
|
||||
});
|
||||
// Put inside path the starting index of each decl name that
|
||||
// we encounter as we navigate through all the field_vals
|
||||
while (tags[lhs] == .field_val or
|
||||
tags[lhs] == .field_call_bind or
|
||||
tags[lhs] == .field_ptr or
|
||||
tags[lhs] == .field_type)
|
||||
{
|
||||
const lhs_extra = file.zir.extraData(
|
||||
Zir.Inst.Field,
|
||||
data[lhs].pl_node.payload_index,
|
||||
);
|
||||
|
||||
try path.append(self.arena, .{
|
||||
.string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
|
||||
});
|
||||
lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
|
||||
}
|
||||
// Put inside path the starting index of each decl name that
|
||||
// we encounter as we navigate through all the field_*s
|
||||
const lhs_ref = blk: {
|
||||
var lhs_extra = extra;
|
||||
while (true) {
|
||||
if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
|
||||
break :blk lhs_extra.data.lhs;
|
||||
}
|
||||
|
||||
const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
|
||||
if (tags[lhs] != .field_val and
|
||||
tags[lhs] != .field_call_bind and
|
||||
tags[lhs] != .field_ptr and
|
||||
tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
|
||||
|
||||
lhs_extra = file.zir.extraData(
|
||||
Zir.Inst.Field,
|
||||
data[lhs].pl_node.payload_index,
|
||||
);
|
||||
|
||||
try path.append(self.arena, .{
|
||||
.string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: double check that we really don't need type info here
|
||||
const wr = try self.walkInstruction(file, parent_scope, lhs, false);
|
||||
const wr = try self.walkRef(file, parent_scope, lhs_ref, false);
|
||||
try path.append(self.arena, wr.expr);
|
||||
|
||||
// This way the data in `path` has the same ordering that the ref
|
||||
@@ -1948,7 +1967,7 @@ fn walkInstruction(
|
||||
// - (2) Paths can sometimes never resolve fully. This means that
|
||||
// any value that depends on that will have to become a
|
||||
// comptimeExpr.
|
||||
try self.tryResolveRefPath(file, lhs, path.items);
|
||||
try self.tryResolveRefPath(file, inst_index, path.items);
|
||||
return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
|
||||
},
|
||||
.int_type => {
|
||||
@@ -2053,6 +2072,46 @@ fn walkInstruction(
|
||||
);
|
||||
return self.cteTodo(@tagName(tags[inst_index]));
|
||||
},
|
||||
.struct_init_anon => {
|
||||
const pl_node = data[inst_index].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
|
||||
|
||||
const field_vals = try self.arena.alloc(
|
||||
DocData.Expr.FieldVal,
|
||||
extra.data.fields_len,
|
||||
);
|
||||
|
||||
log.debug("number of fields: {}", .{extra.data.fields_len});
|
||||
var idx = extra.end;
|
||||
for (field_vals) |*fv| {
|
||||
const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
|
||||
const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
|
||||
fv.* = .{
|
||||
.name = field_name,
|
||||
.val = DocData.WalkResult{
|
||||
.expr = .{ .comptimeExpr = 0 },
|
||||
},
|
||||
};
|
||||
// printWithContext(
|
||||
// file,
|
||||
// inst_index,
|
||||
// "analyzing field [{}] %{} `{s}`",
|
||||
// .{ i, init_extra.data.init, field_name },
|
||||
// );
|
||||
// const value = try self.walkRef(
|
||||
// file,
|
||||
// parent_scope,
|
||||
// init_extra.data.init,
|
||||
// need_type,
|
||||
// );
|
||||
// fv.* = .{ .name = field_name, .val = value };
|
||||
// idx = init_extra.end;
|
||||
}
|
||||
|
||||
return DocData.WalkResult{
|
||||
.expr = .{ .@"struct" = field_vals },
|
||||
};
|
||||
},
|
||||
.error_set_decl => {
|
||||
const pl_node = data[inst_index].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
|
||||
@@ -3094,6 +3153,20 @@ fn tryResolveRefPath(
|
||||
|
||||
return;
|
||||
},
|
||||
.Array => {
|
||||
if (std.mem.eql(u8, child_string, "len")) {
|
||||
path[i + 1] = .{
|
||||
.builtinField = .len,
|
||||
};
|
||||
} else {
|
||||
panicWithContext(
|
||||
file,
|
||||
inst_index,
|
||||
"TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
|
||||
.{ child_string, resolved_parent },
|
||||
);
|
||||
}
|
||||
},
|
||||
.Enum => |t_enum| {
|
||||
for (t_enum.pubDecls) |d| {
|
||||
// TODO: this could be improved a lot
|
||||
@@ -3820,9 +3893,12 @@ fn walkRef(
|
||||
} else if (enum_value < Ref.typed_value_map.len) {
|
||||
switch (ref) {
|
||||
else => {
|
||||
std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
|
||||
@tagName(ref),
|
||||
});
|
||||
panicWithContext(
|
||||
file,
|
||||
0,
|
||||
"TODO: handle {s} in walkRef",
|
||||
.{@tagName(ref)},
|
||||
);
|
||||
},
|
||||
.undef => {
|
||||
return DocData.WalkResult{ .expr = .@"undefined" };
|
||||
|
||||
Reference in New Issue
Block a user