| ... | @@ -9,11 +9,24 @@ const Ref = Zir.Inst.Ref; | ... | @@ -9,11 +9,24 @@ const Ref = Zir.Inst.Ref; |
| 9 | module: *Module, | 9 | module: *Module, |
| 10 | doc_location: Compilation.EmitLoc, | 10 | doc_location: Compilation.EmitLoc, |
| 11 | arena: std.mem.Allocator, | 11 | arena: std.mem.Allocator, |
| 12 | files: std.AutoHashMapUnmanaged(*File, DocData.AutodocFile) = .{}, | 12 | files: std.AutoHashMapUnmanaged(*File, usize) = .{}, |
| 13 | types: std.ArrayListUnmanaged(DocData.Type) = .{}, | 13 | types: std.ArrayListUnmanaged(DocData.Type) = .{}, |
| 14 | decls: std.ArrayListUnmanaged(DocData.Decl) = .{}, | 14 | decls: std.ArrayListUnmanaged(DocData.Decl) = .{}, |
| 15 | ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{}, | 15 | ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{}, |
| 16 | comptimeExprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{}, | 16 | comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{}, |
| | 17 | decl_paths_pending_on_decls: std.AutoHashMapUnmanaged( |
| | 18 | usize, |
| | 19 | std.ArrayListUnmanaged(DeclPathResumeInfo), |
| | 20 | ) = .{}, |
| | 21 | decl_paths_pending_on_types: std.AutoHashMapUnmanaged( |
| | 22 | usize, |
| | 23 | std.ArrayListUnmanaged(DeclPathResumeInfo), |
| | 24 | ) = .{}, |
| | 25 | |
| | 26 | const DeclPathResumeInfo = struct { |
| | 27 | file: *File, |
| | 28 | path: []usize, |
| | 29 | }; |
| 17 | | 30 | |
| 18 | var arena_allocator: std.heap.ArenaAllocator = undefined; | 31 | var arena_allocator: std.heap.ArenaAllocator = undefined; |
| 19 | pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc { | 32 | pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc { |
| ... | @@ -129,22 +142,23 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -129,22 +142,23 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 129 | | 142 | |
| 130 | var root_scope = Scope{ .parent = null }; | 143 | var root_scope = Scope{ .parent = null }; |
| 131 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); | 144 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); |
| 132 | try self.files.put(self.arena, file, .{ | 145 | try self.files.put(self.arena, file, self.types.items.len); |
| 133 | .analyzed = false, | | |
| 134 | .root_struct = self.types.items.len, | | |
| 135 | }); | | |
| 136 | const main_type_index = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst); | 146 | const main_type_index = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst); |
| 137 | self.files.getPtr(file).?.analyzed = true; | | |
| 138 | | 147 | |
| 139 | // TODO: solve every single pending declpath whose analysis | 148 | if (self.decl_paths_pending_on_decls.count() > 0) { |
| 140 | // was delayed because of circular imports. | 149 | @panic("some decl paths were never fully analized (pending on decls)"); |
| | 150 | } |
| | 151 | |
| | 152 | if (self.decl_paths_pending_on_types.count() > 0) { |
| | 153 | @panic("some decl paths were never fully analized (pending on types)"); |
| | 154 | } |
| 141 | | 155 | |
| 142 | var data = DocData{ | 156 | var data = DocData{ |
| 143 | .files = .{ .data = self.files }, | 157 | .files = .{ .data = self.files }, |
| 144 | .types = self.types.items, | 158 | .types = self.types.items, |
| 145 | .decls = self.decls.items, | 159 | .decls = self.decls.items, |
| 146 | .astNodes = self.ast_nodes.items, | 160 | .astNodes = self.ast_nodes.items, |
| 147 | .comptimeExprs = self.comptimeExprs.items, | 161 | .comptimeExprs = self.comptime_exprs.items, |
| 148 | }; | 162 | }; |
| 149 | | 163 | |
| 150 | data.packages[0].main = main_type_index.type; | 164 | data.packages[0].main = main_type_index.type; |
| ... | @@ -232,7 +246,7 @@ const DocData = struct { | ... | @@ -232,7 +246,7 @@ const DocData = struct { |
| 232 | astNodes: []AstNode, | 246 | astNodes: []AstNode, |
| 233 | files: struct { | 247 | files: struct { |
| 234 | // this struct is a temporary hack to support json serialization | 248 | // this struct is a temporary hack to support json serialization |
| 235 | data: std.AutoHashMapUnmanaged(*File, AutodocFile), | 249 | data: std.AutoHashMapUnmanaged(*File, usize), |
| 236 | pub fn jsonStringify( | 250 | pub fn jsonStringify( |
| 237 | self: @This(), | 251 | self: @This(), |
| 238 | opt: std.json.StringifyOptions, | 252 | opt: std.json.StringifyOptions, |
| ... | @@ -248,7 +262,7 @@ const DocData = struct { | ... | @@ -248,7 +262,7 @@ const DocData = struct { |
| 248 | if (options.whitespace) |ws| try ws.outputIndent(w); | 262 | if (options.whitespace) |ws| try ws.outputIndent(w); |
| 249 | try w.print("\"{s}\": {d}", .{ | 263 | try w.print("\"{s}\": {d}", .{ |
| 250 | kv.key_ptr.*.sub_file_path, | 264 | kv.key_ptr.*.sub_file_path, |
| 251 | kv.value_ptr.root_struct, | 265 | kv.value_ptr.*, |
| 252 | }); | 266 | }); |
| 253 | if (idx != self.data.count() - 1) try w.writeByte(','); | 267 | if (idx != self.data.count() - 1) try w.writeByte(','); |
| 254 | try w.writeByte('\n'); | 268 | try w.writeByte('\n'); |
| ... | @@ -261,17 +275,17 @@ const DocData = struct { | ... | @@ -261,17 +275,17 @@ const DocData = struct { |
| 261 | decls: []Decl, | 275 | decls: []Decl, |
| 262 | comptimeExprs: []ComptimeExpr, | 276 | comptimeExprs: []ComptimeExpr, |
| 263 | | 277 | |
| 264 | const AutodocFile = struct { | | |
| 265 | analyzed: bool, // omitted in json data | | |
| 266 | root_struct: usize, // index into `types` | | |
| 267 | }; | | |
| 268 | | | |
| 269 | const DocTypeKinds = blk: { | 278 | const DocTypeKinds = blk: { |
| 270 | var info = @typeInfo(std.builtin.TypeId); | 279 | var info = @typeInfo(std.builtin.TypeId); |
| 271 | info.Enum.fields = info.Enum.fields ++ [1]std.builtin.TypeInfo.EnumField{ | 280 | const original_len = info.Enum.fields.len; |
| | 281 | info.Enum.fields = info.Enum.fields ++ [2]std.builtin.TypeInfo.EnumField{ |
| 272 | .{ | 282 | .{ |
| 273 | .name = "ComptimeExpr", | 283 | .name = "ComptimeExpr", |
| 274 | .value = info.Enum.fields.len, | 284 | .value = original_len, |
| | 285 | }, |
| | 286 | .{ |
| | 287 | .name = "Unanalyzed", |
| | 288 | .value = original_len + 1, |
| 275 | }, | 289 | }, |
| 276 | }; | 290 | }; |
| 277 | break :blk @Type(info); | 291 | break :blk @Type(info); |
| ... | @@ -298,6 +312,7 @@ const DocData = struct { | ... | @@ -298,6 +312,7 @@ const DocData = struct { |
| 298 | value: WalkResult, | 312 | value: WalkResult, |
| 299 | // The index in astNodes of the `test declname { }` node | 313 | // The index in astNodes of the `test declname { }` node |
| 300 | decltest: ?usize = null, | 314 | decltest: ?usize = null, |
| | 315 | _analyzed: bool, // omitted in json data |
| 301 | }; | 316 | }; |
| 302 | | 317 | |
| 303 | const AstNode = struct { | 318 | const AstNode = struct { |
| ... | @@ -310,6 +325,7 @@ const DocData = struct { | ... | @@ -310,6 +325,7 @@ const DocData = struct { |
| 310 | }; | 325 | }; |
| 311 | | 326 | |
| 312 | const Type = union(DocTypeKinds) { | 327 | const Type = union(DocTypeKinds) { |
| | 328 | Unanalyzed: void, |
| 313 | Type: struct { name: []const u8 }, | 329 | Type: struct { name: []const u8 }, |
| 314 | Void: struct { name: []const u8 }, | 330 | Void: struct { name: []const u8 }, |
| 315 | Bool: struct { name: []const u8 }, | 331 | Bool: struct { name: []const u8 }, |
| ... | @@ -480,7 +496,7 @@ const DocData = struct { | ... | @@ -480,7 +496,7 @@ const DocData = struct { |
| 480 | @"struct": Struct, | 496 | @"struct": Struct, |
| 481 | bool: bool, | 497 | bool: bool, |
| 482 | type: usize, // index in `types` | 498 | type: usize, // index in `types` |
| 483 | declPath: []usize, // indices in `decls` | 499 | declPath: []usize, // indices in `decl` |
| 484 | int: struct { | 500 | int: struct { |
| 485 | typeRef: TypeRef, | 501 | typeRef: TypeRef, |
| 486 | value: usize, // direct value | 502 | value: usize, // direct value |
| ... | @@ -584,16 +600,12 @@ fn walkInstruction( | ... | @@ -584,16 +600,12 @@ fn walkInstruction( |
| 584 | // importFile cannot error out since all files | 600 | // importFile cannot error out since all files |
| 585 | // are already loaded at this point | 601 | // are already loaded at this point |
| 586 | const new_file = self.module.importFile(file, path) catch unreachable; | 602 | const new_file = self.module.importFile(file, path) catch unreachable; |
| 587 | | | |
| 588 | const result = try self.files.getOrPut(self.arena, new_file.file); | 603 | const result = try self.files.getOrPut(self.arena, new_file.file); |
| 589 | if (result.found_existing) { | 604 | if (result.found_existing) { |
| 590 | return DocData.WalkResult{ .type = result.value_ptr.root_struct }; | 605 | return DocData.WalkResult{ .type = result.value_ptr.* }; |
| 591 | } | 606 | } |
| 592 | | 607 | |
| 593 | result.value_ptr.* = .{ | 608 | result.value_ptr.* = self.types.items.len; |
| 594 | .analyzed = false, | | |
| 595 | .root_struct = self.types.items.len, | | |
| 596 | }; | | |
| 597 | | 609 | |
| 598 | var new_scope = Scope{ .parent = null }; | 610 | var new_scope = Scope{ .parent = null }; |
| 599 | const new_file_walk_result = self.walkInstruction( | 611 | const new_file_walk_result = self.walkInstruction( |
| ... | @@ -601,14 +613,12 @@ fn walkInstruction( | ... | @@ -601,14 +613,12 @@ fn walkInstruction( |
| 601 | &new_scope, | 613 | &new_scope, |
| 602 | Zir.main_struct_inst, | 614 | Zir.main_struct_inst, |
| 603 | ); | 615 | ); |
| 604 | // We re-access the hashmap in case it was modified | 616 | |
| 605 | // by walkInstruction() | | |
| 606 | self.files.getPtr(new_file.file).?.analyzed = true; | | |
| 607 | return new_file_walk_result; | 617 | return new_file_walk_result; |
| 608 | }, | 618 | }, |
| 609 | .block => { | 619 | .block => { |
| 610 | const res = DocData.WalkResult{ .comptimeExpr = self.comptimeExprs.items.len }; | 620 | const res = DocData.WalkResult{ .comptimeExpr = self.comptime_exprs.items.len }; |
| 611 | try self.comptimeExprs.append(self.arena, .{ | 621 | try self.comptime_exprs.append(self.arena, .{ |
| 612 | .code = "if(banana) 1 else 0", | 622 | .code = "if(banana) 1 else 0", |
| 613 | .typeRef = .{ .type = 0 }, | 623 | .typeRef = .{ .type = 0 }, |
| 614 | }); | 624 | }); |
| ... | @@ -669,7 +679,7 @@ fn walkInstruction( | ... | @@ -669,7 +679,7 @@ fn walkInstruction( |
| 669 | // TODO: Actually, this is a good moment to check if | 679 | // TODO: Actually, this is a good moment to check if |
| 670 | // the result is indeed a type!! | 680 | // the result is indeed a type!! |
| 671 | .comptimeExpr => { | 681 | .comptimeExpr => { |
| 672 | self.comptimeExprs.items[operand.comptimeExpr].typeRef = dest_type_ref; | 682 | self.comptime_exprs.items[operand.comptimeExpr].typeRef = dest_type_ref; |
| 673 | }, | 683 | }, |
| 674 | .int => operand.int.typeRef = dest_type_ref, | 684 | .int => operand.int.typeRef = dest_type_ref, |
| 675 | .@"struct" => operand.@"struct".typeRef = dest_type_ref, | 685 | .@"struct" => operand.@"struct".typeRef = dest_type_ref, |
| ... | @@ -731,35 +741,7 @@ fn walkInstruction( | ... | @@ -731,35 +741,7 @@ fn walkInstruction( |
| 731 | // the analyzed data corresponding to the top-most decl of this path. | 741 | // the analyzed data corresponding to the top-most decl of this path. |
| 732 | // We are now going to reverse loop over `path` to resolve each name | 742 | // We are now going to reverse loop over `path` to resolve each name |
| 733 | // to its corresponding index in `decls`. | 743 | // to its corresponding index in `decls`. |
| 734 | | 744 | try self.tryResolveDeclPath(file, path.items); |
| 735 | var i: usize = path.items.len; | | |
| 736 | while (i > 1) { | | |
| 737 | i -= 1; | | |
| 738 | const parent = self.decls.items[path.items[i]]; | | |
| 739 | const child_decl_name = file.zir.nullTerminatedString(path.items[i - 1]); | | |
| 740 | switch (parent.value) { | | |
| 741 | else => { | | |
| 742 | std.debug.print( | | |
| 743 | "TODO: handle `{s}`in walkInstruction.field_val\n", | | |
| 744 | .{@tagName(parent.value)}, | | |
| 745 | ); | | |
| 746 | unreachable; | | |
| 747 | }, | | |
| 748 | .type => |t_index| { | | |
| 749 | const t_struct = self.types.items[t_index].Struct; // todo: support more types | | |
| 750 | for (t_struct.pubDecls) |d| { | | |
| 751 | // TODO: this could be improved a lot | | |
| 752 | // by having our own string table! | | |
| 753 | const decl = self.decls.items[d]; | | |
| 754 | if (std.mem.eql(u8, decl.name, child_decl_name)) { | | |
| 755 | path.items[i - 1] = d; | | |
| 756 | continue; | | |
| 757 | } | | |
| 758 | } | | |
| 759 | }, | | |
| 760 | } | | |
| 761 | } | | |
| 762 | | | |
| 763 | return DocData.WalkResult{ .declPath = path.items }; | 745 | return DocData.WalkResult{ .declPath = path.items }; |
| 764 | }, | 746 | }, |
| 765 | .int_type => { | 747 | .int_type => { |
| ... | @@ -841,6 +823,29 @@ fn walkInstruction( | ... | @@ -841,6 +823,29 @@ fn walkInstruction( |
| 841 | return DocData.WalkResult{ .type = self.types.items.len - 1 }; | 823 | return DocData.WalkResult{ .type = self.types.items.len - 1 }; |
| 842 | }, | 824 | }, |
| 843 | .extended => { | 825 | .extended => { |
| | 826 | // TODO: this assumes that we always return a type when analyzing |
| | 827 | // an extended instruction. Also we willingfully not reserve |
| | 828 | // a slot for functions (handled right above) despite them |
| | 829 | // being stored in `types`. The reason why we reserve a slot |
| | 830 | // in here, is for decl paths and their resolution system. |
| | 831 | const type_slot_index = self.types.items.len; |
| | 832 | try self.types.append(self.arena, .{ .Unanalyzed = {} }); |
| | 833 | |
| | 834 | defer { |
| | 835 | if (self.decl_paths_pending_on_types.get(type_slot_index)) |paths| { |
| | 836 | for (paths.items) |resume_info| { |
| | 837 | self.tryResolveDeclPath(resume_info.file, resume_info.path) catch { |
| | 838 | @panic("Out of memory"); |
| | 839 | }; |
| | 840 | } |
| | 841 | |
| | 842 | _ = self.decl_paths_pending_on_types.remove(type_slot_index); |
| | 843 | // TODO: we should deallocate the arraylist that holds all the |
| | 844 | // decl paths. not doing it now since it's arena-allocated |
| | 845 | // anyway, but maybe we should put it elsewhere. |
| | 846 | } |
| | 847 | } |
| | 848 | |
| 844 | const extended = data[inst_index].extended; | 849 | const extended = data[inst_index].extended; |
| 845 | switch (extended.opcode) { | 850 | switch (extended.opcode) { |
| 846 | else => { | 851 | else => { |
| ... | @@ -898,6 +903,9 @@ fn walkInstruction( | ... | @@ -898,6 +903,9 @@ fn walkInstruction( |
| 898 | { | 903 | { |
| 899 | var it = file.zir.declIterator(@intCast(u32, inst_index)); | 904 | var it = file.zir.declIterator(@intCast(u32, inst_index)); |
| 900 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); | 905 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); |
| | 906 | for (self.decls.items[decls_first_index..]) |*slot| { |
| | 907 | slot._analyzed = false; |
| | 908 | } |
| 901 | var decls_slot_index = decls_first_index; | 909 | var decls_slot_index = decls_first_index; |
| 902 | while (it.next()) |d| : (decls_slot_index += 1) { | 910 | while (it.next()) |d| : (decls_slot_index += 1) { |
| 903 | const decl_name_index = file.zir.extra[d.sub_index + 5]; | 911 | const decl_name_index = file.zir.extra[d.sub_index + 5]; |
| ... | @@ -937,7 +945,7 @@ fn walkInstruction( | ... | @@ -937,7 +945,7 @@ fn walkInstruction( |
| 937 | | 945 | |
| 938 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; | 946 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; |
| 939 | | 947 | |
| 940 | try self.types.append(self.arena, .{ | 948 | self.types.items[type_slot_index] = .{ |
| 941 | .Union = .{ | 949 | .Union = .{ |
| 942 | .name = "todo_name", | 950 | .name = "todo_name", |
| 943 | .src = self_ast_node_index, | 951 | .src = self_ast_node_index, |
| ... | @@ -945,9 +953,9 @@ fn walkInstruction( | ... | @@ -945,9 +953,9 @@ fn walkInstruction( |
| 945 | .pubDecls = decl_indexes.items, | 953 | .pubDecls = decl_indexes.items, |
| 946 | .fields = field_type_refs.items, | 954 | .fields = field_type_refs.items, |
| 947 | }, | 955 | }, |
| 948 | }); | 956 | }; |
| 949 | | 957 | |
| 950 | return DocData.WalkResult{ .type = self.types.items.len - 1 }; | 958 | return DocData.WalkResult{ .type = type_slot_index }; |
| 951 | }, | 959 | }, |
| 952 | .enum_decl => { | 960 | .enum_decl => { |
| 953 | var scope: Scope = .{ .parent = parent_scope }; | 961 | var scope: Scope = .{ .parent = parent_scope }; |
| ... | @@ -998,6 +1006,9 @@ fn walkInstruction( | ... | @@ -998,6 +1006,9 @@ fn walkInstruction( |
| 998 | { | 1006 | { |
| 999 | var it = file.zir.declIterator(@intCast(u32, inst_index)); | 1007 | var it = file.zir.declIterator(@intCast(u32, inst_index)); |
| 1000 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); | 1008 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); |
| | 1009 | for (self.decls.items[decls_first_index..]) |*slot| { |
| | 1010 | slot._analyzed = false; |
| | 1011 | } |
| 1001 | var decls_slot_index = decls_first_index; | 1012 | var decls_slot_index = decls_first_index; |
| 1002 | while (it.next()) |d| : (decls_slot_index += 1) { | 1013 | while (it.next()) |d| : (decls_slot_index += 1) { |
| 1003 | const decl_name_index = file.zir.extra[d.sub_index + 5]; | 1014 | const decl_name_index = file.zir.extra[d.sub_index + 5]; |
| ... | @@ -1063,16 +1074,16 @@ fn walkInstruction( | ... | @@ -1063,16 +1074,16 @@ fn walkInstruction( |
| 1063 | | 1074 | |
| 1064 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; | 1075 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; |
| 1065 | | 1076 | |
| 1066 | try self.types.append(self.arena, .{ | 1077 | self.types.items[type_slot_index] = .{ |
| 1067 | .Enum = .{ | 1078 | .Enum = .{ |
| 1068 | .name = "todo_name", | 1079 | .name = "todo_name", |
| 1069 | .src = self_ast_node_index, | 1080 | .src = self_ast_node_index, |
| 1070 | .privDecls = priv_decl_indexes.items, | 1081 | .privDecls = priv_decl_indexes.items, |
| 1071 | .pubDecls = decl_indexes.items, | 1082 | .pubDecls = decl_indexes.items, |
| 1072 | }, | 1083 | }, |
| 1073 | }); | 1084 | }; |
| 1074 | | 1085 | |
| 1075 | return DocData.WalkResult{ .type = self.types.items.len - 1 }; | 1086 | return DocData.WalkResult{ .type = type_slot_index }; |
| 1076 | }, | 1087 | }, |
| 1077 | .struct_decl => { | 1088 | .struct_decl => { |
| 1078 | var scope: Scope = .{ .parent = parent_scope }; | 1089 | var scope: Scope = .{ .parent = parent_scope }; |
| ... | @@ -1116,6 +1127,9 @@ fn walkInstruction( | ... | @@ -1116,6 +1127,9 @@ fn walkInstruction( |
| 1116 | { | 1127 | { |
| 1117 | var it = file.zir.declIterator(@intCast(u32, inst_index)); | 1128 | var it = file.zir.declIterator(@intCast(u32, inst_index)); |
| 1118 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); | 1129 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); |
| | 1130 | for (self.decls.items[decls_first_index..]) |*slot| { |
| | 1131 | slot._analyzed = false; |
| | 1132 | } |
| 1119 | var decls_slot_index = decls_first_index; | 1133 | var decls_slot_index = decls_first_index; |
| 1120 | while (it.next()) |d| : (decls_slot_index += 1) { | 1134 | while (it.next()) |d| : (decls_slot_index += 1) { |
| 1121 | const decl_name_index = file.zir.extra[d.sub_index + 5]; | 1135 | const decl_name_index = file.zir.extra[d.sub_index + 5]; |
| ... | @@ -1149,7 +1163,7 @@ fn walkInstruction( | ... | @@ -1149,7 +1163,7 @@ fn walkInstruction( |
| 1149 | | 1163 | |
| 1150 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; | 1164 | self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; |
| 1151 | | 1165 | |
| 1152 | try self.types.append(self.arena, .{ | 1166 | self.types.items[type_slot_index] = .{ |
| 1153 | .Struct = .{ | 1167 | .Struct = .{ |
| 1154 | .name = "todo_name", | 1168 | .name = "todo_name", |
| 1155 | .src = self_ast_node_index, | 1169 | .src = self_ast_node_index, |
| ... | @@ -1157,9 +1171,9 @@ fn walkInstruction( | ... | @@ -1157,9 +1171,9 @@ fn walkInstruction( |
| 1157 | .pubDecls = decl_indexes.items, | 1171 | .pubDecls = decl_indexes.items, |
| 1158 | .fields = field_type_refs.items, | 1172 | .fields = field_type_refs.items, |
| 1159 | }, | 1173 | }, |
| 1160 | }); | 1174 | }; |
| 1161 | | 1175 | |
| 1162 | return DocData.WalkResult{ .type = self.types.items.len - 1 }; | 1176 | return DocData.WalkResult{ .type = type_slot_index }; |
| 1163 | }, | 1177 | }, |
| 1164 | } | 1178 | } |
| 1165 | }, | 1179 | }, |
| ... | @@ -1310,6 +1324,7 @@ fn walkDecls( | ... | @@ -1310,6 +1324,7 @@ fn walkDecls( |
| 1310 | }; | 1324 | }; |
| 1311 | self.decls.items[decl_being_tested].decltest = ast_node_index; | 1325 | self.decls.items[decl_being_tested].decltest = ast_node_index; |
| 1312 | self.decls.items[decls_slot_index] = .{ | 1326 | self.decls.items[decls_slot_index] = .{ |
| | 1327 | ._analyzed = true, |
| 1313 | .name = "test", | 1328 | .name = "test", |
| 1314 | .src = ast_node_index, | 1329 | .src = ast_node_index, |
| 1315 | .value = .{ .type = 0 }, | 1330 | .value = .{ .type = 0 }, |
| ... | @@ -1368,17 +1383,110 @@ fn walkDecls( | ... | @@ -1368,17 +1383,110 @@ fn walkDecls( |
| 1368 | // }; | 1383 | // }; |
| 1369 | | 1384 | |
| 1370 | self.decls.items[decls_slot_index] = .{ | 1385 | self.decls.items[decls_slot_index] = .{ |
| | 1386 | ._analyzed = true, |
| 1371 | .name = name, | 1387 | .name = name, |
| 1372 | .src = ast_node_index, | 1388 | .src = ast_node_index, |
| 1373 | // .typeRef = decl_type_ref, | 1389 | // .typeRef = decl_type_ref, |
| 1374 | .value = walk_result, | 1390 | .value = walk_result, |
| 1375 | .kind = "const", // find where this information can be found | 1391 | .kind = "const", // find where this information can be found |
| 1376 | }; | 1392 | }; |
| | 1393 | |
| | 1394 | // Unblock any pending decl path that was waiting for this decl. |
| | 1395 | if (self.decl_paths_pending_on_decls.get(decls_slot_index)) |paths| { |
| | 1396 | for (paths.items) |resume_info| { |
| | 1397 | try self.tryResolveDeclPath(resume_info.file, resume_info.path); |
| | 1398 | } |
| | 1399 | |
| | 1400 | _ = self.decl_paths_pending_on_decls.remove(decls_slot_index); |
| | 1401 | // TODO: we should deallocate the arraylist that holds all the |
| | 1402 | // decl paths. not doing it now since it's arena-allocated |
| | 1403 | // anyway, but maybe we should put it elsewhere. |
| | 1404 | } |
| 1377 | } | 1405 | } |
| 1378 | | 1406 | |
| 1379 | return extra_index; | 1407 | return extra_index; |
| 1380 | } | 1408 | } |
| 1381 | | 1409 | |
| | 1410 | /// An unresolved path has a decl index at its end, while every other element |
| | 1411 | /// is an index into the string table. Resolving means resolving iteratively |
| | 1412 | /// each string into a decl_index. If we encounter an unanalyzed decl during |
| | 1413 | /// the process, we append the unsolved sub-path to `self.decl_paths_pending_on_decls` |
| | 1414 | /// and bail out. |
| | 1415 | fn tryResolveDeclPath( |
| | 1416 | self: *Autodoc, |
| | 1417 | /// File from which the decl path originates. |
| | 1418 | file: *File, |
| | 1419 | path: []usize, |
| | 1420 | ) !void { |
| | 1421 | var i: usize = path.len; |
| | 1422 | while (i > 1) { |
| | 1423 | i -= 1; |
| | 1424 | const decl_index = path[i]; |
| | 1425 | const string_index = path[i - 1]; |
| | 1426 | |
| | 1427 | const parent = self.decls.items[decl_index]; |
| | 1428 | if (!parent._analyzed) { |
| | 1429 | const res = try self.decl_paths_pending_on_decls.getOrPut(self.arena, decl_index); |
| | 1430 | if (!res.found_existing) res.value_ptr.* = .{}; |
| | 1431 | try res.value_ptr.*.append(self.arena, .{ |
| | 1432 | .file = file, |
| | 1433 | .path = path[0 .. i + 1], |
| | 1434 | }); |
| | 1435 | return; |
| | 1436 | } |
| | 1437 | |
| | 1438 | const child_decl_name = file.zir.nullTerminatedString(string_index); |
| | 1439 | switch (parent.value) { |
| | 1440 | else => { |
| | 1441 | std.debug.panic( |
| | 1442 | "TODO: handle `{s}`in walkInstruction.field_val\n", |
| | 1443 | .{@tagName(parent.value)}, |
| | 1444 | ); |
| | 1445 | }, |
| | 1446 | .type => |t_index| switch (self.types.items[t_index]) { |
| | 1447 | else => { |
| | 1448 | std.debug.panic( |
| | 1449 | "TODO: handle `{s}` in tryResolveDeclPath.type\n", |
| | 1450 | .{@tagName(self.types.items[t_index])}, |
| | 1451 | ); |
| | 1452 | }, |
| | 1453 | .Unanalyzed => { |
| | 1454 | const res = try self.decl_paths_pending_on_types.getOrPut( |
| | 1455 | self.arena, |
| | 1456 | t_index, |
| | 1457 | ); |
| | 1458 | if (!res.found_existing) res.value_ptr.* = .{}; |
| | 1459 | try res.value_ptr.*.append(self.arena, .{ |
| | 1460 | .file = file, |
| | 1461 | .path = path[0 .. i + 1], |
| | 1462 | }); |
| | 1463 | return; |
| | 1464 | }, |
| | 1465 | .Struct => |t_struct| { |
| | 1466 | for (t_struct.pubDecls) |d| { |
| | 1467 | // TODO: this could be improved a lot |
| | 1468 | // by having our own string table! |
| | 1469 | const decl = self.decls.items[d]; |
| | 1470 | if (std.mem.eql(u8, decl.name, child_decl_name)) { |
| | 1471 | path[i - 1] = d; |
| | 1472 | continue; |
| | 1473 | } |
| | 1474 | } |
| | 1475 | for (t_struct.privDecls) |d| { |
| | 1476 | // TODO: this could be improved a lot |
| | 1477 | // by having our own string table! |
| | 1478 | const decl = self.decls.items[d]; |
| | 1479 | if (std.mem.eql(u8, decl.name, child_decl_name)) { |
| | 1480 | path[i - 1] = d; |
| | 1481 | continue; |
| | 1482 | } |
| | 1483 | } |
| | 1484 | }, |
| | 1485 | }, |
| | 1486 | } |
| | 1487 | } |
| | 1488 | } |
| | 1489 | |
| 1382 | fn collectUnionFieldInfo( | 1490 | fn collectUnionFieldInfo( |
| 1383 | self: *Autodoc, | 1491 | self: *Autodoc, |
| 1384 | file: *File, | 1492 | file: *File, |