authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-22 18:07:10+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
logdf3074aa985da82a01f94ba6b9a43535c7d438a9
tree8dd108022b69fe083ed58822f339572b1abf4be5
parent5f0ab34cc5b5d4d59bf4665964b36ae8c218df76

autodoc: fix offset math for decls and change TODOs from panics to just

prints

1 files changed, 248 insertions(+), 90 deletions(-)

src/Autodoc.zig+248-90
......@@ -411,17 +411,17 @@ const DocData = struct {
411411 },
412412 Enum: struct {
413413 name: []const u8,
414 src: ?usize = null, // index into astNodes
415 privDecls: ?[]usize = null, // index into decls
416 pubDecls: ?[]usize = null, // index into decls
414 src: usize, // index into astNodes
415 privDecls: []usize = &.{}, // index into decls
416 pubDecls: []usize = &.{}, // index into decls
417417 // (use src->fields to find field names)
418418 },
419419 Union: struct {
420420 name: []const u8,
421 src: ?usize = null, // index into astNodes
422 privDecls: ?[]usize = null, // index into decls
423 pubDecls: ?[]usize = null, // index into decls
424 fields: ?[]WalkResult = null, // (use src->fields to find names)
421 src: usize, // index into astNodes
422 privDecls: []usize = &.{}, // index into decls
423 pubDecls: []usize = &.{}, // index into decls
424 fields: []WalkResult = &.{}, // (use src->fields to find names)
425425 },
426426 Fn: struct {
427427 name: []const u8,
......@@ -465,6 +465,7 @@ const DocData = struct {
465465 .Struct => |v| try printTypeBody(v, options, w),
466466 .Fn => |v| try printTypeBody(v, options, w),
467467 .Union => |v| try printTypeBody(v, options, w),
468 .ErrorSet => |v| try printTypeBody(v, options, w),
468469 .Enum => |v| try printTypeBody(v, options, w),
469470 .Int => |v| try printTypeBody(v, options, w),
470471 .Float => |v| try printTypeBody(v, options, w),
......@@ -604,8 +605,12 @@ const DocData = struct {
604605 , .{});
605606 try v.typeRef.jsonStringify(options, w);
606607 try w.print(
607 \\, "value": {s}{} }} }}
608 , .{ neg, v.value });
608 \\, "value": {s}1 }} }}
609 , .{neg});
610 // TODO: uncomment once float panic is fixed in stdlib
611 // try w.print(
612 // \\, "value": {s}{e} }} }}
613 // , .{ neg, v.value });
609614 },
610615 .bool => |v| {
611616 try w.print(
......@@ -685,12 +690,13 @@ fn walkInstruction(
685690
686691 switch (tags[inst_index]) {
687692 else => {
688 panicWithContext(
693 printWithContext(
689694 file,
690695 inst_index,
691696 "TODO: implement `{s}` for walkInstruction\n\n",
692697 .{@tagName(tags[inst_index])},
693698 );
699 return self.cteTodo(@tagName(tags[inst_index]));
694700 },
695701 .closure_get => {
696702 const inst_node = data[inst_index].inst_node;
......@@ -752,17 +758,11 @@ fn walkInstruction(
752758
753759 return DocData.WalkResult{ .compileError = operand.string };
754760 },
755 .switch_block => return self.cteTodo("[switch]"),
756761 .enum_literal => {
757762 const str_tok = data[inst_index].str_tok;
758763 const literal = file.zir.nullTerminatedString(str_tok.start);
759764 return DocData.WalkResult{ .enumLiteral = literal };
760765 },
761 .div_exact, .div => return self.cteTodo("@div(...)"),
762 .mul => return self.cteTodo("@mul(...)"),
763 .array_mul => return self.cteTodo("a ** b"),
764 .bool_br_and, .bool_br_or => return self.cteTodo("bool op"),
765 .cmp_eq => return self.cteTodo("bool op"),
766766 .int => {
767767 const int = data[inst_index].int;
768768 const t = try self.arena.create(DocData.WalkResult);
......@@ -849,7 +849,7 @@ fn walkInstruction(
849849 .negated = false,
850850 },
851851 },
852 .child = typeOfWalkResult(array_data[0]),
852 .child = try self.typeOfWalkResult(array_data[0]),
853853 },
854854 });
855855
......@@ -880,7 +880,17 @@ fn walkInstruction(
880880 parent_scope,
881881 un_node.operand,
882882 );
883 operand.int.negated = true; // only support ints for now
883 switch (operand) {
884 .int => |*int| int.negated = true,
885 else => {
886 printWithContext(
887 file,
888 inst_index,
889 "TODO: support negation for more types",
890 .{},
891 );
892 },
893 }
884894 return operand;
885895 },
886896 .size_of => {
......@@ -913,21 +923,19 @@ fn walkInstruction(
913923 var operand = try self.walkRef(file, parent_scope, extra.data.operand);
914924
915925 switch (operand) {
916 else => panicWithContext(
926 else => printWithContext(
917927 file,
918928 inst_index,
919 "TODO: handle {s} in `walkInstruction.as_node`\n",
929 "TODO: handle {s} in `walkInstruction.as_node`",
920930 .{@tagName(operand)},
921931 ),
922 .refPath, .type, .string, .call, .enumLiteral => {},
932 .declRef, .refPath, .type, .string, .call, .enumLiteral => {},
923933 // we don't do anything because up until now,
924934 // I've only seen this used as such:
925935 // @as(@as(type, Baz), .{})
926936 // and we don't want to toss away the
927937 // decl_val information (eg by replacing it with
928938 // a WalkResult.type).
929 // TODO: Actually, this is a good moment to check if
930 // the result is indeed a type!!
931939 .comptimeExpr => {
932940 self.comptime_exprs.items[operand.comptimeExpr].typeRef = dest_type_ref;
933941 },
......@@ -1043,7 +1051,7 @@ fn walkInstruction(
10431051 var idx = extra.end;
10441052 for (field_vals) |*fv| {
10451053 const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx);
1046 idx = init_extra.end;
1054 defer idx = init_extra.end;
10471055
10481056 const field_name = blk: {
10491057 const field_inst_index = init_extra.data.field_type;
......@@ -1176,53 +1184,45 @@ fn walkInstruction(
11761184 );
11771185 },
11781186 .extended => {
1179 // NOTE: this code + the subsequent defer block are working towards
1180 // solving pending decl paths that depend on completing the analysis of a type.
1181 // When we don't find a type, the defer will run anyway but shouldn't
1182 // ever be able to find a match inside `decl_paths_pending_on_types`
1183 // TODO: extract this logic into a function and only call it when appropriate.
1184 const type_slot_index = self.types.items.len;
1185 try self.types.append(self.arena, .{ .Unanalyzed = {} });
1186
1187 defer {
1188 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
1189 for (paths.items) |resume_info| {
1190 self.tryResolveRefPath(
1191 resume_info.file,
1192 inst_index,
1193 resume_info.ref_path,
1194 ) catch {
1195 @panic("Out of memory");
1196 };
1197 }
1198
1199 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
1200 // TODO: we should deallocate the arraylist that holds all the
1201 // decl paths. not doing it now since it's arena-allocated
1202 // anyway, but maybe we should put it elsewhere.
1203 }
1204 }
1205
12061187 const extended = data[inst_index].extended;
12071188 switch (extended.opcode) {
12081189 else => {
1209 panicWithContext(
1190 printWithContext(
12101191 file,
12111192 inst_index,
1212 "TODO: implement `walkInstruction.extended` for {s}\n\n",
1193 "TODO: implement `walkInstruction.extended` for {s}",
12131194 .{@tagName(extended.opcode)},
12141195 );
1196 return self.cteTodo(@tagName(extended.opcode));
12151197 },
12161198
12171199 .opaque_decl => return self.cteTodo("opaque {...}"),
12181200 .func => {
1219 return try self.analyzeFunction(
1201 const type_slot_index = self.types.items.len;
1202 try self.types.append(self.arena, .{ .Unanalyzed = {} });
1203
1204 const result = try self.analyzeFunction(
12201205 file,
12211206 parent_scope,
12221207 inst_index,
12231208 self_ast_node_index,
12241209 type_slot_index,
12251210 );
1211 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
1212 for (paths.items) |resume_info| {
1213 try self.tryResolveRefPath(
1214 resume_info.file,
1215 inst_index,
1216 resume_info.ref_path,
1217 );
1218 }
1219
1220 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
1221 // TODO: we should deallocate the arraylist that holds all the
1222 // decl paths. not doing it now since it's arena-allocated
1223 // anyway, but maybe we should put it elsewhere.
1224 }
1225 return result;
12261226 },
12271227 .variable => {
12281228 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
......@@ -1237,6 +1237,9 @@ fn walkInstruction(
12371237 return value;
12381238 },
12391239 .union_decl => {
1240 const type_slot_index = self.types.items.len;
1241 try self.types.append(self.arena, .{ .Unanalyzed = {} });
1242
12401243 var scope: Scope = .{
12411244 .parent = parent_scope,
12421245 .enclosing_type = type_slot_index,
......@@ -1340,9 +1343,27 @@ fn walkInstruction(
13401343 },
13411344 };
13421345
1346 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
1347 for (paths.items) |resume_info| {
1348 try self.tryResolveRefPath(
1349 resume_info.file,
1350 inst_index,
1351 resume_info.ref_path,
1352 );
1353 }
1354
1355 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
1356 // TODO: we should deallocate the arraylist that holds all the
1357 // decl paths. not doing it now since it's arena-allocated
1358 // anyway, but maybe we should put it elsewhere.
1359 }
1360
13431361 return DocData.WalkResult{ .type = type_slot_index };
13441362 },
13451363 .enum_decl => {
1364 const type_slot_index = self.types.items.len;
1365 try self.types.append(self.arena, .{ .Unanalyzed = {} });
1366
13461367 var scope: Scope = .{
13471368 .parent = parent_scope,
13481369 .enclosing_type = type_slot_index,
......@@ -1470,10 +1491,27 @@ fn walkInstruction(
14701491 .pubDecls = decl_indexes.items,
14711492 },
14721493 };
1494 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
1495 for (paths.items) |resume_info| {
1496 try self.tryResolveRefPath(
1497 resume_info.file,
1498 inst_index,
1499 resume_info.ref_path,
1500 );
1501 }
1502
1503 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
1504 // TODO: we should deallocate the arraylist that holds all the
1505 // decl paths. not doing it now since it's arena-allocated
1506 // anyway, but maybe we should put it elsewhere.
1507 }
14731508
14741509 return DocData.WalkResult{ .type = type_slot_index };
14751510 },
14761511 .struct_decl => {
1512 const type_slot_index = self.types.items.len;
1513 try self.types.append(self.arena, .{ .Unanalyzed = {} });
1514
14771515 var scope: Scope = .{
14781516 .parent = parent_scope,
14791517 .enclosing_type = type_slot_index,
......@@ -1563,6 +1601,20 @@ fn walkInstruction(
15631601 .fields = field_type_refs.items,
15641602 },
15651603 };
1604 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
1605 for (paths.items) |resume_info| {
1606 try self.tryResolveRefPath(
1607 resume_info.file,
1608 inst_index,
1609 resume_info.ref_path,
1610 );
1611 }
1612
1613 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
1614 // TODO: we should deallocate the arraylist that holds all the
1615 // decl paths. not doing it now since it's arena-allocated
1616 // anyway, but maybe we should put it elsewhere.
1617 }
15661618
15671619 return DocData.WalkResult{ .type = type_slot_index };
15681620 },
......@@ -1608,9 +1660,9 @@ fn walkDecls(
16081660 cur_bit_bag >>= 1;
16091661 const is_exported = @truncate(u1, cur_bit_bag) != 0;
16101662 cur_bit_bag >>= 1;
1611 // const has_align = @truncate(u1, cur_bit_bag) != 0;
1663 const has_align = @truncate(u1, cur_bit_bag) != 0;
16121664 cur_bit_bag >>= 1;
1613 // const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0;
1665 const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0;
16141666 cur_bit_bag >>= 1;
16151667
16161668 // const sub_index = extra_index;
......@@ -1626,21 +1678,26 @@ fn walkDecls(
16261678 const doc_comment_index = file.zir.extra[extra_index];
16271679 extra_index += 1;
16281680
1629 // const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
1630 // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1631 // extra_index += 1;
1632 // break :inst inst;
1633 // };
1634 // const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1635 // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1636 // extra_index += 1;
1637 // break :inst inst;
1638 // };
1639 // const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1640 // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1641 // extra_index += 1;
1642 // break :inst inst;
1643 // };
1681 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
1682 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1683 extra_index += 1;
1684 break :inst inst;
1685 };
1686 _ = align_inst;
1687
1688 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1689 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1690 extra_index += 1;
1691 break :inst inst;
1692 };
1693 _ = section_inst;
1694
1695 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1696 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1697 extra_index += 1;
1698 break :inst inst;
1699 };
1700 _ = addrspace_inst;
16441701
16451702 // const pub_str = if (is_pub) "pub " else "";
16461703 // const hash_bytes = @bitCast([16]u8, hash_u32s.*);
......@@ -1848,6 +1905,7 @@ fn tryResolveRefPath(
18481905 while (j < 10_000) : (j += 1) {
18491906 switch (resolved_parent) {
18501907 else => break,
1908 .this => |t| resolved_parent = .{ .type = t },
18511909 .declRef => |decl_index| {
18521910 const decl = self.decls.items[decl_index];
18531911 if (decl._analyzed) {
......@@ -1927,12 +1985,14 @@ fn tryResolveRefPath(
19271985 else => {
19281986 // NOTE: indirect references to types / decls should be handled
19291987 // in the switch above this one!
1930 panicWithContext(
1988 printWithContext(
19311989 file,
19321990 inst_index,
19331991 "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
19341992 .{ @tagName(resolved_parent), resolved_parent },
19351993 );
1994 path[i + 1] = try self.cteTodo("match failure");
1995 continue :outer;
19361996 },
19371997 .comptimeExpr, .call => {
19381998 // Since we hit a cte, we leave the remaining strings unresolved
......@@ -1971,15 +2031,106 @@ fn tryResolveRefPath(
19712031
19722032 return;
19732033 },
2034 .Enum => |t_enum| {
2035 for (t_enum.pubDecls) |d| {
2036 // TODO: this could be improved a lot
2037 // by having our own string table!
2038 const decl = self.decls.items[d];
2039 if (std.mem.eql(u8, decl.name, child_string)) {
2040 path[i + 1] = .{ .declRef = d };
2041 continue :outer;
2042 }
2043 }
2044 for (t_enum.privDecls) |d| {
2045 // TODO: this could be improved a lot
2046 // by having our own string table!
2047 const decl = self.decls.items[d];
2048 if (std.mem.eql(u8, decl.name, child_string)) {
2049 path[i + 1] = .{ .declRef = d };
2050 continue :outer;
2051 }
2052 }
2053
2054 for (self.ast_nodes.items[t_enum.src].fields.?) |ast_node, idx| {
2055 const name = self.ast_nodes.items[ast_node].name.?;
2056 if (std.mem.eql(u8, name, child_string)) {
2057 // TODO: should we really create an artificial
2058 // decl for this type? Probably not.
2059
2060 path[i + 1] = .{
2061 .fieldRef = .{
2062 .type = t_index,
2063 .index = idx,
2064 },
2065 };
2066 continue :outer;
2067 }
2068 }
2069
2070 // if we got here, our search failed
2071 printWithContext(
2072 file,
2073 inst_index,
2074 "failed to match `{s}` in enum",
2075 .{child_string},
2076 );
2077
2078 path[i + 1] = try self.cteTodo("match failure");
2079 continue :outer;
2080 },
2081 .Union => |t_union| {
2082 for (t_union.pubDecls) |d| {
2083 // TODO: this could be improved a lot
2084 // by having our own string table!
2085 const decl = self.decls.items[d];
2086 if (std.mem.eql(u8, decl.name, child_string)) {
2087 path[i + 1] = .{ .declRef = d };
2088 continue :outer;
2089 }
2090 }
2091 for (t_union.privDecls) |d| {
2092 // TODO: this could be improved a lot
2093 // by having our own string table!
2094 const decl = self.decls.items[d];
2095 if (std.mem.eql(u8, decl.name, child_string)) {
2096 path[i + 1] = .{ .declRef = d };
2097 continue :outer;
2098 }
2099 }
2100
2101 for (self.ast_nodes.items[t_union.src].fields.?) |ast_node, idx| {
2102 const name = self.ast_nodes.items[ast_node].name.?;
2103 if (std.mem.eql(u8, name, child_string)) {
2104 // TODO: should we really create an artificial
2105 // decl for this type? Probably not.
2106
2107 path[i + 1] = .{
2108 .fieldRef = .{
2109 .type = t_index,
2110 .index = idx,
2111 },
2112 };
2113 continue :outer;
2114 }
2115 }
2116
2117 // if we got here, our search failed
2118 printWithContext(
2119 file,
2120 inst_index,
2121 "failed to match `{s}` in union",
2122 .{child_string},
2123 );
2124 path[i + 1] = try self.cteTodo("match failure");
2125 continue :outer;
2126 },
2127
19742128 .Struct => |t_struct| {
1975 std.debug.print("search: {s}\n", .{child_string});
19762129 for (t_struct.pubDecls) |d| {
19772130 // TODO: this could be improved a lot
19782131 // by having our own string table!
19792132 const decl = self.decls.items[d];
1980 std.debug.print("pub decl `{s}`\n", .{decl.name});
19812133 if (std.mem.eql(u8, decl.name, child_string)) {
1982 std.debug.print("match!\n", .{});
19832134 path[i + 1] = .{ .declRef = d };
19842135 continue :outer;
19852136 }
......@@ -1988,9 +2139,7 @@ fn tryResolveRefPath(
19882139 // TODO: this could be improved a lot
19892140 // by having our own string table!
19902141 const decl = self.decls.items[d];
1991 std.debug.print("priv decl `{s}`\n", .{decl.name});
19922142 if (std.mem.eql(u8, decl.name, child_string)) {
1993 std.debug.print("match!\n", .{});
19942143 path[i + 1] = .{ .declRef = d };
19952144 continue :outer;
19962145 }
......@@ -1998,9 +2147,7 @@ fn tryResolveRefPath(
19982147
19992148 for (self.ast_nodes.items[t_struct.src].fields.?) |ast_node, idx| {
20002149 const name = self.ast_nodes.items[ast_node].name.?;
2001 std.debug.print("field `{s}`\n", .{name});
20022150 if (std.mem.eql(u8, name, child_string)) {
2003 std.debug.print("match!\n", .{});
20042151 // TODO: should we really create an artificial
20052152 // decl for this type? Probably not.
20062153
......@@ -2015,12 +2162,14 @@ fn tryResolveRefPath(
20152162 }
20162163
20172164 // if we got here, our search failed
2018 panicWithContext(
2165 printWithContext(
20192166 file,
20202167 inst_index,
2021 "failed to match `{s}`",
2168 "failed to match `{s}` in struct",
20222169 .{child_string},
20232170 );
2171 path[i + 1] = try self.cteTodo("match failure");
2172 continue :outer;
20242173 },
20252174 },
20262175 }
......@@ -2070,7 +2219,7 @@ fn analyzeFunction(
20702219 "TODO: handle `{s}` in walkInstruction.func\n",
20712220 .{@tagName(tags[param_index])},
20722221 ),
2073 .param_anytype => {
2222 .param_anytype, .param_anytype_comptime => {
20742223 // TODO: where are the doc comments?
20752224 const str_tok = data[param_index].str_tok;
20762225
......@@ -2097,7 +2246,7 @@ fn analyzeFunction(
20972246 const name = file.zir.nullTerminatedString(extra.data.name);
20982247
20992248 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
2100 self.ast_nodes.appendAssumeCapacity(.{
2249 try self.ast_nodes.append(self.arena, .{
21012250 .name = name,
21022251 .docs = doc_comment,
21032252 .@"comptime" = tags[param_index] == .param_comptime,
......@@ -2382,12 +2531,15 @@ fn walkRef(
23822531/// Given a WalkResult, tries to find its type.
23832532/// Used to analyze instructions like `array_init`, which require us to
23842533/// inspect its first element to find out the array type.
2385fn typeOfWalkResult(wr: DocData.WalkResult) DocData.WalkResult {
2534fn typeOfWalkResult(self: *Autodoc, wr: DocData.WalkResult) !DocData.WalkResult {
23862535 return switch (wr) {
2387 else => std.debug.panic(
2388 "TODO: handle `{s}` in typeOfWalkResult\n",
2389 .{@tagName(wr)},
2390 ),
2536 else => {
2537 std.debug.print(
2538 "TODO: handle `{s}` in typeOfWalkResult\n",
2539 .{@tagName(wr)},
2540 );
2541 return self.cteTodo(@tagName(wr));
2542 },
23912543 .type => .{ .type = @enumToInt(DocData.DocTypeKinds.Type) },
23922544 .int => |v| v.typeRef.*,
23932545 .float => |v| v.typeRef.*,
......@@ -2403,9 +2555,15 @@ fn getBlockInlineBreak(zir: Zir, inst_index: usize) Zir.Inst.Ref {
24032555 return data[break_index].@"break".operand;
24042556}
24052557
2406fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn {
2558fn printWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) void {
24072559 std.debug.print("Context [{s}] % {}\n", .{ file.sub_file_path, inst });
2408 std.debug.panic(fmt, args);
2560 std.debug.print(fmt, args);
2561 std.debug.print("\n", .{});
2562}
2563
2564fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn {
2565 printWithContext(file, inst, fmt, args);
2566 unreachable;
24092567}
24102568
24112569fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult {