authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-15 01:38:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-15 02:07:30-07:00
log804b51b179bf7af689d308a092d1b02e94674570
treeebc4cb661d0bbe4556de0a1659fc0dab99a8114d
parenteac628024177434563d348272165d4e3a0a281af

stage2: VarDecl and FnProto take advantage of TrailerFlags API

These AST nodes now have a flags field and then a bunch of optional trailing objects. The end result is lower memory usage and consequently better performance. This is part of an ongoing effort to reduce the amount of memory parsed ASTs take up. Running `zig fmt` on the std lib: * cache-misses: 2,554,321 => 2,534,745 * instructions: 3,293,220,119 => 3,302,479,874 * peak memory: 74.0 MiB => 73.0 MiB Holding the entire std lib AST in memory at the same time: 93.9 MiB => 88.5 MiB

8 files changed, 662 insertions(+), 428 deletions(-)

lib/std/meta/trailer_flags.zig+35-7
...@@ -33,17 +33,30 @@ pub fn TrailerFlags(comptime Fields: type) type {...@@ -33,17 +33,30 @@ pub fn TrailerFlags(comptime Fields: type) type {
33 self.bits |= 1 << field_index;33 self.bits |= 1 << field_index;
34 }34 }
3535
36 pub fn init(comptime names: anytype) Self {36 /// `fields` is a struct with each field set to an optional value.
37 /// Missing fields are assumed to be `null`.
38 /// Only the non-null bits are observed and are used to set the flag bits.
39 pub fn init(fields: anytype) Self {
37 var self: Self = .{ .bits = 0 };40 var self: Self = .{ .bits = 0 };
38 inline for (@typeInfo(@TypeOf(names)).Struct.fields) |field| {41 inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
39 if (@field(names, field.name)) {42 const opt: ?Field(field.name) = @field(fields, field.name);
40 const field_index = meta.fieldIndex(Fields, field.name).?;43 const field_index = meta.fieldIndex(Fields, field.name).?;
41 self.bits |= 1 << field_index;44 self.bits |= @as(Int, @boolToInt(opt != null)) << field_index;
42 }
43 }45 }
44 return self;46 return self;
45 }47 }
4648
49 /// `fields` is a struct with each field set to an optional value (same as `init`).
50 /// Missing fields are assumed to be `null`.
51 pub fn setMany(self: Self, p: [*]align(@alignOf(Fields)) u8, fields: anytype) void {
52 inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
53 const opt: ?Field(field.name) = @field(fields, field.name);
54 if (opt) |value| {
55 self.set(p, field.name, value);
56 }
57 }
58 }
59
47 pub fn set(60 pub fn set(
48 self: Self,61 self: Self,
49 p: [*]align(@alignOf(Fields)) u8,62 p: [*]align(@alignOf(Fields)) u8,
...@@ -54,11 +67,15 @@ pub fn TrailerFlags(comptime Fields: type) type {...@@ -54,11 +67,15 @@ pub fn TrailerFlags(comptime Fields: type) type {
54 }67 }
5568
56 pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) {69 pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) {
70 if (@sizeOf(Field(name)) == 0)
71 return undefined;
57 const off = self.offset(p, name);72 const off = self.offset(p, name);
58 return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));73 return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
59 }74 }
6075
61 pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) {76 pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) {
77 if (@sizeOf(Field(name)) == 0)
78 return undefined;
62 const off = self.offset(p, name);79 const off = self.offset(p, name);
63 return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));80 return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
64 }81 }
...@@ -85,6 +102,8 @@ pub fn TrailerFlags(comptime Fields: type) type {...@@ -85,6 +102,8 @@ pub fn TrailerFlags(comptime Fields: type) type {
85 pub fn sizeInBytes(self: Self) usize {102 pub fn sizeInBytes(self: Self) usize {
86 var off: usize = 0;103 var off: usize = 0;
87 inline for (@typeInfo(Fields).Struct.fields) |field, i| {104 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
105 if (@sizeOf(field.field_type) == 0)
106 continue;
88 if ((self.bits & (1 << i)) != 0) {107 if ((self.bits & (1 << i)) != 0) {
89 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));108 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
90 off += @sizeOf(field.field_type);109 off += @sizeOf(field.field_type);
...@@ -103,7 +122,7 @@ test "TrailerFlags" {...@@ -103,7 +122,7 @@ test "TrailerFlags" {
103 });122 });
104 var flags = Flags.init(.{123 var flags = Flags.init(.{
105 .b = true,124 .b = true,
106 .c = true,125 .c = 1234,
107 });126 });
108 testing.expect(flags.sizeInBytes() == 16);127 testing.expect(flags.sizeInBytes() == 16);
109 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);128 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
...@@ -115,4 +134,13 @@ test "TrailerFlags" {...@@ -115,4 +134,13 @@ test "TrailerFlags" {
115 testing.expect(flags.get(slice.ptr, "a") == null);134 testing.expect(flags.get(slice.ptr, "a") == null);
116 testing.expect(!flags.get(slice.ptr, "b").?);135 testing.expect(!flags.get(slice.ptr, "b").?);
117 testing.expect(flags.get(slice.ptr, "c").? == 12345678);136 testing.expect(flags.get(slice.ptr, "c").? == 12345678);
137
138 flags.setMany(slice.ptr, .{
139 .b = true,
140 .c = 5678,
141 });
142
143 testing.expect(flags.get(slice.ptr, "a") == null);
144 testing.expect(flags.get(slice.ptr, "b").?);
145 testing.expect(flags.get(slice.ptr, "c").? == 5678);
118}146}
lib/std/zig/ast.zig+159-60
...@@ -675,42 +675,84 @@ pub const Node = struct {...@@ -675,42 +675,84 @@ pub const Node = struct {
675 }675 }
676 };676 };
677677
678 /// Trailed in memory by possibly many things, with each optional thing
679 /// determined by a bit in `trailer_flags`.
678 pub const VarDecl = struct {680 pub const VarDecl = struct {
679 base: Node = Node{ .id = .VarDecl },681 base: Node = Node{ .id = .VarDecl },
680 doc_comments: ?*DocComment,682 trailer_flags: TrailerFlags,
681 visib_token: ?TokenIndex,
682 thread_local_token: ?TokenIndex,
683 name_token: TokenIndex,
684 eq_token: ?TokenIndex,
685 mut_token: TokenIndex,683 mut_token: TokenIndex,
686 comptime_token: ?TokenIndex,684 name_token: TokenIndex,
687 extern_export_token: ?TokenIndex,
688 lib_name: ?*Node,
689 type_node: ?*Node,
690 align_node: ?*Node,
691 section_node: ?*Node,
692 init_node: ?*Node,
693 semicolon_token: TokenIndex,685 semicolon_token: TokenIndex,
694686
687 pub const TrailerFlags = std.meta.TrailerFlags(struct {
688 doc_comments: *DocComment,
689 visib_token: TokenIndex,
690 thread_local_token: TokenIndex,
691 eq_token: TokenIndex,
692 comptime_token: TokenIndex,
693 extern_export_token: TokenIndex,
694 lib_name: *Node,
695 type_node: *Node,
696 align_node: *Node,
697 section_node: *Node,
698 init_node: *Node,
699 });
700
701 pub const RequiredFields = struct {
702 mut_token: TokenIndex,
703 name_token: TokenIndex,
704 semicolon_token: TokenIndex,
705 };
706
707 pub fn getTrailer(self: *const VarDecl, comptime name: []const u8) ?TrailerFlags.Field(name) {
708 const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(VarDecl);
709 return self.trailer_flags.get(trailers_start, name);
710 }
711
712 pub fn setTrailer(self: *VarDecl, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
713 const trailers_start = @ptrCast([*]u8, self) + @sizeOf(VarDecl);
714 self.trailer_flags.set(trailers_start, name, value);
715 }
716
717 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*VarDecl {
718 const trailer_flags = TrailerFlags.init(trailers);
719 const bytes = try allocator.alignedAlloc(u8, @alignOf(VarDecl), sizeInBytes(trailer_flags));
720 const var_decl = @ptrCast(*VarDecl, bytes.ptr);
721 var_decl.* = .{
722 .trailer_flags = trailer_flags,
723 .mut_token = required.mut_token,
724 .name_token = required.name_token,
725 .semicolon_token = required.semicolon_token,
726 };
727 const trailers_start = bytes.ptr + @sizeOf(VarDecl);
728 trailer_flags.setMany(trailers_start, trailers);
729 return var_decl;
730 }
731
732 pub fn destroy(self: *VarDecl, allocator: *mem.Allocator) void {
733 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)];
734 allocator.free(bytes);
735 }
736
695 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {737 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
696 var i = index;738 var i = index;
697739
698 if (self.type_node) |type_node| {740 if (self.getTrailer("type_node")) |type_node| {
699 if (i < 1) return type_node;741 if (i < 1) return type_node;
700 i -= 1;742 i -= 1;
701 }743 }
702744
703 if (self.align_node) |align_node| {745 if (self.getTrailer("align_node")) |align_node| {
704 if (i < 1) return align_node;746 if (i < 1) return align_node;
705 i -= 1;747 i -= 1;
706 }748 }
707749
708 if (self.section_node) |section_node| {750 if (self.getTrailer("section_node")) |section_node| {
709 if (i < 1) return section_node;751 if (i < 1) return section_node;
710 i -= 1;752 i -= 1;
711 }753 }
712754
713 if (self.init_node) |init_node| {755 if (self.getTrailer("init_node")) |init_node| {
714 if (i < 1) return init_node;756 if (i < 1) return init_node;
715 i -= 1;757 i -= 1;
716 }758 }
...@@ -719,17 +761,21 @@ pub const Node = struct {...@@ -719,17 +761,21 @@ pub const Node = struct {
719 }761 }
720762
721 pub fn firstToken(self: *const VarDecl) TokenIndex {763 pub fn firstToken(self: *const VarDecl) TokenIndex {
722 if (self.visib_token) |visib_token| return visib_token;764 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
723 if (self.thread_local_token) |thread_local_token| return thread_local_token;765 if (self.getTrailer("thread_local_token")) |thread_local_token| return thread_local_token;
724 if (self.comptime_token) |comptime_token| return comptime_token;766 if (self.getTrailer("comptime_token")) |comptime_token| return comptime_token;
725 if (self.extern_export_token) |extern_export_token| return extern_export_token;767 if (self.getTrailer("extern_export_token")) |extern_export_token| return extern_export_token;
726 assert(self.lib_name == null);768 assert(self.getTrailer("lib_name") == null);
727 return self.mut_token;769 return self.mut_token;
728 }770 }
729771
730 pub fn lastToken(self: *const VarDecl) TokenIndex {772 pub fn lastToken(self: *const VarDecl) TokenIndex {
731 return self.semicolon_token;773 return self.semicolon_token;
732 }774 }
775
776 fn sizeInBytes(trailer_flags: TrailerFlags) usize {
777 return @sizeOf(VarDecl) + trailer_flags.sizeInBytes();
778 }
733 };779 };
734780
735 pub const Use = struct {781 pub const Use = struct {
...@@ -972,25 +1018,34 @@ pub const Node = struct {...@@ -972,25 +1018,34 @@ pub const Node = struct {
972 };1018 };
9731019
974 /// The params are directly after the FnProto in memory.1020 /// The params are directly after the FnProto in memory.
975 /// TODO have a flags field for the optional nodes, and have them appended1021 /// Next, each optional thing determined by a bit in `trailer_flags`.
976 /// before or after the parameters in memory.
977 pub const FnProto = struct {1022 pub const FnProto = struct {
978 base: Node = Node{ .id = .FnProto },1023 base: Node = Node{ .id = .FnProto },
979 doc_comments: ?*DocComment,1024 trailer_flags: TrailerFlags,
980 visib_token: ?TokenIndex,
981 fn_token: TokenIndex,1025 fn_token: TokenIndex,
982 name_token: ?TokenIndex,
983 params_len: NodeIndex,1026 params_len: NodeIndex,
984 return_type: ReturnType,1027 return_type: ReturnType,
985 var_args_token: ?TokenIndex,1028
986 extern_export_inline_token: ?TokenIndex,1029 pub const TrailerFlags = std.meta.TrailerFlags(struct {
987 body_node: ?*Node,1030 doc_comments: *DocComment,
988 lib_name: ?*Node, // populated if this is an extern declaration1031 body_node: *Node,
989 align_expr: ?*Node, // populated if align(A) is present1032 lib_name: *Node, // populated if this is an extern declaration
990 section_expr: ?*Node, // populated if linksection(A) is present1033 align_expr: *Node, // populated if align(A) is present
991 callconv_expr: ?*Node, // populated if callconv(A) is present1034 section_expr: *Node, // populated if linksection(A) is present
992 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is1035 callconv_expr: *Node, // populated if callconv(A) is present
993 is_async: bool = false, // TODO: remove once async fn rewriting is1036 visib_token: TokenIndex,
1037 name_token: TokenIndex,
1038 var_args_token: TokenIndex,
1039 extern_export_inline_token: TokenIndex,
1040 is_extern_prototype: void, // TODO: Remove once extern fn rewriting is
1041 is_async: void, // TODO: remove once async fn rewriting is
1042 });
1043
1044 pub const RequiredFields = struct {
1045 fn_token: TokenIndex,
1046 params_len: NodeIndex,
1047 return_type: ReturnType,
1048 };
9941049
995 pub const ReturnType = union(enum) {1050 pub const ReturnType = union(enum) {
996 Explicit: *Node,1051 Explicit: *Node,
...@@ -1007,7 +1062,6 @@ pub const Node = struct {...@@ -1007,7 +1062,6 @@ pub const Node = struct {
10071062
1008 pub const ParamType = union(enum) {1063 pub const ParamType = union(enum) {
1009 any_type: *Node,1064 any_type: *Node,
1010 var_args: TokenIndex,
1011 type_expr: *Node,1065 type_expr: *Node,
1012 };1066 };
10131067
...@@ -1016,7 +1070,6 @@ pub const Node = struct {...@@ -1016,7 +1070,6 @@ pub const Node = struct {
10161070
1017 if (i < 1) {1071 if (i < 1) {
1018 switch (self.param_type) {1072 switch (self.param_type) {
1019 .var_args => return null,
1020 .any_type, .type_expr => |node| return node,1073 .any_type, .type_expr => |node| return node,
1021 }1074 }
1022 }1075 }
...@@ -1030,34 +1083,79 @@ pub const Node = struct {...@@ -1030,34 +1083,79 @@ pub const Node = struct {
1030 if (self.noalias_token) |noalias_token| return noalias_token;1083 if (self.noalias_token) |noalias_token| return noalias_token;
1031 if (self.name_token) |name_token| return name_token;1084 if (self.name_token) |name_token| return name_token;
1032 switch (self.param_type) {1085 switch (self.param_type) {
1033 .var_args => |tok| return tok,
1034 .any_type, .type_expr => |node| return node.firstToken(),1086 .any_type, .type_expr => |node| return node.firstToken(),
1035 }1087 }
1036 }1088 }
10371089
1038 pub fn lastToken(self: *const ParamDecl) TokenIndex {1090 pub fn lastToken(self: *const ParamDecl) TokenIndex {
1039 switch (self.param_type) {1091 switch (self.param_type) {
1040 .var_args => |tok| return tok,
1041 .any_type, .type_expr => |node| return node.lastToken(),1092 .any_type, .type_expr => |node| return node.lastToken(),
1042 }1093 }
1043 }1094 }
1044 };1095 };
10451096
1097 /// For debugging purposes.
1098 pub fn dump(self: *const FnProto) void {
1099 const trailers_start = @alignCast(
1100 @alignOf(ParamDecl),
1101 @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1102 );
1103 std.debug.print("{*} flags: {b} name_token: {} {*} params_len: {}\n", .{
1104 self,
1105 self.trailer_flags.bits,
1106 self.getTrailer("name_token"),
1107 self.trailer_flags.ptrConst(trailers_start, "name_token"),
1108 self.params_len,
1109 });
1110 }
1111
1112 pub fn getTrailer(self: *const FnProto, comptime name: []const u8) ?TrailerFlags.Field(name) {
1113 const trailers_start = @alignCast(
1114 @alignOf(ParamDecl),
1115 @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1116 );
1117 return self.trailer_flags.get(trailers_start, name);
1118 }
1119
1120 pub fn setTrailer(self: *FnProto, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
1121 const trailers_start = @alignCast(
1122 @alignOf(ParamDecl),
1123 @ptrCast([*]u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1124 );
1125 self.trailer_flags.set(trailers_start, name, value);
1126 }
1127
1046 /// After this the caller must initialize the params list.1128 /// After this the caller must initialize the params list.
1047 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {1129 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*FnProto {
1048 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));1130 const trailer_flags = TrailerFlags.init(trailers);
1049 return @ptrCast(*FnProto, bytes.ptr);1131 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(
1132 required.params_len,
1133 trailer_flags,
1134 ));
1135 const fn_proto = @ptrCast(*FnProto, bytes.ptr);
1136 fn_proto.* = .{
1137 .trailer_flags = trailer_flags,
1138 .fn_token = required.fn_token,
1139 .params_len = required.params_len,
1140 .return_type = required.return_type,
1141 };
1142 const trailers_start = @alignCast(
1143 @alignOf(ParamDecl),
1144 bytes.ptr + @sizeOf(FnProto) + @sizeOf(ParamDecl) * required.params_len,
1145 );
1146 trailer_flags.setMany(trailers_start, trailers);
1147 return fn_proto;
1050 }1148 }
10511149
1052 pub fn free(self: *FnProto, allocator: *mem.Allocator) void {1150 pub fn destroy(self: *FnProto, allocator: *mem.Allocator) void {
1053 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];1151 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len, self.trailer_flags)];
1054 allocator.free(bytes);1152 allocator.free(bytes);
1055 }1153 }
10561154
1057 pub fn iterate(self: *const FnProto, index: usize) ?*Node {1155 pub fn iterate(self: *const FnProto, index: usize) ?*Node {
1058 var i = index;1156 var i = index;
10591157
1060 if (self.lib_name) |lib_name| {1158 if (self.getTrailer("lib_name")) |lib_name| {
1061 if (i < 1) return lib_name;1159 if (i < 1) return lib_name;
1062 i -= 1;1160 i -= 1;
1063 }1161 }
...@@ -1066,23 +1164,21 @@ pub const Node = struct {...@@ -1066,23 +1164,21 @@ pub const Node = struct {
1066 01164 0
1067 else switch (self.paramsConst()[self.params_len - 1].param_type) {1165 else switch (self.paramsConst()[self.params_len - 1].param_type) {
1068 .any_type, .type_expr => self.params_len,1166 .any_type, .type_expr => self.params_len,
1069 .var_args => self.params_len - 1,
1070 };1167 };
1071 if (i < params_len) {1168 if (i < params_len) {
1072 switch (self.paramsConst()[i].param_type) {1169 switch (self.paramsConst()[i].param_type) {
1073 .any_type => |n| return n,1170 .any_type => |n| return n,
1074 .var_args => unreachable,
1075 .type_expr => |n| return n,1171 .type_expr => |n| return n,
1076 }1172 }
1077 }1173 }
1078 i -= params_len;1174 i -= params_len;
10791175
1080 if (self.align_expr) |align_expr| {1176 if (self.getTrailer("align_expr")) |align_expr| {
1081 if (i < 1) return align_expr;1177 if (i < 1) return align_expr;
1082 i -= 1;1178 i -= 1;
1083 }1179 }
10841180
1085 if (self.section_expr) |section_expr| {1181 if (self.getTrailer("section_expr")) |section_expr| {
1086 if (i < 1) return section_expr;1182 if (i < 1) return section_expr;
1087 i -= 1;1183 i -= 1;
1088 }1184 }
...@@ -1095,7 +1191,7 @@ pub const Node = struct {...@@ -1095,7 +1191,7 @@ pub const Node = struct {
1095 .Invalid => {},1191 .Invalid => {},
1096 }1192 }
10971193
1098 if (self.body_node) |body_node| {1194 if (self.getTrailer("body_node")) |body_node| {
1099 if (i < 1) return body_node;1195 if (i < 1) return body_node;
1100 i -= 1;1196 i -= 1;
1101 }1197 }
...@@ -1104,14 +1200,14 @@ pub const Node = struct {...@@ -1104,14 +1200,14 @@ pub const Node = struct {
1104 }1200 }
11051201
1106 pub fn firstToken(self: *const FnProto) TokenIndex {1202 pub fn firstToken(self: *const FnProto) TokenIndex {
1107 if (self.visib_token) |visib_token| return visib_token;1203 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
1108 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;1204 if (self.getTrailer("extern_export_inline_token")) |extern_export_inline_token| return extern_export_inline_token;
1109 assert(self.lib_name == null);1205 assert(self.getTrailer("lib_name") == null);
1110 return self.fn_token;1206 return self.fn_token;
1111 }1207 }
11121208
1113 pub fn lastToken(self: *const FnProto) TokenIndex {1209 pub fn lastToken(self: *const FnProto) TokenIndex {
1114 if (self.body_node) |body_node| return body_node.lastToken();1210 if (self.getTrailer("body_node")) |body_node| return body_node.lastToken();
1115 switch (self.return_type) {1211 switch (self.return_type) {
1116 .Explicit, .InferErrorSet => |node| return node.lastToken(),1212 .Explicit, .InferErrorSet => |node| return node.lastToken(),
1117 .Invalid => |tok| return tok,1213 .Invalid => |tok| return tok,
...@@ -1119,17 +1215,17 @@ pub const Node = struct {...@@ -1119,17 +1215,17 @@ pub const Node = struct {
1119 }1215 }
11201216
1121 pub fn params(self: *FnProto) []ParamDecl {1217 pub fn params(self: *FnProto) []ParamDecl {
1122 const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);1218 const params_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1123 return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];1219 return @ptrCast([*]ParamDecl, params_start)[0..self.params_len];
1124 }1220 }
11251221
1126 pub fn paramsConst(self: *const FnProto) []const ParamDecl {1222 pub fn paramsConst(self: *const FnProto) []const ParamDecl {
1127 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);1223 const params_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1128 return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];1224 return @ptrCast([*]const ParamDecl, params_start)[0..self.params_len];
1129 }1225 }
11301226
1131 fn sizeInBytes(params_len: NodeIndex) usize {1227 fn sizeInBytes(params_len: NodeIndex, trailer_flags: TrailerFlags) usize {
1132 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);1228 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len) + trailer_flags.sizeInBytes();
1133 }1229 }
1134 };1230 };
11351231
...@@ -2829,6 +2925,9 @@ pub const Node = struct {...@@ -2829,6 +2925,9 @@ pub const Node = struct {
2829 }2925 }
2830 };2926 };
28312927
2928 /// TODO remove from the Node base struct
2929 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
2930 /// and forwards to find same-line doc comments.
2832 pub const DocComment = struct {2931 pub const DocComment = struct {
2833 base: Node = Node{ .id = .DocComment },2932 base: Node = Node{ .id = .DocComment },
2834 /// Points to the first doc comment token. API users are expected to iterate over the2933 /// Points to the first doc comment token. API users are expected to iterate over the
lib/std/zig/parse.zig+92-100
...@@ -150,7 +150,7 @@ const Parser = struct {...@@ -150,7 +150,7 @@ const Parser = struct {
150150
151 const visib_token = p.eatToken(.Keyword_pub);151 const visib_token = p.eatToken(.Keyword_pub);
152152
153 if (p.parseTopLevelDecl() catch |err| switch (err) {153 if (p.parseTopLevelDecl(doc_comments, visib_token) catch |err| switch (err) {
154 error.OutOfMemory => return error.OutOfMemory,154 error.OutOfMemory => return error.OutOfMemory,
155 error.ParseError => {155 error.ParseError => {
156 p.findNextContainerMember();156 p.findNextContainerMember();
...@@ -160,30 +160,7 @@ const Parser = struct {...@@ -160,30 +160,7 @@ const Parser = struct {
160 if (field_state == .seen) {160 if (field_state == .seen) {
161 field_state = .{ .end = visib_token orelse node.firstToken() };161 field_state = .{ .end = visib_token orelse node.firstToken() };
162 }162 }
163 switch (node.id) {
164 .FnProto => {
165 node.cast(Node.FnProto).?.doc_comments = doc_comments;
166 node.cast(Node.FnProto).?.visib_token = visib_token;
167 },
168 .VarDecl => {
169 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
170 node.cast(Node.VarDecl).?.visib_token = visib_token;
171 },
172 .Use => {
173 node.cast(Node.Use).?.doc_comments = doc_comments;
174 node.cast(Node.Use).?.visib_token = visib_token;
175 },
176 else => unreachable,
177 }
178 try list.append(node);163 try list.append(node);
179 if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| {
180 switch (node.id) {
181 .FnProto => {},
182 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
183 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
184 else => unreachable,
185 }
186 }
187 continue;164 continue;
188 }165 }
189166
...@@ -417,7 +394,7 @@ const Parser = struct {...@@ -417,7 +394,7 @@ const Parser = struct {
417 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)394 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
418 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl395 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
419 /// / KEYWORD_usingnamespace Expr SEMICOLON396 /// / KEYWORD_usingnamespace Expr SEMICOLON
420 fn parseTopLevelDecl(p: *Parser) !?*Node {397 fn parseTopLevelDecl(p: *Parser, doc_comments: ?*Node.DocComment, visib_token: ?TokenIndex) !?*Node {
421 var lib_name: ?*Node = null;398 var lib_name: ?*Node = null;
422 const extern_export_inline_token = blk: {399 const extern_export_inline_token = blk: {
423 if (p.eatToken(.Keyword_export)) |token| break :blk token;400 if (p.eatToken(.Keyword_export)) |token| break :blk token;
...@@ -430,20 +407,12 @@ const Parser = struct {...@@ -430,20 +407,12 @@ const Parser = struct {
430 break :blk null;407 break :blk null;
431 };408 };
432409
433 if (try p.parseFnProto()) |node| {410 if (try p.parseFnProto(.top_level, .{
434 const fn_node = node.cast(Node.FnProto).?;411 .doc_comments = doc_comments,
435 fn_node.*.extern_export_inline_token = extern_export_inline_token;412 .visib_token = visib_token,
436 fn_node.*.lib_name = lib_name;413 .extern_export_inline_token = extern_export_inline_token,
437 if (p.eatToken(.Semicolon)) |_| return node;414 .lib_name = lib_name,
438415 })) |node| {
439 if (try p.expectNodeRecoverable(parseBlock, .{
440 // since parseBlock only return error.ParseError on
441 // a missing '}' we can assume this function was
442 // supposed to end here.
443 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
444 })) |body_node| {
445 fn_node.body_node = body_node;
446 }
447 return node;416 return node;
448 }417 }
449418
...@@ -460,12 +429,13 @@ const Parser = struct {...@@ -460,12 +429,13 @@ const Parser = struct {
460429
461 const thread_local_token = p.eatToken(.Keyword_threadlocal);430 const thread_local_token = p.eatToken(.Keyword_threadlocal);
462431
463 if (try p.parseVarDecl()) |node| {432 if (try p.parseVarDecl(.{
464 var var_decl = node.cast(Node.VarDecl).?;433 .doc_comments = doc_comments,
465 var_decl.*.thread_local_token = thread_local_token;434 .visib_token = visib_token,
466 var_decl.*.comptime_token = null;435 .thread_local_token = thread_local_token,
467 var_decl.*.extern_export_token = extern_export_inline_token;436 .extern_export_token = extern_export_inline_token,
468 var_decl.*.lib_name = lib_name;437 .lib_name = lib_name,
438 })) |node| {
469 return node;439 return node;
470 }440 }
471441
...@@ -485,21 +455,41 @@ const Parser = struct {...@@ -485,21 +455,41 @@ const Parser = struct {
485 return error.ParseError;455 return error.ParseError;
486 }456 }
487457
488 return p.parseUse();458 const use_token = p.eatToken(.Keyword_usingnamespace) orelse return null;
459 const expr = try p.expectNode(parseExpr, .{
460 .ExpectedExpr = .{ .token = p.tok_i },
461 });
462 const semicolon_token = try p.expectToken(.Semicolon);
463
464 const node = try p.arena.allocator.create(Node.Use);
465 node.* = .{
466 .doc_comments = doc_comments orelse try p.parseAppendedDocComment(semicolon_token),
467 .visib_token = visib_token,
468 .use_token = use_token,
469 .expr = expr,
470 .semicolon_token = semicolon_token,
471 };
472
473 return &node.base;
489 }474 }
490475
491 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)476 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
492 fn parseFnProto(p: *Parser) !?*Node {477 fn parseFnProto(p: *Parser, level: enum { top_level, as_type }, fields: struct {
478 doc_comments: ?*Node.DocComment = null,
479 visib_token: ?TokenIndex = null,
480 extern_export_inline_token: ?TokenIndex = null,
481 lib_name: ?*Node = null,
482 }) !?*Node {
493 // TODO: Remove once extern/async fn rewriting is483 // TODO: Remove once extern/async fn rewriting is
494 var is_async = false;484 var is_async: ?void = null;
495 var is_extern = false;485 var is_extern_prototype: ?void = null;
496 const cc_token: ?TokenIndex = blk: {486 const cc_token: ?TokenIndex = blk: {
497 if (p.eatToken(.Keyword_extern)) |token| {487 if (p.eatToken(.Keyword_extern)) |token| {
498 is_extern = true;488 is_extern_prototype = {};
499 break :blk token;489 break :blk token;
500 }490 }
501 if (p.eatToken(.Keyword_async)) |token| {491 if (p.eatToken(.Keyword_async)) |token| {
502 is_async = true;492 is_async = {};
503 break :blk token;493 break :blk token;
504 }494 }
505 break :blk null;495 break :blk null;
...@@ -513,6 +503,7 @@ const Parser = struct {...@@ -513,6 +503,7 @@ const Parser = struct {
513 const lparen = try p.expectToken(.LParen);503 const lparen = try p.expectToken(.LParen);
514 const params = try p.parseParamDeclList();504 const params = try p.parseParamDeclList();
515 defer p.gpa.free(params);505 defer p.gpa.free(params);
506 const var_args_token = p.eatToken(.Ellipsis3);
516 const rparen = try p.expectToken(.RParen);507 const rparen = try p.expectToken(.RParen);
517 const align_expr = try p.parseByteAlign();508 const align_expr = try p.parseByteAlign();
518 const section_expr = try p.parseLinkSection();509 const section_expr = try p.parseLinkSection();
...@@ -535,37 +526,53 @@ const Parser = struct {...@@ -535,37 +526,53 @@ const Parser = struct {
535 else526 else
536 R{ .Explicit = return_type_expr.? };527 R{ .Explicit = return_type_expr.? };
537528
538 const var_args_token = if (params.len > 0) blk: {529 const body_node: ?*Node = switch (level) {
539 const param_type = params[params.len - 1].param_type;530 .top_level => blk: {
540 break :blk if (param_type == .var_args) param_type.var_args else null;531 if (p.eatToken(.Semicolon)) |_| {
541 } else532 break :blk null;
542 null;533 }
534 break :blk try p.expectNodeRecoverable(parseBlock, .{
535 // Since parseBlock only return error.ParseError on
536 // a missing '}' we can assume this function was
537 // supposed to end here.
538 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
539 });
540 },
541 .as_type => null,
542 };
543543
544 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);544 const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{
545 fn_proto_node.* = .{
546 .doc_comments = null,
547 .visib_token = null,
548 .fn_token = fn_token,
549 .name_token = name_token,
550 .params_len = params.len,545 .params_len = params.len,
546 .fn_token = fn_token,
551 .return_type = return_type,547 .return_type = return_type,
548 }, .{
549 .doc_comments = fields.doc_comments,
550 .visib_token = fields.visib_token,
551 .name_token = name_token,
552 .var_args_token = var_args_token,552 .var_args_token = var_args_token,
553 .extern_export_inline_token = null,553 .extern_export_inline_token = fields.extern_export_inline_token,
554 .body_node = null,554 .body_node = body_node,
555 .lib_name = null,555 .lib_name = fields.lib_name,
556 .align_expr = align_expr,556 .align_expr = align_expr,
557 .section_expr = section_expr,557 .section_expr = section_expr,
558 .callconv_expr = callconv_expr,558 .callconv_expr = callconv_expr,
559 .is_extern_prototype = is_extern,559 .is_extern_prototype = is_extern_prototype,
560 .is_async = is_async,560 .is_async = is_async,
561 };561 });
562 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);562 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
563563
564 return &fn_proto_node.base;564 return &fn_proto_node.base;
565 }565 }
566566
567 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON567 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
568 fn parseVarDecl(p: *Parser) !?*Node {568 fn parseVarDecl(p: *Parser, fields: struct {
569 doc_comments: ?*Node.DocComment = null,
570 visib_token: ?TokenIndex = null,
571 thread_local_token: ?TokenIndex = null,
572 extern_export_token: ?TokenIndex = null,
573 lib_name: ?*Node = null,
574 comptime_token: ?TokenIndex = null,
575 }) !?*Node {
569 const mut_token = p.eatToken(.Keyword_const) orelse576 const mut_token = p.eatToken(.Keyword_const) orelse
570 p.eatToken(.Keyword_var) orelse577 p.eatToken(.Keyword_var) orelse
571 return null;578 return null;
...@@ -587,23 +594,25 @@ const Parser = struct {...@@ -587,23 +594,25 @@ const Parser = struct {
587 } else null;594 } else null;
588 const semicolon_token = try p.expectToken(.Semicolon);595 const semicolon_token = try p.expectToken(.Semicolon);
589596
590 const node = try p.arena.allocator.create(Node.VarDecl);597 const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token);
591 node.* = .{598
592 .doc_comments = null,599 const node = try Node.VarDecl.create(&p.arena.allocator, .{
593 .visib_token = null,600 .mut_token = mut_token,
594 .thread_local_token = null,
595 .name_token = name_token,601 .name_token = name_token,
602 .semicolon_token = semicolon_token,
603 }, .{
604 .doc_comments = doc_comments,
605 .visib_token = fields.visib_token,
606 .thread_local_token = fields.thread_local_token,
596 .eq_token = eq_token,607 .eq_token = eq_token,
597 .mut_token = mut_token,608 .comptime_token = fields.comptime_token,
598 .comptime_token = null,609 .extern_export_token = fields.extern_export_token,
599 .extern_export_token = null,610 .lib_name = fields.lib_name,
600 .lib_name = null,
601 .type_node = type_node,611 .type_node = type_node,
602 .align_node = align_node,612 .align_node = align_node,
603 .section_node = section_node,613 .section_node = section_node,
604 .init_node = init_node,614 .init_node = init_node,
605 .semicolon_token = semicolon_token,615 });
606 };
607 return &node.base;616 return &node.base;
608 }617 }
609618
...@@ -663,10 +672,9 @@ const Parser = struct {...@@ -663,10 +672,9 @@ const Parser = struct {
663 fn parseStatement(p: *Parser) Error!?*Node {672 fn parseStatement(p: *Parser) Error!?*Node {
664 const comptime_token = p.eatToken(.Keyword_comptime);673 const comptime_token = p.eatToken(.Keyword_comptime);
665674
666 const var_decl_node = try p.parseVarDecl();675 if (try p.parseVarDecl(.{
667 if (var_decl_node) |node| {676 .comptime_token = comptime_token,
668 const var_decl = node.cast(Node.VarDecl).?;677 })) |node| {
669 var_decl.comptime_token = comptime_token;
670 return node;678 return node;
671 }679 }
672680
...@@ -1527,7 +1535,7 @@ const Parser = struct {...@@ -1527,7 +1535,7 @@ const Parser = struct {
1527 if (try p.parseAnonLiteral()) |node| return node;1535 if (try p.parseAnonLiteral()) |node| return node;
1528 if (try p.parseErrorSetDecl()) |node| return node;1536 if (try p.parseErrorSetDecl()) |node| return node;
1529 if (try p.parseFloatLiteral()) |node| return node;1537 if (try p.parseFloatLiteral()) |node| return node;
1530 if (try p.parseFnProto()) |node| return node;1538 if (try p.parseFnProto(.as_type, .{})) |node| return node;
1531 if (try p.parseGroupedExpr()) |node| return node;1539 if (try p.parseGroupedExpr()) |node| return node;
1532 if (try p.parseLabeledTypeExpr()) |node| return node;1540 if (try p.parseLabeledTypeExpr()) |node| return node;
1533 if (try p.parseIdentifier()) |node| return node;1541 if (try p.parseIdentifier()) |node| return node;
...@@ -2028,7 +2036,6 @@ const Parser = struct {...@@ -2028,7 +2036,6 @@ const Parser = struct {
2028 // TODO cast from tuple to error union is broken2036 // TODO cast from tuple to error union is broken
2029 const P = Node.FnProto.ParamDecl.ParamType;2037 const P = Node.FnProto.ParamDecl.ParamType;
2030 if (try p.parseAnyType()) |node| return P{ .any_type = node };2038 if (try p.parseAnyType()) |node| return P{ .any_type = node };
2031 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
2032 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };2039 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
2033 return null;2040 return null;
2034 }2041 }
...@@ -3149,21 +3156,6 @@ const Parser = struct {...@@ -3149,21 +3156,6 @@ const Parser = struct {
3149 return &node.base;3156 return &node.base;
3150 }3157 }
31513158
3152 fn parseUse(p: *Parser) !?*Node {
3153 const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
3154 const node = try p.arena.allocator.create(Node.Use);
3155 node.* = .{
3156 .doc_comments = null,
3157 .visib_token = null,
3158 .use_token = token,
3159 .expr = try p.expectNode(parseExpr, .{
3160 .ExpectedExpr = .{ .token = p.tok_i },
3161 }),
3162 .semicolon_token = try p.expectToken(.Semicolon),
3163 };
3164 return &node.base;
3165 }
3166
3167 /// IfPrefix Body (KEYWORD_else Payload? Body)?3159 /// IfPrefix Body (KEYWORD_else Payload? Body)?
3168 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {3160 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
3169 const node = (try p.parseIfPrefix()) orelse return null;3161 const node = (try p.parseIfPrefix()) orelse return null;
lib/std/zig/parser_test.zig+32-27
...@@ -1,4 +1,32 @@...@@ -1,4 +1,32 @@
1const builtin = @import("builtin");1test "zig fmt: convert var to anytype" {
2 // TODO remove in next release cycle
3 try testTransform(
4 \\pub fn main(
5 \\ a: var,
6 \\ bar: var,
7 \\) void {}
8 ,
9 \\pub fn main(
10 \\ a: anytype,
11 \\ bar: anytype,
12 \\) void {}
13 \\
14 );
15}
16
17test "zig fmt: noasync to nosuspend" {
18 // TODO: remove this
19 try testTransform(
20 \\pub fn main() void {
21 \\ noasync call();
22 \\}
23 ,
24 \\pub fn main() void {
25 \\ nosuspend call();
26 \\}
27 \\
28 );
29}
230
3test "recovery: top level" {31test "recovery: top level" {
4 try testError(32 try testError(
...@@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {...@@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
3146 );3174 );
3147}3175}
31483176
3149test "zig fmt: noasync to nosuspend" {
3150 // TODO: remove this
3151 try testTransform(
3152 \\pub fn main() void {
3153 \\ noasync call();
3154 \\}
3155 ,
3156 \\pub fn main() void {
3157 \\ nosuspend call();
3158 \\}
3159 \\
3160 );
3161}
3162
3163test "zig fmt: convert async fn into callconv(.Async)" {3177test "zig fmt: convert async fn into callconv(.Async)" {
3164 try testTransform(3178 try testTransform(
3165 \\async fn foo() void {}3179 \\async fn foo() void {}
...@@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" {...@@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" {
3180 );3194 );
3181}3195}
31823196
3183test "zig fmt: convert var to anytype" {3197test "zig fmt: C var args" {
3184 // TODO remove in next release cycle3198 try testCanonical(
3185 try testTransform(3199 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3186 \\pub fn main(
3187 \\ a: var,
3188 \\ bar: var,
3189 \\) void {}
3190 ,
3191 \\pub fn main(
3192 \\ a: anytype,
3193 \\ bar: anytype,
3194 \\) void {}
3195 \\3200 \\
3196 );3201 );
3197}3202}
lib/std/zig/render.zig+52-40
...@@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
227 .FnProto => {227 .FnProto => {
228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
229229
230 try renderDocComments(tree, stream, fn_proto, indent, start_col);230 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col);
231231
232 if (fn_proto.body_node) |body_node| {232 if (fn_proto.getTrailer("body_node")) |body_node| {
233 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);233 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
234 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);234 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
235 } else {235 } else {
...@@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
252 .VarDecl => {252 .VarDecl => {
253 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);253 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
254254
255 try renderDocComments(tree, stream, var_decl, indent, start_col);255 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col);
256 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);256 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
257 },257 },
258258
259 .TestDecl => {259 .TestDecl => {
260 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);260 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
261261
262 try renderDocComments(tree, stream, test_decl, indent, start_col);262 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col);
263 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);263 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
264 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);264 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
265 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);265 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);
...@@ -268,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -268,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
268 .ContainerField => {268 .ContainerField => {
269 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);269 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
270270
271 try renderDocComments(tree, stream, field, indent, start_col);271 try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col);
272 if (field.comptime_token) |t| {272 if (field.comptime_token) |t| {
273 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime273 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
274 }274 }
...@@ -1409,7 +1409,7 @@ fn renderExpression(...@@ -1409,7 +1409,7 @@ fn renderExpression(
1409 .ErrorTag => {1409 .ErrorTag => {
1410 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);1410 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
14111411
1412 try renderDocComments(tree, stream, tag, indent, start_col);1412 try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col);
1413 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name1413 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
1414 },1414 },
14151415
...@@ -1483,23 +1483,23 @@ fn renderExpression(...@@ -1483,23 +1483,23 @@ fn renderExpression(
1483 .FnProto => {1483 .FnProto => {
1484 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);1484 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14851485
1486 if (fn_proto.visib_token) |visib_token_index| {1486 if (fn_proto.getTrailer("visib_token")) |visib_token_index| {
1487 const visib_token = tree.token_ids[visib_token_index];1487 const visib_token = tree.token_ids[visib_token_index];
1488 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);1488 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14891489
1490 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub1490 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
1491 }1491 }
14921492
1493 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {1493 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
1494 if (!fn_proto.is_extern_prototype)1494 if (fn_proto.getTrailer("is_extern_prototype") == null)
1495 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline1495 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
1496 }1496 }
14971497
1498 if (fn_proto.lib_name) |lib_name| {1498 if (fn_proto.getTrailer("lib_name")) |lib_name| {
1499 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);1499 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
1500 }1500 }
15011501
1502 const lparen = if (fn_proto.name_token) |name_token| blk: {1502 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
1503 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1503 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1504 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name1504 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
1505 break :blk tree.nextToken(name_token);1505 break :blk tree.nextToken(name_token);
...@@ -1512,11 +1512,11 @@ fn renderExpression(...@@ -1512,11 +1512,11 @@ fn renderExpression(
1512 const rparen = tree.prevToken(1512 const rparen = tree.prevToken(
1513 // the first token for the annotation expressions is the left1513 // the first token for the annotation expressions is the left
1514 // parenthesis, hence the need for two prevToken1514 // parenthesis, hence the need for two prevToken
1515 if (fn_proto.align_expr) |align_expr|1515 if (fn_proto.getTrailer("align_expr")) |align_expr|
1516 tree.prevToken(tree.prevToken(align_expr.firstToken()))1516 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1517 else if (fn_proto.section_expr) |section_expr|1517 else if (fn_proto.getTrailer("section_expr")) |section_expr|
1518 tree.prevToken(tree.prevToken(section_expr.firstToken()))1518 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1519 else if (fn_proto.callconv_expr) |callconv_expr|1519 else if (fn_proto.getTrailer("callconv_expr")) |callconv_expr|
1520 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))1520 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1521 else switch (fn_proto.return_type) {1521 else switch (fn_proto.return_type) {
1522 .Explicit => |node| node.firstToken(),1522 .Explicit => |node| node.firstToken(),
...@@ -1537,11 +1537,14 @@ fn renderExpression(...@@ -1537,11 +1537,14 @@ fn renderExpression(
1537 for (fn_proto.params()) |param_decl, i| {1537 for (fn_proto.params()) |param_decl, i| {
1538 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);1538 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
15391539
1540 if (i + 1 < fn_proto.params_len) {1540 if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {
1541 const comma = tree.nextToken(param_decl.lastToken());1541 const comma = tree.nextToken(param_decl.lastToken());
1542 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,1542 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
1543 }1543 }
1544 }1544 }
1545 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1546 try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);
1547 }
1545 } else {1548 } else {
1546 // one param per line1549 // one param per line
1547 const new_indent = indent + indent_delta;1550 const new_indent = indent + indent_delta;
...@@ -1551,12 +1554,16 @@ fn renderExpression(...@@ -1551,12 +1554,16 @@ fn renderExpression(
1551 try stream.writeByteNTimes(' ', new_indent);1554 try stream.writeByteNTimes(' ', new_indent);
1552 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);1555 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1553 }1556 }
1557 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1558 try stream.writeByteNTimes(' ', new_indent);
1559 try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
1560 }
1554 try stream.writeByteNTimes(' ', indent);1561 try stream.writeByteNTimes(' ', indent);
1555 }1562 }
15561563
1557 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1564 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
15581565
1559 if (fn_proto.align_expr) |align_expr| {1566 if (fn_proto.getTrailer("align_expr")) |align_expr| {
1560 const align_rparen = tree.nextToken(align_expr.lastToken());1567 const align_rparen = tree.nextToken(align_expr.lastToken());
1561 const align_lparen = tree.prevToken(align_expr.firstToken());1568 const align_lparen = tree.prevToken(align_expr.firstToken());
1562 const align_kw = tree.prevToken(align_lparen);1569 const align_kw = tree.prevToken(align_lparen);
...@@ -1567,7 +1574,7 @@ fn renderExpression(...@@ -1567,7 +1574,7 @@ fn renderExpression(
1567 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )1574 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
1568 }1575 }
15691576
1570 if (fn_proto.section_expr) |section_expr| {1577 if (fn_proto.getTrailer("section_expr")) |section_expr| {
1571 const section_rparen = tree.nextToken(section_expr.lastToken());1578 const section_rparen = tree.nextToken(section_expr.lastToken());
1572 const section_lparen = tree.prevToken(section_expr.firstToken());1579 const section_lparen = tree.prevToken(section_expr.firstToken());
1573 const section_kw = tree.prevToken(section_lparen);1580 const section_kw = tree.prevToken(section_lparen);
...@@ -1578,7 +1585,7 @@ fn renderExpression(...@@ -1578,7 +1585,7 @@ fn renderExpression(
1578 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )1585 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
1579 }1586 }
15801587
1581 if (fn_proto.callconv_expr) |callconv_expr| {1588 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
1582 const callconv_rparen = tree.nextToken(callconv_expr.lastToken());1589 const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
1583 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());1590 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
1584 const callconv_kw = tree.prevToken(callconv_lparen);1591 const callconv_kw = tree.prevToken(callconv_lparen);
...@@ -1587,9 +1594,9 @@ fn renderExpression(...@@ -1587,9 +1594,9 @@ fn renderExpression(
1587 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (1594 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
1588 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);1595 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
1589 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )1596 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
1590 } else if (fn_proto.is_extern_prototype) {1597 } else if (fn_proto.getTrailer("is_extern_prototype") != null) {
1591 try stream.writeAll("callconv(.C) ");1598 try stream.writeAll("callconv(.C) ");
1592 } else if (fn_proto.is_async) {1599 } else if (fn_proto.getTrailer("is_async") != null) {
1593 try stream.writeAll("callconv(.Async) ");1600 try stream.writeAll("callconv(.Async) ");
1594 }1601 }
15951602
...@@ -2177,64 +2184,69 @@ fn renderVarDecl(...@@ -2177,64 +2184,69 @@ fn renderVarDecl(
2177 start_col: *usize,2184 start_col: *usize,
2178 var_decl: *ast.Node.VarDecl,2185 var_decl: *ast.Node.VarDecl,
2179) (@TypeOf(stream).Error || Error)!void {2186) (@TypeOf(stream).Error || Error)!void {
2180 if (var_decl.visib_token) |visib_token| {2187 if (var_decl.getTrailer("visib_token")) |visib_token| {
2181 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub2188 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
2182 }2189 }
21832190
2184 if (var_decl.extern_export_token) |extern_export_token| {2191 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
2185 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern2192 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
21862193
2187 if (var_decl.lib_name) |lib_name| {2194 if (var_decl.getTrailer("lib_name")) |lib_name| {
2188 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"2195 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
2189 }2196 }
2190 }2197 }
21912198
2192 if (var_decl.comptime_token) |comptime_token| {2199 if (var_decl.getTrailer("comptime_token")) |comptime_token| {
2193 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime2200 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
2194 }2201 }
21952202
2196 if (var_decl.thread_local_token) |thread_local_token| {2203 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
2197 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal2204 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
2198 }2205 }
2199 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var2206 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
22002207
2201 const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or2208 const name_space = if (var_decl.getTrailer("type_node") == null and
2202 var_decl.section_node != null or var_decl.init_node != null)) Space.Space else Space.None;2209 (var_decl.getTrailer("align_node") != null or
2210 var_decl.getTrailer("section_node") != null or
2211 var_decl.getTrailer("init_node") != null))
2212 Space.Space
2213 else
2214 Space.None;
2203 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);2215 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
22042216
2205 if (var_decl.type_node) |type_node| {2217 if (var_decl.getTrailer("type_node")) |type_node| {
2206 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);2218 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
2207 const s = if (var_decl.align_node != null or2219 const s = if (var_decl.getTrailer("align_node") != null or
2208 var_decl.section_node != null or2220 var_decl.getTrailer("section_node") != null or
2209 var_decl.init_node != null) Space.Space else Space.None;2221 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2210 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);2222 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
2211 }2223 }
22122224
2213 if (var_decl.align_node) |align_node| {2225 if (var_decl.getTrailer("align_node")) |align_node| {
2214 const lparen = tree.prevToken(align_node.firstToken());2226 const lparen = tree.prevToken(align_node.firstToken());
2215 const align_kw = tree.prevToken(lparen);2227 const align_kw = tree.prevToken(lparen);
2216 const rparen = tree.nextToken(align_node.lastToken());2228 const rparen = tree.nextToken(align_node.lastToken());
2217 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align2229 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
2218 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2230 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
2219 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);2231 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
2220 const s = if (var_decl.section_node != null or var_decl.init_node != null) Space.Space else Space.None;2232 const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2221 try renderToken(tree, stream, rparen, indent, start_col, s); // )2233 try renderToken(tree, stream, rparen, indent, start_col, s); // )
2222 }2234 }
22232235
2224 if (var_decl.section_node) |section_node| {2236 if (var_decl.getTrailer("section_node")) |section_node| {
2225 const lparen = tree.prevToken(section_node.firstToken());2237 const lparen = tree.prevToken(section_node.firstToken());
2226 const section_kw = tree.prevToken(lparen);2238 const section_kw = tree.prevToken(lparen);
2227 const rparen = tree.nextToken(section_node.lastToken());2239 const rparen = tree.nextToken(section_node.lastToken());
2228 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection2240 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
2229 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2241 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
2230 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);2242 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);
2231 const s = if (var_decl.init_node != null) Space.Space else Space.None;2243 const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2232 try renderToken(tree, stream, rparen, indent, start_col, s); // )2244 try renderToken(tree, stream, rparen, indent, start_col, s); // )
2233 }2245 }
22342246
2235 if (var_decl.init_node) |init_node| {2247 if (var_decl.getTrailer("init_node")) |init_node| {
2236 const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;2248 const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;
2237 try renderToken(tree, stream, var_decl.eq_token.?, indent, start_col, s); // =2249 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
2238 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);2250 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
2239 }2251 }
22402252
...@@ -2250,7 +2262,7 @@ fn renderParamDecl(...@@ -2250,7 +2262,7 @@ fn renderParamDecl(
2250 param_decl: ast.Node.FnProto.ParamDecl,2262 param_decl: ast.Node.FnProto.ParamDecl,
2251 space: Space,2263 space: Space,
2252) (@TypeOf(stream).Error || Error)!void {2264) (@TypeOf(stream).Error || Error)!void {
2253 try renderDocComments(tree, stream, param_decl, indent, start_col);2265 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);
22542266
2255 if (param_decl.comptime_token) |comptime_token| {2267 if (param_decl.comptime_token) |comptime_token| {
2256 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);2268 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
...@@ -2263,7 +2275,6 @@ fn renderParamDecl(...@@ -2263,7 +2275,6 @@ fn renderParamDecl(
2263 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :2275 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
2264 }2276 }
2265 switch (param_decl.param_type) {2277 switch (param_decl.param_type) {
2266 .var_args => |token| try renderToken(tree, stream, token, indent, start_col, space),
2267 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),2278 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
2268 }2279 }
2269}2280}
...@@ -2519,10 +2530,11 @@ fn renderDocComments(...@@ -2519,10 +2530,11 @@ fn renderDocComments(
2519 tree: *ast.Tree,2530 tree: *ast.Tree,
2520 stream: anytype,2531 stream: anytype,
2521 node: anytype,2532 node: anytype,
2533 doc_comments: ?*ast.Node.DocComment,
2522 indent: usize,2534 indent: usize,
2523 start_col: *usize,2535 start_col: *usize,
2524) (@TypeOf(stream).Error || Error)!void {2536) (@TypeOf(stream).Error || Error)!void {
2525 const comment = node.doc_comments orelse return;2537 const comment = doc_comments orelse return;
2526 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);2538 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
2527}2539}
25282540
src-self-hosted/Module.zig+12-10
...@@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1130 };1130 };
1131 defer fn_type_scope.instructions.deinit(self.gpa);1131 defer fn_type_scope.instructions.deinit(self.gpa);
11321132
1133 const body_node = fn_proto.body_node orelse1133 const body_node = fn_proto.getTrailer("body_node") orelse
1134 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});1134 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
11351135
1136 const param_decls = fn_proto.params();1136 const param_decls = fn_proto.params();
...@@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1138 for (param_decls) |param_decl, i| {1138 for (param_decls) |param_decl, i| {
1139 const param_type_node = switch (param_decl.param_type) {1139 const param_type_node = switch (param_decl.param_type) {
1140 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),1140 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
1141 .var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}),
1142 .type_expr => |node| node,1141 .type_expr => |node| node,
1143 };1142 };
1144 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);1143 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
1145 }1144 }
1146 if (fn_proto.lib_name) |lib_name| {1145 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1146 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
1147 }
1148 if (fn_proto.getTrailer("lib_name")) |lib_name| {
1147 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});1149 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
1148 }1150 }
1149 if (fn_proto.align_expr) |align_expr| {1151 if (fn_proto.getTrailer("align_expr")) |align_expr| {
1150 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});1152 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
1151 }1153 }
1152 if (fn_proto.section_expr) |sect_expr| {1154 if (fn_proto.getTrailer("section_expr")) |sect_expr| {
1153 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});1155 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
1154 }1156 }
1155 if (fn_proto.callconv_expr) |callconv_expr| {1157 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
1156 return self.failNode(1158 return self.failNode(
1157 &fn_type_scope.base,1159 &fn_type_scope.base,
1158 callconv_expr,1160 callconv_expr,
...@@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1265 self.bin_file.freeDecl(decl);1267 self.bin_file.freeDecl(decl);
1266 }1268 }
12671269
1268 if (fn_proto.extern_export_inline_token) |maybe_export_token| {1270 if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
1269 if (tree.token_ids[maybe_export_token] == .Keyword_export) {1271 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1270 const export_src = tree.token_locs[maybe_export_token].start;1272 const export_src = tree.token_locs[maybe_export_token].start;
1271 const name_loc = tree.token_locs[fn_proto.name_token.?];1273 const name_loc = tree.token_locs[fn_proto.getTrailer("name_token").?];
1272 const name = tree.tokenSliceLoc(name_loc);1274 const name = tree.tokenSliceLoc(name_loc);
1273 // The scope needs to have the decl in it.1275 // The scope needs to have the decl in it.
1274 try self.analyzeExport(&block_scope.base, export_src, name, decl);1276 try self.analyzeExport(&block_scope.base, export_src, name, decl);
...@@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1867 for (decls) |src_decl, decl_i| {1869 for (decls) |src_decl, decl_i| {
1868 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {1870 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
1869 // We will create a Decl for it regardless of analysis status.1871 // We will create a Decl for it regardless of analysis status.
1870 const name_tok = fn_proto.name_token orelse {1872 const name_tok = fn_proto.getTrailer("name_token") orelse {
1871 @panic("TODO missing function name");1873 @panic("TODO missing function name");
1872 };1874 };
18731875
...@@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1893 } else {1895 } else {
1894 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);1896 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1895 root_scope.decls.appendAssumeCapacity(new_decl);1897 root_scope.decls.appendAssumeCapacity(new_decl);
1896 if (fn_proto.extern_export_inline_token) |maybe_export_token| {1898 if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
1897 if (tree.token_ids[maybe_export_token] == .Keyword_export) {1899 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1898 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });1900 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1899 }1901 }
src-self-hosted/translate_c.zig+279-183
...@@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
586 for (proto_node.params()) |*param, i| {586 for (proto_node.params()) |*param, i| {
587 const param_name = if (param.name_token) |name_tok|587 const param_name = if (param.name_token) |name_tok|
588 tokenSlice(c, name_tok)588 tokenSlice(c, name_tok)
589 else if (param.param_type == .var_args) {589 else
590 assert(i + 1 == proto_node.params_len);
591 proto_node.params_len -= 1;
592 break;
593 } else
594 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});590 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
595591
596 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);592 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
...@@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
602 if (!is_const) {598 if (!is_const) {
603 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});599 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});
604 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);600 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
605 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);601
606 node.eq_token = try appendToken(c, .Equal, "=");602 const mut_tok = try appendToken(c, .Keyword_var, "var");
607 node.init_node = try transCreateNodeIdentifier(c, arg_name);603 const name_tok = try appendIdentifier(c, mangled_param_name);
608 node.semicolon_token = try appendToken(c, .Semicolon, ";");604 const eq_token = try appendToken(c, .Equal, "=");
605 const init_node = try transCreateNodeIdentifier(c, arg_name);
606 const semicolon_token = try appendToken(c, .Semicolon, ";");
607 const node = try ast.Node.VarDecl.create(c.arena, .{
608 .mut_token = mut_tok,
609 .name_token = name_tok,
610 .semicolon_token = semicolon_token,
611 }, .{
612 .eq_token = eq_token,
613 .init_node = init_node,
614 });
609 try block_scope.statements.append(&node.base);615 try block_scope.statements.append(&node.base);
610 param.name_token = try appendIdentifier(c, arg_name);616 param.name_token = try appendIdentifier(c, arg_name);
611 _ = try appendToken(c, .Colon, ":");617 _ = try appendToken(c, .Colon, ":");
...@@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
622 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),628 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
623 };629 };
624 const body_node = try block_scope.complete(rp.c);630 const body_node = try block_scope.complete(rp.c);
625 proto_node.body_node = &body_node.base;631 proto_node.setTrailer("body_node", &body_node.base);
626 return addTopLevelDecl(c, fn_name, &proto_node.base);632 return addTopLevelDecl(c, fn_name, &proto_node.base);
627}633}
628634
...@@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
725 break :blk null;731 break :blk null;
726 };732 };
727733
728 const node = try c.arena.create(ast.Node.VarDecl);734 const node = try ast.Node.VarDecl.create(c.arena, .{
729 node.* = .{735 .name_token = name_tok,
730 .doc_comments = null,736 .mut_token = mut_tok,
737 .semicolon_token = try appendToken(c, .Semicolon, ";"),
738 }, .{
731 .visib_token = visib_tok,739 .visib_token = visib_tok,
732 .thread_local_token = thread_local_token,740 .thread_local_token = thread_local_token,
733 .name_token = name_tok,
734 .eq_token = eq_tok,741 .eq_token = eq_tok,
735 .mut_token = mut_tok,
736 .comptime_token = null,
737 .extern_export_token = extern_tok,742 .extern_export_token = extern_tok,
738 .lib_name = null,
739 .type_node = type_node,743 .type_node = type_node,
740 .align_node = align_expr,744 .align_node = align_expr,
741 .section_node = linksection_expr,745 .section_node = linksection_expr,
742 .init_node = init_node,746 .init_node = init_node,
743 .semicolon_token = try appendToken(c, .Semicolon, ";"),747 });
744 };
745 return addTopLevelDecl(c, checked_name, &node.base);748 return addTopLevelDecl(c, checked_name, &node.base);
746}749}
747750
...@@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l...@@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
795798
796 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);799 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
797 const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;800 const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
798 try addTopLevelDecl(c, checked_name, &node.base);801 try addTopLevelDecl(c, checked_name, node);
799 return transCreateNodeIdentifier(c, checked_name);802 return transCreateNodeIdentifier(c, checked_name);
800}803}
801804
802fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl {805fn transCreateNodeTypedef(
803 const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name);806 rp: RestorePoint,
804 node.eq_token = try appendToken(rp.c, .Equal, "=");807 typedef_decl: *const ZigClangTypedefNameDecl,
805808 toplevel: bool,
809 checked_name: []const u8,
810) Error!?*ast.Node {
811 const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null;
812 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
813 const name_tok = try appendIdentifier(rp.c, checked_name);
814 const eq_token = try appendToken(rp.c, .Equal, "=");
806 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);815 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
807 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);816 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
808 node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {817 const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
809 error.UnsupportedType => {818 error.UnsupportedType => {
810 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});819 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
811 return null;820 return null;
812 },821 },
813 error.OutOfMemory => |e| return e,822 error.OutOfMemory => |e| return e,
814 };823 };
824 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
815825
816 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");826 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
817 return node;827 .name_token = name_tok,
828 .mut_token = mut_tok,
829 .semicolon_token = semicolon_token,
830 }, .{
831 .visib_token = visib_tok,
832 .eq_token = eq_token,
833 .init_node = init_node,
834 });
835 return &node.base;
818}836}
819837
820fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {838fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
...@@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
847 const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });865 const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
848 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);866 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
849867
850 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);868 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
869 const mut_tok = try appendToken(c, .Keyword_const, "const");
870 const name_tok = try appendIdentifier(c, name);
851871
852 node.eq_token = try appendToken(c, .Equal, "=");872 const eq_token = try appendToken(c, .Equal, "=");
853873
854 var semicolon: ast.TokenIndex = undefined;874 var semicolon: ast.TokenIndex = undefined;
855 node.init_node = blk: {875 const init_node = blk: {
856 const rp = makeRestorePoint(c);876 const rp = makeRestorePoint(c);
857 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {877 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
858 const opaque = try transCreateNodeOpaqueType(c);878 const opaque = try transCreateNodeOpaqueType(c);
...@@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
959 semicolon = try appendToken(c, .Semicolon, ";");979 semicolon = try appendToken(c, .Semicolon, ";");
960 break :blk &container_node.base;980 break :blk &container_node.base;
961 };981 };
962 node.semicolon_token = semicolon;982
983 const node = try ast.Node.VarDecl.create(c.arena, .{
984 .name_token = name_tok,
985 .mut_token = mut_tok,
986 .semicolon_token = semicolon,
987 }, .{
988 .visib_token = visib_tok,
989 .eq_token = eq_token,
990 .init_node = init_node,
991 });
963992
964 try addTopLevelDecl(c, name, &node.base);993 try addTopLevelDecl(c, name, &node.base);
965 if (!is_unnamed)994 if (!is_unnamed)
...@@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9821011
983 const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});1012 const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
984 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);1013 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
985 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
986 node.eq_token = try appendToken(c, .Equal, "=");
9871014
988 node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {1015 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
1016 const mut_tok = try appendToken(c, .Keyword_const, "const");
1017 const name_tok = try appendIdentifier(c, name);
1018 const eq_token = try appendToken(c, .Equal, "=");
1019
1020 const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
989 var pure_enum = true;1021 var pure_enum = true;
990 var it = ZigClangEnumDecl_enumerator_begin(enum_def);1022 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
991 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);1023 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
...@@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10631095
1064 // In C each enum value is in the global namespace. So we put them there too.1096 // In C each enum value is in the global namespace. So we put them there too.
1065 // At this point we can rely on the enum emitting successfully.1097 // At this point we can rely on the enum emitting successfully.
1066 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);1098 const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
1067 tld_node.eq_token = try appendToken(c, .Equal, "=");1099 const tld_mut_tok = try appendToken(c, .Keyword_const, "const");
1100 const tld_name_tok = try appendIdentifier(c, enum_val_name);
1101 const tld_eq_token = try appendToken(c, .Equal, "=");
1068 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);1102 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
1069 const enum_ident = try transCreateNodeIdentifier(c, name);1103 const enum_ident = try transCreateNodeIdentifier(c, name);
1070 const period_tok = try appendToken(c, .Period, ".");1104 const period_tok = try appendToken(c, .Period, ".");
...@@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
1078 };1112 };
1079 cast_node.params()[0] = &field_access_node.base;1113 cast_node.params()[0] = &field_access_node.base;
1080 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1114 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1081 tld_node.init_node = &cast_node.base;1115 const tld_init_node = &cast_node.base;
1082 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");1116 const tld_semicolon_token = try appendToken(c, .Semicolon, ";");
1117 const tld_node = try ast.Node.VarDecl.create(c.arena, .{
1118 .name_token = tld_name_tok,
1119 .mut_token = tld_mut_tok,
1120 .semicolon_token = tld_semicolon_token,
1121 }, .{
1122 .visib_token = tld_visib_tok,
1123 .eq_token = tld_eq_token,
1124 .init_node = tld_init_node,
1125 });
1083 try addTopLevelDecl(c, field_name, &tld_node.base);1126 try addTopLevelDecl(c, field_name, &tld_node.base);
1084 }1127 }
1085 // make non exhaustive1128 // make non exhaustive
...@@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
1109 } else1152 } else
1110 try transCreateNodeOpaqueType(c);1153 try transCreateNodeOpaqueType(c);
11111154
1112 node.semicolon_token = try appendToken(c, .Semicolon, ";");1155 const semicolon_token = try appendToken(c, .Semicolon, ";");
1156 const node = try ast.Node.VarDecl.create(c.arena, .{
1157 .name_token = name_tok,
1158 .mut_token = mut_tok,
1159 .semicolon_token = semicolon_token,
1160 }, .{
1161 .visib_token = visib_tok,
1162 .eq_token = eq_token,
1163 .init_node = init_node,
1164 });
11131165
1114 try addTopLevelDecl(c, name, &node.base);1166 try addTopLevelDecl(c, name, &node.base);
1115 if (!is_unnamed)1167 if (!is_unnamed)
...@@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
1118}1170}
11191171
1120fn createAlias(c: *Context, alias: anytype) !void {1172fn createAlias(c: *Context, alias: anytype) !void {
1121 const node = try transCreateNodeVarDecl(c, true, true, alias.alias);1173 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1122 node.eq_token = try appendToken(c, .Equal, "=");1174 const mut_tok = try appendToken(c, .Keyword_const, "const");
1123 node.init_node = try transCreateNodeIdentifier(c, alias.name);1175 const name_tok = try appendIdentifier(c, alias.alias);
1124 node.semicolon_token = try appendToken(c, .Semicolon, ";");1176 const eq_token = try appendToken(c, .Equal, "=");
1177 const init_node = try transCreateNodeIdentifier(c, alias.name);
1178 const semicolon_token = try appendToken(c, .Semicolon, ";");
1179
1180 const node = try ast.Node.VarDecl.create(c.arena, .{
1181 .name_token = name_tok,
1182 .mut_token = mut_tok,
1183 .semicolon_token = semicolon_token,
1184 }, .{
1185 .visib_token = visib_tok,
1186 .eq_token = eq_token,
1187 .init_node = init_node,
1188 });
1125 return addTopLevelDecl(c, alias.alias, &node.base);1189 return addTopLevelDecl(c, alias.alias, &node.base);
1126}1190}
11271191
...@@ -1461,13 +1525,17 @@ fn transDeclStmtOne(...@@ -1461,13 +1525,17 @@ fn transDeclStmtOne(
1461 @ptrCast(*const ZigClangNamedDecl, var_decl),1525 @ptrCast(*const ZigClangNamedDecl, var_decl),
1462 ));1526 ));
1463 const mangled_name = try block_scope.makeMangledName(c, name);1527 const mangled_name = try block_scope.makeMangledName(c, name);
1464 const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name);1528 const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
1529 try appendToken(c, .Keyword_const, "const")
1530 else
1531 try appendToken(c, .Keyword_var, "var");
1532 const name_tok = try appendIdentifier(c, mangled_name);
14651533
1466 _ = try appendToken(c, .Colon, ":");1534 _ = try appendToken(c, .Colon, ":");
1467 const loc = ZigClangDecl_getLocation(decl);1535 const loc = ZigClangDecl_getLocation(decl);
1468 node.type_node = try transQualType(rp, qual_type, loc);1536 const type_node = try transQualType(rp, qual_type, loc);
14691537
1470 node.eq_token = try appendToken(c, .Equal, "=");1538 const eq_token = try appendToken(c, .Equal, "=");
1471 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|1539 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
1472 try transExprCoercing(rp, scope, expr, .used, .r_value)1540 try transExprCoercing(rp, scope, expr, .used, .r_value)
1473 else1541 else
...@@ -1478,8 +1546,17 @@ fn transDeclStmtOne(...@@ -1478,8 +1546,17 @@ fn transDeclStmtOne(
1478 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1546 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1479 init_node = &builtin_node.base;1547 init_node = &builtin_node.base;
1480 }1548 }
1481 node.init_node = init_node;1549 const semicolon_token = try appendToken(c, .Semicolon, ";");
1482 node.semicolon_token = try appendToken(c, .Semicolon, ";");1550 const node = try ast.Node.VarDecl.create(c.arena, .{
1551 .name_token = name_tok,
1552 .mut_token = mut_tok,
1553 .semicolon_token = semicolon_token,
1554 }, .{
1555 .thread_local_token = thread_local_token,
1556 .eq_token = eq_token,
1557 .type_node = type_node,
1558 .init_node = init_node,
1559 });
1483 return &node.base;1560 return &node.base;
1484 },1561 },
1485 .Typedef => {1562 .Typedef => {
...@@ -1494,7 +1571,7 @@ fn transDeclStmtOne(...@@ -1494,7 +1571,7 @@ fn transDeclStmtOne(
1494 const mangled_name = try block_scope.makeMangledName(c, name);1571 const mangled_name = try block_scope.makeMangledName(c, name);
1495 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse1572 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
1496 return error.UnsupportedTranslation;1573 return error.UnsupportedTranslation;
1497 return &node.base;1574 return node;
1498 },1575 },
1499 else => |kind| return revertAndWarn(1576 else => |kind| return revertAndWarn(
1500 rp,1577 rp,
...@@ -3105,12 +3182,21 @@ fn transCreatePreCrement(...@@ -3105,12 +3182,21 @@ fn transCreatePreCrement(
3105 defer block_scope.deinit();3182 defer block_scope.deinit();
3106 const ref = try block_scope.makeMangledName(rp.c, "ref");3183 const ref = try block_scope.makeMangledName(rp.c, "ref");
31073184
3108 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3185 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3109 node.eq_token = try appendToken(rp.c, .Equal, "=");3186 const name_tok = try appendIdentifier(rp.c, ref);
3187 const eq_token = try appendToken(rp.c, .Equal, "=");
3110 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");3188 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3111 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3189 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3112 node.init_node = &rhs_node.base;3190 const init_node = &rhs_node.base;
3113 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3191 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3192 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3193 .name_token = name_tok,
3194 .mut_token = mut_tok,
3195 .semicolon_token = semicolon_token,
3196 }, .{
3197 .eq_token = eq_token,
3198 .init_node = init_node,
3199 });
3114 try block_scope.statements.append(&node.base);3200 try block_scope.statements.append(&node.base);
31153201
3116 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3202 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
...@@ -3171,12 +3257,21 @@ fn transCreatePostCrement(...@@ -3171,12 +3257,21 @@ fn transCreatePostCrement(
3171 defer block_scope.deinit();3257 defer block_scope.deinit();
3172 const ref = try block_scope.makeMangledName(rp.c, "ref");3258 const ref = try block_scope.makeMangledName(rp.c, "ref");
31733259
3174 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3260 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3175 node.eq_token = try appendToken(rp.c, .Equal, "=");3261 const name_tok = try appendIdentifier(rp.c, ref);
3262 const eq_token = try appendToken(rp.c, .Equal, "=");
3176 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");3263 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3177 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3264 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3178 node.init_node = &rhs_node.base;3265 const init_node = &rhs_node.base;
3179 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3266 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3267 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3268 .name_token = name_tok,
3269 .mut_token = mut_tok,
3270 .semicolon_token = semicolon_token,
3271 }, .{
3272 .eq_token = eq_token,
3273 .init_node = init_node,
3274 });
3180 try block_scope.statements.append(&node.base);3275 try block_scope.statements.append(&node.base);
31813276
3182 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3277 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
...@@ -3184,10 +3279,19 @@ fn transCreatePostCrement(...@@ -3184,10 +3279,19 @@ fn transCreatePostCrement(
3184 _ = try appendToken(rp.c, .Semicolon, ";");3279 _ = try appendToken(rp.c, .Semicolon, ";");
31853280
3186 const tmp = try block_scope.makeMangledName(rp.c, "tmp");3281 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3187 const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp);3282 const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3188 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");3283 const tmp_name_tok = try appendIdentifier(rp.c, tmp);
3189 tmp_node.init_node = ref_node;3284 const tmp_eq_token = try appendToken(rp.c, .Equal, "=");
3190 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3285 const tmp_init_node = ref_node;
3286 const tmp_semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3287 const tmp_node = try ast.Node.VarDecl.create(rp.c.arena, .{
3288 .name_token = tmp_name_tok,
3289 .mut_token = tmp_mut_tok,
3290 .semicolon_token = semicolon_token,
3291 }, .{
3292 .eq_token = tmp_eq_token,
3293 .init_node = tmp_init_node,
3294 });
3191 try block_scope.statements.append(&tmp_node.base);3295 try block_scope.statements.append(&tmp_node.base);
31923296
3193 const token = try appendToken(rp.c, op_tok_id, bytes);3297 const token = try appendToken(rp.c, op_tok_id, bytes);
...@@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign(...@@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign(
3325 defer block_scope.deinit();3429 defer block_scope.deinit();
3326 const ref = try block_scope.makeMangledName(rp.c, "ref");3430 const ref = try block_scope.makeMangledName(rp.c, "ref");
33273431
3328 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3432 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3329 node.eq_token = try appendToken(rp.c, .Equal, "=");3433 const name_tok = try appendIdentifier(rp.c, ref);
3434 const eq_token = try appendToken(rp.c, .Equal, "=");
3330 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");3435 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3331 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);3436 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3332 node.init_node = &addr_node.base;3437 const init_node = &addr_node.base;
3333 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3438 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3439 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3440 .name_token = name_tok,
3441 .mut_token = mut_tok,
3442 .semicolon_token = semicolon_token,
3443 }, .{
3444 .eq_token = eq_token,
3445 .init_node = init_node,
3446 });
3334 try block_scope.statements.append(&node.base);3447 try block_scope.statements.append(&node.base);
33353448
3336 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3449 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
...@@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign(...@@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign(
3375 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);3488 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
3376 _ = try appendToken(rp.c, .Semicolon, ";");3489 _ = try appendToken(rp.c, .Semicolon, ";");
33773490
3378 const eq_token = try appendToken(rp.c, .Equal, "=");3491 const ass_eq_token = try appendToken(rp.c, .Equal, "=");
3379 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);3492 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
3380 try block_scope.statements.append(assign);3493 try block_scope.statements.append(assign);
3381 }3494 }
33823495
...@@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3494 defer block_scope.deinit();3607 defer block_scope.deinit();
34953608
3496 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");3609 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
3497 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);3610 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3498 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");3611 const name_tok = try appendIdentifier(rp.c, mangled_name);
3499 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);3612 const eq_token = try appendToken(rp.c, .Equal, "=");
3500 tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3613 const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3614 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3615 const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{
3616 .name_token = name_tok,
3617 .mut_token = mut_tok,
3618 .semicolon_token = semicolon_token,
3619 }, .{
3620 .eq_token = eq_token,
3621 .init_node = init_node,
3622 });
3501 try block_scope.statements.append(&tmp_var.base);3623 try block_scope.statements.append(&tmp_var.base);
35023624
3503 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);3625 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
...@@ -3932,9 +4054,9 @@ fn transCreateNodeAssign(...@@ -3932,9 +4054,9 @@ fn transCreateNodeAssign(
3932 defer block_scope.deinit();4054 defer block_scope.deinit();
39334055
3934 const tmp = try block_scope.makeMangledName(rp.c, "tmp");4056 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
39354057 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3936 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);4058 const name_tok = try appendIdentifier(rp.c, tmp);
3937 node.eq_token = try appendToken(rp.c, .Equal, "=");4059 const eq_token = try appendToken(rp.c, .Equal, "=");
3938 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);4060 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
3939 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {4061 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3940 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);4062 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
...@@ -3942,16 +4064,24 @@ fn transCreateNodeAssign(...@@ -3942,16 +4064,24 @@ fn transCreateNodeAssign(
3942 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");4064 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3943 rhs_node = &builtin_node.base;4065 rhs_node = &builtin_node.base;
3944 }4066 }
3945 node.init_node = rhs_node;4067 const init_node = rhs_node;
3946 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");4068 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
4069 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
4070 .name_token = name_tok,
4071 .mut_token = mut_tok,
4072 .semicolon_token = semicolon_token,
4073 }, .{
4074 .eq_token = eq_token,
4075 .init_node = init_node,
4076 });
3947 try block_scope.statements.append(&node.base);4077 try block_scope.statements.append(&node.base);
39484078
3949 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);4079 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
3950 const eq_token = try appendToken(rp.c, .Equal, "=");4080 const lhs_eq_token = try appendToken(rp.c, .Equal, "=");
3951 const ident = try transCreateNodeIdentifier(rp.c, tmp);4081 const ident = try transCreateNodeIdentifier(rp.c, tmp);
3952 _ = try appendToken(rp.c, .Semicolon, ";");4082 _ = try appendToken(rp.c, .Semicolon, ";");
39534083
3954 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false);4084 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
3955 try block_scope.statements.append(assign);4085 try block_scope.statements.append(assign);
39564086
3957 const break_node = try transCreateNodeBreak(rp.c, label_name);4087 const break_node = try transCreateNodeBreak(rp.c, label_name);
...@@ -4232,28 +4362,10 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4232,28 +4362,10 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
42324362
4233 _ = try appendToken(c, .RParen, ")");4363 _ = try appendToken(c, .RParen, ")");
42344364
4235 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
4236 fn_proto.* = .{
4237 .doc_comments = null,
4238 .visib_token = pub_tok,
4239 .fn_token = fn_tok,
4240 .name_token = name_tok,
4241 .params_len = fn_params.items.len,
4242 .return_type = proto_alias.return_type,
4243 .var_args_token = null,
4244 .extern_export_inline_token = inline_tok,
4245 .body_node = null,
4246 .lib_name = null,
4247 .align_expr = null,
4248 .section_expr = null,
4249 .callconv_expr = null,
4250 };
4251 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4252
4253 const block_lbrace = try appendToken(c, .LBrace, "{");4365 const block_lbrace = try appendToken(c, .LBrace, "{");
42544366
4255 const return_expr = try transCreateNodeReturnExpr(c);4367 const return_expr = try transCreateNodeReturnExpr(c);
4256 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);4368 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);
42574369
4258 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);4370 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
4259 const call_params = call_expr.params();4371 const call_params = call_expr.params();
...@@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4277 .rbrace = try appendToken(c, .RBrace, "}"),4389 .rbrace = try appendToken(c, .RBrace, "}"),
4278 };4390 };
4279 block.statements()[0] = &return_expr.base;4391 block.statements()[0] = &return_expr.base;
4280 fn_proto.body_node = &block.base;4392
4393 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
4394 .params_len = fn_params.items.len,
4395 .fn_token = fn_tok,
4396 .return_type = proto_alias.return_type,
4397 }, .{
4398 .visib_token = pub_tok,
4399 .name_token = name_tok,
4400 .extern_export_inline_token = inline_tok,
4401 .body_node = &block.base,
4402 });
4403 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4281 return &fn_proto.base;4404 return &fn_proto.base;
4282}4405}
42834406
...@@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE...@@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
4356 return node;4479 return node;
4357}4480}
43584481
4359fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []const u8) !*ast.Node.VarDecl {
4360 const visib_tok = if (is_pub) try appendToken(c, .Keyword_pub, "pub") else null;
4361 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
4362 const name_tok = try appendIdentifier(c, name);
4363
4364 const node = try c.arena.create(ast.Node.VarDecl);
4365 node.* = .{
4366 .doc_comments = null,
4367 .visib_token = visib_tok,
4368 .thread_local_token = null,
4369 .name_token = name_tok,
4370 .eq_token = undefined,
4371 .mut_token = mut_tok,
4372 .comptime_token = null,
4373 .extern_export_token = null,
4374 .lib_name = null,
4375 .type_node = null,
4376 .align_node = null,
4377 .section_node = null,
4378 .init_node = null,
4379 .semicolon_token = undefined,
4380 };
4381 return node;
4382}
4383
4384fn transCreateNodeWhile(c: *Context) !*ast.Node.While {4482fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
4385 const while_tok = try appendToken(c, .Keyword_while, "while");4483 const while_tok = try appendToken(c, .Keyword_while, "while");
4386 _ = try appendToken(c, .LParen, "(");4484 _ = try appendToken(c, .LParen, "(");
...@@ -4782,19 +4880,12 @@ fn finishTransFnProto(...@@ -4782,19 +4880,12 @@ fn finishTransFnProto(
4782 }4880 }
4783 }4881 }
47844882
4785 if (is_var_args) {4883 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
4786 if (param_count > 0) {4884 if (param_count > 0) {
4787 _ = try appendToken(rp.c, .Comma, ",");4885 _ = try appendToken(rp.c, .Comma, ",");
4788 }4886 }
47894887 break :blk try appendToken(rp.c, .Ellipsis3, "...");
4790 fn_params.addOneAssumeCapacity().* = .{4888 } else null;
4791 .doc_comments = null,
4792 .comptime_token = null,
4793 .noalias_token = null,
4794 .name_token = null,
4795 .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") },
4796 };
4797 }
47984889
4799 const rparen_tok = try appendToken(rp.c, .RParen, ")");4890 const rparen_tok = try appendToken(rp.c, .RParen, ")");
48004891
...@@ -4860,22 +4951,31 @@ fn finishTransFnProto(...@@ -4860,22 +4951,31 @@ fn finishTransFnProto(
4860 }4951 }
4861 };4952 };
48624953
4863 const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len);4954 // We need to reserve an undefined (but non-null) body node to set later.
4864 fn_proto.* = .{4955 var body_node: ?*ast.Node = null;
4865 .doc_comments = null,4956 if (fn_decl_context) |ctx| {
4866 .visib_token = pub_tok,4957 if (ctx.has_body) {
4867 .fn_token = fn_tok,4958 // TODO: we should be able to use undefined here but
4868 .name_token = name_tok,4959 // it causes a bug. This is undefined without zig language
4960 // being aware of it.
4961 body_node = @intToPtr(*ast.Node, 0x08);
4962 }
4963 }
4964
4965 const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
4869 .params_len = fn_params.items.len,4966 .params_len = fn_params.items.len,
4870 .return_type = .{ .Explicit = return_type_node },4967 .return_type = .{ .Explicit = return_type_node },
4871 .var_args_token = null, // TODO this field is broken in the AST data model4968 .fn_token = fn_tok,
4969 }, .{
4970 .visib_token = pub_tok,
4971 .name_token = name_tok,
4872 .extern_export_inline_token = extern_export_inline_tok,4972 .extern_export_inline_token = extern_export_inline_tok,
4873 .body_node = null,
4874 .lib_name = null,
4875 .align_expr = align_expr,4973 .align_expr = align_expr,
4876 .section_expr = linksection_expr,4974 .section_expr = linksection_expr,
4877 .callconv_expr = callconv_expr,4975 .callconv_expr = callconv_expr,
4878 };4976 .body_node = body_node,
4977 .var_args_token = var_args_token,
4978 });
4879 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);4979 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4880 return fn_proto;4980 return fn_proto;
4881}4981}
...@@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp...@@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
4923 };5023 };
4924 call_node.params()[0] = &msg_node.base;5024 call_node.params()[0] = &msg_node.base;
49255025
4926 const var_decl_node = try c.arena.create(ast.Node.VarDecl);5026 const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
4927 var_decl_node.* = .{
4928 .doc_comments = null,
4929 .visib_token = pub_tok,
4930 .thread_local_token = null,
4931 .name_token = name_tok,5027 .name_token = name_tok,
4932 .eq_token = eq_tok,
4933 .mut_token = const_tok,5028 .mut_token = const_tok,
4934 .comptime_token = null,
4935 .extern_export_token = null,
4936 .lib_name = null,
4937 .type_node = null,
4938 .align_node = null,
4939 .section_node = null,
4940 .init_node = &call_node.base,
4941 .semicolon_token = semi_tok,5029 .semicolon_token = semi_tok,
4942 };5030 }, .{
5031 .visib_token = pub_tok,
5032 .eq_token = eq_tok,
5033 .init_node = &call_node.base,
5034 });
4943 try addTopLevelDecl(c, name, &var_decl_node.base);5035 try addTopLevelDecl(c, name, &var_decl_node.base);
4944}5036}
49455037
...@@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
5132fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {5224fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
5133 const scope = &c.global_scope.base;5225 const scope = &c.global_scope.base;
51345226
5135 const node = try transCreateNodeVarDecl(c, true, true, name);5227 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
5136 node.eq_token = try appendToken(c, .Equal, "=");5228 const mut_tok = try appendToken(c, .Keyword_const, "const");
5229 const name_tok = try appendIdentifier(c, name);
5230 const eq_token = try appendToken(c, .Equal, "=");
51375231
5138 node.init_node = try parseCExpr(c, it, source, source_loc, scope);5232 const init_node = try parseCExpr(c, it, source, source_loc, scope);
5139 const last = it.next().?;5233 const last = it.next().?;
5140 if (last.id != .Eof and last.id != .Nl)5234 if (last.id != .Eof and last.id != .Nl)
5141 return failDecl(5235 return failDecl(
...@@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n...@@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
5146 .{@tagName(last.id)},5240 .{@tagName(last.id)},
5147 );5241 );
51485242
5149 node.semicolon_token = try appendToken(c, .Semicolon, ";");5243 const semicolon_token = try appendToken(c, .Semicolon, ";");
5244 const node = try ast.Node.VarDecl.create(c.arena, .{
5245 .name_token = name_tok,
5246 .mut_token = mut_tok,
5247 .semicolon_token = semicolon_token,
5248 }, .{
5249 .visib_token = visib_tok,
5250 .eq_token = eq_token,
5251 .init_node = init_node,
5252 });
5150 _ = try c.global_scope.macro_table.put(name, &node.base);5253 _ = try c.global_scope.macro_table.put(name, &node.base);
5151}5254}
51525255
...@@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52235326
5224 const type_of = try c.createBuiltinCall("@TypeOf", 1);5327 const type_of = try c.createBuiltinCall("@TypeOf", 1);
52255328
5226 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
5227 fn_proto.* = .{
5228 .visib_token = pub_tok,
5229 .extern_export_inline_token = inline_tok,
5230 .fn_token = fn_tok,
5231 .name_token = name_tok,
5232 .params_len = fn_params.items.len,
5233 .return_type = .{ .Explicit = &type_of.base },
5234 .doc_comments = null,
5235 .var_args_token = null,
5236 .body_node = null,
5237 .lib_name = null,
5238 .align_expr = null,
5239 .section_expr = null,
5240 .callconv_expr = null,
5241 };
5242 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5243
5244 const return_expr = try transCreateNodeReturnExpr(c);5329 const return_expr = try transCreateNodeReturnExpr(c);
5245 const expr = try parseCExpr(c, it, source, source_loc, scope);5330 const expr = try parseCExpr(c, it, source, source_loc, scope);
5246 const last = it.next().?;5331 const last = it.next().?;
...@@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52665351
5267 try block_scope.statements.append(&return_expr.base);5352 try block_scope.statements.append(&return_expr.base);
5268 const block_node = try block_scope.complete(c);5353 const block_node = try block_scope.complete(c);
5269 fn_proto.body_node = &block_node.base;5354 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
5355 .fn_token = fn_tok,
5356 .params_len = fn_params.items.len,
5357 .return_type = .{ .Explicit = &type_of.base },
5358 }, .{
5359 .visib_token = pub_tok,
5360 .extern_export_inline_token = inline_tok,
5361 .name_token = name_tok,
5362 .body_node = &block_node.base,
5363 });
5364 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5365
5270 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);5366 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
5271}5367}
52725368
...@@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6030 const ident = node.cast(ast.Node.Identifier).?;6126 const ident = node.cast(ast.Node.Identifier).?;
6031 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {6127 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6032 if (value.cast(ast.Node.VarDecl)) |var_decl|6128 if (value.cast(ast.Node.VarDecl)) |var_decl|
6033 return getContainer(c, var_decl.init_node.?);6129 return getContainer(c, var_decl.getTrailer("init_node").?);
6034 }6130 }
6035 },6131 },
60366132
...@@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6060 if (ref.cast(ast.Node.Identifier)) |ident| {6156 if (ref.cast(ast.Node.Identifier)) |ident| {
6061 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {6157 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6062 if (value.cast(ast.Node.VarDecl)) |var_decl| {6158 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6063 if (var_decl.type_node) |ty|6159 if (var_decl.getTrailer("type_node")) |ty|
6064 return getContainer(c, ty);6160 return getContainer(c, ty);
6065 }6161 }
6066 }6162 }
...@@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6084}6180}
60856181
6086fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {6182fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6087 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;6183 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;
6088 if (getContainerTypeOf(c, init)) |ty_node| {6184 if (getContainerTypeOf(c, init)) |ty_node| {
6089 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {6185 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
6090 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {6186 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
test/translate_c.zig+1-1
...@@ -2797,7 +2797,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2797,7 +2797,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2797 \\pub fn a() callconv(.C) void {}2797 \\pub fn a() callconv(.C) void {}
2798 \\pub fn b() callconv(.C) void {}2798 \\pub fn b() callconv(.C) void {}
2799 \\pub export fn c() void {}2799 \\pub export fn c() void {}
2800 \\pub fn foo() callconv(.C) void {}2800 \\pub fn foo(...) callconv(.C) void {}
2801 });2801 });
28022802
2803 cases.add("casting away const and volatile",2803 cases.add("casting away const and volatile",