| ... | @@ -144,10 +144,11 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -144,10 +144,11 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 144 | } | 144 | } |
| 145 | } | 145 | } |
| 146 | | 146 | |
| 147 | var root_scope = Scope{ .parent = null }; | 147 | const main_type_index = self.types.items.len; |
| | 148 | var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index }; |
| 148 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); | 149 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); |
| 149 | try self.files.put(self.arena, file, self.types.items.len); | 150 | try self.files.put(self.arena, file, main_type_index); |
| 150 | const main_type_index = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst); | 151 | _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst); |
| 151 | | 152 | |
| 152 | if (self.decl_paths_pending_on_decls.count() > 0) { | 153 | if (self.decl_paths_pending_on_decls.count() > 0) { |
| 153 | @panic("some decl paths were never fully analized (pending on decls)"); | 154 | @panic("some decl paths were never fully analized (pending on decls)"); |
| ... | @@ -170,7 +171,7 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -170,7 +171,7 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 170 | .comptimeExprs = self.comptime_exprs.items, | 171 | .comptimeExprs = self.comptime_exprs.items, |
| 171 | }; | 172 | }; |
| 172 | | 173 | |
| 173 | data.packages[0].main = main_type_index.type; | 174 | data.packages[0].main = main_type_index; |
| 174 | | 175 | |
| 175 | if (self.doc_location.directory) |d| { | 176 | if (self.doc_location.directory) |d| { |
| 176 | d.handle.makeDir( | 177 | d.handle.makeDir( |
| ... | @@ -215,6 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -215,6 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 215 | const Scope = struct { | 216 | const Scope = struct { |
| 216 | parent: ?*Scope, | 217 | parent: ?*Scope, |
| 217 | map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls` | 218 | map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls` |
| | 219 | enclosing_type: usize, // index into `types` |
| 218 | | 220 | |
| 219 | /// Assumes all decls in present scope and upper scopes have already | 221 | /// Assumes all decls in present scope and upper scopes have already |
| 220 | /// been either fully resolved or at least reserved. | 222 | /// been either fully resolved or at least reserved. |
| ... | @@ -475,6 +477,7 @@ const DocData = struct { | ... | @@ -475,6 +477,7 @@ const DocData = struct { |
| 475 | const DeclPath = struct { | 477 | const DeclPath = struct { |
| 476 | path: []usize, // indexes in `decls` | 478 | path: []usize, // indexes in `decls` |
| 477 | hasCte: bool = false, // a prefix of this path could not be resolved | 479 | hasCte: bool = false, // a prefix of this path could not be resolved |
| | 480 | // TODO: make hasCte return the actual index where the cte is! |
| 478 | }; | 481 | }; |
| 479 | | 482 | |
| 480 | const TypeRef = union(enum) { | 483 | const TypeRef = union(enum) { |
| ... | @@ -482,14 +485,10 @@ const DocData = struct { | ... | @@ -482,14 +485,10 @@ const DocData = struct { |
| 482 | declPath: DeclPath, | 485 | declPath: DeclPath, |
| 483 | type: usize, // index in `types` | 486 | type: usize, // index in `types` |
| 484 | comptimeExpr: usize, // index in `comptimeExprs` | 487 | comptimeExpr: usize, // index in `comptimeExprs` |
| 485 | | 488 | // TODO: maybe we should not consider calls to be typerefs and instread |
| 486 | pub fn fromWalkResult(wr: WalkResult) TypeRef { | 489 | // directly refer to their return value. The problem at the moment |
| 487 | return switch (wr) { | 490 | // is that we can't analyze function calls at all. |
| 488 | .declPath => |v| .{ .declPath = v }, | 491 | call: usize, // index in `call` |
| 489 | .type => |v| .{ .type = v }, | | |
| 490 | else => @panic("Found non-type WalkResult"), | | |
| 491 | }; | | |
| 492 | } | | |
| 493 | | 492 | |
| 494 | pub fn jsonStringify( | 493 | pub fn jsonStringify( |
| 495 | self: TypeRef, | 494 | self: TypeRef, |
| ... | @@ -503,7 +502,7 @@ const DocData = struct { | ... | @@ -503,7 +502,7 @@ const DocData = struct { |
| 503 | , .{}); | 502 | , .{}); |
| 504 | }, | 503 | }, |
| 505 | | 504 | |
| 506 | .type, .comptimeExpr => |v| { | 505 | .type, .comptimeExpr, .call => |v| { |
| 507 | try w.print( | 506 | try w.print( |
| 508 | \\{{ "{s}":{} }} | 507 | \\{{ "{s}":{} }} |
| 509 | , .{ @tagName(self), v }); | 508 | , .{ @tagName(self), v }); |
| ... | @@ -647,7 +646,7 @@ fn walkInstruction( | ... | @@ -647,7 +646,7 @@ fn walkInstruction( |
| 647 | switch (tags[inst_index]) { | 646 | switch (tags[inst_index]) { |
| 648 | else => { | 647 | else => { |
| 649 | std.debug.panic( | 648 | std.debug.panic( |
| 650 | "TODO: implement `walkInstruction` for {s}\n\n", | 649 | "TODO: implement `{s}` for walkInstruction\n\n", |
| 651 | .{@tagName(tags[inst_index])}, | 650 | .{@tagName(tags[inst_index])}, |
| 652 | ); | 651 | ); |
| 653 | }, | 652 | }, |
| ... | @@ -674,7 +673,10 @@ fn walkInstruction( | ... | @@ -674,7 +673,10 @@ fn walkInstruction( |
| 674 | | 673 | |
| 675 | result.value_ptr.* = self.types.items.len; | 674 | result.value_ptr.* = self.types.items.len; |
| 676 | | 675 | |
| 677 | var new_scope = Scope{ .parent = null }; | 676 | var new_scope = Scope{ |
| | 677 | .parent = null, |
| | 678 | .enclosing_type = self.types.items.len, |
| | 679 | }; |
| 678 | const new_file_walk_result = self.walkInstruction( | 680 | const new_file_walk_result = self.walkInstruction( |
| 679 | new_file.file, | 681 | new_file.file, |
| 680 | &new_scope, | 682 | &new_scope, |
| ... | @@ -849,7 +851,7 @@ fn walkInstruction( | ... | @@ -849,7 +851,7 @@ fn walkInstruction( |
| 849 | }); | 851 | }); |
| 850 | break :idx idx; | 852 | break :idx idx; |
| 851 | }; | 853 | }; |
| 852 | const str_tok = data[inst_index].str_tok; | 854 | const str_tok = data[lhs].str_tok; |
| 853 | const file_path = str_tok.get(file.zir); | 855 | const file_path = str_tok.get(file.zir); |
| 854 | | 856 | |
| 855 | const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path}); | 857 | const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path}); |
| ... | @@ -906,7 +908,7 @@ fn walkInstruction( | ... | @@ -906,7 +908,7 @@ fn walkInstruction( |
| 906 | const pl_node = data[inst_index].pl_node; | 908 | const pl_node = data[inst_index].pl_node; |
| 907 | const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index); | 909 | const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index); |
| 908 | | 910 | |
| 909 | const callee = DocData.TypeRef.fromWalkResult( | 911 | const callee = walkResultToTypeRef( |
| 910 | try self.walkRef(file, parent_scope, extra.data.callee), | 912 | try self.walkRef(file, parent_scope, extra.data.callee), |
| 911 | ); | 913 | ); |
| 912 | | 914 | |
| ... | @@ -917,11 +919,21 @@ fn walkInstruction( | ... | @@ -917,11 +919,21 @@ fn walkInstruction( |
| 917 | args[idx] = try self.walkRef(file, parent_scope, ref); | 919 | args[idx] = try self.walkRef(file, parent_scope, ref); |
| 918 | } | 920 | } |
| 919 | | 921 | |
| | 922 | // TODO: see if we can ever do something better than just always |
| | 923 | // resolve function calls to a comptimeExpr. |
| | 924 | const cte_slot_index = self.comptime_exprs.items.len; |
| | 925 | try self.comptime_exprs.append(self.arena, .{ |
| | 926 | .code = "func call", |
| | 927 | .typeRef = .{ |
| | 928 | .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr), |
| | 929 | }, // TODO: extract return type from callee when available |
| | 930 | }); |
| | 931 | |
| 920 | const call_slot_index = self.calls.items.len; | 932 | const call_slot_index = self.calls.items.len; |
| 921 | try self.calls.append(self.arena, .{ | 933 | try self.calls.append(self.arena, .{ |
| 922 | .func = callee, | 934 | .func = callee, |
| 923 | .args = args, | 935 | .args = args, |
| 924 | .ret = .{ .void = {} }, // TODO: handle returns! | 936 | .ret = .{ .comptimeExpr = cte_slot_index }, |
| 925 | }); | 937 | }); |
| 926 | | 938 | |
| 927 | return DocData.WalkResult{ .call = call_slot_index }; | 939 | return DocData.WalkResult{ .call = call_slot_index }; |
| ... | @@ -967,7 +979,7 @@ fn walkInstruction( | ... | @@ -967,7 +979,7 @@ fn walkInstruction( |
| 967 | const param_type_ref = try self.walkRef(file, parent_scope, break_operand); | 979 | const param_type_ref = try self.walkRef(file, parent_scope, break_operand); |
| 968 | | 980 | |
| 969 | param_type_refs.appendAssumeCapacity( | 981 | param_type_refs.appendAssumeCapacity( |
| 970 | DocData.TypeRef.fromWalkResult(param_type_ref), | 982 | walkResultToTypeRef(param_type_ref), |
| 971 | ); | 983 | ); |
| 972 | }, | 984 | }, |
| 973 | } | 985 | } |
| ... | @@ -978,7 +990,7 @@ fn walkInstruction( | ... | @@ -978,7 +990,7 @@ fn walkInstruction( |
| 978 | const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; | 990 | const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; |
| 979 | const break_operand = data[last_instr_index].@"break".operand; | 991 | const break_operand = data[last_instr_index].@"break".operand; |
| 980 | const wr = try self.walkRef(file, parent_scope, break_operand); | 992 | const wr = try self.walkRef(file, parent_scope, break_operand); |
| 981 | break :blk DocData.TypeRef.fromWalkResult(wr); | 993 | break :blk walkResultToTypeRef(wr); |
| 982 | }; | 994 | }; |
| 983 | | 995 | |
| 984 | self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items; | 996 | self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items; |
| ... | @@ -1025,7 +1037,10 @@ fn walkInstruction( | ... | @@ -1025,7 +1037,10 @@ fn walkInstruction( |
| 1025 | ); | 1037 | ); |
| 1026 | }, | 1038 | }, |
| 1027 | .union_decl => { | 1039 | .union_decl => { |
| 1028 | var scope: Scope = .{ .parent = parent_scope }; | 1040 | var scope: Scope = .{ |
| | 1041 | .parent = parent_scope, |
| | 1042 | .enclosing_type = type_slot_index, |
| | 1043 | }; |
| 1029 | | 1044 | |
| 1030 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); | 1045 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| 1031 | var extra_index: usize = extended.operand; | 1046 | var extra_index: usize = extended.operand; |
| ... | @@ -1128,7 +1143,10 @@ fn walkInstruction( | ... | @@ -1128,7 +1143,10 @@ fn walkInstruction( |
| 1128 | return DocData.WalkResult{ .type = type_slot_index }; | 1143 | return DocData.WalkResult{ .type = type_slot_index }; |
| 1129 | }, | 1144 | }, |
| 1130 | .enum_decl => { | 1145 | .enum_decl => { |
| 1131 | var scope: Scope = .{ .parent = parent_scope }; | 1146 | var scope: Scope = .{ |
| | 1147 | .parent = parent_scope, |
| | 1148 | .enclosing_type = type_slot_index, |
| | 1149 | }; |
| 1132 | | 1150 | |
| 1133 | const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); | 1151 | const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); |
| 1134 | var extra_index: usize = extended.operand; | 1152 | var extra_index: usize = extended.operand; |
| ... | @@ -1256,7 +1274,10 @@ fn walkInstruction( | ... | @@ -1256,7 +1274,10 @@ fn walkInstruction( |
| 1256 | return DocData.WalkResult{ .type = type_slot_index }; | 1274 | return DocData.WalkResult{ .type = type_slot_index }; |
| 1257 | }, | 1275 | }, |
| 1258 | .struct_decl => { | 1276 | .struct_decl => { |
| 1259 | var scope: Scope = .{ .parent = parent_scope }; | 1277 | var scope: Scope = .{ |
| | 1278 | .parent = parent_scope, |
| | 1279 | .enclosing_type = type_slot_index, |
| | 1280 | }; |
| 1260 | | 1281 | |
| 1261 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 1282 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| 1262 | var extra_index: usize = extended.operand; | 1283 | var extra_index: usize = extended.operand; |
| ... | @@ -1345,6 +1366,24 @@ fn walkInstruction( | ... | @@ -1345,6 +1366,24 @@ fn walkInstruction( |
| 1345 | | 1366 | |
| 1346 | return DocData.WalkResult{ .type = type_slot_index }; | 1367 | return DocData.WalkResult{ .type = type_slot_index }; |
| 1347 | }, | 1368 | }, |
| | 1369 | .this => { |
| | 1370 | // TODO: consider if we should reuse an existing decl |
| | 1371 | // that points to this type (if present). |
| | 1372 | const decl_slot_index = self.decls.items.len; |
| | 1373 | try self.decls.append(self.arena, .{ |
| | 1374 | .name = "@This()", |
| | 1375 | .value = .{ .type = parent_scope.enclosing_type }, |
| | 1376 | .src = 0, |
| | 1377 | .kind = "const", |
| | 1378 | ._analyzed = false, |
| | 1379 | }); |
| | 1380 | const dpath = try self.arena.alloc(usize, 1); |
| | 1381 | dpath[0] = decl_slot_index; |
| | 1382 | return DocData.WalkResult{ .declPath = .{ |
| | 1383 | .hasCte = false, |
| | 1384 | .path = dpath, |
| | 1385 | } }; |
| | 1386 | }, |
| 1348 | } | 1387 | } |
| 1349 | }, | 1388 | }, |
| 1350 | } | 1389 | } |
| ... | @@ -1625,11 +1664,11 @@ fn tryResolveDeclPath( | ... | @@ -1625,11 +1664,11 @@ fn tryResolveDeclPath( |
| 1625 | switch (parent.value) { | 1664 | switch (parent.value) { |
| 1626 | else => { | 1665 | else => { |
| 1627 | std.debug.panic( | 1666 | std.debug.panic( |
| 1628 | "TODO: handle `{s}`in tryResolveDecl.field_val\n \"{s}\":{}", | 1667 | "TODO: handle `{s}`in tryResolveDecl\n \"{s}\":{}", |
| 1629 | .{ @tagName(parent.value), parent.name, parent.value }, | 1668 | .{ @tagName(parent.value), parent.name, parent.value }, |
| 1630 | ); | 1669 | ); |
| 1631 | }, | 1670 | }, |
| 1632 | .comptimeExpr => { | 1671 | .comptimeExpr, .call => { |
| 1633 | // Since we hit a cte, we leave the remaining strings unresolved | 1672 | // Since we hit a cte, we leave the remaining strings unresolved |
| 1634 | // and completely give up on resolving this decl path. | 1673 | // and completely give up on resolving this decl path. |
| 1635 | decl_path.hasCte = true; | 1674 | decl_path.hasCte = true; |
| ... | @@ -1968,12 +2007,13 @@ fn walkRef( | ... | @@ -1968,12 +2007,13 @@ fn walkRef( |
| 1968 | fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef { | 2007 | fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef { |
| 1969 | return switch (wr) { | 2008 | return switch (wr) { |
| 1970 | else => std.debug.panic( | 2009 | else => std.debug.panic( |
| 1971 | "TODO: handle `{s}` in `walkResultToTypeRef.as_node.dest_type`\n", | 2010 | "TODO: handle `{s}` in `walkResultToTypeRef`\n", |
| 1972 | .{@tagName(wr)}, | 2011 | .{@tagName(wr)}, |
| 1973 | ), | 2012 | ), |
| 1974 | | 2013 | |
| 1975 | .declPath => |v| .{ .declPath = v }, | 2014 | .declPath => |v| .{ .declPath = v }, |
| 1976 | .type => |v| .{ .type = v }, | 2015 | .type => |v| .{ .type = v }, |
| | 2016 | .call => |v| .{ .call = v }, |
| 1977 | }; | 2017 | }; |
| 1978 | } | 2018 | } |
| 1979 | | 2019 | |