| ... | @@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| 71 | | 71 | |
| | 72 | log.debug("Ref map size: {}", .{Ref.typed_value_map.len}); |
| | 73 | |
| 72 | const root_src_dir = self.module.main_pkg.root_src_directory; | 74 | const root_src_dir = self.module.main_pkg.root_src_directory; |
| 73 | const root_src_path = self.module.main_pkg.root_src_path; | 75 | const root_src_path = self.module.main_pkg.root_src_path; |
| 74 | const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path}); | 76 | const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path}); |
| ... | @@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 159 | .void_type => .{ | 161 | .void_type => .{ |
| 160 | .Void = .{ .name = tmpbuf.toOwnedSlice() }, | 162 | .Void = .{ .name = tmpbuf.toOwnedSlice() }, |
| 161 | }, | 163 | }, |
| | 164 | .type_info_type => .{ |
| | 165 | .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() }, |
| | 166 | }, |
| 162 | .type_type => .{ | 167 | .type_type => .{ |
| 163 | .Type = .{ .name = tmpbuf.toOwnedSlice() }, | 168 | .Type = .{ .name = tmpbuf.toOwnedSlice() }, |
| 164 | }, | 169 | }, |
| ... | @@ -608,6 +613,7 @@ const DocData = struct { | ... | @@ -608,6 +613,7 @@ const DocData = struct { |
| 608 | type: usize, // index in `types` | 613 | type: usize, // index in `types` |
| 609 | this: usize, // index in `types` | 614 | this: usize, // index in `types` |
| 610 | declRef: usize, // index in `decls` | 615 | declRef: usize, // index in `decls` |
| | 616 | builtinField: enum { len, ptr }, |
| 611 | fieldRef: FieldRef, | 617 | fieldRef: FieldRef, |
| 612 | refPath: []Expr, | 618 | refPath: []Expr, |
| 613 | int: struct { | 619 | int: struct { |
| ... | @@ -697,20 +703,26 @@ const DocData = struct { | ... | @@ -697,20 +703,26 @@ const DocData = struct { |
| 697 | var jsw = std.json.writeStream(w, 15); | 703 | var jsw = std.json.writeStream(w, 15); |
| 698 | try jsw.beginObject(); | 704 | try jsw.beginObject(); |
| 699 | try jsw.objectField(@tagName(active_tag)); | 705 | try jsw.objectField(@tagName(active_tag)); |
| 700 | inline for (comptime std.meta.fields(Expr)) |case| { | 706 | switch (self) { |
| 701 | if (@field(Expr, case.name) == active_tag) { | 707 | .int => { |
| 702 | switch (active_tag) { | 708 | if (self.int.negated) try w.writeAll("-"); |
| 703 | .int => { | 709 | try jsw.emitNumber(self.int.value); |
| 704 | if (self.int.negated) try w.writeAll("-"); | 710 | }, |
| 705 | try jsw.emitNumber(self.int.value); | 711 | .int_big => { |
| 706 | }, | | |
| 707 | .int_big => { | | |
| 708 | | 712 | |
| 709 | //@panic("TODO: json serialization of big ints!"); | 713 | //@panic("TODO: json serialization of big ints!"); |
| 710 | //if (v.negated) try w.writeAll("-"); | 714 | //if (v.negated) try w.writeAll("-"); |
| 711 | //try jsw.emitNumber(v.value); | 715 | //try jsw.emitNumber(v.value); |
| 712 | }, | 716 | }, |
| 713 | else => { | 717 | .builtinField => { |
| | 718 | try jsw.emitString(@tagName(self.builtinField)); |
| | 719 | }, |
| | 720 | else => { |
| | 721 | inline for (comptime std.meta.fields(Expr)) |case| { |
| | 722 | // TODO: this is super ugly, fix once `inline else` is a thing |
| | 723 | if (comptime std.mem.eql(u8, case.name, "builtinField")) |
| | 724 | continue; |
| | 725 | if (@field(Expr, case.name) == active_tag) { |
| 714 | try std.json.stringify(@field(self, case.name), opt, w); | 726 | try std.json.stringify(@field(self, case.name), opt, w); |
| 715 | jsw.state_index -= 1; | 727 | jsw.state_index -= 1; |
| 716 | // TODO: we should not reach into the state of the | 728 | // TODO: we should not reach into the state of the |
| ... | @@ -719,9 +731,9 @@ const DocData = struct { | ... | @@ -719,9 +731,9 @@ const DocData = struct { |
| 719 | // would be nice to have a proper integration | 731 | // would be nice to have a proper integration |
| 720 | // between the json writer and the generic | 732 | // between the json writer and the generic |
| 721 | // std.json.stringify implementation | 733 | // std.json.stringify implementation |
| 722 | }, | 734 | } |
| 723 | } | 735 | } |
| 724 | } | 736 | }, |
| 725 | } | 737 | } |
| 726 | try jsw.endObject(); | 738 | try jsw.endObject(); |
| 727 | } | 739 | } |
| ... | @@ -1905,31 +1917,60 @@ fn walkInstruction( | ... | @@ -1905,31 +1917,60 @@ fn walkInstruction( |
| 1905 | const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index); | 1917 | const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index); |
| 1906 | | 1918 | |
| 1907 | var path: std.ArrayListUnmanaged(DocData.Expr) = .{}; | 1919 | var path: std.ArrayListUnmanaged(DocData.Expr) = .{}; |
| 1908 | var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs | | |
| 1909 | | | |
| 1910 | try path.append(self.arena, .{ | 1920 | try path.append(self.arena, .{ |
| 1911 | .string = file.zir.nullTerminatedString(extra.data.field_name_start), | 1921 | .string = file.zir.nullTerminatedString(extra.data.field_name_start), |
| 1912 | }); | 1922 | }); |
| | 1923 | |
| 1913 | // Put inside path the starting index of each decl name that | 1924 | // Put inside path the starting index of each decl name that |
| 1914 | // we encounter as we navigate through all the field_vals | 1925 | // we encounter as we navigate through all the field_*s |
| 1915 | while (tags[lhs] == .field_val or | 1926 | const lhs_ref = blk: { |
| 1916 | tags[lhs] == .field_call_bind or | 1927 | var lhs_extra = extra; |
| 1917 | tags[lhs] == .field_ptr or | 1928 | while (true) { |
| 1918 | tags[lhs] == .field_type) | 1929 | if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) { |
| 1919 | { | 1930 | break :blk lhs_extra.data.lhs; |
| 1920 | const lhs_extra = file.zir.extraData( | 1931 | } |
| 1921 | Zir.Inst.Field, | | |
| 1922 | data[lhs].pl_node.payload_index, | | |
| 1923 | ); | | |
| 1924 | | 1932 | |
| 1925 | try path.append(self.arena, .{ | 1933 | const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; |
| 1926 | .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start), | 1934 | if (tags[lhs] != .field_val and |
| 1927 | }); | 1935 | tags[lhs] != .field_call_bind and |
| 1928 | lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs | 1936 | tags[lhs] != .field_ptr and |
| 1929 | } | 1937 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; |
| | 1938 | |
| | 1939 | lhs_extra = file.zir.extraData( |
| | 1940 | Zir.Inst.Field, |
| | 1941 | data[lhs].pl_node.payload_index, |
| | 1942 | ); |
| | 1943 | |
| | 1944 | try path.append(self.arena, .{ |
| | 1945 | .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start), |
| | 1946 | }); |
| | 1947 | } |
| | 1948 | }; |
| 1930 | | 1949 | |
| | 1950 | // If the lhs is a `call` instruction, it means that we're inside |
| | 1951 | // a function call and we're referring to one of its arguments. |
| | 1952 | // We can't just blindly analyze the instruction or we will |
| | 1953 | // start recursing forever. |
| | 1954 | // TODO: add proper resolution of the container type for `calls` |
| | 1955 | // TODO: we're like testing lhs as an instruction twice |
| | 1956 | // (above and below) this todo, maybe a cleaer solution woul |
| | 1957 | // avoid that. |
| 1931 | // TODO: double check that we really don't need type info here | 1958 | // TODO: double check that we really don't need type info here |
| 1932 | const wr = try self.walkInstruction(file, parent_scope, lhs, false); | 1959 | |
| | 1960 | const wr = blk: { |
| | 1961 | if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) { |
| | 1962 | const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len; |
| | 1963 | if (tags[lhs_inst] == .call) { |
| | 1964 | break :blk DocData.WalkResult{ |
| | 1965 | .expr = .{ |
| | 1966 | .comptimeExpr = 0, |
| | 1967 | }, |
| | 1968 | }; |
| | 1969 | } |
| | 1970 | } |
| | 1971 | |
| | 1972 | break :blk try self.walkRef(file, parent_scope, lhs_ref, false); |
| | 1973 | }; |
| 1933 | try path.append(self.arena, wr.expr); | 1974 | try path.append(self.arena, wr.expr); |
| 1934 | | 1975 | |
| 1935 | // This way the data in `path` has the same ordering that the ref | 1976 | // This way the data in `path` has the same ordering that the ref |
| ... | @@ -1948,7 +1989,7 @@ fn walkInstruction( | ... | @@ -1948,7 +1989,7 @@ fn walkInstruction( |
| 1948 | // - (2) Paths can sometimes never resolve fully. This means that | 1989 | // - (2) Paths can sometimes never resolve fully. This means that |
| 1949 | // any value that depends on that will have to become a | 1990 | // any value that depends on that will have to become a |
| 1950 | // comptimeExpr. | 1991 | // comptimeExpr. |
| 1951 | try self.tryResolveRefPath(file, lhs, path.items); | 1992 | try self.tryResolveRefPath(file, inst_index, path.items); |
| 1952 | return DocData.WalkResult{ .expr = .{ .refPath = path.items } }; | 1993 | return DocData.WalkResult{ .expr = .{ .refPath = path.items } }; |
| 1953 | }, | 1994 | }, |
| 1954 | .int_type => { | 1995 | .int_type => { |
| ... | @@ -2053,6 +2094,33 @@ fn walkInstruction( | ... | @@ -2053,6 +2094,33 @@ fn walkInstruction( |
| 2053 | ); | 2094 | ); |
| 2054 | return self.cteTodo(@tagName(tags[inst_index])); | 2095 | return self.cteTodo(@tagName(tags[inst_index])); |
| 2055 | }, | 2096 | }, |
| | 2097 | .struct_init_anon => { |
| | 2098 | const pl_node = data[inst_index].pl_node; |
| | 2099 | const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index); |
| | 2100 | |
| | 2101 | const field_vals = try self.arena.alloc( |
| | 2102 | DocData.Expr.FieldVal, |
| | 2103 | extra.data.fields_len, |
| | 2104 | ); |
| | 2105 | |
| | 2106 | var idx = extra.end; |
| | 2107 | for (field_vals) |*fv| { |
| | 2108 | const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx); |
| | 2109 | const field_name = file.zir.nullTerminatedString(init_extra.data.field_name); |
| | 2110 | const value = try self.walkRef( |
| | 2111 | file, |
| | 2112 | parent_scope, |
| | 2113 | init_extra.data.init, |
| | 2114 | need_type, |
| | 2115 | ); |
| | 2116 | fv.* = .{ .name = field_name, .val = value }; |
| | 2117 | idx = init_extra.end; |
| | 2118 | } |
| | 2119 | |
| | 2120 | return DocData.WalkResult{ |
| | 2121 | .expr = .{ .@"struct" = field_vals }, |
| | 2122 | }; |
| | 2123 | }, |
| 2056 | .error_set_decl => { | 2124 | .error_set_decl => { |
| 2057 | const pl_node = data[inst_index].pl_node; | 2125 | const pl_node = data[inst_index].pl_node; |
| 2058 | const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index); | 2126 | const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index); |
| ... | @@ -3072,6 +3140,10 @@ fn tryResolveRefPath( | ... | @@ -3072,6 +3140,10 @@ fn tryResolveRefPath( |
| 3072 | .{ @tagName(self.types.items[t_index]), resolved_parent }, | 3140 | .{ @tagName(self.types.items[t_index]), resolved_parent }, |
| 3073 | ); | 3141 | ); |
| 3074 | }, | 3142 | }, |
| | 3143 | .ComptimeExpr => { |
| | 3144 | // Same as the comptimeExpr branch above |
| | 3145 | break :outer; |
| | 3146 | }, |
| 3075 | .Unanalyzed => { | 3147 | .Unanalyzed => { |
| 3076 | // This decl path is pending completion | 3148 | // This decl path is pending completion |
| 3077 | { | 3149 | { |
| ... | @@ -3094,6 +3166,20 @@ fn tryResolveRefPath( | ... | @@ -3094,6 +3166,20 @@ fn tryResolveRefPath( |
| 3094 | | 3166 | |
| 3095 | return; | 3167 | return; |
| 3096 | }, | 3168 | }, |
| | 3169 | .Array => { |
| | 3170 | if (std.mem.eql(u8, child_string, "len")) { |
| | 3171 | path[i + 1] = .{ |
| | 3172 | .builtinField = .len, |
| | 3173 | }; |
| | 3174 | } else { |
| | 3175 | panicWithContext( |
| | 3176 | file, |
| | 3177 | inst_index, |
| | 3178 | "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}", |
| | 3179 | .{ child_string, resolved_parent }, |
| | 3180 | ); |
| | 3181 | } |
| | 3182 | }, |
| 3097 | .Enum => |t_enum| { | 3183 | .Enum => |t_enum| { |
| 3098 | for (t_enum.pubDecls) |d| { | 3184 | for (t_enum.pubDecls) |d| { |
| 3099 | // TODO: this could be improved a lot | 3185 | // TODO: this could be improved a lot |
| ... | @@ -3820,9 +3906,12 @@ fn walkRef( | ... | @@ -3820,9 +3906,12 @@ fn walkRef( |
| 3820 | } else if (enum_value < Ref.typed_value_map.len) { | 3906 | } else if (enum_value < Ref.typed_value_map.len) { |
| 3821 | switch (ref) { | 3907 | switch (ref) { |
| 3822 | else => { | 3908 | else => { |
| 3823 | std.debug.panic("TODO: handle {s} in `walkRef`\n", .{ | 3909 | panicWithContext( |
| 3824 | @tagName(ref), | 3910 | file, |
| 3825 | }); | 3911 | 0, |
| | 3912 | "TODO: handle {s} in walkRef", |
| | 3913 | .{@tagName(ref)}, |
| | 3914 | ); |
| 3826 | }, | 3915 | }, |
| 3827 | .undef => { | 3916 | .undef => { |
| 3828 | return DocData.WalkResult{ .expr = .@"undefined" }; | 3917 | return DocData.WalkResult{ .expr = .@"undefined" }; |