authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-04 20:43:43+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
logeced8c065d8f90e81af5673ba8086078bd22b9d2
tree11ab9c73b901c4ecf7dc53911f4bc4d6af7828d4
parent8bb529b39598f53939f7429257b862b513fb3091

autodoc: add support for solving decl paths depending on other

decl paths

1 files changed, 106 insertions(+), 11 deletions(-)

src/Autodoc.zig+106-11
......@@ -15,6 +15,10 @@ types: std.ArrayListUnmanaged(DocData.Type) = .{},
1515decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
1616ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
1717comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
18pending_decl_paths: std.AutoHashMapUnmanaged(
19 *usize, // pointer to declpath head (ie `&decl_path[0]`)
20 std.ArrayListUnmanaged(DeclPathResumeInfo),
21) = .{},
1822decl_paths_pending_on_decls: std.AutoHashMapUnmanaged(
1923 usize,
2024 std.ArrayListUnmanaged(DeclPathResumeInfo),
......@@ -154,6 +158,10 @@ pub fn generateZirData(self: *Autodoc) !void {
154158 @panic("some decl paths were never fully analized (pending on types)");
155159 }
156160
161 if (self.pending_decl_paths.count() > 0) {
162 @panic("some decl paths were never fully analized");
163 }
164
157165 var data = DocData{
158166 .files = .{ .data = self.files },
159167 .calls = self.calls.items,
......@@ -733,15 +741,49 @@ fn walkInstruction(
733741 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
734742 }
735743
736 if (tags[lhs] != .decl_val and tags[lhs] != .decl_ref) {
737 std.debug.panic(
738 "TODO: handle `{s}` endings in walkInstruction.field_val",
739 .{@tagName(tags[lhs])},
740 );
744 switch (tags[lhs]) {
745 else => {
746 std.debug.panic(
747 "TODO: handle `{s}` endings in walkInstruction.field_val",
748 .{@tagName(tags[lhs])},
749 );
750 },
751 .import => {
752 const walk_result = try self.walkInstruction(file, parent_scope, lhs);
753
754 // astnode
755 const ast_node_index = idx: {
756 const idx = self.ast_nodes.items.len;
757 try self.ast_nodes.append(self.arena, .{
758 .file = 0,
759 .line = 0,
760 .col = 0,
761 .docs = "",
762 .fields = null, // walkInstruction will fill `fields` if necessary
763 });
764 break :idx idx;
765 };
766 const str_tok = data[inst_index].str_tok;
767 const file_path = str_tok.get(file.zir);
768
769 const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});
770 const decls_slot_index = self.decls.items.len;
771 try self.decls.append(self.arena, .{
772 ._analyzed = true,
773 .name = name,
774 .src = ast_node_index,
775 // .typeRef = decl_type_ref,
776 .value = walk_result,
777 .kind = "const", // find where this information can be found
778 });
779 try path.append(self.arena, decls_slot_index);
780 },
781 .decl_val, .decl_ref => {
782 const str_tok = data[lhs].str_tok;
783 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
784 try path.append(self.arena, decls_slot_index);
785 },
741786 }
742 const str_tok = data[lhs].str_tok;
743 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
744 try path.append(self.arena, decls_slot_index);
745787
746788 // Righ now, every element of `path` is the first index of a
747789 // decl name except for the final element, which instead points to
......@@ -1458,7 +1500,7 @@ fn tryResolveDeclPath(
14581500 /// File from which the decl path originates.
14591501 file: *File,
14601502 path: []usize,
1461) !void {
1503) error{OutOfMemory}!void {
14621504 var i: usize = path.len;
14631505 while (i > 1) {
14641506 i -= 1;
......@@ -1467,12 +1509,19 @@ fn tryResolveDeclPath(
14671509
14681510 const parent = self.decls.items[decl_index];
14691511 if (!parent._analyzed) {
1512 // This decl path is pending completion
1513 {
1514 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1515 if (!res.found_existing) res.value_ptr.* = .{};
1516 }
1517
14701518 const res = try self.decl_paths_pending_on_decls.getOrPut(self.arena, decl_index);
14711519 if (!res.found_existing) res.value_ptr.* = .{};
14721520 try res.value_ptr.*.append(self.arena, .{
14731521 .file = file,
14741522 .path = path[0 .. i + 1],
14751523 });
1524
14761525 return;
14771526 }
14781527
......@@ -1480,10 +1529,37 @@ fn tryResolveDeclPath(
14801529 switch (parent.value) {
14811530 else => {
14821531 std.debug.panic(
1483 "TODO: handle `{s}`in walkInstruction.field_val\n",
1484 .{@tagName(parent.value)},
1532 "TODO: handle `{s}`in walkInstruction.field_val\n \"{s}\":{}",
1533 .{ @tagName(parent.value), parent.name, parent.value },
14851534 );
14861535 },
1536 .declPath => |dp| {
1537 if (self.pending_decl_paths.getPtr(&dp[0])) |waiter_list| {
1538 try waiter_list.append(self.arena, .{
1539 .file = file,
1540 .path = path[0 .. i + 1],
1541 });
1542
1543 // This decl path is pending completion
1544 {
1545 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1546 if (!res.found_existing) res.value_ptr.* = .{};
1547 }
1548
1549 return;
1550 }
1551
1552 const final_decl_index = dp[0];
1553 // For the purpose of being able to call tryResolveDeclPath again,
1554 // we momentarily replace the decl index present in `path[i]`
1555 // with the final decl in `dp`.
1556 // We then write the original value back as soon as we're done with the
1557 // recoursive call. This will work out correctly even if the path
1558 // will not get fully resolved.
1559 path[i] = final_decl_index;
1560 try self.tryResolveDeclPath(file, path);
1561 path[i] = decl_index;
1562 },
14871563 .type => |t_index| switch (self.types.items[t_index]) {
14881564 else => {
14891565 std.debug.panic(
......@@ -1492,6 +1568,12 @@ fn tryResolveDeclPath(
14921568 );
14931569 },
14941570 .Unanalyzed => {
1571 // This decl path is pending completion
1572 {
1573 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1574 if (!res.found_existing) res.value_ptr.* = .{};
1575 }
1576
14951577 const res = try self.decl_paths_pending_on_types.getOrPut(
14961578 self.arena,
14971579 t_index,
......@@ -1501,6 +1583,7 @@ fn tryResolveDeclPath(
15011583 .file = file,
15021584 .path = path[0 .. i + 1],
15031585 });
1586
15041587 return;
15051588 },
15061589 .Struct => |t_struct| {
......@@ -1526,6 +1609,18 @@ fn tryResolveDeclPath(
15261609 },
15271610 }
15281611 }
1612
1613 if (self.pending_decl_paths.get(&path[0])) |waiter_list| {
1614 // It's important to de-register oureslves as pending before
1615 // attempting to resolve any other decl.
1616 _ = self.pending_decl_paths.remove(&path[0]);
1617
1618 for (waiter_list.items) |resume_info| {
1619 try self.tryResolveDeclPath(resume_info.file, resume_info.path);
1620 }
1621 // TODO: this is where we should free waiter_list, but its in the arena
1622 // that said, we might want to store it elsewhere and reclaim memory asap
1623 }
15291624}
15301625
15311626fn collectUnionFieldInfo(