mirror of
https://github.com/ziglang/zig.git
synced 2026-01-15 11:55:14 +00:00
autodoc: add support for solving decl paths depending on other
decl paths
This commit is contained in:
parent
8bb529b395
commit
eced8c065d
117
src/Autodoc.zig
117
src/Autodoc.zig
@ -15,6 +15,10 @@ types: std.ArrayListUnmanaged(DocData.Type) = .{},
|
||||
decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
|
||||
ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
|
||||
comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
|
||||
pending_decl_paths: std.AutoHashMapUnmanaged(
|
||||
*usize, // pointer to declpath head (ie `&decl_path[0]`)
|
||||
std.ArrayListUnmanaged(DeclPathResumeInfo),
|
||||
) = .{},
|
||||
decl_paths_pending_on_decls: std.AutoHashMapUnmanaged(
|
||||
usize,
|
||||
std.ArrayListUnmanaged(DeclPathResumeInfo),
|
||||
@ -154,6 +158,10 @@ pub fn generateZirData(self: *Autodoc) !void {
|
||||
@panic("some decl paths were never fully analized (pending on types)");
|
||||
}
|
||||
|
||||
if (self.pending_decl_paths.count() > 0) {
|
||||
@panic("some decl paths were never fully analized");
|
||||
}
|
||||
|
||||
var data = DocData{
|
||||
.files = .{ .data = self.files },
|
||||
.calls = self.calls.items,
|
||||
@ -733,15 +741,49 @@ fn walkInstruction(
|
||||
lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
|
||||
}
|
||||
|
||||
if (tags[lhs] != .decl_val and tags[lhs] != .decl_ref) {
|
||||
std.debug.panic(
|
||||
"TODO: handle `{s}` endings in walkInstruction.field_val",
|
||||
.{@tagName(tags[lhs])},
|
||||
);
|
||||
switch (tags[lhs]) {
|
||||
else => {
|
||||
std.debug.panic(
|
||||
"TODO: handle `{s}` endings in walkInstruction.field_val",
|
||||
.{@tagName(tags[lhs])},
|
||||
);
|
||||
},
|
||||
.import => {
|
||||
const walk_result = try self.walkInstruction(file, parent_scope, lhs);
|
||||
|
||||
// astnode
|
||||
const ast_node_index = idx: {
|
||||
const idx = self.ast_nodes.items.len;
|
||||
try self.ast_nodes.append(self.arena, .{
|
||||
.file = 0,
|
||||
.line = 0,
|
||||
.col = 0,
|
||||
.docs = "",
|
||||
.fields = null, // walkInstruction will fill `fields` if necessary
|
||||
});
|
||||
break :idx idx;
|
||||
};
|
||||
const str_tok = data[inst_index].str_tok;
|
||||
const file_path = str_tok.get(file.zir);
|
||||
|
||||
const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});
|
||||
const decls_slot_index = self.decls.items.len;
|
||||
try self.decls.append(self.arena, .{
|
||||
._analyzed = true,
|
||||
.name = name,
|
||||
.src = ast_node_index,
|
||||
// .typeRef = decl_type_ref,
|
||||
.value = walk_result,
|
||||
.kind = "const", // find where this information can be found
|
||||
});
|
||||
try path.append(self.arena, decls_slot_index);
|
||||
},
|
||||
.decl_val, .decl_ref => {
|
||||
const str_tok = data[lhs].str_tok;
|
||||
const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
|
||||
try path.append(self.arena, decls_slot_index);
|
||||
},
|
||||
}
|
||||
const str_tok = data[lhs].str_tok;
|
||||
const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
|
||||
try path.append(self.arena, decls_slot_index);
|
||||
|
||||
// Righ now, every element of `path` is the first index of a
|
||||
// decl name except for the final element, which instead points to
|
||||
@ -1458,7 +1500,7 @@ fn tryResolveDeclPath(
|
||||
/// File from which the decl path originates.
|
||||
file: *File,
|
||||
path: []usize,
|
||||
) !void {
|
||||
) error{OutOfMemory}!void {
|
||||
var i: usize = path.len;
|
||||
while (i > 1) {
|
||||
i -= 1;
|
||||
@ -1467,12 +1509,19 @@ fn tryResolveDeclPath(
|
||||
|
||||
const parent = self.decls.items[decl_index];
|
||||
if (!parent._analyzed) {
|
||||
// This decl path is pending completion
|
||||
{
|
||||
const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
}
|
||||
|
||||
const res = try self.decl_paths_pending_on_decls.getOrPut(self.arena, decl_index);
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
try res.value_ptr.*.append(self.arena, .{
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1480,10 +1529,37 @@ fn tryResolveDeclPath(
|
||||
switch (parent.value) {
|
||||
else => {
|
||||
std.debug.panic(
|
||||
"TODO: handle `{s}`in walkInstruction.field_val\n",
|
||||
.{@tagName(parent.value)},
|
||||
"TODO: handle `{s}`in walkInstruction.field_val\n \"{s}\":{}",
|
||||
.{ @tagName(parent.value), parent.name, parent.value },
|
||||
);
|
||||
},
|
||||
.declPath => |dp| {
|
||||
if (self.pending_decl_paths.getPtr(&dp[0])) |waiter_list| {
|
||||
try waiter_list.append(self.arena, .{
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
});
|
||||
|
||||
// This decl path is pending completion
|
||||
{
|
||||
const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const final_decl_index = dp[0];
|
||||
// For the purpose of being able to call tryResolveDeclPath again,
|
||||
// we momentarily replace the decl index present in `path[i]`
|
||||
// with the final decl in `dp`.
|
||||
// We then write the original value back as soon as we're done with the
|
||||
// recoursive call. This will work out correctly even if the path
|
||||
// will not get fully resolved.
|
||||
path[i] = final_decl_index;
|
||||
try self.tryResolveDeclPath(file, path);
|
||||
path[i] = decl_index;
|
||||
},
|
||||
.type => |t_index| switch (self.types.items[t_index]) {
|
||||
else => {
|
||||
std.debug.panic(
|
||||
@ -1492,6 +1568,12 @@ fn tryResolveDeclPath(
|
||||
);
|
||||
},
|
||||
.Unanalyzed => {
|
||||
// This decl path is pending completion
|
||||
{
|
||||
const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
}
|
||||
|
||||
const res = try self.decl_paths_pending_on_types.getOrPut(
|
||||
self.arena,
|
||||
t_index,
|
||||
@ -1501,6 +1583,7 @@ fn tryResolveDeclPath(
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
});
|
||||
|
||||
return;
|
||||
},
|
||||
.Struct => |t_struct| {
|
||||
@ -1526,6 +1609,18 @@ fn tryResolveDeclPath(
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (self.pending_decl_paths.get(&path[0])) |waiter_list| {
|
||||
// It's important to de-register oureslves as pending before
|
||||
// attempting to resolve any other decl.
|
||||
_ = self.pending_decl_paths.remove(&path[0]);
|
||||
|
||||
for (waiter_list.items) |resume_info| {
|
||||
try self.tryResolveDeclPath(resume_info.file, resume_info.path);
|
||||
}
|
||||
// TODO: this is where we should free waiter_list, but its in the arena
|
||||
// that said, we might want to store it elsewhere and reclaim memory asap
|
||||
}
|
||||
}
|
||||
|
||||
fn collectUnionFieldInfo(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user