diff options
| author | Loris Cro <kappaloris@gmail.com> | 2022-03-22 18:07:10 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-07-19 19:10:11 -0700 |
| commit | df3074aa985da82a01f94ba6b9a43535c7d438a9 (patch) | |
| tree | 8dd108022b69fe083ed58822f339572b1abf4be5 /src | |
| parent | 5f0ab34cc5b5d4d59bf4665964b36ae8c218df76 (diff) | |
| download | zig-df3074aa985da82a01f94ba6b9a43535c7d438a9.tar.gz zig-df3074aa985da82a01f94ba6b9a43535c7d438a9.zip | |
autodoc: fix offset math for decls and change TODOs from panics to just
prints
Diffstat (limited to 'src')
| -rw-r--r-- | src/Autodoc.zig | 338 |
1 files changed, 248 insertions, 90 deletions
diff --git a/src/Autodoc.zig b/src/Autodoc.zig index c0913c3d19..fd43274586 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -411,17 +411,17 @@ const DocData = struct { }, Enum: struct { name: []const u8, - src: ?usize = null, // index into astNodes - privDecls: ?[]usize = null, // index into decls - pubDecls: ?[]usize = null, // index into decls + src: usize, // index into astNodes + privDecls: []usize = &.{}, // index into decls + pubDecls: []usize = &.{}, // index into decls // (use src->fields to find field names) }, Union: struct { name: []const u8, - src: ?usize = null, // index into astNodes - privDecls: ?[]usize = null, // index into decls - pubDecls: ?[]usize = null, // index into decls - fields: ?[]WalkResult = null, // (use src->fields to find names) + src: usize, // index into astNodes + privDecls: []usize = &.{}, // index into decls + pubDecls: []usize = &.{}, // index into decls + fields: []WalkResult = &.{}, // (use src->fields to find names) }, Fn: struct { name: []const u8, @@ -465,6 +465,7 @@ const DocData = struct { .Struct => |v| try printTypeBody(v, options, w), .Fn => |v| try printTypeBody(v, options, w), .Union => |v| try printTypeBody(v, options, w), + .ErrorSet => |v| try printTypeBody(v, options, w), .Enum => |v| try printTypeBody(v, options, w), .Int => |v| try printTypeBody(v, options, w), .Float => |v| try printTypeBody(v, options, w), @@ -604,8 +605,12 @@ const DocData = struct { , .{}); try v.typeRef.jsonStringify(options, w); try w.print( - \\, "value": {s}{} }} }} - , .{ neg, v.value }); + \\, "value": {s}1 }} }} + , .{neg}); + // TODO: uncomment once float panic is fixed in stdlib + // try w.print( + // \\, "value": {s}{e} }} }} + // , .{ neg, v.value }); }, .bool => |v| { try w.print( @@ -685,12 +690,13 @@ fn walkInstruction( switch (tags[inst_index]) { else => { - panicWithContext( + printWithContext( file, inst_index, "TODO: implement `{s}` for walkInstruction\n\n", .{@tagName(tags[inst_index])}, ); + return self.cteTodo(@tagName(tags[inst_index])); }, .closure_get => { const inst_node = data[inst_index].inst_node; @@ -752,17 +758,11 @@ fn walkInstruction( return DocData.WalkResult{ .compileError = operand.string }; }, - .switch_block => return self.cteTodo("[switch]"), .enum_literal => { const str_tok = data[inst_index].str_tok; const literal = file.zir.nullTerminatedString(str_tok.start); return DocData.WalkResult{ .enumLiteral = literal }; }, - .div_exact, .div => return self.cteTodo("@div(...)"), - .mul => return self.cteTodo("@mul(...)"), - .array_mul => return self.cteTodo("a ** b"), - .bool_br_and, .bool_br_or => return self.cteTodo("bool op"), - .cmp_eq => return self.cteTodo("bool op"), .int => { const int = data[inst_index].int; const t = try self.arena.create(DocData.WalkResult); @@ -849,7 +849,7 @@ fn walkInstruction( .negated = false, }, }, - .child = typeOfWalkResult(array_data[0]), + .child = try self.typeOfWalkResult(array_data[0]), }, }); @@ -880,7 +880,17 @@ fn walkInstruction( parent_scope, un_node.operand, ); - operand.int.negated = true; // only support ints for now + switch (operand) { + .int => |*int| int.negated = true, + else => { + printWithContext( + file, + inst_index, + "TODO: support negation for more types", + .{}, + ); + }, + } return operand; }, .size_of => { @@ -913,21 +923,19 @@ fn walkInstruction( var operand = try self.walkRef(file, parent_scope, extra.data.operand); switch (operand) { - else => panicWithContext( + else => printWithContext( file, inst_index, - "TODO: handle {s} in `walkInstruction.as_node`\n", + "TODO: handle {s} in `walkInstruction.as_node`", .{@tagName(operand)}, ), - .refPath, .type, .string, .call, .enumLiteral => {}, + .declRef, .refPath, .type, .string, .call, .enumLiteral => {}, // we don't do anything because up until now, // I've only seen this used as such: // @as(@as(type, Baz), .{}) // and we don't want to toss away the // decl_val information (eg by replacing it with // a WalkResult.type). - // TODO: Actually, this is a good moment to check if - // the result is indeed a type!! .comptimeExpr => { self.comptime_exprs.items[operand.comptimeExpr].typeRef = dest_type_ref; }, @@ -1043,7 +1051,7 @@ fn walkInstruction( var idx = extra.end; for (field_vals) |*fv| { const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx); - idx = init_extra.end; + defer idx = init_extra.end; const field_name = blk: { const field_inst_index = init_extra.data.field_type; @@ -1176,53 +1184,45 @@ fn walkInstruction( ); }, .extended => { - // NOTE: this code + the subsequent defer block are working towards - // solving pending decl paths that depend on completing the analysis of a type. - // When we don't find a type, the defer will run anyway but shouldn't - // ever be able to find a match inside `decl_paths_pending_on_types` - // TODO: extract this logic into a function and only call it when appropriate. - const type_slot_index = self.types.items.len; - try self.types.append(self.arena, .{ .Unanalyzed = {} }); - - defer { - if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { - for (paths.items) |resume_info| { - self.tryResolveRefPath( - resume_info.file, - inst_index, - resume_info.ref_path, - ) catch { - @panic("Out of memory"); - }; - } - - _ = self.ref_paths_pending_on_types.remove(type_slot_index); - // TODO: we should deallocate the arraylist that holds all the - // decl paths. not doing it now since it's arena-allocated - // anyway, but maybe we should put it elsewhere. - } - } - const extended = data[inst_index].extended; switch (extended.opcode) { else => { - panicWithContext( + printWithContext( file, inst_index, - "TODO: implement `walkInstruction.extended` for {s}\n\n", + "TODO: implement `walkInstruction.extended` for {s}", .{@tagName(extended.opcode)}, ); + return self.cteTodo(@tagName(extended.opcode)); }, .opaque_decl => return self.cteTodo("opaque {...}"), .func => { - return try self.analyzeFunction( + const type_slot_index = self.types.items.len; + try self.types.append(self.arena, .{ .Unanalyzed = {} }); + + const result = try self.analyzeFunction( file, parent_scope, inst_index, self_ast_node_index, type_slot_index, ); + if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { + for (paths.items) |resume_info| { + try self.tryResolveRefPath( + resume_info.file, + inst_index, + resume_info.ref_path, + ); + } + + _ = self.ref_paths_pending_on_types.remove(type_slot_index); + // TODO: we should deallocate the arraylist that holds all the + // decl paths. not doing it now since it's arena-allocated + // anyway, but maybe we should put it elsewhere. + } + return result; }, .variable => { const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); @@ -1237,6 +1237,9 @@ fn walkInstruction( return value; }, .union_decl => { + const type_slot_index = self.types.items.len; + try self.types.append(self.arena, .{ .Unanalyzed = {} }); + var scope: Scope = .{ .parent = parent_scope, .enclosing_type = type_slot_index, @@ -1340,9 +1343,27 @@ fn walkInstruction( }, }; + if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { + for (paths.items) |resume_info| { + try self.tryResolveRefPath( + resume_info.file, + inst_index, + resume_info.ref_path, + ); + } + + _ = self.ref_paths_pending_on_types.remove(type_slot_index); + // TODO: we should deallocate the arraylist that holds all the + // decl paths. not doing it now since it's arena-allocated + // anyway, but maybe we should put it elsewhere. + } + return DocData.WalkResult{ .type = type_slot_index }; }, .enum_decl => { + const type_slot_index = self.types.items.len; + try self.types.append(self.arena, .{ .Unanalyzed = {} }); + var scope: Scope = .{ .parent = parent_scope, .enclosing_type = type_slot_index, @@ -1470,10 +1491,27 @@ fn walkInstruction( .pubDecls = decl_indexes.items, }, }; + if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { + for (paths.items) |resume_info| { + try self.tryResolveRefPath( + resume_info.file, + inst_index, + resume_info.ref_path, + ); + } + + _ = self.ref_paths_pending_on_types.remove(type_slot_index); + // TODO: we should deallocate the arraylist that holds all the + // decl paths. not doing it now since it's arena-allocated + // anyway, but maybe we should put it elsewhere. + } return DocData.WalkResult{ .type = type_slot_index }; }, .struct_decl => { + const type_slot_index = self.types.items.len; + try self.types.append(self.arena, .{ .Unanalyzed = {} }); + var scope: Scope = .{ .parent = parent_scope, .enclosing_type = type_slot_index, @@ -1563,6 +1601,20 @@ fn walkInstruction( .fields = field_type_refs.items, }, }; + if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { + for (paths.items) |resume_info| { + try self.tryResolveRefPath( + resume_info.file, + inst_index, + resume_info.ref_path, + ); + } + + _ = self.ref_paths_pending_on_types.remove(type_slot_index); + // TODO: we should deallocate the arraylist that holds all the + // decl paths. not doing it now since it's arena-allocated + // anyway, but maybe we should put it elsewhere. + } return DocData.WalkResult{ .type = type_slot_index }; }, @@ -1608,9 +1660,9 @@ fn walkDecls( cur_bit_bag >>= 1; const is_exported = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - // const has_align = @truncate(u1, cur_bit_bag) != 0; + const has_align = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - // const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0; + const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; // const sub_index = extra_index; @@ -1626,21 +1678,26 @@ fn walkDecls( const doc_comment_index = file.zir.extra[extra_index]; extra_index += 1; - // const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: { - // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); - // extra_index += 1; - // break :inst inst; - // }; - // const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { - // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); - // extra_index += 1; - // break :inst inst; - // }; - // const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { - // const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); - // extra_index += 1; - // break :inst inst; - // }; + const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: { + const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + _ = align_inst; + + const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { + const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + _ = section_inst; + + const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { + const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + _ = addrspace_inst; // const pub_str = if (is_pub) "pub " else ""; // const hash_bytes = @bitCast([16]u8, hash_u32s.*); @@ -1848,6 +1905,7 @@ fn tryResolveRefPath( while (j < 10_000) : (j += 1) { switch (resolved_parent) { else => break, + .this => |t| resolved_parent = .{ .type = t }, .declRef => |decl_index| { const decl = self.decls.items[decl_index]; if (decl._analyzed) { @@ -1927,12 +1985,14 @@ fn tryResolveRefPath( else => { // NOTE: indirect references to types / decls should be handled // in the switch above this one! - panicWithContext( + printWithContext( file, inst_index, "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}", .{ @tagName(resolved_parent), resolved_parent }, ); + path[i + 1] = try self.cteTodo("match failure"); + continue :outer; }, .comptimeExpr, .call => { // Since we hit a cte, we leave the remaining strings unresolved @@ -1971,15 +2031,106 @@ fn tryResolveRefPath( return; }, + .Enum => |t_enum| { + for (t_enum.pubDecls) |d| { + // TODO: this could be improved a lot + // by having our own string table! + const decl = self.decls.items[d]; + if (std.mem.eql(u8, decl.name, child_string)) { + path[i + 1] = .{ .declRef = d }; + continue :outer; + } + } + for (t_enum.privDecls) |d| { + // TODO: this could be improved a lot + // by having our own string table! + const decl = self.decls.items[d]; + if (std.mem.eql(u8, decl.name, child_string)) { + path[i + 1] = .{ .declRef = d }; + continue :outer; + } + } + + for (self.ast_nodes.items[t_enum.src].fields.?) |ast_node, idx| { + const name = self.ast_nodes.items[ast_node].name.?; + if (std.mem.eql(u8, name, child_string)) { + // TODO: should we really create an artificial + // decl for this type? Probably not. + + path[i + 1] = .{ + .fieldRef = .{ + .type = t_index, + .index = idx, + }, + }; + continue :outer; + } + } + + // if we got here, our search failed + printWithContext( + file, + inst_index, + "failed to match `{s}` in enum", + .{child_string}, + ); + + path[i + 1] = try self.cteTodo("match failure"); + continue :outer; + }, + .Union => |t_union| { + for (t_union.pubDecls) |d| { + // TODO: this could be improved a lot + // by having our own string table! + const decl = self.decls.items[d]; + if (std.mem.eql(u8, decl.name, child_string)) { + path[i + 1] = .{ .declRef = d }; + continue :outer; + } + } + for (t_union.privDecls) |d| { + // TODO: this could be improved a lot + // by having our own string table! + const decl = self.decls.items[d]; + if (std.mem.eql(u8, decl.name, child_string)) { + path[i + 1] = .{ .declRef = d }; + continue :outer; + } + } + + for (self.ast_nodes.items[t_union.src].fields.?) |ast_node, idx| { + const name = self.ast_nodes.items[ast_node].name.?; + if (std.mem.eql(u8, name, child_string)) { + // TODO: should we really create an artificial + // decl for this type? Probably not. + + path[i + 1] = .{ + .fieldRef = .{ + .type = t_index, + .index = idx, + }, + }; + continue :outer; + } + } + + // if we got here, our search failed + printWithContext( + file, + inst_index, + "failed to match `{s}` in union", + .{child_string}, + ); + path[i + 1] = try self.cteTodo("match failure"); + continue :outer; + }, + .Struct => |t_struct| { - std.debug.print("search: {s}\n", .{child_string}); for (t_struct.pubDecls) |d| { // TODO: this could be improved a lot // by having our own string table! const decl = self.decls.items[d]; - std.debug.print("pub decl `{s}`\n", .{decl.name}); if (std.mem.eql(u8, decl.name, child_string)) { - std.debug.print("match!\n", .{}); path[i + 1] = .{ .declRef = d }; continue :outer; } @@ -1988,9 +2139,7 @@ fn tryResolveRefPath( // TODO: this could be improved a lot // by having our own string table! const decl = self.decls.items[d]; - std.debug.print("priv decl `{s}`\n", .{decl.name}); if (std.mem.eql(u8, decl.name, child_string)) { - std.debug.print("match!\n", .{}); path[i + 1] = .{ .declRef = d }; continue :outer; } @@ -1998,9 +2147,7 @@ fn tryResolveRefPath( for (self.ast_nodes.items[t_struct.src].fields.?) |ast_node, idx| { const name = self.ast_nodes.items[ast_node].name.?; - std.debug.print("field `{s}`\n", .{name}); if (std.mem.eql(u8, name, child_string)) { - std.debug.print("match!\n", .{}); // TODO: should we really create an artificial // decl for this type? Probably not. @@ -2015,12 +2162,14 @@ fn tryResolveRefPath( } // if we got here, our search failed - panicWithContext( + printWithContext( file, inst_index, - "failed to match `{s}`", + "failed to match `{s}` in struct", .{child_string}, ); + path[i + 1] = try self.cteTodo("match failure"); + continue :outer; }, }, } @@ -2070,7 +2219,7 @@ fn analyzeFunction( "TODO: handle `{s}` in walkInstruction.func\n", .{@tagName(tags[param_index])}, ), - .param_anytype => { + .param_anytype, .param_anytype_comptime => { // TODO: where are the doc comments? const str_tok = data[param_index].str_tok; @@ -2097,7 +2246,7 @@ fn analyzeFunction( const name = file.zir.nullTerminatedString(extra.data.name); param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len); - self.ast_nodes.appendAssumeCapacity(.{ + try self.ast_nodes.append(self.arena, .{ .name = name, .docs = doc_comment, .@"comptime" = tags[param_index] == .param_comptime, @@ -2382,12 +2531,15 @@ fn walkRef( /// Given a WalkResult, tries to find its type. /// Used to analyze instructions like `array_init`, which require us to /// inspect its first element to find out the array type. -fn typeOfWalkResult(wr: DocData.WalkResult) DocData.WalkResult { +fn typeOfWalkResult(self: *Autodoc, wr: DocData.WalkResult) !DocData.WalkResult { return switch (wr) { - else => std.debug.panic( - "TODO: handle `{s}` in typeOfWalkResult\n", - .{@tagName(wr)}, - ), + else => { + std.debug.print( + "TODO: handle `{s}` in typeOfWalkResult\n", + .{@tagName(wr)}, + ); + return self.cteTodo(@tagName(wr)); + }, .type => .{ .type = @enumToInt(DocData.DocTypeKinds.Type) }, .int => |v| v.typeRef.*, .float => |v| v.typeRef.*, @@ -2403,9 +2555,15 @@ fn getBlockInlineBreak(zir: Zir, inst_index: usize) Zir.Inst.Ref { return data[break_index].@"break".operand; } -fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn { +fn printWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) void { std.debug.print("Context [{s}] % {}\n", .{ file.sub_file_path, inst }); - std.debug.panic(fmt, args); + std.debug.print(fmt, args); + std.debug.print("\n", .{}); +} + +fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn { + printWithContext(file, inst, fmt, args); + unreachable; } fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult { |
