authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-15 18:34:06+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-15 18:34:06+00:00
log6b103324d2d935260138584877dbe1593790b953
tree3d1dc5c5378ac41ab5ca24f549721a882583454f
parenta7c3cec65f1639195e787b98900c3f126953f880
parentc5b7322319a9559423fcda5c20c3b2e22338b2b4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5872 from ziglang/ast-flatten-2

stage2: introduce the concept of "trailer flags" to the AST

9 files changed, 773 insertions(+), 421 deletions(-)

lib/std/meta.zig+1
...@@ -6,6 +6,7 @@ const math = std.math;...@@ -6,6 +6,7 @@ const math = std.math;
6const testing = std.testing;6const testing = std.testing;
77
8pub const trait = @import("meta/trait.zig");8pub const trait = @import("meta/trait.zig");
9pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags;
910
10const TypeInfo = builtin.TypeInfo;11const TypeInfo = builtin.TypeInfo;
1112
lib/std/meta/trailer_flags.zig created+145
...@@ -0,0 +1,145 @@
1const std = @import("../std.zig");
2const meta = std.meta;
3const testing = std.testing;
4const mem = std.mem;
5const assert = std.debug.assert;
6
7/// This is useful for saving memory when allocating an object that has many
8/// optional components. The optional objects are allocated sequentially in
9/// memory, and a single integer is used to represent each optional object
10/// and whether it is present based on each corresponding bit.
11pub fn TrailerFlags(comptime Fields: type) type {
12 return struct {
13 bits: Int,
14
15 pub const Int = @Type(.{ .Int = .{ .bits = bit_count, .is_signed = false } });
16 pub const bit_count = @typeInfo(Fields).Struct.fields.len;
17
18 pub const Self = @This();
19
20 pub fn has(self: Self, comptime name: []const u8) bool {
21 const field_index = meta.fieldIndex(Fields, name).?;
22 return (self.bits & (1 << field_index)) != 0;
23 }
24
25 pub fn get(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) ?Field(name) {
26 if (!self.has(name))
27 return null;
28 return self.ptrConst(p, name).*;
29 }
30
31 pub fn setFlag(self: *Self, comptime name: []const u8) void {
32 const field_index = meta.fieldIndex(Fields, name).?;
33 self.bits |= 1 << field_index;
34 }
35
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 {
40 var self: Self = .{ .bits = 0 };
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;
45 }
46 return self;
47 }
48
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
60 pub fn set(
61 self: Self,
62 p: [*]align(@alignOf(Fields)) u8,
63 comptime name: []const u8,
64 value: Field(name),
65 ) void {
66 self.ptr(p, name).* = value;
67 }
68
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;
72 const off = self.offset(p, name);
73 return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
74 }
75
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;
79 const off = self.offset(p, name);
80 return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
81 }
82
83 pub fn offset(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) usize {
84 var off: usize = 0;
85 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
86 const active = (self.bits & (1 << i)) != 0;
87 if (comptime mem.eql(u8, field.name, name)) {
88 assert(active);
89 return mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
90 } else if (active) {
91 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
92 off += @sizeOf(field.field_type);
93 }
94 }
95 @compileError("no field named " ++ name ++ " in type " ++ @typeName(Fields));
96 }
97
98 pub fn Field(comptime name: []const u8) type {
99 return meta.fieldInfo(Fields, name).field_type;
100 }
101
102 pub fn sizeInBytes(self: Self) usize {
103 var off: usize = 0;
104 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
105 if (@sizeOf(field.field_type) == 0)
106 continue;
107 if ((self.bits & (1 << i)) != 0) {
108 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
109 off += @sizeOf(field.field_type);
110 }
111 }
112 return off;
113 }
114 };
115}
116
117test "TrailerFlags" {
118 const Flags = TrailerFlags(struct {
119 a: i32,
120 b: bool,
121 c: u64,
122 });
123 var flags = Flags.init(.{
124 .b = true,
125 .c = 1234,
126 });
127 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
128 defer testing.allocator.free(slice);
129
130 flags.set(slice.ptr, "b", false);
131 flags.set(slice.ptr, "c", 12345678);
132
133 testing.expect(flags.get(slice.ptr, "a") == null);
134 testing.expect(!flags.get(slice.ptr, "b").?);
135 testing.expect(flags.get(slice.ptr, "c").? == 12345678);
136
137 flags.setMany(slice.ptr, .{
138 .b = true,
139 .c = 5678,
140 });
141
142 testing.expect(flags.get(slice.ptr, "a") == null);
143 testing.expect(flags.get(slice.ptr, "b").?);
144 testing.expect(flags.get(slice.ptr, "c").? == 5678);
145}
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",