authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-21 18:53:00+02:00
committergravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-23 18:37:29+02:00
log0482e8ba9d63ea009a9e0c2d497371261764d3e1
tree3e92ac8a2a2da11a0bc301510bdefb87d5dd9723
parent583175dc1d8d14bc92838476eb226f0e91077abc

autodoc: initial support for struct_init_anon


2 files changed, 129 insertions(+), 48 deletions(-)

lib/docs/main.js+16-11
......@@ -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+113-37
......@@ -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 }
......@@ -1905,31 +1917,38 @@ 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
19311950 // TODO: double check that we really don't need type info here
1932 const wr = try self.walkInstruction(file, parent_scope, lhs, false);
1951 const wr = try self.walkRef(file, parent_scope, lhs_ref, false);
19331952 try path.append(self.arena, wr.expr);
19341953
19351954 // This way the data in `path` has the same ordering that the ref
......@@ -1948,7 +1967,7 @@ fn walkInstruction(
19481967 // - (2) Paths can sometimes never resolve fully. This means that
19491968 // any value that depends on that will have to become a
19501969 // comptimeExpr.
1951 try self.tryResolveRefPath(file, lhs, path.items);
1970 try self.tryResolveRefPath(file, inst_index, path.items);
19521971 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
19531972 },
19541973 .int_type => {
......@@ -2053,6 +2072,46 @@ fn walkInstruction(
20532072 );
20542073 return self.cteTodo(@tagName(tags[inst_index]));
20552074 },
2075 .struct_init_anon => {
2076 const pl_node = data[inst_index].pl_node;
2077 const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
2078
2079 const field_vals = try self.arena.alloc(
2080 DocData.Expr.FieldVal,
2081 extra.data.fields_len,
2082 );
2083
2084 log.debug("number of fields: {}", .{extra.data.fields_len});
2085 var idx = extra.end;
2086 for (field_vals) |*fv| {
2087 const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
2088 const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
2089 fv.* = .{
2090 .name = field_name,
2091 .val = DocData.WalkResult{
2092 .expr = .{ .comptimeExpr = 0 },
2093 },
2094 };
2095 // printWithContext(
2096 // file,
2097 // inst_index,
2098 // "analyzing field [{}] %{} `{s}`",
2099 // .{ i, init_extra.data.init, field_name },
2100 // );
2101 // const value = try self.walkRef(
2102 // file,
2103 // parent_scope,
2104 // init_extra.data.init,
2105 // need_type,
2106 // );
2107 // fv.* = .{ .name = field_name, .val = value };
2108 // idx = init_extra.end;
2109 }
2110
2111 return DocData.WalkResult{
2112 .expr = .{ .@"struct" = field_vals },
2113 };
2114 },
20562115 .error_set_decl => {
20572116 const pl_node = data[inst_index].pl_node;
20582117 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
......@@ -3094,6 +3153,20 @@ fn tryResolveRefPath(
30943153
30953154 return;
30963155 },
3156 .Array => {
3157 if (std.mem.eql(u8, child_string, "len")) {
3158 path[i + 1] = .{
3159 .builtinField = .len,
3160 };
3161 } else {
3162 panicWithContext(
3163 file,
3164 inst_index,
3165 "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
3166 .{ child_string, resolved_parent },
3167 );
3168 }
3169 },
30973170 .Enum => |t_enum| {
30983171 for (t_enum.pubDecls) |d| {
30993172 // TODO: this could be improved a lot
......@@ -3820,9 +3893,12 @@ fn walkRef(
38203893 } else if (enum_value < Ref.typed_value_map.len) {
38213894 switch (ref) {
38223895 else => {
3823 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
3824 @tagName(ref),
3825 });
3896 panicWithContext(
3897 file,
3898 0,
3899 "TODO: handle {s} in walkRef",
3900 .{@tagName(ref)},
3901 );
38263902 },
38273903 .undef => {
38283904 return DocData.WalkResult{ .expr = .@"undefined" };