From 98fddd1c54171b080eb254527203b6f4e4e2f6ca Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Thu, 20 Jan 2022 19:59:40 +0100 Subject: [PATCH] add field doc comments to zir Doc comment information is stored in `extra` unconditionally for each field. This commmit covers Structs, Enums, Unions, and ErrSets. --- src/AstGen.zig | 27 +++++++++++++++++++++------ src/Sema.zig | 18 +++++++++++++++--- src/Zir.zig | 7 +++++++ src/print_zir.zig | 47 ++++++++++++++++++++++++++++++++++++----------- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index eda06d0441..142806e74c 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3193,7 +3193,7 @@ fn fnDecl( // missing function name already happened in scanDecls() const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; const fn_name_str_index = try astgen.identAsString(fn_name_token); - const doc_comment_index = try docCommentAsString(astgen, fn_name_token - 1); + const doc_comment_index = try astgen.docCommentAsString(fn_name_token - 1); // We insert this at the beginning so that its instruction index marks the // start of the top level declaration. @@ -3474,7 +3474,7 @@ fn globalVarDecl( const name_token = var_decl.ast.mut_token + 1; const name_str_index = try astgen.identAsString(name_token); - const doc_comment_index = try docCommentAsString(astgen, var_decl.ast.mut_token); + const doc_comment_index = try astgen.docCommentAsString(var_decl.ast.mut_token); var block_scope: GenZir = .{ .parent = scope, @@ -3864,7 +3864,7 @@ fn structDeclInner( const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); const bits_per_field = 4; - const max_field_size = 4; + const max_field_size = 5; var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); defer wip_members.deinit(); @@ -3888,6 +3888,9 @@ fn structDeclInner( try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); wip_members.appendToField(@enumToInt(field_type)); + const doc_comment_index = try astgen.docCommentAsString(member.ast.name_token); + wip_members.appendToField(doc_comment_index); + known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr); const have_align = member.ast.align_expr != 0; @@ -3986,7 +3989,7 @@ fn unionDeclInner( .none; const bits_per_field = 4; - const max_field_size = 4; + const max_field_size = 5; var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); defer wip_members.deinit(); @@ -4002,6 +4005,9 @@ fn unionDeclInner( const field_name = try astgen.identAsString(member.ast.name_token); wip_members.appendToField(field_name); + const doc_comment_index = try astgen.docCommentAsString(member.ast.name_token); + wip_members.appendToField(doc_comment_index); + const have_type = member.ast.type_expr != 0; const have_align = member.ast.align_expr != 0; const have_value = member.ast.value_expr != 0; @@ -4265,7 +4271,7 @@ fn containerDecl( .none; const bits_per_field = 1; - const max_field_size = 2; + const max_field_size = 3; var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); defer wip_members.deinit(); @@ -4283,6 +4289,9 @@ fn containerDecl( const field_name = try astgen.identAsString(member.ast.name_token); wip_members.appendToField(field_name); + const doc_comment_index = try astgen.docCommentAsString(member.ast.name_token); + wip_members.appendToField(doc_comment_index); + const have_value = member.ast.value_expr != 0; wip_members.nextField(bits_per_field, .{have_value}); @@ -4513,8 +4522,14 @@ fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir switch (token_tags[tok_i]) { .doc_comment, .comma => {}, .identifier => { + // TODO: maybe consider not using `docCommentAsString` + // since we're already visiting the first doc comment + // token. + try astgen.extra.ensureUnusedCapacity(gpa, 2); const str_index = try astgen.identAsString(tok_i); - try astgen.extra.append(gpa, str_index); + astgen.extra.appendAssumeCapacity(str_index); + const doc_comment_index = try astgen.docCommentAsString(tok_i); + astgen.extra.appendAssumeCapacity(doc_comment_index); fields_len += 1; }, .r_brace => break, diff --git a/src/Sema.zig b/src/Sema.zig index d3802a1784..6a2085cf3f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1916,6 +1916,9 @@ fn zirEnumDecl( const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); extra_index += 1; + // doc comment + extra_index += 1; + // This string needs to outlive the ZIR code. const field_name = try new_decl_arena_allocator.dupe(u8, field_name_zir); @@ -2103,7 +2106,6 @@ fn zirErrorSetDecl( const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); - const fields = sema.code.extra[extra.end..][0..extra.data.fields_len]; var new_decl_arena = std.heap.ArenaAllocator.init(gpa); errdefer new_decl_arena.deinit(); @@ -2121,8 +2123,12 @@ fn zirErrorSetDecl( errdefer sema.mod.abortAnonDecl(new_decl); var names = Module.ErrorSet.NameMap{}; - try names.ensureUnusedCapacity(new_decl_arena_allocator, fields.len); - for (fields) |str_index| { + try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len); + + var extra_index = @intCast(u32, extra.end); + const extra_index_end = extra_index + (extra.data.fields_len * 2); + while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string + const str_index = sema.code.extra[extra_index]; const name = try new_decl_arena_allocator.dupe(u8, sema.code.nullTerminatedString(str_index)); // TODO: This check should be performed in AstGen instead. @@ -16313,6 +16319,9 @@ fn semaStructFields( const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); extra_index += 1; + // doc_comment + extra_index += 1; + // This string needs to outlive the ZIR code. const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); const field_ty: Type = if (field_type_ref == .none) @@ -16502,6 +16511,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); extra_index += 1; + // doc_comment + extra_index += 1; + const field_type_ref: Zir.Inst.Ref = if (has_type) blk: { const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); extra_index += 1; diff --git a/src/Zir.zig b/src/Zir.zig index 74f85aa95a..b50a63163f 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2571,6 +2571,7 @@ pub const Inst = struct { /// - if there is a 0 byte at the position `name` indexes, it indicates /// this is a test decl, and the name starts at `name+1`. /// value: Index, + /// doc_comment: u32, // 0 if no doc comment /// align: Ref, // if corresponding bit is set /// link_section_or_address_space: { // if corresponding bit is set. /// link_section: Ref, @@ -2588,6 +2589,7 @@ pub const Inst = struct { /// field_name: u32, /// field_type: Ref, /// - if none, means `anytype`. + /// doc_comment: u32, // 0 if no doc comment /// align: Ref, // if corresponding bit is set /// default_value: Ref, // if corresponding bit is set /// } @@ -2638,6 +2640,7 @@ pub const Inst = struct { /// - if there is a 0 byte at the position `name` indexes, it indicates /// this is a test decl, and the name starts at `name+1`. /// value: Index, + /// doc_comment: u32, // 0 if no doc_comment /// align: Ref, // if corresponding bit is set /// link_section_or_address_space: { // if corresponding bit is set. /// link_section: Ref, @@ -2649,6 +2652,7 @@ pub const Inst = struct { /// - the bit is whether corresponding field has an value expression /// 9. fields: { // for every fields_len /// field_name: u32, + /// doc_comment: u32, // 0 if no doc_comment /// value: Ref, // if corresponding bit is set /// } pub const EnumDecl = struct { @@ -2686,6 +2690,7 @@ pub const Inst = struct { /// - if there is a 0 byte at the position `name` indexes, it indicates /// this is a test decl, and the name starts at `name+1`. /// value: Index, + /// doc_comment: u32, // 0 if no doc comment /// align: Ref, // if corresponding bit is set /// link_section_or_address_space: { // if corresponding bit is set. /// link_section: Ref, @@ -2701,6 +2706,7 @@ pub const Inst = struct { /// 0bX000: unused /// 9. fields: { // for every fields_len /// field_name: u32, // null terminated string index + /// doc_comment: u32, // 0 if no doc comment /// field_type: Ref, // if corresponding bit is set /// - if none, means `anytype`. /// align: Ref, // if corresponding bit is set @@ -2745,6 +2751,7 @@ pub const Inst = struct { /// - if there is a 0 byte at the position `name` indexes, it indicates /// this is a test decl, and the name starts at `name+1`. /// value: Index, + /// doc_comment: u32, // 0 if no doc comment, /// align: Ref, // if corresponding bit is set /// link_section_or_address_space: { // if corresponding bit is set. /// link_section: Ref, diff --git a/src/print_zir.zig b/src/print_zir.zig index 7a82d84bbd..9fd6b61231 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -1207,6 +1207,10 @@ const Writer = struct { extra_index += 1; const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); extra_index += 1; + const doc_comment_index = self.code.extra[extra_index]; + extra_index += 1; + + try self.writeDocComment(stream, doc_comment_index); try stream.writeByteNTimes(' ', self.indent); try self.writeFlag(stream, "comptime ", is_comptime); @@ -1332,6 +1336,10 @@ const Writer = struct { const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); extra_index += 1; + const doc_comment_index = self.code.extra[extra_index]; + extra_index += 1; + + try self.writeDocComment(stream, doc_comment_index); try stream.writeByteNTimes(' ', self.indent); try stream.print("{}", .{std.zig.fmtId(field_name)}); @@ -1419,12 +1427,13 @@ const Writer = struct { const pub_str = if (is_pub) "pub " else ""; const hash_bytes = @bitCast([16]u8, hash_u32s.*); - try stream.writeByteNTimes(' ', self.indent); if (decl_name_index == 0) { + try stream.writeByteNTimes(' ', self.indent); const name = if (is_exported) "usingnamespace" else "comptime"; try stream.writeAll(pub_str); try stream.writeAll(name); } else if (decl_name_index == 1) { + try stream.writeByteNTimes(' ', self.indent); try stream.writeAll("test"); } else { const raw_decl_name = self.code.nullTerminatedString(decl_name_index); @@ -1435,15 +1444,9 @@ const Writer = struct { const test_str = if (raw_decl_name.len == 0) "test " else ""; const export_str = if (is_exported) "export " else ""; - if (doc_comment_index != 0) { - const doc_comment = self.code.nullTerminatedString(doc_comment_index); - var it = std.mem.tokenize(u8, doc_comment, "\n"); - while (it.next()) |doc_line| { - try stream.print("///{s}\n", .{doc_line}); - try stream.writeByteNTimes(' ', self.indent); - } - } + try self.writeDocComment(stream, doc_comment_index); + try stream.writeByteNTimes(' ', self.indent); try stream.print("[{d}] {s}{s}{s}{}", .{ sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), }); @@ -1569,6 +1572,11 @@ const Writer = struct { const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); extra_index += 1; + const doc_comment_index = self.code.extra[extra_index]; + extra_index += 1; + + try self.writeDocComment(stream, doc_comment_index); + try stream.writeByteNTimes(' ', self.indent); try stream.print("{}", .{std.zig.fmtId(field_name)}); @@ -1632,17 +1640,23 @@ const Writer = struct { ) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); - const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; try stream.print("{s}, ", .{@tagName(name_strategy)}); try stream.writeAll("{\n"); self.indent += 2; - for (fields) |str_index| { + + var extra_index = @intCast(u32, extra.end); + const extra_index_end = extra_index + (extra.data.fields_len * 2); + while (extra_index < extra_index_end) : (extra_index += 2) { + const str_index = self.code.extra[extra_index]; const name = self.code.nullTerminatedString(str_index); + const doc_comment_index = self.code.extra[extra_index + 1]; + try self.writeDocComment(stream, doc_comment_index); try stream.writeByteNTimes(' ', self.indent); try stream.print("{},\n", .{std.zig.fmtId(name)}); } + self.indent -= 2; try stream.writeByteNTimes(' ', self.indent); try stream.writeAll("}) "); @@ -2134,6 +2148,17 @@ const Writer = struct { } } + fn writeDocComment(self: *Writer, stream: anytype, doc_comment_index: u32) !void { + if (doc_comment_index != 0) { + const doc_comment = self.code.nullTerminatedString(doc_comment_index); + var it = std.mem.tokenize(u8, doc_comment, "\n"); + while (it.next()) |doc_line| { + try stream.writeByteNTimes(' ', self.indent); + try stream.print("///{s}\n", .{doc_line}); + } + } + } + fn writeBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void { for (body) |inst| { try stream.writeByteNTimes(' ', self.indent);