authorgravatar for schteven.codes@gmail.comschtvn <schteven.codes@gmail.com> 2025-02-17 22:02:12-08:00
committergravatar for schteven.codes@gmail.comschtvn <schteven.codes@gmail.com> 2025-02-17 22:27:01-08:00
log5a313192e668501f7ab04b2f1d55b92a3cf33a0e
tree1a5c5cfca3c5386b0cde33f0c5e8df8b96700eb1
parentd2e70ef84a912947f6485f6fc480030c2d6a8c8f

Autodoc: Improve documentation for common types declared as type functions, such as ArrayList, StaticStringMap, BoundedArray, and more


2 files changed, 114 insertions(+), 4 deletions(-)

lib/docs/wasm/Decl.zig+71
...@@ -130,6 +130,77 @@ pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {...@@ -130,6 +130,77 @@ pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {
130 const child_node = scope.get_child(name) orelse return null;130 const child_node = scope.get_child(name) orelse return null;
131 return file.node_decls.get(child_node);131 return file.node_decls.get(child_node);
132 },132 },
133 .type_function => {
134 // Find a decl with this function as the parent, with a name matching `name`
135 for (Walk.decls.items, 0..) |*candidate, i| {
136 if (candidate.parent != .none and candidate.parent.get() == decl and std.mem.eql(u8, candidate.extra_info().name, name)) {
137 return @enumFromInt(i);
138 }
139 }
140
141 return null;
142 },
143 else => return null,
144 }
145}
146
147/// If the type function returns another type function, return the index of that type function.
148pub fn get_type_fn_return_type_fn(decl: *const Decl) ?Decl.Index {
149 if (decl.get_type_fn_return_expr()) |return_expr| {
150 const ast = decl.file.get_ast();
151 const node_tags = ast.nodes.items(.tag);
152
153 switch (node_tags[return_expr]) {
154 .call, .call_comma, .call_one, .call_one_comma => {
155 const node_data = ast.nodes.items(.data);
156 const function = node_data[return_expr].lhs;
157 const token = ast.nodes.items(.main_token)[function];
158 const name = ast.tokenSlice(token);
159 if (decl.lookup(name)) |function_decl| {
160 return function_decl;
161 }
162 },
163 else => {},
164 }
165 }
166 return null;
167}
168
169/// Gets the expression after the `return` keyword in a type function declaration.
170pub fn get_type_fn_return_expr(decl: *const Decl) ?Ast.Node.Index {
171 switch (decl.categorize()) {
172 .type_function => {
173 const ast = decl.file.get_ast();
174 const node_tags = ast.nodes.items(.tag);
175 const node_data = ast.nodes.items(.data);
176 const body_node = node_data[decl.ast_node].rhs;
177 if (body_node == 0) return null;
178
179 switch (node_tags[body_node]) {
180 .block, .block_semicolon => {
181 const statements = ast.extra_data[node_data[body_node].lhs..node_data[body_node].rhs];
182 // Look for the return statement
183 for (statements) |stmt| {
184 if (node_tags[stmt] == .@"return") {
185 return node_data[stmt].lhs;
186 }
187 }
188 return null;
189 },
190 .block_two, .block_two_semicolon => {
191 if (node_tags[node_data[body_node].lhs] == .@"return") {
192 return node_data[node_data[body_node].lhs].lhs;
193 }
194 if (node_data[body_node].rhs != 0 and
195 node_tags[node_data[body_node].rhs] == .@"return")
196 {
197 return node_data[node_data[body_node].rhs].lhs;
198 }
199 return null;
200 },
201 else => return null,
202 }
203 },
133 else => return null,204 else => return null,
134 }205 }
135}206}
lib/docs/wasm/main.zig+43-4
...@@ -380,16 +380,48 @@ export fn decl_params(decl_index: Decl.Index) Slice(Ast.Node.Index) {...@@ -380,16 +380,48 @@ export fn decl_params(decl_index: Decl.Index) Slice(Ast.Node.Index) {
380}380}
381381
382fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {382fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
383 const decl = decl_index.get();
384 const ast = decl.file.get_ast();
385
386 switch (decl.categorize()) {
387 .type_function => {
388 const node_tags = ast.nodes.items(.tag);
389
390 // Find the return statement
391 if (decl.get_type_fn_return_expr()) |return_expr| {
392 switch (node_tags[return_expr]) {
393 .call, .call_comma, .call_one, .call_one_comma => {
394 const node_data = ast.nodes.items(.data);
395 const function = node_data[return_expr].lhs;
396 const token = ast.nodes.items(.main_token)[function];
397 const name = ast.tokenSlice(token);
398 if (decl.lookup(name)) |function_decl| {
399 return decl_fields_fallible(function_decl);
400 }
401 },
402 .container_decl, .container_decl_trailing, .container_decl_two, .container_decl_two_trailing, .container_decl_arg, .container_decl_arg_trailing => {
403 return ast_decl_fields_fallible(ast, return_expr);
404 },
405 else => {},
406 }
407 }
408 return &.{};
409 },
410 else => {
411 const value_node = decl.value_node() orelse return &.{};
412 return ast_decl_fields_fallible(ast, value_node);
413 },
414 }
415}
416
417fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {
383 const g = struct {418 const g = struct {
384 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;419 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;
385 };420 };
386 g.result.clearRetainingCapacity();421 g.result.clearRetainingCapacity();
387 const decl = decl_index.get();
388 const ast = decl.file.get_ast();
389 const node_tags = ast.nodes.items(.tag);422 const node_tags = ast.nodes.items(.tag);
390 const value_node = decl.value_node() orelse return &.{};
391 var buf: [2]Ast.Node.Index = undefined;423 var buf: [2]Ast.Node.Index = undefined;
392 const container_decl = ast.fullContainerDecl(&buf, value_node) orelse return &.{};424 const container_decl = ast.fullContainerDecl(&buf, ast_index) orelse return &.{};
393 for (container_decl.ast.members) |member_node| switch (node_tags[member_node]) {425 for (container_decl.ast.members) |member_node| switch (node_tags[member_node]) {
394 .container_field_init,426 .container_field_init,
395 .container_field_align,427 .container_field_align,
...@@ -883,6 +915,13 @@ export fn categorize_decl(decl_index: Decl.Index, resolve_alias_count: usize) Wa...@@ -883,6 +915,13 @@ export fn categorize_decl(decl_index: Decl.Index, resolve_alias_count: usize) Wa
883}915}
884916
885export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {917export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
918 const decl = parent.get();
919
920 // If the type function returns another type function, get the members of that function
921 if (decl.get_type_fn_return_type_fn()) |function_decl| {
922 return namespace_members(function_decl, include_private);
923 }
924
886 return namespace_members(parent, include_private);925 return namespace_members(parent, include_private);
887}926}
888927