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 {
3333 self.bits |= 1 << field_index;
3434 }
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 {
3740 var self: Self = .{ .bits = 0 };
38 inline for (@typeInfo(@TypeOf(names)).Struct.fields) |field| {
39 if (@field(names, field.name)) {
40 const field_index = meta.fieldIndex(Fields, field.name).?;
41 self.bits |= 1 << field_index;
42 }
41 inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
42 const opt: ?Field(field.name) = @field(fields, field.name);
43 const field_index = meta.fieldIndex(Fields, field.name).?;
44 self.bits |= @as(Int, @boolToInt(opt != null)) << field_index;
4345 }
4446 return self;
4547 }
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
4760 pub fn set(
4861 self: Self,
4962 p: [*]align(@alignOf(Fields)) u8,
......@@ -54,11 +67,15 @@ pub fn TrailerFlags(comptime Fields: type) type {
5467 }
5568
5669 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;
5772 const off = self.offset(p, name);
5873 return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
5974 }
6075
6176 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;
6279 const off = self.offset(p, name);
6380 return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
6481 }
......@@ -85,6 +102,8 @@ pub fn TrailerFlags(comptime Fields: type) type {
85102 pub fn sizeInBytes(self: Self) usize {
86103 var off: usize = 0;
87104 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
105 if (@sizeOf(field.field_type) == 0)
106 continue;
88107 if ((self.bits & (1 << i)) != 0) {
89108 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
90109 off += @sizeOf(field.field_type);
......@@ -103,7 +122,7 @@ test "TrailerFlags" {
103122 });
104123 var flags = Flags.init(.{
105124 .b = true,
106 .c = true,
125 .c = 1234,
107126 });
108127 testing.expect(flags.sizeInBytes() == 16);
109128 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
......@@ -115,4 +134,13 @@ test "TrailerFlags" {
115134 testing.expect(flags.get(slice.ptr, "a") == null);
116135 testing.expect(!flags.get(slice.ptr, "b").?);
117136 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);
118146}
lib/std/zig/ast.zig+159-60
......@@ -675,42 +675,84 @@ pub const Node = struct {
675675 }
676676 };
677677
678 /// Trailed in memory by possibly many things, with each optional thing
679 /// determined by a bit in `trailer_flags`.
678680 pub const VarDecl = struct {
679681 base: Node = Node{ .id = .VarDecl },
680 doc_comments: ?*DocComment,
681 visib_token: ?TokenIndex,
682 thread_local_token: ?TokenIndex,
683 name_token: TokenIndex,
684 eq_token: ?TokenIndex,
682 trailer_flags: TrailerFlags,
685683 mut_token: TokenIndex,
686 comptime_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,
684 name_token: TokenIndex,
693685 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
695737 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
696738 var i = index;
697739
698 if (self.type_node) |type_node| {
740 if (self.getTrailer("type_node")) |type_node| {
699741 if (i < 1) return type_node;
700742 i -= 1;
701743 }
702744
703 if (self.align_node) |align_node| {
745 if (self.getTrailer("align_node")) |align_node| {
704746 if (i < 1) return align_node;
705747 i -= 1;
706748 }
707749
708 if (self.section_node) |section_node| {
750 if (self.getTrailer("section_node")) |section_node| {
709751 if (i < 1) return section_node;
710752 i -= 1;
711753 }
712754
713 if (self.init_node) |init_node| {
755 if (self.getTrailer("init_node")) |init_node| {
714756 if (i < 1) return init_node;
715757 i -= 1;
716758 }
......@@ -719,17 +761,21 @@ pub const Node = struct {
719761 }
720762
721763 pub fn firstToken(self: *const VarDecl) TokenIndex {
722 if (self.visib_token) |visib_token| return visib_token;
723 if (self.thread_local_token) |thread_local_token| return thread_local_token;
724 if (self.comptime_token) |comptime_token| return comptime_token;
725 if (self.extern_export_token) |extern_export_token| return extern_export_token;
726 assert(self.lib_name == null);
764 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
765 if (self.getTrailer("thread_local_token")) |thread_local_token| return thread_local_token;
766 if (self.getTrailer("comptime_token")) |comptime_token| return comptime_token;
767 if (self.getTrailer("extern_export_token")) |extern_export_token| return extern_export_token;
768 assert(self.getTrailer("lib_name") == null);
727769 return self.mut_token;
728770 }
729771
730772 pub fn lastToken(self: *const VarDecl) TokenIndex {
731773 return self.semicolon_token;
732774 }
775
776 fn sizeInBytes(trailer_flags: TrailerFlags) usize {
777 return @sizeOf(VarDecl) + trailer_flags.sizeInBytes();
778 }
733779 };
734780
735781 pub const Use = struct {
......@@ -972,25 +1018,34 @@ pub const Node = struct {
9721018 };
9731019
9741020 /// The params are directly after the FnProto in memory.
975 /// TODO have a flags field for the optional nodes, and have them appended
976 /// before or after the parameters in memory.
1021 /// Next, each optional thing determined by a bit in `trailer_flags`.
9771022 pub const FnProto = struct {
9781023 base: Node = Node{ .id = .FnProto },
979 doc_comments: ?*DocComment,
980 visib_token: ?TokenIndex,
1024 trailer_flags: TrailerFlags,
9811025 fn_token: TokenIndex,
982 name_token: ?TokenIndex,
9831026 params_len: NodeIndex,
9841027 return_type: ReturnType,
985 var_args_token: ?TokenIndex,
986 extern_export_inline_token: ?TokenIndex,
987 body_node: ?*Node,
988 lib_name: ?*Node, // populated if this is an extern declaration
989 align_expr: ?*Node, // populated if align(A) is present
990 section_expr: ?*Node, // populated if linksection(A) is present
991 callconv_expr: ?*Node, // populated if callconv(A) is present
992 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
993 is_async: bool = false, // TODO: remove once async fn rewriting is
1028
1029 pub const TrailerFlags = std.meta.TrailerFlags(struct {
1030 doc_comments: *DocComment,
1031 body_node: *Node,
1032 lib_name: *Node, // populated if this is an extern declaration
1033 align_expr: *Node, // populated if align(A) is present
1034 section_expr: *Node, // populated if linksection(A) is present
1035 callconv_expr: *Node, // populated if callconv(A) is present
1036 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
9951050 pub const ReturnType = union(enum) {
9961051 Explicit: *Node,
......@@ -1007,7 +1062,6 @@ pub const Node = struct {
10071062
10081063 pub const ParamType = union(enum) {
10091064 any_type: *Node,
1010 var_args: TokenIndex,
10111065 type_expr: *Node,
10121066 };
10131067
......@@ -1016,7 +1070,6 @@ pub const Node = struct {
10161070
10171071 if (i < 1) {
10181072 switch (self.param_type) {
1019 .var_args => return null,
10201073 .any_type, .type_expr => |node| return node,
10211074 }
10221075 }
......@@ -1030,34 +1083,79 @@ pub const Node = struct {
10301083 if (self.noalias_token) |noalias_token| return noalias_token;
10311084 if (self.name_token) |name_token| return name_token;
10321085 switch (self.param_type) {
1033 .var_args => |tok| return tok,
10341086 .any_type, .type_expr => |node| return node.firstToken(),
10351087 }
10361088 }
10371089
10381090 pub fn lastToken(self: *const ParamDecl) TokenIndex {
10391091 switch (self.param_type) {
1040 .var_args => |tok| return tok,
10411092 .any_type, .type_expr => |node| return node.lastToken(),
10421093 }
10431094 }
10441095 };
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
10461128 /// After this the caller must initialize the params list.
1047 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {
1048 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));
1049 return @ptrCast(*FnProto, bytes.ptr);
1129 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*FnProto {
1130 const trailer_flags = TrailerFlags.init(trailers);
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;
10501148 }
10511149
1052 pub fn free(self: *FnProto, allocator: *mem.Allocator) void {
1053 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
1150 pub fn destroy(self: *FnProto, allocator: *mem.Allocator) void {
1151 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len, self.trailer_flags)];
10541152 allocator.free(bytes);
10551153 }
10561154
10571155 pub fn iterate(self: *const FnProto, index: usize) ?*Node {
10581156 var i = index;
10591157
1060 if (self.lib_name) |lib_name| {
1158 if (self.getTrailer("lib_name")) |lib_name| {
10611159 if (i < 1) return lib_name;
10621160 i -= 1;
10631161 }
......@@ -1066,23 +1164,21 @@ pub const Node = struct {
10661164 0
10671165 else switch (self.paramsConst()[self.params_len - 1].param_type) {
10681166 .any_type, .type_expr => self.params_len,
1069 .var_args => self.params_len - 1,
10701167 };
10711168 if (i < params_len) {
10721169 switch (self.paramsConst()[i].param_type) {
10731170 .any_type => |n| return n,
1074 .var_args => unreachable,
10751171 .type_expr => |n| return n,
10761172 }
10771173 }
10781174 i -= params_len;
10791175
1080 if (self.align_expr) |align_expr| {
1176 if (self.getTrailer("align_expr")) |align_expr| {
10811177 if (i < 1) return align_expr;
10821178 i -= 1;
10831179 }
10841180
1085 if (self.section_expr) |section_expr| {
1181 if (self.getTrailer("section_expr")) |section_expr| {
10861182 if (i < 1) return section_expr;
10871183 i -= 1;
10881184 }
......@@ -1095,7 +1191,7 @@ pub const Node = struct {
10951191 .Invalid => {},
10961192 }
10971193
1098 if (self.body_node) |body_node| {
1194 if (self.getTrailer("body_node")) |body_node| {
10991195 if (i < 1) return body_node;
11001196 i -= 1;
11011197 }
......@@ -1104,14 +1200,14 @@ pub const Node = struct {
11041200 }
11051201
11061202 pub fn firstToken(self: *const FnProto) TokenIndex {
1107 if (self.visib_token) |visib_token| return visib_token;
1108 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
1109 assert(self.lib_name == null);
1203 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
1204 if (self.getTrailer("extern_export_inline_token")) |extern_export_inline_token| return extern_export_inline_token;
1205 assert(self.getTrailer("lib_name") == null);
11101206 return self.fn_token;
11111207 }
11121208
11131209 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();
11151211 switch (self.return_type) {
11161212 .Explicit, .InferErrorSet => |node| return node.lastToken(),
11171213 .Invalid => |tok| return tok,
......@@ -1119,17 +1215,17 @@ pub const Node = struct {
11191215 }
11201216
11211217 pub fn params(self: *FnProto) []ParamDecl {
1122 const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1123 return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];
1218 const params_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1219 return @ptrCast([*]ParamDecl, params_start)[0..self.params_len];
11241220 }
11251221
11261222 pub fn paramsConst(self: *const FnProto) []const ParamDecl {
1127 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1128 return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];
1223 const params_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1224 return @ptrCast([*]const ParamDecl, params_start)[0..self.params_len];
11291225 }
11301226
1131 fn sizeInBytes(params_len: NodeIndex) usize {
1132 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);
1227 fn sizeInBytes(params_len: NodeIndex, trailer_flags: TrailerFlags) usize {
1228 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len) + trailer_flags.sizeInBytes();
11331229 }
11341230 };
11351231
......@@ -2829,6 +2925,9 @@ pub const Node = struct {
28292925 }
28302926 };
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.
28322931 pub const DocComment = struct {
28332932 base: Node = Node{ .id = .DocComment },
28342933 /// 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 {
150150
151151 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) {
154154 error.OutOfMemory => return error.OutOfMemory,
155155 error.ParseError => {
156156 p.findNextContainerMember();
......@@ -160,30 +160,7 @@ const Parser = struct {
160160 if (field_state == .seen) {
161161 field_state = .{ .end = visib_token orelse node.firstToken() };
162162 }
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 }
178163 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 }
187164 continue;
188165 }
189166
......@@ -417,7 +394,7 @@ const Parser = struct {
417394 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
418395 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
419396 /// / KEYWORD_usingnamespace Expr SEMICOLON
420 fn parseTopLevelDecl(p: *Parser) !?*Node {
397 fn parseTopLevelDecl(p: *Parser, doc_comments: ?*Node.DocComment, visib_token: ?TokenIndex) !?*Node {
421398 var lib_name: ?*Node = null;
422399 const extern_export_inline_token = blk: {
423400 if (p.eatToken(.Keyword_export)) |token| break :blk token;
......@@ -430,20 +407,12 @@ const Parser = struct {
430407 break :blk null;
431408 };
432409
433 if (try p.parseFnProto()) |node| {
434 const fn_node = node.cast(Node.FnProto).?;
435 fn_node.*.extern_export_inline_token = extern_export_inline_token;
436 fn_node.*.lib_name = lib_name;
437 if (p.eatToken(.Semicolon)) |_| return node;
438
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 }
410 if (try p.parseFnProto(.top_level, .{
411 .doc_comments = doc_comments,
412 .visib_token = visib_token,
413 .extern_export_inline_token = extern_export_inline_token,
414 .lib_name = lib_name,
415 })) |node| {
447416 return node;
448417 }
449418
......@@ -460,12 +429,13 @@ const Parser = struct {
460429
461430 const thread_local_token = p.eatToken(.Keyword_threadlocal);
462431
463 if (try p.parseVarDecl()) |node| {
464 var var_decl = node.cast(Node.VarDecl).?;
465 var_decl.*.thread_local_token = thread_local_token;
466 var_decl.*.comptime_token = null;
467 var_decl.*.extern_export_token = extern_export_inline_token;
468 var_decl.*.lib_name = lib_name;
432 if (try p.parseVarDecl(.{
433 .doc_comments = doc_comments,
434 .visib_token = visib_token,
435 .thread_local_token = thread_local_token,
436 .extern_export_token = extern_export_inline_token,
437 .lib_name = lib_name,
438 })) |node| {
469439 return node;
470440 }
471441
......@@ -485,21 +455,41 @@ const Parser = struct {
485455 return error.ParseError;
486456 }
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;
489474 }
490475
491476 /// 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 {
493483 // TODO: Remove once extern/async fn rewriting is
494 var is_async = false;
495 var is_extern = false;
484 var is_async: ?void = null;
485 var is_extern_prototype: ?void = null;
496486 const cc_token: ?TokenIndex = blk: {
497487 if (p.eatToken(.Keyword_extern)) |token| {
498 is_extern = true;
488 is_extern_prototype = {};
499489 break :blk token;
500490 }
501491 if (p.eatToken(.Keyword_async)) |token| {
502 is_async = true;
492 is_async = {};
503493 break :blk token;
504494 }
505495 break :blk null;
......@@ -513,6 +503,7 @@ const Parser = struct {
513503 const lparen = try p.expectToken(.LParen);
514504 const params = try p.parseParamDeclList();
515505 defer p.gpa.free(params);
506 const var_args_token = p.eatToken(.Ellipsis3);
516507 const rparen = try p.expectToken(.RParen);
517508 const align_expr = try p.parseByteAlign();
518509 const section_expr = try p.parseLinkSection();
......@@ -535,37 +526,53 @@ const Parser = struct {
535526 else
536527 R{ .Explicit = return_type_expr.? };
537528
538 const var_args_token = if (params.len > 0) blk: {
539 const param_type = params[params.len - 1].param_type;
540 break :blk if (param_type == .var_args) param_type.var_args else null;
541 } else
542 null;
529 const body_node: ?*Node = switch (level) {
530 .top_level => blk: {
531 if (p.eatToken(.Semicolon)) |_| {
532 break :blk 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);
545 fn_proto_node.* = .{
546 .doc_comments = null,
547 .visib_token = null,
548 .fn_token = fn_token,
549 .name_token = name_token,
544 const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{
550545 .params_len = params.len,
546 .fn_token = fn_token,
551547 .return_type = return_type,
548 }, .{
549 .doc_comments = fields.doc_comments,
550 .visib_token = fields.visib_token,
551 .name_token = name_token,
552552 .var_args_token = var_args_token,
553 .extern_export_inline_token = null,
554 .body_node = null,
555 .lib_name = null,
553 .extern_export_inline_token = fields.extern_export_inline_token,
554 .body_node = body_node,
555 .lib_name = fields.lib_name,
556556 .align_expr = align_expr,
557557 .section_expr = section_expr,
558558 .callconv_expr = callconv_expr,
559 .is_extern_prototype = is_extern,
559 .is_extern_prototype = is_extern_prototype,
560560 .is_async = is_async,
561 };
561 });
562562 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
563563
564564 return &fn_proto_node.base;
565565 }
566566
567567 /// 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 {
569576 const mut_token = p.eatToken(.Keyword_const) orelse
570577 p.eatToken(.Keyword_var) orelse
571578 return null;
......@@ -587,23 +594,25 @@ const Parser = struct {
587594 } else null;
588595 const semicolon_token = try p.expectToken(.Semicolon);
589596
590 const node = try p.arena.allocator.create(Node.VarDecl);
591 node.* = .{
592 .doc_comments = null,
593 .visib_token = null,
594 .thread_local_token = null,
597 const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token);
598
599 const node = try Node.VarDecl.create(&p.arena.allocator, .{
600 .mut_token = mut_token,
595601 .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,
596607 .eq_token = eq_token,
597 .mut_token = mut_token,
598 .comptime_token = null,
599 .extern_export_token = null,
600 .lib_name = null,
608 .comptime_token = fields.comptime_token,
609 .extern_export_token = fields.extern_export_token,
610 .lib_name = fields.lib_name,
601611 .type_node = type_node,
602612 .align_node = align_node,
603613 .section_node = section_node,
604614 .init_node = init_node,
605 .semicolon_token = semicolon_token,
606 };
615 });
607616 return &node.base;
608617 }
609618
......@@ -663,10 +672,9 @@ const Parser = struct {
663672 fn parseStatement(p: *Parser) Error!?*Node {
664673 const comptime_token = p.eatToken(.Keyword_comptime);
665674
666 const var_decl_node = try p.parseVarDecl();
667 if (var_decl_node) |node| {
668 const var_decl = node.cast(Node.VarDecl).?;
669 var_decl.comptime_token = comptime_token;
675 if (try p.parseVarDecl(.{
676 .comptime_token = comptime_token,
677 })) |node| {
670678 return node;
671679 }
672680
......@@ -1527,7 +1535,7 @@ const Parser = struct {
15271535 if (try p.parseAnonLiteral()) |node| return node;
15281536 if (try p.parseErrorSetDecl()) |node| return node;
15291537 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;
15311539 if (try p.parseGroupedExpr()) |node| return node;
15321540 if (try p.parseLabeledTypeExpr()) |node| return node;
15331541 if (try p.parseIdentifier()) |node| return node;
......@@ -2028,7 +2036,6 @@ const Parser = struct {
20282036 // TODO cast from tuple to error union is broken
20292037 const P = Node.FnProto.ParamDecl.ParamType;
20302038 if (try p.parseAnyType()) |node| return P{ .any_type = node };
2031 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
20322039 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
20332040 return null;
20342041 }
......@@ -3149,21 +3156,6 @@ const Parser = struct {
31493156 return &node.base;
31503157 }
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
31673159 /// IfPrefix Body (KEYWORD_else Payload? Body)?
31683160 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
31693161 const node = (try p.parseIfPrefix()) orelse return null;
lib/std/zig/parser_test.zig+32-27
......@@ -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
331test "recovery: top level" {
432 try testError(
......@@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
31463174 );
31473175}
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
31633177test "zig fmt: convert async fn into callconv(.Async)" {
31643178 try testTransform(
31653179 \\async fn foo() void {}
......@@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" {
31803194 );
31813195}
31823196
3183test "zig fmt: convert var to anytype" {
3184 // TODO remove in next release cycle
3185 try testTransform(
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 {}
3197test "zig fmt: C var args" {
3198 try testCanonical(
3199 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
31953200 \\
31963201 );
31973202}
lib/std/zig/render.zig+52-40
......@@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
227227 .FnProto => {
228228 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| {
233233 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
234234 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
235235 } else {
......@@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
252252 .VarDecl => {
253253 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);
256256 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
257257 },
258258
259259 .TestDecl => {
260260 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);
263263 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
264264 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
265265 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
268268 .ContainerField => {
269269 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);
272272 if (field.comptime_token) |t| {
273273 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
274274 }
......@@ -1409,7 +1409,7 @@ fn renderExpression(
14091409 .ErrorTag => {
14101410 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);
14131413 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
14141414 },
14151415
......@@ -1483,23 +1483,23 @@ fn renderExpression(
14831483 .FnProto => {
14841484 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| {
14871487 const visib_token = tree.token_ids[visib_token_index];
14881488 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14891489
14901490 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
14911491 }
14921492
1493 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
1494 if (!fn_proto.is_extern_prototype)
1493 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
1494 if (fn_proto.getTrailer("is_extern_prototype") == null)
14951495 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
14961496 }
14971497
1498 if (fn_proto.lib_name) |lib_name| {
1498 if (fn_proto.getTrailer("lib_name")) |lib_name| {
14991499 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
15001500 }
15011501
1502 const lparen = if (fn_proto.name_token) |name_token| blk: {
1502 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
15031503 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
15041504 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
15051505 break :blk tree.nextToken(name_token);
......@@ -1512,11 +1512,11 @@ fn renderExpression(
15121512 const rparen = tree.prevToken(
15131513 // the first token for the annotation expressions is the left
15141514 // parenthesis, hence the need for two prevToken
1515 if (fn_proto.align_expr) |align_expr|
1515 if (fn_proto.getTrailer("align_expr")) |align_expr|
15161516 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|
15181518 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|
15201520 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
15211521 else switch (fn_proto.return_type) {
15221522 .Explicit => |node| node.firstToken(),
......@@ -1537,11 +1537,14 @@ fn renderExpression(
15371537 for (fn_proto.params()) |param_decl, i| {
15381538 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) {
15411541 const comma = tree.nextToken(param_decl.lastToken());
15421542 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
15431543 }
15441544 }
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 }
15451548 } else {
15461549 // one param per line
15471550 const new_indent = indent + indent_delta;
......@@ -1551,12 +1554,16 @@ fn renderExpression(
15511554 try stream.writeByteNTimes(' ', new_indent);
15521555 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
15531556 }
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 }
15541561 try stream.writeByteNTimes(' ', indent);
15551562 }
15561563
15571564 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| {
15601567 const align_rparen = tree.nextToken(align_expr.lastToken());
15611568 const align_lparen = tree.prevToken(align_expr.firstToken());
15621569 const align_kw = tree.prevToken(align_lparen);
......@@ -1567,7 +1574,7 @@ fn renderExpression(
15671574 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
15681575 }
15691576
1570 if (fn_proto.section_expr) |section_expr| {
1577 if (fn_proto.getTrailer("section_expr")) |section_expr| {
15711578 const section_rparen = tree.nextToken(section_expr.lastToken());
15721579 const section_lparen = tree.prevToken(section_expr.firstToken());
15731580 const section_kw = tree.prevToken(section_lparen);
......@@ -1578,7 +1585,7 @@ fn renderExpression(
15781585 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
15791586 }
15801587
1581 if (fn_proto.callconv_expr) |callconv_expr| {
1588 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
15821589 const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
15831590 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
15841591 const callconv_kw = tree.prevToken(callconv_lparen);
......@@ -1587,9 +1594,9 @@ fn renderExpression(
15871594 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
15881595 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
15891596 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) {
15911598 try stream.writeAll("callconv(.C) ");
1592 } else if (fn_proto.is_async) {
1599 } else if (fn_proto.getTrailer("is_async") != null) {
15931600 try stream.writeAll("callconv(.Async) ");
15941601 }
15951602
......@@ -2177,64 +2184,69 @@ fn renderVarDecl(
21772184 start_col: *usize,
21782185 var_decl: *ast.Node.VarDecl,
21792186) (@TypeOf(stream).Error || Error)!void {
2180 if (var_decl.visib_token) |visib_token| {
2187 if (var_decl.getTrailer("visib_token")) |visib_token| {
21812188 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
21822189 }
21832190
2184 if (var_decl.extern_export_token) |extern_export_token| {
2191 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
21852192 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| {
21882195 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
21892196 }
21902197 }
21912198
2192 if (var_decl.comptime_token) |comptime_token| {
2199 if (var_decl.getTrailer("comptime_token")) |comptime_token| {
21932200 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
21942201 }
21952202
2196 if (var_decl.thread_local_token) |thread_local_token| {
2203 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
21972204 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
21982205 }
21992206 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 or
2202 var_decl.section_node != null or var_decl.init_node != null)) Space.Space else Space.None;
2208 const name_space = if (var_decl.getTrailer("type_node") == null and
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;
22032215 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| {
22062218 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
2207 const s = if (var_decl.align_node != null or
2208 var_decl.section_node != null or
2209 var_decl.init_node != null) Space.Space else Space.None;
2219 const s = if (var_decl.getTrailer("align_node") != null or
2220 var_decl.getTrailer("section_node") != null or
2221 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
22102222 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
22112223 }
22122224
2213 if (var_decl.align_node) |align_node| {
2225 if (var_decl.getTrailer("align_node")) |align_node| {
22142226 const lparen = tree.prevToken(align_node.firstToken());
22152227 const align_kw = tree.prevToken(lparen);
22162228 const rparen = tree.nextToken(align_node.lastToken());
22172229 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
22182230 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
22192231 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;
22212233 try renderToken(tree, stream, rparen, indent, start_col, s); // )
22222234 }
22232235
2224 if (var_decl.section_node) |section_node| {
2236 if (var_decl.getTrailer("section_node")) |section_node| {
22252237 const lparen = tree.prevToken(section_node.firstToken());
22262238 const section_kw = tree.prevToken(lparen);
22272239 const rparen = tree.nextToken(section_node.lastToken());
22282240 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
22292241 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
22302242 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;
22322244 try renderToken(tree, stream, rparen, indent, start_col, s); // )
22332245 }
22342246
2235 if (var_decl.init_node) |init_node| {
2247 if (var_decl.getTrailer("init_node")) |init_node| {
22362248 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); // =
22382250 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
22392251 }
22402252
......@@ -2250,7 +2262,7 @@ fn renderParamDecl(
22502262 param_decl: ast.Node.FnProto.ParamDecl,
22512263 space: Space,
22522264) (@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
22552267 if (param_decl.comptime_token) |comptime_token| {
22562268 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
......@@ -2263,7 +2275,6 @@ fn renderParamDecl(
22632275 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
22642276 }
22652277 switch (param_decl.param_type) {
2266 .var_args => |token| try renderToken(tree, stream, token, indent, start_col, space),
22672278 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
22682279 }
22692280}
......@@ -2519,10 +2530,11 @@ fn renderDocComments(
25192530 tree: *ast.Tree,
25202531 stream: anytype,
25212532 node: anytype,
2533 doc_comments: ?*ast.Node.DocComment,
25222534 indent: usize,
25232535 start_col: *usize,
25242536) (@TypeOf(stream).Error || Error)!void {
2525 const comment = node.doc_comments orelse return;
2537 const comment = doc_comments orelse return;
25262538 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
25272539}
25282540
src-self-hosted/Module.zig+12-10
......@@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11301130 };
11311131 defer fn_type_scope.instructions.deinit(self.gpa);
11321132
1133 const body_node = fn_proto.body_node orelse
1133 const body_node = fn_proto.getTrailer("body_node") orelse
11341134 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
11351135
11361136 const param_decls = fn_proto.params();
......@@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11381138 for (param_decls) |param_decl, i| {
11391139 const param_type_node = switch (param_decl.param_type) {
11401140 .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", .{}),
11421141 .type_expr => |node| node,
11431142 };
11441143 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
11451144 }
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| {
11471149 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
11481150 }
1149 if (fn_proto.align_expr) |align_expr| {
1151 if (fn_proto.getTrailer("align_expr")) |align_expr| {
11501152 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
11511153 }
1152 if (fn_proto.section_expr) |sect_expr| {
1154 if (fn_proto.getTrailer("section_expr")) |sect_expr| {
11531155 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
11541156 }
1155 if (fn_proto.callconv_expr) |callconv_expr| {
1157 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
11561158 return self.failNode(
11571159 &fn_type_scope.base,
11581160 callconv_expr,
......@@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12651267 self.bin_file.freeDecl(decl);
12661268 }
12671269
1268 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1270 if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
12691271 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
12701272 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").?];
12721274 const name = tree.tokenSliceLoc(name_loc);
12731275 // The scope needs to have the decl in it.
12741276 try self.analyzeExport(&block_scope.base, export_src, name, decl);
......@@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18671869 for (decls) |src_decl, decl_i| {
18681870 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
18691871 // 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 {
18711873 @panic("TODO missing function name");
18721874 };
18731875
......@@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18931895 } else {
18941896 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
18951897 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| {
18971899 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
18981900 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
18991901 }
src-self-hosted/translate_c.zig+279-183
......@@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
586586 for (proto_node.params()) |*param, i| {
587587 const param_name = if (param.name_token) |name_tok|
588588 tokenSlice(c, name_tok)
589 else if (param.param_type == .var_args) {
590 assert(i + 1 == proto_node.params_len);
591 proto_node.params_len -= 1;
592 break;
593 } else
589 else
594590 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
595591
596592 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
......@@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
602598 if (!is_const) {
603599 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});
604600 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
605 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);
606 node.eq_token = try appendToken(c, .Equal, "=");
607 node.init_node = try transCreateNodeIdentifier(c, arg_name);
608 node.semicolon_token = try appendToken(c, .Semicolon, ";");
601
602 const mut_tok = try appendToken(c, .Keyword_var, "var");
603 const name_tok = try appendIdentifier(c, mangled_param_name);
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 });
609615 try block_scope.statements.append(&node.base);
610616 param.name_token = try appendIdentifier(c, arg_name);
611617 _ = try appendToken(c, .Colon, ":");
......@@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
622628 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
623629 };
624630 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);
626632 return addTopLevelDecl(c, fn_name, &proto_node.base);
627633}
628634
......@@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
725731 break :blk null;
726732 };
727733
728 const node = try c.arena.create(ast.Node.VarDecl);
729 node.* = .{
730 .doc_comments = null,
734 const node = try ast.Node.VarDecl.create(c.arena, .{
735 .name_token = name_tok,
736 .mut_token = mut_tok,
737 .semicolon_token = try appendToken(c, .Semicolon, ";"),
738 }, .{
731739 .visib_token = visib_tok,
732740 .thread_local_token = thread_local_token,
733 .name_token = name_tok,
734741 .eq_token = eq_tok,
735 .mut_token = mut_tok,
736 .comptime_token = null,
737742 .extern_export_token = extern_tok,
738 .lib_name = null,
739743 .type_node = type_node,
740744 .align_node = align_expr,
741745 .section_node = linksection_expr,
742746 .init_node = init_node,
743 .semicolon_token = try appendToken(c, .Semicolon, ";"),
744 };
747 });
745748 return addTopLevelDecl(c, checked_name, &node.base);
746749}
747750
......@@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
795798
796799 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
797800 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);
799802 return transCreateNodeIdentifier(c, checked_name);
800803}
801804
802fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl {
803 const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name);
804 node.eq_token = try appendToken(rp.c, .Equal, "=");
805
805fn transCreateNodeTypedef(
806 rp: RestorePoint,
807 typedef_decl: *const ZigClangTypedefNameDecl,
808 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, "=");
806815 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
807816 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) {
809818 error.UnsupportedType => {
810819 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
811820 return null;
812821 },
813822 error.OutOfMemory => |e| return e,
814823 };
824 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
815825
816 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
817 return node;
826 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
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;
818836}
819837
820838fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
......@@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
847865 const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
848866 _ = 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
854874 var semicolon: ast.TokenIndex = undefined;
855 node.init_node = blk: {
875 const init_node = blk: {
856876 const rp = makeRestorePoint(c);
857877 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
858878 const opaque = try transCreateNodeOpaqueType(c);
......@@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
959979 semicolon = try appendToken(c, .Semicolon, ";");
960980 break :blk &container_node.base;
961981 };
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
964993 try addTopLevelDecl(c, name, &node.base);
965994 if (!is_unnamed)
......@@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9821011
9831012 const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
9841013 _ = 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: {
9891021 var pure_enum = true;
9901022 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
9911023 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
......@@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10631095
10641096 // In C each enum value is in the global namespace. So we put them there too.
10651097 // At this point we can rely on the enum emitting successfully.
1066 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
1067 tld_node.eq_token = try appendToken(c, .Equal, "=");
1098 const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
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, "=");
10681102 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
10691103 const enum_ident = try transCreateNodeIdentifier(c, name);
10701104 const period_tok = try appendToken(c, .Period, ".");
......@@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10781112 };
10791113 cast_node.params()[0] = &field_access_node.base;
10801114 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1081 tld_node.init_node = &cast_node.base;
1082 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
1115 const tld_init_node = &cast_node.base;
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 });
10831126 try addTopLevelDecl(c, field_name, &tld_node.base);
10841127 }
10851128 // make non exhaustive
......@@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
11091152 } else
11101153 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
11141166 try addTopLevelDecl(c, name, &node.base);
11151167 if (!is_unnamed)
......@@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
11181170}
11191171
11201172fn createAlias(c: *Context, alias: anytype) !void {
1121 const node = try transCreateNodeVarDecl(c, true, true, alias.alias);
1122 node.eq_token = try appendToken(c, .Equal, "=");
1123 node.init_node = try transCreateNodeIdentifier(c, alias.name);
1124 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1173 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1174 const mut_tok = try appendToken(c, .Keyword_const, "const");
1175 const name_tok = try appendIdentifier(c, alias.alias);
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 });
11251189 return addTopLevelDecl(c, alias.alias, &node.base);
11261190}
11271191
......@@ -1461,13 +1525,17 @@ fn transDeclStmtOne(
14611525 @ptrCast(*const ZigClangNamedDecl, var_decl),
14621526 ));
14631527 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
14661534 _ = try appendToken(c, .Colon, ":");
14671535 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, "=");
14711539 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
14721540 try transExprCoercing(rp, scope, expr, .used, .r_value)
14731541 else
......@@ -1478,8 +1546,17 @@ fn transDeclStmtOne(
14781546 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
14791547 init_node = &builtin_node.base;
14801548 }
1481 node.init_node = init_node;
1482 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1549 const 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 });
14831560 return &node.base;
14841561 },
14851562 .Typedef => {
......@@ -1494,7 +1571,7 @@ fn transDeclStmtOne(
14941571 const mangled_name = try block_scope.makeMangledName(c, name);
14951572 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
14961573 return error.UnsupportedTranslation;
1497 return &node.base;
1574 return node;
14981575 },
14991576 else => |kind| return revertAndWarn(
15001577 rp,
......@@ -3105,12 +3182,21 @@ fn transCreatePreCrement(
31053182 defer block_scope.deinit();
31063183 const ref = try block_scope.makeMangledName(rp.c, "ref");
31073184
3108 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3109 node.eq_token = try appendToken(rp.c, .Equal, "=");
3185 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3186 const name_tok = try appendIdentifier(rp.c, ref);
3187 const eq_token = try appendToken(rp.c, .Equal, "=");
31103188 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31113189 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3112 node.init_node = &rhs_node.base;
3113 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3190 const init_node = &rhs_node.base;
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 });
31143200 try block_scope.statements.append(&node.base);
31153201
31163202 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3171,12 +3257,21 @@ fn transCreatePostCrement(
31713257 defer block_scope.deinit();
31723258 const ref = try block_scope.makeMangledName(rp.c, "ref");
31733259
3174 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3175 node.eq_token = try appendToken(rp.c, .Equal, "=");
3260 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3261 const name_tok = try appendIdentifier(rp.c, ref);
3262 const eq_token = try appendToken(rp.c, .Equal, "=");
31763263 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31773264 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3178 node.init_node = &rhs_node.base;
3179 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3265 const init_node = &rhs_node.base;
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 });
31803275 try block_scope.statements.append(&node.base);
31813276
31823277 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3184,10 +3279,19 @@ fn transCreatePostCrement(
31843279 _ = try appendToken(rp.c, .Semicolon, ";");
31853280
31863281 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3187 const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
3188 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
3189 tmp_node.init_node = ref_node;
3190 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3282 const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3283 const tmp_name_tok = try appendIdentifier(rp.c, tmp);
3284 const tmp_eq_token = try appendToken(rp.c, .Equal, "=");
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 });
31913295 try block_scope.statements.append(&tmp_node.base);
31923296
31933297 const token = try appendToken(rp.c, op_tok_id, bytes);
......@@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign(
33253429 defer block_scope.deinit();
33263430 const ref = try block_scope.makeMangledName(rp.c, "ref");
33273431
3328 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3329 node.eq_token = try appendToken(rp.c, .Equal, "=");
3432 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3433 const name_tok = try appendIdentifier(rp.c, ref);
3434 const eq_token = try appendToken(rp.c, .Equal, "=");
33303435 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
33313436 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3332 node.init_node = &addr_node.base;
3333 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3437 const init_node = &addr_node.base;
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 });
33343447 try block_scope.statements.append(&node.base);
33353448
33363449 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign(
33753488 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
33763489 _ = try appendToken(rp.c, .Semicolon, ";");
33773490
3378 const eq_token = try appendToken(rp.c, .Equal, "=");
3379 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
3491 const ass_eq_token = try appendToken(rp.c, .Equal, "=");
3492 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
33803493 try block_scope.statements.append(assign);
33813494 }
33823495
......@@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
34943607 defer block_scope.deinit();
34953608
34963609 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
3497 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);
3498 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");
3499 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3500 tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3610 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3611 const name_tok = try appendIdentifier(rp.c, mangled_name);
3612 const eq_token = try appendToken(rp.c, .Equal, "=");
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 });
35013623 try block_scope.statements.append(&tmp_var.base);
35023624
35033625 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
......@@ -3932,9 +4054,9 @@ fn transCreateNodeAssign(
39324054 defer block_scope.deinit();
39334055
39344056 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3935
3936 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
3937 node.eq_token = try appendToken(rp.c, .Equal, "=");
4057 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
4058 const name_tok = try appendIdentifier(rp.c, tmp);
4059 const eq_token = try appendToken(rp.c, .Equal, "=");
39384060 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
39394061 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
39404062 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
......@@ -3942,16 +4064,24 @@ fn transCreateNodeAssign(
39424064 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
39434065 rhs_node = &builtin_node.base;
39444066 }
3945 node.init_node = rhs_node;
3946 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
4067 const init_node = rhs_node;
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 });
39474077 try block_scope.statements.append(&node.base);
39484078
39494079 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, "=");
39514081 const ident = try transCreateNodeIdentifier(rp.c, tmp);
39524082 _ = 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);
39554085 try block_scope.statements.append(assign);
39564086
39574087 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
42324362
42334363 _ = 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
42534365 const block_lbrace = try appendToken(c, .LBrace, "{");
42544366
42554367 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
42584370 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
42594371 const call_params = call_expr.params();
......@@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
42774389 .rbrace = try appendToken(c, .RBrace, "}"),
42784390 };
42794391 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);
42814404 return &fn_proto.base;
42824405}
42834406
......@@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
43564479 return node;
43574480}
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
43844482fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
43854483 const while_tok = try appendToken(c, .Keyword_while, "while");
43864484 _ = try appendToken(c, .LParen, "(");
......@@ -4782,19 +4880,12 @@ fn finishTransFnProto(
47824880 }
47834881 }
47844882
4785 if (is_var_args) {
4883 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
47864884 if (param_count > 0) {
47874885 _ = try appendToken(rp.c, .Comma, ",");
47884886 }
4789
4790 fn_params.addOneAssumeCapacity().* = .{
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 }
4887 break :blk try appendToken(rp.c, .Ellipsis3, "...");
4888 } else null;
47984889
47994890 const rparen_tok = try appendToken(rp.c, .RParen, ")");
48004891
......@@ -4860,22 +4951,31 @@ fn finishTransFnProto(
48604951 }
48614952 };
48624953
4863 const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len);
4864 fn_proto.* = .{
4865 .doc_comments = null,
4866 .visib_token = pub_tok,
4867 .fn_token = fn_tok,
4868 .name_token = name_tok,
4954 // We need to reserve an undefined (but non-null) body node to set later.
4955 var body_node: ?*ast.Node = null;
4956 if (fn_decl_context) |ctx| {
4957 if (ctx.has_body) {
4958 // TODO: we should be able to use undefined here but
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, .{
48694966 .params_len = fn_params.items.len,
48704967 .return_type = .{ .Explicit = return_type_node },
4871 .var_args_token = null, // TODO this field is broken in the AST data model
4968 .fn_token = fn_tok,
4969 }, .{
4970 .visib_token = pub_tok,
4971 .name_token = name_tok,
48724972 .extern_export_inline_token = extern_export_inline_tok,
4873 .body_node = null,
4874 .lib_name = null,
48754973 .align_expr = align_expr,
48764974 .section_expr = linksection_expr,
48774975 .callconv_expr = callconv_expr,
4878 };
4976 .body_node = body_node,
4977 .var_args_token = var_args_token,
4978 });
48794979 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
48804980 return fn_proto;
48814981}
......@@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
49235023 };
49245024 call_node.params()[0] = &msg_node.base;
49255025
4926 const var_decl_node = try c.arena.create(ast.Node.VarDecl);
4927 var_decl_node.* = .{
4928 .doc_comments = null,
4929 .visib_token = pub_tok,
4930 .thread_local_token = null,
5026 const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
49315027 .name_token = name_tok,
4932 .eq_token = eq_tok,
49335028 .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,
49415029 .semicolon_token = semi_tok,
4942 };
5030 }, .{
5031 .visib_token = pub_tok,
5032 .eq_token = eq_tok,
5033 .init_node = &call_node.base,
5034 });
49435035 try addTopLevelDecl(c, name, &var_decl_node.base);
49445036}
49455037
......@@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
51325224fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
51335225 const scope = &c.global_scope.base;
51345226
5135 const node = try transCreateNodeVarDecl(c, true, true, name);
5136 node.eq_token = try appendToken(c, .Equal, "=");
5227 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
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);
51395233 const last = it.next().?;
51405234 if (last.id != .Eof and last.id != .Nl)
51415235 return failDecl(
......@@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
51465240 .{@tagName(last.id)},
51475241 );
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 });
51505253 _ = try c.global_scope.macro_table.put(name, &node.base);
51515254}
51525255
......@@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52235326
52245327 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
52445329 const return_expr = try transCreateNodeReturnExpr(c);
52455330 const expr = try parseCExpr(c, it, source, source_loc, scope);
52465331 const last = it.next().?;
......@@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52665351
52675352 try block_scope.statements.append(&return_expr.base);
52685353 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
52705366 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
52715367}
52725368
......@@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60306126 const ident = node.cast(ast.Node.Identifier).?;
60316127 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
60326128 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").?);
60346130 }
60356131 },
60366132
......@@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60606156 if (ref.cast(ast.Node.Identifier)) |ident| {
60616157 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
60626158 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6063 if (var_decl.type_node) |ty|
6159 if (var_decl.getTrailer("type_node")) |ty|
60646160 return getContainer(c, ty);
60656161 }
60666162 }
......@@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60846180}
60856181
60866182fn 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;
60886184 if (getContainerTypeOf(c, init)) |ty_node| {
60896185 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
60906186 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 {
27972797 \\pub fn a() callconv(.C) void {}
27982798 \\pub fn b() callconv(.C) void {}
27992799 \\pub export fn c() void {}
2800 \\pub fn foo() callconv(.C) void {}
2800 \\pub fn foo(...) callconv(.C) void {}
28012801 });
28022802
28032803 cases.add("casting away const and volatile",