authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-23 18:50:36+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-23 18:50:36+02:00
logc8d04fea157444f88485bd69b42f58b5c8f12b1e
tree6f979ca279de8d96951c55975978e92c1008e048
parent583175dc1d8d14bc92838476eb226f0e91077abc
parentb32e5a14ce20ae2943576de76d1af4c8bcc9dd72
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12598 from ziglang/autodoc-anonstruct-wip

Autodoc: anon_init_struct support

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

lib/docs/main.js+15-11
...@@ -1430,20 +1430,24 @@ var zigAnalysis;...@@ -1430,20 +1430,24 @@ var zigAnalysis;
1430 return lhs + "!" + rhs;1430 return lhs + "!" + rhs;
1431 }1431 }
1432 case "struct": {1432 case "struct": {
1433 const struct_name =1433 // const struct_name =
1434 zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;1434 // zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1435 const struct_name = ".";
1435 let struct_body = "";1436 let struct_body = "";
1436 struct_body += struct_name + "{ ";1437 struct_body += struct_name + "{ ";
1437 for (let i = 0; i < expr.struct.length; i++) {1438 for (let i = 0; i < expr.struct.length; i++) {
1438 const val = expr.struct[i].name;1439 const fv = expr.struct[i];
1439 const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];1440 const field_name = fv.name;
1440 let value_field = exprArg[Object.keys(exprArg)[0]];1441 const field_value = exprName(fv.val.expr, opts);
1441 if (value_field instanceof Object) {1442 // TODO: commented out because it seems not needed. if it deals
1442 value_field =1443 // with a corner case, please add a comment when re-enabling it.
1443 zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]1444 // let field_value = exprArg[Object.keys(exprArg)[0]];
1444 .name;1445 // if (field_value instanceof Object) {
1445 }1446 // value_field = exprName(value_field)
1446 struct_body += "." + val + " = " + value_field;1447 // zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
1448 // .name;
1449 // }
1450 struct_body += "." + field_name + " = " + field_value;
1447 if (i !== expr.struct.length - 1) {1451 if (i !== expr.struct.length - 1) {
1448 struct_body += ", ";1452 struct_body += ", ";
1449 } else {1453 } else {
src/Autodoc.zig+126-37
...@@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
69 }69 }
70 }70 }
7171
72 log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
73
72 const root_src_dir = self.module.main_pkg.root_src_directory;74 const root_src_dir = self.module.main_pkg.root_src_directory;
73 const root_src_path = self.module.main_pkg.root_src_path;75 const root_src_path = self.module.main_pkg.root_src_path;
74 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});76 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
...@@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
159 .void_type => .{161 .void_type => .{
160 .Void = .{ .name = tmpbuf.toOwnedSlice() },162 .Void = .{ .name = tmpbuf.toOwnedSlice() },
161 },163 },
164 .type_info_type => .{
165 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
166 },
162 .type_type => .{167 .type_type => .{
163 .Type = .{ .name = tmpbuf.toOwnedSlice() },168 .Type = .{ .name = tmpbuf.toOwnedSlice() },
164 },169 },
...@@ -608,6 +613,7 @@ const DocData = struct {...@@ -608,6 +613,7 @@ const DocData = struct {
608 type: usize, // index in `types`613 type: usize, // index in `types`
609 this: usize, // index in `types`614 this: usize, // index in `types`
610 declRef: usize, // index in `decls`615 declRef: usize, // index in `decls`
616 builtinField: enum { len, ptr },
611 fieldRef: FieldRef,617 fieldRef: FieldRef,
612 refPath: []Expr,618 refPath: []Expr,
613 int: struct {619 int: struct {
...@@ -697,20 +703,26 @@ const DocData = struct {...@@ -697,20 +703,26 @@ const DocData = struct {
697 var jsw = std.json.writeStream(w, 15);703 var jsw = std.json.writeStream(w, 15);
698 try jsw.beginObject();704 try jsw.beginObject();
699 try jsw.objectField(@tagName(active_tag));705 try jsw.objectField(@tagName(active_tag));
700 inline for (comptime std.meta.fields(Expr)) |case| {706 switch (self) {
701 if (@field(Expr, case.name) == active_tag) {707 .int => {
702 switch (active_tag) {708 if (self.int.negated) try w.writeAll("-");
703 .int => {709 try jsw.emitNumber(self.int.value);
704 if (self.int.negated) try w.writeAll("-");710 },
705 try jsw.emitNumber(self.int.value);711 .int_big => {
706 },
707 .int_big => {
708712
709 //@panic("TODO: json serialization of big ints!");713 //@panic("TODO: json serialization of big ints!");
710 //if (v.negated) try w.writeAll("-");714 //if (v.negated) try w.writeAll("-");
711 //try jsw.emitNumber(v.value);715 //try jsw.emitNumber(v.value);
712 },716 },
713 else => {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) {
714 try std.json.stringify(@field(self, case.name), opt, w);726 try std.json.stringify(@field(self, case.name), opt, w);
715 jsw.state_index -= 1;727 jsw.state_index -= 1;
716 // TODO: we should not reach into the state of the728 // TODO: we should not reach into the state of the
...@@ -719,9 +731,9 @@ const DocData = struct {...@@ -719,9 +731,9 @@ const DocData = struct {
719 // would be nice to have a proper integration731 // would be nice to have a proper integration
720 // between the json writer and the generic732 // between the json writer and the generic
721 // std.json.stringify implementation733 // std.json.stringify implementation
722 },734 }
723 }735 }
724 }736 },
725 }737 }
726 try jsw.endObject();738 try jsw.endObject();
727 }739 }
...@@ -1905,31 +1917,60 @@ fn walkInstruction(...@@ -1905,31 +1917,60 @@ fn walkInstruction(
1905 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);1917 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
19061918
1907 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};1919 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
1908 var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1909
1910 try path.append(self.arena, .{1920 try path.append(self.arena, .{
1911 .string = file.zir.nullTerminatedString(extra.data.field_name_start),1921 .string = file.zir.nullTerminatedString(extra.data.field_name_start),
1912 });1922 });
1923
1913 // Put inside path the starting index of each decl name that1924 // Put inside path the starting index of each decl name that
1914 // we encounter as we navigate through all the field_vals1925 // we encounter as we navigate through all the field_*s
1915 while (tags[lhs] == .field_val or1926 const lhs_ref = blk: {
1916 tags[lhs] == .field_call_bind or1927 var lhs_extra = extra;
1917 tags[lhs] == .field_ptr or1928 while (true) {
1918 tags[lhs] == .field_type)1929 if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
1919 {1930 break :blk lhs_extra.data.lhs;
1920 const lhs_extra = file.zir.extraData(1931 }
1921 Zir.Inst.Field,
1922 data[lhs].pl_node.payload_index,
1923 );
19241932
1925 try path.append(self.arena, .{1933 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
1926 .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),1934 if (tags[lhs] != .field_val and
1927 });1935 tags[lhs] != .field_call_bind and
1928 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs1936 tags[lhs] != .field_ptr and
1929 }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.
1931 // TODO: double check that we really don't need type info here1958 // 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 };
1933 try path.append(self.arena, wr.expr);1974 try path.append(self.arena, wr.expr);
19341975
1935 // This way the data in `path` has the same ordering that the ref1976 // This way the data in `path` has the same ordering that the ref
...@@ -1948,7 +1989,7 @@ fn walkInstruction(...@@ -1948,7 +1989,7 @@ fn walkInstruction(
1948 // - (2) Paths can sometimes never resolve fully. This means that1989 // - (2) Paths can sometimes never resolve fully. This means that
1949 // any value that depends on that will have to become a1990 // any value that depends on that will have to become a
1950 // comptimeExpr.1991 // comptimeExpr.
1951 try self.tryResolveRefPath(file, lhs, path.items);1992 try self.tryResolveRefPath(file, inst_index, path.items);
1952 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };1993 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
1953 },1994 },
1954 .int_type => {1995 .int_type => {
...@@ -2053,6 +2094,33 @@ fn walkInstruction(...@@ -2053,6 +2094,33 @@ fn walkInstruction(
2053 );2094 );
2054 return self.cteTodo(@tagName(tags[inst_index]));2095 return self.cteTodo(@tagName(tags[inst_index]));
2055 },2096 },
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 },
2056 .error_set_decl => {2124 .error_set_decl => {
2057 const pl_node = data[inst_index].pl_node;2125 const pl_node = data[inst_index].pl_node;
2058 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);2126 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
...@@ -3072,6 +3140,10 @@ fn tryResolveRefPath(...@@ -3072,6 +3140,10 @@ fn tryResolveRefPath(
3072 .{ @tagName(self.types.items[t_index]), resolved_parent },3140 .{ @tagName(self.types.items[t_index]), resolved_parent },
3073 );3141 );
3074 },3142 },
3143 .ComptimeExpr => {
3144 // Same as the comptimeExpr branch above
3145 break :outer;
3146 },
3075 .Unanalyzed => {3147 .Unanalyzed => {
3076 // This decl path is pending completion3148 // This decl path is pending completion
3077 {3149 {
...@@ -3094,6 +3166,20 @@ fn tryResolveRefPath(...@@ -3094,6 +3166,20 @@ fn tryResolveRefPath(
30943166
3095 return;3167 return;
3096 },3168 },
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 },
3097 .Enum => |t_enum| {3183 .Enum => |t_enum| {
3098 for (t_enum.pubDecls) |d| {3184 for (t_enum.pubDecls) |d| {
3099 // TODO: this could be improved a lot3185 // TODO: this could be improved a lot
...@@ -3820,9 +3906,12 @@ fn walkRef(...@@ -3820,9 +3906,12 @@ fn walkRef(
3820 } else if (enum_value < Ref.typed_value_map.len) {3906 } else if (enum_value < Ref.typed_value_map.len) {
3821 switch (ref) {3907 switch (ref) {
3822 else => {3908 else => {
3823 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{3909 panicWithContext(
3824 @tagName(ref),3910 file,
3825 });3911 0,
3912 "TODO: handle {s} in walkRef",
3913 .{@tagName(ref)},
3914 );
3826 },3915 },
3827 .undef => {3916 .undef => {
3828 return DocData.WalkResult{ .expr = .@"undefined" };3917 return DocData.WalkResult{ .expr = .@"undefined" };