authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-24 09:44:08-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-05-24 09:44:08-04:00
log2ff3995a708b03480d5ca51b3ffa92f52cdf81d0
treef6abe8da2a54b481e15bccc7468c7ec283330413
parent882921b5dd5d6527198f67f9514bca6d5c24798b
parent8a3cd82b854164758eef17440d86105472e9e7a9
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5378 from ziglang/speed-up-stage2-parsing

improve std.zig.parse performance using flat arrays for AST nodes and tokens

15 files changed, 5315 insertions(+), 4612 deletions(-)

doc/docgen.zig+18-18
...@@ -776,7 +776,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -776,7 +776,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
776 next_tok_is_fn = false;776 next_tok_is_fn = false;
777777
778 const token = tokenizer.next();778 const token = tokenizer.next();
779 try writeEscaped(out, src[index..token.start]);779 try writeEscaped(out, src[index..token.loc.start]);
780 switch (token.id) {780 switch (token.id) {
781 .Eof => break,781 .Eof => break,
782782
...@@ -827,13 +827,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -827,13 +827,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
827 .Keyword_while,827 .Keyword_while,
828 => {828 => {
829 try out.writeAll("<span class=\"tok-kw\">");829 try out.writeAll("<span class=\"tok-kw\">");
830 try writeEscaped(out, src[token.start..token.end]);830 try writeEscaped(out, src[token.loc.start..token.loc.end]);
831 try out.writeAll("</span>");831 try out.writeAll("</span>");
832 },832 },
833833
834 .Keyword_fn => {834 .Keyword_fn => {
835 try out.writeAll("<span class=\"tok-kw\">");835 try out.writeAll("<span class=\"tok-kw\">");
836 try writeEscaped(out, src[token.start..token.end]);836 try writeEscaped(out, src[token.loc.start..token.loc.end]);
837 try out.writeAll("</span>");837 try out.writeAll("</span>");
838 next_tok_is_fn = true;838 next_tok_is_fn = true;
839 },839 },
...@@ -844,7 +844,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -844,7 +844,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
844 .Keyword_false,844 .Keyword_false,
845 => {845 => {
846 try out.writeAll("<span class=\"tok-null\">");846 try out.writeAll("<span class=\"tok-null\">");
847 try writeEscaped(out, src[token.start..token.end]);847 try writeEscaped(out, src[token.loc.start..token.loc.end]);
848 try out.writeAll("</span>");848 try out.writeAll("</span>");
849 },849 },
850850
...@@ -853,13 +853,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -853,13 +853,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
853 .CharLiteral,853 .CharLiteral,
854 => {854 => {
855 try out.writeAll("<span class=\"tok-str\">");855 try out.writeAll("<span class=\"tok-str\">");
856 try writeEscaped(out, src[token.start..token.end]);856 try writeEscaped(out, src[token.loc.start..token.loc.end]);
857 try out.writeAll("</span>");857 try out.writeAll("</span>");
858 },858 },
859859
860 .Builtin => {860 .Builtin => {
861 try out.writeAll("<span class=\"tok-builtin\">");861 try out.writeAll("<span class=\"tok-builtin\">");
862 try writeEscaped(out, src[token.start..token.end]);862 try writeEscaped(out, src[token.loc.start..token.loc.end]);
863 try out.writeAll("</span>");863 try out.writeAll("</span>");
864 },864 },
865865
...@@ -869,34 +869,34 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -869,34 +869,34 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
869 .ShebangLine,869 .ShebangLine,
870 => {870 => {
871 try out.writeAll("<span class=\"tok-comment\">");871 try out.writeAll("<span class=\"tok-comment\">");
872 try writeEscaped(out, src[token.start..token.end]);872 try writeEscaped(out, src[token.loc.start..token.loc.end]);
873 try out.writeAll("</span>");873 try out.writeAll("</span>");
874 },874 },
875875
876 .Identifier => {876 .Identifier => {
877 if (prev_tok_was_fn) {877 if (prev_tok_was_fn) {
878 try out.writeAll("<span class=\"tok-fn\">");878 try out.writeAll("<span class=\"tok-fn\">");
879 try writeEscaped(out, src[token.start..token.end]);879 try writeEscaped(out, src[token.loc.start..token.loc.end]);
880 try out.writeAll("</span>");880 try out.writeAll("</span>");
881 } else {881 } else {
882 const is_int = blk: {882 const is_int = blk: {
883 if (src[token.start] != 'i' and src[token.start] != 'u')883 if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
884 break :blk false;884 break :blk false;
885 var i = token.start + 1;885 var i = token.loc.start + 1;
886 if (i == token.end)886 if (i == token.loc.end)
887 break :blk false;887 break :blk false;
888 while (i != token.end) : (i += 1) {888 while (i != token.loc.end) : (i += 1) {
889 if (src[i] < '0' or src[i] > '9')889 if (src[i] < '0' or src[i] > '9')
890 break :blk false;890 break :blk false;
891 }891 }
892 break :blk true;892 break :blk true;
893 };893 };
894 if (is_int or isType(src[token.start..token.end])) {894 if (is_int or isType(src[token.loc.start..token.loc.end])) {
895 try out.writeAll("<span class=\"tok-type\">");895 try out.writeAll("<span class=\"tok-type\">");
896 try writeEscaped(out, src[token.start..token.end]);896 try writeEscaped(out, src[token.loc.start..token.loc.end]);
897 try out.writeAll("</span>");897 try out.writeAll("</span>");
898 } else {898 } else {
899 try writeEscaped(out, src[token.start..token.end]);899 try writeEscaped(out, src[token.loc.start..token.loc.end]);
900 }900 }
901 }901 }
902 },902 },
...@@ -905,7 +905,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -905,7 +905,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
905 .FloatLiteral,905 .FloatLiteral,
906 => {906 => {
907 try out.writeAll("<span class=\"tok-number\">");907 try out.writeAll("<span class=\"tok-number\">");
908 try writeEscaped(out, src[token.start..token.end]);908 try writeEscaped(out, src[token.loc.start..token.loc.end]);
909 try out.writeAll("</span>");909 try out.writeAll("</span>");
910 },910 },
911911
...@@ -963,7 +963,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -963,7 +963,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
963 .AngleBracketAngleBracketRight,963 .AngleBracketAngleBracketRight,
964 .AngleBracketAngleBracketRightEqual,964 .AngleBracketAngleBracketRightEqual,
965 .Tilde,965 .Tilde,
966 => try writeEscaped(out, src[token.start..token.end]),966 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
967967
968 .Invalid, .Invalid_ampersands => return parseError(968 .Invalid, .Invalid_ampersands => return parseError(
969 docgen_tokenizer,969 docgen_tokenizer,
...@@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
972 .{},972 .{},
973 ),973 ),
974 }974 }
975 index = token.end;975 index = token.loc.end;
976 }976 }
977 try out.writeAll("</code>");977 try out.writeAll("</code>");
978}978}
lib/std/heap/arena_allocator.zig+3-7
...@@ -46,13 +46,9 @@ pub const ArenaAllocator = struct {...@@ -46,13 +46,9 @@ pub const ArenaAllocator = struct {
46 }46 }
4747
48 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {48 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
49 const actual_min_size = minimum_size + @sizeOf(BufNode);49 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
50 var len = prev_len;50 const big_enough_len = prev_len + actual_min_size;
51 while (true) {51 const len = big_enough_len + big_enough_len / 2;
52 len += len / 2;
53 len += mem.page_size - @rem(len, mem.page_size);
54 if (len >= actual_min_size) break;
55 }
56 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);52 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
57 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);53 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);
58 const buf_node = &buf_node_slice[0];54 const buf_node = &buf_node_slice[0];
lib/std/linked_list.zig+43-71
...@@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type {
21 next: ?*Node = null,21 next: ?*Node = null,
22 data: T,22 data: T,
2323
24 pub const Data = T;
25
24 pub fn init(data: T) Node {26 pub fn init(data: T) Node {
25 return Node{27 return Node{
26 .data = data,28 .data = data,
...@@ -47,28 +49,29 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -47,28 +49,29 @@ pub fn SinglyLinkedList(comptime T: type) type {
47 node.next = next_node.next;49 node.next = next_node.next;
48 return next_node;50 return next_node;
49 }51 }
50 };
5152
52 first: ?*Node = null,53 /// Iterate over the singly-linked list from this node, until the final node is found.
54 /// This operation is O(N).
55 pub fn findLast(node: *Node) *Node {
56 var it = node;
57 while (true) {
58 it = it.next orelse return it;
59 }
60 }
5361
54 /// Initialize a linked list.62 /// Iterate over each next node, returning the count of all nodes except the starting one.
55 ///63 /// This operation is O(N).
56 /// Returns:64 pub fn countChildren(node: *const Node) usize {
57 /// An empty linked list.65 var count: usize = 0;
58 pub fn init() Self {66 var it: ?*const Node = node;
59 return Self{67 while (it) |n| : (it = n.next) {
60 .first = null,68 count += 1;
61 };69 }
62 }70 return count;
71 }
72 };
6373
64 /// Insert a new node after an existing one.74 first: ?*Node = null,
65 ///
66 /// Arguments:
67 /// node: Pointer to a node in the list.
68 /// new_node: Pointer to the new node to insert.
69 pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
70 node.insertAfter(new_node);
71 }
7275
73 /// Insert a new node at the head.76 /// Insert a new node at the head.
74 ///77 ///
...@@ -105,64 +108,33 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -105,64 +108,33 @@ pub fn SinglyLinkedList(comptime T: type) type {
105 return first;108 return first;
106 }109 }
107110
108 /// Allocate a new node.111 /// Iterate over all nodes, returning the count.
109 ///112 /// This operation is O(N).
110 /// Arguments:113 pub fn len(list: Self) usize {
111 /// allocator: Dynamic memory allocator.114 if (list.first) |n| {
112 ///115 return 1 + n.countChildren();
113 /// Returns:116 } else {
114 /// A pointer to the new node.117 return 0;
115 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {118 }
116 return allocator.create(Node);
117 }
118
119 /// Deallocate a node.
120 ///
121 /// Arguments:
122 /// node: Pointer to the node to deallocate.
123 /// allocator: Dynamic memory allocator.
124 pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void {
125 allocator.destroy(node);
126 }
127
128 /// Allocate and initialize a node and its data.
129 ///
130 /// Arguments:
131 /// data: The data to put inside the node.
132 /// allocator: Dynamic memory allocator.
133 ///
134 /// Returns:
135 /// A pointer to the new node.
136 pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node {
137 var node = try list.allocateNode(allocator);
138 node.* = Node.init(data);
139 return node;
140 }119 }
141 };120 };
142}121}
143122
144test "basic SinglyLinkedList test" {123test "basic SinglyLinkedList test" {
145 const allocator = testing.allocator;124 const L = SinglyLinkedList(u32);
146 var list = SinglyLinkedList(u32).init();125 var list = L{};
147126
148 var one = try list.createNode(1, allocator);127 var one = L.Node{.data = 1};
149 var two = try list.createNode(2, allocator);128 var two = L.Node{.data = 2};
150 var three = try list.createNode(3, allocator);129 var three = L.Node{.data = 3};
151 var four = try list.createNode(4, allocator);130 var four = L.Node{.data = 4};
152 var five = try list.createNode(5, allocator);131 var five = L.Node{.data = 5};
153 defer {
154 list.destroyNode(one, allocator);
155 list.destroyNode(two, allocator);
156 list.destroyNode(three, allocator);
157 list.destroyNode(four, allocator);
158 list.destroyNode(five, allocator);
159 }
160132
161 list.prepend(two); // {2}133 list.prepend(&two); // {2}
162 list.insertAfter(two, five); // {2, 5}134 two.insertAfter(&five); // {2, 5}
163 list.prepend(one); // {1, 2, 5}135 list.prepend(&one); // {1, 2, 5}
164 list.insertAfter(two, three); // {1, 2, 3, 5}136 two.insertAfter(&three); // {1, 2, 3, 5}
165 list.insertAfter(three, four); // {1, 2, 3, 4, 5}137 three.insertAfter(&four); // {1, 2, 3, 4, 5}
166138
167 // Traverse forwards.139 // Traverse forwards.
168 {140 {
...@@ -175,7 +147,7 @@ test "basic SinglyLinkedList test" {...@@ -175,7 +147,7 @@ test "basic SinglyLinkedList test" {
175 }147 }
176148
177 _ = list.popFirst(); // {2, 3, 4, 5}149 _ = list.popFirst(); // {2, 3, 4, 5}
178 _ = list.remove(five); // {2, 3, 4}150 _ = list.remove(&five); // {2, 3, 4}
179 _ = two.removeNext(); // {2, 4}151 _ = two.removeNext(); // {2, 4}
180152
181 testing.expect(list.first.?.data == 2);153 testing.expect(list.first.?.data == 2);
lib/std/rand.zig+1-1
...@@ -658,7 +658,7 @@ pub const Xoroshiro128 = struct {...@@ -658,7 +658,7 @@ pub const Xoroshiro128 = struct {
658 self.s[1] = s1;658 self.s[1] = s1;
659 }659 }
660660
661 fn seed(self: *Xoroshiro128, init_s: u64) void {661 pub fn seed(self: *Xoroshiro128, init_s: u64) void {
662 // Xoroshiro requires 128-bits of seed.662 // Xoroshiro requires 128-bits of seed.
663 var gen = SplitMix64.init(init_s);663 var gen = SplitMix64.init(init_s);
664664
lib/std/testing.zig+4-3
...@@ -320,10 +320,11 @@ fn printWithVisibleNewlines(source: []const u8) void {...@@ -320,10 +320,11 @@ fn printWithVisibleNewlines(source: []const u8) void {
320}320}
321321
322fn printLine(line: []const u8) void {322fn printLine(line: []const u8) void {
323 switch (line[line.len - 1]) {323 if (line.len != 0) switch (line[line.len - 1]) {
324 ' ', '\t' => warn("{}⏎\n", .{line}), // Carriage return symbol,324 ' ', '\t' => warn("{}⏎\n", .{line}), // Carriage return symbol,
325 else => warn("{}\n", .{line}),325 else => {},
326 }326 };
327 warn("{}\n", .{line});
327}328}
328329
329test "" {330test "" {
lib/std/zig/ast.zig+783-313
...@@ -1,51 +1,50 @@...@@ -1,51 +1,50 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const SegmentedList = std.SegmentedList;
5const mem = std.mem;4const mem = std.mem;
6const Token = std.zig.Token;5const Token = std.zig.Token;
76
8pub const TokenIndex = usize;7pub const TokenIndex = usize;
8pub const NodeIndex = usize;
99
10pub const Tree = struct {10pub const Tree = struct {
11 /// Reference to externally-owned data.
11 source: []const u8,12 source: []const u8,
12 tokens: TokenList,13 token_ids: []const Token.Id,
1314 token_locs: []const Token.Loc,
14 /// undefined on parse error (errors not empty)15 errors: []const Error,
16 /// undefined on parse error (when errors field is not empty)
15 root_node: *Node.Root,17 root_node: *Node.Root,
16 arena_allocator: std.heap.ArenaAllocator,18
17 errors: ErrorList,19 arena: std.heap.ArenaAllocator.State,
20 gpa: *mem.Allocator,
1821
19 /// translate-c uses this to avoid having to emit correct newlines22 /// translate-c uses this to avoid having to emit correct newlines
20 /// TODO get rid of this hack23 /// TODO get rid of this hack
21 generated: bool = false,24 generated: bool = false,
2225
23 pub const TokenList = SegmentedList(Token, 64);
24 pub const ErrorList = SegmentedList(Error, 0);
25
26 pub fn deinit(self: *Tree) void {26 pub fn deinit(self: *Tree) void {
27 // Here we copy the arena allocator into stack memory, because27 self.gpa.free(self.token_ids);
28 // otherwise it would destroy itself while it was still working.28 self.gpa.free(self.token_locs);
29 var arena_allocator = self.arena_allocator;29 self.gpa.free(self.errors);
30 arena_allocator.deinit();30 self.arena.promote(self.gpa).deinit();
31 // self is destroyed
32 }31 }
3332
34 pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {33 pub fn renderError(self: *Tree, parse_error: *const Error, stream: var) !void {
35 return parse_error.render(&self.tokens, stream);34 return parse_error.render(self.token_ids, stream);
36 }35 }
3736
38 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {37 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {
39 return self.tokenSlicePtr(self.tokens.at(token_index));38 return self.tokenSliceLoc(self.token_locs[token_index]);
40 }39 }
4140
42 pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {41 pub fn tokenSliceLoc(self: *Tree, token: Token.Loc) []const u8 {
43 return self.source[token.start..token.end];42 return self.source[token.start..token.end];
44 }43 }
4544
46 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {45 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {
47 const first_token = self.tokens.at(node.firstToken());46 const first_token = self.token_locs[node.firstToken()];
48 const last_token = self.tokens.at(node.lastToken());47 const last_token = self.token_locs[node.lastToken()];
49 return self.source[first_token.start..last_token.end];48 return self.source[first_token.start..last_token.end];
50 }49 }
5150
...@@ -57,7 +56,7 @@ pub const Tree = struct {...@@ -57,7 +56,7 @@ pub const Tree = struct {
57 };56 };
5857
59 /// Return the Location of the token relative to the offset specified by `start_index`.58 /// Return the Location of the token relative to the offset specified by `start_index`.
60 pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: *const Token) Location {59 pub fn tokenLocationLoc(self: *Tree, start_index: usize, token: Token.Loc) Location {
61 var loc = Location{60 var loc = Location{
62 .line = 0,61 .line = 0,
63 .column = 0,62 .column = 0,
...@@ -85,14 +84,14 @@ pub const Tree = struct {...@@ -85,14 +84,14 @@ pub const Tree = struct {
85 }84 }
8685
87 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {86 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {
88 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));87 return self.tokenLocationLoc(start_index, self.token_locs[token_index]);
89 }88 }
9089
91 pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {90 pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {
92 return self.tokensOnSameLinePtr(self.tokens.at(token1_index), self.tokens.at(token2_index));91 return self.tokensOnSameLineLoc(self.token_locs[token1_index], self.token_locs[token2_index]);
93 }92 }
9493
95 pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool {94 pub fn tokensOnSameLineLoc(self: *Tree, token1: Token.Loc, token2: Token.Loc) bool {
96 return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;95 return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;
97 }96 }
9897
...@@ -103,7 +102,7 @@ pub const Tree = struct {...@@ -103,7 +102,7 @@ pub const Tree = struct {
103 /// Skips over comments102 /// Skips over comments
104 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {103 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
105 var index = token_index - 1;104 var index = token_index - 1;
106 while (self.tokens.at(index).id == Token.Id.LineComment) {105 while (self.token_ids[index] == Token.Id.LineComment) {
107 index -= 1;106 index -= 1;
108 }107 }
109 return index;108 return index;
...@@ -112,7 +111,7 @@ pub const Tree = struct {...@@ -112,7 +111,7 @@ pub const Tree = struct {
112 /// Skips over comments111 /// Skips over comments
113 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {112 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
114 var index = token_index + 1;113 var index = token_index + 1;
115 while (self.tokens.at(index).id == Token.Id.LineComment) {114 while (self.token_ids[index] == Token.Id.LineComment) {
116 index += 1;115 index += 1;
117 }116 }
118 return index;117 return index;
...@@ -169,7 +168,7 @@ pub const Error = union(enum) {...@@ -169,7 +168,7 @@ pub const Error = union(enum) {
169 DeclBetweenFields: DeclBetweenFields,168 DeclBetweenFields: DeclBetweenFields,
170 InvalidAnd: InvalidAnd,169 InvalidAnd: InvalidAnd,
171170
172 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {171 pub fn render(self: *const Error, tokens: []const Token.Id, stream: var) !void {
173 switch (self.*) {172 switch (self.*) {
174 .InvalidToken => |*x| return x.render(tokens, stream),173 .InvalidToken => |*x| return x.render(tokens, stream),
175 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),174 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),
...@@ -324,8 +323,8 @@ pub const Error = union(enum) {...@@ -324,8 +323,8 @@ pub const Error = union(enum) {
324 pub const ExpectedCall = struct {323 pub const ExpectedCall = struct {
325 node: *Node,324 node: *Node,
326325
327 pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void {326 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: var) !void {
328 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{327 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
329 @tagName(self.node.id),328 @tagName(self.node.id),
330 });329 });
331 }330 }
...@@ -334,8 +333,8 @@ pub const Error = union(enum) {...@@ -334,8 +333,8 @@ pub const Error = union(enum) {
334 pub const ExpectedCallOrFnProto = struct {333 pub const ExpectedCallOrFnProto = struct {
335 node: *Node,334 node: *Node,
336335
337 pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void {336 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: var) !void {
338 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++337 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
339 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});338 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
340 }339 }
341 };340 };
...@@ -344,14 +343,14 @@ pub const Error = union(enum) {...@@ -344,14 +343,14 @@ pub const Error = union(enum) {
344 token: TokenIndex,343 token: TokenIndex,
345 expected_id: Token.Id,344 expected_id: Token.Id,
346345
347 pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {346 pub fn render(self: *const ExpectedToken, tokens: []const Token.Id, stream: var) !void {
348 const found_token = tokens.at(self.token);347 const found_token = tokens[self.token];
349 switch (found_token.id) {348 switch (found_token) {
350 .Invalid => {349 .Invalid => {
351 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});350 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
352 },351 },
353 else => {352 else => {
354 const token_name = found_token.id.symbol();353 const token_name = found_token.symbol();
355 return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });354 return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
356 },355 },
357 }356 }
...@@ -362,11 +361,11 @@ pub const Error = union(enum) {...@@ -362,11 +361,11 @@ pub const Error = union(enum) {
362 token: TokenIndex,361 token: TokenIndex,
363 end_id: Token.Id,362 end_id: Token.Id,
364363
365 pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void {364 pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token.Id, stream: var) !void {
366 const actual_token = tokens.at(self.token);365 const actual_token = tokens[self.token];
367 return stream.print("expected ',' or '{}', found '{}'", .{366 return stream.print("expected ',' or '{}', found '{}'", .{
368 self.end_id.symbol(),367 self.end_id.symbol(),
369 actual_token.id.symbol(),368 actual_token.symbol(),
370 });369 });
371 }370 }
372 };371 };
...@@ -377,9 +376,9 @@ pub const Error = union(enum) {...@@ -377,9 +376,9 @@ pub const Error = union(enum) {
377376
378 token: TokenIndex,377 token: TokenIndex,
379378
380 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {379 pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void {
381 const actual_token = tokens.at(self.token);380 const actual_token = tokens[self.token];
382 return stream.print(msg, .{actual_token.id.symbol()});381 return stream.print(msg, .{actual_token.symbol()});
383 }382 }
384 };383 };
385 }384 }
...@@ -390,7 +389,7 @@ pub const Error = union(enum) {...@@ -390,7 +389,7 @@ pub const Error = union(enum) {
390389
391 token: TokenIndex,390 token: TokenIndex,
392391
393 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {392 pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void {
394 return stream.writeAll(msg);393 return stream.writeAll(msg);
395 }394 }
396 };395 };
...@@ -413,7 +412,19 @@ pub const Node = struct {...@@ -413,7 +412,19 @@ pub const Node = struct {
413 // Operators412 // Operators
414 InfixOp,413 InfixOp,
415 PrefixOp,414 PrefixOp,
415 /// Not all suffix operations are under this tag. To save memory, some
416 /// suffix operations have dedicated Node tags.
416 SuffixOp,417 SuffixOp,
418 /// `T{a, b}`
419 ArrayInitializer,
420 /// ArrayInitializer but with `.` instead of a left-hand-side operand.
421 ArrayInitializerDot,
422 /// `T{.a = b}`
423 StructInitializer,
424 /// StructInitializer but with `.` instead of a left-hand-side operand.
425 StructInitializerDot,
426 /// `foo()`
427 Call,
417428
418 // Control flow429 // Control flow
419 Switch,430 Switch,
...@@ -460,9 +471,6 @@ pub const Node = struct {...@@ -460,9 +471,6 @@ pub const Node = struct {
460 PointerIndexPayload,471 PointerIndexPayload,
461 ContainerField,472 ContainerField,
462 ErrorTag,473 ErrorTag,
463 AsmInput,
464 AsmOutput,
465 ParamDecl,
466 FieldInitializer,474 FieldInitializer,
467 };475 };
468476
...@@ -518,7 +526,6 @@ pub const Node = struct {...@@ -518,7 +526,6 @@ pub const Node = struct {
518 switch (n.id) {526 switch (n.id) {
519 .Root,527 .Root,
520 .ContainerField,528 .ContainerField,
521 .ParamDecl,
522 .Block,529 .Block,
523 .Payload,530 .Payload,
524 .PointerPayload,531 .PointerPayload,
...@@ -602,26 +609,57 @@ pub const Node = struct {...@@ -602,26 +609,57 @@ pub const Node = struct {
602 }609 }
603 }610 }
604611
612 /// The decls data follows this struct in memory as an array of Node pointers.
605 pub const Root = struct {613 pub const Root = struct {
606 base: Node = Node{ .id = .Root },614 base: Node = Node{ .id = .Root },
607 decls: DeclList,
608 eof_token: TokenIndex,615 eof_token: TokenIndex,
616 decls_len: NodeIndex,
617
618 /// After this the caller must initialize the decls list.
619 pub fn create(allocator: *mem.Allocator, decls_len: NodeIndex, eof_token: TokenIndex) !*Root {
620 const bytes = try allocator.alignedAlloc(u8, @alignOf(Root), sizeInBytes(decls_len));
621 const self = @ptrCast(*Root, bytes.ptr);
622 self.* = .{
623 .eof_token = eof_token,
624 .decls_len = decls_len,
625 };
626 return self;
627 }
628
629 pub fn destroy(self: *Decl, allocator: *mem.Allocator) void {
630 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)];
631 allocator.free(bytes);
632 }
609633
610 pub const DeclList = SegmentedList(*Node, 4);634 pub fn iterate(self: *const Root, index: usize) ?*Node {
635 var i = index;
611636
612 pub fn iterate(self: *Root, index: usize) ?*Node {637 if (i < self.decls_len) return self.declsConst()[i];
613 if (index < self.decls.len) {
614 return self.decls.at(index).*;
615 }
616 return null;638 return null;
617 }639 }
618640
641 pub fn decls(self: *Root) []*Node {
642 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Root);
643 return @ptrCast([*]*Node, decls_start)[0..self.decls_len];
644 }
645
646 pub fn declsConst(self: *const Root) []const *Node {
647 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Root);
648 return @ptrCast([*]const *Node, decls_start)[0..self.decls_len];
649 }
650
619 pub fn firstToken(self: *const Root) TokenIndex {651 pub fn firstToken(self: *const Root) TokenIndex {
620 return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();652 if (self.decls_len == 0) return self.eof_token;
653 return self.declsConst()[0].firstToken();
621 }654 }
622655
623 pub fn lastToken(self: *const Root) TokenIndex {656 pub fn lastToken(self: *const Root) TokenIndex {
624 return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken();657 if (self.decls_len == 0) return self.eof_token;
658 return self.declsConst()[self.decls_len - 1].lastToken();
659 }
660
661 fn sizeInBytes(decls_len: NodeIndex) usize {
662 return @sizeOf(Root) + @sizeOf(*Node) * @as(usize, decls_len);
625 }663 }
626 };664 };
627665
...@@ -642,7 +680,7 @@ pub const Node = struct {...@@ -642,7 +680,7 @@ pub const Node = struct {
642 init_node: ?*Node,680 init_node: ?*Node,
643 semicolon_token: TokenIndex,681 semicolon_token: TokenIndex,
644682
645 pub fn iterate(self: *VarDecl, index: usize) ?*Node {683 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
646 var i = index;684 var i = index;
647685
648 if (self.type_node) |type_node| {686 if (self.type_node) |type_node| {
...@@ -668,6 +706,7 @@ pub const Node = struct {...@@ -668,6 +706,7 @@ pub const Node = struct {
668 return null;706 return null;
669 }707 }
670708
709
671 pub fn firstToken(self: *const VarDecl) TokenIndex {710 pub fn firstToken(self: *const VarDecl) TokenIndex {
672 if (self.visib_token) |visib_token| return visib_token;711 if (self.visib_token) |visib_token| return visib_token;
673 if (self.thread_local_token) |thread_local_token| return thread_local_token;712 if (self.thread_local_token) |thread_local_token| return thread_local_token;
...@@ -690,7 +729,7 @@ pub const Node = struct {...@@ -690,7 +729,7 @@ pub const Node = struct {
690 expr: *Node,729 expr: *Node,
691 semicolon_token: TokenIndex,730 semicolon_token: TokenIndex,
692731
693 pub fn iterate(self: *Use, index: usize) ?*Node {732 pub fn iterate(self: *const Use, index: usize) ?*Node {
694 var i = index;733 var i = index;
695734
696 if (i < 1) return self.expr;735 if (i < 1) return self.expr;
...@@ -712,16 +751,25 @@ pub const Node = struct {...@@ -712,16 +751,25 @@ pub const Node = struct {
712 pub const ErrorSetDecl = struct {751 pub const ErrorSetDecl = struct {
713 base: Node = Node{ .id = .ErrorSetDecl },752 base: Node = Node{ .id = .ErrorSetDecl },
714 error_token: TokenIndex,753 error_token: TokenIndex,
715 decls: DeclList,
716 rbrace_token: TokenIndex,754 rbrace_token: TokenIndex,
755 decls_len: NodeIndex,
717756
718 pub const DeclList = SegmentedList(*Node, 2);757 /// After this the caller must initialize the decls list.
758 pub fn alloc(allocator: *mem.Allocator, decls_len: NodeIndex) !*ErrorSetDecl {
759 const bytes = try allocator.alignedAlloc(u8, @alignOf(ErrorSetDecl), sizeInBytes(decls_len));
760 return @ptrCast(*ErrorSetDecl, bytes.ptr);
761 }
719762
720 pub fn iterate(self: *ErrorSetDecl, index: usize) ?*Node {763 pub fn free(self: *ErrorSetDecl, allocator: *mem.Allocator) void {
764 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)];
765 allocator.free(bytes);
766 }
767
768 pub fn iterate(self: *const ErrorSetDecl, index: usize) ?*Node {
721 var i = index;769 var i = index;
722770
723 if (i < self.decls.len) return self.decls.at(i).*;771 if (i < self.decls_len) return self.declsConst()[i];
724 i -= self.decls.len;772 i -= self.decls_len;
725773
726 return null;774 return null;
727 }775 }
...@@ -733,18 +781,31 @@ pub const Node = struct {...@@ -733,18 +781,31 @@ pub const Node = struct {
733 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {781 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
734 return self.rbrace_token;782 return self.rbrace_token;
735 }783 }
784
785 pub fn decls(self: *ErrorSetDecl) []*Node {
786 const decls_start = @ptrCast([*]u8, self) + @sizeOf(ErrorSetDecl);
787 return @ptrCast([*]*Node, decls_start)[0..self.decls_len];
788 }
789
790 pub fn declsConst(self: *const ErrorSetDecl) []const *Node {
791 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ErrorSetDecl);
792 return @ptrCast([*]const *Node, decls_start)[0..self.decls_len];
793 }
794
795 fn sizeInBytes(decls_len: NodeIndex) usize {
796 return @sizeOf(ErrorSetDecl) + @sizeOf(*Node) * @as(usize, decls_len);
797 }
736 };798 };
737799
800 /// The fields and decls Node pointers directly follow this struct in memory.
738 pub const ContainerDecl = struct {801 pub const ContainerDecl = struct {
739 base: Node = Node{ .id = .ContainerDecl },802 base: Node = Node{ .id = .ContainerDecl },
740 layout_token: ?TokenIndex,
741 kind_token: TokenIndex,803 kind_token: TokenIndex,
742 init_arg_expr: InitArg,804 layout_token: ?TokenIndex,
743 fields_and_decls: DeclList,
744 lbrace_token: TokenIndex,805 lbrace_token: TokenIndex,
745 rbrace_token: TokenIndex,806 rbrace_token: TokenIndex,
746807 fields_and_decls_len: NodeIndex,
747 pub const DeclList = Root.DeclList;808 init_arg_expr: InitArg,
748809
749 pub const InitArg = union(enum) {810 pub const InitArg = union(enum) {
750 None,811 None,
...@@ -752,7 +813,18 @@ pub const Node = struct {...@@ -752,7 +813,18 @@ pub const Node = struct {
752 Type: *Node,813 Type: *Node,
753 };814 };
754815
755 pub fn iterate(self: *ContainerDecl, index: usize) ?*Node {816 /// After this the caller must initialize the fields_and_decls list.
817 pub fn alloc(allocator: *mem.Allocator, fields_and_decls_len: NodeIndex) !*ContainerDecl {
818 const bytes = try allocator.alignedAlloc(u8, @alignOf(ContainerDecl), sizeInBytes(fields_and_decls_len));
819 return @ptrCast(*ContainerDecl, bytes.ptr);
820 }
821
822 pub fn free(self: *ContainerDecl, allocator: *mem.Allocator) void {
823 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.fields_and_decls_len)];
824 allocator.free(bytes);
825 }
826
827 pub fn iterate(self: *const ContainerDecl, index: usize) ?*Node {
756 var i = index;828 var i = index;
757829
758 switch (self.init_arg_expr) {830 switch (self.init_arg_expr) {
...@@ -763,8 +835,8 @@ pub const Node = struct {...@@ -763,8 +835,8 @@ pub const Node = struct {
763 .None, .Enum => {},835 .None, .Enum => {},
764 }836 }
765837
766 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;838 if (i < self.fields_and_decls_len) return self.fieldsAndDeclsConst()[i];
767 i -= self.fields_and_decls.len;839 i -= self.fields_and_decls_len;
768840
769 return null;841 return null;
770 }842 }
...@@ -779,6 +851,20 @@ pub const Node = struct {...@@ -779,6 +851,20 @@ pub const Node = struct {
779 pub fn lastToken(self: *const ContainerDecl) TokenIndex {851 pub fn lastToken(self: *const ContainerDecl) TokenIndex {
780 return self.rbrace_token;852 return self.rbrace_token;
781 }853 }
854
855 pub fn fieldsAndDecls(self: *ContainerDecl) []*Node {
856 const decls_start = @ptrCast([*]u8, self) + @sizeOf(ContainerDecl);
857 return @ptrCast([*]*Node, decls_start)[0..self.fields_and_decls_len];
858 }
859
860 pub fn fieldsAndDeclsConst(self: *const ContainerDecl) []const *Node {
861 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ContainerDecl);
862 return @ptrCast([*]const *Node, decls_start)[0..self.fields_and_decls_len];
863 }
864
865 fn sizeInBytes(fields_and_decls_len: NodeIndex) usize {
866 return @sizeOf(ContainerDecl) + @sizeOf(*Node) * @as(usize, fields_and_decls_len);
867 }
782 };868 };
783869
784 pub const ContainerField = struct {870 pub const ContainerField = struct {
...@@ -790,7 +876,7 @@ pub const Node = struct {...@@ -790,7 +876,7 @@ pub const Node = struct {
790 value_expr: ?*Node,876 value_expr: ?*Node,
791 align_expr: ?*Node,877 align_expr: ?*Node,
792878
793 pub fn iterate(self: *ContainerField, index: usize) ?*Node {879 pub fn iterate(self: *const ContainerField, index: usize) ?*Node {
794 var i = index;880 var i = index;
795881
796 if (self.type_expr) |type_expr| {882 if (self.type_expr) |type_expr| {
...@@ -837,7 +923,7 @@ pub const Node = struct {...@@ -837,7 +923,7 @@ pub const Node = struct {
837 doc_comments: ?*DocComment,923 doc_comments: ?*DocComment,
838 name_token: TokenIndex,924 name_token: TokenIndex,
839925
840 pub fn iterate(self: *ErrorTag, index: usize) ?*Node {926 pub fn iterate(self: *const ErrorTag, index: usize) ?*Node {
841 var i = index;927 var i = index;
842928
843 if (self.doc_comments) |comments| {929 if (self.doc_comments) |comments| {
...@@ -861,7 +947,7 @@ pub const Node = struct {...@@ -861,7 +947,7 @@ pub const Node = struct {
861 base: Node = Node{ .id = .Identifier },947 base: Node = Node{ .id = .Identifier },
862 token: TokenIndex,948 token: TokenIndex,
863949
864 pub fn iterate(self: *Identifier, index: usize) ?*Node {950 pub fn iterate(self: *const Identifier, index: usize) ?*Node {
865 return null;951 return null;
866 }952 }
867953
...@@ -874,13 +960,14 @@ pub const Node = struct {...@@ -874,13 +960,14 @@ pub const Node = struct {
874 }960 }
875 };961 };
876962
963 /// The params are directly after the FnProto in memory.
877 pub const FnProto = struct {964 pub const FnProto = struct {
878 base: Node = Node{ .id = .FnProto },965 base: Node = Node{ .id = .FnProto },
879 doc_comments: ?*DocComment,966 doc_comments: ?*DocComment,
880 visib_token: ?TokenIndex,967 visib_token: ?TokenIndex,
881 fn_token: TokenIndex,968 fn_token: TokenIndex,
882 name_token: ?TokenIndex,969 name_token: ?TokenIndex,
883 params: ParamList,970 params_len: NodeIndex,
884 return_type: ReturnType,971 return_type: ReturnType,
885 var_args_token: ?TokenIndex,972 var_args_token: ?TokenIndex,
886 extern_export_inline_token: ?TokenIndex,973 extern_export_inline_token: ?TokenIndex,
...@@ -892,15 +979,69 @@ pub const Node = struct {...@@ -892,15 +979,69 @@ pub const Node = struct {
892 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is979 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
893 is_async: bool = false, // TODO: remove once async fn rewriting is980 is_async: bool = false, // TODO: remove once async fn rewriting is
894981
895 pub const ParamList = SegmentedList(*Node, 2);
896
897 pub const ReturnType = union(enum) {982 pub const ReturnType = union(enum) {
898 Explicit: *Node,983 Explicit: *Node,
899 InferErrorSet: *Node,984 InferErrorSet: *Node,
900 Invalid: TokenIndex,985 Invalid: TokenIndex,
901 };986 };
902987
903 pub fn iterate(self: *FnProto, index: usize) ?*Node {988 pub const ParamDecl = struct {
989 doc_comments: ?*DocComment,
990 comptime_token: ?TokenIndex,
991 noalias_token: ?TokenIndex,
992 name_token: ?TokenIndex,
993 param_type: ParamType,
994
995 pub const ParamType = union(enum) {
996 var_type: *Node,
997 var_args: TokenIndex,
998 type_expr: *Node,
999 };
1000
1001 pub fn iterate(self: *const ParamDecl, index: usize) ?*Node {
1002 var i = index;
1003
1004 if (i < 1) {
1005 switch (self.param_type) {
1006 .var_args => return null,
1007 .var_type, .type_expr => |node| return node,
1008 }
1009 }
1010 i -= 1;
1011
1012 return null;
1013 }
1014
1015 pub fn firstToken(self: *const ParamDecl) TokenIndex {
1016 if (self.comptime_token) |comptime_token| return comptime_token;
1017 if (self.noalias_token) |noalias_token| return noalias_token;
1018 if (self.name_token) |name_token| return name_token;
1019 switch (self.param_type) {
1020 .var_args => |tok| return tok,
1021 .var_type, .type_expr => |node| return node.firstToken(),
1022 }
1023 }
1024
1025 pub fn lastToken(self: *const ParamDecl) TokenIndex {
1026 switch (self.param_type) {
1027 .var_args => |tok| return tok,
1028 .var_type, .type_expr => |node| return node.lastToken(),
1029 }
1030 }
1031 };
1032
1033 /// After this the caller must initialize the params list.
1034 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {
1035 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));
1036 return @ptrCast(*FnProto, bytes.ptr);
1037 }
1038
1039 pub fn free(self: *FnProto, allocator: *mem.Allocator) void {
1040 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
1041 allocator.free(bytes);
1042 }
1043
1044 pub fn iterate(self: *const FnProto, index: usize) ?*Node {
904 var i = index;1045 var i = index;
9051046
906 if (self.lib_name) |lib_name| {1047 if (self.lib_name) |lib_name| {
...@@ -908,8 +1049,18 @@ pub const Node = struct {...@@ -908,8 +1049,18 @@ pub const Node = struct {
908 i -= 1;1049 i -= 1;
909 }1050 }
9101051
911 if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;1052 const params_len = switch (self.paramsConst()[self.params_len - 1].param_type) {
912 i -= self.params.len;1053 .var_type, .type_expr => self.params_len,
1054 .var_args => self.params_len - 1,
1055 };
1056 if (i < params_len) {
1057 switch (self.paramsConst()[i].param_type) {
1058 .var_type => |n| return n,
1059 .var_args => unreachable,
1060 .type_expr => |n| return n,
1061 }
1062 }
1063 i -= params_len;
9131064
914 if (self.align_expr) |align_expr| {1065 if (self.align_expr) |align_expr| {
915 if (i < 1) return align_expr;1066 if (i < 1) return align_expr;
...@@ -951,6 +1102,20 @@ pub const Node = struct {...@@ -951,6 +1102,20 @@ pub const Node = struct {
951 .Invalid => |tok| return tok,1102 .Invalid => |tok| return tok,
952 }1103 }
953 }1104 }
1105
1106 pub fn params(self: *FnProto) []ParamDecl {
1107 const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1108 return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];
1109 }
1110
1111 pub fn paramsConst(self: *const FnProto) []const ParamDecl {
1112 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1113 return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];
1114 }
1115
1116 fn sizeInBytes(params_len: NodeIndex) usize {
1117 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);
1118 }
954 };1119 };
9551120
956 pub const AnyFrameType = struct {1121 pub const AnyFrameType = struct {
...@@ -963,7 +1128,7 @@ pub const Node = struct {...@@ -963,7 +1128,7 @@ pub const Node = struct {
963 return_type: *Node,1128 return_type: *Node,
964 };1129 };
9651130
966 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {1131 pub fn iterate(self: *const AnyFrameType, index: usize) ?*Node {
967 var i = index;1132 var i = index;
9681133
969 if (self.result) |result| {1134 if (self.result) |result| {
...@@ -984,66 +1149,30 @@ pub const Node = struct {...@@ -984,66 +1149,30 @@ pub const Node = struct {
984 }1149 }
985 };1150 };
9861151
987 pub const ParamDecl = struct {1152 /// The statements of the block follow Block directly in memory.
988 base: Node = Node{ .id = .ParamDecl },
989 doc_comments: ?*DocComment,
990 comptime_token: ?TokenIndex,
991 noalias_token: ?TokenIndex,
992 name_token: ?TokenIndex,
993 param_type: ParamType,
994
995 pub const ParamType = union(enum) {
996 var_type: *Node,
997 var_args: TokenIndex,
998 type_expr: *Node,
999 };
1000
1001 pub fn iterate(self: *ParamDecl, index: usize) ?*Node {
1002 var i = index;
1003
1004 if (i < 1) {
1005 switch (self.param_type) {
1006 .var_args => return null,
1007 .var_type, .type_expr => |node| return node,
1008 }
1009 }
1010 i -= 1;
1011
1012 return null;
1013 }
1014
1015 pub fn firstToken(self: *const ParamDecl) TokenIndex {
1016 if (self.comptime_token) |comptime_token| return comptime_token;
1017 if (self.noalias_token) |noalias_token| return noalias_token;
1018 if (self.name_token) |name_token| return name_token;
1019 switch (self.param_type) {
1020 .var_args => |tok| return tok,
1021 .var_type, .type_expr => |node| return node.firstToken(),
1022 }
1023 }
1024
1025 pub fn lastToken(self: *const ParamDecl) TokenIndex {
1026 switch (self.param_type) {
1027 .var_args => |tok| return tok,
1028 .var_type, .type_expr => |node| return node.lastToken(),
1029 }
1030 }
1031 };
1032
1033 pub const Block = struct {1153 pub const Block = struct {
1034 base: Node = Node{ .id = .Block },1154 base: Node = Node{ .id = .Block },
1035 label: ?TokenIndex,1155 statements_len: NodeIndex,
1036 lbrace: TokenIndex,1156 lbrace: TokenIndex,
1037 statements: StatementList,
1038 rbrace: TokenIndex,1157 rbrace: TokenIndex,
1158 label: ?TokenIndex,
1159
1160 /// After this the caller must initialize the statements list.
1161 pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*Block {
1162 const bytes = try allocator.alignedAlloc(u8, @alignOf(Block), sizeInBytes(statements_len));
1163 return @ptrCast(*Block, bytes.ptr);
1164 }
10391165
1040 pub const StatementList = Root.DeclList;1166 pub fn free(self: *Block, allocator: *mem.Allocator) void {
1167 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.statements_len)];
1168 allocator.free(bytes);
1169 }
10411170
1042 pub fn iterate(self: *Block, index: usize) ?*Node {1171 pub fn iterate(self: *const Block, index: usize) ?*Node {
1043 var i = index;1172 var i = index;
10441173
1045 if (i < self.statements.len) return self.statements.at(i).*;1174 if (i < self.statements_len) return self.statementsConst()[i];
1046 i -= self.statements.len;1175 i -= self.statements_len;
10471176
1048 return null;1177 return null;
1049 }1178 }
...@@ -1059,6 +1188,20 @@ pub const Node = struct {...@@ -1059,6 +1188,20 @@ pub const Node = struct {
1059 pub fn lastToken(self: *const Block) TokenIndex {1188 pub fn lastToken(self: *const Block) TokenIndex {
1060 return self.rbrace;1189 return self.rbrace;
1061 }1190 }
1191
1192 pub fn statements(self: *Block) []*Node {
1193 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Block);
1194 return @ptrCast([*]*Node, decls_start)[0..self.statements_len];
1195 }
1196
1197 pub fn statementsConst(self: *const Block) []const *Node {
1198 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Block);
1199 return @ptrCast([*]const *Node, decls_start)[0..self.statements_len];
1200 }
1201
1202 fn sizeInBytes(statements_len: NodeIndex) usize {
1203 return @sizeOf(Block) + @sizeOf(*Node) * @as(usize, statements_len);
1204 }
1062 };1205 };
10631206
1064 pub const Defer = struct {1207 pub const Defer = struct {
...@@ -1067,7 +1210,7 @@ pub const Node = struct {...@@ -1067,7 +1210,7 @@ pub const Node = struct {
1067 payload: ?*Node,1210 payload: ?*Node,
1068 expr: *Node,1211 expr: *Node,
10691212
1070 pub fn iterate(self: *Defer, index: usize) ?*Node {1213 pub fn iterate(self: *const Defer, index: usize) ?*Node {
1071 var i = index;1214 var i = index;
10721215
1073 if (i < 1) return self.expr;1216 if (i < 1) return self.expr;
...@@ -1091,7 +1234,7 @@ pub const Node = struct {...@@ -1091,7 +1234,7 @@ pub const Node = struct {
1091 comptime_token: TokenIndex,1234 comptime_token: TokenIndex,
1092 expr: *Node,1235 expr: *Node,
10931236
1094 pub fn iterate(self: *Comptime, index: usize) ?*Node {1237 pub fn iterate(self: *const Comptime, index: usize) ?*Node {
1095 var i = index;1238 var i = index;
10961239
1097 if (i < 1) return self.expr;1240 if (i < 1) return self.expr;
...@@ -1114,7 +1257,7 @@ pub const Node = struct {...@@ -1114,7 +1257,7 @@ pub const Node = struct {
1114 nosuspend_token: TokenIndex,1257 nosuspend_token: TokenIndex,
1115 expr: *Node,1258 expr: *Node,
11161259
1117 pub fn iterate(self: *Nosuspend, index: usize) ?*Node {1260 pub fn iterate(self: *const Nosuspend, index: usize) ?*Node {
1118 var i = index;1261 var i = index;
11191262
1120 if (i < 1) return self.expr;1263 if (i < 1) return self.expr;
...@@ -1138,7 +1281,7 @@ pub const Node = struct {...@@ -1138,7 +1281,7 @@ pub const Node = struct {
1138 error_symbol: *Node,1281 error_symbol: *Node,
1139 rpipe: TokenIndex,1282 rpipe: TokenIndex,
11401283
1141 pub fn iterate(self: *Payload, index: usize) ?*Node {1284 pub fn iterate(self: *const Payload, index: usize) ?*Node {
1142 var i = index;1285 var i = index;
11431286
1144 if (i < 1) return self.error_symbol;1287 if (i < 1) return self.error_symbol;
...@@ -1163,7 +1306,7 @@ pub const Node = struct {...@@ -1163,7 +1306,7 @@ pub const Node = struct {
1163 value_symbol: *Node,1306 value_symbol: *Node,
1164 rpipe: TokenIndex,1307 rpipe: TokenIndex,
11651308
1166 pub fn iterate(self: *PointerPayload, index: usize) ?*Node {1309 pub fn iterate(self: *const PointerPayload, index: usize) ?*Node {
1167 var i = index;1310 var i = index;
11681311
1169 if (i < 1) return self.value_symbol;1312 if (i < 1) return self.value_symbol;
...@@ -1189,7 +1332,7 @@ pub const Node = struct {...@@ -1189,7 +1332,7 @@ pub const Node = struct {
1189 index_symbol: ?*Node,1332 index_symbol: ?*Node,
1190 rpipe: TokenIndex,1333 rpipe: TokenIndex,
11911334
1192 pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node {1335 pub fn iterate(self: *const PointerIndexPayload, index: usize) ?*Node {
1193 var i = index;1336 var i = index;
11941337
1195 if (i < 1) return self.value_symbol;1338 if (i < 1) return self.value_symbol;
...@@ -1218,7 +1361,7 @@ pub const Node = struct {...@@ -1218,7 +1361,7 @@ pub const Node = struct {
1218 payload: ?*Node,1361 payload: ?*Node,
1219 body: *Node,1362 body: *Node,
12201363
1221 pub fn iterate(self: *Else, index: usize) ?*Node {1364 pub fn iterate(self: *const Else, index: usize) ?*Node {
1222 var i = index;1365 var i = index;
12231366
1224 if (self.payload) |payload| {1367 if (self.payload) |payload| {
...@@ -1241,25 +1384,34 @@ pub const Node = struct {...@@ -1241,25 +1384,34 @@ pub const Node = struct {
1241 }1384 }
1242 };1385 };
12431386
1387 /// The cases node pointers are found in memory after Switch.
1388 /// They must be SwitchCase or SwitchElse nodes.
1244 pub const Switch = struct {1389 pub const Switch = struct {
1245 base: Node = Node{ .id = .Switch },1390 base: Node = Node{ .id = .Switch },
1246 switch_token: TokenIndex,1391 switch_token: TokenIndex,
1392 rbrace: TokenIndex,
1393 cases_len: NodeIndex,
1247 expr: *Node,1394 expr: *Node,
12481395
1249 /// these must be SwitchCase nodes1396 /// After this the caller must initialize the fields_and_decls list.
1250 cases: CaseList,1397 pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch {
1251 rbrace: TokenIndex,1398 const bytes = try allocator.alignedAlloc(u8, @alignOf(Switch), sizeInBytes(cases_len));
1399 return @ptrCast(*Switch, bytes.ptr);
1400 }
12521401
1253 pub const CaseList = SegmentedList(*Node, 2);1402 pub fn free(self: *Switch, allocator: *mem.Allocator) void {
1403 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.cases_len)];
1404 allocator.free(bytes);
1405 }
12541406
1255 pub fn iterate(self: *Switch, index: usize) ?*Node {1407 pub fn iterate(self: *const Switch, index: usize) ?*Node {
1256 var i = index;1408 var i = index;
12571409
1258 if (i < 1) return self.expr;1410 if (i < 1) return self.expr;
1259 i -= 1;1411 i -= 1;
12601412
1261 if (i < self.cases.len) return self.cases.at(i).*;1413 if (i < self.cases_len) return self.casesConst()[i];
1262 i -= self.cases.len;1414 i -= self.cases_len;
12631415
1264 return null;1416 return null;
1265 }1417 }
...@@ -1271,22 +1423,46 @@ pub const Node = struct {...@@ -1271,22 +1423,46 @@ pub const Node = struct {
1271 pub fn lastToken(self: *const Switch) TokenIndex {1423 pub fn lastToken(self: *const Switch) TokenIndex {
1272 return self.rbrace;1424 return self.rbrace;
1273 }1425 }
1426
1427 pub fn cases(self: *Switch) []*Node {
1428 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Switch);
1429 return @ptrCast([*]*Node, decls_start)[0..self.cases_len];
1430 }
1431
1432 pub fn casesConst(self: *const Switch) []const *Node {
1433 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Switch);
1434 return @ptrCast([*]const *Node, decls_start)[0..self.cases_len];
1435 }
1436
1437 fn sizeInBytes(cases_len: NodeIndex) usize {
1438 return @sizeOf(Switch) + @sizeOf(*Node) * @as(usize, cases_len);
1439 }
1274 };1440 };
12751441
1442 /// Items sub-nodes appear in memory directly following SwitchCase.
1276 pub const SwitchCase = struct {1443 pub const SwitchCase = struct {
1277 base: Node = Node{ .id = .SwitchCase },1444 base: Node = Node{ .id = .SwitchCase },
1278 items: ItemList,
1279 arrow_token: TokenIndex,1445 arrow_token: TokenIndex,
1280 payload: ?*Node,1446 payload: ?*Node,
1281 expr: *Node,1447 expr: *Node,
1448 items_len: NodeIndex,
12821449
1283 pub const ItemList = SegmentedList(*Node, 1);1450 /// After this the caller must initialize the fields_and_decls list.
1451 pub fn alloc(allocator: *mem.Allocator, items_len: NodeIndex) !*SwitchCase {
1452 const bytes = try allocator.alignedAlloc(u8, @alignOf(SwitchCase), sizeInBytes(items_len));
1453 return @ptrCast(*SwitchCase, bytes.ptr);
1454 }
1455
1456 pub fn free(self: *SwitchCase, allocator: *mem.Allocator) void {
1457 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.items_len)];
1458 allocator.free(bytes);
1459 }
12841460
1285 pub fn iterate(self: *SwitchCase, index: usize) ?*Node {1461 pub fn iterate(self: *const SwitchCase, index: usize) ?*Node {
1286 var i = index;1462 var i = index;
12871463
1288 if (i < self.items.len) return self.items.at(i).*;1464 if (i < self.items_len) return self.itemsConst()[i];
1289 i -= self.items.len;1465 i -= self.items_len;
12901466
1291 if (self.payload) |payload| {1467 if (self.payload) |payload| {
1292 if (i < 1) return payload;1468 if (i < 1) return payload;
...@@ -1300,19 +1476,33 @@ pub const Node = struct {...@@ -1300,19 +1476,33 @@ pub const Node = struct {
1300 }1476 }
13011477
1302 pub fn firstToken(self: *const SwitchCase) TokenIndex {1478 pub fn firstToken(self: *const SwitchCase) TokenIndex {
1303 return (self.items.at(0).*).firstToken();1479 return self.itemsConst()[0].firstToken();
1304 }1480 }
13051481
1306 pub fn lastToken(self: *const SwitchCase) TokenIndex {1482 pub fn lastToken(self: *const SwitchCase) TokenIndex {
1307 return self.expr.lastToken();1483 return self.expr.lastToken();
1308 }1484 }
1485
1486 pub fn items(self: *SwitchCase) []*Node {
1487 const decls_start = @ptrCast([*]u8, self) + @sizeOf(SwitchCase);
1488 return @ptrCast([*]*Node, decls_start)[0..self.items_len];
1489 }
1490
1491 pub fn itemsConst(self: *const SwitchCase) []const *Node {
1492 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(SwitchCase);
1493 return @ptrCast([*]const *Node, decls_start)[0..self.items_len];
1494 }
1495
1496 fn sizeInBytes(items_len: NodeIndex) usize {
1497 return @sizeOf(SwitchCase) + @sizeOf(*Node) * @as(usize, items_len);
1498 }
1309 };1499 };
13101500
1311 pub const SwitchElse = struct {1501 pub const SwitchElse = struct {
1312 base: Node = Node{ .id = .SwitchElse },1502 base: Node = Node{ .id = .SwitchElse },
1313 token: TokenIndex,1503 token: TokenIndex,
13141504
1315 pub fn iterate(self: *SwitchElse, index: usize) ?*Node {1505 pub fn iterate(self: *const SwitchElse, index: usize) ?*Node {
1316 return null;1506 return null;
1317 }1507 }
13181508
...@@ -1336,7 +1526,7 @@ pub const Node = struct {...@@ -1336,7 +1526,7 @@ pub const Node = struct {
1336 body: *Node,1526 body: *Node,
1337 @"else": ?*Else,1527 @"else": ?*Else,
13381528
1339 pub fn iterate(self: *While, index: usize) ?*Node {1529 pub fn iterate(self: *const While, index: usize) ?*Node {
1340 var i = index;1530 var i = index;
13411531
1342 if (i < 1) return self.condition;1532 if (i < 1) return self.condition;
...@@ -1394,7 +1584,7 @@ pub const Node = struct {...@@ -1394,7 +1584,7 @@ pub const Node = struct {
1394 body: *Node,1584 body: *Node,
1395 @"else": ?*Else,1585 @"else": ?*Else,
13961586
1397 pub fn iterate(self: *For, index: usize) ?*Node {1587 pub fn iterate(self: *const For, index: usize) ?*Node {
1398 var i = index;1588 var i = index;
13991589
1400 if (i < 1) return self.array_expr;1590 if (i < 1) return self.array_expr;
...@@ -1443,7 +1633,7 @@ pub const Node = struct {...@@ -1443,7 +1633,7 @@ pub const Node = struct {
1443 body: *Node,1633 body: *Node,
1444 @"else": ?*Else,1634 @"else": ?*Else,
14451635
1446 pub fn iterate(self: *If, index: usize) ?*Node {1636 pub fn iterate(self: *const If, index: usize) ?*Node {
1447 var i = index;1637 var i = index;
14481638
1449 if (i < 1) return self.condition;1639 if (i < 1) return self.condition;
...@@ -1531,7 +1721,7 @@ pub const Node = struct {...@@ -1531,7 +1721,7 @@ pub const Node = struct {
1531 UnwrapOptional,1721 UnwrapOptional,
1532 };1722 };
15331723
1534 pub fn iterate(self: *InfixOp, index: usize) ?*Node {1724 pub fn iterate(self: *const InfixOp, index: usize) ?*Node {
1535 var i = index;1725 var i = index;
15361726
1537 if (i < 1) return self.lhs;1727 if (i < 1) return self.lhs;
...@@ -1649,7 +1839,7 @@ pub const Node = struct {...@@ -1649,7 +1839,7 @@ pub const Node = struct {
1649 };1839 };
1650 };1840 };
16511841
1652 pub fn iterate(self: *PrefixOp, index: usize) ?*Node {1842 pub fn iterate(self: *const PrefixOp, index: usize) ?*Node {
1653 var i = index;1843 var i = index;
16541844
1655 switch (self.op) {1845 switch (self.op) {
...@@ -1707,7 +1897,7 @@ pub const Node = struct {...@@ -1707,7 +1897,7 @@ pub const Node = struct {
1707 name_token: TokenIndex,1897 name_token: TokenIndex,
1708 expr: *Node,1898 expr: *Node,
17091899
1710 pub fn iterate(self: *FieldInitializer, index: usize) ?*Node {1900 pub fn iterate(self: *const FieldInitializer, index: usize) ?*Node {
1711 var i = index;1901 var i = index;
17121902
1713 if (i < 1) return self.expr;1903 if (i < 1) return self.expr;
...@@ -1725,35 +1915,279 @@ pub const Node = struct {...@@ -1725,35 +1915,279 @@ pub const Node = struct {
1725 }1915 }
1726 };1916 };
17271917
1918 /// Elements occur directly in memory after ArrayInitializer.
1919 pub const ArrayInitializer = struct {
1920 base: Node = Node{ .id = .ArrayInitializer },
1921 rtoken: TokenIndex,
1922 list_len: NodeIndex,
1923 lhs: *Node,
1924
1925 /// After this the caller must initialize the fields_and_decls list.
1926 pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializer {
1927 const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializer), sizeInBytes(list_len));
1928 return @ptrCast(*ArrayInitializer, bytes.ptr);
1929 }
1930
1931 pub fn free(self: *ArrayInitializer, allocator: *mem.Allocator) void {
1932 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
1933 allocator.free(bytes);
1934 }
1935
1936 pub fn iterate(self: *const ArrayInitializer, index: usize) ?*Node {
1937 var i = index;
1938
1939 if (i < 1) return self.lhs;
1940 i -= 1;
1941
1942 if (i < self.list_len) return self.listConst()[i];
1943 i -= self.list_len;
1944
1945 return null;
1946 }
1947
1948 pub fn firstToken(self: *const ArrayInitializer) TokenIndex {
1949 return self.lhs.firstToken();
1950 }
1951
1952 pub fn lastToken(self: *const ArrayInitializer) TokenIndex {
1953 return self.rtoken;
1954 }
1955
1956 pub fn list(self: *ArrayInitializer) []*Node {
1957 const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializer);
1958 return @ptrCast([*]*Node, decls_start)[0..self.list_len];
1959 }
1960
1961 pub fn listConst(self: *const ArrayInitializer) []const *Node {
1962 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializer);
1963 return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
1964 }
1965
1966 fn sizeInBytes(list_len: NodeIndex) usize {
1967 return @sizeOf(ArrayInitializer) + @sizeOf(*Node) * @as(usize, list_len);
1968 }
1969 };
1970
1971 /// Elements occur directly in memory after ArrayInitializerDot.
1972 pub const ArrayInitializerDot = struct {
1973 base: Node = Node{ .id = .ArrayInitializerDot },
1974 dot: TokenIndex,
1975 rtoken: TokenIndex,
1976 list_len: NodeIndex,
1977
1978 /// After this the caller must initialize the fields_and_decls list.
1979 pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializerDot {
1980 const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializerDot), sizeInBytes(list_len));
1981 return @ptrCast(*ArrayInitializerDot, bytes.ptr);
1982 }
1983
1984 pub fn free(self: *ArrayInitializerDot, allocator: *mem.Allocator) void {
1985 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
1986 allocator.free(bytes);
1987 }
1988
1989 pub fn iterate(self: *const ArrayInitializerDot, index: usize) ?*Node {
1990 var i = index;
1991
1992 if (i < self.list_len) return self.listConst()[i];
1993 i -= self.list_len;
1994
1995 return null;
1996 }
1997
1998 pub fn firstToken(self: *const ArrayInitializerDot) TokenIndex {
1999 return self.dot;
2000 }
2001
2002 pub fn lastToken(self: *const ArrayInitializerDot) TokenIndex {
2003 return self.rtoken;
2004 }
2005
2006 pub fn list(self: *ArrayInitializerDot) []*Node {
2007 const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializerDot);
2008 return @ptrCast([*]*Node, decls_start)[0..self.list_len];
2009 }
2010
2011 pub fn listConst(self: *const ArrayInitializerDot) []const *Node {
2012 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializerDot);
2013 return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
2014 }
2015
2016 fn sizeInBytes(list_len: NodeIndex) usize {
2017 return @sizeOf(ArrayInitializerDot) + @sizeOf(*Node) * @as(usize, list_len);
2018 }
2019 };
2020
2021 /// Elements occur directly in memory after StructInitializer.
2022 pub const StructInitializer = struct {
2023 base: Node = Node{ .id = .StructInitializer },
2024 rtoken: TokenIndex,
2025 list_len: NodeIndex,
2026 lhs: *Node,
2027
2028 /// After this the caller must initialize the fields_and_decls list.
2029 pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializer {
2030 const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializer), sizeInBytes(list_len));
2031 return @ptrCast(*StructInitializer, bytes.ptr);
2032 }
2033
2034 pub fn free(self: *StructInitializer, allocator: *mem.Allocator) void {
2035 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
2036 allocator.free(bytes);
2037 }
2038
2039 pub fn iterate(self: *const StructInitializer, index: usize) ?*Node {
2040 var i = index;
2041
2042 if (i < 1) return self.lhs;
2043 i -= 1;
2044
2045 if (i < self.list_len) return self.listConst()[i];
2046 i -= self.list_len;
2047
2048 return null;
2049 }
2050
2051 pub fn firstToken(self: *const StructInitializer) TokenIndex {
2052 return self.lhs.firstToken();
2053 }
2054
2055 pub fn lastToken(self: *const StructInitializer) TokenIndex {
2056 return self.rtoken;
2057 }
2058
2059 pub fn list(self: *StructInitializer) []*Node {
2060 const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializer);
2061 return @ptrCast([*]*Node, decls_start)[0..self.list_len];
2062 }
2063
2064 pub fn listConst(self: *const StructInitializer) []const *Node {
2065 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializer);
2066 return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
2067 }
2068
2069 fn sizeInBytes(list_len: NodeIndex) usize {
2070 return @sizeOf(StructInitializer) + @sizeOf(*Node) * @as(usize, list_len);
2071 }
2072 };
2073
2074 /// Elements occur directly in memory after StructInitializerDot.
2075 pub const StructInitializerDot = struct {
2076 base: Node = Node{ .id = .StructInitializerDot },
2077 dot: TokenIndex,
2078 rtoken: TokenIndex,
2079 list_len: NodeIndex,
2080
2081 /// After this the caller must initialize the fields_and_decls list.
2082 pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializerDot {
2083 const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializerDot), sizeInBytes(list_len));
2084 return @ptrCast(*StructInitializerDot, bytes.ptr);
2085 }
2086
2087 pub fn free(self: *StructInitializerDot, allocator: *mem.Allocator) void {
2088 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
2089 allocator.free(bytes);
2090 }
2091
2092 pub fn iterate(self: *const StructInitializerDot, index: usize) ?*Node {
2093 var i = index;
2094
2095 if (i < self.list_len) return self.listConst()[i];
2096 i -= self.list_len;
2097
2098 return null;
2099 }
2100
2101 pub fn firstToken(self: *const StructInitializerDot) TokenIndex {
2102 return self.dot;
2103 }
2104
2105 pub fn lastToken(self: *const StructInitializerDot) TokenIndex {
2106 return self.rtoken;
2107 }
2108
2109 pub fn list(self: *StructInitializerDot) []*Node {
2110 const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializerDot);
2111 return @ptrCast([*]*Node, decls_start)[0..self.list_len];
2112 }
2113
2114 pub fn listConst(self: *const StructInitializerDot) []const *Node {
2115 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializerDot);
2116 return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
2117 }
2118
2119 fn sizeInBytes(list_len: NodeIndex) usize {
2120 return @sizeOf(StructInitializerDot) + @sizeOf(*Node) * @as(usize, list_len);
2121 }
2122 };
2123
2124 /// Parameter nodes directly follow Call in memory.
2125 pub const Call = struct {
2126 base: Node = Node{ .id = .Call },
2127 lhs: *Node,
2128 rtoken: TokenIndex,
2129 params_len: NodeIndex,
2130 async_token: ?TokenIndex,
2131
2132 /// After this the caller must initialize the fields_and_decls list.
2133 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*Call {
2134 const bytes = try allocator.alignedAlloc(u8, @alignOf(Call), sizeInBytes(params_len));
2135 return @ptrCast(*Call, bytes.ptr);
2136 }
2137
2138 pub fn free(self: *Call, allocator: *mem.Allocator) void {
2139 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
2140 allocator.free(bytes);
2141 }
2142
2143 pub fn iterate(self: *const Call, index: usize) ?*Node {
2144 var i = index;
2145
2146 if (i < 1) return self.lhs;
2147 i -= 1;
2148
2149 if (i < self.params_len) return self.paramsConst()[i];
2150 i -= self.params_len;
2151
2152 return null;
2153 }
2154
2155 pub fn firstToken(self: *const Call) TokenIndex {
2156 if (self.async_token) |async_token| return async_token;
2157 return self.lhs.firstToken();
2158 }
2159
2160 pub fn lastToken(self: *const Call) TokenIndex {
2161 return self.rtoken;
2162 }
2163
2164 pub fn params(self: *Call) []*Node {
2165 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Call);
2166 return @ptrCast([*]*Node, decls_start)[0..self.params_len];
2167 }
2168
2169 pub fn paramsConst(self: *const Call) []const *Node {
2170 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Call);
2171 return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
2172 }
2173
2174 fn sizeInBytes(params_len: NodeIndex) usize {
2175 return @sizeOf(Call) + @sizeOf(*Node) * @as(usize, params_len);
2176 }
2177 };
2178
1728 pub const SuffixOp = struct {2179 pub const SuffixOp = struct {
1729 base: Node = Node{ .id = .SuffixOp },2180 base: Node = Node{ .id = .SuffixOp },
1730 lhs: Lhs,
1731 op: Op,2181 op: Op,
2182 lhs: *Node,
1732 rtoken: TokenIndex,2183 rtoken: TokenIndex,
17332184
1734 pub const Lhs = union(enum) {
1735 node: *Node,
1736 dot: TokenIndex,
1737 };
1738
1739 pub const Op = union(enum) {2185 pub const Op = union(enum) {
1740 Call: Call,
1741 ArrayAccess: *Node,2186 ArrayAccess: *Node,
1742 Slice: Slice,2187 Slice: Slice,
1743 ArrayInitializer: InitList,
1744 StructInitializer: InitList,
1745 Deref,2188 Deref,
1746 UnwrapOptional,2189 UnwrapOptional,
17472190
1748 pub const InitList = SegmentedList(*Node, 2);
1749
1750 pub const Call = struct {
1751 params: ParamList,
1752 async_token: ?TokenIndex,
1753
1754 pub const ParamList = SegmentedList(*Node, 2);
1755 };
1756
1757 pub const Slice = struct {2191 pub const Slice = struct {
1758 start: *Node,2192 start: *Node,
1759 end: ?*Node,2193 end: ?*Node,
...@@ -1761,22 +2195,13 @@ pub const Node = struct {...@@ -1761,22 +2195,13 @@ pub const Node = struct {
1761 };2195 };
1762 };2196 };
17632197
1764 pub fn iterate(self: *SuffixOp, index: usize) ?*Node {2198 pub fn iterate(self: *const SuffixOp, index: usize) ?*Node {
1765 var i = index;2199 var i = index;
17662200
1767 switch (self.lhs) {2201 if (i == 0) return self.lhs;
1768 .node => |node| {2202 i -= 1;
1769 if (i == 0) return node;
1770 i -= 1;
1771 },
1772 .dot => {},
1773 }
17742203
1775 switch (self.op) {2204 switch (self.op) {
1776 .Call => |*call_info| {
1777 if (i < call_info.params.len) return call_info.params.at(i).*;
1778 i -= call_info.params.len;
1779 },
1780 .ArrayAccess => |index_expr| {2205 .ArrayAccess => |index_expr| {
1781 if (i < 1) return index_expr;2206 if (i < 1) return index_expr;
1782 i -= 1;2207 i -= 1;
...@@ -1794,14 +2219,6 @@ pub const Node = struct {...@@ -1794,14 +2219,6 @@ pub const Node = struct {
1794 i -= 1;2219 i -= 1;
1795 }2220 }
1796 },2221 },
1797 .ArrayInitializer => |*exprs| {
1798 if (i < exprs.len) return exprs.at(i).*;
1799 i -= exprs.len;
1800 },
1801 .StructInitializer => |*fields| {
1802 if (i < fields.len) return fields.at(i).*;
1803 i -= fields.len;
1804 },
1805 .UnwrapOptional,2222 .UnwrapOptional,
1806 .Deref,2223 .Deref,
1807 => {},2224 => {},
...@@ -1811,14 +2228,7 @@ pub const Node = struct {...@@ -1811,14 +2228,7 @@ pub const Node = struct {
1811 }2228 }
18122229
1813 pub fn firstToken(self: *const SuffixOp) TokenIndex {2230 pub fn firstToken(self: *const SuffixOp) TokenIndex {
1814 switch (self.op) {2231 return self.lhs.firstToken();
1815 .Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
1816 else => {},
1817 }
1818 switch (self.lhs) {
1819 .node => |node| return node.firstToken(),
1820 .dot => |dot| return dot,
1821 }
1822 }2232 }
18232233
1824 pub fn lastToken(self: *const SuffixOp) TokenIndex {2234 pub fn lastToken(self: *const SuffixOp) TokenIndex {
...@@ -1832,7 +2242,7 @@ pub const Node = struct {...@@ -1832,7 +2242,7 @@ pub const Node = struct {
1832 expr: *Node,2242 expr: *Node,
1833 rparen: TokenIndex,2243 rparen: TokenIndex,
18342244
1835 pub fn iterate(self: *GroupedExpression, index: usize) ?*Node {2245 pub fn iterate(self: *const GroupedExpression, index: usize) ?*Node {
1836 var i = index;2246 var i = index;
18372247
1838 if (i < 1) return self.expr;2248 if (i < 1) return self.expr;
...@@ -1862,7 +2272,7 @@ pub const Node = struct {...@@ -1862,7 +2272,7 @@ pub const Node = struct {
1862 Return,2272 Return,
1863 };2273 };
18642274
1865 pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node {2275 pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node {
1866 var i = index;2276 var i = index;
18672277
1868 switch (self.kind) {2278 switch (self.kind) {
...@@ -1910,7 +2320,7 @@ pub const Node = struct {...@@ -1910,7 +2320,7 @@ pub const Node = struct {
1910 suspend_token: TokenIndex,2320 suspend_token: TokenIndex,
1911 body: ?*Node,2321 body: ?*Node,
19122322
1913 pub fn iterate(self: *Suspend, index: usize) ?*Node {2323 pub fn iterate(self: *const Suspend, index: usize) ?*Node {
1914 var i = index;2324 var i = index;
19152325
1916 if (self.body) |body| {2326 if (self.body) |body| {
...@@ -1938,7 +2348,7 @@ pub const Node = struct {...@@ -1938,7 +2348,7 @@ pub const Node = struct {
1938 base: Node = Node{ .id = .IntegerLiteral },2348 base: Node = Node{ .id = .IntegerLiteral },
1939 token: TokenIndex,2349 token: TokenIndex,
19402350
1941 pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {2351 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
1942 return null;2352 return null;
1943 }2353 }
19442354
...@@ -1956,7 +2366,7 @@ pub const Node = struct {...@@ -1956,7 +2366,7 @@ pub const Node = struct {
1956 dot: TokenIndex,2366 dot: TokenIndex,
1957 name: TokenIndex,2367 name: TokenIndex,
19582368
1959 pub fn iterate(self: *EnumLiteral, index: usize) ?*Node {2369 pub fn iterate(self: *const EnumLiteral, index: usize) ?*Node {
1960 return null;2370 return null;
1961 }2371 }
19622372
...@@ -1973,7 +2383,7 @@ pub const Node = struct {...@@ -1973,7 +2383,7 @@ pub const Node = struct {
1973 base: Node = Node{ .id = .FloatLiteral },2383 base: Node = Node{ .id = .FloatLiteral },
1974 token: TokenIndex,2384 token: TokenIndex,
19752385
1976 pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {2386 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
1977 return null;2387 return null;
1978 }2388 }
19792389
...@@ -1986,19 +2396,29 @@ pub const Node = struct {...@@ -1986,19 +2396,29 @@ pub const Node = struct {
1986 }2396 }
1987 };2397 };
19882398
2399 /// Parameters are in memory following BuiltinCall.
1989 pub const BuiltinCall = struct {2400 pub const BuiltinCall = struct {
1990 base: Node = Node{ .id = .BuiltinCall },2401 base: Node = Node{ .id = .BuiltinCall },
2402 params_len: NodeIndex,
1991 builtin_token: TokenIndex,2403 builtin_token: TokenIndex,
1992 params: ParamList,
1993 rparen_token: TokenIndex,2404 rparen_token: TokenIndex,
19942405
1995 pub const ParamList = SegmentedList(*Node, 2);2406 /// After this the caller must initialize the fields_and_decls list.
2407 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*BuiltinCall {
2408 const bytes = try allocator.alignedAlloc(u8, @alignOf(BuiltinCall), sizeInBytes(params_len));
2409 return @ptrCast(*BuiltinCall, bytes.ptr);
2410 }
19962411
1997 pub fn iterate(self: *BuiltinCall, index: usize) ?*Node {2412 pub fn free(self: *BuiltinCall, allocator: *mem.Allocator) void {
2413 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
2414 allocator.free(bytes);
2415 }
2416
2417 pub fn iterate(self: *const BuiltinCall, index: usize) ?*Node {
1998 var i = index;2418 var i = index;
19992419
2000 if (i < self.params.len) return self.params.at(i).*;2420 if (i < self.params_len) return self.paramsConst()[i];
2001 i -= self.params.len;2421 i -= self.params_len;
20022422
2003 return null;2423 return null;
2004 }2424 }
...@@ -2010,13 +2430,27 @@ pub const Node = struct {...@@ -2010,13 +2430,27 @@ pub const Node = struct {
2010 pub fn lastToken(self: *const BuiltinCall) TokenIndex {2430 pub fn lastToken(self: *const BuiltinCall) TokenIndex {
2011 return self.rparen_token;2431 return self.rparen_token;
2012 }2432 }
2433
2434 pub fn params(self: *BuiltinCall) []*Node {
2435 const decls_start = @ptrCast([*]u8, self) + @sizeOf(BuiltinCall);
2436 return @ptrCast([*]*Node, decls_start)[0..self.params_len];
2437 }
2438
2439 pub fn paramsConst(self: *const BuiltinCall) []const *Node {
2440 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(BuiltinCall);
2441 return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
2442 }
2443
2444 fn sizeInBytes(params_len: NodeIndex) usize {
2445 return @sizeOf(BuiltinCall) + @sizeOf(*Node) * @as(usize, params_len);
2446 }
2013 };2447 };
20142448
2015 pub const StringLiteral = struct {2449 pub const StringLiteral = struct {
2016 base: Node = Node{ .id = .StringLiteral },2450 base: Node = Node{ .id = .StringLiteral },
2017 token: TokenIndex,2451 token: TokenIndex,
20182452
2019 pub fn iterate(self: *StringLiteral, index: usize) ?*Node {2453 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
2020 return null;2454 return null;
2021 }2455 }
20222456
...@@ -2029,22 +2463,46 @@ pub const Node = struct {...@@ -2029,22 +2463,46 @@ pub const Node = struct {
2029 }2463 }
2030 };2464 };
20312465
2466 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
2032 pub const MultilineStringLiteral = struct {2467 pub const MultilineStringLiteral = struct {
2033 base: Node = Node{ .id = .MultilineStringLiteral },2468 base: Node = Node{ .id = .MultilineStringLiteral },
2034 lines: LineList,2469 lines_len: TokenIndex,
20352470
2036 pub const LineList = SegmentedList(TokenIndex, 4);2471 /// After this the caller must initialize the lines list.
2472 pub fn alloc(allocator: *mem.Allocator, lines_len: NodeIndex) !*MultilineStringLiteral {
2473 const bytes = try allocator.alignedAlloc(u8, @alignOf(MultilineStringLiteral), sizeInBytes(lines_len));
2474 return @ptrCast(*MultilineStringLiteral, bytes.ptr);
2475 }
20372476
2038 pub fn iterate(self: *MultilineStringLiteral, index: usize) ?*Node {2477 pub fn free(self: *MultilineStringLiteral, allocator: *mem.Allocator) void {
2478 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.lines_len)];
2479 allocator.free(bytes);
2480 }
2481
2482 pub fn iterate(self: *const MultilineStringLiteral, index: usize) ?*Node {
2039 return null;2483 return null;
2040 }2484 }
20412485
2042 pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {2486 pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {
2043 return self.lines.at(0).*;2487 return self.linesConst()[0];
2044 }2488 }
20452489
2046 pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex {2490 pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex {
2047 return self.lines.at(self.lines.len - 1).*;2491 return self.linesConst()[self.lines_len - 1];
2492 }
2493
2494 pub fn lines(self: *MultilineStringLiteral) []TokenIndex {
2495 const decls_start = @ptrCast([*]u8, self) + @sizeOf(MultilineStringLiteral);
2496 return @ptrCast([*]TokenIndex, decls_start)[0..self.lines_len];
2497 }
2498
2499 pub fn linesConst(self: *const MultilineStringLiteral) []const TokenIndex {
2500 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(MultilineStringLiteral);
2501 return @ptrCast([*]const TokenIndex, decls_start)[0..self.lines_len];
2502 }
2503
2504 fn sizeInBytes(lines_len: NodeIndex) usize {
2505 return @sizeOf(MultilineStringLiteral) + @sizeOf(TokenIndex) * @as(usize, lines_len);
2048 }2506 }
2049 };2507 };
20502508
...@@ -2052,7 +2510,7 @@ pub const Node = struct {...@@ -2052,7 +2510,7 @@ pub const Node = struct {
2052 base: Node = Node{ .id = .CharLiteral },2510 base: Node = Node{ .id = .CharLiteral },
2053 token: TokenIndex,2511 token: TokenIndex,
20542512
2055 pub fn iterate(self: *CharLiteral, index: usize) ?*Node {2513 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
2056 return null;2514 return null;
2057 }2515 }
20582516
...@@ -2069,7 +2527,7 @@ pub const Node = struct {...@@ -2069,7 +2527,7 @@ pub const Node = struct {
2069 base: Node = Node{ .id = .BoolLiteral },2527 base: Node = Node{ .id = .BoolLiteral },
2070 token: TokenIndex,2528 token: TokenIndex,
20712529
2072 pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {2530 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
2073 return null;2531 return null;
2074 }2532 }
20752533
...@@ -2086,7 +2544,7 @@ pub const Node = struct {...@@ -2086,7 +2544,7 @@ pub const Node = struct {
2086 base: Node = Node{ .id = .NullLiteral },2544 base: Node = Node{ .id = .NullLiteral },
2087 token: TokenIndex,2545 token: TokenIndex,
20882546
2089 pub fn iterate(self: *NullLiteral, index: usize) ?*Node {2547 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
2090 return null;2548 return null;
2091 }2549 }
20922550
...@@ -2103,7 +2561,7 @@ pub const Node = struct {...@@ -2103,7 +2561,7 @@ pub const Node = struct {
2103 base: Node = Node{ .id = .UndefinedLiteral },2561 base: Node = Node{ .id = .UndefinedLiteral },
2104 token: TokenIndex,2562 token: TokenIndex,
21052563
2106 pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {2564 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
2107 return null;2565 return null;
2108 }2566 }
21092567
...@@ -2116,105 +2574,114 @@ pub const Node = struct {...@@ -2116,105 +2574,114 @@ pub const Node = struct {
2116 }2574 }
2117 };2575 };
21182576
2119 pub const AsmOutput = struct {2577 pub const Asm = struct {
2120 base: Node = Node{ .id = .AsmOutput },2578 base: Node = Node{ .id = .Asm },
2121 lbracket: TokenIndex,2579 asm_token: TokenIndex,
2122 symbolic_name: *Node,
2123 constraint: *Node,
2124 kind: Kind,
2125 rparen: TokenIndex,2580 rparen: TokenIndex,
2581 volatile_token: ?TokenIndex,
2582 template: *Node,
2583 outputs: []Output,
2584 inputs: []Input,
2585 /// A clobber node must be a StringLiteral or MultilineStringLiteral.
2586 clobbers: []*Node,
2587
2588 pub const Output = struct {
2589 lbracket: TokenIndex,
2590 symbolic_name: *Node,
2591 constraint: *Node,
2592 kind: Kind,
2593 rparen: TokenIndex,
2594
2595 pub const Kind = union(enum) {
2596 Variable: *Identifier,
2597 Return: *Node,
2598 };
21262599
2127 pub const Kind = union(enum) {2600 pub fn iterate(self: *const Output, index: usize) ?*Node {
2128 Variable: *Identifier,2601 var i = index;
2129 Return: *Node,
2130 };
21312602
2132 pub fn iterate(self: *AsmOutput, index: usize) ?*Node {2603 if (i < 1) return self.symbolic_name;
2133 var i = index;2604 i -= 1;
21342605
2135 if (i < 1) return self.symbolic_name;2606 if (i < 1) return self.constraint;
2136 i -= 1;2607 i -= 1;
21372608
2138 if (i < 1) return self.constraint;2609 switch (self.kind) {
2139 i -= 1;2610 .Variable => |variable_name| {
2611 if (i < 1) return &variable_name.base;
2612 i -= 1;
2613 },
2614 .Return => |return_type| {
2615 if (i < 1) return return_type;
2616 i -= 1;
2617 },
2618 }
21402619
2141 switch (self.kind) {2620 return null;
2142 .Variable => |variable_name| {
2143 if (i < 1) return &variable_name.base;
2144 i -= 1;
2145 },
2146 .Return => |return_type| {
2147 if (i < 1) return return_type;
2148 i -= 1;
2149 },
2150 }2621 }
21512622
2152 return null;2623 pub fn firstToken(self: *const Output) TokenIndex {
2153 }2624 return self.lbracket;
21542625 }
2155 pub fn firstToken(self: *const AsmOutput) TokenIndex {
2156 return self.lbracket;
2157 }
2158
2159 pub fn lastToken(self: *const AsmOutput) TokenIndex {
2160 return self.rparen;
2161 }
2162 };
21632626
2164 pub const AsmInput = struct {2627 pub fn lastToken(self: *const Output) TokenIndex {
2165 base: Node = Node{ .id = .AsmInput },2628 return self.rparen;
2166 lbracket: TokenIndex,2629 }
2167 symbolic_name: *Node,2630 };
2168 constraint: *Node,
2169 expr: *Node,
2170 rparen: TokenIndex,
21712631
2172 pub fn iterate(self: *AsmInput, index: usize) ?*Node {2632 pub const Input = struct {
2173 var i = index;2633 lbracket: TokenIndex,
2634 symbolic_name: *Node,
2635 constraint: *Node,
2636 expr: *Node,
2637 rparen: TokenIndex,
21742638
2175 if (i < 1) return self.symbolic_name;2639 pub fn iterate(self: *const Input, index: usize) ?*Node {
2176 i -= 1;2640 var i = index;
21772641
2178 if (i < 1) return self.constraint;2642 if (i < 1) return self.symbolic_name;
2179 i -= 1;2643 i -= 1;
21802644
2181 if (i < 1) return self.expr;2645 if (i < 1) return self.constraint;
2182 i -= 1;2646 i -= 1;
21832647
2184 return null;2648 if (i < 1) return self.expr;
2185 }2649 i -= 1;
21862650
2187 pub fn firstToken(self: *const AsmInput) TokenIndex {2651 return null;
2188 return self.lbracket;2652 }
2189 }
21902653
2191 pub fn lastToken(self: *const AsmInput) TokenIndex {2654 pub fn firstToken(self: *const Input) TokenIndex {
2192 return self.rparen;2655 return self.lbracket;
2193 }2656 }
2194 };
21952657
2196 pub const Asm = struct {2658 pub fn lastToken(self: *const Input) TokenIndex {
2197 base: Node = Node{ .id = .Asm },2659 return self.rparen;
2198 asm_token: TokenIndex,2660 }
2199 volatile_token: ?TokenIndex,2661 };
2200 template: *Node,
2201 outputs: OutputList,
2202 inputs: InputList,
2203 clobbers: ClobberList,
2204 rparen: TokenIndex,
22052662
2206 pub const OutputList = SegmentedList(*AsmOutput, 2);
2207 pub const InputList = SegmentedList(*AsmInput, 2);
2208 pub const ClobberList = SegmentedList(*Node, 2);
22092663
2210 pub fn iterate(self: *Asm, index: usize) ?*Node {2664 pub fn iterate(self: *const Asm, index: usize) ?*Node {
2211 var i = index;2665 var i = index;
22122666
2213 if (i < self.outputs.len) return &self.outputs.at(i).*.base;2667 if (i < self.outputs.len * 3) switch (i % 3) {
2214 i -= self.outputs.len;2668 0 => return self.outputs[i / 3].symbolic_name,
2669 1 => return self.outputs[i / 3].constraint,
2670 2 => switch (self.outputs[i / 3].kind) {
2671 .Variable => |variable_name| return &variable_name.base,
2672 .Return => |return_type| return return_type,
2673 },
2674 else => unreachable,
2675 };
2676 i -= self.outputs.len * 3;
22152677
2216 if (i < self.inputs.len) return &self.inputs.at(i).*.base;2678 if (i < self.inputs.len * 3) switch (i % 3) {
2217 i -= self.inputs.len;2679 0 => return self.inputs[i / 3].symbolic_name,
2680 1 => return self.inputs[i / 3].constraint,
2681 2 => return self.inputs[i / 3].expr,
2682 else => unreachable,
2683 };
2684 i -= self.inputs.len * 3;
22182685
2219 return null;2686 return null;
2220 }2687 }
...@@ -2232,7 +2699,7 @@ pub const Node = struct {...@@ -2232,7 +2699,7 @@ pub const Node = struct {
2232 base: Node = Node{ .id = .Unreachable },2699 base: Node = Node{ .id = .Unreachable },
2233 token: TokenIndex,2700 token: TokenIndex,
22342701
2235 pub fn iterate(self: *Unreachable, index: usize) ?*Node {2702 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
2236 return null;2703 return null;
2237 }2704 }
22382705
...@@ -2249,7 +2716,7 @@ pub const Node = struct {...@@ -2249,7 +2716,7 @@ pub const Node = struct {
2249 base: Node = Node{ .id = .ErrorType },2716 base: Node = Node{ .id = .ErrorType },
2250 token: TokenIndex,2717 token: TokenIndex,
22512718
2252 pub fn iterate(self: *ErrorType, index: usize) ?*Node {2719 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
2253 return null;2720 return null;
2254 }2721 }
22552722
...@@ -2266,7 +2733,7 @@ pub const Node = struct {...@@ -2266,7 +2733,7 @@ pub const Node = struct {
2266 base: Node = Node{ .id = .VarType },2733 base: Node = Node{ .id = .VarType },
2267 token: TokenIndex,2734 token: TokenIndex,
22682735
2269 pub fn iterate(self: *VarType, index: usize) ?*Node {2736 pub fn iterate(self: *const VarType, index: usize) ?*Node {
2270 return null;2737 return null;
2271 }2738 }
22722739
...@@ -2281,20 +2748,23 @@ pub const Node = struct {...@@ -2281,20 +2748,23 @@ pub const Node = struct {
22812748
2282 pub const DocComment = struct {2749 pub const DocComment = struct {
2283 base: Node = Node{ .id = .DocComment },2750 base: Node = Node{ .id = .DocComment },
2284 lines: LineList,2751 /// Points to the first doc comment token. API users are expected to iterate over the
22852752 /// tokens array, looking for more doc comments, ignoring line comments, and stopping
2286 pub const LineList = SegmentedList(TokenIndex, 4);2753 /// at the first other token.
2754 first_line: TokenIndex,
22872755
2288 pub fn iterate(self: *DocComment, index: usize) ?*Node {2756 pub fn iterate(self: *const DocComment, index: usize) ?*Node {
2289 return null;2757 return null;
2290 }2758 }
22912759
2292 pub fn firstToken(self: *const DocComment) TokenIndex {2760 pub fn firstToken(self: *const DocComment) TokenIndex {
2293 return self.lines.at(0).*;2761 return self.first_line;
2294 }2762 }
22952763
2764 /// Returns the first doc comment line. Be careful, this may not be the desired behavior,
2765 /// which would require the tokens array.
2296 pub fn lastToken(self: *const DocComment) TokenIndex {2766 pub fn lastToken(self: *const DocComment) TokenIndex {
2297 return self.lines.at(self.lines.len - 1).*;2767 return self.first_line;
2298 }2768 }
2299 };2769 };
23002770
...@@ -2305,7 +2775,7 @@ pub const Node = struct {...@@ -2305,7 +2775,7 @@ pub const Node = struct {
2305 name: *Node,2775 name: *Node,
2306 body_node: *Node,2776 body_node: *Node,
23072777
2308 pub fn iterate(self: *TestDecl, index: usize) ?*Node {2778 pub fn iterate(self: *const TestDecl, index: usize) ?*Node {
2309 var i = index;2779 var i = index;
23102780
2311 if (i < 1) return self.body_node;2781 if (i < 1) return self.body_node;
...@@ -2327,7 +2797,7 @@ pub const Node = struct {...@@ -2327,7 +2797,7 @@ pub const Node = struct {
2327test "iterate" {2797test "iterate" {
2328 var root = Node.Root{2798 var root = Node.Root{
2329 .base = Node{ .id = Node.Id.Root },2799 .base = Node{ .id = Node.Id.Root },
2330 .decls = Node.Root.DeclList.init(std.testing.allocator),2800 .decls_len = 0,
2331 .eof_token = 0,2801 .eof_token = 0,
2332 };2802 };
2333 var base = &root.base;2803 var base = &root.base;
lib/std/zig/parse.zig+2886-2803
...@@ -6,3304 +6,3387 @@ const Node = ast.Node;...@@ -6,3304 +6,3387 @@ const Node = ast.Node;
6const Tree = ast.Tree;6const Tree = ast.Tree;
7const AstError = ast.Error;7const AstError = ast.Error;
8const TokenIndex = ast.TokenIndex;8const TokenIndex = ast.TokenIndex;
9const NodeIndex = ast.NodeIndex;
9const Token = std.zig.Token;10const Token = std.zig.Token;
10const TokenIterator = Tree.TokenList.Iterator;
1111
12pub const Error = error{ParseError} || Allocator.Error;12pub const Error = error{ParseError} || Allocator.Error;
1313
14/// Result should be freed with tree.deinit() when there are14/// Result should be freed with tree.deinit() when there are
15/// no more references to any of the tokens or nodes.15/// no more references to any of the tokens or nodes.
16pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {16pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
17 const tree = blk: {17 // TODO optimization idea: ensureCapacity on the tokens list and
18 // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists18 // then appendAssumeCapacity inside the loop.
19 // from being initialized with a pointer to this `arena`, which is created on19 var token_ids = std.ArrayList(Token.Id).init(gpa);
20 // the stack. Following code should instead refer to `&tree.arena_allocator`, a20 defer token_ids.deinit();
21 // pointer to data which lives safely on the heap and will outlive `parse`. See:21 var token_locs = std.ArrayList(Token.Loc).init(gpa);
22 // https://github.com/ziglang/zig/commit/cb4fb14b6e66bd213575f69eec9598be8394fae622 defer token_locs.deinit();
23 var arena = std.heap.ArenaAllocator.init(allocator);
24 errdefer arena.deinit();
25 const tree = try arena.allocator.create(ast.Tree);
26 tree.* = .{
27 .source = source,
28 .root_node = undefined,
29 .arena_allocator = arena,
30 .tokens = undefined,
31 .errors = undefined,
32 };
33 break :blk tree;
34 };
35 errdefer tree.deinit();
36 const arena = &tree.arena_allocator.allocator;
37
38 tree.tokens = ast.Tree.TokenList.init(arena);
39 tree.errors = ast.Tree.ErrorList.init(arena);
4023
41 var tokenizer = std.zig.Tokenizer.init(source);24 var tokenizer = std.zig.Tokenizer.init(source);
42 while (true) {25 while (true) {
43 const tree_token = try tree.tokens.addOne();26 const token = tokenizer.next();
44 tree_token.* = tokenizer.next();27 try token_ids.append(token.id);
45 if (tree_token.id == .Eof) break;28 try token_locs.append(token.loc);
46 }29 if (token.id == .Eof) break;
47 var it = tree.tokens.iterator(0);30 }
4831
49 while (it.peek().?.id == .LineComment) _ = it.next();32 var parser: Parser = .{
5033 .source = source,
51 tree.root_node = try parseRoot(arena, &it, tree);34 .arena = std.heap.ArenaAllocator.init(gpa),
5235 .gpa = gpa,
36 .token_ids = token_ids.items,
37 .token_locs = token_locs.items,
38 .errors = .{},
39 .tok_i = 0,
40 };
41 defer parser.errors.deinit(gpa);
42 errdefer parser.arena.deinit();
43
44 while (token_ids.items[parser.tok_i] == .LineComment) parser.tok_i += 1;
45
46 const root_node = try parser.parseRoot();
47
48 const tree = try parser.arena.allocator.create(Tree);
49 tree.* = .{
50 .gpa = gpa,
51 .source = source,
52 .token_ids = token_ids.toOwnedSlice(),
53 .token_locs = token_locs.toOwnedSlice(),
54 .errors = parser.errors.toOwnedSlice(gpa),
55 .root_node = root_node,
56 .arena = parser.arena.state,
57 };
53 return tree;58 return tree;
54}59}
5560
56/// Root <- skip ContainerMembers eof61/// Represents in-progress parsing, will be converted to an ast.Tree after completion.
57fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {62const Parser = struct {
58 const node = try arena.create(Node.Root);63 arena: std.heap.ArenaAllocator,
59 node.* = .{64 gpa: *Allocator,
60 .decls = try parseContainerMembers(arena, it, tree, true),65 source: []const u8,
66 token_ids: []const Token.Id,
67 token_locs: []const Token.Loc,
68 tok_i: TokenIndex,
69 errors: std.ArrayListUnmanaged(AstError),
70
71 /// Root <- skip ContainerMembers eof
72 fn parseRoot(p: *Parser) Allocator.Error!*Node.Root {
73 const decls = try parseContainerMembers(p, true);
74 defer p.gpa.free(decls);
75
61 // parseContainerMembers will try to skip as much76 // parseContainerMembers will try to skip as much
62 // invalid tokens as it can so this can only be the EOF77 // invalid tokens as it can so this can only be the EOF
63 .eof_token = eatToken(it, .Eof).?,78 const eof_token = p.eatToken(.Eof).?;
64 };
65 return node;
66}
6779
68/// ContainerMembers80 const decls_len = @intCast(NodeIndex, decls.len);
69/// <- TestDecl ContainerMembers81 const node = try Node.Root.create(&p.arena.allocator, decls_len, eof_token);
70/// / TopLevelComptime ContainerMembers82 std.mem.copy(*Node, node.decls(), decls);
71/// / KEYWORD_pub? TopLevelDecl ContainerMembers
72/// / ContainerField COMMA ContainerMembers
73/// / ContainerField
74/// /
75fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top_level: bool) !Node.Root.DeclList {
76 var list = Node.Root.DeclList.init(arena);
77
78 var field_state: union(enum) {
79 /// no fields have been seen
80 none,
81 /// currently parsing fields
82 seen,
83 /// saw fields and then a declaration after them.
84 /// payload is first token of previous declaration.
85 end: TokenIndex,
86 /// ther was a declaration between fields, don't report more errors
87 err,
88 } = .none;
8983
90 while (true) {84 return node;
91 if (try parseContainerDocComments(arena, it, tree)) |node| {85 }
92 try list.push(node);
93 continue;
94 }
9586
96 const doc_comments = try parseDocComment(arena, it, tree);87 /// ContainerMembers
88 /// <- TestDecl ContainerMembers
89 /// / TopLevelComptime ContainerMembers
90 /// / KEYWORD_pub? TopLevelDecl ContainerMembers
91 /// / ContainerField COMMA ContainerMembers
92 /// / ContainerField
93 /// /
94 fn parseContainerMembers(p: *Parser, top_level: bool) ![]*Node {
95 var list = std.ArrayList(*Node).init(p.gpa);
96 defer list.deinit();
97
98 var field_state: union(enum) {
99 /// no fields have been seen
100 none,
101 /// currently parsing fields
102 seen,
103 /// saw fields and then a declaration after them.
104 /// payload is first token of previous declaration.
105 end: TokenIndex,
106 /// ther was a declaration between fields, don't report more errors
107 err,
108 } = .none;
97109
98 if (parseTestDecl(arena, it, tree) catch |err| switch (err) {110 while (true) {
99 error.OutOfMemory => return error.OutOfMemory,111 if (try p.parseContainerDocComments()) |node| {
100 error.ParseError => {112 try list.append(node);
101 findNextContainerMember(it);
102 continue;113 continue;
103 },
104 }) |node| {
105 if (field_state == .seen) {
106 field_state = .{ .end = node.firstToken() };
107 }114 }
108 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
109 try list.push(node);
110 continue;
111 }
112115
113 if (parseTopLevelComptime(arena, it, tree) catch |err| switch (err) {116 const doc_comments = try p.parseDocComment();
114 error.OutOfMemory => return error.OutOfMemory,117
115 error.ParseError => {118 if (p.parseTestDecl() catch |err| switch (err) {
116 findNextContainerMember(it);119 error.OutOfMemory => return error.OutOfMemory,
120 error.ParseError => {
121 p.findNextContainerMember();
122 continue;
123 },
124 }) |node| {
125 if (field_state == .seen) {
126 field_state = .{ .end = node.firstToken() };
127 }
128 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
129 try list.append(node);
117 continue;130 continue;
118 },
119 }) |node| {
120 if (field_state == .seen) {
121 field_state = .{ .end = node.firstToken() };
122 }131 }
123 node.cast(Node.Comptime).?.doc_comments = doc_comments;
124 try list.push(node);
125 continue;
126 }
127132
128 const visib_token = eatToken(it, .Keyword_pub);133 if (p.parseTopLevelComptime() catch |err| switch (err) {
129134 error.OutOfMemory => return error.OutOfMemory,
130 if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {135 error.ParseError => {
131 error.OutOfMemory => return error.OutOfMemory,136 p.findNextContainerMember();
132 error.ParseError => {137 continue;
133 findNextContainerMember(it);138 },
139 }) |node| {
140 if (field_state == .seen) {
141 field_state = .{ .end = node.firstToken() };
142 }
143 node.cast(Node.Comptime).?.doc_comments = doc_comments;
144 try list.append(node);
134 continue;145 continue;
135 },
136 }) |node| {
137 if (field_state == .seen) {
138 field_state = .{ .end = visib_token orelse node.firstToken() };
139 }146 }
140 switch (node.id) {147
141 .FnProto => {148 const visib_token = p.eatToken(.Keyword_pub);
142 node.cast(Node.FnProto).?.doc_comments = doc_comments;149
143 node.cast(Node.FnProto).?.visib_token = visib_token;150 if (p.parseTopLevelDecl() catch |err| switch (err) {
144 },151 error.OutOfMemory => return error.OutOfMemory,
145 .VarDecl => {152 error.ParseError => {
146 node.cast(Node.VarDecl).?.doc_comments = doc_comments;153 p.findNextContainerMember();
147 node.cast(Node.VarDecl).?.visib_token = visib_token;154 continue;
148 },
149 .Use => {
150 node.cast(Node.Use).?.doc_comments = doc_comments;
151 node.cast(Node.Use).?.visib_token = visib_token;
152 },155 },
153 else => unreachable,156 }) |node| {
154 }157 if (field_state == .seen) {
155 try list.push(node);158 field_state = .{ .end = visib_token orelse node.firstToken() };
156 if (try parseAppendedDocComment(arena, it, tree, node.lastToken())) |appended_comment| {159 }
157 switch (node.id) {160 switch (node.id) {
158 .FnProto => {},161 .FnProto => {
159 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,162 node.cast(Node.FnProto).?.doc_comments = doc_comments;
160 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,163 node.cast(Node.FnProto).?.visib_token = visib_token;
164 },
165 .VarDecl => {
166 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
167 node.cast(Node.VarDecl).?.visib_token = visib_token;
168 },
169 .Use => {
170 node.cast(Node.Use).?.doc_comments = doc_comments;
171 node.cast(Node.Use).?.visib_token = visib_token;
172 },
161 else => unreachable,173 else => unreachable,
162 }174 }
175 try list.append(node);
176 if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| {
177 switch (node.id) {
178 .FnProto => {},
179 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
180 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
181 else => unreachable,
182 }
183 }
184 continue;
163 }185 }
164 continue;
165 }
166
167 if (visib_token != null) {
168 try tree.errors.push(.{
169 .ExpectedPubItem = .{ .token = it.index },
170 });
171 // ignore this pub
172 continue;
173 }
174186
175 if (parseContainerField(arena, it, tree) catch |err| switch (err) {187 if (visib_token != null) {
176 error.OutOfMemory => return error.OutOfMemory,188 try p.errors.append(p.gpa, .{
177 error.ParseError => {189 .ExpectedPubItem = .{ .token = p.tok_i },
178 // attempt to recover190 });
179 findNextContainerMember(it);191 // ignore this pub
180 continue;192 continue;
181 },
182 }) |node| {
183 switch (field_state) {
184 .none => field_state = .seen,
185 .err, .seen => {},
186 .end => |tok| {
187 try tree.errors.push(.{
188 .DeclBetweenFields = .{ .token = tok },
189 });
190 // continue parsing, error will be reported later
191 field_state = .err;
192 },
193 }193 }
194194
195 const field = node.cast(Node.ContainerField).?;195 if (p.parseContainerField() catch |err| switch (err) {
196 field.doc_comments = doc_comments;196 error.OutOfMemory => return error.OutOfMemory,
197 try list.push(node);197 error.ParseError => {
198 const comma = eatToken(it, .Comma) orelse {198 // attempt to recover
199 // try to continue parsing199 p.findNextContainerMember();
200 const index = it.index;200 continue;
201 findNextContainerMember(it);201 },
202 const next = it.peek().?.id;202 }) |node| {
203 switch (next) {203 switch (field_state) {
204 .Eof => break,204 .none => field_state = .seen,
205 else => {205 .err, .seen => {},
206 if (next == .RBrace) {206 .end => |tok| {
207 if (!top_level) break;207 try p.errors.append(p.gpa, .{
208 _ = nextToken(it);208 .DeclBetweenFields = .{ .token = tok },
209 }
210
211 // add error and continue
212 try tree.errors.push(.{
213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
214 });209 });
215 continue;210 // continue parsing, error will be reported later
211 field_state = .err;
216 },212 },
217 }213 }
218 };
219 if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment|
220 field.doc_comments = appended_comment;
221 continue;
222 }
223
224 // Dangling doc comment
225 if (doc_comments != null) {
226 try tree.errors.push(.{
227 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
228 });
229 }
230214
231 const next = it.peek().?.id;215 const field = node.cast(Node.ContainerField).?;
232 switch (next) {216 field.doc_comments = doc_comments;
233 .Eof => break,217 try list.append(node);
234 .Keyword_comptime => {218 const comma = p.eatToken(.Comma) orelse {
235 _ = nextToken(it);219 // try to continue parsing
236 try tree.errors.push(.{220 const index = p.tok_i;
237 .ExpectedBlockOrField = .{ .token = it.index },221 p.findNextContainerMember();
238 });222 const next = p.token_ids[p.tok_i];
239 },223 switch (next) {
240 else => {224 .Eof => break,
241 const index = it.index;225 else => {
242 if (next == .RBrace) {226 if (next == .RBrace) {
243 if (!top_level) break;227 if (!top_level) break;
244 _ = nextToken(it);228 _ = p.nextToken();
245 }229 }
230
231 // add error and continue
232 try p.errors.append(p.gpa, .{
233 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
234 });
235 continue;
236 },
237 }
238 };
239 if (try p.parseAppendedDocComment(comma)) |appended_comment|
240 field.doc_comments = appended_comment;
241 continue;
242 }
246243
247 // this was likely not supposed to end yet,244 // Dangling doc comment
248 // try to find the next declaration245 if (doc_comments != null) {
249 findNextContainerMember(it);246 try p.errors.append(p.gpa, .{
250 try tree.errors.push(.{247 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
251 .ExpectedContainerMembers = .{ .token = index },
252 });248 });
253 },249 }
254 }
255 }
256250
257 return list;251 const next = p.token_ids[p.tok_i];
258}252 switch (next) {
253 .Eof => break,
254 .Keyword_comptime => {
255 _ = p.nextToken();
256 try p.errors.append(p.gpa, .{
257 .ExpectedBlockOrField = .{ .token = p.tok_i },
258 });
259 },
260 else => {
261 const index = p.tok_i;
262 if (next == .RBrace) {
263 if (!top_level) break;
264 _ = p.nextToken();
265 }
259266
260/// Attempts to find next container member by searching for certain tokens267 // this was likely not supposed to end yet,
261fn findNextContainerMember(it: *TokenIterator) void {268 // try to find the next declaration
262 var level: u32 = 0;269 p.findNextContainerMember();
263 while (true) {270 try p.errors.append(p.gpa, .{
264 const tok = nextToken(it);271 .ExpectedContainerMembers = .{ .token = index },
265 switch (tok.ptr.id) {272 });
266 // any of these can start a new top level declaration273 },
267 .Keyword_test,274 }
268 .Keyword_comptime,
269 .Keyword_pub,
270 .Keyword_export,
271 .Keyword_extern,
272 .Keyword_inline,
273 .Keyword_noinline,
274 .Keyword_usingnamespace,
275 .Keyword_threadlocal,
276 .Keyword_const,
277 .Keyword_var,
278 .Keyword_fn,
279 .Identifier,
280 => {
281 if (level == 0) {
282 putBackToken(it, tok.index);
283 return;
284 }
285 },
286 .Comma, .Semicolon => {
287 // this decl was likely meant to end here
288 if (level == 0) {
289 return;
290 }
291 },
292 .LParen, .LBracket, .LBrace => level += 1,
293 .RParen, .RBracket => {
294 if (level != 0) level -= 1;
295 },
296 .RBrace => {
297 if (level == 0) {
298 // end of container, exit
299 putBackToken(it, tok.index);
300 return;
301 }
302 level -= 1;
303 },
304 .Eof => {
305 putBackToken(it, tok.index);
306 return;
307 },
308 else => {},
309 }275 }
276
277 return list.toOwnedSlice();
310 }278 }
311}
312279
313/// Attempts to find the next statement by searching for a semicolon280 /// Attempts to find next container member by searching for certain tokens
314fn findNextStmt(it: *TokenIterator) void {281 fn findNextContainerMember(p: *Parser) void {
315 var level: u32 = 0;282 var level: u32 = 0;
316 while (true) {283 while (true) {
317 const tok = nextToken(it);284 const tok = p.nextToken();
318 switch (tok.ptr.id) {285 switch (p.token_ids[tok]) {
319 .LBrace => level += 1,286 // any of these can start a new top level declaration
320 .RBrace => {287 .Keyword_test,
321 if (level == 0) {288 .Keyword_comptime,
322 putBackToken(it, tok.index);289 .Keyword_pub,
323 return;290 .Keyword_export,
324 }291 .Keyword_extern,
325 level -= 1;292 .Keyword_inline,
326 },293 .Keyword_noinline,
327 .Semicolon => {294 .Keyword_usingnamespace,
328 if (level == 0) {295 .Keyword_threadlocal,
296 .Keyword_const,
297 .Keyword_var,
298 .Keyword_fn,
299 .Identifier,
300 => {
301 if (level == 0) {
302 p.putBackToken(tok);
303 return;
304 }
305 },
306 .Comma, .Semicolon => {
307 // this decl was likely meant to end here
308 if (level == 0) {
309 return;
310 }
311 },
312 .LParen, .LBracket, .LBrace => level += 1,
313 .RParen, .RBracket => {
314 if (level != 0) level -= 1;
315 },
316 .RBrace => {
317 if (level == 0) {
318 // end of container, exit
319 p.putBackToken(tok);
320 return;
321 }
322 level -= 1;
323 },
324 .Eof => {
325 p.putBackToken(tok);
329 return;326 return;
330 }327 },
331 },328 else => {},
332 .Eof => {329 }
333 putBackToken(it, tok.index);
334 return;
335 },
336 else => {},
337 }330 }
338 }331 }
339}
340
341/// Eat a multiline container doc comment
342fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
343 var lines = Node.DocComment.LineList.init(arena);
344 while (eatToken(it, .ContainerDocComment)) |line| {
345 try lines.push(line);
346 }
347
348 if (lines.len == 0) return null;
349
350 const node = try arena.create(Node.DocComment);
351 node.* = .{
352 .lines = lines,
353 };
354 return &node.base;
355}
356
357/// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block
358fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
359 const test_token = eatToken(it, .Keyword_test) orelse return null;
360 const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{
361 .ExpectedStringLiteral = .{ .token = it.index },
362 });
363 const block_node = try expectNode(arena, it, tree, parseBlock, .{
364 .ExpectedLBrace = .{ .token = it.index },
365 });
366
367 const test_node = try arena.create(Node.TestDecl);
368 test_node.* = .{
369 .doc_comments = null,
370 .test_token = test_token,
371 .name = name_node,
372 .body_node = block_node,
373 };
374 return &test_node.base;
375}
376
377/// TopLevelComptime <- KEYWORD_comptime BlockExpr
378fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
379 const tok = eatToken(it, .Keyword_comptime) orelse return null;
380 const lbrace = eatToken(it, .LBrace) orelse {
381 putBackToken(it, tok);
382 return null;
383 };
384 putBackToken(it, lbrace);
385 const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{
386 .ExpectedLabelOrLBrace = .{ .token = it.index },
387 });
388
389 const comptime_node = try arena.create(Node.Comptime);
390 comptime_node.* = .{
391 .doc_comments = null,
392 .comptime_token = tok,
393 .expr = block_node,
394 };
395 return &comptime_node.base;
396}
397
398/// TopLevelDecl
399/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
400/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
401/// / KEYWORD_usingnamespace Expr SEMICOLON
402fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
403 var lib_name: ?*Node = null;
404 const extern_export_inline_token = blk: {
405 if (eatToken(it, .Keyword_export)) |token| break :blk token;
406 if (eatToken(it, .Keyword_extern)) |token| {
407 lib_name = try parseStringLiteralSingle(arena, it, tree);
408 break :blk token;
409 }
410 if (eatToken(it, .Keyword_inline)) |token| break :blk token;
411 if (eatToken(it, .Keyword_noinline)) |token| break :blk token;
412 break :blk null;
413 };
414332
415 if (try parseFnProto(arena, it, tree)) |node| {333 /// Attempts to find the next statement by searching for a semicolon
416 const fn_node = node.cast(Node.FnProto).?;334 fn findNextStmt(p: *Parser) void {
417 fn_node.*.extern_export_inline_token = extern_export_inline_token;335 var level: u32 = 0;
418 fn_node.*.lib_name = lib_name;336 while (true) {
419 if (eatToken(it, .Semicolon)) |_| return node;337 const tok = p.nextToken();
420338 switch (p.token_ids[tok]) {
421 if (try expectNodeRecoverable(arena, it, tree, parseBlock, .{339 .LBrace => level += 1,
422 // since parseBlock only return error.ParseError on340 .RBrace => {
423 // a missing '}' we can assume this function was341 if (level == 0) {
424 // supposed to end here.342 p.putBackToken(tok);
425 .ExpectedSemiOrLBrace = .{ .token = it.index },343 return;
426 })) |body_node| {344 }
427 fn_node.body_node = body_node;345 level -= 1;
346 },
347 .Semicolon => {
348 if (level == 0) {
349 return;
350 }
351 },
352 .Eof => {
353 p.putBackToken(tok);
354 return;
355 },
356 else => {},
357 }
428 }358 }
429 return node;
430 }359 }
431360
432 if (extern_export_inline_token) |token| {361 /// Eat a multiline container doc comment
433 if (tree.tokens.at(token).id == .Keyword_inline or362 fn parseContainerDocComments(p: *Parser) !?*Node {
434 tree.tokens.at(token).id == .Keyword_noinline)363 if (p.eatToken(.ContainerDocComment)) |first_line| {
435 {364 while (p.eatToken(.ContainerDocComment)) |_| {}
436 try tree.errors.push(.{365 const node = try p.arena.allocator.create(Node.DocComment);
437 .ExpectedFn = .{ .token = it.index },366 node.* = .{ .first_line = first_line };
438 });367 return &node.base;
439 return error.ParseError;
440 }368 }
369 return null;
441 }370 }
442371
443 const thread_local_token = eatToken(it, .Keyword_threadlocal);372 /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block
444373 fn parseTestDecl(p: *Parser) !?*Node {
445 if (try parseVarDecl(arena, it, tree)) |node| {374 const test_token = p.eatToken(.Keyword_test) orelse return null;
446 var var_decl = node.cast(Node.VarDecl).?;375 const name_node = try p.expectNode(parseStringLiteralSingle, .{
447 var_decl.*.thread_local_token = thread_local_token;376 .ExpectedStringLiteral = .{ .token = p.tok_i },
448 var_decl.*.comptime_token = null;
449 var_decl.*.extern_export_token = extern_export_inline_token;
450 var_decl.*.lib_name = lib_name;
451 return node;
452 }
453
454 if (thread_local_token != null) {
455 try tree.errors.push(.{
456 .ExpectedVarDecl = .{ .token = it.index },
457 });377 });
458 // ignore this and try again;378 const block_node = try p.expectNode(parseBlock, .{
459 return error.ParseError;379 .ExpectedLBrace = .{ .token = p.tok_i },
460 }
461
462 if (extern_export_inline_token) |token| {
463 try tree.errors.push(.{
464 .ExpectedVarDeclOrFn = .{ .token = it.index },
465 });380 });
466 // ignore this and try again;381
467 return error.ParseError;382 const test_node = try p.arena.allocator.create(Node.TestDecl);
383 test_node.* = .{
384 .doc_comments = null,
385 .test_token = test_token,
386 .name = name_node,
387 .body_node = block_node,
388 };
389 return &test_node.base;
468 }390 }
469391
470 return try parseUse(arena, it, tree);392 /// TopLevelComptime <- KEYWORD_comptime BlockExpr
471}393 fn parseTopLevelComptime(p: *Parser) !?*Node {
394 const tok = p.eatToken(.Keyword_comptime) orelse return null;
395 const lbrace = p.eatToken(.LBrace) orelse {
396 p.putBackToken(tok);
397 return null;
398 };
399 p.putBackToken(lbrace);
400 const block_node = try p.expectNode(parseBlockExpr, .{
401 .ExpectedLabelOrLBrace = .{ .token = p.tok_i },
402 });
472403
473/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)404 const comptime_node = try p.arena.allocator.create(Node.Comptime);
474fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {405 comptime_node.* = .{
475 // TODO: Remove once extern/async fn rewriting is406 .doc_comments = null,
476 var is_async = false;407 .comptime_token = tok,
477 var is_extern = false;408 .expr = block_node,
478 const cc_token: ?usize = blk: {409 };
479 if (eatToken(it, .Keyword_extern)) |token| {410 return &comptime_node.base;
480 is_extern = true;411 }
481 break :blk token;412
482 }413 /// TopLevelDecl
483 if (eatToken(it, .Keyword_async)) |token| {414 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
484 is_async = true;415 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
485 break :blk token;416 /// / KEYWORD_usingnamespace Expr SEMICOLON
486 }417 fn parseTopLevelDecl(p: *Parser) !?*Node {
487 break :blk null;418 var lib_name: ?*Node = null;
488 };419 const extern_export_inline_token = blk: {
489 const fn_token = eatToken(it, .Keyword_fn) orelse {420 if (p.eatToken(.Keyword_export)) |token| break :blk token;
490 if (cc_token) |token|421 if (p.eatToken(.Keyword_extern)) |token| {
491 putBackToken(it, token);422 lib_name = try p.parseStringLiteralSingle();
492 return null;423 break :blk token;
493 };424 }
494 const name_token = eatToken(it, .Identifier);425 if (p.eatToken(.Keyword_inline)) |token| break :blk token;
495 const lparen = try expectToken(it, tree, .LParen);426 if (p.eatToken(.Keyword_noinline)) |token| break :blk token;
496 const params = try parseParamDeclList(arena, it, tree);427 break :blk null;
497 const rparen = try expectToken(it, tree, .RParen);428 };
498 const align_expr = try parseByteAlign(arena, it, tree);
499 const section_expr = try parseLinkSection(arena, it, tree);
500 const callconv_expr = try parseCallconv(arena, it, tree);
501 const exclamation_token = eatToken(it, .Bang);
502
503 const return_type_expr = (try parseVarType(arena, it, tree)) orelse
504 try expectNodeRecoverable(arena, it, tree, parseTypeExpr, .{
505 // most likely the user forgot to specify the return type.
506 // Mark return type as invalid and try to continue.
507 .ExpectedReturnType = .{ .token = it.index },
508 });
509
510 // TODO https://github.com/ziglang/zig/issues/3750
511 const R = Node.FnProto.ReturnType;
512 const return_type = if (return_type_expr == null)
513 R{ .Invalid = rparen }
514 else if (exclamation_token != null)
515 R{ .InferErrorSet = return_type_expr.? }
516 else
517 R{ .Explicit = return_type_expr.? };
518
519 const var_args_token = if (params.len > 0) blk: {
520 const param_type = params.at(params.len - 1).*.cast(Node.ParamDecl).?.param_type;
521 break :blk if (param_type == .var_args) param_type.var_args else null;
522 } else
523 null;
524
525 const fn_proto_node = try arena.create(Node.FnProto);
526 fn_proto_node.* = .{
527 .doc_comments = null,
528 .visib_token = null,
529 .fn_token = fn_token,
530 .name_token = name_token,
531 .params = params,
532 .return_type = return_type,
533 .var_args_token = var_args_token,
534 .extern_export_inline_token = null,
535 .body_node = null,
536 .lib_name = null,
537 .align_expr = align_expr,
538 .section_expr = section_expr,
539 .callconv_expr = callconv_expr,
540 .is_extern_prototype = is_extern,
541 .is_async = is_async,
542 };
543429
544 return &fn_proto_node.base;430 if (try p.parseFnProto()) |node| {
545}431 const fn_node = node.cast(Node.FnProto).?;
432 fn_node.*.extern_export_inline_token = extern_export_inline_token;
433 fn_node.*.lib_name = lib_name;
434 if (p.eatToken(.Semicolon)) |_| return node;
435
436 if (try p.expectNodeRecoverable(parseBlock, .{
437 // since parseBlock only return error.ParseError on
438 // a missing '}' we can assume this function was
439 // supposed to end here.
440 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
441 })) |body_node| {
442 fn_node.body_node = body_node;
443 }
444 return node;
445 }
546446
547/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON447 if (extern_export_inline_token) |token| {
548fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {448 if (p.token_ids[token] == .Keyword_inline or
549 const mut_token = eatToken(it, .Keyword_const) orelse449 p.token_ids[token] == .Keyword_noinline)
550 eatToken(it, .Keyword_var) orelse450 {
551 return null;451 try p.errors.append(p.gpa, .{
452 .ExpectedFn = .{ .token = p.tok_i },
453 });
454 return error.ParseError;
455 }
456 }
552457
553 const name_token = try expectToken(it, tree, .Identifier);458 const thread_local_token = p.eatToken(.Keyword_threadlocal);
554 const type_node = if (eatToken(it, .Colon) != null)
555 try expectNode(arena, it, tree, parseTypeExpr, .{
556 .ExpectedTypeExpr = .{ .token = it.index },
557 })
558 else
559 null;
560 const align_node = try parseByteAlign(arena, it, tree);
561 const section_node = try parseLinkSection(arena, it, tree);
562 const eq_token = eatToken(it, .Equal);
563 const init_node = if (eq_token != null) blk: {
564 break :blk try expectNode(arena, it, tree, parseExpr, .{
565 .ExpectedExpr = .{ .token = it.index },
566 });
567 } else null;
568 const semicolon_token = try expectToken(it, tree, .Semicolon);
569
570 const node = try arena.create(Node.VarDecl);
571 node.* = .{
572 .doc_comments = null,
573 .visib_token = null,
574 .thread_local_token = null,
575 .name_token = name_token,
576 .eq_token = eq_token,
577 .mut_token = mut_token,
578 .comptime_token = null,
579 .extern_export_token = null,
580 .lib_name = null,
581 .type_node = type_node,
582 .align_node = align_node,
583 .section_node = section_node,
584 .init_node = init_node,
585 .semicolon_token = semicolon_token,
586 };
587 return &node.base;
588}
589459
590/// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?460 if (try p.parseVarDecl()) |node| {
591fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {461 var var_decl = node.cast(Node.VarDecl).?;
592 const comptime_token = eatToken(it, .Keyword_comptime);462 var_decl.*.thread_local_token = thread_local_token;
593 const name_token = eatToken(it, .Identifier) orelse {463 var_decl.*.comptime_token = null;
594 if (comptime_token) |t| putBackToken(it, t);464 var_decl.*.extern_export_token = extern_export_inline_token;
595 return null;465 var_decl.*.lib_name = lib_name;
596 };466 return node;
467 }
597468
598 var align_expr: ?*Node = null;469 if (thread_local_token != null) {
599 var type_expr: ?*Node = null;470 try p.errors.append(p.gpa, .{
600 if (eatToken(it, .Colon)) |_| {471 .ExpectedVarDecl = .{ .token = p.tok_i },
601 if (eatToken(it, .Keyword_var)) |var_tok| {
602 const node = try arena.create(ast.Node.VarType);
603 node.* = .{ .token = var_tok };
604 type_expr = &node.base;
605 } else {
606 type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
607 .ExpectedTypeExpr = .{ .token = it.index },
608 });472 });
609 align_expr = try parseByteAlign(arena, it, tree);473 // ignore this and try again;
474 return error.ParseError;
610 }475 }
611 }
612476
613 const value_expr = if (eatToken(it, .Equal)) |_|477 if (extern_export_inline_token) |token| {
614 try expectNode(arena, it, tree, parseExpr, .{478 try p.errors.append(p.gpa, .{
615 .ExpectedExpr = .{ .token = it.index },479 .ExpectedVarDeclOrFn = .{ .token = p.tok_i },
616 })480 });
617 else481 // ignore this and try again;
618 null;482 return error.ParseError;
619483 }
620 const node = try arena.create(Node.ContainerField);
621 node.* = .{
622 .doc_comments = null,
623 .comptime_token = comptime_token,
624 .name_token = name_token,
625 .type_expr = type_expr,
626 .value_expr = value_expr,
627 .align_expr = align_expr,
628 };
629 return &node.base;
630}
631484
632/// Statement485 return p.parseUse();
633/// <- KEYWORD_comptime? VarDecl
634/// / KEYWORD_comptime BlockExprStatement
635/// / KEYWORD_nosuspend BlockExprStatement
636/// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
637/// / KEYWORD_defer BlockExprStatement
638/// / KEYWORD_errdefer Payload? BlockExprStatement
639/// / IfStatement
640/// / LabeledStatement
641/// / SwitchExpr
642/// / AssignExpr SEMICOLON
643fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
644 const comptime_token = eatToken(it, .Keyword_comptime);
645
646 const var_decl_node = try parseVarDecl(arena, it, tree);
647 if (var_decl_node) |node| {
648 const var_decl = node.cast(Node.VarDecl).?;
649 var_decl.comptime_token = comptime_token;
650 return node;
651 }486 }
652487
653 if (comptime_token) |token| {488 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
654 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{489 fn parseFnProto(p: *Parser) !?*Node {
655 .ExpectedBlockOrAssignment = .{ .token = it.index },490 // TODO: Remove once extern/async fn rewriting is
491 var is_async = false;
492 var is_extern = false;
493 const cc_token: ?TokenIndex = blk: {
494 if (p.eatToken(.Keyword_extern)) |token| {
495 is_extern = true;
496 break :blk token;
497 }
498 if (p.eatToken(.Keyword_async)) |token| {
499 is_async = true;
500 break :blk token;
501 }
502 break :blk null;
503 };
504 const fn_token = p.eatToken(.Keyword_fn) orelse {
505 if (cc_token) |token|
506 p.putBackToken(token);
507 return null;
508 };
509 const name_token = p.eatToken(.Identifier);
510 const lparen = try p.expectToken(.LParen);
511 const params = try p.parseParamDeclList();
512 defer p.gpa.free(params);
513 const rparen = try p.expectToken(.RParen);
514 const align_expr = try p.parseByteAlign();
515 const section_expr = try p.parseLinkSection();
516 const callconv_expr = try p.parseCallconv();
517 const exclamation_token = p.eatToken(.Bang);
518
519 const return_type_expr = (try p.parseVarType()) orelse
520 try p.expectNodeRecoverable(parseTypeExpr, .{
521 // most likely the user forgot to specify the return type.
522 // Mark return type as invalid and try to continue.
523 .ExpectedReturnType = .{ .token = p.tok_i },
656 });524 });
657525
658 const node = try arena.create(Node.Comptime);526 // TODO https://github.com/ziglang/zig/issues/3750
659 node.* = .{527 const R = Node.FnProto.ReturnType;
660 .doc_comments = null,528 const return_type = if (return_type_expr == null)
661 .comptime_token = token,529 R{ .Invalid = rparen }
662 .expr = block_expr,530 else if (exclamation_token != null)
663 };531 R{ .InferErrorSet = return_type_expr.? }
664 return &node.base;532 else
665 }533 R{ .Explicit = return_type_expr.? };
666534
667 if (eatToken(it, .Keyword_nosuspend)) |nosuspend_token| {535 const var_args_token = if (params.len > 0) blk: {
668 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{536 const param_type = params[params.len - 1].param_type;
669 .ExpectedBlockOrAssignment = .{ .token = it.index },537 break :blk if (param_type == .var_args) param_type.var_args else null;
670 });538 } else
539 null;
671540
672 const node = try arena.create(Node.Nosuspend);541 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
673 node.* = .{542 fn_proto_node.* = .{
674 .nosuspend_token = nosuspend_token,543 .doc_comments = null,
675 .expr = block_expr,544 .visib_token = null,
545 .fn_token = fn_token,
546 .name_token = name_token,
547 .params_len = params.len,
548 .return_type = return_type,
549 .var_args_token = var_args_token,
550 .extern_export_inline_token = null,
551 .body_node = null,
552 .lib_name = null,
553 .align_expr = align_expr,
554 .section_expr = section_expr,
555 .callconv_expr = callconv_expr,
556 .is_extern_prototype = is_extern,
557 .is_async = is_async,
676 };558 };
677 return &node.base;559 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
560
561 return &fn_proto_node.base;
678 }562 }
679563
680 if (eatToken(it, .Keyword_suspend)) |suspend_token| {564 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
681 const semicolon = eatToken(it, .Semicolon);565 fn parseVarDecl(p: *Parser) !?*Node {
566 const mut_token = p.eatToken(.Keyword_const) orelse
567 p.eatToken(.Keyword_var) orelse
568 return null;
682569
683 const body_node = if (semicolon == null) blk: {570 const name_token = try p.expectToken(.Identifier);
684 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{571 const type_node = if (p.eatToken(.Colon) != null)
685 .ExpectedBlockOrExpression = .{ .token = it.index },572 try p.expectNode(parseTypeExpr, .{
573 .ExpectedTypeExpr = .{ .token = p.tok_i },
574 })
575 else
576 null;
577 const align_node = try p.parseByteAlign();
578 const section_node = try p.parseLinkSection();
579 const eq_token = p.eatToken(.Equal);
580 const init_node = if (eq_token != null) blk: {
581 break :blk try p.expectNode(parseExpr, .{
582 .ExpectedExpr = .{ .token = p.tok_i },
686 });583 });
687 } else null;584 } else null;
585 const semicolon_token = try p.expectToken(.Semicolon);
688586
689 const node = try arena.create(Node.Suspend);587 const node = try p.arena.allocator.create(Node.VarDecl);
690 node.* = .{588 node.* = .{
691 .suspend_token = suspend_token,589 .doc_comments = null,
692 .body = body_node,590 .visib_token = null,
591 .thread_local_token = null,
592 .name_token = name_token,
593 .eq_token = eq_token,
594 .mut_token = mut_token,
595 .comptime_token = null,
596 .extern_export_token = null,
597 .lib_name = null,
598 .type_node = type_node,
599 .align_node = align_node,
600 .section_node = section_node,
601 .init_node = init_node,
602 .semicolon_token = semicolon_token,
693 };603 };
694 return &node.base;604 return &node.base;
695 }605 }
696606
697 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);607 /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
698 if (defer_token) |token| {608 fn parseContainerField(p: *Parser) !?*Node {
699 const payload = if (tree.tokens.at(token).id == .Keyword_errdefer)609 const comptime_token = p.eatToken(.Keyword_comptime);
700 try parsePayload(arena, it, tree)610 const name_token = p.eatToken(.Identifier) orelse {
611 if (comptime_token) |t| p.putBackToken(t);
612 return null;
613 };
614
615 var align_expr: ?*Node = null;
616 var type_expr: ?*Node = null;
617 if (p.eatToken(.Colon)) |_| {
618 if (p.eatToken(.Keyword_var)) |var_tok| {
619 const node = try p.arena.allocator.create(Node.VarType);
620 node.* = .{ .token = var_tok };
621 type_expr = &node.base;
622 } else {
623 type_expr = try p.expectNode(parseTypeExpr, .{
624 .ExpectedTypeExpr = .{ .token = p.tok_i },
625 });
626 align_expr = try p.parseByteAlign();
627 }
628 }
629
630 const value_expr = if (p.eatToken(.Equal)) |_|
631 try p.expectNode(parseExpr, .{
632 .ExpectedExpr = .{ .token = p.tok_i },
633 })
701 else634 else
702 null;635 null;
703 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{636
704 .ExpectedBlockOrExpression = .{ .token = it.index },637 const node = try p.arena.allocator.create(Node.ContainerField);
705 });
706 const node = try arena.create(Node.Defer);
707 node.* = .{638 node.* = .{
708 .defer_token = token,639 .doc_comments = null,
709 .expr = expr_node,640 .comptime_token = comptime_token,
710 .payload = payload,641 .name_token = name_token,
642 .type_expr = type_expr,
643 .value_expr = value_expr,
644 .align_expr = align_expr,
711 };645 };
712 return &node.base;646 return &node.base;
713 }647 }
714648
715 if (try parseIfStatement(arena, it, tree)) |node| return node;649 /// Statement
716 if (try parseLabeledStatement(arena, it, tree)) |node| return node;650 /// <- KEYWORD_comptime? VarDecl
717 if (try parseSwitchExpr(arena, it, tree)) |node| return node;651 /// / KEYWORD_comptime BlockExprStatement
718 if (try parseAssignExpr(arena, it, tree)) |node| {652 /// / KEYWORD_nosuspend BlockExprStatement
719 _ = try expectTokenRecoverable(it, tree, .Semicolon);653 /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
720 return node;654 /// / KEYWORD_defer BlockExprStatement
721 }655 /// / KEYWORD_errdefer Payload? BlockExprStatement
656 /// / IfStatement
657 /// / LabeledStatement
658 /// / SwitchExpr
659 /// / AssignExpr SEMICOLON
660 fn parseStatement(p: *Parser) Error!?*Node {
661 const comptime_token = p.eatToken(.Keyword_comptime);
662
663 const var_decl_node = try p.parseVarDecl();
664 if (var_decl_node) |node| {
665 const var_decl = node.cast(Node.VarDecl).?;
666 var_decl.comptime_token = comptime_token;
667 return node;
668 }
722669
723 return null;670 if (comptime_token) |token| {
724}671 const block_expr = try p.expectNode(parseBlockExprStatement, .{
672 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
673 });
725674
726/// IfStatement675 const node = try p.arena.allocator.create(Node.Comptime);
727/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?676 node.* = .{
728/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )677 .doc_comments = null,
729fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {678 .comptime_token = token,
730 const if_node = (try parseIfPrefix(arena, it, tree)) orelse return null;679 .expr = block_expr,
731 const if_prefix = if_node.cast(Node.If).?;680 };
732681 return &node.base;
733 const block_expr = (try parseBlockExpr(arena, it, tree));682 }
734 const assign_expr = if (block_expr == null)
735 try expectNode(arena, it, tree, parseAssignExpr, .{
736 .ExpectedBlockOrAssignment = .{ .token = it.index },
737 })
738 else
739 null;
740
741 const semicolon = if (assign_expr != null) eatToken(it, .Semicolon) else null;
742
743 const else_node = if (semicolon == null) blk: {
744 const else_token = eatToken(it, .Keyword_else) orelse break :blk null;
745 const payload = try parsePayload(arena, it, tree);
746 const else_body = try expectNode(arena, it, tree, parseStatement, .{
747 .InvalidToken = .{ .token = it.index },
748 });
749683
750 const node = try arena.create(Node.Else);684 if (p.eatToken(.Keyword_nosuspend)) |nosuspend_token| {
751 node.* = .{685 const block_expr = try p.expectNode(parseBlockExprStatement, .{
752 .else_token = else_token,686 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
753 .payload = payload,687 });
754 .body = else_body,
755 };
756688
757 break :blk node;689 const node = try p.arena.allocator.create(Node.Nosuspend);
758 } else null;690 node.* = .{
691 .nosuspend_token = nosuspend_token,
692 .expr = block_expr,
693 };
694 return &node.base;
695 }
759696
760 if (block_expr) |body| {697 if (p.eatToken(.Keyword_suspend)) |suspend_token| {
761 if_prefix.body = body;698 const semicolon = p.eatToken(.Semicolon);
762 if_prefix.@"else" = else_node;
763 return if_node;
764 }
765699
766 if (assign_expr) |body| {700 const body_node = if (semicolon == null) blk: {
767 if_prefix.body = body;701 break :blk try p.expectNode(parseBlockExprStatement, .{
768 if (semicolon != null) return if_node;702 .ExpectedBlockOrExpression = .{ .token = p.tok_i },
769 if (else_node != null) {703 });
770 if_prefix.@"else" = else_node;704 } else null;
771 return if_node;
772 }
773 try tree.errors.push(.{
774 .ExpectedSemiOrElse = .{ .token = it.index },
775 });
776 }
777
778 return if_node;
779}
780705
781/// LabeledStatement <- BlockLabel? (Block / LoopStatement)706 const node = try p.arena.allocator.create(Node.Suspend);
782fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {707 node.* = .{
783 var colon: TokenIndex = undefined;708 .suspend_token = suspend_token,
784 const label_token = parseBlockLabel(arena, it, tree, &colon);709 .body = body_node,
710 };
711 return &node.base;
712 }
785713
786 if (try parseBlock(arena, it, tree)) |node| {714 const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer);
787 node.cast(Node.Block).?.label = label_token;715 if (defer_token) |token| {
788 return node;716 const payload = if (p.token_ids[token] == .Keyword_errdefer)
789 }717 try p.parsePayload()
718 else
719 null;
720 const expr_node = try p.expectNode(parseBlockExprStatement, .{
721 .ExpectedBlockOrExpression = .{ .token = p.tok_i },
722 });
723 const node = try p.arena.allocator.create(Node.Defer);
724 node.* = .{
725 .defer_token = token,
726 .expr = expr_node,
727 .payload = payload,
728 };
729 return &node.base;
730 }
790731
791 if (try parseLoopStatement(arena, it, tree)) |node| {732 if (try p.parseIfStatement()) |node| return node;
792 if (node.cast(Node.For)) |for_node| {733 if (try p.parseLabeledStatement()) |node| return node;
793 for_node.label = label_token;734 if (try p.parseSwitchExpr()) |node| return node;
794 } else if (node.cast(Node.While)) |while_node| {735 if (try p.parseAssignExpr()) |node| {
795 while_node.label = label_token;736 _ = try p.expectTokenRecoverable(.Semicolon);
796 } else unreachable;737 return node;
797 return node;738 }
798 }
799739
800 if (label_token != null) {740 return null;
801 try tree.errors.push(.{
802 .ExpectedLabelable = .{ .token = it.index },
803 });
804 return error.ParseError;
805 }741 }
806742
807 return null;743 /// IfStatement
808}744 /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
745 /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
746 fn parseIfStatement(p: *Parser) !?*Node {
747 const if_node = (try p.parseIfPrefix()) orelse return null;
748 const if_prefix = if_node.cast(Node.If).?;
809749
810/// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)750 const block_expr = (try p.parseBlockExpr());
811fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {751 const assign_expr = if (block_expr == null)
812 const inline_token = eatToken(it, .Keyword_inline);752 try p.expectNode(parseAssignExpr, .{
753 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
754 })
755 else
756 null;
813757
814 if (try parseForStatement(arena, it, tree)) |node| {758 const semicolon = if (assign_expr != null) p.eatToken(.Semicolon) else null;
815 node.cast(Node.For).?.inline_token = inline_token;
816 return node;
817 }
818759
819 if (try parseWhileStatement(arena, it, tree)) |node| {760 const else_node = if (semicolon == null) blk: {
820 node.cast(Node.While).?.inline_token = inline_token;761 const else_token = p.eatToken(.Keyword_else) orelse break :blk null;
821 return node;762 const payload = try p.parsePayload();
822 }763 const else_body = try p.expectNode(parseStatement, .{
823 if (inline_token == null) return null;764 .InvalidToken = .{ .token = p.tok_i },
765 });
824766
825 // If we've seen "inline", there should have been a "for" or "while"767 const node = try p.arena.allocator.create(Node.Else);
826 try tree.errors.push(.{768 node.* = .{
827 .ExpectedInlinable = .{ .token = it.index },769 .else_token = else_token,
828 });770 .payload = payload,
829 return error.ParseError;771 .body = else_body,
830}772 };
831773
832/// ForStatement774 break :blk node;
833/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?775 } else null;
834/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
835fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
836 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
837 const for_prefix = node.cast(Node.For).?;
838776
839 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {777 if (block_expr) |body| {
840 for_prefix.body = block_expr_node;778 if_prefix.body = body;
779 if_prefix.@"else" = else_node;
780 return if_node;
781 }
841782
842 if (eatToken(it, .Keyword_else)) |else_token| {783 if (assign_expr) |body| {
843 const statement_node = try expectNode(arena, it, tree, parseStatement, .{784 if_prefix.body = body;
844 .InvalidToken = .{ .token = it.index },785 if (semicolon != null) return if_node;
786 if (else_node != null) {
787 if_prefix.@"else" = else_node;
788 return if_node;
789 }
790 try p.errors.append(p.gpa, .{
791 .ExpectedSemiOrElse = .{ .token = p.tok_i },
845 });792 });
793 }
846794
847 const else_node = try arena.create(Node.Else);795 return if_node;
848 else_node.* = .{796 }
849 .else_token = else_token,
850 .payload = null,
851 .body = statement_node,
852 };
853 for_prefix.@"else" = else_node;
854797
798 /// LabeledStatement <- BlockLabel? (Block / LoopStatement)
799 fn parseLabeledStatement(p: *Parser) !?*Node {
800 var colon: TokenIndex = undefined;
801 const label_token = p.parseBlockLabel(&colon);
802
803 if (try p.parseBlock()) |node| {
804 node.cast(Node.Block).?.label = label_token;
855 return node;805 return node;
856 }806 }
857807
858 return node;808 if (try p.parseLoopStatement()) |node| {
859 }809 if (node.cast(Node.For)) |for_node| {
810 for_node.label = label_token;
811 } else if (node.cast(Node.While)) |while_node| {
812 while_node.label = label_token;
813 } else unreachable;
814 return node;
815 }
860816
861 if (try parseAssignExpr(arena, it, tree)) |assign_expr| {817 if (label_token != null) {
862 for_prefix.body = assign_expr;818 try p.errors.append(p.gpa, .{
819 .ExpectedLabelable = .{ .token = p.tok_i },
820 });
821 return error.ParseError;
822 }
863823
864 if (eatToken(it, .Semicolon) != null) return node;824 return null;
825 }
865826
866 if (eatToken(it, .Keyword_else)) |else_token| {827 /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
867 const statement_node = try expectNode(arena, it, tree, parseStatement, .{828 fn parseLoopStatement(p: *Parser) !?*Node {
868 .ExpectedStatement = .{ .token = it.index },829 const inline_token = p.eatToken(.Keyword_inline);
869 });
870830
871 const else_node = try arena.create(Node.Else);831 if (try p.parseForStatement()) |node| {
872 else_node.* = .{832 node.cast(Node.For).?.inline_token = inline_token;
873 .else_token = else_token,
874 .payload = null,
875 .body = statement_node,
876 };
877 for_prefix.@"else" = else_node;
878 return node;833 return node;
879 }834 }
880835
881 try tree.errors.push(.{836 if (try p.parseWhileStatement()) |node| {
882 .ExpectedSemiOrElse = .{ .token = it.index },837 node.cast(Node.While).?.inline_token = inline_token;
883 });838 return node;
839 }
840 if (inline_token == null) return null;
884841
885 return node;842 // If we've seen "inline", there should have been a "for" or "while"
843 try p.errors.append(p.gpa, .{
844 .ExpectedInlinable = .{ .token = p.tok_i },
845 });
846 return error.ParseError;
886 }847 }
887848
888 return null;849 /// ForStatement
889}850 /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
890851 /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
891/// WhileStatement852 fn parseForStatement(p: *Parser) !?*Node {
892/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?853 const node = (try p.parseForPrefix()) orelse return null;
893/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )854 const for_prefix = node.cast(Node.For).?;
894fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
895 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
896 const while_prefix = node.cast(Node.While).?;
897855
898 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {856 if (try p.parseBlockExpr()) |block_expr_node| {
899 while_prefix.body = block_expr_node;857 for_prefix.body = block_expr_node;
900858
901 if (eatToken(it, .Keyword_else)) |else_token| {859 if (p.eatToken(.Keyword_else)) |else_token| {
902 const payload = try parsePayload(arena, it, tree);860 const statement_node = try p.expectNode(parseStatement, .{
861 .InvalidToken = .{ .token = p.tok_i },
862 });
903863
904 const statement_node = try expectNode(arena, it, tree, parseStatement, .{864 const else_node = try p.arena.allocator.create(Node.Else);
905 .InvalidToken = .{ .token = it.index },865 else_node.* = .{
906 });866 .else_token = else_token,
867 .payload = null,
868 .body = statement_node,
869 };
870 for_prefix.@"else" = else_node;
907871
908 const else_node = try arena.create(Node.Else);872 return node;
909 else_node.* = .{873 }
910 .else_token = else_token,
911 .payload = payload,
912 .body = statement_node,
913 };
914 while_prefix.@"else" = else_node;
915874
916 return node;875 return node;
917 }876 }
918877
919 return node;878 if (try p.parseAssignExpr()) |assign_expr| {
920 }879 for_prefix.body = assign_expr;
921880
922 if (try parseAssignExpr(arena, it, tree)) |assign_expr_node| {881 if (p.eatToken(.Semicolon) != null) return node;
923 while_prefix.body = assign_expr_node;
924882
925 if (eatToken(it, .Semicolon) != null) return node;883 if (p.eatToken(.Keyword_else)) |else_token| {
884 const statement_node = try p.expectNode(parseStatement, .{
885 .ExpectedStatement = .{ .token = p.tok_i },
886 });
926887
927 if (eatToken(it, .Keyword_else)) |else_token| {888 const else_node = try p.arena.allocator.create(Node.Else);
928 const payload = try parsePayload(arena, it, tree);889 else_node.* = .{
890 .else_token = else_token,
891 .payload = null,
892 .body = statement_node,
893 };
894 for_prefix.@"else" = else_node;
895 return node;
896 }
929897
930 const statement_node = try expectNode(arena, it, tree, parseStatement, .{898 try p.errors.append(p.gpa, .{
931 .ExpectedStatement = .{ .token = it.index },899 .ExpectedSemiOrElse = .{ .token = p.tok_i },
932 });900 });
933901
934 const else_node = try arena.create(Node.Else);
935 else_node.* = .{
936 .else_token = else_token,
937 .payload = payload,
938 .body = statement_node,
939 };
940 while_prefix.@"else" = else_node;
941 return node;902 return node;
942 }903 }
943904
944 try tree.errors.push(.{905 return null;
945 .ExpectedSemiOrElse = .{ .token = it.index },
946 });
947
948 return node;
949 }906 }
950907
951 return null;908 /// WhileStatement
952}909 /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
910 /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
911 fn parseWhileStatement(p: *Parser) !?*Node {
912 const node = (try p.parseWhilePrefix()) orelse return null;
913 const while_prefix = node.cast(Node.While).?;
953914
954/// BlockExprStatement915 if (try p.parseBlockExpr()) |block_expr_node| {
955/// <- BlockExpr916 while_prefix.body = block_expr_node;
956/// / AssignExpr SEMICOLON
957fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
958 if (try parseBlockExpr(arena, it, tree)) |node| return node;
959 if (try parseAssignExpr(arena, it, tree)) |node| {
960 _ = try expectTokenRecoverable(it, tree, .Semicolon);
961 return node;
962 }
963 return null;
964}
965917
966/// BlockExpr <- BlockLabel? Block918 if (p.eatToken(.Keyword_else)) |else_token| {
967fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {919 const payload = try p.parsePayload();
968 var colon: TokenIndex = undefined;
969 const label_token = parseBlockLabel(arena, it, tree, &colon);
970 const block_node = (try parseBlock(arena, it, tree)) orelse {
971 if (label_token) |label| {
972 putBackToken(it, label + 1); // ":"
973 putBackToken(it, label); // IDENTIFIER
974 }
975 return null;
976 };
977 block_node.cast(Node.Block).?.label = label_token;
978 return block_node;
979}
980920
981/// AssignExpr <- Expr (AssignOp Expr)?921 const statement_node = try p.expectNode(parseStatement, .{
982fn parseAssignExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {922 .InvalidToken = .{ .token = p.tok_i },
983 return parseBinOpExpr(arena, it, tree, parseAssignOp, parseExpr, .Once);923 });
984}
985924
986/// Expr <- KEYWORD_try* BoolOrExpr925 const else_node = try p.arena.allocator.create(Node.Else);
987fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {926 else_node.* = .{
988 return parsePrefixOpExpr(arena, it, tree, parseTry, parseBoolOrExpr);927 .else_token = else_token,
989}928 .payload = payload,
929 .body = statement_node,
930 };
931 while_prefix.@"else" = else_node;
990932
991/// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*933 return node;
992fn parseBoolOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {934 }
993 return parseBinOpExpr(
994 arena,
995 it,
996 tree,
997 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
998 parseBoolAndExpr,
999 .Infinitely,
1000 );
1001}
1002935
1003/// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*936 return node;
1004fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {937 }
1005 return parseBinOpExpr(
1006 arena,
1007 it,
1008 tree,
1009 SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
1010 parseCompareExpr,
1011 .Infinitely,
1012 );
1013}
1014938
1015/// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?939 if (try p.parseAssignExpr()) |assign_expr_node| {
1016fn parseCompareExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {940 while_prefix.body = assign_expr_node;
1017 return parseBinOpExpr(arena, it, tree, parseCompareOp, parseBitwiseExpr, .Once);
1018}
1019941
1020/// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*942 if (p.eatToken(.Semicolon) != null) return node;
1021fn parseBitwiseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1022 return parseBinOpExpr(arena, it, tree, parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1023}
1024943
1025/// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*944 if (p.eatToken(.Keyword_else)) |else_token| {
1026fn parseBitShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {945 const payload = try p.parsePayload();
1027 return parseBinOpExpr(arena, it, tree, parseBitShiftOp, parseAdditionExpr, .Infinitely);
1028}
1029946
1030/// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*947 const statement_node = try p.expectNode(parseStatement, .{
1031fn parseAdditionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {948 .ExpectedStatement = .{ .token = p.tok_i },
1032 return parseBinOpExpr(arena, it, tree, parseAdditionOp, parseMultiplyExpr, .Infinitely);949 });
1033}
1034950
1035/// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*951 const else_node = try p.arena.allocator.create(Node.Else);
1036fn parseMultiplyExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {952 else_node.* = .{
1037 return parseBinOpExpr(arena, it, tree, parseMultiplyOp, parsePrefixExpr, .Infinitely);953 .else_token = else_token,
1038}954 .payload = payload,
955 .body = statement_node,
956 };
957 while_prefix.@"else" = else_node;
958 return node;
959 }
1039960
1040/// PrefixExpr <- PrefixOp* PrimaryExpr961 try p.errors.append(p.gpa, .{
1041fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {962 .ExpectedSemiOrElse = .{ .token = p.tok_i },
1042 return parsePrefixOpExpr(arena, it, tree, parsePrefixOp, parsePrimaryExpr);963 });
1043}
1044964
1045/// PrimaryExpr965 return node;
1046/// <- AsmExpr966 }
1047/// / IfExpr
1048/// / KEYWORD_break BreakLabel? Expr?
1049/// / KEYWORD_comptime Expr
1050/// / KEYWORD_nosuspend Expr
1051/// / KEYWORD_continue BreakLabel?
1052/// / KEYWORD_resume Expr
1053/// / KEYWORD_return Expr?
1054/// / BlockLabel? LoopExpr
1055/// / Block
1056/// / CurlySuffixExpr
1057fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1058 if (try parseAsmExpr(arena, it, tree)) |node| return node;
1059 if (try parseIfExpr(arena, it, tree)) |node| return node;
1060
1061 if (eatToken(it, .Keyword_break)) |token| {
1062 const label = try parseBreakLabel(arena, it, tree);
1063 const expr_node = try parseExpr(arena, it, tree);
1064 const node = try arena.create(Node.ControlFlowExpression);
1065 node.* = .{
1066 .ltoken = token,
1067 .kind = .{ .Break = label },
1068 .rhs = expr_node,
1069 };
1070 return &node.base;
1071 }
1072967
1073 if (eatToken(it, .Keyword_comptime)) |token| {968 return null;
1074 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1075 .ExpectedExpr = .{ .token = it.index },
1076 });
1077 const node = try arena.create(Node.Comptime);
1078 node.* = .{
1079 .doc_comments = null,
1080 .comptime_token = token,
1081 .expr = expr_node,
1082 };
1083 return &node.base;
1084 }969 }
1085970
1086 if (eatToken(it, .Keyword_nosuspend)) |token| {971 /// BlockExprStatement
1087 const expr_node = try expectNode(arena, it, tree, parseExpr, .{972 /// <- BlockExpr
1088 .ExpectedExpr = .{ .token = it.index },973 /// / AssignExpr SEMICOLON
1089 });974 fn parseBlockExprStatement(p: *Parser) !?*Node {
1090 const node = try arena.create(Node.Nosuspend);975 if (try p.parseBlockExpr()) |node| return node;
1091 node.* = .{976 if (try p.parseAssignExpr()) |node| {
1092 .nosuspend_token = token,977 _ = try p.expectTokenRecoverable(.Semicolon);
1093 .expr = expr_node,978 return node;
1094 };979 }
1095 return &node.base;980 return null;
1096 }981 }
1097982
1098 if (eatToken(it, .Keyword_continue)) |token| {983 /// BlockExpr <- BlockLabel? Block
1099 const label = try parseBreakLabel(arena, it, tree);984 fn parseBlockExpr(p: *Parser) Error!?*Node {
1100 const node = try arena.create(Node.ControlFlowExpression);985 var colon: TokenIndex = undefined;
1101 node.* = .{986 const label_token = p.parseBlockLabel(&colon);
1102 .ltoken = token,987 const block_node = (try p.parseBlock()) orelse {
1103 .kind = .{ .Continue = label },988 if (label_token) |label| {
1104 .rhs = null,989 p.putBackToken(label + 1); // ":"
990 p.putBackToken(label); // IDENTIFIER
991 }
992 return null;
1105 };993 };
1106 return &node.base;994 block_node.cast(Node.Block).?.label = label_token;
995 return block_node;
1107 }996 }
1108997
1109 if (eatToken(it, .Keyword_resume)) |token| {998 /// AssignExpr <- Expr (AssignOp Expr)?
1110 const expr_node = try expectNode(arena, it, tree, parseExpr, .{999 fn parseAssignExpr(p: *Parser) !?*Node {
1111 .ExpectedExpr = .{ .token = it.index },1000 return p.parseBinOpExpr(parseAssignOp, parseExpr, .Once);
1112 });
1113 const node = try arena.create(Node.PrefixOp);
1114 node.* = .{
1115 .op_token = token,
1116 .op = .Resume,
1117 .rhs = expr_node,
1118 };
1119 return &node.base;
1120 }1001 }
11211002
1122 if (eatToken(it, .Keyword_return)) |token| {1003 /// Expr <- KEYWORD_try* BoolOrExpr
1123 const expr_node = try parseExpr(arena, it, tree);1004 fn parseExpr(p: *Parser) Error!?*Node {
1124 const node = try arena.create(Node.ControlFlowExpression);1005 return p.parsePrefixOpExpr(parseTry, parseBoolOrExpr);
1125 node.* = .{
1126 .ltoken = token,
1127 .kind = .Return,
1128 .rhs = expr_node,
1129 };
1130 return &node.base;
1131 }1006 }
11321007
1133 var colon: TokenIndex = undefined;1008 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
1134 const label = parseBlockLabel(arena, it, tree, &colon);1009 fn parseBoolOrExpr(p: *Parser) !?*Node {
1135 if (try parseLoopExpr(arena, it, tree)) |node| {1010 return p.parseBinOpExpr(
1136 if (node.cast(Node.For)) |for_node| {1011 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
1137 for_node.label = label;1012 parseBoolAndExpr,
1138 } else if (node.cast(Node.While)) |while_node| {1013 .Infinitely,
1139 while_node.label = label;1014 );
1140 } else unreachable;
1141 return node;
1142 }
1143 if (label) |token| {
1144 putBackToken(it, token + 1); // ":"
1145 putBackToken(it, token); // IDENTIFIER
1146 }1015 }
11471016
1148 if (try parseBlock(arena, it, tree)) |node| return node;1017 /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
1149 if (try parseCurlySuffixExpr(arena, it, tree)) |node| return node;1018 fn parseBoolAndExpr(p: *Parser) !?*Node {
1019 return p.parseBinOpExpr(
1020 SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
1021 parseCompareExpr,
1022 .Infinitely,
1023 );
1024 }
11501025
1151 return null;1026 /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
1152}1027 fn parseCompareExpr(p: *Parser) !?*Node {
1028 return p.parseBinOpExpr(parseCompareOp, parseBitwiseExpr, .Once);
1029 }
11531030
1154/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?1031 /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
1155fn parseIfExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1032 fn parseBitwiseExpr(p: *Parser) !?*Node {
1156 return parseIf(arena, it, tree, parseExpr);1033 return p.parseBinOpExpr(parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1157}1034 }
11581035
1159/// Block <- LBRACE Statement* RBRACE1036 /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
1160fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1037 fn parseBitShiftExpr(p: *Parser) !?*Node {
1161 const lbrace = eatToken(it, .LBrace) orelse return null;1038 return p.parseBinOpExpr(parseBitShiftOp, parseAdditionExpr, .Infinitely);
1039 }
11621040
1163 var statements = Node.Block.StatementList.init(arena);1041 /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
1164 while (true) {1042 fn parseAdditionExpr(p: *Parser) !?*Node {
1165 const statement = (parseStatement(arena, it, tree) catch |err| switch (err) {1043 return p.parseBinOpExpr(parseAdditionOp, parseMultiplyExpr, .Infinitely);
1166 error.OutOfMemory => return error.OutOfMemory,
1167 error.ParseError => {
1168 // try to skip to the next statement
1169 findNextStmt(it);
1170 continue;
1171 },
1172 }) orelse break;
1173 try statements.push(statement);
1174 }1044 }
11751045
1176 const rbrace = try expectToken(it, tree, .RBrace);1046 /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
1047 fn parseMultiplyExpr(p: *Parser) !?*Node {
1048 return p.parseBinOpExpr(parseMultiplyOp, parsePrefixExpr, .Infinitely);
1049 }
11771050
1178 const block_node = try arena.create(Node.Block);1051 /// PrefixExpr <- PrefixOp* PrimaryExpr
1179 block_node.* = .{1052 fn parsePrefixExpr(p: *Parser) !?*Node {
1180 .label = null,1053 return p.parsePrefixOpExpr(parsePrefixOp, parsePrimaryExpr);
1181 .lbrace = lbrace,1054 }
1182 .statements = statements,
1183 .rbrace = rbrace,
1184 };
11851055
1186 return &block_node.base;1056 /// PrimaryExpr
1187}1057 /// <- AsmExpr
1058 /// / IfExpr
1059 /// / KEYWORD_break BreakLabel? Expr?
1060 /// / KEYWORD_comptime Expr
1061 /// / KEYWORD_nosuspend Expr
1062 /// / KEYWORD_continue BreakLabel?
1063 /// / KEYWORD_resume Expr
1064 /// / KEYWORD_return Expr?
1065 /// / BlockLabel? LoopExpr
1066 /// / Block
1067 /// / CurlySuffixExpr
1068 fn parsePrimaryExpr(p: *Parser) !?*Node {
1069 if (try p.parseAsmExpr()) |node| return node;
1070 if (try p.parseIfExpr()) |node| return node;
11881071
1189/// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)1072 if (p.eatToken(.Keyword_break)) |token| {
1190fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1073 const label = try p.parseBreakLabel();
1191 const inline_token = eatToken(it, .Keyword_inline);1074 const expr_node = try p.parseExpr();
1075 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1076 node.* = .{
1077 .ltoken = token,
1078 .kind = .{ .Break = label },
1079 .rhs = expr_node,
1080 };
1081 return &node.base;
1082 }
11921083
1193 if (try parseForExpr(arena, it, tree)) |node| {1084 if (p.eatToken(.Keyword_comptime)) |token| {
1194 node.cast(Node.For).?.inline_token = inline_token;1085 const expr_node = try p.expectNode(parseExpr, .{
1195 return node;1086 .ExpectedExpr = .{ .token = p.tok_i },
1196 }1087 });
1088 const node = try p.arena.allocator.create(Node.Comptime);
1089 node.* = .{
1090 .doc_comments = null,
1091 .comptime_token = token,
1092 .expr = expr_node,
1093 };
1094 return &node.base;
1095 }
11971096
1198 if (try parseWhileExpr(arena, it, tree)) |node| {1097 if (p.eatToken(.Keyword_nosuspend)) |token| {
1199 node.cast(Node.While).?.inline_token = inline_token;1098 const expr_node = try p.expectNode(parseExpr, .{
1200 return node;1099 .ExpectedExpr = .{ .token = p.tok_i },
1201 }1100 });
1101 const node = try p.arena.allocator.create(Node.Nosuspend);
1102 node.* = .{
1103 .nosuspend_token = token,
1104 .expr = expr_node,
1105 };
1106 return &node.base;
1107 }
12021108
1203 if (inline_token == null) return null;1109 if (p.eatToken(.Keyword_continue)) |token| {
1110 const label = try p.parseBreakLabel();
1111 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1112 node.* = .{
1113 .ltoken = token,
1114 .kind = .{ .Continue = label },
1115 .rhs = null,
1116 };
1117 return &node.base;
1118 }
12041119
1205 // If we've seen "inline", there should have been a "for" or "while"1120 if (p.eatToken(.Keyword_resume)) |token| {
1206 try tree.errors.push(.{1121 const expr_node = try p.expectNode(parseExpr, .{
1207 .ExpectedInlinable = .{ .token = it.index },1122 .ExpectedExpr = .{ .token = p.tok_i },
1208 });1123 });
1209 return error.ParseError;1124 const node = try p.arena.allocator.create(Node.PrefixOp);
1210}1125 node.* = .{
1126 .op_token = token,
1127 .op = .Resume,
1128 .rhs = expr_node,
1129 };
1130 return &node.base;
1131 }
12111132
1212/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?1133 if (p.eatToken(.Keyword_return)) |token| {
1213fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1134 const expr_node = try p.parseExpr();
1214 const node = (try parseForPrefix(arena, it, tree)) orelse return null;1135 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1215 const for_prefix = node.cast(Node.For).?;1136 node.* = .{
1137 .ltoken = token,
1138 .kind = .Return,
1139 .rhs = expr_node,
1140 };
1141 return &node.base;
1142 }
12161143
1217 const body_node = try expectNode(arena, it, tree, parseExpr, .{1144 var colon: TokenIndex = undefined;
1218 .ExpectedExpr = .{ .token = it.index },1145 const label = p.parseBlockLabel(&colon);
1219 });1146 if (try p.parseLoopExpr()) |node| {
1220 for_prefix.body = body_node;1147 if (node.cast(Node.For)) |for_node| {
1148 for_node.label = label;
1149 } else if (node.cast(Node.While)) |while_node| {
1150 while_node.label = label;
1151 } else unreachable;
1152 return node;
1153 }
1154 if (label) |token| {
1155 p.putBackToken(token + 1); // ":"
1156 p.putBackToken(token); // IDENTIFIER
1157 }
12211158
1222 if (eatToken(it, .Keyword_else)) |else_token| {1159 if (try p.parseBlock()) |node| return node;
1223 const body = try expectNode(arena, it, tree, parseExpr, .{1160 if (try p.parseCurlySuffixExpr()) |node| return node;
1224 .ExpectedExpr = .{ .token = it.index },
1225 });
12261161
1227 const else_node = try arena.create(Node.Else);1162 return null;
1228 else_node.* = .{1163 }
1229 .else_token = else_token,
1230 .payload = null,
1231 .body = body,
1232 };
12331164
1234 for_prefix.@"else" = else_node;1165 /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
1166 fn parseIfExpr(p: *Parser) !?*Node {
1167 return p.parseIf(parseExpr);
1235 }1168 }
12361169
1237 return node;1170 /// Block <- LBRACE Statement* RBRACE
1238}1171 fn parseBlock(p: *Parser) !?*Node {
1172 const lbrace = p.eatToken(.LBrace) orelse return null;
1173
1174 var statements = std.ArrayList(*Node).init(p.gpa);
1175 defer statements.deinit();
12391176
1240/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?1177 while (true) {
1241fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1178 const statement = (p.parseStatement() catch |err| switch (err) {
1242 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;1179 error.OutOfMemory => return error.OutOfMemory,
1243 const while_prefix = node.cast(Node.While).?;1180 error.ParseError => {
1181 // try to skip to the next statement
1182 p.findNextStmt();
1183 continue;
1184 },
1185 }) orelse break;
1186 try statements.append(statement);
1187 }
12441188
1245 const body_node = try expectNode(arena, it, tree, parseExpr, .{1189 const rbrace = try p.expectToken(.RBrace);
1246 .ExpectedExpr = .{ .token = it.index },
1247 });
1248 while_prefix.body = body_node;
12491190
1250 if (eatToken(it, .Keyword_else)) |else_token| {1191 const statements_len = @intCast(NodeIndex, statements.items.len);
1251 const payload = try parsePayload(arena, it, tree);
1252 const body = try expectNode(arena, it, tree, parseExpr, .{
1253 .ExpectedExpr = .{ .token = it.index },
1254 });
12551192
1256 const else_node = try arena.create(Node.Else);1193 const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
1257 else_node.* = .{1194 block_node.* = .{
1258 .else_token = else_token,1195 .label = null,
1259 .payload = payload,1196 .lbrace = lbrace,
1260 .body = body,1197 .statements_len = statements_len,
1198 .rbrace = rbrace,
1261 };1199 };
1200 std.mem.copy(*Node, block_node.statements(), statements.items);
12621201
1263 while_prefix.@"else" = else_node;1202 return &block_node.base;
1264 }1203 }
12651204
1266 return node;1205 /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
1267}1206 fn parseLoopExpr(p: *Parser) !?*Node {
12681207 const inline_token = p.eatToken(.Keyword_inline);
1269/// CurlySuffixExpr <- TypeExpr InitList?
1270fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1271 const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
1272 const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr;
1273 suffix_op.lhs.node = type_expr;
1274 return &suffix_op.base;
1275}
12761208
1277/// InitList1209 if (try p.parseForExpr()) |node| {
1278/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE1210 node.cast(Node.For).?.inline_token = inline_token;
1279/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE1211 return node;
1280/// / LBRACE RBRACE
1281fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp {
1282 const lbrace = eatToken(it, .LBrace) orelse return null;
1283 var init_list = Node.SuffixOp.Op.InitList.init(arena);
1284
1285 const op: Node.SuffixOp.Op = blk: {
1286 if (try parseFieldInit(arena, it, tree)) |field_init| {
1287 try init_list.push(field_init);
1288 while (eatToken(it, .Comma)) |_| {
1289 const next = (try parseFieldInit(arena, it, tree)) orelse break;
1290 try init_list.push(next);
1291 }
1292 break :blk .{ .StructInitializer = init_list };
1293 }1212 }
12941213
1295 if (try parseExpr(arena, it, tree)) |expr| {1214 if (try p.parseWhileExpr()) |node| {
1296 try init_list.push(expr);1215 node.cast(Node.While).?.inline_token = inline_token;
1297 while (eatToken(it, .Comma)) |_| {1216 return node;
1298 const next = (try parseExpr(arena, it, tree)) orelse break;
1299 try init_list.push(next);
1300 }
1301 break :blk .{ .ArrayInitializer = init_list };
1302 }1217 }
13031218
1304 break :blk .{ .StructInitializer = init_list };1219 if (inline_token == null) return null;
1305 };
1306
1307 const node = try arena.create(Node.SuffixOp);
1308 node.* = .{
1309 .lhs = .{ .node = undefined }, // set by caller
1310 .op = op,
1311 .rtoken = try expectToken(it, tree, .RBrace),
1312 };
1313 return node;
1314}
13151220
1316/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr1221 // If we've seen "inline", there should have been a "for" or "while"
1317fn parseTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {1222 try p.errors.append(p.gpa, .{
1318 return parsePrefixOpExpr(arena, it, tree, parsePrefixTypeOp, parseErrorUnionExpr);1223 .ExpectedInlinable = .{ .token = p.tok_i },
1319}1224 });
1225 return error.ParseError;
1226 }
13201227
1321/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?1228 /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
1322fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1229 fn parseForExpr(p: *Parser) !?*Node {
1323 const suffix_expr = (try parseSuffixExpr(arena, it, tree)) orelse return null;1230 const node = (try p.parseForPrefix()) orelse return null;
1231 const for_prefix = node.cast(Node.For).?;
13241232
1325 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| {1233 const body_node = try p.expectNode(parseExpr, .{
1326 const error_union = node.cast(Node.InfixOp).?;1234 .ExpectedExpr = .{ .token = p.tok_i },
1327 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1328 .ExpectedTypeExpr = .{ .token = it.index },
1329 });1235 });
1330 error_union.lhs = suffix_expr;1236 for_prefix.body = body_node;
1331 error_union.rhs = type_expr;1237
1238 if (p.eatToken(.Keyword_else)) |else_token| {
1239 const body = try p.expectNode(parseExpr, .{
1240 .ExpectedExpr = .{ .token = p.tok_i },
1241 });
1242
1243 const else_node = try p.arena.allocator.create(Node.Else);
1244 else_node.* = .{
1245 .else_token = else_token,
1246 .payload = null,
1247 .body = body,
1248 };
1249
1250 for_prefix.@"else" = else_node;
1251 }
1252
1332 return node;1253 return node;
1333 }1254 }
13341255
1335 return suffix_expr;1256 /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
1336}1257 fn parseWhileExpr(p: *Parser) !?*Node {
1258 const node = (try p.parseWhilePrefix()) orelse return null;
1259 const while_prefix = node.cast(Node.While).?;
13371260
1338/// SuffixExpr1261 const body_node = try p.expectNode(parseExpr, .{
1339/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments1262 .ExpectedExpr = .{ .token = p.tok_i },
1340/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1341fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1342 const maybe_async = eatToken(it, .Keyword_async);
1343 if (maybe_async) |async_token| {
1344 const token_fn = eatToken(it, .Keyword_fn);
1345 if (token_fn != null) {
1346 // TODO: remove this hack when async fn rewriting is
1347 // HACK: If we see the keyword `fn`, then we assume that
1348 // we are parsing an async fn proto, and not a call.
1349 // We therefore put back all tokens consumed by the async
1350 // prefix...
1351 putBackToken(it, token_fn.?);
1352 putBackToken(it, async_token);
1353 return parsePrimaryTypeExpr(arena, it, tree);
1354 }
1355 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{
1356 .ExpectedPrimaryTypeExpr = .{ .token = it.index },
1357 });1263 });
1264 while_prefix.body = body_node;
13581265
1359 while (try parseSuffixOp(arena, it, tree)) |node| {1266 if (p.eatToken(.Keyword_else)) |else_token| {
1360 switch (node.id) {1267 const payload = try p.parsePayload();
1361 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },1268 const body = try p.expectNode(parseExpr, .{
1362 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,1269 .ExpectedExpr = .{ .token = p.tok_i },
1363 else => unreachable,
1364 }
1365 res = node;
1366 }
1367
1368 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
1369 try tree.errors.push(.{
1370 .ExpectedParamList = .{ .token = it.index },
1371 });1270 });
1372 // ignore this, continue parsing1271
1373 return res;1272 const else_node = try p.arena.allocator.create(Node.Else);
1273 else_node.* = .{
1274 .else_token = else_token,
1275 .payload = payload,
1276 .body = body,
1277 };
1278
1279 while_prefix.@"else" = else_node;
1280 }
1281
1282 return node;
1283 }
1284
1285 /// CurlySuffixExpr <- TypeExpr InitList?
1286 fn parseCurlySuffixExpr(p: *Parser) !?*Node {
1287 const lhs = (try p.parseTypeExpr()) orelse return null;
1288 const suffix_op = (try p.parseInitList(lhs)) orelse return lhs;
1289 return suffix_op;
1290 }
1291
1292 /// InitList
1293 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
1294 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
1295 /// / LBRACE RBRACE
1296 fn parseInitList(p: *Parser, lhs: *Node) !?*Node {
1297 const lbrace = p.eatToken(.LBrace) orelse return null;
1298 var init_list = std.ArrayList(*Node).init(p.gpa);
1299 defer init_list.deinit();
1300
1301 if (try p.parseFieldInit()) |field_init| {
1302 try init_list.append(field_init);
1303 while (p.eatToken(.Comma)) |_| {
1304 const next = (try p.parseFieldInit()) orelse break;
1305 try init_list.append(next);
1306 }
1307 const node = try Node.StructInitializer.alloc(&p.arena.allocator, init_list.items.len);
1308 node.* = .{
1309 .lhs = lhs,
1310 .rtoken = try p.expectToken(.RBrace),
1311 .list_len = init_list.items.len,
1312 };
1313 std.mem.copy(*Node, node.list(), init_list.items);
1314 return &node.base;
1315 }
1316
1317 if (try p.parseExpr()) |expr| {
1318 try init_list.append(expr);
1319 while (p.eatToken(.Comma)) |_| {
1320 const next = (try p.parseExpr()) orelse break;
1321 try init_list.append(next);
1322 }
1323 const node = try Node.ArrayInitializer.alloc(&p.arena.allocator, init_list.items.len);
1324 node.* = .{
1325 .lhs = lhs,
1326 .rtoken = try p.expectToken(.RBrace),
1327 .list_len = init_list.items.len,
1328 };
1329 std.mem.copy(*Node, node.list(), init_list.items);
1330 return &node.base;
1331 }
1332
1333 const node = try p.arena.allocator.create(Node.StructInitializer);
1334 node.* = .{
1335 .lhs = lhs,
1336 .rtoken = try p.expectToken(.RBrace),
1337 .list_len = 0,
1374 };1338 };
1375 const node = try arena.create(Node.SuffixOp);1339 return &node.base;
1340 }
1341
1342 /// InitList
1343 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
1344 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
1345 /// / LBRACE RBRACE
1346 fn parseAnonInitList(p: *Parser, dot: TokenIndex) !?*Node {
1347 const lbrace = p.eatToken(.LBrace) orelse return null;
1348 var init_list = std.ArrayList(*Node).init(p.gpa);
1349 defer init_list.deinit();
1350
1351 if (try p.parseFieldInit()) |field_init| {
1352 try init_list.append(field_init);
1353 while (p.eatToken(.Comma)) |_| {
1354 const next = (try p.parseFieldInit()) orelse break;
1355 try init_list.append(next);
1356 }
1357 const node = try Node.StructInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
1358 node.* = .{
1359 .dot = dot,
1360 .rtoken = try p.expectToken(.RBrace),
1361 .list_len = init_list.items.len,
1362 };
1363 std.mem.copy(*Node, node.list(), init_list.items);
1364 return &node.base;
1365 }
1366
1367 if (try p.parseExpr()) |expr| {
1368 try init_list.append(expr);
1369 while (p.eatToken(.Comma)) |_| {
1370 const next = (try p.parseExpr()) orelse break;
1371 try init_list.append(next);
1372 }
1373 const node = try Node.ArrayInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
1374 node.* = .{
1375 .dot = dot,
1376 .rtoken = try p.expectToken(.RBrace),
1377 .list_len = init_list.items.len,
1378 };
1379 std.mem.copy(*Node, node.list(), init_list.items);
1380 return &node.base;
1381 }
1382
1383 const node = try p.arena.allocator.create(Node.StructInitializerDot);
1376 node.* = .{1384 node.* = .{
1377 .lhs = .{ .node = res },1385 .dot = dot,
1378 .op = .{1386 .rtoken = try p.expectToken(.RBrace),
1379 .Call = .{1387 .list_len = 0,
1380 .params = params.list,
1381 .async_token = async_token,
1382 },
1383 },
1384 .rtoken = params.rparen,
1385 };1388 };
1386 return &node.base;1389 return &node.base;
1387 }1390 }
1388 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
1389 var res = expr;
13901391
1391 while (true) {1392 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1392 if (try parseSuffixOp(arena, it, tree)) |node| {1393 fn parseTypeExpr(p: *Parser) Error!?*Node {
1394 return p.parsePrefixOpExpr(parsePrefixTypeOp, parseErrorUnionExpr);
1395 }
1396
1397 /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
1398 fn parseErrorUnionExpr(p: *Parser) !?*Node {
1399 const suffix_expr = (try p.parseSuffixExpr()) orelse return null;
1400
1401 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| {
1402 const error_union = node.cast(Node.InfixOp).?;
1403 const type_expr = try p.expectNode(parseTypeExpr, .{
1404 .ExpectedTypeExpr = .{ .token = p.tok_i },
1405 });
1406 error_union.lhs = suffix_expr;
1407 error_union.rhs = type_expr;
1408 return node;
1409 }
1410
1411 return suffix_expr;
1412 }
1413
1414 /// SuffixExpr
1415 /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
1416 /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1417 fn parseSuffixExpr(p: *Parser) !?*Node {
1418 const maybe_async = p.eatToken(.Keyword_async);
1419 if (maybe_async) |async_token| {
1420 const token_fn = p.eatToken(.Keyword_fn);
1421 if (token_fn != null) {
1422 // TODO: remove this hack when async fn rewriting is
1423 // HACK: If we see the keyword `fn`, then we assume that
1424 // we are parsing an async fn proto, and not a call.
1425 // We therefore put back all tokens consumed by the async
1426 // prefix...
1427 p.putBackToken(token_fn.?);
1428 p.putBackToken(async_token);
1429 return p.parsePrimaryTypeExpr();
1430 }
1431 var res = try p.expectNode(parsePrimaryTypeExpr, .{
1432 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
1433 });
1434
1435 while (try p.parseSuffixOp()) |node| {
1393 switch (node.id) {1436 switch (node.id) {
1394 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },1437 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1395 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,1438 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1396 else => unreachable,1439 else => unreachable,
1397 }1440 }
1398 res = node;1441 res = node;
1399 continue;
1400 }1442 }
1401 if (try parseFnCallArguments(arena, it, tree)) |params| {1443
1402 const call = try arena.create(Node.SuffixOp);1444 const params = (try p.parseFnCallArguments()) orelse {
1403 call.* = .{1445 try p.errors.append(p.gpa, .{
1404 .lhs = .{ .node = res },1446 .ExpectedParamList = .{ .token = p.tok_i },
1405 .op = .{1447 });
1406 .Call = .{1448 // ignore this, continue parsing
1407 .params = params.list,1449 return res;
1408 .async_token = null,1450 };
1409 },1451 defer p.gpa.free(params.list);
1410 },1452 const node = try Node.Call.alloc(&p.arena.allocator, params.list.len);
1411 .rtoken = params.rparen,1453 node.* = .{
1412 };1454 .lhs = res,
1413 res = &call.base;1455 .params_len = params.list.len,
1414 continue;1456 .async_token = async_token,
1457 .rtoken = params.rparen,
1458 };
1459 std.mem.copy(*Node, node.params(), params.list);
1460 return &node.base;
1461 }
1462 if (try p.parsePrimaryTypeExpr()) |expr| {
1463 var res = expr;
1464
1465 while (true) {
1466 if (try p.parseSuffixOp()) |node| {
1467 switch (node.id) {
1468 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1469 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1470 else => unreachable,
1471 }
1472 res = node;
1473 continue;
1474 }
1475 if (try p.parseFnCallArguments()) |params| {
1476 defer p.gpa.free(params.list);
1477 const call = try Node.Call.alloc(&p.arena.allocator, params.list.len);
1478 call.* = .{
1479 .lhs = res,
1480 .params_len = params.list.len,
1481 .async_token = null,
1482 .rtoken = params.rparen,
1483 };
1484 std.mem.copy(*Node, call.params(), params.list);
1485 res = &call.base;
1486 continue;
1487 }
1488 break;
1415 }1489 }
1416 break;1490 return res;
1417 }1491 }
1418 return res;1492
1493 return null;
1419 }1494 }
14201495
1421 return null;1496 /// PrimaryTypeExpr
1422}1497 /// <- BUILTINIDENTIFIER FnCallArguments
1498 /// / CHAR_LITERAL
1499 /// / ContainerDecl
1500 /// / DOT IDENTIFIER
1501 /// / ErrorSetDecl
1502 /// / FLOAT
1503 /// / FnProto
1504 /// / GroupedExpr
1505 /// / LabeledTypeExpr
1506 /// / IDENTIFIER
1507 /// / IfTypeExpr
1508 /// / INTEGER
1509 /// / KEYWORD_comptime TypeExpr
1510 /// / KEYWORD_error DOT IDENTIFIER
1511 /// / KEYWORD_false
1512 /// / KEYWORD_null
1513 /// / KEYWORD_anyframe
1514 /// / KEYWORD_true
1515 /// / KEYWORD_undefined
1516 /// / KEYWORD_unreachable
1517 /// / STRINGLITERAL
1518 /// / SwitchExpr
1519 fn parsePrimaryTypeExpr(p: *Parser) !?*Node {
1520 if (try p.parseBuiltinCall()) |node| return node;
1521 if (p.eatToken(.CharLiteral)) |token| {
1522 const node = try p.arena.allocator.create(Node.CharLiteral);
1523 node.* = .{
1524 .token = token,
1525 };
1526 return &node.base;
1527 }
1528 if (try p.parseContainerDecl()) |node| return node;
1529 if (try p.parseAnonLiteral()) |node| return node;
1530 if (try p.parseErrorSetDecl()) |node| return node;
1531 if (try p.parseFloatLiteral()) |node| return node;
1532 if (try p.parseFnProto()) |node| return node;
1533 if (try p.parseGroupedExpr()) |node| return node;
1534 if (try p.parseLabeledTypeExpr()) |node| return node;
1535 if (try p.parseIdentifier()) |node| return node;
1536 if (try p.parseIfTypeExpr()) |node| return node;
1537 if (try p.parseIntegerLiteral()) |node| return node;
1538 if (p.eatToken(.Keyword_comptime)) |token| {
1539 const expr = (try p.parseTypeExpr()) orelse return null;
1540 const node = try p.arena.allocator.create(Node.Comptime);
1541 node.* = .{
1542 .doc_comments = null,
1543 .comptime_token = token,
1544 .expr = expr,
1545 };
1546 return &node.base;
1547 }
1548 if (p.eatToken(.Keyword_error)) |token| {
1549 const period = try p.expectTokenRecoverable(.Period);
1550 const identifier = try p.expectNodeRecoverable(parseIdentifier, .{
1551 .ExpectedIdentifier = .{ .token = p.tok_i },
1552 });
1553 const global_error_set = try p.createLiteral(Node.ErrorType, token);
1554 if (period == null or identifier == null) return global_error_set;
14231555
1424/// PrimaryTypeExpr1556 const node = try p.arena.allocator.create(Node.InfixOp);
1425/// <- BUILTINIDENTIFIER FnCallArguments1557 node.* = .{
1426/// / CHAR_LITERAL1558 .op_token = period.?,
1427/// / ContainerDecl1559 .lhs = global_error_set,
1428/// / DOT IDENTIFIER1560 .op = .Period,
1429/// / ErrorSetDecl1561 .rhs = identifier.?,
1430/// / FLOAT1562 };
1431/// / FnProto1563 return &node.base;
1432/// / GroupedExpr1564 }
1433/// / LabeledTypeExpr1565 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token);
1434/// / IDENTIFIER1566 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token);
1435/// / IfTypeExpr1567 if (p.eatToken(.Keyword_anyframe)) |token| {
1436/// / INTEGER1568 const node = try p.arena.allocator.create(Node.AnyFrameType);
1437/// / KEYWORD_comptime TypeExpr1569 node.* = .{
1438/// / KEYWORD_error DOT IDENTIFIER1570 .anyframe_token = token,
1439/// / KEYWORD_false1571 .result = null,
1440/// / KEYWORD_null1572 };
1441/// / KEYWORD_anyframe1573 return &node.base;
1442/// / KEYWORD_true1574 }
1443/// / KEYWORD_undefined1575 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token);
1444/// / KEYWORD_unreachable1576 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token);
1445/// / STRINGLITERAL1577 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token);
1446/// / SwitchExpr1578 if (try p.parseStringLiteral()) |node| return node;
1447fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1579 if (try p.parseSwitchExpr()) |node| return node;
1448 if (try parseBuiltinCall(arena, it, tree)) |node| return node;1580
1449 if (eatToken(it, .CharLiteral)) |token| {1581 return null;
1450 const node = try arena.create(Node.CharLiteral);1582 }
1451 node.* = .{1583
1452 .token = token,1584 /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
1585 fn parseContainerDecl(p: *Parser) !?*Node {
1586 const layout_token = p.eatToken(.Keyword_extern) orelse
1587 p.eatToken(.Keyword_packed);
1588
1589 const node = (try p.parseContainerDeclAuto()) orelse {
1590 if (layout_token) |token|
1591 p.putBackToken(token);
1592 return null;
1453 };1593 };
1454 return &node.base;1594 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
1595 return node;
1455 }1596 }
1456 if (try parseContainerDecl(arena, it, tree)) |node| return node;1597
1457 if (try parseAnonLiteral(arena, it, tree)) |node| return node;1598 /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1458 if (try parseErrorSetDecl(arena, it, tree)) |node| return node;1599 fn parseErrorSetDecl(p: *Parser) !?*Node {
1459 if (try parseFloatLiteral(arena, it, tree)) |node| return node;1600 const error_token = p.eatToken(.Keyword_error) orelse return null;
1460 if (try parseFnProto(arena, it, tree)) |node| return node;1601 if (p.eatToken(.LBrace) == null) {
1461 if (try parseGroupedExpr(arena, it, tree)) |node| return node;1602 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1462 if (try parseLabeledTypeExpr(arena, it, tree)) |node| return node;1603 p.putBackToken(error_token);
1463 if (try parseIdentifier(arena, it, tree)) |node| return node;1604 return null;
1464 if (try parseIfTypeExpr(arena, it, tree)) |node| return node;1605 }
1465 if (try parseIntegerLiteral(arena, it, tree)) |node| return node;1606 const decls = try p.parseErrorTagList();
1466 if (eatToken(it, .Keyword_comptime)) |token| {1607 defer p.gpa.free(decls);
1467 const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;1608 const rbrace = try p.expectToken(.RBrace);
1468 const node = try arena.create(Node.Comptime);1609
1610 const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len);
1469 node.* = .{1611 node.* = .{
1470 .doc_comments = null,1612 .error_token = error_token,
1471 .comptime_token = token,1613 .decls_len = decls.len,
1472 .expr = expr,1614 .rbrace_token = rbrace,
1473 };1615 };
1616 std.mem.copy(*Node, node.decls(), decls);
1474 return &node.base;1617 return &node.base;
1475 }1618 }
1476 if (eatToken(it, .Keyword_error)) |token| {1619
1477 const period = try expectTokenRecoverable(it, tree, .Period);1620 /// GroupedExpr <- LPAREN Expr RPAREN
1478 const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{1621 fn parseGroupedExpr(p: *Parser) !?*Node {
1479 .ExpectedIdentifier = .{ .token = it.index },1622 const lparen = p.eatToken(.LParen) orelse return null;
1623 const expr = try p.expectNode(parseExpr, .{
1624 .ExpectedExpr = .{ .token = p.tok_i },
1480 });1625 });
1481 const global_error_set = try createLiteral(arena, Node.ErrorType, token);1626 const rparen = try p.expectToken(.RParen);
1482 if (period == null or identifier == null) return global_error_set;
14831627
1484 const node = try arena.create(Node.InfixOp);1628 const node = try p.arena.allocator.create(Node.GroupedExpression);
1485 node.* = .{1629 node.* = .{
1486 .op_token = period.?,1630 .lparen = lparen,
1487 .lhs = global_error_set,1631 .expr = expr,
1488 .op = .Period,1632 .rparen = rparen,
1489 .rhs = identifier.?,
1490 };1633 };
1491 return &node.base;1634 return &node.base;
1492 }1635 }
1493 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);1636
1494 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);1637 /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1495 if (eatToken(it, .Keyword_anyframe)) |token| {1638 fn parseIfTypeExpr(p: *Parser) !?*Node {
1496 const node = try arena.create(Node.AnyFrameType);1639 return p.parseIf(parseTypeExpr);
1497 node.* = .{
1498 .anyframe_token = token,
1499 .result = null,
1500 };
1501 return &node.base;
1502 }1640 }
1503 if (eatToken(it, .Keyword_true)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1504 if (eatToken(it, .Keyword_undefined)) |token| return createLiteral(arena, Node.UndefinedLiteral, token);
1505 if (eatToken(it, .Keyword_unreachable)) |token| return createLiteral(arena, Node.Unreachable, token);
1506 if (try parseStringLiteral(arena, it, tree)) |node| return node;
1507 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
15081641
1509 return null;1642 /// LabeledTypeExpr
1510}1643 /// <- BlockLabel Block
1644 /// / BlockLabel? LoopTypeExpr
1645 fn parseLabeledTypeExpr(p: *Parser) !?*Node {
1646 var colon: TokenIndex = undefined;
1647 const label = p.parseBlockLabel(&colon);
15111648
1512/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto1649 if (label) |token| {
1513fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1650 if (try p.parseBlock()) |node| {
1514 const layout_token = eatToken(it, .Keyword_extern) orelse1651 node.cast(Node.Block).?.label = token;
1515 eatToken(it, .Keyword_packed);1652 return node;
1653 }
1654 }
15161655
1517 const node = (try parseContainerDeclAuto(arena, it, tree)) orelse {1656 if (try p.parseLoopTypeExpr()) |node| {
1518 if (layout_token) |token|1657 switch (node.id) {
1519 putBackToken(it, token);1658 .For => node.cast(Node.For).?.label = label,
1520 return null;1659 .While => node.cast(Node.While).?.label = label,
1521 };1660 else => unreachable,
1522 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;1661 }
1523 return node;1662 return node;
1524}1663 }
15251664
1526/// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE1665 if (label) |token| {
1527fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1666 p.putBackToken(colon);
1528 const error_token = eatToken(it, .Keyword_error) orelse return null;1667 p.putBackToken(token);
1529 if (eatToken(it, .LBrace) == null) {1668 }
1530 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1531 putBackToken(it, error_token);
1532 return null;1669 return null;
1533 }1670 }
1534 const decls = try parseErrorTagList(arena, it, tree);
1535 const rbrace = try expectToken(it, tree, .RBrace);
1536
1537 const node = try arena.create(Node.ErrorSetDecl);
1538 node.* = .{
1539 .error_token = error_token,
1540 .decls = decls,
1541 .rbrace_token = rbrace,
1542 };
1543 return &node.base;
1544}
15451671
1546/// GroupedExpr <- LPAREN Expr RPAREN1672 /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1547fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1673 fn parseLoopTypeExpr(p: *Parser) !?*Node {
1548 const lparen = eatToken(it, .LParen) orelse return null;1674 const inline_token = p.eatToken(.Keyword_inline);
1549 const expr = try expectNode(arena, it, tree, parseExpr, .{
1550 .ExpectedExpr = .{ .token = it.index },
1551 });
1552 const rparen = try expectToken(it, tree, .RParen);
1553
1554 const node = try arena.create(Node.GroupedExpression);
1555 node.* = .{
1556 .lparen = lparen,
1557 .expr = expr,
1558 .rparen = rparen,
1559 };
1560 return &node.base;
1561}
1562
1563/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1564fn parseIfTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1565 return parseIf(arena, it, tree, parseTypeExpr);
1566}
15671675
1568/// LabeledTypeExpr1676 if (try p.parseForTypeExpr()) |node| {
1569/// <- BlockLabel Block1677 node.cast(Node.For).?.inline_token = inline_token;
1570/// / BlockLabel? LoopTypeExpr
1571fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1572 var colon: TokenIndex = undefined;
1573 const label = parseBlockLabel(arena, it, tree, &colon);
1574
1575 if (label) |token| {
1576 if (try parseBlock(arena, it, tree)) |node| {
1577 node.cast(Node.Block).?.label = token;
1578 return node;1678 return node;
1579 }1679 }
1580 }
15811680
1582 if (try parseLoopTypeExpr(arena, it, tree)) |node| {1681 if (try p.parseWhileTypeExpr()) |node| {
1583 switch (node.id) {1682 node.cast(Node.While).?.inline_token = inline_token;
1584 .For => node.cast(Node.For).?.label = label,1683 return node;
1585 .While => node.cast(Node.While).?.label = label,
1586 else => unreachable,
1587 }1684 }
1588 return node;
1589 }
15901685
1591 if (label) |token| {1686 if (inline_token == null) return null;
1592 putBackToken(it, colon);1687
1593 putBackToken(it, token);1688 // If we've seen "inline", there should have been a "for" or "while"
1689 try p.errors.append(p.gpa, .{
1690 .ExpectedInlinable = .{ .token = p.tok_i },
1691 });
1692 return error.ParseError;
1594 }1693 }
1595 return null;
1596}
15971694
1598/// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)1695 /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
1599fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1696 fn parseForTypeExpr(p: *Parser) !?*Node {
1600 const inline_token = eatToken(it, .Keyword_inline);1697 const node = (try p.parseForPrefix()) orelse return null;
1698 const for_prefix = node.cast(Node.For).?;
16011699
1602 if (try parseForTypeExpr(arena, it, tree)) |node| {1700 const type_expr = try p.expectNode(parseTypeExpr, .{
1603 node.cast(Node.For).?.inline_token = inline_token;1701 .ExpectedTypeExpr = .{ .token = p.tok_i },
1604 return node;1702 });
1605 }1703 for_prefix.body = type_expr;
16061704
1607 if (try parseWhileTypeExpr(arena, it, tree)) |node| {1705 if (p.eatToken(.Keyword_else)) |else_token| {
1608 node.cast(Node.While).?.inline_token = inline_token;1706 const else_expr = try p.expectNode(parseTypeExpr, .{
1609 return node;1707 .ExpectedTypeExpr = .{ .token = p.tok_i },
1610 }1708 });
16111709
1612 if (inline_token == null) return null;1710 const else_node = try p.arena.allocator.create(Node.Else);
1711 else_node.* = .{
1712 .else_token = else_token,
1713 .payload = null,
1714 .body = else_expr,
1715 };
16131716
1614 // If we've seen "inline", there should have been a "for" or "while"1717 for_prefix.@"else" = else_node;
1615 try tree.errors.push(.{1718 }
1616 .ExpectedInlinable = .{ .token = it.index },
1617 });
1618 return error.ParseError;
1619}
16201719
1621/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?1720 return node;
1622fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1721 }
1623 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1624 const for_prefix = node.cast(Node.For).?;
16251722
1626 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1723 /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1627 .ExpectedTypeExpr = .{ .token = it.index },1724 fn parseWhileTypeExpr(p: *Parser) !?*Node {
1628 });1725 const node = (try p.parseWhilePrefix()) orelse return null;
1629 for_prefix.body = type_expr;1726 const while_prefix = node.cast(Node.While).?;
16301727
1631 if (eatToken(it, .Keyword_else)) |else_token| {1728 const type_expr = try p.expectNode(parseTypeExpr, .{
1632 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1729 .ExpectedTypeExpr = .{ .token = p.tok_i },
1633 .ExpectedTypeExpr = .{ .token = it.index },
1634 });1730 });
1731 while_prefix.body = type_expr;
16351732
1636 const else_node = try arena.create(Node.Else);1733 if (p.eatToken(.Keyword_else)) |else_token| {
1637 else_node.* = .{1734 const payload = try p.parsePayload();
1638 .else_token = else_token,
1639 .payload = null,
1640 .body = else_expr,
1641 };
1642
1643 for_prefix.@"else" = else_node;
1644 }
16451735
1646 return node;1736 const else_expr = try p.expectNode(parseTypeExpr, .{
1647}1737 .ExpectedTypeExpr = .{ .token = p.tok_i },
1738 });
16481739
1649/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?1740 const else_node = try p.arena.allocator.create(Node.Else);
1650fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1741 else_node.* = .{
1651 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;1742 .else_token = else_token,
1652 const while_prefix = node.cast(Node.While).?;1743 .payload = null,
1744 .body = else_expr,
1745 };
16531746
1654 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1747 while_prefix.@"else" = else_node;
1655 .ExpectedTypeExpr = .{ .token = it.index },1748 }
1656 });
1657 while_prefix.body = type_expr;
16581749
1659 if (eatToken(it, .Keyword_else)) |else_token| {1750 return node;
1660 const payload = try parsePayload(arena, it, tree);1751 }
16611752
1662 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1753 /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
1663 .ExpectedTypeExpr = .{ .token = it.index },1754 fn parseSwitchExpr(p: *Parser) !?*Node {
1755 const switch_token = p.eatToken(.Keyword_switch) orelse return null;
1756 _ = try p.expectToken(.LParen);
1757 const expr_node = try p.expectNode(parseExpr, .{
1758 .ExpectedExpr = .{ .token = p.tok_i },
1664 });1759 });
1760 _ = try p.expectToken(.RParen);
1761 _ = try p.expectToken(.LBrace);
1762 const cases = try p.parseSwitchProngList();
1763 defer p.gpa.free(cases);
1764 const rbrace = try p.expectToken(.RBrace);
16651765
1666 const else_node = try arena.create(Node.Else);1766 const node = try Node.Switch.alloc(&p.arena.allocator, cases.len);
1667 else_node.* = .{1767 node.* = .{
1668 .else_token = else_token,1768 .switch_token = switch_token,
1669 .payload = null,1769 .expr = expr_node,
1670 .body = else_expr,1770 .cases_len = cases.len,
1771 .rbrace = rbrace,
1671 };1772 };
16721773 std.mem.copy(*Node, node.cases(), cases);
1673 while_prefix.@"else" = else_node;1774 return &node.base;
1674 }1775 }
16751776
1676 return node;1777 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1677}1778 /// AsmOutput <- COLON AsmOutputList AsmInput?
1779 /// AsmInput <- COLON AsmInputList AsmClobbers?
1780 /// AsmClobbers <- COLON StringList
1781 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
1782 fn parseAsmExpr(p: *Parser) !?*Node {
1783 const asm_token = p.eatToken(.Keyword_asm) orelse return null;
1784 const volatile_token = p.eatToken(.Keyword_volatile);
1785 _ = try p.expectToken(.LParen);
1786 const template = try p.expectNode(parseExpr, .{
1787 .ExpectedExpr = .{ .token = p.tok_i },
1788 });
16781789
1679/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE1790 var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{};
1680fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1791 var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{};
1681 const switch_token = eatToken(it, .Keyword_switch) orelse return null;1792 var arena_clobbers: []*Node = &[0]*Node{};
1682 _ = try expectToken(it, tree, .LParen);
1683 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1684 .ExpectedExpr = .{ .token = it.index },
1685 });
1686 _ = try expectToken(it, tree, .RParen);
1687 _ = try expectToken(it, tree, .LBrace);
1688 const cases = try parseSwitchProngList(arena, it, tree);
1689 const rbrace = try expectToken(it, tree, .RBrace);
1690
1691 const node = try arena.create(Node.Switch);
1692 node.* = .{
1693 .switch_token = switch_token,
1694 .expr = expr_node,
1695 .cases = cases,
1696 .rbrace = rbrace,
1697 };
1698 return &node.base;
1699}
17001793
1701/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN1794 if (p.eatToken(.Colon) != null) {
1702fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1795 const outputs = try p.parseAsmOutputList();
1703 const asm_token = eatToken(it, .Keyword_asm) orelse return null;1796 defer p.gpa.free(outputs);
1704 const volatile_token = eatToken(it, .Keyword_volatile);1797 arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs);
1705 _ = try expectToken(it, tree, .LParen);
1706 const template = try expectNode(arena, it, tree, parseExpr, .{
1707 .ExpectedExpr = .{ .token = it.index },
1708 });
1709
1710 const node = try arena.create(Node.Asm);
1711 node.* = .{
1712 .asm_token = asm_token,
1713 .volatile_token = volatile_token,
1714 .template = template,
1715 .outputs = Node.Asm.OutputList.init(arena),
1716 .inputs = Node.Asm.InputList.init(arena),
1717 .clobbers = Node.Asm.ClobberList.init(arena),
1718 .rparen = undefined,
1719 };
17201798
1721 try parseAsmOutput(arena, it, tree, node);1799 if (p.eatToken(.Colon) != null) {
1722 node.rparen = try expectToken(it, tree, .RParen);1800 const inputs = try p.parseAsmInputList();
1723 return &node.base;1801 defer p.gpa.free(inputs);
1724}1802 arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs);
17251803
1726/// DOT IDENTIFIER1804 if (p.eatToken(.Colon) != null) {
1727fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1805 const clobbers = try ListParseFn(*Node, parseStringLiteral)(p);
1728 const dot = eatToken(it, .Period) orelse return null;1806 defer p.gpa.free(clobbers);
1807 arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers);
1808 }
1809 }
1810 }
17291811
1730 // anon enum literal1812 const node = try p.arena.allocator.create(Node.Asm);
1731 if (eatToken(it, .Identifier)) |name| {
1732 const node = try arena.create(Node.EnumLiteral);
1733 node.* = .{1813 node.* = .{
1734 .dot = dot,1814 .asm_token = asm_token,
1735 .name = name,1815 .volatile_token = volatile_token,
1816 .template = template,
1817 .outputs = arena_outputs,
1818 .inputs = arena_inputs,
1819 .clobbers = arena_clobbers,
1820 .rparen = try p.expectToken(.RParen),
1736 };1821 };
1737 return &node.base;
1738 }
17391822
1740 // anon container literal
1741 if (try parseInitList(arena, it, tree)) |node| {
1742 node.lhs = .{ .dot = dot };
1743 return &node.base;1823 return &node.base;
1744 }1824 }
17451825
1746 putBackToken(it, dot);1826 /// DOT IDENTIFIER
1747 return null;1827 fn parseAnonLiteral(p: *Parser) !?*Node {
1748}1828 const dot = p.eatToken(.Period) orelse return null;
1749
1750/// AsmOutput <- COLON AsmOutputList AsmInput?
1751fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1752 if (eatToken(it, .Colon) == null) return;
1753 asm_node.outputs = try parseAsmOutputList(arena, it, tree);
1754 try parseAsmInput(arena, it, tree, asm_node);
1755}
17561829
1757/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN1830 // anon enum literal
1758fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput {1831 if (p.eatToken(.Identifier)) |name| {
1759 const lbracket = eatToken(it, .LBracket) orelse return null;1832 const node = try p.arena.allocator.create(Node.EnumLiteral);
1760 const name = try expectNode(arena, it, tree, parseIdentifier, .{1833 node.* = .{
1761 .ExpectedIdentifier = .{ .token = it.index },1834 .dot = dot,
1762 });1835 .name = name,
1763 _ = try expectToken(it, tree, .RBracket);1836 };
17641837 return &node.base;
1765 const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{
1766 .ExpectedStringLiteral = .{ .token = it.index },
1767 });
1768
1769 _ = try expectToken(it, tree, .LParen);
1770 const kind: Node.AsmOutput.Kind = blk: {
1771 if (eatToken(it, .Arrow) != null) {
1772 const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{
1773 .ExpectedTypeExpr = .{ .token = it.index },
1774 });
1775 break :blk .{ .Return = return_ident };
1776 }1838 }
1777 const variable = try expectNode(arena, it, tree, parseIdentifier, .{
1778 .ExpectedIdentifier = .{ .token = it.index },
1779 });
1780 break :blk .{ .Variable = variable.cast(Node.Identifier).? };
1781 };
1782 const rparen = try expectToken(it, tree, .RParen);
1783
1784 const node = try arena.create(Node.AsmOutput);
1785 node.* = .{
1786 .lbracket = lbracket,
1787 .symbolic_name = name,
1788 .constraint = constraint,
1789 .kind = kind,
1790 .rparen = rparen,
1791 };
1792 return node;
1793}
17941839
1795/// AsmInput <- COLON AsmInputList AsmClobbers?1840 if (try p.parseAnonInitList(dot)) |node| {
1796fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {1841 return node;
1797 if (eatToken(it, .Colon) == null) return;1842 }
1798 asm_node.inputs = try parseAsmInputList(arena, it, tree);
1799 try parseAsmClobbers(arena, it, tree, asm_node);
1800}
18011843
1802/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN1844 p.putBackToken(dot);
1803fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {1845 return null;
1804 const lbracket = eatToken(it, .LBracket) orelse return null;1846 }
1805 const name = try expectNode(arena, it, tree, parseIdentifier, .{
1806 .ExpectedIdentifier = .{ .token = it.index },
1807 });
1808 _ = try expectToken(it, tree, .RBracket);
1809
1810 const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{
1811 .ExpectedStringLiteral = .{ .token = it.index },
1812 });
1813
1814 _ = try expectToken(it, tree, .LParen);
1815 const expr = try expectNode(arena, it, tree, parseExpr, .{
1816 .ExpectedExpr = .{ .token = it.index },
1817 });
1818 const rparen = try expectToken(it, tree, .RParen);
1819
1820 const node = try arena.create(Node.AsmInput);
1821 node.* = .{
1822 .lbracket = lbracket,
1823 .symbolic_name = name,
1824 .constraint = constraint,
1825 .expr = expr,
1826 .rparen = rparen,
1827 };
1828 return node;
1829}
18301847
1831/// AsmClobbers <- COLON StringList1848 /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1832/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?1849 fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output {
1833fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {1850 const lbracket = p.eatToken(.LBracket) orelse return null;
1834 if (eatToken(it, .Colon) == null) return;1851 const name = try p.expectNode(parseIdentifier, .{
1835 asm_node.clobbers = try ListParseFn(1852 .ExpectedIdentifier = .{ .token = p.tok_i },
1836 Node.Asm.ClobberList,1853 });
1837 parseStringLiteral,1854 _ = try p.expectToken(.RBracket);
1838 )(arena, it, tree);
1839}
18401855
1841/// BreakLabel <- COLON IDENTIFIER1856 const constraint = try p.expectNode(parseStringLiteral, .{
1842fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1857 .ExpectedStringLiteral = .{ .token = p.tok_i },
1843 _ = eatToken(it, .Colon) orelse return null;1858 });
1844 return try expectNode(arena, it, tree, parseIdentifier, .{
1845 .ExpectedIdentifier = .{ .token = it.index },
1846 });
1847}
18481859
1849/// BlockLabel <- IDENTIFIER COLON1860 _ = try p.expectToken(.LParen);
1850fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree, colon_token: *TokenIndex) ?TokenIndex {1861 const kind: Node.Asm.Output.Kind = blk: {
1851 const identifier = eatToken(it, .Identifier) orelse return null;1862 if (p.eatToken(.Arrow) != null) {
1852 if (eatToken(it, .Colon)) |colon| {1863 const return_ident = try p.expectNode(parseTypeExpr, .{
1853 colon_token.* = colon;1864 .ExpectedTypeExpr = .{ .token = p.tok_i },
1854 return identifier;1865 });
1866 break :blk .{ .Return = return_ident };
1867 }
1868 const variable = try p.expectNode(parseIdentifier, .{
1869 .ExpectedIdentifier = .{ .token = p.tok_i },
1870 });
1871 break :blk .{ .Variable = variable.cast(Node.Identifier).? };
1872 };
1873 const rparen = try p.expectToken(.RParen);
1874
1875 return Node.Asm.Output{
1876 .lbracket = lbracket,
1877 .symbolic_name = name,
1878 .constraint = constraint,
1879 .kind = kind,
1880 .rparen = rparen,
1881 };
1855 }1882 }
1856 putBackToken(it, identifier);
1857 return null;
1858}
18591883
1860/// FieldInit <- DOT IDENTIFIER EQUAL Expr1884 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1861fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1885 fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
1862 const period_token = eatToken(it, .Period) orelse return null;1886 const lbracket = p.eatToken(.LBracket) orelse return null;
1863 const name_token = eatToken(it, .Identifier) orelse {1887 const name = try p.expectNode(parseIdentifier, .{
1864 // Because of anon literals `.{` is also valid.1888 .ExpectedIdentifier = .{ .token = p.tok_i },
1865 putBackToken(it, period_token);1889 });
1866 return null;1890 _ = try p.expectToken(.RBracket);
1867 };
1868 const eq_token = eatToken(it, .Equal) orelse {
1869 // `.Name` may also be an enum literal, which is a later rule.
1870 putBackToken(it, name_token);
1871 putBackToken(it, period_token);
1872 return null;
1873 };
1874 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1875 .ExpectedExpr = .{ .token = it.index },
1876 });
1877
1878 const node = try arena.create(Node.FieldInitializer);
1879 node.* = .{
1880 .period_token = period_token,
1881 .name_token = name_token,
1882 .expr = expr_node,
1883 };
1884 return &node.base;
1885}
18861891
1887/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN1892 const constraint = try p.expectNode(parseStringLiteral, .{
1888fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1893 .ExpectedStringLiteral = .{ .token = p.tok_i },
1889 _ = eatToken(it, .Colon) orelse return null;1894 });
1890 _ = try expectToken(it, tree, .LParen);
1891 const node = try expectNode(arena, it, tree, parseAssignExpr, .{
1892 .ExpectedExprOrAssignment = .{ .token = it.index },
1893 });
1894 _ = try expectToken(it, tree, .RParen);
1895 return node;
1896}
18971895
1898/// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN1896 _ = try p.expectToken(.LParen);
1899fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1897 const expr = try p.expectNode(parseExpr, .{
1900 _ = eatToken(it, .Keyword_linksection) orelse return null;1898 .ExpectedExpr = .{ .token = p.tok_i },
1901 _ = try expectToken(it, tree, .LParen);1899 });
1902 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1900 const rparen = try p.expectToken(.RParen);
1903 .ExpectedExpr = .{ .token = it.index },
1904 });
1905 _ = try expectToken(it, tree, .RParen);
1906 return expr_node;
1907}
19081901
1909/// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN1902 return Node.Asm.Input{
1910fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1903 .lbracket = lbracket,
1911 _ = eatToken(it, .Keyword_callconv) orelse return null;1904 .symbolic_name = name,
1912 _ = try expectToken(it, tree, .LParen);1905 .constraint = constraint,
1913 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1906 .expr = expr,
1914 .ExpectedExpr = .{ .token = it.index },1907 .rparen = rparen,
1915 });1908 };
1916 _ = try expectToken(it, tree, .RParen);1909 }
1917 return expr_node;
1918}
19191910
1920/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType1911 /// BreakLabel <- COLON IDENTIFIER
1921fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1912 fn parseBreakLabel(p: *Parser) !?*Node {
1922 const doc_comments = try parseDocComment(arena, it, tree);1913 _ = p.eatToken(.Colon) orelse return null;
1923 const noalias_token = eatToken(it, .Keyword_noalias);1914 return p.expectNode(parseIdentifier, .{
1924 const comptime_token = if (noalias_token == null) eatToken(it, .Keyword_comptime) else null;1915 .ExpectedIdentifier = .{ .token = p.tok_i },
1925 const name_token = blk: {
1926 const identifier = eatToken(it, .Identifier) orelse break :blk null;
1927 if (eatToken(it, .Colon) != null) break :blk identifier;
1928 putBackToken(it, identifier); // ParamType may also be an identifier
1929 break :blk null;
1930 };
1931 const param_type = (try parseParamType(arena, it, tree)) orelse {
1932 // Only return cleanly if no keyword, identifier, or doc comment was found
1933 if (noalias_token == null and
1934 comptime_token == null and
1935 name_token == null and
1936 doc_comments == null) return null;
1937 try tree.errors.push(.{
1938 .ExpectedParamType = .{ .token = it.index },
1939 });1916 });
1940 return error.ParseError;1917 }
1941 };
1942
1943 const param_decl = try arena.create(Node.ParamDecl);
1944 param_decl.* = .{
1945 .doc_comments = doc_comments,
1946 .comptime_token = comptime_token,
1947 .noalias_token = noalias_token,
1948 .name_token = name_token,
1949 .param_type = param_type,
1950 };
1951 return &param_decl.base;
1952}
19531918
1954/// ParamType1919 /// BlockLabel <- IDENTIFIER COLON
1955/// <- KEYWORD_var1920 fn parseBlockLabel(p: *Parser, colon_token: *TokenIndex) ?TokenIndex {
1956/// / DOT31921 const identifier = p.eatToken(.Identifier) orelse return null;
1957/// / TypeExpr1922 if (p.eatToken(.Colon)) |colon| {
1958fn parseParamType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?Node.ParamDecl.ParamType {1923 colon_token.* = colon;
1959 // TODO cast from tuple to error union is broken1924 return identifier;
1960 const P = Node.ParamDecl.ParamType;1925 }
1961 if (try parseVarType(arena, it, tree)) |node| return P{ .var_type = node };1926 p.putBackToken(identifier);
1962 if (eatToken(it, .Ellipsis3)) |token| return P{ .var_args = token };1927 return null;
1963 if (try parseTypeExpr(arena, it, tree)) |node| return P{ .type_expr = node };1928 }
1964 return null;
1965}
19661929
1967/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?1930 /// FieldInit <- DOT IDENTIFIER EQUAL Expr
1968fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1931 fn parseFieldInit(p: *Parser) !?*Node {
1969 const if_token = eatToken(it, .Keyword_if) orelse return null;1932 const period_token = p.eatToken(.Period) orelse return null;
1970 _ = try expectToken(it, tree, .LParen);1933 const name_token = p.eatToken(.Identifier) orelse {
1971 const condition = try expectNode(arena, it, tree, parseExpr, .{1934 // Because of anon literals `.{` is also valid.
1972 .ExpectedExpr = .{ .token = it.index },1935 p.putBackToken(period_token);
1973 });1936 return null;
1974 _ = try expectToken(it, tree, .RParen);1937 };
1975 const payload = try parsePtrPayload(arena, it, tree);1938 const eq_token = p.eatToken(.Equal) orelse {
19761939 // `.Name` may also be an enum literal, which is a later rule.
1977 const node = try arena.create(Node.If);1940 p.putBackToken(name_token);
1978 node.* = .{1941 p.putBackToken(period_token);
1979 .if_token = if_token,1942 return null;
1980 .condition = condition,1943 };
1981 .payload = payload,1944 const expr_node = try p.expectNode(parseExpr, .{
1982 .body = undefined, // set by caller1945 .ExpectedExpr = .{ .token = p.tok_i },
1983 .@"else" = null,1946 });
1984 };
1985 return &node.base;
1986}
19871947
1988/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?1948 const node = try p.arena.allocator.create(Node.FieldInitializer);
1989fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1949 node.* = .{
1990 const while_token = eatToken(it, .Keyword_while) orelse return null;1950 .period_token = period_token,
19911951 .name_token = name_token,
1992 _ = try expectToken(it, tree, .LParen);1952 .expr = expr_node,
1993 const condition = try expectNode(arena, it, tree, parseExpr, .{1953 };
1994 .ExpectedExpr = .{ .token = it.index },1954 return &node.base;
1995 });1955 }
1996 _ = try expectToken(it, tree, .RParen);
1997
1998 const payload = try parsePtrPayload(arena, it, tree);
1999 const continue_expr = try parseWhileContinueExpr(arena, it, tree);
2000
2001 const node = try arena.create(Node.While);
2002 node.* = .{
2003 .label = null,
2004 .inline_token = null,
2005 .while_token = while_token,
2006 .condition = condition,
2007 .payload = payload,
2008 .continue_expr = continue_expr,
2009 .body = undefined, // set by caller
2010 .@"else" = null,
2011 };
2012 return &node.base;
2013}
20141956
2015/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload1957 /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
2016fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1958 fn parseWhileContinueExpr(p: *Parser) !?*Node {
2017 const for_token = eatToken(it, .Keyword_for) orelse return null;1959 _ = p.eatToken(.Colon) orelse return null;
20181960 _ = try p.expectToken(.LParen);
2019 _ = try expectToken(it, tree, .LParen);1961 const node = try p.expectNode(parseAssignExpr, .{
2020 const array_expr = try expectNode(arena, it, tree, parseExpr, .{1962 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
2021 .ExpectedExpr = .{ .token = it.index },1963 });
2022 });1964 _ = try p.expectToken(.RParen);
2023 _ = try expectToken(it, tree, .RParen);1965 return node;
20241966 }
2025 const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{
2026 .ExpectedPayload = .{ .token = it.index },
2027 });
2028
2029 const node = try arena.create(Node.For);
2030 node.* = .{
2031 .label = null,
2032 .inline_token = null,
2033 .for_token = for_token,
2034 .array_expr = array_expr,
2035 .payload = payload,
2036 .body = undefined, // set by caller
2037 .@"else" = null,
2038 };
2039 return &node.base;
2040}
20411967
2042/// Payload <- PIPE IDENTIFIER PIPE1968 /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
2043fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1969 fn parseLinkSection(p: *Parser) !?*Node {
2044 const lpipe = eatToken(it, .Pipe) orelse return null;1970 _ = p.eatToken(.Keyword_linksection) orelse return null;
2045 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{1971 _ = try p.expectToken(.LParen);
2046 .ExpectedIdentifier = .{ .token = it.index },1972 const expr_node = try p.expectNode(parseExpr, .{
2047 });1973 .ExpectedExpr = .{ .token = p.tok_i },
2048 const rpipe = try expectToken(it, tree, .Pipe);1974 });
20491975 _ = try p.expectToken(.RParen);
2050 const node = try arena.create(Node.Payload);1976 return expr_node;
2051 node.* = .{1977 }
2052 .lpipe = lpipe,
2053 .error_symbol = identifier,
2054 .rpipe = rpipe,
2055 };
2056 return &node.base;
2057}
20581978
2059/// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE1979 /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
2060fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1980 fn parseCallconv(p: *Parser) !?*Node {
2061 const lpipe = eatToken(it, .Pipe) orelse return null;1981 _ = p.eatToken(.Keyword_callconv) orelse return null;
2062 const asterisk = eatToken(it, .Asterisk);1982 _ = try p.expectToken(.LParen);
2063 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{1983 const expr_node = try p.expectNode(parseExpr, .{
2064 .ExpectedIdentifier = .{ .token = it.index },1984 .ExpectedExpr = .{ .token = p.tok_i },
2065 });1985 });
2066 const rpipe = try expectToken(it, tree, .Pipe);1986 _ = try p.expectToken(.RParen);
20671987 return expr_node;
2068 const node = try arena.create(Node.PointerPayload);1988 }
2069 node.* = .{1989
2070 .lpipe = lpipe,1990 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
2071 .ptr_token = asterisk,1991 fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl {
2072 .value_symbol = identifier,1992 const doc_comments = try p.parseDocComment();
2073 .rpipe = rpipe,1993 const noalias_token = p.eatToken(.Keyword_noalias);
2074 };1994 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
2075 return &node.base;1995 const name_token = blk: {
2076}1996 const identifier = p.eatToken(.Identifier) orelse break :blk null;
1997 if (p.eatToken(.Colon) != null) break :blk identifier;
1998 p.putBackToken(identifier); // ParamType may also be an identifier
1999 break :blk null;
2000 };
2001 const param_type = (try p.parseParamType()) orelse {
2002 // Only return cleanly if no keyword, identifier, or doc comment was found
2003 if (noalias_token == null and
2004 comptime_token == null and
2005 name_token == null and
2006 doc_comments == null)
2007 {
2008 return null;
2009 }
2010 try p.errors.append(p.gpa, .{
2011 .ExpectedParamType = .{ .token = p.tok_i },
2012 });
2013 return error.ParseError;
2014 };
20772015
2078/// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE2016 return Node.FnProto.ParamDecl{
2079fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2017 .doc_comments = doc_comments,
2080 const lpipe = eatToken(it, .Pipe) orelse return null;2018 .comptime_token = comptime_token,
2081 const asterisk = eatToken(it, .Asterisk);2019 .noalias_token = noalias_token,
2082 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{2020 .name_token = name_token,
2083 .ExpectedIdentifier = .{ .token = it.index },2021 .param_type = param_type,
2084 });2022 };
20852023 }
2086 const index = if (eatToken(it, .Comma) == null)2024
2087 null2025 /// ParamType
2088 else2026 /// <- KEYWORD_var
2089 try expectNode(arena, it, tree, parseIdentifier, .{2027 /// / DOT3
2090 .ExpectedIdentifier = .{ .token = it.index },2028 /// / TypeExpr
2029 fn parseParamType(p: *Parser) !?Node.FnProto.ParamDecl.ParamType {
2030 // TODO cast from tuple to error union is broken
2031 const P = Node.FnProto.ParamDecl.ParamType;
2032 if (try p.parseVarType()) |node| return P{ .var_type = node };
2033 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
2034 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
2035 return null;
2036 }
2037
2038 /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
2039 fn parseIfPrefix(p: *Parser) !?*Node {
2040 const if_token = p.eatToken(.Keyword_if) orelse return null;
2041 _ = try p.expectToken(.LParen);
2042 const condition = try p.expectNode(parseExpr, .{
2043 .ExpectedExpr = .{ .token = p.tok_i },
2091 });2044 });
2045 _ = try p.expectToken(.RParen);
2046 const payload = try p.parsePtrPayload();
20922047
2093 const rpipe = try expectToken(it, tree, .Pipe);2048 const node = try p.arena.allocator.create(Node.If);
2049 node.* = .{
2050 .if_token = if_token,
2051 .condition = condition,
2052 .payload = payload,
2053 .body = undefined, // set by caller
2054 .@"else" = null,
2055 };
2056 return &node.base;
2057 }
20942058
2095 const node = try arena.create(Node.PointerIndexPayload);2059 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2096 node.* = .{2060 fn parseWhilePrefix(p: *Parser) !?*Node {
2097 .lpipe = lpipe,2061 const while_token = p.eatToken(.Keyword_while) orelse return null;
2098 .ptr_token = asterisk,
2099 .value_symbol = identifier,
2100 .index_symbol = index,
2101 .rpipe = rpipe,
2102 };
2103 return &node.base;
2104}
21052062
2106/// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr2063 _ = try p.expectToken(.LParen);
2107fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2064 const condition = try p.expectNode(parseExpr, .{
2108 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;2065 .ExpectedExpr = .{ .token = p.tok_i },
2109 const arrow = try expectToken(it, tree, .EqualAngleBracketRight);2066 });
2110 const payload = try parsePtrPayload(arena, it, tree);2067 _ = try p.expectToken(.RParen);
2111 const expr = try expectNode(arena, it, tree, parseAssignExpr, .{
2112 .ExpectedExprOrAssignment = .{ .token = it.index },
2113 });
2114
2115 const switch_case = node.cast(Node.SwitchCase).?;
2116 switch_case.arrow_token = arrow;
2117 switch_case.payload = payload;
2118 switch_case.expr = expr;
2119
2120 return node;
2121}
21222068
2123/// SwitchCase2069 const payload = try p.parsePtrPayload();
2124/// <- SwitchItem (COMMA SwitchItem)* COMMA?2070 const continue_expr = try p.parseWhileContinueExpr();
2125/// / KEYWORD_else
2126fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2127 var list = Node.SwitchCase.ItemList.init(arena);
21282071
2129 if (try parseSwitchItem(arena, it, tree)) |first_item| {2072 const node = try p.arena.allocator.create(Node.While);
2130 try list.push(first_item);2073 node.* = .{
2131 while (eatToken(it, .Comma) != null) {2074 .label = null,
2132 const next_item = (try parseSwitchItem(arena, it, tree)) orelse break;2075 .inline_token = null,
2133 try list.push(next_item);2076 .while_token = while_token,
2134 }2077 .condition = condition,
2135 } else if (eatToken(it, .Keyword_else)) |else_token| {2078 .payload = payload,
2136 const else_node = try arena.create(Node.SwitchElse);2079 .continue_expr = continue_expr,
2137 else_node.* = .{2080 .body = undefined, // set by caller
2138 .token = else_token,2081 .@"else" = null,
2139 };2082 };
2140 try list.push(&else_node.base);2083 return &node.base;
2141 } else return null;2084 }
21422085
2143 const node = try arena.create(Node.SwitchCase);2086 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2144 node.* = .{2087 fn parseForPrefix(p: *Parser) !?*Node {
2145 .items = list,2088 const for_token = p.eatToken(.Keyword_for) orelse return null;
2146 .arrow_token = undefined, // set by caller
2147 .payload = null,
2148 .expr = undefined, // set by caller
2149 };
2150 return &node.base;
2151}
21522089
2153/// SwitchItem <- Expr (DOT3 Expr)?2090 _ = try p.expectToken(.LParen);
2154fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2091 const array_expr = try p.expectNode(parseExpr, .{
2155 const expr = (try parseExpr(arena, it, tree)) orelse return null;2092 .ExpectedExpr = .{ .token = p.tok_i },
2156 if (eatToken(it, .Ellipsis3)) |token| {
2157 const range_end = try expectNode(arena, it, tree, parseExpr, .{
2158 .ExpectedExpr = .{ .token = it.index },
2159 });2093 });
2094 _ = try p.expectToken(.RParen);
21602095
2161 const node = try arena.create(Node.InfixOp);2096 const payload = try p.expectNode(parsePtrIndexPayload, .{
2097 .ExpectedPayload = .{ .token = p.tok_i },
2098 });
2099
2100 const node = try p.arena.allocator.create(Node.For);
2162 node.* = .{2101 node.* = .{
2163 .op_token = token,2102 .label = null,
2164 .lhs = expr,2103 .inline_token = null,
2165 .op = .Range,2104 .for_token = for_token,
2166 .rhs = range_end,2105 .array_expr = array_expr,
2106 .payload = payload,
2107 .body = undefined, // set by caller
2108 .@"else" = null,
2167 };2109 };
2168 return &node.base;2110 return &node.base;
2169 }2111 }
2170 return expr;
2171}
21722112
2173/// AssignOp2113 /// Payload <- PIPE IDENTIFIER PIPE
2174/// <- ASTERISKEQUAL2114 fn parsePayload(p: *Parser) !?*Node {
2175/// / SLASHEQUAL2115 const lpipe = p.eatToken(.Pipe) orelse return null;
2176/// / PERCENTEQUAL2116 const identifier = try p.expectNode(parseIdentifier, .{
2177/// / PLUSEQUAL2117 .ExpectedIdentifier = .{ .token = p.tok_i },
2178/// / MINUSEQUAL2118 });
2179/// / LARROW2EQUAL2119 const rpipe = try p.expectToken(.Pipe);
2180/// / RARROW2EQUAL
2181/// / AMPERSANDEQUAL
2182/// / CARETEQUAL
2183/// / PIPEEQUAL
2184/// / ASTERISKPERCENTEQUAL
2185/// / PLUSPERCENTEQUAL
2186/// / MINUSPERCENTEQUAL
2187/// / EQUAL
2188fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2189 const token = nextToken(it);
2190 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2191 .AsteriskEqual => .AssignMul,
2192 .SlashEqual => .AssignDiv,
2193 .PercentEqual => .AssignMod,
2194 .PlusEqual => .AssignAdd,
2195 .MinusEqual => .AssignSub,
2196 .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft,
2197 .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight,
2198 .AmpersandEqual => .AssignBitAnd,
2199 .CaretEqual => .AssignBitXor,
2200 .PipeEqual => .AssignBitOr,
2201 .AsteriskPercentEqual => .AssignMulWrap,
2202 .PlusPercentEqual => .AssignAddWrap,
2203 .MinusPercentEqual => .AssignSubWrap,
2204 .Equal => .Assign,
2205 else => {
2206 putBackToken(it, token.index);
2207 return null;
2208 },
2209 };
22102120
2211 const node = try arena.create(Node.InfixOp);2121 const node = try p.arena.allocator.create(Node.Payload);
2212 node.* = .{2122 node.* = .{
2213 .op_token = token.index,2123 .lpipe = lpipe,
2214 .lhs = undefined, // set by caller2124 .error_symbol = identifier,
2215 .op = op,2125 .rpipe = rpipe,
2216 .rhs = undefined, // set by caller2126 };
2217 };2127 return &node.base;
2218 return &node.base;2128 }
2219}
22202129
2221/// CompareOp2130 /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
2222/// <- EQUALEQUAL2131 fn parsePtrPayload(p: *Parser) !?*Node {
2223/// / EXCLAMATIONMARKEQUAL2132 const lpipe = p.eatToken(.Pipe) orelse return null;
2224/// / LARROW2133 const asterisk = p.eatToken(.Asterisk);
2225/// / RARROW2134 const identifier = try p.expectNode(parseIdentifier, .{
2226/// / LARROWEQUAL2135 .ExpectedIdentifier = .{ .token = p.tok_i },
2227/// / RARROWEQUAL2136 });
2228fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2137 const rpipe = try p.expectToken(.Pipe);
2229 const token = nextToken(it);
2230 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2231 .EqualEqual => .EqualEqual,
2232 .BangEqual => .BangEqual,
2233 .AngleBracketLeft => .LessThan,
2234 .AngleBracketRight => .GreaterThan,
2235 .AngleBracketLeftEqual => .LessOrEqual,
2236 .AngleBracketRightEqual => .GreaterOrEqual,
2237 else => {
2238 putBackToken(it, token.index);
2239 return null;
2240 },
2241 };
22422138
2243 return try createInfixOp(arena, token.index, op);2139 const node = try p.arena.allocator.create(Node.PointerPayload);
2244}2140 node.* = .{
2141 .lpipe = lpipe,
2142 .ptr_token = asterisk,
2143 .value_symbol = identifier,
2144 .rpipe = rpipe,
2145 };
2146 return &node.base;
2147 }
22452148
2246/// BitwiseOp2149 /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
2247/// <- AMPERSAND2150 fn parsePtrIndexPayload(p: *Parser) !?*Node {
2248/// / CARET2151 const lpipe = p.eatToken(.Pipe) orelse return null;
2249/// / PIPE2152 const asterisk = p.eatToken(.Asterisk);
2250/// / KEYWORD_orelse2153 const identifier = try p.expectNode(parseIdentifier, .{
2251/// / KEYWORD_catch Payload?2154 .ExpectedIdentifier = .{ .token = p.tok_i },
2252fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2155 });
2253 const token = nextToken(it);
2254 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2255 .Ampersand => .BitAnd,
2256 .Caret => .BitXor,
2257 .Pipe => .BitOr,
2258 .Keyword_orelse => .UnwrapOptional,
2259 .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) },
2260 else => {
2261 putBackToken(it, token.index);
2262 return null;
2263 },
2264 };
22652156
2266 return try createInfixOp(arena, token.index, op);2157 const index = if (p.eatToken(.Comma) == null)
2267}2158 null
2159 else
2160 try p.expectNode(parseIdentifier, .{
2161 .ExpectedIdentifier = .{ .token = p.tok_i },
2162 });
22682163
2269/// BitShiftOp2164 const rpipe = try p.expectToken(.Pipe);
2270/// <- LARROW2
2271/// / RARROW2
2272fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2273 const token = nextToken(it);
2274 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2275 .AngleBracketAngleBracketLeft => .BitShiftLeft,
2276 .AngleBracketAngleBracketRight => .BitShiftRight,
2277 else => {
2278 putBackToken(it, token.index);
2279 return null;
2280 },
2281 };
22822165
2283 return try createInfixOp(arena, token.index, op);2166 const node = try p.arena.allocator.create(Node.PointerIndexPayload);
2284}2167 node.* = .{
2168 .lpipe = lpipe,
2169 .ptr_token = asterisk,
2170 .value_symbol = identifier,
2171 .index_symbol = index,
2172 .rpipe = rpipe,
2173 };
2174 return &node.base;
2175 }
22852176
2286/// AdditionOp2177 /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
2287/// <- PLUS2178 fn parseSwitchProng(p: *Parser) !?*Node {
2288/// / MINUS2179 const node = (try p.parseSwitchCase()) orelse return null;
2289/// / PLUS22180 const arrow = try p.expectToken(.EqualAngleBracketRight);
2290/// / PLUSPERCENT2181 const payload = try p.parsePtrPayload();
2291/// / MINUSPERCENT2182 const expr = try p.expectNode(parseAssignExpr, .{
2292fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2183 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
2293 const token = nextToken(it);2184 });
2294 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2295 .Plus => .Add,
2296 .Minus => .Sub,
2297 .PlusPlus => .ArrayCat,
2298 .PlusPercent => .AddWrap,
2299 .MinusPercent => .SubWrap,
2300 else => {
2301 putBackToken(it, token.index);
2302 return null;
2303 },
2304 };
23052185
2306 return try createInfixOp(arena, token.index, op);2186 const switch_case = node.cast(Node.SwitchCase).?;
2307}2187 switch_case.arrow_token = arrow;
2188 switch_case.payload = payload;
2189 switch_case.expr = expr;
23082190
2309/// MultiplyOp2191 return node;
2310/// <- PIPE22192 }
2311/// / ASTERISK
2312/// / SLASH
2313/// / PERCENT
2314/// / ASTERISK2
2315/// / ASTERISKPERCENT
2316fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2317 const token = nextToken(it);
2318 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2319 .PipePipe => .MergeErrorSets,
2320 .Asterisk => .Mul,
2321 .Slash => .Div,
2322 .Percent => .Mod,
2323 .AsteriskAsterisk => .ArrayMult,
2324 .AsteriskPercent => .MulWrap,
2325 else => {
2326 putBackToken(it, token.index);
2327 return null;
2328 },
2329 };
23302193
2331 return try createInfixOp(arena, token.index, op);2194 /// SwitchCase
2332}2195 /// <- SwitchItem (COMMA SwitchItem)* COMMA?
2196 /// / KEYWORD_else
2197 fn parseSwitchCase(p: *Parser) !?*Node {
2198 var list = std.ArrayList(*Node).init(p.gpa);
2199 defer list.deinit();
23332200
2334/// PrefixOp2201 if (try p.parseSwitchItem()) |first_item| {
2335/// <- EXCLAMATIONMARK2202 try list.append(first_item);
2336/// / MINUS2203 while (p.eatToken(.Comma) != null) {
2337/// / TILDE2204 const next_item = (try p.parseSwitchItem()) orelse break;
2338/// / MINUSPERCENT2205 try list.append(next_item);
2339/// / AMPERSAND2206 }
2340/// / KEYWORD_try2207 } else if (p.eatToken(.Keyword_else)) |else_token| {
2341/// / KEYWORD_await2208 const else_node = try p.arena.allocator.create(Node.SwitchElse);
2342fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2209 else_node.* = .{
2343 const token = nextToken(it);2210 .token = else_token,
2344 const op: Node.PrefixOp.Op = switch (token.ptr.id) {2211 };
2345 .Bang => .BoolNot,2212 try list.append(&else_node.base);
2346 .Minus => .Negation,2213 } else return null;
2347 .Tilde => .BitNot,
2348 .MinusPercent => .NegationWrap,
2349 .Ampersand => .AddressOf,
2350 .Keyword_try => .Try,
2351 .Keyword_await => .Await,
2352 else => {
2353 putBackToken(it, token.index);
2354 return null;
2355 },
2356 };
23572214
2358 const node = try arena.create(Node.PrefixOp);2215 const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len);
2359 node.* = .{2216 node.* = .{
2360 .op_token = token.index,2217 .items_len = list.items.len,
2361 .op = op,2218 .arrow_token = undefined, // set by caller
2362 .rhs = undefined, // set by caller2219 .payload = null,
2363 };2220 .expr = undefined, // set by caller
2364 return &node.base;2221 };
2365}2222 std.mem.copy(*Node, node.items(), list.items);
2223 return &node.base;
2224 }
2225
2226 /// SwitchItem <- Expr (DOT3 Expr)?
2227 fn parseSwitchItem(p: *Parser) !?*Node {
2228 const expr = (try p.parseExpr()) orelse return null;
2229 if (p.eatToken(.Ellipsis3)) |token| {
2230 const range_end = try p.expectNode(parseExpr, .{
2231 .ExpectedExpr = .{ .token = p.tok_i },
2232 });
2233
2234 const node = try p.arena.allocator.create(Node.InfixOp);
2235 node.* = .{
2236 .op_token = token,
2237 .lhs = expr,
2238 .op = .Range,
2239 .rhs = range_end,
2240 };
2241 return &node.base;
2242 }
2243 return expr;
2244 }
2245
2246 /// AssignOp
2247 /// <- ASTERISKEQUAL
2248 /// / SLASHEQUAL
2249 /// / PERCENTEQUAL
2250 /// / PLUSEQUAL
2251 /// / MINUSEQUAL
2252 /// / LARROW2EQUAL
2253 /// / RARROW2EQUAL
2254 /// / AMPERSANDEQUAL
2255 /// / CARETEQUAL
2256 /// / PIPEEQUAL
2257 /// / ASTERISKPERCENTEQUAL
2258 /// / PLUSPERCENTEQUAL
2259 /// / MINUSPERCENTEQUAL
2260 /// / EQUAL
2261 fn parseAssignOp(p: *Parser) !?*Node {
2262 const token = p.nextToken();
2263 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2264 .AsteriskEqual => .AssignMul,
2265 .SlashEqual => .AssignDiv,
2266 .PercentEqual => .AssignMod,
2267 .PlusEqual => .AssignAdd,
2268 .MinusEqual => .AssignSub,
2269 .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft,
2270 .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight,
2271 .AmpersandEqual => .AssignBitAnd,
2272 .CaretEqual => .AssignBitXor,
2273 .PipeEqual => .AssignBitOr,
2274 .AsteriskPercentEqual => .AssignMulWrap,
2275 .PlusPercentEqual => .AssignAddWrap,
2276 .MinusPercentEqual => .AssignSubWrap,
2277 .Equal => .Assign,
2278 else => {
2279 p.putBackToken(token);
2280 return null;
2281 },
2282 };
23662283
2367// TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on2284 const node = try p.arena.allocator.create(Node.InfixOp);
2368// pointers. Consider updating this rule:
2369// ...
2370// / ArrayTypeStart
2371// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2372// / PtrTypeStart ...
2373
2374/// PrefixTypeOp
2375/// <- QUESTIONMARK
2376/// / KEYWORD_anyframe MINUSRARROW
2377/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2378/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2379fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2380 if (eatToken(it, .QuestionMark)) |token| {
2381 const node = try arena.create(Node.PrefixOp);
2382 node.* = .{2285 node.* = .{
2383 .op_token = token,2286 .op_token = token,
2384 .op = .OptionalType,2287 .lhs = undefined, // set by caller
2288 .op = op,
2385 .rhs = undefined, // set by caller2289 .rhs = undefined, // set by caller
2386 };2290 };
2387 return &node.base;2291 return &node.base;
2388 }2292 }
23892293
2390 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or2294 /// CompareOp
2391 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).2295 /// <- EQUALEQUAL
2392 // Consider making the AnyFrameType a member of PrefixOp and add a2296 /// / EXCLAMATIONMARKEQUAL
2393 // PrefixOp.AnyFrameType variant?2297 /// / LARROW
2394 if (eatToken(it, .Keyword_anyframe)) |token| {2298 /// / RARROW
2395 const arrow = eatToken(it, .Arrow) orelse {2299 /// / LARROWEQUAL
2396 putBackToken(it, token);2300 /// / RARROWEQUAL
2397 return null;2301 fn parseCompareOp(p: *Parser) !?*Node {
2302 const token = p.nextToken();
2303 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2304 .EqualEqual => .EqualEqual,
2305 .BangEqual => .BangEqual,
2306 .AngleBracketLeft => .LessThan,
2307 .AngleBracketRight => .GreaterThan,
2308 .AngleBracketLeftEqual => .LessOrEqual,
2309 .AngleBracketRightEqual => .GreaterOrEqual,
2310 else => {
2311 p.putBackToken(token);
2312 return null;
2313 },
2398 };2314 };
2399 const node = try arena.create(Node.AnyFrameType);2315
2400 node.* = .{2316 return p.createInfixOp(token, op);
2401 .anyframe_token = token,2317 }
2402 .result = .{2318
2403 .arrow_token = arrow,2319 /// BitwiseOp
2404 .return_type = undefined, // set by caller2320 /// <- AMPERSAND
2321 /// / CARET
2322 /// / PIPE
2323 /// / KEYWORD_orelse
2324 /// / KEYWORD_catch Payload?
2325 fn parseBitwiseOp(p: *Parser) !?*Node {
2326 const token = p.nextToken();
2327 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2328 .Ampersand => .BitAnd,
2329 .Caret => .BitXor,
2330 .Pipe => .BitOr,
2331 .Keyword_orelse => .UnwrapOptional,
2332 .Keyword_catch => .{ .Catch = try p.parsePayload() },
2333 else => {
2334 p.putBackToken(token);
2335 return null;
2405 },2336 },
2406 };2337 };
2338
2339 return p.createInfixOp(token, op);
2340 }
2341
2342 /// BitShiftOp
2343 /// <- LARROW2
2344 /// / RARROW2
2345 fn parseBitShiftOp(p: *Parser) !?*Node {
2346 const token = p.nextToken();
2347 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2348 .AngleBracketAngleBracketLeft => .BitShiftLeft,
2349 .AngleBracketAngleBracketRight => .BitShiftRight,
2350 else => {
2351 p.putBackToken(token);
2352 return null;
2353 },
2354 };
2355
2356 return p.createInfixOp(token, op);
2357 }
2358
2359 /// AdditionOp
2360 /// <- PLUS
2361 /// / MINUS
2362 /// / PLUS2
2363 /// / PLUSPERCENT
2364 /// / MINUSPERCENT
2365 fn parseAdditionOp(p: *Parser) !?*Node {
2366 const token = p.nextToken();
2367 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2368 .Plus => .Add,
2369 .Minus => .Sub,
2370 .PlusPlus => .ArrayCat,
2371 .PlusPercent => .AddWrap,
2372 .MinusPercent => .SubWrap,
2373 else => {
2374 p.putBackToken(token);
2375 return null;
2376 },
2377 };
2378
2379 return p.createInfixOp(token, op);
2380 }
2381
2382 /// MultiplyOp
2383 /// <- PIPE2
2384 /// / ASTERISK
2385 /// / SLASH
2386 /// / PERCENT
2387 /// / ASTERISK2
2388 /// / ASTERISKPERCENT
2389 fn parseMultiplyOp(p: *Parser) !?*Node {
2390 const token = p.nextToken();
2391 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2392 .PipePipe => .MergeErrorSets,
2393 .Asterisk => .Mul,
2394 .Slash => .Div,
2395 .Percent => .Mod,
2396 .AsteriskAsterisk => .ArrayMult,
2397 .AsteriskPercent => .MulWrap,
2398 else => {
2399 p.putBackToken(token);
2400 return null;
2401 },
2402 };
2403
2404 return p.createInfixOp(token, op);
2405 }
2406
2407 /// PrefixOp
2408 /// <- EXCLAMATIONMARK
2409 /// / MINUS
2410 /// / TILDE
2411 /// / MINUSPERCENT
2412 /// / AMPERSAND
2413 /// / KEYWORD_try
2414 /// / KEYWORD_await
2415 fn parsePrefixOp(p: *Parser) !?*Node {
2416 const token = p.nextToken();
2417 const op: Node.PrefixOp.Op = switch (p.token_ids[token]) {
2418 .Bang => .BoolNot,
2419 .Minus => .Negation,
2420 .Tilde => .BitNot,
2421 .MinusPercent => .NegationWrap,
2422 .Ampersand => .AddressOf,
2423 .Keyword_try => .Try,
2424 .Keyword_await => .Await,
2425 else => {
2426 p.putBackToken(token);
2427 return null;
2428 },
2429 };
2430
2431 const node = try p.arena.allocator.create(Node.PrefixOp);
2432 node.* = .{
2433 .op_token = token,
2434 .op = op,
2435 .rhs = undefined, // set by caller
2436 };
2407 return &node.base;2437 return &node.base;
2408 }2438 }
24092439
2410 if (try parsePtrTypeStart(arena, it, tree)) |node| {2440 // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
2411 // If the token encountered was **, there will be two nodes instead of one.2441 // pointers. Consider updating this rule:
2412 // The attributes should be applied to the rightmost operator.2442 // ...
2413 const prefix_op = node.cast(Node.PrefixOp).?;2443 // / ArrayTypeStart
2414 var ptr_info = if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk)2444 // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2415 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType2445 // / PtrTypeStart ...
2416 else2446
2417 &prefix_op.op.PtrType;2447 /// PrefixTypeOp
2448 /// <- QUESTIONMARK
2449 /// / KEYWORD_anyframe MINUSRARROW
2450 /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2451 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2452 fn parsePrefixTypeOp(p: *Parser) !?*Node {
2453 if (p.eatToken(.QuestionMark)) |token| {
2454 const node = try p.arena.allocator.create(Node.PrefixOp);
2455 node.* = .{
2456 .op_token = token,
2457 .op = .OptionalType,
2458 .rhs = undefined, // set by caller
2459 };
2460 return &node.base;
2461 }
24182462
2419 while (true) {2463 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2420 if (eatToken(it, .Keyword_align)) |align_token| {2464 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2421 const lparen = try expectToken(it, tree, .LParen);2465 // Consider making the AnyFrameType a member of PrefixOp and add a
2422 const expr_node = try expectNode(arena, it, tree, parseExpr, .{2466 // PrefixOp.AnyFrameType variant?
2423 .ExpectedExpr = .{ .token = it.index },2467 if (p.eatToken(.Keyword_anyframe)) |token| {
2424 });2468 const arrow = p.eatToken(.Arrow) orelse {
2469 p.putBackToken(token);
2470 return null;
2471 };
2472 const node = try p.arena.allocator.create(Node.AnyFrameType);
2473 node.* = .{
2474 .anyframe_token = token,
2475 .result = .{
2476 .arrow_token = arrow,
2477 .return_type = undefined, // set by caller
2478 },
2479 };
2480 return &node.base;
2481 }
24252482
2426 // Optional bit range2483 if (try p.parsePtrTypeStart()) |node| {
2427 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {2484 // If the token encountered was **, there will be two nodes instead of one.
2428 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{2485 // The attributes should be applied to the rightmost operator.
2429 .ExpectedIntegerLiteral = .{ .token = it.index },2486 const prefix_op = node.cast(Node.PrefixOp).?;
2430 });2487 var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)
2431 _ = try expectToken(it, tree, .Colon);2488 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2432 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{2489 else
2433 .ExpectedIntegerLiteral = .{ .token = it.index },2490 &prefix_op.op.PtrType;
2491
2492 while (true) {
2493 if (p.eatToken(.Keyword_align)) |align_token| {
2494 const lparen = try p.expectToken(.LParen);
2495 const expr_node = try p.expectNode(parseExpr, .{
2496 .ExpectedExpr = .{ .token = p.tok_i },
2434 });2497 });
24352498
2436 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{2499 // Optional bit range
2437 .start = range_start,2500 const bit_range = if (p.eatToken(.Colon)) |_| bit_range_value: {
2438 .end = range_end,2501 const range_start = try p.expectNode(parseIntegerLiteral, .{
2502 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
2503 });
2504 _ = try p.expectToken(.Colon);
2505 const range_end = try p.expectNode(parseIntegerLiteral, .{
2506 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
2507 });
2508
2509 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
2510 .start = range_start,
2511 .end = range_end,
2512 };
2513 } else null;
2514 _ = try p.expectToken(.RParen);
2515
2516 if (ptr_info.align_info != null) {
2517 try p.errors.append(p.gpa, .{
2518 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2519 });
2520 continue;
2521 }
2522
2523 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
2524 .node = expr_node,
2525 .bit_range = bit_range,
2439 };2526 };
2440 } else null;
2441 _ = try expectToken(it, tree, .RParen);
24422527
2443 if (ptr_info.align_info != null) {
2444 try tree.errors.push(.{
2445 .ExtraAlignQualifier = .{ .token = it.index - 1 },
2446 });
2447 continue;2528 continue;
2448 }2529 }
24492530 if (p.eatToken(.Keyword_const)) |const_token| {
2450 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{2531 if (ptr_info.const_token != null) {
2451 .node = expr_node,2532 try p.errors.append(p.gpa, .{
2452 .bit_range = bit_range,2533 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2453 };2534 });
24542535 continue;
2455 continue;2536 }
2456 }2537 ptr_info.const_token = const_token;
2457 if (eatToken(it, .Keyword_const)) |const_token| {
2458 if (ptr_info.const_token != null) {
2459 try tree.errors.push(.{
2460 .ExtraConstQualifier = .{ .token = it.index - 1 },
2461 });
2462 continue;2538 continue;
2463 }2539 }
2464 ptr_info.const_token = const_token;2540 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2465 continue;2541 if (ptr_info.volatile_token != null) {
2466 }2542 try p.errors.append(p.gpa, .{
2467 if (eatToken(it, .Keyword_volatile)) |volatile_token| {2543 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2468 if (ptr_info.volatile_token != null) {2544 });
2469 try tree.errors.push(.{2545 continue;
2470 .ExtraVolatileQualifier = .{ .token = it.index - 1 },2546 }
2471 });2547 ptr_info.volatile_token = volatile_token;
2472 continue;2548 continue;
2473 }2549 }
2474 ptr_info.volatile_token = volatile_token;2550 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2475 continue;2551 if (ptr_info.allowzero_token != null) {
2476 }2552 try p.errors.append(p.gpa, .{
2477 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {2553 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2478 if (ptr_info.allowzero_token != null) {2554 });
2479 try tree.errors.push(.{2555 continue;
2480 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },2556 }
2481 });2557 ptr_info.allowzero_token = allowzero_token;
2482 continue;2558 continue;
2483 }2559 }
2484 ptr_info.allowzero_token = allowzero_token;2560 break;
2485 continue;
2486 }2561 }
2487 break;
2488 }
24892562
2490 return node;2563 return node;
2491 }2564 }
24922565
2493 if (try parseArrayTypeStart(arena, it, tree)) |node| {2566 if (try p.parseArrayTypeStart()) |node| {
2494 switch (node.cast(Node.PrefixOp).?.op) {2567 switch (node.cast(Node.PrefixOp).?.op) {
2495 .ArrayType => {},2568 .ArrayType => {},
2496 .SliceType => |*slice_type| {2569 .SliceType => |*slice_type| {
2497 // Collect pointer qualifiers in any order, but disallow duplicates2570 // Collect pointer qualifiers in any order, but disallow duplicates
2498 while (true) {2571 while (true) {
2499 if (try parseByteAlign(arena, it, tree)) |align_expr| {2572 if (try p.parseByteAlign()) |align_expr| {
2500 if (slice_type.align_info != null) {2573 if (slice_type.align_info != null) {
2501 try tree.errors.push(.{2574 try p.errors.append(p.gpa, .{
2502 .ExtraAlignQualifier = .{ .token = it.index - 1 },2575 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2503 });2576 });
2577 continue;
2578 }
2579 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2580 .node = align_expr,
2581 .bit_range = null,
2582 };
2504 continue;2583 continue;
2505 }2584 }
2506 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{2585 if (p.eatToken(.Keyword_const)) |const_token| {
2507 .node = align_expr,2586 if (slice_type.const_token != null) {
2508 .bit_range = null,2587 try p.errors.append(p.gpa, .{
2509 };2588 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2510 continue;2589 });
2511 }2590 continue;
2512 if (eatToken(it, .Keyword_const)) |const_token| {2591 }
2513 if (slice_type.const_token != null) {2592 slice_type.const_token = const_token;
2514 try tree.errors.push(.{
2515 .ExtraConstQualifier = .{ .token = it.index - 1 },
2516 });
2517 continue;2593 continue;
2518 }2594 }
2519 slice_type.const_token = const_token;2595 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2520 continue;2596 if (slice_type.volatile_token != null) {
2521 }2597 try p.errors.append(p.gpa, .{
2522 if (eatToken(it, .Keyword_volatile)) |volatile_token| {2598 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2523 if (slice_type.volatile_token != null) {2599 });
2524 try tree.errors.push(.{2600 continue;
2525 .ExtraVolatileQualifier = .{ .token = it.index - 1 },2601 }
2526 });2602 slice_type.volatile_token = volatile_token;
2527 continue;2603 continue;
2528 }2604 }
2529 slice_type.volatile_token = volatile_token;2605 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2530 continue;2606 if (slice_type.allowzero_token != null) {
2607 try p.errors.append(p.gpa, .{
2608 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2609 });
2610 continue;
2611 }
2612 slice_type.allowzero_token = allowzero_token;
2613 continue;
2614 }
2615 break;
2531 }2616 }
2532 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {2617 },
2533 if (slice_type.allowzero_token != null) {2618 else => unreachable,
2534 try tree.errors.push(.{2619 }
2535 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },2620 return node;
2621 }
2622
2623 return null;
2624 }
2625
2626 /// SuffixOp
2627 /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
2628 /// / DOT IDENTIFIER
2629 /// / DOTASTERISK
2630 /// / DOTQUESTIONMARK
2631 fn parseSuffixOp(p: *Parser) !?*Node {
2632 const OpAndToken = struct {
2633 op: Node.SuffixOp.Op,
2634 token: TokenIndex,
2635 };
2636 const op_and_token: OpAndToken = blk: {
2637 if (p.eatToken(.LBracket)) |_| {
2638 const index_expr = try p.expectNode(parseExpr, .{
2639 .ExpectedExpr = .{ .token = p.tok_i },
2640 });
2641
2642 if (p.eatToken(.Ellipsis2) != null) {
2643 const end_expr = try p.parseExpr();
2644 const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
2645 try p.parseExpr()
2646 else
2647 null;
2648 break :blk .{
2649 .op = .{
2650 .Slice = .{
2651 .start = index_expr,
2652 .end = end_expr,
2653 .sentinel = sentinel,
2654 },
2655 },
2656 .token = try p.expectToken(.RBracket),
2657 };
2658 }
2659
2660 break :blk .{
2661 .op = .{ .ArrayAccess = index_expr },
2662 .token = try p.expectToken(.RBracket),
2663 };
2664 }
2665
2666 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
2667 break :blk .{ .op = .Deref, .token = period_asterisk };
2668 }
2669
2670 if (p.eatToken(.Period)) |period| {
2671 if (try p.parseIdentifier()) |identifier| {
2672 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2673 // Should there be an Node.SuffixOp.FieldAccess variant? Or should
2674 // this grammar rule be altered?
2675 const node = try p.arena.allocator.create(Node.InfixOp);
2676 node.* = .{
2677 .op_token = period,
2678 .lhs = undefined, // set by caller
2679 .op = .Period,
2680 .rhs = identifier,
2681 };
2682 return &node.base;
2683 }
2684 if (p.eatToken(.QuestionMark)) |question_mark| {
2685 break :blk .{ .op = .UnwrapOptional, .token = question_mark };
2686 }
2687 try p.errors.append(p.gpa, .{
2688 .ExpectedSuffixOp = .{ .token = p.tok_i },
2689 });
2690 return null;
2691 }
2692
2693 return null;
2694 };
2695
2696 const node = try p.arena.allocator.create(Node.SuffixOp);
2697 node.* = .{
2698 .lhs = undefined, // set by caller
2699 .op = op_and_token.op,
2700 .rtoken = op_and_token.token,
2701 };
2702 return &node.base;
2703 }
2704
2705 /// FnCallArguments <- LPAREN ExprList RPAREN
2706 /// ExprList <- (Expr COMMA)* Expr?
2707 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
2708 if (p.eatToken(.LParen) == null) return null;
2709 const list = try ListParseFn(*Node, parseExpr)(p);
2710 errdefer p.gpa.free(list);
2711 const rparen = try p.expectToken(.RParen);
2712 return AnnotatedParamList{ .list = list, .rparen = rparen };
2713 }
2714
2715 const AnnotatedParamList = struct {
2716 list: []*Node,
2717 rparen: TokenIndex,
2718 };
2719
2720 /// ArrayTypeStart <- LBRACKET Expr? RBRACKET
2721 fn parseArrayTypeStart(p: *Parser) !?*Node {
2722 const lbracket = p.eatToken(.LBracket) orelse return null;
2723 const expr = try p.parseExpr();
2724 const sentinel = if (p.eatToken(.Colon)) |_|
2725 try p.expectNode(parseExpr, .{
2726 .ExpectedExpr = .{ .token = p.tok_i },
2727 })
2728 else
2729 null;
2730 const rbracket = try p.expectToken(.RBracket);
2731
2732 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2733 .{
2734 .ArrayType = .{
2735 .len_expr = len_expr,
2736 .sentinel = sentinel,
2737 },
2738 }
2739 else
2740 .{
2741 .SliceType = Node.PrefixOp.PtrInfo{
2742 .allowzero_token = null,
2743 .align_info = null,
2744 .const_token = null,
2745 .volatile_token = null,
2746 .sentinel = sentinel,
2747 },
2748 };
2749
2750 const node = try p.arena.allocator.create(Node.PrefixOp);
2751 node.* = .{
2752 .op_token = lbracket,
2753 .op = op,
2754 .rhs = undefined, // set by caller
2755 };
2756 return &node.base;
2757 }
2758
2759 /// PtrTypeStart
2760 /// <- ASTERISK
2761 /// / ASTERISK2
2762 /// / PTRUNKNOWN
2763 /// / PTRC
2764 fn parsePtrTypeStart(p: *Parser) !?*Node {
2765 if (p.eatToken(.Asterisk)) |asterisk| {
2766 const sentinel = if (p.eatToken(.Colon)) |_|
2767 try p.expectNode(parseExpr, .{
2768 .ExpectedExpr = .{ .token = p.tok_i },
2769 })
2770 else
2771 null;
2772 const node = try p.arena.allocator.create(Node.PrefixOp);
2773 node.* = .{
2774 .op_token = asterisk,
2775 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2776 .rhs = undefined, // set by caller
2777 };
2778 return &node.base;
2779 }
2780
2781 if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
2782 const node = try p.arena.allocator.create(Node.PrefixOp);
2783 node.* = .{
2784 .op_token = double_asterisk,
2785 .op = .{ .PtrType = .{} },
2786 .rhs = undefined, // set by caller
2787 };
2788
2789 // Special case for **, which is its own token
2790 const child = try p.arena.allocator.create(Node.PrefixOp);
2791 child.* = .{
2792 .op_token = double_asterisk,
2793 .op = .{ .PtrType = .{} },
2794 .rhs = undefined, // set by caller
2795 };
2796 node.rhs = &child.base;
2797
2798 return &node.base;
2799 }
2800 if (p.eatToken(.LBracket)) |lbracket| {
2801 const asterisk = p.eatToken(.Asterisk) orelse {
2802 p.putBackToken(lbracket);
2803 return null;
2804 };
2805 if (p.eatToken(.Identifier)) |ident| {
2806 const token_loc = p.token_locs[ident];
2807 const token_slice = p.source[token_loc.start..token_loc.end];
2808 if (!std.mem.eql(u8, token_slice, "c")) {
2809 p.putBackToken(ident);
2810 } else {
2811 _ = try p.expectToken(.RBracket);
2812 const node = try p.arena.allocator.create(Node.PrefixOp);
2813 node.* = .{
2814 .op_token = lbracket,
2815 .op = .{ .PtrType = .{} },
2816 .rhs = undefined, // set by caller
2817 };
2818 return &node.base;
2819 }
2820 }
2821 const sentinel = if (p.eatToken(.Colon)) |_|
2822 try p.expectNode(parseExpr, .{
2823 .ExpectedExpr = .{ .token = p.tok_i },
2824 })
2825 else
2826 null;
2827 _ = try p.expectToken(.RBracket);
2828 const node = try p.arena.allocator.create(Node.PrefixOp);
2829 node.* = .{
2830 .op_token = lbracket,
2831 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2832 .rhs = undefined, // set by caller
2833 };
2834 return &node.base;
2835 }
2836 return null;
2837 }
2838
2839 /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
2840 fn parseContainerDeclAuto(p: *Parser) !?*Node {
2841 const container_decl_type = (try p.parseContainerDeclType()) orelse return null;
2842 const lbrace = try p.expectToken(.LBrace);
2843 const members = try p.parseContainerMembers(false);
2844 defer p.gpa.free(members);
2845 const rbrace = try p.expectToken(.RBrace);
2846
2847 const members_len = @intCast(NodeIndex, members.len);
2848 const node = try Node.ContainerDecl.alloc(&p.arena.allocator, members_len);
2849 node.* = .{
2850 .layout_token = null,
2851 .kind_token = container_decl_type.kind_token,
2852 .init_arg_expr = container_decl_type.init_arg_expr,
2853 .fields_and_decls_len = members_len,
2854 .lbrace_token = lbrace,
2855 .rbrace_token = rbrace,
2856 };
2857 std.mem.copy(*Node, node.fieldsAndDecls(), members);
2858 return &node.base;
2859 }
2860
2861 /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.
2862 const ContainerDeclType = struct {
2863 kind_token: TokenIndex,
2864 init_arg_expr: Node.ContainerDecl.InitArg,
2865 };
2866
2867 /// ContainerDeclType
2868 /// <- KEYWORD_struct
2869 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
2870 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2871 fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
2872 const kind_token = p.nextToken();
2873
2874 const init_arg_expr = switch (p.token_ids[kind_token]) {
2875 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
2876 .Keyword_enum => blk: {
2877 if (p.eatToken(.LParen) != null) {
2878 const expr = try p.expectNode(parseExpr, .{
2879 .ExpectedExpr = .{ .token = p.tok_i },
2880 });
2881 _ = try p.expectToken(.RParen);
2882 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2883 }
2884 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2885 },
2886 .Keyword_union => blk: {
2887 if (p.eatToken(.LParen) != null) {
2888 if (p.eatToken(.Keyword_enum) != null) {
2889 if (p.eatToken(.LParen) != null) {
2890 const expr = try p.expectNode(parseExpr, .{
2891 .ExpectedExpr = .{ .token = p.tok_i },
2536 });2892 });
2537 continue;2893 _ = try p.expectToken(.RParen);
2894 _ = try p.expectToken(.RParen);
2895 break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
2538 }2896 }
2539 slice_type.allowzero_token = allowzero_token;2897 _ = try p.expectToken(.RParen);
2540 continue;2898 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
2541 }2899 }
2542 break;2900 const expr = try p.expectNode(parseExpr, .{
2901 .ExpectedExpr = .{ .token = p.tok_i },
2902 });
2903 _ = try p.expectToken(.RParen);
2904 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2543 }2905 }
2906 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2544 },2907 },
2545 else => unreachable,2908 else => {
2546 }2909 p.putBackToken(kind_token);
2547 return node;2910 return null;
2911 },
2912 };
2913
2914 return ContainerDeclType{
2915 .kind_token = kind_token,
2916 .init_arg_expr = init_arg_expr,
2917 };
2918 }
2919
2920 /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
2921 fn parseByteAlign(p: *Parser) !?*Node {
2922 _ = p.eatToken(.Keyword_align) orelse return null;
2923 _ = try p.expectToken(.LParen);
2924 const expr = try p.expectNode(parseExpr, .{
2925 .ExpectedExpr = .{ .token = p.tok_i },
2926 });
2927 _ = try p.expectToken(.RParen);
2928 return expr;
2929 }
2930
2931 /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
2932 /// Only ErrorSetDecl parses an IdentifierList
2933 fn parseErrorTagList(p: *Parser) ![]*Node {
2934 return ListParseFn(*Node, parseErrorTag)(p);
2548 }2935 }
25492936
2550 return null;2937 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2551}2938 fn parseSwitchProngList(p: *Parser) ![]*Node {
2939 return ListParseFn(*Node, parseSwitchProng)(p);
2940 }
25522941
2553/// SuffixOp2942 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2554/// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET2943 fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
2555/// / DOT IDENTIFIER2944 return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
2556/// / DOTASTERISK2945 }
2557/// / DOTQUESTIONMARK
2558fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2559 const OpAndToken = struct {
2560 op: Node.SuffixOp.Op,
2561 token: TokenIndex,
2562 };
2563 const op_and_token: OpAndToken = blk: {
2564 if (eatToken(it, .LBracket)) |_| {
2565 const index_expr = try expectNode(arena, it, tree, parseExpr, .{
2566 .ExpectedExpr = .{ .token = it.index },
2567 });
25682946
2569 if (eatToken(it, .Ellipsis2) != null) {2947 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2570 const end_expr = try parseExpr(arena, it, tree);2948 fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
2571 const sentinel: ?*ast.Node = if (eatToken(it, .Colon) != null)2949 return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
2572 try parseExpr(arena, it, tree)2950 }
2573 else2951
2574 null;2952 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2575 break :blk .{2953 fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
2576 .op = .{2954 return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
2577 .Slice = .{2955 }
2578 .start = index_expr,2956
2579 .end = end_expr,2957 const NodeParseFn = fn (p: *Parser) Error!?*Node;
2580 .sentinel = sentinel,2958
2959 fn ListParseFn(comptime E: type, comptime nodeParseFn: var) ParseFn([]E) {
2960 return struct {
2961 pub fn parse(p: *Parser) ![]E {
2962 var list = std.ArrayList(E).init(p.gpa);
2963 defer list.deinit();
2964
2965 while (try nodeParseFn(p)) |item| {
2966 try list.append(item);
2967
2968 switch (p.token_ids[p.tok_i]) {
2969 .Comma => _ = p.nextToken(),
2970 // all possible delimiters
2971 .Colon, .RParen, .RBrace, .RBracket => break,
2972 else => {
2973 // this is likely just a missing comma,
2974 // continue parsing this list and give an error
2975 try p.errors.append(p.gpa, .{
2976 .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
2977 });
2581 },2978 },
2582 },2979 }
2583 .token = try expectToken(it, tree, .RBracket),2980 }
2584 };2981 return list.toOwnedSlice();
2585 }2982 }
2983 }.parse;
2984 }
25862985
2587 break :blk .{2986 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
2588 .op = .{ .ArrayAccess = index_expr },2987 return struct {
2589 .token = try expectToken(it, tree, .RBracket),2988 pub fn parse(p: *Parser) Error!?*Node {
2590 };2989 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
2591 }2990 .Keyword_and => p.nextToken(),
25922991 .Invalid_ampersands => blk: {
2593 if (eatToken(it, .PeriodAsterisk)) |period_asterisk| {2992 try p.errors.append(p.gpa, .{
2594 break :blk .{ .op = .Deref, .token = period_asterisk };2993 .InvalidAnd = .{ .token = p.tok_i },
2595 }2994 });
2995 break :blk p.nextToken();
2996 },
2997 else => return null,
2998 } else p.eatToken(token) orelse return null;
25962999
2597 if (eatToken(it, .Period)) |period| {3000 const node = try p.arena.allocator.create(Node.InfixOp);
2598 if (try parseIdentifier(arena, it, tree)) |identifier| {
2599 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2600 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should
2601 // this grammar rule be altered?
2602 const node = try arena.create(Node.InfixOp);
2603 node.* = .{3001 node.* = .{
2604 .op_token = period,3002 .op_token = op_token,
2605 .lhs = undefined, // set by caller3003 .lhs = undefined, // set by caller
2606 .op = .Period,3004 .op = op,
2607 .rhs = identifier,3005 .rhs = undefined, // set by caller
2608 };3006 };
2609 return &node.base;3007 return &node.base;
2610 }3008 }
2611 if (eatToken(it, .QuestionMark)) |question_mark| {3009 }.parse;
2612 break :blk .{ .op = .UnwrapOptional, .token = question_mark };3010 }
2613 }
2614 try tree.errors.push(.{
2615 .ExpectedSuffixOp = .{ .token = it.index },
2616 });
2617 return null;
2618 }
2619
2620 return null;
2621 };
2622
2623 const node = try arena.create(Node.SuffixOp);
2624 node.* = .{
2625 .lhs = undefined, // set by caller
2626 .op = op_and_token.op,
2627 .rtoken = op_and_token.token,
2628 };
2629 return &node.base;
2630}
26313011
2632/// FnCallArguments <- LPAREN ExprList RPAREN3012 // Helper parsers not included in the grammar
2633/// ExprList <- (Expr COMMA)* Expr?
2634fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {
2635 if (eatToken(it, .LParen) == null) return null;
2636 const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(arena, it, tree);
2637 const rparen = try expectToken(it, tree, .RParen);
2638 return AnnotatedParamList{ .list = list, .rparen = rparen };
2639}
26403013
2641const AnnotatedParamList = struct {3014 fn parseBuiltinCall(p: *Parser) !?*Node {
2642 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)3015 const token = p.eatToken(.Builtin) orelse return null;
2643 rparen: TokenIndex,3016 const params = (try p.parseFnCallArguments()) orelse {
2644};3017 try p.errors.append(p.gpa, .{
3018 .ExpectedParamList = .{ .token = p.tok_i },
3019 });
26453020
2646/// ArrayTypeStart <- LBRACKET Expr? RBRACKET3021 // lets pretend this was an identifier so we can continue parsing
2647fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3022 const node = try p.arena.allocator.create(Node.Identifier);
2648 const lbracket = eatToken(it, .LBracket) orelse return null;3023 node.* = .{
2649 const expr = try parseExpr(arena, it, tree);3024 .token = token,
2650 const sentinel = if (eatToken(it, .Colon)) |_|3025 };
2651 try expectNode(arena, it, tree, parseExpr, .{3026 return &node.base;
2652 .ExpectedExpr = .{ .token = it.index },
2653 })
2654 else
2655 null;
2656 const rbracket = try expectToken(it, tree, .RBracket);
2657
2658 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2659 .{
2660 .ArrayType = .{
2661 .len_expr = len_expr,
2662 .sentinel = sentinel,
2663 },
2664 }
2665 else
2666 .{
2667 .SliceType = Node.PrefixOp.PtrInfo{
2668 .allowzero_token = null,
2669 .align_info = null,
2670 .const_token = null,
2671 .volatile_token = null,
2672 .sentinel = sentinel,
2673 },
2674 };3027 };
3028 defer p.gpa.free(params.list);
26753029
2676 const node = try arena.create(Node.PrefixOp);3030 const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len);
2677 node.* = .{
2678 .op_token = lbracket,
2679 .op = op,
2680 .rhs = undefined, // set by caller
2681 };
2682 return &node.base;
2683}
2684
2685/// PtrTypeStart
2686/// <- ASTERISK
2687/// / ASTERISK2
2688/// / PTRUNKNOWN
2689/// / PTRC
2690fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2691 if (eatToken(it, .Asterisk)) |asterisk| {
2692 const sentinel = if (eatToken(it, .Colon)) |_|
2693 try expectNode(arena, it, tree, parseExpr, .{
2694 .ExpectedExpr = .{ .token = it.index },
2695 })
2696 else
2697 null;
2698 const node = try arena.create(Node.PrefixOp);
2699 node.* = .{3031 node.* = .{
2700 .op_token = asterisk,3032 .builtin_token = token,
2701 .op = .{ .PtrType = .{ .sentinel = sentinel } },3033 .params_len = params.list.len,
2702 .rhs = undefined, // set by caller3034 .rparen_token = params.rparen,
2703 };3035 };
3036 std.mem.copy(*Node, node.params(), params.list);
2704 return &node.base;3037 return &node.base;
2705 }3038 }
27063039
2707 if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| {3040 fn parseErrorTag(p: *Parser) !?*Node {
2708 const node = try arena.create(Node.PrefixOp);3041 const doc_comments = try p.parseDocComment(); // no need to rewind on failure
3042 const token = p.eatToken(.Identifier) orelse return null;
3043
3044 const node = try p.arena.allocator.create(Node.ErrorTag);
2709 node.* = .{3045 node.* = .{
2710 .op_token = double_asterisk,3046 .doc_comments = doc_comments,
2711 .op = .{ .PtrType = .{} },3047 .name_token = token,
2712 .rhs = undefined, // set by caller
2713 };3048 };
3049 return &node.base;
3050 }
27143051
2715 // Special case for **, which is its own token3052 fn parseIdentifier(p: *Parser) !?*Node {
2716 const child = try arena.create(Node.PrefixOp);3053 const token = p.eatToken(.Identifier) orelse return null;
2717 child.* = .{3054 const node = try p.arena.allocator.create(Node.Identifier);
2718 .op_token = double_asterisk,3055 node.* = .{
2719 .op = .{ .PtrType = .{} },3056 .token = token,
2720 .rhs = undefined, // set by caller
2721 };3057 };
2722 node.rhs = &child.base;
2723
2724 return &node.base;3058 return &node.base;
2725 }3059 }
2726 if (eatToken(it, .LBracket)) |lbracket| {3060
2727 const asterisk = eatToken(it, .Asterisk) orelse {3061 fn parseVarType(p: *Parser) !?*Node {
2728 putBackToken(it, lbracket);3062 const token = p.eatToken(.Keyword_var) orelse return null;
2729 return null;3063 const node = try p.arena.allocator.create(Node.VarType);
2730 };
2731 if (eatToken(it, .Identifier)) |ident| {
2732 if (!std.mem.eql(u8, tree.tokenSlice(ident), "c")) {
2733 putBackToken(it, ident);
2734 } else {
2735 _ = try expectToken(it, tree, .RBracket);
2736 const node = try arena.create(Node.PrefixOp);
2737 node.* = .{
2738 .op_token = lbracket,
2739 .op = .{ .PtrType = .{} },
2740 .rhs = undefined, // set by caller
2741 };
2742 return &node.base;
2743 }
2744 }
2745 const sentinel = if (eatToken(it, .Colon)) |_|
2746 try expectNode(arena, it, tree, parseExpr, .{
2747 .ExpectedExpr = .{ .token = it.index },
2748 })
2749 else
2750 null;
2751 _ = try expectToken(it, tree, .RBracket);
2752 const node = try arena.create(Node.PrefixOp);
2753 node.* = .{3064 node.* = .{
2754 .op_token = lbracket,3065 .token = token,
2755 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2756 .rhs = undefined, // set by caller
2757 };3066 };
2758 return &node.base;3067 return &node.base;
2759 }3068 }
2760 return null;
2761}
27623069
2763/// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE3070 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
2764fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3071 const result = try p.arena.allocator.create(T);
2765 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;3072 result.* = T{
2766 const lbrace = try expectToken(it, tree, .LBrace);3073 .base = Node{ .id = Node.typeToId(T) },
2767 const members = try parseContainerMembers(arena, it, tree, false);3074 .token = token,
2768 const rbrace = try expectToken(it, tree, .RBrace);3075 };
3076 return &result.base;
3077 }
27693078
2770 const decl_type = node.cast(Node.ContainerDecl).?;3079 fn parseStringLiteralSingle(p: *Parser) !?*Node {
2771 decl_type.fields_and_decls = members;3080 if (p.eatToken(.StringLiteral)) |token| {
2772 decl_type.lbrace_token = lbrace;3081 const node = try p.arena.allocator.create(Node.StringLiteral);
2773 decl_type.rbrace_token = rbrace;3082 node.* = .{
3083 .token = token,
3084 };
3085 return &node.base;
3086 }
3087 return null;
3088 }
27743089
2775 return node;3090 // string literal or multiline string literal
2776}3091 fn parseStringLiteral(p: *Parser) !?*Node {
3092 if (try p.parseStringLiteralSingle()) |node| return node;
27773093
2778/// ContainerDeclType3094 if (p.eatToken(.MultilineStringLiteralLine)) |first_line| {
2779/// <- KEYWORD_struct3095 const start_tok_i = p.tok_i;
2780/// / KEYWORD_enum (LPAREN Expr RPAREN)?3096 var tok_i = start_tok_i;
2781/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?3097 var count: usize = 1; // including first_line
2782fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3098 while (true) : (tok_i += 1) {
2783 const kind_token = nextToken(it);3099 switch (p.token_ids[tok_i]) {
27843100 .LineComment => continue,
2785 const init_arg_expr = switch (kind_token.ptr.id) {3101 .MultilineStringLiteralLine => count += 1,
2786 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },3102 else => break,
2787 .Keyword_enum => blk: {
2788 if (eatToken(it, .LParen) != null) {
2789 const expr = try expectNode(arena, it, tree, parseExpr, .{
2790 .ExpectedExpr = .{ .token = it.index },
2791 });
2792 _ = try expectToken(it, tree, .RParen);
2793 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2794 }
2795 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2796 },
2797 .Keyword_union => blk: {
2798 if (eatToken(it, .LParen) != null) {
2799 if (eatToken(it, .Keyword_enum) != null) {
2800 if (eatToken(it, .LParen) != null) {
2801 const expr = try expectNode(arena, it, tree, parseExpr, .{
2802 .ExpectedExpr = .{ .token = it.index },
2803 });
2804 _ = try expectToken(it, tree, .RParen);
2805 _ = try expectToken(it, tree, .RParen);
2806 break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
2807 }
2808 _ = try expectToken(it, tree, .RParen);
2809 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
2810 }3103 }
2811 const expr = try expectNode(arena, it, tree, parseExpr, .{
2812 .ExpectedExpr = .{ .token = it.index },
2813 });
2814 _ = try expectToken(it, tree, .RParen);
2815 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2816 }3104 }
2817 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2818 },
2819 else => {
2820 putBackToken(it, kind_token.index);
2821 return null;
2822 },
2823 };
2824
2825 const node = try arena.create(Node.ContainerDecl);
2826 node.* = .{
2827 .layout_token = null,
2828 .kind_token = kind_token.index,
2829 .init_arg_expr = init_arg_expr,
2830 .fields_and_decls = undefined, // set by caller
2831 .lbrace_token = undefined, // set by caller
2832 .rbrace_token = undefined, // set by caller
2833 };
2834 return &node.base;
2835}
2836
2837/// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
2838fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2839 _ = eatToken(it, .Keyword_align) orelse return null;
2840 _ = try expectToken(it, tree, .LParen);
2841 const expr = try expectNode(arena, it, tree, parseExpr, .{
2842 .ExpectedExpr = .{ .token = it.index },
2843 });
2844 _ = try expectToken(it, tree, .RParen);
2845 return expr;
2846}
2847
2848/// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
2849/// Only ErrorSetDecl parses an IdentifierList
2850fn parseErrorTagList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.ErrorSetDecl.DeclList {
2851 return try ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(arena, it, tree);
2852}
2853
2854/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2855fn parseSwitchProngList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Switch.CaseList {
2856 return try ListParseFn(Node.Switch.CaseList, parseSwitchProng)(arena, it, tree);
2857}
2858
2859/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2860fn parseAsmOutputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.OutputList {
2861 return try ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(arena, it, tree);
2862}
2863
2864/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2865fn parseAsmInputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.InputList {
2866 return try ListParseFn(Node.Asm.InputList, parseAsmInputItem)(arena, it, tree);
2867}
2868
2869/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2870fn parseParamDeclList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.FnProto.ParamList {
2871 return try ListParseFn(Node.FnProto.ParamList, parseParamDecl)(arena, it, tree);
2872}
2873
2874fn ParseFn(comptime T: type) type {
2875 return fn (*Allocator, *TokenIterator, *Tree) Error!T;
2876}
28773105
2878const NodeParseFn = fn (*Allocator, *TokenIterator, *Tree) Error!?*Node;3106 const node = try Node.MultilineStringLiteral.alloc(&p.arena.allocator, count);
28793107 node.* = .{ .lines_len = count };
2880fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {3108 const lines = node.lines();
2881 return struct {3109 tok_i = start_tok_i;
2882 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !L {3110 lines[0] = first_line;
2883 var list = L.init(arena);3111 count = 1;
2884 while (try nodeParseFn(arena, it, tree)) |node| {3112 while (true) : (tok_i += 1) {
2885 try list.push(node);3113 switch (p.token_ids[tok_i]) {
28863114 .LineComment => continue,
2887 switch (it.peek().?.id) {3115 .MultilineStringLiteralLine => {
2888 .Comma => _ = nextToken(it),3116 lines[count] = tok_i;
2889 // all possible delimiters3117 count += 1;
2890 .Colon, .RParen, .RBrace, .RBracket => break,
2891 else => {
2892 // this is likely just a missing comma,
2893 // continue parsing this list and give an error
2894 try tree.errors.push(.{
2895 .ExpectedToken = .{ .token = it.index, .expected_id = .Comma },
2896 });
2897 },3118 },
3119 else => break,
2898 }3120 }
2899 }3121 }
2900 return list;3122 p.tok_i = tok_i;
2901 }
2902 }.parse;
2903}
2904
2905fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
2906 return struct {
2907 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
2908 const op_token = if (token == .Keyword_and) switch (it.peek().?.id) {
2909 .Keyword_and => nextToken(it).index,
2910 .Invalid_ampersands => blk: {
2911 try tree.errors.push(.{
2912 .InvalidAnd = .{ .token = it.index },
2913 });
2914 break :blk nextToken(it).index;
2915 },
2916 else => return null,
2917 } else eatToken(it, token) orelse return null;
2918
2919 const node = try arena.create(Node.InfixOp);
2920 node.* = .{
2921 .op_token = op_token,
2922 .lhs = undefined, // set by caller
2923 .op = op,
2924 .rhs = undefined, // set by caller
2925 };
2926 return &node.base;3123 return &node.base;
2927 }3124 }
2928 }.parse;
2929}
2930
2931// Helper parsers not included in the grammar
29323125
2933fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3126 return null;
2934 const token = eatToken(it, .Builtin) orelse return null;3127 }
2935 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
2936 try tree.errors.push(.{
2937 .ExpectedParamList = .{ .token = it.index },
2938 });
29393128
2940 // lets pretend this was an identifier so we can continue parsing3129 fn parseIntegerLiteral(p: *Parser) !?*Node {
2941 const node = try arena.create(Node.Identifier);3130 const token = p.eatToken(.IntegerLiteral) orelse return null;
3131 const node = try p.arena.allocator.create(Node.IntegerLiteral);
2942 node.* = .{3132 node.* = .{
2943 .token = token,3133 .token = token,
2944 };3134 };
2945 return &node.base;3135 return &node.base;
2946 };3136 }
2947 const node = try arena.create(Node.BuiltinCall);
2948 node.* = .{
2949 .builtin_token = token,
2950 .params = params.list,
2951 .rparen_token = params.rparen,
2952 };
2953 return &node.base;
2954}
2955
2956fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2957 const doc_comments = try parseDocComment(arena, it, tree); // no need to rewind on failure
2958 const token = eatToken(it, .Identifier) orelse return null;
2959
2960 const node = try arena.create(Node.ErrorTag);
2961 node.* = .{
2962 .doc_comments = doc_comments,
2963 .name_token = token,
2964 };
2965 return &node.base;
2966}
2967
2968fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2969 const token = eatToken(it, .Identifier) orelse return null;
2970 const node = try arena.create(Node.Identifier);
2971 node.* = .{
2972 .token = token,
2973 };
2974 return &node.base;
2975}
2976
2977fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2978 const token = eatToken(it, .Keyword_var) orelse return null;
2979 const node = try arena.create(Node.VarType);
2980 node.* = .{
2981 .token = token,
2982 };
2983 return &node.base;
2984}
2985
2986fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node {
2987 const result = try arena.create(T);
2988 result.* = T{
2989 .base = Node{ .id = Node.typeToId(T) },
2990 .token = token,
2991 };
2992 return &result.base;
2993}
29943137
2995fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3138 fn parseFloatLiteral(p: *Parser) !?*Node {
2996 if (eatToken(it, .StringLiteral)) |token| {3139 const token = p.eatToken(.FloatLiteral) orelse return null;
2997 const node = try arena.create(Node.StringLiteral);3140 const node = try p.arena.allocator.create(Node.FloatLiteral);
2998 node.* = .{3141 node.* = .{
2999 .token = token,3142 .token = token,
3000 };3143 };
3001 return &node.base;3144 return &node.base;
3002 }3145 }
3003 return null;
3004}
3005
3006// string literal or multiline string literal
3007fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
3008 if (try parseStringLiteralSingle(arena, it, tree)) |node| return node;
30093146
3010 if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {3147 fn parseTry(p: *Parser) !?*Node {
3011 const node = try arena.create(Node.MultilineStringLiteral);3148 const token = p.eatToken(.Keyword_try) orelse return null;
3149 const node = try p.arena.allocator.create(Node.PrefixOp);
3012 node.* = .{3150 node.* = .{
3013 .lines = Node.MultilineStringLiteral.LineList.init(arena),3151 .op_token = token,
3152 .op = .Try,
3153 .rhs = undefined, // set by caller
3014 };3154 };
3015 try node.lines.push(first_line);
3016 while (eatToken(it, .MultilineStringLiteralLine)) |line|
3017 try node.lines.push(line);
3018
3019 return &node.base;3155 return &node.base;
3020 }3156 }
30213157
3022 return null;3158 fn parseUse(p: *Parser) !?*Node {
3023}3159 const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
30243160 const node = try p.arena.allocator.create(Node.Use);
3025fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3161 node.* = .{
3026 const token = eatToken(it, .IntegerLiteral) orelse return null;3162 .doc_comments = null,
3027 const node = try arena.create(Node.IntegerLiteral);3163 .visib_token = null,
3028 node.* = .{3164 .use_token = token,
3029 .token = token,3165 .expr = try p.expectNode(parseExpr, .{
3030 };3166 .ExpectedExpr = .{ .token = p.tok_i },
3031 return &node.base;3167 }),
3032}3168 .semicolon_token = try p.expectToken(.Semicolon),
30333169 };
3034fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3170 return &node.base;
3035 const token = eatToken(it, .FloatLiteral) orelse return null;3171 }
3036 const node = try arena.create(Node.FloatLiteral);
3037 node.* = .{
3038 .token = token,
3039 };
3040 return &node.base;
3041}
3042
3043fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
3044 const token = eatToken(it, .Keyword_try) orelse return null;
3045 const node = try arena.create(Node.PrefixOp);
3046 node.* = .{
3047 .op_token = token,
3048 .op = .Try,
3049 .rhs = undefined, // set by caller
3050 };
3051 return &node.base;
3052}
30533172
3054fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3173 /// IfPrefix Body (KEYWORD_else Payload? Body)?
3055 const token = eatToken(it, .Keyword_usingnamespace) orelse return null;3174 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
3056 const node = try arena.create(Node.Use);3175 const node = (try p.parseIfPrefix()) orelse return null;
3057 node.* = .{3176 const if_prefix = node.cast(Node.If).?;
3058 .doc_comments = null,
3059 .visib_token = null,
3060 .use_token = token,
3061 .expr = try expectNode(arena, it, tree, parseExpr, .{
3062 .ExpectedExpr = .{ .token = it.index },
3063 }),
3064 .semicolon_token = try expectToken(it, tree, .Semicolon),
3065 };
3066 return &node.base;
3067}
30683177
3069/// IfPrefix Body (KEYWORD_else Payload? Body)?3178 if_prefix.body = try p.expectNode(bodyParseFn, .{
3070fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: NodeParseFn) !?*Node {3179 .InvalidToken = .{ .token = p.tok_i },
3071 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;3180 });
3072 const if_prefix = node.cast(Node.If).?;
3073
3074 if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{
3075 .InvalidToken = .{ .token = it.index },
3076 });
3077
3078 const else_token = eatToken(it, .Keyword_else) orelse return node;
3079 const payload = try parsePayload(arena, it, tree);
3080 const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{
3081 .InvalidToken = .{ .token = it.index },
3082 });
3083 const else_node = try arena.create(Node.Else);
3084 else_node.* = .{
3085 .else_token = else_token,
3086 .payload = payload,
3087 .body = else_expr,
3088 };
3089 if_prefix.@"else" = else_node;
30903181
3091 return node;3182 const else_token = p.eatToken(.Keyword_else) orelse return node;
3092}3183 const payload = try p.parsePayload();
3184 const else_expr = try p.expectNode(bodyParseFn, .{
3185 .InvalidToken = .{ .token = p.tok_i },
3186 });
3187 const else_node = try p.arena.allocator.create(Node.Else);
3188 else_node.* = .{
3189 .else_token = else_token,
3190 .payload = payload,
3191 .body = else_expr,
3192 };
3193 if_prefix.@"else" = else_node;
30933194
3094/// Eat a multiline doc comment3195 return node;
3095fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.DocComment {
3096 var lines = Node.DocComment.LineList.init(arena);
3097 while (eatToken(it, .DocComment)) |line| {
3098 try lines.push(line);
3099 }3196 }
31003197
3101 if (lines.len == 0) return null;3198 /// Eat a multiline doc comment
3199 fn parseDocComment(p: *Parser) !?*Node.DocComment {
3200 if (p.eatToken(.DocComment)) |first_line| {
3201 while (p.eatToken(.DocComment)) |_| {}
3202 const node = try p.arena.allocator.create(Node.DocComment);
3203 node.* = .{ .first_line = first_line };
3204 return node;
3205 }
3206 return null;
3207 }
31023208
3103 const node = try arena.create(Node.DocComment);3209 fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool {
3104 node.* = .{3210 return std.mem.indexOfScalar(u8, p.source[p.token_locs[token1].end..p.token_locs[token2].start], '\n') == null;
3105 .lines = lines,3211 }
3106 };
3107 return node;
3108}
31093212
3110/// Eat a single-line doc comment on the same line as another node3213 /// Eat a single-line doc comment on the same line as another node
3111fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, after_token: TokenIndex) !?*Node.DocComment {3214 fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !?*Node.DocComment {
3112 const comment_token = eatToken(it, .DocComment) orelse return null;3215 const comment_token = p.eatToken(.DocComment) orelse return null;
3113 if (tree.tokensOnSameLine(after_token, comment_token)) {3216 if (p.tokensOnSameLine(after_token, comment_token)) {
3114 const node = try arena.create(Node.DocComment);3217 const node = try p.arena.allocator.create(Node.DocComment);
3115 node.* = .{3218 node.* = .{ .first_line = comment_token };
3116 .lines = Node.DocComment.LineList.init(arena),3219 return node;
3117 };3220 }
3118 try node.lines.push(comment_token);3221 p.putBackToken(comment_token);
3119 return node;3222 return null;
3120 }3223 }
3121 putBackToken(it, comment_token);
3122 return null;
3123}
31243224
3125/// Op* Child3225 /// Op* Child
3126fn parsePrefixOpExpr(3226 fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node {
3127 arena: *Allocator,3227 if (try opParseFn(p)) |first_op| {
3128 it: *TokenIterator,3228 var rightmost_op = first_op;
3129 tree: *Tree,3229 while (true) {
3130 opParseFn: NodeParseFn,3230 switch (rightmost_op.id) {
3131 childParseFn: NodeParseFn,3231 .PrefixOp => {
3132) Error!?*Node {3232 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3133 if (try opParseFn(arena, it, tree)) |first_op| {3233 // If the token encountered was **, there will be two nodes
3134 var rightmost_op = first_op;3234 if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {
3135 while (true) {3235 rightmost_op = prefix_op.rhs;
3236 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3237 }
3238 if (try opParseFn(p)) |rhs| {
3239 prefix_op.rhs = rhs;
3240 rightmost_op = rhs;
3241 } else break;
3242 },
3243 .AnyFrameType => {
3244 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3245 if (try opParseFn(p)) |rhs| {
3246 prom.result.?.return_type = rhs;
3247 rightmost_op = rhs;
3248 } else break;
3249 },
3250 else => unreachable,
3251 }
3252 }
3253
3254 // If any prefix op existed, a child node on the RHS is required
3136 switch (rightmost_op.id) {3255 switch (rightmost_op.id) {
3137 .PrefixOp => {3256 .PrefixOp => {
3138 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;3257 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3139 // If the token encountered was **, there will be two nodes3258 prefix_op.rhs = try p.expectNode(childParseFn, .{
3140 if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) {3259 .InvalidToken = .{ .token = p.tok_i },
3141 rightmost_op = prefix_op.rhs;3260 });
3142 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3143 }
3144 if (try opParseFn(arena, it, tree)) |rhs| {
3145 prefix_op.rhs = rhs;
3146 rightmost_op = rhs;
3147 } else break;
3148 },3261 },
3149 .AnyFrameType => {3262 .AnyFrameType => {
3150 const prom = rightmost_op.cast(Node.AnyFrameType).?;3263 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3151 if (try opParseFn(arena, it, tree)) |rhs| {3264 prom.result.?.return_type = try p.expectNode(childParseFn, .{
3152 prom.result.?.return_type = rhs;3265 .InvalidToken = .{ .token = p.tok_i },
3153 rightmost_op = rhs;3266 });
3154 } else break;
3155 },3267 },
3156 else => unreachable,3268 else => unreachable,
3157 }3269 }
3158 }
31593270
3160 // If any prefix op existed, a child node on the RHS is required3271 return first_op;
3161 switch (rightmost_op.id) {
3162 .PrefixOp => {
3163 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3164 prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{
3165 .InvalidToken = .{ .token = it.index },
3166 });
3167 },
3168 .AnyFrameType => {
3169 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3170 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{
3171 .InvalidToken = .{ .token = it.index },
3172 });
3173 },
3174 else => unreachable,
3175 }3272 }
31763273
3177 return first_op;3274 // Otherwise, the child node is optional
3275 return childParseFn(p);
3178 }3276 }
31793277
3180 // Otherwise, the child node is optional3278 /// Child (Op Child)*
3181 return try childParseFn(arena, it, tree);3279 /// Child (Op Child)?
3182}3280 fn parseBinOpExpr(
3281 p: *Parser,
3282 opParseFn: NodeParseFn,
3283 childParseFn: NodeParseFn,
3284 chain: enum {
3285 Once,
3286 Infinitely,
3287 },
3288 ) Error!?*Node {
3289 var res = (try childParseFn(p)) orelse return null;
31833290
3184/// Child (Op Child)*3291 while (try opParseFn(p)) |node| {
3185/// Child (Op Child)?3292 const right = try p.expectNode(childParseFn, .{
3186fn parseBinOpExpr(3293 .InvalidToken = .{ .token = p.tok_i },
3187 arena: *Allocator,3294 });
3188 it: *TokenIterator,3295 const left = res;
3189 tree: *Tree,3296 res = node;
3190 opParseFn: NodeParseFn,
3191 childParseFn: NodeParseFn,
3192 chain: enum {
3193 Once,
3194 Infinitely,
3195 },
3196) Error!?*Node {
3197 var res = (try childParseFn(arena, it, tree)) orelse return null;
3198
3199 while (try opParseFn(arena, it, tree)) |node| {
3200 const right = try expectNode(arena, it, tree, childParseFn, .{
3201 .InvalidToken = .{ .token = it.index },
3202 });
3203 const left = res;
3204 res = node;
32053297
3206 const op = node.cast(Node.InfixOp).?;3298 const op = node.cast(Node.InfixOp).?;
3207 op.*.lhs = left;3299 op.*.lhs = left;
3208 op.*.rhs = right;3300 op.*.rhs = right;
32093301
3210 switch (chain) {3302 switch (chain) {
3211 .Once => break,3303 .Once => break,
3212 .Infinitely => continue,3304 .Infinitely => continue,
3305 }
3213 }3306 }
3307
3308 return res;
3214 }3309 }
32153310
3216 return res;3311 fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
3217}3312 const node = try p.arena.allocator.create(Node.InfixOp);
3313 node.* = .{
3314 .op_token = index,
3315 .lhs = undefined, // set by caller
3316 .op = op,
3317 .rhs = undefined, // set by caller
3318 };
3319 return &node.base;
3320 }
32183321
3219fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {3322 fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
3220 const node = try arena.create(Node.InfixOp);3323 return if (p.token_ids[p.tok_i] == id) p.nextToken() else null;
3221 node.* = .{3324 }
3222 .op_token = index,
3223 .lhs = undefined, // set by caller
3224 .op = op,
3225 .rhs = undefined, // set by caller
3226 };
3227 return &node.base;
3228}
32293325
3230fn eatToken(it: *TokenIterator, id: Token.Id) ?TokenIndex {3326 fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex {
3231 return if (eatAnnotatedToken(it, id)) |token| token.index else null;3327 return (try p.expectTokenRecoverable(id)) orelse error.ParseError;
3232}3328 }
32333329
3234fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {3330 fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex {
3235 return if (it.peek().?.id == id) nextToken(it) else null;3331 const token = p.nextToken();
3236}3332 if (p.token_ids[token] != id) {
3333 try p.errors.append(p.gpa, .{
3334 .ExpectedToken = .{ .token = token, .expected_id = id },
3335 });
3336 // go back so that we can recover properly
3337 p.putBackToken(token);
3338 return null;
3339 }
3340 return token;
3341 }
32373342
3238fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {3343 fn nextToken(p: *Parser) TokenIndex {
3239 return (try expectTokenRecoverable(it, tree, id)) orelse3344 const result = p.tok_i;
3240 error.ParseError;3345 p.tok_i += 1;
3241}3346 assert(p.token_ids[result] != .LineComment);
3347 if (p.tok_i >= p.token_ids.len) return result;
32423348
3243fn expectTokenRecoverable(it: *TokenIterator, tree: *Tree, id: Token.Id) !?TokenIndex {3349 while (true) {
3244 const token = nextToken(it);3350 if (p.token_ids[p.tok_i] != .LineComment) return result;
3245 if (token.ptr.id != id) {3351 p.tok_i += 1;
3246 try tree.errors.push(.{3352 }
3247 .ExpectedToken = .{ .token = token.index, .expected_id = id },
3248 });
3249 // go back so that we can recover properly
3250 putBackToken(it, token.index);
3251 return null;
3252 }3353 }
3253 return token.index;
3254}
3255
3256fn nextToken(it: *TokenIterator) AnnotatedToken {
3257 const result = AnnotatedToken{
3258 .index = it.index,
3259 .ptr = it.next().?,
3260 };
3261 assert(result.ptr.id != .LineComment);
32623354
3263 while (true) {3355 fn putBackToken(p: *Parser, putting_back: TokenIndex) void {
3264 const next_tok = it.peek() orelse return result;3356 while (p.tok_i > 0) {
3265 if (next_tok.id != .LineComment) return result;3357 p.tok_i -= 1;
3266 _ = it.next();3358 if (p.token_ids[p.tok_i] == .LineComment) continue;
3359 assert(putting_back == p.tok_i);
3360 return;
3361 }
3267 }3362 }
3268}
32693363
3270fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {3364 fn expectNode(
3271 while (true) {3365 p: *Parser,
3272 const prev_tok = it.prev() orelse return;3366 parseFn: NodeParseFn,
3273 if (prev_tok.id == .LineComment) continue;3367 /// if parsing fails
3274 assert(it.list.at(putting_back) == prev_tok);3368 err: AstError,
3275 return;3369 ) Error!*Node {
3370 return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
3276 }3371 }
3277}
32783372
3279const AnnotatedToken = struct {3373 fn expectNodeRecoverable(
3280 index: TokenIndex,3374 p: *Parser,
3281 ptr: *Token,3375 parseFn: NodeParseFn,
3376 /// if parsing fails
3377 err: AstError,
3378 ) !?*Node {
3379 return (try parseFn(p)) orelse {
3380 try p.errors.append(p.gpa, err);
3381 return null;
3382 };
3383 }
3282};3384};
32833385
3284fn expectNode(3386fn ParseFn(comptime T: type) type {
3285 arena: *Allocator,3387 return fn (p: *Parser) Error!T;
3286 it: *TokenIterator,
3287 tree: *Tree,
3288 parseFn: NodeParseFn,
3289 err: AstError, // if parsing fails
3290) Error!*Node {
3291 return (try expectNodeRecoverable(arena, it, tree, parseFn, err)) orelse
3292 return error.ParseError;
3293}3388}
32943389
3295fn expectNodeRecoverable(
3296 arena: *Allocator,
3297 it: *TokenIterator,
3298 tree: *Tree,
3299 parseFn: NodeParseFn,
3300 err: AstError, // if parsing fails
3301) !?*Node {
3302 return (try parseFn(arena, it, tree)) orelse {
3303 try tree.errors.push(err);
3304 return null;
3305 };
3306}
33073390
3308test "std.zig.parser" {3391test "std.zig.parser" {
3309 _ = @import("parser_test.zig");3392 _ = @import("parser_test.zig");
lib/std/zig/parser_test.zig+3-6
...@@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b...@@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
3180 const tree = try std.zig.parse(allocator, source);3180 const tree = try std.zig.parse(allocator, source);
3181 defer tree.deinit();3181 defer tree.deinit();
31823182
3183 var error_it = tree.errors.iterator(0);3183 for (tree.errors) |*parse_error| {
3184 while (error_it.next()) |parse_error| {3184 const token = tree.token_locs[parse_error.loc()];
3185 const token = tree.tokens.at(parse_error.loc());
3186 const loc = tree.tokenLocation(0, parse_error.loc());3185 const loc = tree.tokenLocation(0, parse_error.loc());
3187 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });3186 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
3188 try tree.renderError(parse_error, stderr);3187 try tree.renderError(parse_error, stderr);
...@@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {...@@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {
32713270
3272 std.testing.expect(tree.errors.len == expected_errors.len);3271 std.testing.expect(tree.errors.len == expected_errors.len);
3273 for (expected_errors) |expected, i| {3272 for (expected_errors) |expected, i| {
3274 const err = tree.errors.at(i);3273 std.testing.expect(expected == tree.errors[i]);
3275
3276 std.testing.expect(expected == err.*);
3277 }3274 }
3278}3275}
lib/std/zig/render.zig+630-573
...@@ -67,24 +67,23 @@ fn renderRoot(...@@ -67,24 +67,23 @@ fn renderRoot(
67 stream: var,67 stream: var,
68 tree: *ast.Tree,68 tree: *ast.Tree,
69) (@TypeOf(stream).Error || Error)!void {69) (@TypeOf(stream).Error || Error)!void {
70 var tok_it = tree.tokens.iterator(0);
71
72 // render all the line comments at the beginning of the file70 // render all the line comments at the beginning of the file
73 while (tok_it.next()) |token| {71 for (tree.token_ids) |token_id, i| {
74 if (token.id != .LineComment) break;72 if (token_id != .LineComment) break;
75 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")});73 const token_loc = tree.token_locs[i];
76 if (tok_it.peek()) |next_token| {74 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
77 const loc = tree.tokenLocationPtr(token.end, next_token);75 const next_token = tree.token_locs[i + 1];
78 if (loc.line >= 2) {76 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
79 try stream.writeByte('\n');77 if (loc.line >= 2) {
80 }78 try stream.writeByte('\n');
81 }79 }
82 }80 }
8381
84 var start_col: usize = 0;82 var start_col: usize = 0;
85 var it = tree.root_node.decls.iterator(0);83 var decl_i: ast.NodeIndex = 0;
84 const root_decls = tree.root_node.decls();
86 while (true) {85 while (true) {
87 var decl = (it.next() orelse return).*;86 var decl = root_decls[decl_i];
8887
89 // This loop does the following:88 // This loop does the following:
90 //89 //
...@@ -103,8 +102,8 @@ fn renderRoot(...@@ -103,8 +102,8 @@ fn renderRoot(
103102
104 while (token_index != 0) {103 while (token_index != 0) {
105 token_index -= 1;104 token_index -= 1;
106 const token = tree.tokens.at(token_index);105 const token_id = tree.token_ids[token_index];
107 switch (token.id) {106 switch (token_id) {
108 .LineComment => {},107 .LineComment => {},
109 .DocComment => {108 .DocComment => {
110 copy_start_token_index = token_index;109 copy_start_token_index = token_index;
...@@ -113,12 +112,13 @@ fn renderRoot(...@@ -113,12 +112,13 @@ fn renderRoot(
113 else => break,112 else => break,
114 }113 }
115114
116 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) {115 const token_loc = tree.token_locs[token_index];
116 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
117 if (!found_fmt_directive) {117 if (!found_fmt_directive) {
118 fmt_active = false;118 fmt_active = false;
119 found_fmt_directive = true;119 found_fmt_directive = true;
120 }120 }
121 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) {121 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
122 if (!found_fmt_directive) {122 if (!found_fmt_directive) {
123 fmt_active = true;123 fmt_active = true;
124 found_fmt_directive = true;124 found_fmt_directive = true;
...@@ -133,25 +133,28 @@ fn renderRoot(...@@ -133,25 +133,28 @@ fn renderRoot(
133 token_index = decl.firstToken();133 token_index = decl.firstToken();
134134
135 while (!fmt_active) {135 while (!fmt_active) {
136 decl = (it.next() orelse {136 decl_i += 1;
137 if (decl_i >= root_decls.len) {
137 // If there's no next reformatted `decl`, just copy the138 // If there's no next reformatted `decl`, just copy the
138 // remaining input tokens and bail out.139 // remaining input tokens and bail out.
139 const start = tree.tokens.at(copy_start_token_index).start;140 const start = tree.token_locs[copy_start_token_index].start;
140 try copyFixingWhitespace(stream, tree.source[start..]);141 try copyFixingWhitespace(stream, tree.source[start..]);
141 return;142 return;
142 }).*;143 }
144 decl = root_decls[decl_i];
143 var decl_first_token_index = decl.firstToken();145 var decl_first_token_index = decl.firstToken();
144146
145 while (token_index < decl_first_token_index) : (token_index += 1) {147 while (token_index < decl_first_token_index) : (token_index += 1) {
146 const token = tree.tokens.at(token_index);148 const token_id = tree.token_ids[token_index];
147 switch (token.id) {149 switch (token_id) {
148 .LineComment => {},150 .LineComment => {},
149 .Eof => unreachable,151 .Eof => unreachable,
150 else => continue,152 else => continue,
151 }153 }
152 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) {154 const token_loc = tree.token_locs[token_index];
155 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
153 fmt_active = true;156 fmt_active = true;
154 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) {157 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
155 fmt_active = false;158 fmt_active = false;
156 }159 }
157 }160 }
...@@ -163,8 +166,8 @@ fn renderRoot(...@@ -163,8 +166,8 @@ fn renderRoot(
163 token_index = copy_end_token_index;166 token_index = copy_end_token_index;
164 while (token_index != 0) {167 while (token_index != 0) {
165 token_index -= 1;168 token_index -= 1;
166 const token = tree.tokens.at(token_index);169 const token_id = tree.token_ids[token_index];
167 switch (token.id) {170 switch (token_id) {
168 .LineComment => {},171 .LineComment => {},
169 .DocComment => {172 .DocComment => {
170 copy_end_token_index = token_index;173 copy_end_token_index = token_index;
...@@ -174,30 +177,33 @@ fn renderRoot(...@@ -174,30 +177,33 @@ fn renderRoot(
174 }177 }
175 }178 }
176179
177 const start = tree.tokens.at(copy_start_token_index).start;180 const start = tree.token_locs[copy_start_token_index].start;
178 const end = tree.tokens.at(copy_end_token_index).start;181 const end = tree.token_locs[copy_end_token_index].start;
179 try copyFixingWhitespace(stream, tree.source[start..end]);182 try copyFixingWhitespace(stream, tree.source[start..end]);
180 }183 }
181184
182 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);185 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);
183 if (it.peek()) |next_decl| {186 decl_i += 1;
184 try renderExtraNewline(tree, stream, &start_col, next_decl.*);187 if (decl_i >= root_decls.len) return;
185 }188 try renderExtraNewline(tree, stream, &start_col, root_decls[decl_i]);
186 }189 }
187}190}
188191
189fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {192fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
190 const first_token = node.firstToken();193 return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());
194}
195
196fn renderExtraNewlineToken(tree: *ast.Tree, stream: var, start_col: *usize, first_token: ast.TokenIndex,) @TypeOf(stream).Error!void {
191 var prev_token = first_token;197 var prev_token = first_token;
192 if (prev_token == 0) return;198 if (prev_token == 0) return;
193 var newline_threshold: usize = 2;199 var newline_threshold: usize = 2;
194 while (tree.tokens.at(prev_token - 1).id == .DocComment) {200 while (tree.token_ids[prev_token - 1] == .DocComment) {
195 if (tree.tokenLocation(tree.tokens.at(prev_token - 1).end, prev_token).line == 1) {201 if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) {
196 newline_threshold += 1;202 newline_threshold += 1;
197 }203 }
198 prev_token -= 1;204 prev_token -= 1;
199 }205 }
200 const prev_token_end = tree.tokens.at(prev_token - 1).end;206 const prev_token_end = tree.token_locs[prev_token - 1].end;
201 const loc = tree.tokenLocation(prev_token_end, first_token);207 const loc = tree.tokenLocation(prev_token_end, first_token);
202 if (loc.line >= newline_threshold) {208 if (loc.line >= newline_threshold) {
203 try stream.writeByte('\n');209 try stream.writeByte('\n');
...@@ -262,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,...@@ -262,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
262268
263 const src_has_trailing_comma = blk: {269 const src_has_trailing_comma = blk: {
264 const maybe_comma = tree.nextToken(field.lastToken());270 const maybe_comma = tree.nextToken(field.lastToken());
265 break :blk tree.tokens.at(maybe_comma).id == .Comma;271 break :blk tree.token_ids[maybe_comma] == .Comma;
266 };272 };
267273
268 // The trailing comma is emitted at the end, but if it's not present274 // The trailing comma is emitted at the end, but if it's not present
...@@ -324,11 +330,18 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,...@@ -324,11 +330,18 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
324330
325 .DocComment => {331 .DocComment => {
326 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);332 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
327 var it = comment.lines.iterator(0);333 const kind = tree.token_ids[comment.first_line];
328 while (it.next()) |line_token_index| {334 try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline);
329 try renderToken(tree, stream, line_token_index.*, indent, start_col, .Newline);335 var tok_i = comment.first_line + 1;
330 if (it.peek()) |_| {336 while (true) : (tok_i += 1) {
337 const tok_id = tree.token_ids[tok_i];
338 if (tok_id == kind) {
331 try stream.writeByteNTimes(' ', indent);339 try stream.writeByteNTimes(' ', indent);
340 try renderToken(tree, stream, tok_i, indent, start_col, .Newline);
341 } else if (tok_id == .LineComment) {
342 continue;
343 } else {
344 break;
332 }345 }
333 }346 }
334 },347 },
...@@ -358,20 +371,20 @@ fn renderExpression(...@@ -358,20 +371,20 @@ fn renderExpression(
358 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);371 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
359 }372 }
360373
361 if (block.statements.len == 0) {374 if (block.statements_len == 0) {
362 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);375 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
363 return renderToken(tree, stream, block.rbrace, indent, start_col, space);376 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
364 } else {377 } else {
365 const block_indent = indent + indent_delta;378 const block_indent = indent + indent_delta;
366 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);379 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
367380
368 var it = block.statements.iterator(0);381 const block_statements = block.statements();
369 while (it.next()) |statement| {382 for (block_statements) |statement, i| {
370 try stream.writeByteNTimes(' ', block_indent);383 try stream.writeByteNTimes(' ', block_indent);
371 try renderStatement(allocator, stream, tree, block_indent, start_col, statement.*);384 try renderStatement(allocator, stream, tree, block_indent, start_col, statement);
372385
373 if (it.peek()) |next_statement| {386 if (i + 1 < block_statements.len) {
374 try renderExtraNewline(tree, stream, start_col, next_statement.*);387 try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]);
375 }388 }
376 }389 }
377390
...@@ -426,13 +439,13 @@ fn renderExpression(...@@ -426,13 +439,13 @@ fn renderExpression(
426 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);439 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
427440
428 const after_op_space = blk: {441 const after_op_space = blk: {
429 const loc = tree.tokenLocation(tree.tokens.at(infix_op_node.op_token).end, tree.nextToken(infix_op_node.op_token));442 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
430 break :blk if (loc.line == 0) op_space else Space.Newline;443 break :blk if (loc.line == 0) op_space else Space.Newline;
431 };444 };
432445
433 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);446 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
434 if (after_op_space == Space.Newline and447 if (after_op_space == Space.Newline and
435 tree.tokens.at(tree.nextToken(infix_op_node.op_token)).id != .MultilineStringLiteralLine)448 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)
436 {449 {
437 try stream.writeByteNTimes(' ', indent + indent_delta);450 try stream.writeByteNTimes(' ', indent + indent_delta);
438 start_col.* = indent + indent_delta;451 start_col.* = indent + indent_delta;
...@@ -453,10 +466,10 @@ fn renderExpression(...@@ -453,10 +466,10 @@ fn renderExpression(
453466
454 switch (prefix_op_node.op) {467 switch (prefix_op_node.op) {
455 .PtrType => |ptr_info| {468 .PtrType => |ptr_info| {
456 const op_tok_id = tree.tokens.at(prefix_op_node.op_token).id;469 const op_tok_id = tree.token_ids[prefix_op_node.op_token];
457 switch (op_tok_id) {470 switch (op_tok_id) {
458 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),471 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
459 .LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier)472 .LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier)
460 try stream.writeAll("[*c")473 try stream.writeAll("[*c")
461 else474 else
462 try stream.writeAll("[*"),475 try stream.writeAll("[*"),
...@@ -568,8 +581,8 @@ fn renderExpression(...@@ -568,8 +581,8 @@ fn renderExpression(
568581
569 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [582 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
570583
571 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;584 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
572 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;585 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
573 const new_indent = if (ends_with_comment) indent + indent_delta else indent;586 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
574 const new_space = if (ends_with_comment) Space.Newline else Space.None;587 const new_space = if (ends_with_comment) Space.Newline else Space.None;
575 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);588 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
...@@ -610,80 +623,371 @@ fn renderExpression(...@@ -610,80 +623,371 @@ fn renderExpression(
610 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);623 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);
611 },624 },
612625
613 .SuffixOp => {626 .ArrayInitializer, .ArrayInitializerDot => {
614 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);627 var rtoken: ast.TokenIndex = undefined;
615628 var exprs: []*ast.Node = undefined;
616 switch (suffix_op.op) {629 const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){
617 .Call => |*call_info| {630 .ArrayInitializerDot => blk: {
618 if (call_info.async_token) |async_token| {631 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
619 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);632 rtoken = casted.rtoken;
620 }633 exprs = casted.list();
621634 break :blk .{ .dot = casted.dot };
622 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);635 },
623636 .ArrayInitializer => blk: {
624 const lparen = tree.nextToken(suffix_op.lhs.node.lastToken());637 const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base);
638 rtoken = casted.rtoken;
639 exprs = casted.list();
640 break :blk .{ .node = casted.lhs };
641 },
642 else => unreachable,
643 };
625644
626 if (call_info.params.len == 0) {645 const lbrace = switch (lhs) {
627 try renderToken(tree, stream, lparen, indent, start_col, Space.None);646 .dot => |dot| tree.nextToken(dot),
628 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);647 .node => |node| tree.nextToken(node.lastToken()),
629 }648 };
630649
631 const src_has_trailing_comma = blk: {650 if (exprs.len == 0) {
632 const maybe_comma = tree.prevToken(suffix_op.rtoken);651 switch (lhs) {
633 break :blk tree.tokens.at(maybe_comma).id == .Comma;652 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
634 };653 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
654 }
655 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
656 return renderToken(tree, stream, rtoken, indent, start_col, space);
657 }
635658
636 if (src_has_trailing_comma) {659 if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) {
637 const new_indent = indent + indent_delta;660 const expr = exprs[0];
638 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);661 switch (lhs) {
662 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
663 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
664 }
665 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
666 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
667 return renderToken(tree, stream, rtoken, indent, start_col, space);
668 }
639669
640 var it = call_info.params.iterator(0);670 switch (lhs) {
641 while (true) {671 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
642 const param_node = it.next().?;672 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
673 }
643674
644 const param_node_new_indent = if (param_node.*.id == .MultilineStringLiteral) blk: {675 // scan to find row size
645 break :blk indent;676 const maybe_row_size: ?usize = blk: {
646 } else blk: {677 var count: usize = 1;
647 try stream.writeByteNTimes(' ', new_indent);678 for (exprs) |expr, i| {
648 break :blk new_indent;679 if (i + 1 < exprs.len) {
680 const expr_last_token = expr.lastToken() + 1;
681 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i+1].firstToken());
682 if (loc.line != 0) break :blk count;
683 count += 1;
684 } else {
685 const expr_last_token = expr.lastToken();
686 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
687 if (loc.line == 0) {
688 // all on one line
689 const src_has_trailing_comma = trailblk: {
690 const maybe_comma = tree.prevToken(rtoken);
691 break :trailblk tree.token_ids[maybe_comma] == .Comma;
649 };692 };
650693 if (src_has_trailing_comma) {
651 if (it.peek()) |next_node| {694 break :blk 1; // force row size 1
652 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.None);
653 const comma = tree.nextToken(param_node.*.lastToken());
654 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
655 try renderExtraNewline(tree, stream, start_col, next_node.*);
656 } else {695 } else {
657 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.Comma);696 break :blk null; // no newlines
658 try stream.writeByteNTimes(' ', indent);
659 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
660 }697 }
661 }698 }
699 break :blk count;
662 }700 }
701 }
702 unreachable;
703 };
663704
664 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (705 if (maybe_row_size) |row_size| {
706 // A place to store the width of each expression and its column's maximum
707 var widths = try allocator.alloc(usize, exprs.len + row_size);
708 defer allocator.free(widths);
709 mem.set(usize, widths, 0);
710
711 var expr_widths = widths[0 .. widths.len - row_size];
712 var column_widths = widths[widths.len - row_size ..];
713
714 // Null stream for counting the printed length of each expression
715 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
716
717 for (exprs) |expr, i| {
718 counting_stream.bytes_written = 0;
719 var dummy_col: usize = 0;
720 try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None);
721 const width = @intCast(usize, counting_stream.bytes_written);
722 const col = i % row_size;
723 column_widths[col] = std.math.max(column_widths[col], width);
724 expr_widths[i] = width;
725 }
726
727 var new_indent = indent + indent_delta;
728
729 if (tree.token_ids[tree.nextToken(lbrace)] != .MultilineStringLiteralLine) {
730 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
731 try stream.writeByteNTimes(' ', new_indent);
732 } else {
733 new_indent -= indent_delta;
734 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None);
735 }
736
737 var col: usize = 1;
738 for (exprs) |expr, i| {
739 if (i + 1 < exprs.len) {
740 const next_expr = exprs[i + 1];
741 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.None);
742
743 const comma = tree.nextToken(expr.lastToken());
744
745 if (col != row_size) {
746 try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // ,
747
748 const padding = column_widths[i % row_size] - expr_widths[i];
749 try stream.writeByteNTimes(' ', padding);
750
751 col += 1;
752 continue;
753 }
754 col = 1;
665755
666 var it = call_info.params.iterator(0);756 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
667 while (it.next()) |param_node| {757 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
668 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);758 } else {
759 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
760 }
669761
670 if (it.peek() != null) {762 try renderExtraNewline(tree, stream, start_col, next_expr);
671 const comma = tree.nextToken(param_node.*.lastToken());763 if (next_expr.id != .MultilineStringLiteral) {
672 try renderToken(tree, stream, comma, indent, start_col, Space.Space);764 try stream.writeByteNTimes(' ', new_indent);
673 }765 }
766 } else {
767 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,
768 }
769 }
770 if (exprs[exprs.len - 1].id != .MultilineStringLiteral) {
771 try stream.writeByteNTimes(' ', indent);
772 }
773 return renderToken(tree, stream, rtoken, indent, start_col, space);
774 } else {
775 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
776 for (exprs) |expr, i| {
777 if (i + 1 < exprs.len) {
778 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
779 const comma = tree.nextToken(expr.lastToken());
780 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
781 } else {
782 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space);
674 }783 }
675 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);784 }
785
786 return renderToken(tree, stream, rtoken, indent, start_col, space);
787 }
788 },
789
790 .StructInitializer, .StructInitializerDot => {
791 var rtoken: ast.TokenIndex = undefined;
792 var field_inits: []*ast.Node = undefined;
793 const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){
794 .StructInitializerDot => blk: {
795 const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
796 rtoken = casted.rtoken;
797 field_inits = casted.list();
798 break :blk .{ .dot = casted.dot };
676 },799 },
800 .StructInitializer => blk: {
801 const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
802 rtoken = casted.rtoken;
803 field_inits = casted.list();
804 break :blk .{ .node = casted.lhs };
805 },
806 else => unreachable,
807 };
808
809 const lbrace = switch (lhs) {
810 .dot => |dot| tree.nextToken(dot),
811 .node => |node| tree.nextToken(node.lastToken()),
812 };
813
814 if (field_inits.len == 0) {
815 switch (lhs) {
816 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
817 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
818 }
819 try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);
820 return renderToken(tree, stream, rtoken, indent, start_col, space);
821 }
822
823 const src_has_trailing_comma = blk: {
824 const maybe_comma = tree.prevToken(rtoken);
825 break :blk tree.token_ids[maybe_comma] == .Comma;
826 };
827
828 const src_same_line = blk: {
829 const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
830 break :blk loc.line == 0;
831 };
832
833 const expr_outputs_one_line = blk: {
834 // render field expressions until a LF is found
835 for (field_inits) |field_init| {
836 var find_stream = FindByteOutStream.init('\n');
837 var dummy_col: usize = 0;
838 try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None);
839 if (find_stream.byte_found) break :blk false;
840 }
841 break :blk true;
842 };
843
844 if (field_inits.len == 1) blk: {
845 const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?;
846
847 switch (field_init.expr.id) {
848 .StructInitializer,
849 .StructInitializerDot,
850 => break :blk,
851
852 else => {},
853 }
854
855 // if the expression outputs to multiline, make this struct multiline
856 if (!expr_outputs_one_line or src_has_trailing_comma) {
857 break :blk;
858 }
859
860 switch (lhs) {
861 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
862 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
863 }
864 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
865 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);
866 return renderToken(tree, stream, rtoken, indent, start_col, space);
867 }
868
869 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
870 // render all on one line, no trailing comma
871 switch (lhs) {
872 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
873 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
874 }
875 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
876
877 for (field_inits) |field_init, i| {
878 if (i + 1 < field_inits.len) {
879 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None);
880
881 const comma = tree.nextToken(field_init.lastToken());
882 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
883 } else {
884 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space);
885 }
886 }
887
888 return renderToken(tree, stream, rtoken, indent, start_col, space);
889 }
890
891 const new_indent = indent + indent_delta;
892
893 switch (lhs) {
894 .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),
895 .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None),
896 }
897 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
898
899 for (field_inits) |field_init, i| {
900 try stream.writeByteNTimes(' ', new_indent);
901
902 if (i + 1 < field_inits.len) {
903 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None);
904
905 const comma = tree.nextToken(field_init.lastToken());
906 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline);
907
908 try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]);
909 } else {
910 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma);
911 }
912 }
913
914 try stream.writeByteNTimes(' ', indent);
915 return renderToken(tree, stream, rtoken, indent, start_col, space);
916 },
917
918 .Call => {
919 const call = @fieldParentPtr(ast.Node.Call, "base", base);
920 if (call.async_token) |async_token| {
921 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
922 }
923
924 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);
925
926 const lparen = tree.nextToken(call.lhs.lastToken());
927
928 if (call.params_len == 0) {
929 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
930 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
931 }
932
933 const src_has_trailing_comma = blk: {
934 const maybe_comma = tree.prevToken(call.rtoken);
935 break :blk tree.token_ids[maybe_comma] == .Comma;
936 };
937
938 if (src_has_trailing_comma) {
939 const new_indent = indent + indent_delta;
940 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
677941
942 const params = call.params();
943 for (params) |param_node, i| {
944 const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
945 break :blk indent;
946 } else blk: {
947 try stream.writeByteNTimes(' ', new_indent);
948 break :blk new_indent;
949 };
950
951 if (i + 1 < params.len) {
952 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
953 const comma = tree.nextToken(param_node.lastToken());
954 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
955 try renderExtraNewline(tree, stream, start_col, params[i + 1]);
956 } else {
957 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
958 try stream.writeByteNTimes(' ', indent);
959 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
960 }
961 }
962 }
963
964 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
965
966 const params = call.params();
967 for (params) |param_node, i| {
968 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
969
970 if (i + 1 < params.len) {
971 const comma = tree.nextToken(param_node.lastToken());
972 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
973 }
974 }
975 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
976 },
977
978 .SuffixOp => {
979 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
980
981 switch (suffix_op.op) {
678 .ArrayAccess => |index_expr| {982 .ArrayAccess => |index_expr| {
679 const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken());983 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
680 const rbracket = tree.nextToken(index_expr.lastToken());984 const rbracket = tree.nextToken(index_expr.lastToken());
681985
682 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);986 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
683 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [987 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
684988
685 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;989 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
686 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;990 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
687 const new_indent = if (ends_with_comment) indent + indent_delta else indent;991 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
688 const new_space = if (ends_with_comment) Space.Newline else Space.None;992 const new_space = if (ends_with_comment) Space.Newline else Space.None;
689 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);993 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
...@@ -697,18 +1001,18 @@ fn renderExpression(...@@ -697,18 +1001,18 @@ fn renderExpression(
697 },1001 },
6981002
699 .Deref => {1003 .Deref => {
700 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);1004 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
701 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*1005 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
702 },1006 },
7031007
704 .UnwrapOptional => {1008 .UnwrapOptional => {
705 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);1009 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
706 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .1010 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
707 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?1011 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
708 },1012 },
7091013
710 .Slice => |range| {1014 .Slice => |range| {
711 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);1015 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
7121016
713 const lbracket = tree.prevToken(range.start.firstToken());1017 const lbracket = tree.prevToken(range.start.firstToken());
714 const dotdot = tree.nextToken(range.start.lastToken());1018 const dotdot = tree.nextToken(range.start.lastToken());
...@@ -733,269 +1037,6 @@ fn renderExpression(...@@ -733,269 +1037,6 @@ fn renderExpression(
733 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]1037 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
734 },1038 },
7351039
736 .StructInitializer => |*field_inits| {
737 const lbrace = switch (suffix_op.lhs) {
738 .dot => |dot| tree.nextToken(dot),
739 .node => |node| tree.nextToken(node.lastToken()),
740 };
741
742 if (field_inits.len == 0) {
743 switch (suffix_op.lhs) {
744 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
745 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
746 }
747 try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);
748 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
749 }
750
751 const src_has_trailing_comma = blk: {
752 const maybe_comma = tree.prevToken(suffix_op.rtoken);
753 break :blk tree.tokens.at(maybe_comma).id == .Comma;
754 };
755
756 const src_same_line = blk: {
757 const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken);
758 break :blk loc.line == 0;
759 };
760
761 const expr_outputs_one_line = blk: {
762 // render field expressions until a LF is found
763 var it = field_inits.iterator(0);
764 while (it.next()) |field_init| {
765 var find_stream = FindByteOutStream.init('\n');
766 var dummy_col: usize = 0;
767 try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init.*, Space.None);
768 if (find_stream.byte_found) break :blk false;
769 }
770 break :blk true;
771 };
772
773 if (field_inits.len == 1) blk: {
774 const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?;
775
776 if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| {
777 if (nested_suffix_op.op == .StructInitializer) {
778 break :blk;
779 }
780 }
781
782 // if the expression outputs to multiline, make this struct multiline
783 if (!expr_outputs_one_line or src_has_trailing_comma) {
784 break :blk;
785 }
786
787 switch (suffix_op.lhs) {
788 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
789 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
790 }
791 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
792 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);
793 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
794 }
795
796 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
797 // render all on one line, no trailing comma
798 switch (suffix_op.lhs) {
799 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
800 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
801 }
802 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
803
804 var it = field_inits.iterator(0);
805 while (it.next()) |field_init| {
806 if (it.peek() != null) {
807 try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.None);
808
809 const comma = tree.nextToken(field_init.*.lastToken());
810 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
811 } else {
812 try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.Space);
813 }
814 }
815
816 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
817 }
818
819 const new_indent = indent + indent_delta;
820
821 switch (suffix_op.lhs) {
822 .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),
823 .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None),
824 }
825 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
826
827 var it = field_inits.iterator(0);
828 while (it.next()) |field_init| {
829 try stream.writeByteNTimes(' ', new_indent);
830
831 if (it.peek()) |next_field_init| {
832 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.None);
833
834 const comma = tree.nextToken(field_init.*.lastToken());
835 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline);
836
837 try renderExtraNewline(tree, stream, start_col, next_field_init.*);
838 } else {
839 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.Comma);
840 }
841 }
842
843 try stream.writeByteNTimes(' ', indent);
844 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
845 },
846
847 .ArrayInitializer => |*exprs| {
848 const lbrace = switch (suffix_op.lhs) {
849 .dot => |dot| tree.nextToken(dot),
850 .node => |node| tree.nextToken(node.lastToken()),
851 };
852
853 if (exprs.len == 0) {
854 switch (suffix_op.lhs) {
855 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
856 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
857 }
858 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
859 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
860 }
861 if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) {
862 const expr = exprs.at(0).*;
863
864 switch (suffix_op.lhs) {
865 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
866 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
867 }
868 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
869 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
870 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
871 }
872
873 switch (suffix_op.lhs) {
874 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
875 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
876 }
877
878 // scan to find row size
879 const maybe_row_size: ?usize = blk: {
880 var count: usize = 1;
881 var it = exprs.iterator(0);
882 while (true) {
883 const expr = it.next().?.*;
884 if (it.peek()) |next_expr| {
885 const expr_last_token = expr.*.lastToken() + 1;
886 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());
887 if (loc.line != 0) break :blk count;
888 count += 1;
889 } else {
890 const expr_last_token = expr.*.lastToken();
891 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, suffix_op.rtoken);
892 if (loc.line == 0) {
893 // all on one line
894 const src_has_trailing_comma = trailblk: {
895 const maybe_comma = tree.prevToken(suffix_op.rtoken);
896 break :trailblk tree.tokens.at(maybe_comma).id == .Comma;
897 };
898 if (src_has_trailing_comma) {
899 break :blk 1; // force row size 1
900 } else {
901 break :blk null; // no newlines
902 }
903 }
904 break :blk count;
905 }
906 }
907 };
908
909 if (maybe_row_size) |row_size| {
910 // A place to store the width of each expression and its column's maximum
911 var widths = try allocator.alloc(usize, exprs.len + row_size);
912 defer allocator.free(widths);
913 mem.set(usize, widths, 0);
914
915 var expr_widths = widths[0 .. widths.len - row_size];
916 var column_widths = widths[widths.len - row_size ..];
917
918 // Null stream for counting the printed length of each expression
919 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
920
921 var it = exprs.iterator(0);
922 var i: usize = 0;
923
924 while (it.next()) |expr| : (i += 1) {
925 counting_stream.bytes_written = 0;
926 var dummy_col: usize = 0;
927 try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr.*, Space.None);
928 const width = @intCast(usize, counting_stream.bytes_written);
929 const col = i % row_size;
930 column_widths[col] = std.math.max(column_widths[col], width);
931 expr_widths[i] = width;
932 }
933
934 var new_indent = indent + indent_delta;
935
936 if (tree.tokens.at(tree.nextToken(lbrace)).id != .MultilineStringLiteralLine) {
937 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
938 try stream.writeByteNTimes(' ', new_indent);
939 } else {
940 new_indent -= indent_delta;
941 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None);
942 }
943
944 it.set(0);
945 i = 0;
946 var col: usize = 1;
947 while (it.next()) |expr| : (i += 1) {
948 if (it.peek()) |next_expr| {
949 try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.None);
950
951 const comma = tree.nextToken(expr.*.lastToken());
952
953 if (col != row_size) {
954 try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // ,
955
956 const padding = column_widths[i % row_size] - expr_widths[i];
957 try stream.writeByteNTimes(' ', padding);
958
959 col += 1;
960 continue;
961 }
962 col = 1;
963
964 if (tree.tokens.at(tree.nextToken(comma)).id != .MultilineStringLiteralLine) {
965 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
966 } else {
967 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
968 }
969
970 try renderExtraNewline(tree, stream, start_col, next_expr.*);
971 if (next_expr.*.id != .MultilineStringLiteral) {
972 try stream.writeByteNTimes(' ', new_indent);
973 }
974 } else {
975 try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.Comma); // ,
976 }
977 }
978 const last_node = it.prev().?;
979 if (last_node.*.id != .MultilineStringLiteral) {
980 try stream.writeByteNTimes(' ', indent);
981 }
982 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
983 } else {
984 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
985 var it = exprs.iterator(0);
986 while (it.next()) |expr| {
987 if (it.peek()) |next_expr| {
988 try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.None);
989 const comma = tree.nextToken(expr.*.lastToken());
990 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
991 } else {
992 try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.Space);
993 }
994 }
995
996 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
997 }
998 },
999 }1040 }
1000 },1041 },
10011042
...@@ -1179,7 +1220,7 @@ fn renderExpression(...@@ -1179,7 +1220,7 @@ fn renderExpression(
1179 },1220 },
1180 }1221 }
11811222
1182 if (container_decl.fields_and_decls.len == 0) {1223 if (container_decl.fields_and_decls_len == 0) {
1183 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {1224 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {
1184 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }1225 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
1185 }1226 }
...@@ -1188,23 +1229,24 @@ fn renderExpression(...@@ -1188,23 +1229,24 @@ fn renderExpression(
1188 var maybe_comma = tree.prevToken(container_decl.lastToken());1229 var maybe_comma = tree.prevToken(container_decl.lastToken());
1189 // Doc comments for a field may also appear after the comma, eg.1230 // Doc comments for a field may also appear after the comma, eg.
1190 // field_name: T, // comment attached to field_name1231 // field_name: T, // comment attached to field_name
1191 if (tree.tokens.at(maybe_comma).id == .DocComment)1232 if (tree.token_ids[maybe_comma] == .DocComment)
1192 maybe_comma = tree.prevToken(maybe_comma);1233 maybe_comma = tree.prevToken(maybe_comma);
1193 break :blk tree.tokens.at(maybe_comma).id == .Comma;1234 break :blk tree.token_ids[maybe_comma] == .Comma;
1194 };1235 };
11951236
1237 const fields_and_decls = container_decl.fieldsAndDecls();
1238
1196 // Check if the first declaration and the { are on the same line1239 // Check if the first declaration and the { are on the same line
1197 const src_has_newline = !tree.tokensOnSameLine(1240 const src_has_newline = !tree.tokensOnSameLine(
1198 container_decl.lbrace_token,1241 container_decl.lbrace_token,
1199 container_decl.fields_and_decls.at(0).*.firstToken(),1242 fields_and_decls[0].firstToken(),
1200 );1243 );
12011244
1202 // We can only print all the elements in-line if all the1245 // We can only print all the elements in-line if all the
1203 // declarations inside are fields1246 // declarations inside are fields
1204 const src_has_only_fields = blk: {1247 const src_has_only_fields = blk: {
1205 var it = container_decl.fields_and_decls.iterator(0);1248 for (fields_and_decls) |decl| {
1206 while (it.next()) |decl| {1249 if (decl.id != .ContainerField) break :blk false;
1207 if (decl.*.id != .ContainerField) break :blk false;
1208 }1250 }
1209 break :blk true;1251 break :blk true;
1210 };1252 };
...@@ -1214,13 +1256,12 @@ fn renderExpression(...@@ -1214,13 +1256,12 @@ fn renderExpression(
1214 const new_indent = indent + indent_delta;1256 const new_indent = indent + indent_delta;
1215 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {1257 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {
12161258
1217 var it = container_decl.fields_and_decls.iterator(0);1259 for (fields_and_decls) |decl, i| {
1218 while (it.next()) |decl| {
1219 try stream.writeByteNTimes(' ', new_indent);1260 try stream.writeByteNTimes(' ', new_indent);
1220 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, .Newline);1261 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, .Newline);
12211262
1222 if (it.peek()) |next_decl| {1263 if (i + 1 < fields_and_decls.len) {
1223 try renderExtraNewline(tree, stream, start_col, next_decl.*);1264 try renderExtraNewline(tree, stream, start_col, fields_and_decls[i + 1]);
1224 }1265 }
1225 }1266 }
12261267
...@@ -1233,10 +1274,9 @@ fn renderExpression(...@@ -1233,10 +1274,9 @@ fn renderExpression(
1233 const new_indent = indent + indent_delta;1274 const new_indent = indent + indent_delta;
1234 try stream.writeByteNTimes(' ', new_indent);1275 try stream.writeByteNTimes(' ', new_indent);
12351276
1236 var it = container_decl.fields_and_decls.iterator(0);1277 for (fields_and_decls) |decl, i| {
1237 while (it.next()) |decl| {1278 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1238 const space_after_decl: Space = if (it.peek() == null) .Newline else .Space;1279 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, space_after_decl);
1239 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, space_after_decl);
1240 }1280 }
12411281
1242 try stream.writeByteNTimes(' ', indent);1282 try stream.writeByteNTimes(' ', indent);
...@@ -1244,9 +1284,8 @@ fn renderExpression(...@@ -1244,9 +1284,8 @@ fn renderExpression(
1244 // All the declarations on the same line1284 // All the declarations on the same line
1245 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // {1285 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // {
12461286
1247 var it = container_decl.fields_and_decls.iterator(0);1287 for (fields_and_decls) |decl| {
1248 while (it.next()) |decl| {1288 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Space);
1249 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl.*, .Space);
1250 }1289 }
1251 }1290 }
12521291
...@@ -1258,14 +1297,14 @@ fn renderExpression(...@@ -1258,14 +1297,14 @@ fn renderExpression(
12581297
1259 const lbrace = tree.nextToken(err_set_decl.error_token);1298 const lbrace = tree.nextToken(err_set_decl.error_token);
12601299
1261 if (err_set_decl.decls.len == 0) {1300 if (err_set_decl.decls_len == 0) {
1262 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);1301 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
1263 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);1302 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
1264 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);1303 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
1265 }1304 }
12661305
1267 if (err_set_decl.decls.len == 1) blk: {1306 if (err_set_decl.decls_len == 1) blk: {
1268 const node = err_set_decl.decls.at(0).*;1307 const node = err_set_decl.decls()[0];
12691308
1270 // if there are any doc comments or same line comments1309 // if there are any doc comments or same line comments
1271 // don't try to put it all on one line1310 // don't try to put it all on one line
...@@ -1285,24 +1324,24 @@ fn renderExpression(...@@ -1285,24 +1324,24 @@ fn renderExpression(
12851324
1286 const src_has_trailing_comma = blk: {1325 const src_has_trailing_comma = blk: {
1287 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);1326 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1288 break :blk tree.tokens.at(maybe_comma).id == .Comma;1327 break :blk tree.token_ids[maybe_comma] == .Comma;
1289 };1328 };
12901329
1291 if (src_has_trailing_comma) {1330 if (src_has_trailing_comma) {
1292 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {1331 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
1293 const new_indent = indent + indent_delta;1332 const new_indent = indent + indent_delta;
12941333
1295 var it = err_set_decl.decls.iterator(0);1334 const decls = err_set_decl.decls();
1296 while (it.next()) |node| {1335 for (decls) |node, i| {
1297 try stream.writeByteNTimes(' ', new_indent);1336 try stream.writeByteNTimes(' ', new_indent);
12981337
1299 if (it.peek()) |next_node| {1338 if (i + 1 < decls.len) {
1300 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None);1339 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
1301 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // ,1340 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,
13021341
1303 try renderExtraNewline(tree, stream, start_col, next_node.*);1342 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
1304 } else {1343 } else {
1305 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);1344 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
1306 }1345 }
1307 }1346 }
13081347
...@@ -1311,17 +1350,17 @@ fn renderExpression(...@@ -1311,17 +1350,17 @@ fn renderExpression(
1311 } else {1350 } else {
1312 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {1351 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
13131352
1314 var it = err_set_decl.decls.iterator(0);1353 const decls = err_set_decl.decls();
1315 while (it.next()) |node| {1354 for (decls) |node, i| {
1316 if (it.peek()) |next_node| {1355 if (i + 1 < decls.len) {
1317 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);1356 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
13181357
1319 const comma_token = tree.nextToken(node.*.lastToken());1358 const comma_token = tree.nextToken(node.lastToken());
1320 assert(tree.tokens.at(comma_token).id == .Comma);1359 assert(tree.token_ids[comma_token] == .Comma);
1321 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1360 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1322 try renderExtraNewline(tree, stream, start_col, next_node.*);1361 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
1323 } else {1362 } else {
1324 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space);1363 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
1325 }1364 }
1326 }1365 }
13271366
...@@ -1342,14 +1381,12 @@ fn renderExpression(...@@ -1342,14 +1381,12 @@ fn renderExpression(
1342 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);1381 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
13431382
1344 var skip_first_indent = true;1383 var skip_first_indent = true;
1345 if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != .LineComment) {1384 if (tree.token_ids[multiline_str_literal.firstToken() - 1] != .LineComment) {
1346 try stream.print("\n", .{});1385 try stream.print("\n", .{});
1347 skip_first_indent = false;1386 skip_first_indent = false;
1348 }1387 }
13491388
1350 var i: usize = 0;1389 for (multiline_str_literal.lines()) |t| {
1351 while (i < multiline_str_literal.lines.len) : (i += 1) {
1352 const t = multiline_str_literal.lines.at(i).*;
1353 if (!skip_first_indent) {1390 if (!skip_first_indent) {
1354 try stream.writeByteNTimes(' ', indent + indent_delta);1391 try stream.writeByteNTimes(' ', indent + indent_delta);
1355 }1392 }
...@@ -1369,10 +1406,10 @@ fn renderExpression(...@@ -1369,10 +1406,10 @@ fn renderExpression(
1369 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name1406 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
13701407
1371 const src_params_trailing_comma = blk: {1408 const src_params_trailing_comma = blk: {
1372 if (builtin_call.params.len < 2) break :blk false;1409 if (builtin_call.params_len < 2) break :blk false;
1373 const last_node = builtin_call.params.at(builtin_call.params.len - 1).*;1410 const last_node = builtin_call.params()[builtin_call.params_len - 1];
1374 const maybe_comma = tree.nextToken(last_node.lastToken());1411 const maybe_comma = tree.nextToken(last_node.lastToken());
1375 break :blk tree.tokens.at(maybe_comma).id == .Comma;1412 break :blk tree.token_ids[maybe_comma] == .Comma;
1376 };1413 };
13771414
1378 const lparen = tree.nextToken(builtin_call.builtin_token);1415 const lparen = tree.nextToken(builtin_call.builtin_token);
...@@ -1381,12 +1418,12 @@ fn renderExpression(...@@ -1381,12 +1418,12 @@ fn renderExpression(
1381 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1418 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
13821419
1383 // render all on one line, no trailing comma1420 // render all on one line, no trailing comma
1384 var it = builtin_call.params.iterator(0);1421 const params = builtin_call.params();
1385 while (it.next()) |param_node| {1422 for (params) |param_node, i| {
1386 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);1423 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
13871424
1388 if (it.peek() != null) {1425 if (i + 1 < params.len) {
1389 const comma_token = tree.nextToken(param_node.*.lastToken());1426 const comma_token = tree.nextToken(param_node.lastToken());
1390 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1427 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1391 }1428 }
1392 }1429 }
...@@ -1395,10 +1432,9 @@ fn renderExpression(...@@ -1395,10 +1432,9 @@ fn renderExpression(
1395 const new_indent = indent + indent_delta;1432 const new_indent = indent + indent_delta;
1396 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1433 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
13971434
1398 var it = builtin_call.params.iterator(0);1435 for (builtin_call.params()) |param_node| {
1399 while (it.next()) |param_node| {
1400 try stream.writeByteNTimes(' ', new_indent);1436 try stream.writeByteNTimes(' ', new_indent);
1401 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.Comma);1437 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
1402 }1438 }
1403 try stream.writeByteNTimes(' ', indent);1439 try stream.writeByteNTimes(' ', indent);
1404 }1440 }
...@@ -1410,8 +1446,8 @@ fn renderExpression(...@@ -1410,8 +1446,8 @@ fn renderExpression(
1410 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);1446 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14111447
1412 if (fn_proto.visib_token) |visib_token_index| {1448 if (fn_proto.visib_token) |visib_token_index| {
1413 const visib_token = tree.tokens.at(visib_token_index);1449 const visib_token = tree.token_ids[visib_token_index];
1414 assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export);1450 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14151451
1416 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub1452 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
1417 }1453 }
...@@ -1433,7 +1469,7 @@ fn renderExpression(...@@ -1433,7 +1469,7 @@ fn renderExpression(
1433 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1469 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1434 break :blk tree.nextToken(fn_proto.fn_token);1470 break :blk tree.nextToken(fn_proto.fn_token);
1435 };1471 };
1436 assert(tree.tokens.at(lparen).id == .LParen);1472 assert(tree.token_ids[lparen] == .LParen);
14371473
1438 const rparen = tree.prevToken(1474 const rparen = tree.prevToken(
1439 // the first token for the annotation expressions is the left1475 // the first token for the annotation expressions is the left
...@@ -1449,10 +1485,10 @@ fn renderExpression(...@@ -1449,10 +1485,10 @@ fn renderExpression(
1449 .InferErrorSet => |node| tree.prevToken(node.firstToken()),1485 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1450 .Invalid => unreachable,1486 .Invalid => unreachable,
1451 });1487 });
1452 assert(tree.tokens.at(rparen).id == .RParen);1488 assert(tree.token_ids[rparen] == .RParen);
14531489
1454 const src_params_trailing_comma = blk: {1490 const src_params_trailing_comma = blk: {
1455 const maybe_comma = tree.tokens.at(rparen - 1).id;1491 const maybe_comma = tree.token_ids[rparen - 1];
1456 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;1492 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
1457 };1493 };
14581494
...@@ -1460,12 +1496,11 @@ fn renderExpression(...@@ -1460,12 +1496,11 @@ fn renderExpression(
1460 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1496 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
14611497
1462 // render all on one line, no trailing comma1498 // render all on one line, no trailing comma
1463 var it = fn_proto.params.iterator(0);1499 for (fn_proto.params()) |param_decl, i| {
1464 while (it.next()) |param_decl_node| {1500 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
1465 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node.*, Space.None);
14661501
1467 if (it.peek() != null) {1502 if (i + 1 < fn_proto.params_len) {
1468 const comma = tree.nextToken(param_decl_node.*.lastToken());1503 const comma = tree.nextToken(param_decl.lastToken());
1469 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,1504 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
1470 }1505 }
1471 }1506 }
...@@ -1474,10 +1509,9 @@ fn renderExpression(...@@ -1474,10 +1509,9 @@ fn renderExpression(
1474 const new_indent = indent + indent_delta;1509 const new_indent = indent + indent_delta;
1475 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1510 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
14761511
1477 var it = fn_proto.params.iterator(0);1512 for (fn_proto.params()) |param_decl| {
1478 while (it.next()) |param_decl_node| {
1479 try stream.writeByteNTimes(' ', new_indent);1513 try stream.writeByteNTimes(' ', new_indent);
1480 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl_node.*, Space.Comma);1514 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1481 }1515 }
1482 try stream.writeByteNTimes(' ', indent);1516 try stream.writeByteNTimes(' ', indent);
1483 }1517 }
...@@ -1556,7 +1590,7 @@ fn renderExpression(...@@ -1556,7 +1590,7 @@ fn renderExpression(
1556 const rparen = tree.nextToken(switch_node.expr.lastToken());1590 const rparen = tree.nextToken(switch_node.expr.lastToken());
1557 const lbrace = tree.nextToken(rparen);1591 const lbrace = tree.nextToken(rparen);
15581592
1559 if (switch_node.cases.len == 0) {1593 if (switch_node.cases_len == 0) {
1560 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1594 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1561 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1595 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1562 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1596 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
...@@ -1570,13 +1604,13 @@ fn renderExpression(...@@ -1570,13 +1604,13 @@ fn renderExpression(
1570 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1604 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1571 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {1605 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
15721606
1573 var it = switch_node.cases.iterator(0);1607 const cases = switch_node.cases();
1574 while (it.next()) |node| {1608 for (cases) |node, i| {
1575 try stream.writeByteNTimes(' ', new_indent);1609 try stream.writeByteNTimes(' ', new_indent);
1576 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);1610 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
15771611
1578 if (it.peek()) |next_node| {1612 if (i + 1 < cases.len) {
1579 try renderExtraNewline(tree, stream, start_col, next_node.*);1613 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
1580 }1614 }
1581 }1615 }
15821616
...@@ -1587,38 +1621,38 @@ fn renderExpression(...@@ -1587,38 +1621,38 @@ fn renderExpression(
1587 .SwitchCase => {1621 .SwitchCase => {
1588 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);1622 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
15891623
1590 assert(switch_case.items.len != 0);1624 assert(switch_case.items_len != 0);
1591 const src_has_trailing_comma = blk: {1625 const src_has_trailing_comma = blk: {
1592 const last_node = switch_case.items.at(switch_case.items.len - 1).*;1626 const last_node = switch_case.items()[switch_case.items_len - 1];
1593 const maybe_comma = tree.nextToken(last_node.lastToken());1627 const maybe_comma = tree.nextToken(last_node.lastToken());
1594 break :blk tree.tokens.at(maybe_comma).id == .Comma;1628 break :blk tree.token_ids[maybe_comma] == .Comma;
1595 };1629 };
15961630
1597 if (switch_case.items.len == 1 or !src_has_trailing_comma) {1631 if (switch_case.items_len == 1 or !src_has_trailing_comma) {
1598 var it = switch_case.items.iterator(0);1632 const items = switch_case.items();
1599 while (it.next()) |node| {1633 for (items) |node, i| {
1600 if (it.peek()) |next_node| {1634 if (i + 1 < items.len) {
1601 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);1635 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
16021636
1603 const comma_token = tree.nextToken(node.*.lastToken());1637 const comma_token = tree.nextToken(node.lastToken());
1604 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1638 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1605 try renderExtraNewline(tree, stream, start_col, next_node.*);1639 try renderExtraNewline(tree, stream, start_col, items[i + 1]);
1606 } else {1640 } else {
1607 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space);1641 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
1608 }1642 }
1609 }1643 }
1610 } else {1644 } else {
1611 var it = switch_case.items.iterator(0);1645 const items = switch_case.items();
1612 while (it.next()) |node| {1646 for (items) |node, i| {
1613 if (it.peek()) |next_node| {1647 if (i + 1 < items.len) {
1614 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);1648 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
16151649
1616 const comma_token = tree.nextToken(node.*.lastToken());1650 const comma_token = tree.nextToken(node.lastToken());
1617 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,1651 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,
1618 try renderExtraNewline(tree, stream, start_col, next_node.*);1652 try renderExtraNewline(tree, stream, start_col, items[i + 1]);
1619 try stream.writeByteNTimes(' ', indent);1653 try stream.writeByteNTimes(' ', indent);
1620 } else {1654 } else {
1621 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma);1655 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);
1622 try stream.writeByteNTimes(' ', indent);1656 try stream.writeByteNTimes(' ', indent);
1623 }1657 }
1624 }1658 }
...@@ -1918,34 +1952,31 @@ fn renderExpression(...@@ -1918,34 +1952,31 @@ fn renderExpression(
1918 } else blk: {1952 } else blk: {
1919 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :1953 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
19201954
1921 var it = asm_node.outputs.iterator(0);1955 for (asm_node.outputs) |*asm_output, i| {
1922 while (true) {1956 if (i + 1 < asm_node.outputs.len) {
1923 const asm_output = it.next().?;1957 const next_asm_output = asm_node.outputs[i + 1];
1924 const node = &(asm_output.*).base;1958 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
19251959
1926 if (it.peek()) |next_asm_output| {1960 const comma = tree.prevToken(next_asm_output.firstToken());
1927 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
1928 const next_node = &(next_asm_output.*).base;
1929
1930 const comma = tree.prevToken(next_asm_output.*.firstToken());
1931 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1961 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
1932 try renderExtraNewline(tree, stream, start_col, next_node);1962 try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
19331963
1934 try stream.writeByteNTimes(' ', indent_extra);1964 try stream.writeByteNTimes(' ', indent_extra);
1935 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {1965 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1936 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1966 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
1937 try stream.writeByteNTimes(' ', indent);1967 try stream.writeByteNTimes(' ', indent);
1938 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);1968 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1939 } else {1969 } else {
1940 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1970 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
1941 try stream.writeByteNTimes(' ', indent_once);1971 try stream.writeByteNTimes(' ', indent_once);
1942 const comma_or_colon = tree.nextToken(node.lastToken());1972 const comma_or_colon = tree.nextToken(asm_output.lastToken());
1943 break :blk switch (tree.tokens.at(comma_or_colon).id) {1973 break :blk switch (tree.token_ids[comma_or_colon]) {
1944 .Comma => tree.nextToken(comma_or_colon),1974 .Comma => tree.nextToken(comma_or_colon),
1945 else => comma_or_colon,1975 else => comma_or_colon,
1946 };1976 };
1947 }1977 }
1948 }1978 }
1979 unreachable;
1949 };1980 };
19501981
1951 const colon3 = if (asm_node.inputs.len == 0) blk: {1982 const colon3 = if (asm_node.inputs.len == 0) blk: {
...@@ -1956,43 +1987,37 @@ fn renderExpression(...@@ -1956,43 +1987,37 @@ fn renderExpression(
1956 } else blk: {1987 } else blk: {
1957 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :1988 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
19581989
1959 var it = asm_node.inputs.iterator(0);1990 for (asm_node.inputs) |*asm_input, i| {
1960 while (true) {1991 if (i + 1 < asm_node.inputs.len) {
1961 const asm_input = it.next().?;1992 const next_asm_input = &asm_node.inputs[i + 1];
1962 const node = &(asm_input.*).base;1993 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
1963
1964 if (it.peek()) |next_asm_input| {
1965 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
1966 const next_node = &(next_asm_input.*).base;
19671994
1968 const comma = tree.prevToken(next_asm_input.*.firstToken());1995 const comma = tree.prevToken(next_asm_input.firstToken());
1969 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1996 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
1970 try renderExtraNewline(tree, stream, start_col, next_node);1997 try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());
19711998
1972 try stream.writeByteNTimes(' ', indent_extra);1999 try stream.writeByteNTimes(' ', indent_extra);
1973 } else if (asm_node.clobbers.len == 0) {2000 } else if (asm_node.clobbers.len == 0) {
1974 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);2001 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
1975 try stream.writeByteNTimes(' ', indent);2002 try stream.writeByteNTimes(' ', indent);
1976 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )2003 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
1977 } else {2004 } else {
1978 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);2005 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
1979 try stream.writeByteNTimes(' ', indent_once);2006 try stream.writeByteNTimes(' ', indent_once);
1980 const comma_or_colon = tree.nextToken(node.lastToken());2007 const comma_or_colon = tree.nextToken(asm_input.lastToken());
1981 break :blk switch (tree.tokens.at(comma_or_colon).id) {2008 break :blk switch (tree.token_ids[comma_or_colon]) {
1982 .Comma => tree.nextToken(comma_or_colon),2009 .Comma => tree.nextToken(comma_or_colon),
1983 else => comma_or_colon,2010 else => comma_or_colon,
1984 };2011 };
1985 }2012 }
1986 }2013 }
2014 unreachable;
1987 };2015 };
19882016
1989 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :2017 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
19902018
1991 var it = asm_node.clobbers.iterator(0);2019 for (asm_node.clobbers) |clobber_node, i| {
1992 while (true) {2020 if (i + 1 >= asm_node.clobbers.len) {
1993 const clobber_node = it.next().?.*;
1994
1995 if (it.peek() == null) {
1996 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);2021 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
1997 try stream.writeByteNTimes(' ', indent);2022 try stream.writeByteNTimes(' ', indent);
1998 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);2023 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
...@@ -2004,40 +2029,6 @@ fn renderExpression(...@@ -2004,40 +2029,6 @@ fn renderExpression(
2004 }2029 }
2005 },2030 },
20062031
2007 .AsmInput => {
2008 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
2009
2010 try stream.writeAll("[");
2011 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2012 try stream.writeAll("] ");
2013 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2014 try stream.writeAll(" (");
2015 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2016 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2017 },
2018
2019 .AsmOutput => {
2020 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
2021
2022 try stream.writeAll("[");
2023 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2024 try stream.writeAll("] ");
2025 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2026 try stream.writeAll(" (");
2027
2028 switch (asm_output.kind) {
2029 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
2030 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2031 },
2032 ast.Node.AsmOutput.Kind.Return => |return_type| {
2033 try stream.writeAll("-> ");
2034 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2035 },
2036 }
2037
2038 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
2039 },
2040
2041 .EnumLiteral => {2032 .EnumLiteral => {
2042 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);2033 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
20432034
...@@ -2050,11 +2041,56 @@ fn renderExpression(...@@ -2050,11 +2041,56 @@ fn renderExpression(
2050 .VarDecl,2041 .VarDecl,
2051 .Use,2042 .Use,
2052 .TestDecl,2043 .TestDecl,
2053 .ParamDecl,
2054 => unreachable,2044 => unreachable,
2055 }2045 }
2056}2046}
20572047
2048fn renderAsmOutput(
2049 allocator: *mem.Allocator,
2050 stream: var,
2051 tree: *ast.Tree,
2052 indent: usize,
2053 start_col: *usize,
2054 asm_output: *const ast.Node.Asm.Output,
2055 space: Space,
2056) (@TypeOf(stream).Error || Error)!void {
2057 try stream.writeAll("[");
2058 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2059 try stream.writeAll("] ");
2060 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2061 try stream.writeAll(" (");
2062
2063 switch (asm_output.kind) {
2064 ast.Node.Asm.Output.Kind.Variable => |variable_name| {
2065 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2066 },
2067 ast.Node.Asm.Output.Kind.Return => |return_type| {
2068 try stream.writeAll("-> ");
2069 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2070 },
2071 }
2072
2073 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
2074}
2075
2076fn renderAsmInput(
2077 allocator: *mem.Allocator,
2078 stream: var,
2079 tree: *ast.Tree,
2080 indent: usize,
2081 start_col: *usize,
2082 asm_input: *const ast.Node.Asm.Input,
2083 space: Space,
2084) (@TypeOf(stream).Error || Error)!void {
2085 try stream.writeAll("[");
2086 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2087 try stream.writeAll("] ");
2088 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2089 try stream.writeAll(" (");
2090 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2091 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2092}
2093
2058fn renderVarDecl(2094fn renderVarDecl(
2059 allocator: *mem.Allocator,2095 allocator: *mem.Allocator,
2060 stream: var,2096 stream: var,
...@@ -2133,11 +2169,9 @@ fn renderParamDecl(...@@ -2133,11 +2169,9 @@ fn renderParamDecl(
2133 tree: *ast.Tree,2169 tree: *ast.Tree,
2134 indent: usize,2170 indent: usize,
2135 start_col: *usize,2171 start_col: *usize,
2136 base: *ast.Node,2172 param_decl: ast.Node.FnProto.ParamDecl,
2137 space: Space,2173 space: Space,
2138) (@TypeOf(stream).Error || Error)!void {2174) (@TypeOf(stream).Error || Error)!void {
2139 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
2140
2141 try renderDocComments(tree, stream, param_decl, indent, start_col);2175 try renderDocComments(tree, stream, param_decl, indent, start_col);
21422176
2143 if (param_decl.comptime_token) |comptime_token| {2177 if (param_decl.comptime_token) |comptime_token| {
...@@ -2174,7 +2208,7 @@ fn renderStatement(...@@ -2174,7 +2208,7 @@ fn renderStatement(
2174 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);2208 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
21752209
2176 const semicolon_index = tree.nextToken(base.lastToken());2210 const semicolon_index = tree.nextToken(base.lastToken());
2177 assert(tree.tokens.at(semicolon_index).id == .Semicolon);2211 assert(tree.token_ids[semicolon_index] == .Semicolon);
2178 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);2212 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
2179 } else {2213 } else {
2180 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);2214 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
...@@ -2212,22 +2246,25 @@ fn renderTokenOffset(...@@ -2212,22 +2246,25 @@ fn renderTokenOffset(
2212 return;2246 return;
2213 }2247 }
22142248
2215 var token = tree.tokens.at(token_index);2249 var token_loc = tree.token_locs[token_index];
2216 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));2250 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
22172251
2218 if (space == Space.NoComment)2252 if (space == Space.NoComment)
2219 return;2253 return;
22202254
2221 var next_token = tree.tokens.at(token_index + 1);2255 var next_token_id = tree.token_ids[token_index + 1];
2256 var next_token_loc = tree.token_locs[token_index + 1];
22222257
2223 if (space == Space.Comma) switch (next_token.id) {2258 if (space == Space.Comma) switch (next_token_id) {
2224 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),2259 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
2225 .LineComment => {2260 .LineComment => {
2226 try stream.writeAll(", ");2261 try stream.writeAll(", ");
2227 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);2262 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
2228 },2263 },
2229 else => {2264 else => {
2230 if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) {2265 if (token_index + 2 < tree.token_ids.len and
2266 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
2267 {
2231 try stream.writeAll(",");2268 try stream.writeAll(",");
2232 return;2269 return;
2233 } else {2270 } else {
...@@ -2240,19 +2277,20 @@ fn renderTokenOffset(...@@ -2240,19 +2277,20 @@ fn renderTokenOffset(
22402277
2241 // Skip over same line doc comments2278 // Skip over same line doc comments
2242 var offset: usize = 1;2279 var offset: usize = 1;
2243 if (next_token.id == .DocComment) {2280 if (next_token_id == .DocComment) {
2244 const loc = tree.tokenLocationPtr(token.end, next_token);2281 const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2245 if (loc.line == 0) {2282 if (loc.line == 0) {
2246 offset += 1;2283 offset += 1;
2247 next_token = tree.tokens.at(token_index + offset);2284 next_token_id = tree.token_ids[token_index + offset];
2285 next_token_loc = tree.token_locs[token_index + offset];
2248 }2286 }
2249 }2287 }
22502288
2251 if (next_token.id != .LineComment) blk: {2289 if (next_token_id != .LineComment) blk: {
2252 switch (space) {2290 switch (space) {
2253 Space.None, Space.NoNewline => return,2291 Space.None, Space.NoNewline => return,
2254 Space.Newline => {2292 Space.Newline => {
2255 if (next_token.id == .MultilineStringLiteralLine) {2293 if (next_token_id == .MultilineStringLiteralLine) {
2256 return;2294 return;
2257 } else {2295 } else {
2258 try stream.writeAll("\n");2296 try stream.writeAll("\n");
...@@ -2261,7 +2299,7 @@ fn renderTokenOffset(...@@ -2261,7 +2299,7 @@ fn renderTokenOffset(
2261 }2299 }
2262 },2300 },
2263 Space.Space, Space.SpaceOrOutdent => {2301 Space.Space, Space.SpaceOrOutdent => {
2264 if (next_token.id == .MultilineStringLiteralLine)2302 if (next_token_id == .MultilineStringLiteralLine)
2265 return;2303 return;
2266 try stream.writeByte(' ');2304 try stream.writeByte(' ');
2267 return;2305 return;
...@@ -2271,14 +2309,15 @@ fn renderTokenOffset(...@@ -2271,14 +2309,15 @@ fn renderTokenOffset(
2271 }2309 }
22722310
2273 while (true) {2311 while (true) {
2274 const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2;2312 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ").len == 2;
2275 if (comment_is_empty) {2313 if (comment_is_empty) {
2276 switch (space) {2314 switch (space) {
2277 Space.Newline => {2315 Space.Newline => {
2278 offset += 1;2316 offset += 1;
2279 token = next_token;2317 token_loc = next_token_loc;
2280 next_token = tree.tokens.at(token_index + offset);2318 next_token_id = tree.token_ids[token_index + offset];
2281 if (next_token.id != .LineComment) {2319 next_token_loc = tree.token_locs[token_index + offset];
2320 if (next_token_id != .LineComment) {
2282 try stream.writeByte('\n');2321 try stream.writeByte('\n');
2283 start_col.* = 0;2322 start_col.* = 0;
2284 return;2323 return;
...@@ -2291,18 +2330,19 @@ fn renderTokenOffset(...@@ -2291,18 +2330,19 @@ fn renderTokenOffset(
2291 }2330 }
2292 }2331 }
22932332
2294 var loc = tree.tokenLocationPtr(token.end, next_token);2333 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2295 if (loc.line == 0) {2334 if (loc.line == 0) {
2296 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")});2335 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
2297 offset = 2;2336 offset = 2;
2298 token = next_token;2337 token_loc = next_token_loc;
2299 next_token = tree.tokens.at(token_index + offset);2338 next_token_loc = tree.token_locs[token_index + offset];
2300 if (next_token.id != .LineComment) {2339 next_token_id = tree.token_ids[token_index + offset];
2340 if (next_token_id != .LineComment) {
2301 switch (space) {2341 switch (space) {
2302 Space.None, Space.Space => {2342 Space.None, Space.Space => {
2303 try stream.writeByte('\n');2343 try stream.writeByte('\n');
2304 const after_comment_token = tree.tokens.at(token_index + offset);2344 const after_comment_token = tree.token_ids[token_index + offset];
2305 const next_line_indent = switch (after_comment_token.id) {2345 const next_line_indent = switch (after_comment_token) {
2306 .RParen, .RBrace, .RBracket => indent,2346 .RParen, .RBrace, .RBracket => indent,
2307 else => indent + indent_delta,2347 else => indent + indent_delta,
2308 };2348 };
...@@ -2315,7 +2355,7 @@ fn renderTokenOffset(...@@ -2315,7 +2355,7 @@ fn renderTokenOffset(
2315 start_col.* = indent;2355 start_col.* = indent;
2316 },2356 },
2317 Space.Newline => {2357 Space.Newline => {
2318 if (next_token.id == .MultilineStringLiteralLine) {2358 if (next_token_id == .MultilineStringLiteralLine) {
2319 return;2359 return;
2320 } else {2360 } else {
2321 try stream.writeAll("\n");2361 try stream.writeAll("\n");
...@@ -2328,7 +2368,7 @@ fn renderTokenOffset(...@@ -2328,7 +2368,7 @@ fn renderTokenOffset(
2328 }2368 }
2329 return;2369 return;
2330 }2370 }
2331 loc = tree.tokenLocationPtr(token.end, next_token);2371 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2332 }2372 }
23332373
2334 while (true) {2374 while (true) {
...@@ -2338,15 +2378,16 @@ fn renderTokenOffset(...@@ -2338,15 +2378,16 @@ fn renderTokenOffset(
2338 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);2378 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2339 try stream.writeByteNTimes('\n', newline_count);2379 try stream.writeByteNTimes('\n', newline_count);
2340 try stream.writeByteNTimes(' ', indent);2380 try stream.writeByteNTimes(' ', indent);
2341 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));2381 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
23422382
2343 offset += 1;2383 offset += 1;
2344 token = next_token;2384 token_loc = next_token_loc;
2345 next_token = tree.tokens.at(token_index + offset);2385 next_token_loc = tree.token_locs[token_index + offset];
2346 if (next_token.id != .LineComment) {2386 next_token_id = tree.token_ids[token_index + offset];
2387 if (next_token_id != .LineComment) {
2347 switch (space) {2388 switch (space) {
2348 Space.Newline => {2389 Space.Newline => {
2349 if (next_token.id == .MultilineStringLiteralLine) {2390 if (next_token_id == .MultilineStringLiteralLine) {
2350 return;2391 return;
2351 } else {2392 } else {
2352 try stream.writeAll("\n");2393 try stream.writeAll("\n");
...@@ -2357,8 +2398,8 @@ fn renderTokenOffset(...@@ -2357,8 +2398,8 @@ fn renderTokenOffset(
2357 Space.None, Space.Space => {2398 Space.None, Space.Space => {
2358 try stream.writeByte('\n');2399 try stream.writeByte('\n');
23592400
2360 const after_comment_token = tree.tokens.at(token_index + offset);2401 const after_comment_token = tree.token_ids[token_index + offset];
2361 const next_line_indent = switch (after_comment_token.id) {2402 const next_line_indent = switch (after_comment_token) {
2362 .RParen, .RBrace, .RBracket => blk: {2403 .RParen, .RBrace, .RBracket => blk: {
2363 if (indent > indent_delta) {2404 if (indent > indent_delta) {
2364 break :blk indent - indent_delta;2405 break :blk indent - indent_delta;
...@@ -2381,7 +2422,7 @@ fn renderTokenOffset(...@@ -2381,7 +2422,7 @@ fn renderTokenOffset(
2381 }2422 }
2382 return;2423 return;
2383 }2424 }
2384 loc = tree.tokenLocationPtr(token.end, next_token);2425 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2385 }2426 }
2386}2427}
23872428
...@@ -2404,16 +2445,32 @@ fn renderDocComments(...@@ -2404,16 +2445,32 @@ fn renderDocComments(
2404 start_col: *usize,2445 start_col: *usize,
2405) (@TypeOf(stream).Error || Error)!void {2446) (@TypeOf(stream).Error || Error)!void {
2406 const comment = node.doc_comments orelse return;2447 const comment = node.doc_comments orelse return;
2407 var it = comment.lines.iterator(0);2448 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
2408 const first_token = node.firstToken();2449}
2409 while (it.next()) |line_token_index| {2450
2410 if (line_token_index.* < first_token) {2451fn renderDocCommentsToken(
2411 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline);2452 tree: *ast.Tree,
2412 try stream.writeByteNTimes(' ', indent);2453 stream: var,
2413 } else {2454 comment: *ast.Node.DocComment,
2414 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);2455 first_token: ast.TokenIndex,
2415 try stream.writeAll("\n");2456 indent: usize,
2416 try stream.writeByteNTimes(' ', indent);2457 start_col: *usize,
2458) (@TypeOf(stream).Error || Error)!void {
2459 var tok_i = comment.first_line;
2460 while (true) : (tok_i += 1) {
2461 switch (tree.token_ids[tok_i]) {
2462 .DocComment, .ContainerDocComment => {
2463 if (comment.first_line < first_token) {
2464 try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline);
2465 try stream.writeByteNTimes(' ', indent);
2466 } else {
2467 try renderToken(tree, stream, tok_i, indent, start_col, Space.NoComment);
2468 try stream.writeAll("\n");
2469 try stream.writeByteNTimes(' ', indent);
2470 }
2471 },
2472 .LineComment => continue,
2473 else => break,
2417 }2474 }
2418 }2475 }
2419}2476}
lib/std/zig/tokenizer.zig+18-10
...@@ -3,8 +3,12 @@ const mem = std.mem;...@@ -3,8 +3,12 @@ const mem = std.mem;
33
4pub const Token = struct {4pub const Token = struct {
5 id: Id,5 id: Id,
6 start: usize,6 loc: Loc,
7 end: usize,7
8 pub const Loc = struct {
9 start: usize,
10 end: usize,
11 };
812
9 pub const Keyword = struct {13 pub const Keyword = struct {
10 bytes: []const u8,14 bytes: []const u8,
...@@ -426,8 +430,10 @@ pub const Tokenizer = struct {...@@ -426,8 +430,10 @@ pub const Tokenizer = struct {
426 var state: State = .start;430 var state: State = .start;
427 var result = Token{431 var result = Token{
428 .id = .Eof,432 .id = .Eof,
429 .start = self.index,433 .loc = .{
430 .end = undefined,434 .start = self.index,
435 .end = undefined,
436 },
431 };437 };
432 var seen_escape_digits: usize = undefined;438 var seen_escape_digits: usize = undefined;
433 var remaining_code_units: usize = undefined;439 var remaining_code_units: usize = undefined;
...@@ -436,7 +442,7 @@ pub const Tokenizer = struct {...@@ -436,7 +442,7 @@ pub const Tokenizer = struct {
436 switch (state) {442 switch (state) {
437 .start => switch (c) {443 .start => switch (c) {
438 ' ', '\n', '\t', '\r' => {444 ' ', '\n', '\t', '\r' => {
439 result.start = self.index + 1;445 result.loc.start = self.index + 1;
440 },446 },
441 '"' => {447 '"' => {
442 state = .string_literal;448 state = .string_literal;
...@@ -686,7 +692,7 @@ pub const Tokenizer = struct {...@@ -686,7 +692,7 @@ pub const Tokenizer = struct {
686 .identifier => switch (c) {692 .identifier => switch (c) {
687 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},693 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
688 else => {694 else => {
689 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {695 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
690 result.id = id;696 result.id = id;
691 }697 }
692 break;698 break;
...@@ -1313,7 +1319,7 @@ pub const Tokenizer = struct {...@@ -1313,7 +1319,7 @@ pub const Tokenizer = struct {
1313 => {},1319 => {},
13141320
1315 .identifier => {1321 .identifier => {
1316 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {1322 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
1317 result.id = id;1323 result.id = id;
1318 }1324 }
1319 },1325 },
...@@ -1420,7 +1426,7 @@ pub const Tokenizer = struct {...@@ -1420,7 +1426,7 @@ pub const Tokenizer = struct {
1420 }1426 }
1421 }1427 }
14221428
1423 result.end = self.index;1429 result.loc.end = self.index;
1424 return result;1430 return result;
1425 }1431 }
14261432
...@@ -1430,8 +1436,10 @@ pub const Tokenizer = struct {...@@ -1430,8 +1436,10 @@ pub const Tokenizer = struct {
1430 if (invalid_length == 0) return;1436 if (invalid_length == 0) return;
1431 self.pending_invalid_token = .{1437 self.pending_invalid_token = .{
1432 .id = .Invalid,1438 .id = .Invalid,
1433 .start = self.index,1439 .loc = .{
1434 .end = self.index + invalid_length,1440 .start = self.index,
1441 .end = self.index + invalid_length,
1442 },
1435 };1443 };
1436 }1444 }
14371445
src-self-hosted/clang.zig+11-13
...@@ -22,7 +22,7 @@ pub const struct_ZigClangCompoundStmt = @Type(.Opaque);...@@ -22,7 +22,7 @@ pub const struct_ZigClangCompoundStmt = @Type(.Opaque);
22pub const struct_ZigClangConstantArrayType = @Type(.Opaque);22pub const struct_ZigClangConstantArrayType = @Type(.Opaque);
23pub const struct_ZigClangContinueStmt = @Type(.Opaque);23pub const struct_ZigClangContinueStmt = @Type(.Opaque);
24pub const struct_ZigClangDecayedType = @Type(.Opaque);24pub const struct_ZigClangDecayedType = @Type(.Opaque);
25pub const struct_ZigClangDecl = @Type(.Opaque);25pub const ZigClangDecl = @Type(.Opaque);
26pub const struct_ZigClangDeclRefExpr = @Type(.Opaque);26pub const struct_ZigClangDeclRefExpr = @Type(.Opaque);
27pub const struct_ZigClangDeclStmt = @Type(.Opaque);27pub const struct_ZigClangDeclStmt = @Type(.Opaque);
28pub const struct_ZigClangDefaultStmt = @Type(.Opaque);28pub const struct_ZigClangDefaultStmt = @Type(.Opaque);
...@@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque);...@@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque);
63pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque);63pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque);
64pub const struct_ZigClangSourceManager = @Type(.Opaque);64pub const struct_ZigClangSourceManager = @Type(.Opaque);
65pub const struct_ZigClangSourceRange = @Type(.Opaque);65pub const struct_ZigClangSourceRange = @Type(.Opaque);
66pub const struct_ZigClangStmt = @Type(.Opaque);66pub const ZigClangStmt = @Type(.Opaque);
67pub const struct_ZigClangStringLiteral = @Type(.Opaque);67pub const struct_ZigClangStringLiteral = @Type(.Opaque);
68pub const struct_ZigClangStringRef = @Type(.Opaque);68pub const struct_ZigClangStringRef = @Type(.Opaque);
69pub const struct_ZigClangSwitchStmt = @Type(.Opaque);69pub const struct_ZigClangSwitchStmt = @Type(.Opaque);
...@@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla...@@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla
781pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;781pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
782pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;782pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
783pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;783pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
784pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?fn (?*c_void, *const struct_ZigClangDecl) callconv(.C) bool) bool;784pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?fn (?*c_void, *const ZigClangDecl) callconv(.C) bool) bool;
785pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;785pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
786pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool;786pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool;
787pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;787pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;
...@@ -817,7 +817,7 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE...@@ -817,7 +817,7 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE
817pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;817pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;
818pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;818pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;
819pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool;819pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool;
820pub extern fn ZigClangDecl_castToNamedDecl(decl: *const struct_ZigClangDecl) ?*const ZigClangNamedDecl;820pub extern fn ZigClangDecl_castToNamedDecl(decl: *const ZigClangDecl) ?*const ZigClangNamedDecl;
821pub extern fn ZigClangNamedDecl_getName_bytes_begin(decl: ?*const struct_ZigClangNamedDecl) [*:0]const u8;821pub extern fn ZigClangNamedDecl_getName_bytes_begin(decl: ?*const struct_ZigClangNamedDecl) [*:0]const u8;
822pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;822pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
823pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;823pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
...@@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*...@@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*
842pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType;842pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType;
843pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType;843pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType;
844pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType;844pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType;
845pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;845pub extern fn ZigClangStmt_getBeginLoc(self: *const ZigClangStmt) struct_ZigClangSourceLocation;
846pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;846pub extern fn ZigClangStmt_getStmtClass(self: ?*const ZigClangStmt) ZigClangStmtClass;
847pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;847pub extern fn ZigClangStmt_classof_Expr(self: ?*const ZigClangStmt) bool;
848pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;848pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;
849pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;849pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;
850pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;850pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
...@@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl...@@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl
873pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool;873pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool;
874pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass;874pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass;
875pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl;875pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl;
876pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt;876pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const ZigClangStmt;
877pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool;877pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool;
878pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool;878pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool;
879pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool;879pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool;
...@@ -918,7 +918,6 @@ pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt;...@@ -918,7 +918,6 @@ pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt;
918pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType;918pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType;
919pub const ZigClangContinueStmt = struct_ZigClangContinueStmt;919pub const ZigClangContinueStmt = struct_ZigClangContinueStmt;
920pub const ZigClangDecayedType = struct_ZigClangDecayedType;920pub const ZigClangDecayedType = struct_ZigClangDecayedType;
921pub const ZigClangDecl = struct_ZigClangDecl;
922pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr;921pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr;
923pub const ZigClangDeclStmt = struct_ZigClangDeclStmt;922pub const ZigClangDeclStmt = struct_ZigClangDeclStmt;
924pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt;923pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt;
...@@ -959,7 +958,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt;...@@ -959,7 +958,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt;
959pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope;958pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope;
960pub const ZigClangSourceManager = struct_ZigClangSourceManager;959pub const ZigClangSourceManager = struct_ZigClangSourceManager;
961pub const ZigClangSourceRange = struct_ZigClangSourceRange;960pub const ZigClangSourceRange = struct_ZigClangSourceRange;
962pub const ZigClangStmt = struct_ZigClangStmt;
963pub const ZigClangStringLiteral = struct_ZigClangStringLiteral;961pub const ZigClangStringLiteral = struct_ZigClangStringLiteral;
964pub const ZigClangStringRef = struct_ZigClangStringRef;962pub const ZigClangStringRef = struct_ZigClangStringRef;
965pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt;963pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt;
...@@ -1016,14 +1014,14 @@ pub extern fn ZigClangLoadFromCommandLine(...@@ -1016,14 +1014,14 @@ pub extern fn ZigClangLoadFromCommandLine(
1016) ?*ZigClangASTUnit;1014) ?*ZigClangASTUnit;
10171015
1018pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;1016pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;
1019pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8;1017pub extern fn ZigClangDecl_getDeclKindName(decl: *const ZigClangDecl) [*:0]const u8;
10201018
1021pub const ZigClangCompoundStmt_const_body_iterator = [*]const *struct_ZigClangStmt;1019pub const ZigClangCompoundStmt_const_body_iterator = [*]const *ZigClangStmt;
10221020
1023pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;1021pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
1024pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;1022pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
10251023
1026pub const ZigClangDeclStmt_const_decl_iterator = [*]const *struct_ZigClangDecl;1024pub const ZigClangDeclStmt_const_decl_iterator = [*]const *ZigClangDecl;
10271025
1028pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;1026pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
1029pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;1027pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
src-self-hosted/main.zig+8-10
...@@ -600,8 +600,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -600,8 +600,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
600 };600 };
601 defer tree.deinit();601 defer tree.deinit();
602602
603 var error_it = tree.errors.iterator(0);603 for (tree.errors) |parse_error| {
604 while (error_it.next()) |parse_error| {
605 try printErrMsgToFile(gpa, parse_error, tree, "<stdin>", stderr_file, color);604 try printErrMsgToFile(gpa, parse_error, tree, "<stdin>", stderr_file, color);
606 }605 }
607 if (tree.errors.len != 0) {606 if (tree.errors.len != 0) {
...@@ -701,8 +700,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {...@@ -701,8 +700,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
701 };700 };
702 defer tree.deinit();701 defer tree.deinit();
703702
704 var error_it = tree.errors.iterator(0);703 for (tree.errors) |parse_error| {
705 while (error_it.next()) |parse_error| {
706 try printErrMsgToFile(fmt.gpa, parse_error, tree, file_path, std.io.getStdErr(), fmt.color);704 try printErrMsgToFile(fmt.gpa, parse_error, tree, file_path, std.io.getStdErr(), fmt.color);
707 }705 }
708 if (tree.errors.len != 0) {706 if (tree.errors.len != 0) {
...@@ -730,7 +728,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {...@@ -730,7 +728,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
730728
731fn printErrMsgToFile(729fn printErrMsgToFile(
732 gpa: *mem.Allocator,730 gpa: *mem.Allocator,
733 parse_error: *const ast.Error,731 parse_error: ast.Error,
734 tree: *ast.Tree,732 tree: *ast.Tree,
735 path: []const u8,733 path: []const u8,
736 file: fs.File,734 file: fs.File,
...@@ -745,15 +743,15 @@ fn printErrMsgToFile(...@@ -745,15 +743,15 @@ fn printErrMsgToFile(
745 const span_first = lok_token;743 const span_first = lok_token;
746 const span_last = lok_token;744 const span_last = lok_token;
747745
748 const first_token = tree.tokens.at(span_first);746 const first_token = tree.token_locs[span_first];
749 const last_token = tree.tokens.at(span_last);747 const last_token = tree.token_locs[span_last];
750 const start_loc = tree.tokenLocationPtr(0, first_token);748 const start_loc = tree.tokenLocationLoc(0, first_token);
751 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);749 const end_loc = tree.tokenLocationLoc(first_token.end, last_token);
752750
753 var text_buf = std.ArrayList(u8).init(gpa);751 var text_buf = std.ArrayList(u8).init(gpa);
754 defer text_buf.deinit();752 defer text_buf.deinit();
755 const out_stream = text_buf.outStream();753 const out_stream = text_buf.outStream();
756 try parse_error.render(&tree.tokens, out_stream);754 try parse_error.render(tree.token_ids, out_stream);
757 const text = text_buf.span();755 const text = text_buf.span();
758756
759 const stream = file.outStream();757 const stream = file.outStream();
src-self-hosted/translate_c.zig+877-778
...@@ -37,10 +37,10 @@ fn addrEql(a: usize, b: usize) bool {...@@ -37,10 +37,10 @@ fn addrEql(a: usize, b: usize) bool {
37}37}
3838
39const SymbolTable = std.StringHashMap(*ast.Node);39const SymbolTable = std.StringHashMap(*ast.Node);
40const AliasList = std.SegmentedList(struct {40const AliasList = std.ArrayList(struct {
41 alias: []const u8,41 alias: []const u8,
42 name: []const u8,42 name: []const u8,
43}, 4);43});
4444
45const Scope = struct {45const Scope = struct {
46 id: Id,46 id: Id,
...@@ -54,50 +54,99 @@ const Scope = struct {...@@ -54,50 +54,99 @@ const Scope = struct {
54 Loop,54 Loop,
55 };55 };
5656
57 /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated.
58 /// When it is deinitialized, it produces an ast.Node.Switch which is allocated
59 /// into the main arena.
57 const Switch = struct {60 const Switch = struct {
58 base: Scope,61 base: Scope,
59 pending_block: *ast.Node.Block,62 pending_block: Block,
60 cases: *ast.Node.Switch.CaseList,63 cases: []*ast.Node,
64 case_index: usize,
61 has_default: bool = false,65 has_default: bool = false,
62 };66 };
6367
68 /// Used for the scope of condition expressions, for example `if (cond)`.
69 /// The block is lazily initialised because it is only needed for rare
70 /// cases of comma operators being used.
71 const Condition = struct {
72 base: Scope,
73 block: ?Block = null,
74
75 fn getBlockScope(self: *Condition, c: *Context) !*Block {
76 if (self.block) |*b| return b;
77 self.block = try Block.init(c, &self.base, "blk");
78 return &self.block.?;
79 }
80
81 fn deinit(self: *Condition) void {
82 if (self.block) |*b| b.deinit();
83 }
84 };
85
86 /// Represents an in-progress ast.Node.Block. This struct is stack-allocated.
87 /// When it is deinitialized, it produces an ast.Node.Block which is allocated
88 /// into the main arena.
64 const Block = struct {89 const Block = struct {
65 base: Scope,90 base: Scope,
66 block_node: *ast.Node.Block,91 statements: std.ArrayList(*ast.Node),
67 variables: AliasList,92 variables: AliasList,
68 label: ?[]const u8,93 label: ?ast.TokenIndex,
69 mangle_count: u32 = 0,94 mangle_count: u32 = 0,
95 lbrace: ast.TokenIndex,
7096
71 /// Don't forget to set rbrace token and block_node later97 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block {
72 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block {98 return Block{
73 const block = try c.a().create(Block);
74 block.* = .{
75 .base = .{99 .base = .{
76 .id = .Block,100 .id = .Block,
77 .parent = parent,101 .parent = parent,
78 },102 },
79 .block_node = undefined,103 .statements = std.ArrayList(*ast.Node).init(c.gpa),
80 .variables = AliasList.init(c.a()),104 .variables = AliasList.init(c.gpa),
81 .label = label,105 .label = if (label) |l| blk: {
106 const ll = try appendIdentifier(c, l);
107 _ = try appendToken(c, .Colon, ":");
108 break :blk ll;
109 } else null,
110 .lbrace = try appendToken(c, .LBrace, "{"),
82 };111 };
83 return block;112 }
113
114 fn deinit(self: *Block) void {
115 self.statements.deinit();
116 self.variables.deinit();
117 self.* = undefined;
118 }
119
120 fn complete(self: *Block, c: *Context) !*ast.Node.Block {
121 // We reserve 1 extra statement if the parent is a Loop. This is in case of
122 // do while, we want to put `if (cond) break;` at the end.
123 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
124 const node = try ast.Node.Block.alloc(c.arena, alloc_len);
125 node.* = .{
126 .statements_len = self.statements.items.len,
127 .lbrace = self.lbrace,
128 .rbrace = try appendToken(c, .RBrace, "}"),
129 .label = self.label,
130 };
131 mem.copy(*ast.Node, node.statements(), self.statements.items);
132 return node;
84 }133 }
85134
86 /// Given the desired name, return a name that does not shadow anything from outer scopes.135 /// Given the desired name, return a name that does not shadow anything from outer scopes.
87 /// Inserts the returned name into the scope.136 /// Inserts the returned name into the scope.
88 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {137 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
89 var proposed_name = name;138 const name_copy = try c.arena.dupe(u8, name);
139 var proposed_name = name_copy;
90 while (scope.contains(proposed_name)) {140 while (scope.contains(proposed_name)) {
91 scope.mangle_count += 1;141 scope.mangle_count += 1;
92 proposed_name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count });142 proposed_name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ name, scope.mangle_count });
93 }143 }
94 try scope.variables.push(.{ .name = name, .alias = proposed_name });144 try scope.variables.append(.{ .name = name_copy, .alias = proposed_name });
95 return proposed_name;145 return proposed_name;
96 }146 }
97147
98 fn getAlias(scope: *Block, name: []const u8) []const u8 {148 fn getAlias(scope: *Block, name: []const u8) []const u8 {
99 var it = scope.variables.iterator(0);149 for (scope.variables.items) |p| {
100 while (it.next()) |p| {
101 if (mem.eql(u8, p.name, name))150 if (mem.eql(u8, p.name, name))
102 return p.alias;151 return p.alias;
103 }152 }
...@@ -105,8 +154,7 @@ const Scope = struct {...@@ -105,8 +154,7 @@ const Scope = struct {
105 }154 }
106155
107 fn localContains(scope: *Block, name: []const u8) bool {156 fn localContains(scope: *Block, name: []const u8) bool {
108 var it = scope.variables.iterator(0);157 for (scope.variables.items) |p| {
109 while (it.next()) |p| {
110 if (mem.eql(u8, p.name, name))158 if (mem.eql(u8, p.name, name))
111 return true;159 return true;
112 }160 }
...@@ -132,8 +180,8 @@ const Scope = struct {...@@ -132,8 +180,8 @@ const Scope = struct {
132 .id = .Root,180 .id = .Root,
133 .parent = null,181 .parent = null,
134 },182 },
135 .sym_table = SymbolTable.init(c.a()),183 .sym_table = SymbolTable.init(c.arena),
136 .macro_table = SymbolTable.init(c.a()),184 .macro_table = SymbolTable.init(c.arena),
137 .context = c,185 .context = c,
138 };186 };
139 }187 }
...@@ -158,10 +206,7 @@ const Scope = struct {...@@ -158,10 +206,7 @@ const Scope = struct {
158 switch (scope.id) {206 switch (scope.id) {
159 .Root => unreachable,207 .Root => unreachable,
160 .Block => return @fieldParentPtr(Block, "base", scope),208 .Block => return @fieldParentPtr(Block, "base", scope),
161 .Condition => {209 .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),
162 // comma operator used
163 return try Block.init(c, scope, "blk");
164 },
165 else => scope = scope.parent.?,210 else => scope = scope.parent.?,
166 }211 }
167 }212 }
...@@ -208,7 +253,11 @@ const Scope = struct {...@@ -208,7 +253,11 @@ const Scope = struct {
208};253};
209254
210pub const Context = struct {255pub const Context = struct {
211 tree: *ast.Tree,256 gpa: *mem.Allocator,
257 arena: *mem.Allocator,
258 token_ids: std.ArrayListUnmanaged(Token.Id),
259 token_locs: std.ArrayListUnmanaged(Token.Loc),
260 errors: std.ArrayListUnmanaged(ast.Error),
212 source_buffer: *std.ArrayList(u8),261 source_buffer: *std.ArrayList(u8),
213 err: Error,262 err: Error,
214 source_manager: *ZigClangSourceManager,263 source_manager: *ZigClangSourceManager,
...@@ -217,6 +266,7 @@ pub const Context = struct {...@@ -217,6 +266,7 @@ pub const Context = struct {
217 global_scope: *Scope.Root,266 global_scope: *Scope.Root,
218 clang_context: *ZigClangASTContext,267 clang_context: *ZigClangASTContext,
219 mangle_count: u32 = 0,268 mangle_count: u32 = 0,
269 root_decls: std.ArrayListUnmanaged(*ast.Node),
220270
221 /// This one is different than the root scope's name table. This contains271 /// This one is different than the root scope's name table. This contains
222 /// a list of names that we found by visiting all the top level decls without272 /// a list of names that we found by visiting all the top level decls without
...@@ -229,13 +279,9 @@ pub const Context = struct {...@@ -229,13 +279,9 @@ pub const Context = struct {
229 return c.mangle_count;279 return c.mangle_count;
230 }280 }
231281
232 fn a(c: *Context) *mem.Allocator {
233 return &c.tree.arena_allocator.allocator;
234 }
235
236 /// Convert a null-terminated C string to a slice allocated in the arena282 /// Convert a null-terminated C string to a slice allocated in the arena
237 fn str(c: *Context, s: [*:0]const u8) ![]u8 {283 fn str(c: *Context, s: [*:0]const u8) ![]u8 {
238 return mem.dupe(c.a(), u8, mem.spanZ(s));284 return mem.dupe(c.arena, u8, mem.spanZ(s));
239 }285 }
240286
241 /// Convert a clang source location to a file:line:column string287 /// Convert a clang source location to a file:line:column string
...@@ -246,12 +292,52 @@ pub const Context = struct {...@@ -246,12 +292,52 @@ pub const Context = struct {
246292
247 const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc);293 const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc);
248 const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc);294 const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc);
249 return std.fmt.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column });295 return std.fmt.allocPrint(c.arena, "{}:{}:{}", .{ filename, line, column });
296 }
297
298 fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call {
299 _ = try appendToken(c, .LParen, "(");
300 const node = try ast.Node.Call.alloc(c.arena, params_len);
301 node.* = .{
302 .lhs = fn_expr,
303 .params_len = params_len,
304 .async_token = null,
305 .rtoken = undefined, // set after appending args
306 };
307 return node;
308 }
309
310 fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall {
311 const builtin_token = try appendToken(c, .Builtin, name);
312 _ = try appendToken(c, .LParen, "(");
313 const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len);
314 node.* = .{
315 .builtin_token = builtin_token,
316 .params_len = params_len,
317 .rparen_token = undefined, // set after appending args
318 };
319 return node;
320 }
321
322 fn createBlock(c: *Context, label: ?[]const u8, statements_len: ast.NodeIndex) !*ast.Node.Block {
323 const label_node = if (label) |l| blk: {
324 const ll = try appendIdentifier(c, l);
325 _ = try appendToken(c, .Colon, ":");
326 break :blk ll;
327 } else null;
328 const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
329 block_node.* = .{
330 .label = label_node,
331 .lbrace = try appendToken(c, .LBrace, "{"),
332 .statements_len = statements_len,
333 .rbrace = undefined,
334 };
335 return block_node;
250 }336 }
251};337};
252338
253pub fn translate(339pub fn translate(
254 backing_allocator: *mem.Allocator,340 gpa: *mem.Allocator,
255 args_begin: [*]?[*]const u8,341 args_begin: [*]?[*]const u8,
256 args_end: [*]?[*]const u8,342 args_end: [*]?[*]const u8,
257 errors: *[]ClangErrMsg,343 errors: *[]ClangErrMsg,
...@@ -269,47 +355,38 @@ pub fn translate(...@@ -269,47 +355,38 @@ pub fn translate(
269 };355 };
270 defer ZigClangASTUnit_delete(ast_unit);356 defer ZigClangASTUnit_delete(ast_unit);
271357
272 const tree = blk: {358 var source_buffer = std.ArrayList(u8).init(gpa);
273 var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);359 defer source_buffer.deinit();
274 errdefer tree_arena.deinit();
275
276 const tree = try tree_arena.allocator.create(ast.Tree);
277 tree.* = .{
278 .source = undefined, // need to use toOwnedSlice later
279 .root_node = undefined,
280 .arena_allocator = tree_arena,
281 .tokens = undefined, // can't reference the allocator yet
282 .errors = undefined, // can't reference the allocator yet
283 .generated = true,
284 };
285 break :blk tree;
286 };
287 const arena = &tree.arena_allocator.allocator; // now we can reference the allocator
288 errdefer tree.arena_allocator.deinit();
289 tree.tokens = ast.Tree.TokenList.init(arena);
290 tree.errors = ast.Tree.ErrorList.init(arena);
291
292 tree.root_node = try arena.create(ast.Node.Root);
293 tree.root_node.* = .{
294 .decls = ast.Node.Root.DeclList.init(arena),
295 // initialized with the eof token at the end
296 .eof_token = undefined,
297 };
298360
299 var source_buffer = std.ArrayList(u8).init(arena);361 // For memory that has the same lifetime as the Tree that we return
362 // from this function.
363 var arena = std.heap.ArenaAllocator.init(gpa);
364 errdefer arena.deinit();
300365
301 var context = Context{366 var context = Context{
302 .tree = tree,367 .gpa = gpa,
368 .arena = &arena.allocator,
303 .source_buffer = &source_buffer,369 .source_buffer = &source_buffer,
304 .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),370 .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),
305 .err = undefined,371 .err = undefined,
306 .decl_table = DeclTable.init(arena),372 .decl_table = DeclTable.init(gpa),
307 .alias_list = AliasList.init(arena),373 .alias_list = AliasList.init(gpa),
308 .global_scope = try arena.create(Scope.Root),374 .global_scope = try arena.allocator.create(Scope.Root),
309 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,375 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
310 .global_names = std.StringHashMap(void).init(arena),376 .global_names = std.StringHashMap(void).init(gpa),
377 .token_ids = .{},
378 .token_locs = .{},
379 .errors = .{},
380 .root_decls = .{},
311 };381 };
312 context.global_scope.* = Scope.Root.init(&context);382 context.global_scope.* = Scope.Root.init(&context);
383 defer context.decl_table.deinit();
384 defer context.alias_list.deinit();
385 defer context.token_ids.deinit(gpa);
386 defer context.token_locs.deinit(gpa);
387 defer context.errors.deinit(gpa);
388 defer context.global_names.deinit();
389 defer context.root_decls.deinit(gpa);
313390
314 try prepopulateGlobalNameTable(ast_unit, &context);391 try prepopulateGlobalNameTable(ast_unit, &context);
315392
...@@ -320,23 +397,34 @@ pub fn translate(...@@ -320,23 +397,34 @@ pub fn translate(
320 try transPreprocessorEntities(&context, ast_unit);397 try transPreprocessorEntities(&context, ast_unit);
321398
322 try addMacros(&context);399 try addMacros(&context);
323 var it = context.alias_list.iterator(0);400 for (context.alias_list.items) |alias| {
324 while (it.next()) |alias| {
325 if (!context.global_scope.sym_table.contains(alias.alias)) {401 if (!context.global_scope.sym_table.contains(alias.alias)) {
326 try createAlias(&context, alias);402 try createAlias(&context, alias);
327 }403 }
328 }404 }
329405
330 tree.root_node.eof_token = try appendToken(&context, .Eof, "");406 const eof_token = try appendToken(&context, .Eof, "");
331 tree.source = source_buffer.toOwnedSlice();407 const root_node = try ast.Node.Root.create(&arena.allocator, context.root_decls.items.len, eof_token);
408 mem.copy(*ast.Node, root_node.decls(), context.root_decls.items);
409
332 if (false) {410 if (false) {
333 std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{tree.source});411 std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{source_buffer.items});
334 var i: usize = 0;412 for (context.token_ids.items) |token| {
335 while (i < tree.tokens.len) : (i += 1) {
336 const token = tree.tokens.at(i);
337 std.debug.warn("{}\n", .{token});413 std.debug.warn("{}\n", .{token});
338 }414 }
339 }415 }
416
417 const tree = try arena.allocator.create(ast.Tree);
418 tree.* = .{
419 .gpa = gpa,
420 .source = try arena.allocator.dupe(u8, source_buffer.items),
421 .token_ids = context.token_ids.toOwnedSlice(gpa),
422 .token_locs = context.token_locs.toOwnedSlice(gpa),
423 .errors = context.errors.toOwnedSlice(gpa),
424 .root_node = root_node,
425 .arena = arena.state,
426 .generated = true,
427 };
340 return tree;428 return tree;
341}429}
342430
...@@ -490,42 +578,35 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -490,42 +578,35 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
490578
491 // actual function definition with body579 // actual function definition with body
492 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);580 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);
493 const block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null);581 var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null);
582 defer block_scope.deinit();
494 var scope = &block_scope.base;583 var scope = &block_scope.base;
495 const block_node = try transCreateNodeBlock(rp.c, null);
496 block_scope.block_node = block_node;
497584
498 var it = proto_node.params.iterator(0);
499 var param_id: c_uint = 0;585 var param_id: c_uint = 0;
500 while (it.next()) |p| {586 for (proto_node.params()) |*param, i| {
501 const param = @fieldParentPtr(ast.Node.ParamDecl, "base", p.*);
502 const param_name = if (param.name_token) |name_tok|587 const param_name = if (param.name_token) |name_tok|
503 tokenSlice(c, name_tok)588 tokenSlice(c, name_tok)
504 else if (param.param_type == .var_args) {589 else if (param.param_type == .var_args) {
505 assert(it.next() == null);590 assert(i + 1 == proto_node.params_len);
506 _ = proto_node.params.pop();591 proto_node.params_len -= 1;
507 break;592 break;
508 } else593 } else
509 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});594 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
510595
511 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
512
513 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);596 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
514 const qual_type = ZigClangParmVarDecl_getOriginalType(c_param);597 const qual_type = ZigClangParmVarDecl_getOriginalType(c_param);
515 const is_const = ZigClangQualType_isConstQualified(qual_type);598 const is_const = ZigClangQualType_isConstQualified(qual_type);
516599
517 const arg_name = blk: {600 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
518 const param_prefix = if (is_const) "" else "arg_";
519 const bare_arg_name = try std.fmt.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name });
520 break :blk try block_scope.makeMangledName(c, bare_arg_name);
521 };
522601
523 if (!is_const) {602 if (!is_const) {
603 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);
524 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);605 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);
525 node.eq_token = try appendToken(c, .Equal, "=");606 node.eq_token = try appendToken(c, .Equal, "=");
526 node.init_node = try transCreateNodeIdentifier(c, arg_name);607 node.init_node = try transCreateNodeIdentifier(c, arg_name);
527 node.semicolon_token = try appendToken(c, .Semicolon, ";");608 node.semicolon_token = try appendToken(c, .Semicolon, ";");
528 try block_node.statements.push(&node.base);609 try block_scope.statements.append(&node.base);
529 param.name_token = try appendIdentifier(c, arg_name);610 param.name_token = try appendIdentifier(c, arg_name);
530 _ = try appendToken(c, .Colon, ":");611 _ = try appendToken(c, .Colon, ":");
531 }612 }
...@@ -533,14 +614,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -533,14 +614,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
533 param_id += 1;614 param_id += 1;
534 }615 }
535616
536 transCompoundStmtInline(rp, &block_scope.base, @ptrCast(*const ZigClangCompoundStmt, body_stmt), block_node) catch |err| switch (err) {617 const casted_body = @ptrCast(*const ZigClangCompoundStmt, body_stmt);
618 transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
537 error.OutOfMemory => |e| return e,619 error.OutOfMemory => |e| return e,
538 error.UnsupportedTranslation,620 error.UnsupportedTranslation,
539 error.UnsupportedType,621 error.UnsupportedType,
540 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),622 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
541 };623 };
542 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");624 const body_node = try block_scope.complete(rp.c);
543 proto_node.body_node = &block_node.base;625 proto_node.body_node = &body_node.base;
544 return addTopLevelDecl(c, fn_name, &proto_node.base);626 return addTopLevelDecl(c, fn_name, &proto_node.base);
545}627}
546628
...@@ -560,7 +642,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -560,7 +642,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
560642
561 // TODO https://github.com/ziglang/zig/issues/3756643 // TODO https://github.com/ziglang/zig/issues/3756
562 // TODO https://github.com/ziglang/zig/issues/1802644 // TODO https://github.com/ziglang/zig/issues/1802
563 const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ var_name, c.getMangle() }) else var_name;645 const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ var_name, c.getMangle() }) else var_name;
564 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);646 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
565647
566 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);648 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
...@@ -620,7 +702,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -620,7 +702,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
620 _ = try appendToken(rp.c, .LParen, "(");702 _ = try appendToken(rp.c, .LParen, "(");
621 const expr = try transCreateNodeStringLiteral(703 const expr = try transCreateNodeStringLiteral(
622 rp.c,704 rp.c,
623 try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),705 try std.fmt.allocPrint(rp.c.arena, "\"{}\"", .{str_ptr[0..str_len]}),
624 );706 );
625 _ = try appendToken(rp.c, .RParen, ")");707 _ = try appendToken(rp.c, .RParen, ")");
626708
...@@ -643,7 +725,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -643,7 +725,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
643 break :blk null;725 break :blk null;
644 };726 };
645727
646 const node = try c.a().create(ast.Node.VarDecl);728 const node = try c.arena.create(ast.Node.VarDecl);
647 node.* = .{729 node.* = .{
648 .doc_comments = null,730 .doc_comments = null,
649 .visib_token = visib_tok,731 .visib_token = visib_tok,
...@@ -702,7 +784,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l...@@ -702,7 +784,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
702784
703 // TODO https://github.com/ziglang/zig/issues/3756785 // TODO https://github.com/ziglang/zig/issues/3756
704 // TODO https://github.com/ziglang/zig/issues/1802786 // TODO https://github.com/ziglang/zig/issues/1802
705 const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name;787 const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name;
706 if (checkForBuiltinTypedef(checked_name)) |builtin| {788 if (checkForBuiltinTypedef(checked_name)) |builtin| {
707 return transTypeDefAsBuiltin(c, typedef_decl, builtin);789 return transTypeDefAsBuiltin(c, typedef_decl, builtin);
708 }790 }
...@@ -745,7 +827,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -745,7 +827,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
745 // Record declarations such as `struct {...} x` have no name but they're not827 // Record declarations such as `struct {...} x` have no name but they're not
746 // anonymous hence here isAnonymousStructOrUnion is not needed828 // anonymous hence here isAnonymousStructOrUnion is not needed
747 if (bare_name.len == 0) {829 if (bare_name.len == 0) {
748 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});830 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{c.getMangle()});
749 is_unnamed = true;831 is_unnamed = true;
750 }832 }
751833
...@@ -762,7 +844,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -762,7 +844,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
762 return null;844 return null;
763 }845 }
764846
765 const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });847 const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
766 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);848 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
767849
768 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);850 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
...@@ -785,15 +867,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -785,15 +867,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
785 const container_tok = try appendToken(c, container_kind, container_kind_name);867 const container_tok = try appendToken(c, container_kind, container_kind_name);
786 const lbrace_token = try appendToken(c, .LBrace, "{");868 const lbrace_token = try appendToken(c, .LBrace, "{");
787869
788 const container_node = try c.a().create(ast.Node.ContainerDecl);870 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
789 container_node.* = .{871 defer fields_and_decls.deinit();
790 .layout_token = layout_tok,
791 .kind_token = container_tok,
792 .init_arg_expr = .None,
793 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
794 .lbrace_token = lbrace_token,
795 .rbrace_token = undefined,
796 };
797872
798 var unnamed_field_count: u32 = 0;873 var unnamed_field_count: u32 = 0;
799 var it = ZigClangRecordDecl_field_begin(record_def);874 var it = ZigClangRecordDecl_field_begin(record_def);
...@@ -821,7 +896,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -821,7 +896,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
821 var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));896 var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
822 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) {897 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) {
823 // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields.898 // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields.
824 raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{unnamed_field_count});899 raw_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{unnamed_field_count});
825 unnamed_field_count += 1;900 unnamed_field_count += 1;
826 is_anon = true;901 is_anon = true;
827 }902 }
...@@ -851,7 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -851,7 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
851 break :blk null;926 break :blk null;
852 };927 };
853928
854 const field_node = try c.a().create(ast.Node.ContainerField);929 const field_node = try c.arena.create(ast.Node.ContainerField);
855 field_node.* = .{930 field_node.* = .{
856 .doc_comments = null,931 .doc_comments = null,
857 .comptime_token = null,932 .comptime_token = null,
...@@ -868,10 +943,19 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -868,10 +943,19 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
868 );943 );
869 }944 }
870945
871 try container_node.fields_and_decls.push(&field_node.base);946 try fields_and_decls.append(&field_node.base);
872 _ = try appendToken(c, .Comma, ",");947 _ = try appendToken(c, .Comma, ",");
873 }948 }
874 container_node.rbrace_token = try appendToken(c, .RBrace, "}");949 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
950 container_node.* = .{
951 .layout_token = layout_tok,
952 .kind_token = container_tok,
953 .init_arg_expr = .None,
954 .fields_and_decls_len = fields_and_decls.items.len,
955 .lbrace_token = lbrace_token,
956 .rbrace_token = try appendToken(c, .RBrace, "}"),
957 };
958 mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
875 semicolon = try appendToken(c, .Semicolon, ";");959 semicolon = try appendToken(c, .Semicolon, ";");
876 break :blk &container_node.base;960 break :blk &container_node.base;
877 };961 };
...@@ -879,7 +963,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -879,7 +963,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
879963
880 try addTopLevelDecl(c, name, &node.base);964 try addTopLevelDecl(c, name, &node.base);
881 if (!is_unnamed)965 if (!is_unnamed)
882 try c.alias_list.push(.{ .alias = bare_name, .name = name });966 try c.alias_list.append(.{ .alias = bare_name, .name = name });
883 return transCreateNodeIdentifier(c, name);967 return transCreateNodeIdentifier(c, name);
884}968}
885969
...@@ -892,11 +976,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -892,11 +976,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
892 var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl)));976 var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl)));
893 var is_unnamed = false;977 var is_unnamed = false;
894 if (bare_name.len == 0) {978 if (bare_name.len == 0) {
895 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});979 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{c.getMangle()});
896 is_unnamed = true;980 is_unnamed = true;
897 }981 }
898982
899 const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});983 const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
900 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);984 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
901 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);985 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
902 node.eq_token = try appendToken(c, .Equal, "=");986 node.eq_token = try appendToken(c, .Equal, "=");
...@@ -916,15 +1000,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -916,15 +1000,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
916 const extern_tok = try appendToken(c, .Keyword_extern, "extern");1000 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
917 const container_tok = try appendToken(c, .Keyword_enum, "enum");1001 const container_tok = try appendToken(c, .Keyword_enum, "enum");
9181002
919 const container_node = try c.a().create(ast.Node.ContainerDecl);1003 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
920 container_node.* = .{1004 defer fields_and_decls.deinit();
921 .layout_token = extern_tok,
922 .kind_token = container_tok,
923 .init_arg_expr = .None,
924 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
925 .lbrace_token = undefined,
926 .rbrace_token = undefined,
927 };
9281005
929 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);1006 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
930 // The underlying type may be null in case of forward-declared enum1007 // The underlying type may be null in case of forward-declared enum
...@@ -933,7 +1010,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -933,7 +1010,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9331010
934 // default to c_int since msvc and gcc default to different types1011 // default to c_int since msvc and gcc default to different types
935 _ = try appendToken(c, .LParen, "(");1012 _ = try appendToken(c, .LParen, "(");
936 container_node.init_arg_expr = .{1013 const init_arg_expr = ast.Node.ContainerDecl.InitArg{
937 .Type = if (int_type.ptr != null and1014 .Type = if (int_type.ptr != null and
938 !isCBuiltinType(int_type, .UInt) and1015 !isCBuiltinType(int_type, .UInt) and
939 !isCBuiltinType(int_type, .Int))1016 !isCBuiltinType(int_type, .Int))
...@@ -949,7 +1026,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -949,7 +1026,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
949 };1026 };
950 _ = try appendToken(c, .RParen, ")");1027 _ = try appendToken(c, .RParen, ")");
9511028
952 container_node.lbrace_token = try appendToken(c, .LBrace, "{");1029 const lbrace_token = try appendToken(c, .LBrace, "{");
9531030
954 it = ZigClangEnumDecl_enumerator_begin(enum_def);1031 it = ZigClangEnumDecl_enumerator_begin(enum_def);
955 end_it = ZigClangEnumDecl_enumerator_end(enum_def);1032 end_it = ZigClangEnumDecl_enumerator_end(enum_def);
...@@ -971,7 +1048,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -971,7 +1048,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
971 } else1048 } else
972 null;1049 null;
9731050
974 const field_node = try c.a().create(ast.Node.ContainerField);1051 const field_node = try c.arena.create(ast.Node.ContainerField);
975 field_node.* = .{1052 field_node.* = .{
976 .doc_comments = null,1053 .doc_comments = null,
977 .comptime_token = null,1054 .comptime_token = null,
...@@ -981,32 +1058,32 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -981,32 +1058,32 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
981 .align_expr = null,1058 .align_expr = null,
982 };1059 };
9831060
984 try container_node.fields_and_decls.push(&field_node.base);1061 try fields_and_decls.append(&field_node.base);
985 _ = try appendToken(c, .Comma, ",");1062 _ = try appendToken(c, .Comma, ",");
9861063
987 // In C each enum value is in the global namespace. So we put them there too.1064 // In C each enum value is in the global namespace. So we put them there too.
988 // At this point we can rely on the enum emitting successfully.1065 // At this point we can rely on the enum emitting successfully.
989 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);1066 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
990 tld_node.eq_token = try appendToken(c, .Equal, "=");1067 tld_node.eq_token = try appendToken(c, .Equal, "=");
991 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt");1068 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
992 const enum_ident = try transCreateNodeIdentifier(c, name);1069 const enum_ident = try transCreateNodeIdentifier(c, name);
993 const period_tok = try appendToken(c, .Period, ".");1070 const period_tok = try appendToken(c, .Period, ".");
994 const field_ident = try transCreateNodeIdentifier(c, field_name);1071 const field_ident = try transCreateNodeIdentifier(c, field_name);
995 const field_access_node = try c.a().create(ast.Node.InfixOp);1072 const field_access_node = try c.arena.create(ast.Node.InfixOp);
996 field_access_node.* = .{1073 field_access_node.* = .{
997 .op_token = period_tok,1074 .op_token = period_tok,
998 .lhs = enum_ident,1075 .lhs = enum_ident,
999 .op = .Period,1076 .op = .Period,
1000 .rhs = field_ident,1077 .rhs = field_ident,
1001 };1078 };
1002 try cast_node.params.push(&field_access_node.base);1079 cast_node.params()[0] = &field_access_node.base;
1003 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1080 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1004 tld_node.init_node = &cast_node.base;1081 tld_node.init_node = &cast_node.base;
1005 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");1082 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
1006 try addTopLevelDecl(c, field_name, &tld_node.base);1083 try addTopLevelDecl(c, field_name, &tld_node.base);
1007 }1084 }
1008 // make non exhaustive1085 // make non exhaustive
1009 const field_node = try c.a().create(ast.Node.ContainerField);1086 const field_node = try c.arena.create(ast.Node.ContainerField);
1010 field_node.* = .{1087 field_node.* = .{
1011 .doc_comments = null,1088 .doc_comments = null,
1012 .comptime_token = null,1089 .comptime_token = null,
...@@ -1016,10 +1093,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1016,10 +1093,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
1016 .align_expr = null,1093 .align_expr = null,
1017 };1094 };
10181095
1019 try container_node.fields_and_decls.push(&field_node.base);1096 try fields_and_decls.append(&field_node.base);
1020 _ = try appendToken(c, .Comma, ",");1097 _ = try appendToken(c, .Comma, ",");
1021 container_node.rbrace_token = try appendToken(c, .RBrace, "}");1098 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
10221099 container_node.* = .{
1100 .layout_token = extern_tok,
1101 .kind_token = container_tok,
1102 .init_arg_expr = init_arg_expr,
1103 .fields_and_decls_len = fields_and_decls.items.len,
1104 .lbrace_token = lbrace_token,
1105 .rbrace_token = try appendToken(c, .RBrace, "}"),
1106 };
1107 mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
1023 break :blk &container_node.base;1108 break :blk &container_node.base;
1024 } else1109 } else
1025 try transCreateNodeOpaqueType(c);1110 try transCreateNodeOpaqueType(c);
...@@ -1028,7 +1113,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -1028,7 +1113,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10281113
1029 try addTopLevelDecl(c, name, &node.base);1114 try addTopLevelDecl(c, name, &node.base);
1030 if (!is_unnamed)1115 if (!is_unnamed)
1031 try c.alias_list.push(.{ .alias = bare_name, .name = name });1116 try c.alias_list.append(.{ .alias = bare_name, .name = name });
1032 return transCreateNodeIdentifier(c, name);1117 return transCreateNodeIdentifier(c, name);
1033}1118}
10341119
...@@ -1071,7 +1156,7 @@ fn transStmt(...@@ -1071,7 +1156,7 @@ fn transStmt(
1071 .ParenExprClass => {1156 .ParenExprClass => {
1072 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue);1157 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue);
1073 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);1158 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1074 const node = try rp.c.a().create(ast.Node.GroupedExpression);1159 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1075 node.* = .{1160 node.* = .{
1076 .lparen = try appendToken(rp.c, .LParen, "("),1161 .lparen = try appendToken(rp.c, .LParen, "("),
1077 .expr = expr,1162 .expr = expr,
...@@ -1085,7 +1170,7 @@ fn transStmt(...@@ -1085,7 +1170,7 @@ fn transStmt(
1085 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),1170 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
1086 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),1171 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
1087 .NullStmtClass => {1172 .NullStmtClass => {
1088 const block = try transCreateNodeBlock(rp.c, null);1173 const block = try rp.c.createBlock(null, 0);
1089 block.rbrace = try appendToken(rp.c, .RBrace, "}");1174 block.rbrace = try appendToken(rp.c, .RBrace, "}");
1090 return &block.base;1175 return &block.base;
1091 },1176 },
...@@ -1116,7 +1201,7 @@ fn transStmt(...@@ -1116,7 +1201,7 @@ fn transStmt(
1116 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;1201 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;
1117 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);1202 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);
1118 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);1203 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1119 const node = try rp.c.a().create(ast.Node.GroupedExpression);1204 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1120 node.* = .{1205 node.* = .{
1121 .lparen = try appendToken(rp.c, .LParen, "("),1206 .lparen = try appendToken(rp.c, .LParen, "("),
1122 .expr = expr,1207 .expr = expr,
...@@ -1147,31 +1232,27 @@ fn transBinaryOperator(...@@ -1147,31 +1232,27 @@ fn transBinaryOperator(
1147 var op_token: ast.TokenIndex = undefined;1232 var op_token: ast.TokenIndex = undefined;
1148 var op_id: ast.Node.InfixOp.Op = undefined;1233 var op_id: ast.Node.InfixOp.Op = undefined;
1149 switch (op) {1234 switch (op) {
1150 .Assign => return transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),1235 .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
1151 .Comma => {1236 .Comma => {
1152 const block_scope = try scope.findBlockScope(rp.c);1237 const block_scope = try scope.findBlockScope(rp.c);
1153 const expr = block_scope.base.parent == scope;1238 const expr = block_scope.base.parent == scope;
1154 const lparen = if (expr) blk: {1239 const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined;
1155 const l = try appendToken(rp.c, .LParen, "(");
1156 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
1157 break :blk l;
1158 } else undefined;
11591240
1160 const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value);1241 const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value);
1161 try block_scope.block_node.statements.push(lhs);1242 try block_scope.statements.append(lhs);
11621243
1163 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);1244 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
1164 if (expr) {1245 if (expr) {
1165 _ = try appendToken(rp.c, .Semicolon, ";");1246 _ = try appendToken(rp.c, .Semicolon, ";");
1166 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);1247 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
1167 break_node.rhs = rhs;1248 break_node.rhs = rhs;
1168 try block_scope.block_node.statements.push(&break_node.base);1249 try block_scope.statements.append(&break_node.base);
1169 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");1250 const block_node = try block_scope.complete(rp.c);
1170 const rparen = try appendToken(rp.c, .RParen, ")");1251 const rparen = try appendToken(rp.c, .RParen, ")");
1171 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);1252 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1172 grouped_expr.* = .{1253 grouped_expr.* = .{
1173 .lparen = lparen,1254 .lparen = lparen,
1174 .expr = &block_scope.block_node.base,1255 .expr = &block_node.base,
1175 .rparen = rparen,1256 .rparen = rparen,
1176 };1257 };
1177 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);1258 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
...@@ -1182,11 +1263,11 @@ fn transBinaryOperator(...@@ -1182,11 +1263,11 @@ fn transBinaryOperator(
1182 .Div => {1263 .Div => {
1183 if (cIsSignedInteger(qt)) {1264 if (cIsSignedInteger(qt)) {
1184 // signed integer division uses @divTrunc1265 // signed integer division uses @divTrunc
1185 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");1266 const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2);
1186 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));1267 div_trunc_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
1187 _ = try appendToken(rp.c, .Comma, ",");1268 _ = try appendToken(rp.c, .Comma, ",");
1188 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);1269 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
1189 try div_trunc_node.params.push(rhs);1270 div_trunc_node.params()[1] = rhs;
1190 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");1271 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1191 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);1272 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
1192 }1273 }
...@@ -1194,11 +1275,11 @@ fn transBinaryOperator(...@@ -1194,11 +1275,11 @@ fn transBinaryOperator(
1194 .Rem => {1275 .Rem => {
1195 if (cIsSignedInteger(qt)) {1276 if (cIsSignedInteger(qt)) {
1196 // signed integer division uses @rem1277 // signed integer division uses @rem
1197 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");1278 const rem_node = try rp.c.createBuiltinCall("@rem", 2);
1198 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));1279 rem_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
1199 _ = try appendToken(rp.c, .Comma, ",");1280 _ = try appendToken(rp.c, .Comma, ",");
1200 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);1281 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
1201 try rem_node.params.push(rhs);1282 rem_node.params()[1] = rhs;
1202 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");1283 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1203 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);1284 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
1204 }1285 }
...@@ -1302,15 +1383,15 @@ fn transBinaryOperator(...@@ -1302,15 +1383,15 @@ fn transBinaryOperator(
1302 const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);1383 const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
13031384
1304 const lhs = if (isBoolRes(lhs_node)) init: {1385 const lhs = if (isBoolRes(lhs_node)) init: {
1305 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");1386 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1306 try cast_node.params.push(lhs_node);1387 cast_node.params()[0] = lhs_node;
1307 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1388 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1308 break :init &cast_node.base;1389 break :init &cast_node.base;
1309 } else lhs_node;1390 } else lhs_node;
13101391
1311 const rhs = if (isBoolRes(rhs_node)) init: {1392 const rhs = if (isBoolRes(rhs_node)) init: {
1312 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");1393 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1313 try cast_node.params.push(rhs_node);1394 cast_node.params()[0] = rhs_node;
1314 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1395 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1315 break :init &cast_node.base;1396 break :init &cast_node.base;
1316 } else rhs_node;1397 } else rhs_node;
...@@ -1322,23 +1403,22 @@ fn transCompoundStmtInline(...@@ -1322,23 +1403,22 @@ fn transCompoundStmtInline(
1322 rp: RestorePoint,1403 rp: RestorePoint,
1323 parent_scope: *Scope,1404 parent_scope: *Scope,
1324 stmt: *const ZigClangCompoundStmt,1405 stmt: *const ZigClangCompoundStmt,
1325 block_node: *ast.Node.Block,1406 block: *Scope.Block,
1326) TransError!void {1407) TransError!void {
1327 var it = ZigClangCompoundStmt_body_begin(stmt);1408 var it = ZigClangCompoundStmt_body_begin(stmt);
1328 const end_it = ZigClangCompoundStmt_body_end(stmt);1409 const end_it = ZigClangCompoundStmt_body_end(stmt);
1329 while (it != end_it) : (it += 1) {1410 while (it != end_it) : (it += 1) {
1330 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);1411 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
1331 if (result != &block_node.base)1412 try block.statements.append(result);
1332 try block_node.statements.push(result);
1333 }1413 }
1334}1414}
13351415
1336fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {1416fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
1337 const block_scope = try Scope.Block.init(rp.c, scope, null);1417 var block_scope = try Scope.Block.init(rp.c, scope, null);
1338 block_scope.block_node = try transCreateNodeBlock(rp.c, null);1418 defer block_scope.deinit();
1339 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);1419 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
1340 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");1420 const node = try block_scope.complete(rp.c);
1341 return &block_scope.block_node.base;1421 return &node.base;
1342}1422}
13431423
1344fn transCStyleCastExprClass(1424fn transCStyleCastExprClass(
...@@ -1360,77 +1440,83 @@ fn transCStyleCastExprClass(...@@ -1360,77 +1440,83 @@ fn transCStyleCastExprClass(
1360 return maybeSuppressResult(rp, scope, result_used, cast_node);1440 return maybeSuppressResult(rp, scope, result_used, cast_node);
1361}1441}
13621442
1363fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {1443fn transDeclStmtOne(rp: RestorePoint, scope: *Scope, decl: *const ZigClangDecl, block_scope: *Scope.Block,) TransError!*ast.Node {
1364 const c = rp.c;1444 const c = rp.c;
1365 const block_scope = scope.findBlockScope(c) catch unreachable;1445
1446 switch (ZigClangDecl_getKind(decl)) {
1447 .Var => {
1448 const var_decl = @ptrCast(*const ZigClangVarDecl, decl);
1449
1450 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
1451 null
1452 else
1453 try appendToken(c, .Keyword_threadlocal, "threadlocal");
1454 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
1455 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
1456 @ptrCast(*const ZigClangNamedDecl, var_decl),
1457 ));
1458 const mangled_name = try block_scope.makeMangledName(c, name);
1459 const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name);
1460
1461 _ = try appendToken(c, .Colon, ":");
1462 const loc = ZigClangDecl_getLocation(decl);
1463 node.type_node = try transQualType(rp, qual_type, loc);
1464
1465 node.eq_token = try appendToken(c, .Equal, "=");
1466 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
1467 try transExprCoercing(rp, scope, expr, .used, .r_value)
1468 else
1469 try transCreateNodeUndefinedLiteral(c);
1470 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
1471 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1472 builtin_node.params()[0] = init_node;
1473 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1474 init_node = &builtin_node.base;
1475 }
1476 node.init_node = init_node;
1477 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1478 return &node.base;
1479 },
1480 .Typedef => {
1481 const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, decl);
1482 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
1483 @ptrCast(*const ZigClangNamedDecl, typedef_decl),
1484 ));
1485
1486 const underlying_qual = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
1487 const underlying_type = ZigClangQualType_getTypePtr(underlying_qual);
1488
1489 const mangled_name = try block_scope.makeMangledName(c, name);
1490 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
1491 return error.UnsupportedTranslation;
1492 return &node.base;
1493 },
1494 else => |kind| return revertAndWarn(
1495 rp,
1496 error.UnsupportedTranslation,
1497 ZigClangDecl_getLocation(decl),
1498 "TODO implement translation of DeclStmt kind {}",
1499 .{@tagName(kind)},
1500 ),
1501 }
1502}
1503
1504fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {
1505 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
13661506
1367 var it = ZigClangDeclStmt_decl_begin(stmt);1507 var it = ZigClangDeclStmt_decl_begin(stmt);
1368 const end_it = ZigClangDeclStmt_decl_end(stmt);1508 const end_it = ZigClangDeclStmt_decl_end(stmt);
1369 while (it != end_it) : (it += 1) {1509 assert(it != end_it);
1370 switch (ZigClangDecl_getKind(it[0])) {1510 while (true) : (it += 1) {
1371 .Var => {1511 const node = try transDeclStmtOne(rp, scope, it[0], block_scope);
1372 const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]);
13731512
1374 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)1513 if (it + 1 == end_it) {
1375 null1514 return node;
1376 else1515 } else {
1377 try appendToken(c, .Keyword_threadlocal, "threadlocal");1516 try block_scope.statements.append(node);
1378 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
1379 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
1380 @ptrCast(*const ZigClangNamedDecl, var_decl),
1381 ));
1382 const mangled_name = try block_scope.makeMangledName(c, name);
1383 const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name);
1384
1385 _ = try appendToken(c, .Colon, ":");
1386 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));
1387 node.type_node = try transQualType(rp, qual_type, loc);
1388
1389 node.eq_token = try appendToken(c, .Equal, "=");
1390 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
1391 try transExprCoercing(rp, scope, expr, .used, .r_value)
1392 else
1393 try transCreateNodeUndefinedLiteral(c);
1394 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
1395 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1396 try builtin_node.params.push(init_node);
1397 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1398 init_node = &builtin_node.base;
1399 }
1400 node.init_node = init_node;
1401 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1402 try block_scope.block_node.statements.push(&node.base);
1403 },
1404 .Typedef => {
1405 const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, it[0]);
1406 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
1407 @ptrCast(*const ZigClangNamedDecl, typedef_decl),
1408 ));
1409
1410 const underlying_qual = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
1411 const underlying_type = ZigClangQualType_getTypePtr(underlying_qual);
1412
1413 const mangled_name = try block_scope.makeMangledName(c, name);
1414 if (checkForBuiltinTypedef(name)) |builtin| {
1415 try block_scope.variables.push(.{
1416 .alias = builtin,
1417 .name = mangled_name,
1418 });
1419 } else {
1420 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse return error.UnsupportedTranslation;
1421 try block_scope.block_node.statements.push(&node.base);
1422 }
1423 },
1424 else => |kind| return revertAndWarn(
1425 rp,
1426 error.UnsupportedTranslation,
1427 ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)),
1428 "TODO implement translation of DeclStmt kind {}",
1429 .{@tagName(kind)},
1430 ),
1431 }1517 }
1432 }1518 }
1433 return &block_scope.block_node.base;1519 unreachable;
1434}1520}
14351521
1436fn transDeclRefExpr(1522fn transDeclRefExpr(
...@@ -1458,7 +1544,7 @@ fn transImplicitCastExpr(...@@ -1458,7 +1544,7 @@ fn transImplicitCastExpr(
1458 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {1544 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {
1459 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {1545 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
1460 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);1546 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1461 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);1547 return try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
1462 },1548 },
1463 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {1549 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {
1464 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);1550 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
...@@ -1480,8 +1566,8 @@ fn transImplicitCastExpr(...@@ -1480,8 +1566,8 @@ fn transImplicitCastExpr(
1480 },1566 },
1481 .PointerToBoolean => {1567 .PointerToBoolean => {
1482 // @ptrToInt(val) != 01568 // @ptrToInt(val) != 0
1483 const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");1569 const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1);
1484 try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value));1570 ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value);
1485 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");1571 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
14861572
1487 const op_token = try appendToken(rp.c, .BangEqual, "!=");1573 const op_token = try appendToken(rp.c, .BangEqual, "!=");
...@@ -1539,7 +1625,7 @@ fn transBoolExpr(...@@ -1539,7 +1625,7 @@ fn transBoolExpr(
15391625
1540 if (grouped) {1626 if (grouped) {
1541 const rparen = try appendToken(rp.c, .RParen, ")");1627 const rparen = try appendToken(rp.c, .RParen, ")");
1542 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);1628 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1543 grouped_expr.* = .{1629 grouped_expr.* = .{
1544 .lparen = lparen,1630 .lparen = lparen,
1545 .expr = node,1631 .expr = node,
...@@ -1705,13 +1791,11 @@ fn transIntegerLiteral(...@@ -1705,13 +1791,11 @@ fn transIntegerLiteral(
17051791
1706 // @as(T, x)1792 // @as(T, x)
1707 const expr_base = @ptrCast(*const ZigClangExpr, expr);1793 const expr_base = @ptrCast(*const ZigClangExpr, expr);
1708 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");1794 const as_node = try rp.c.createBuiltinCall("@as", 2);
1709 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));1795 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
1710 try as_node.params.push(ty_node);1796 as_node.params()[0] = ty_node;
1711 _ = try appendToken(rp.c, .Comma, ",");1797 _ = try appendToken(rp.c, .Comma, ",");
17121798 as_node.params()[1] = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1713 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1714 try as_node.params.push(int_lit_node);
17151799
1716 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");1800 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1717 return maybeSuppressResult(rp, scope, result_used, &as_node.base);1801 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
...@@ -1747,13 +1831,13 @@ fn transStringLiteral(...@@ -1747,13 +1831,13 @@ fn transStringLiteral(
1747 len = 0;1831 len = 0;
1748 for (str) |c| len += escapeChar(c, &char_buf).len;1832 for (str) |c| len += escapeChar(c, &char_buf).len;
17491833
1750 const buf = try rp.c.a().alloc(u8, len + "\"\"".len);1834 const buf = try rp.c.arena.alloc(u8, len + "\"\"".len);
1751 buf[0] = '"';1835 buf[0] = '"';
1752 writeEscapedString(buf[1..], str);1836 writeEscapedString(buf[1..], str);
1753 buf[buf.len - 1] = '"';1837 buf[buf.len - 1] = '"';
17541838
1755 const token = try appendToken(rp.c, .StringLiteral, buf);1839 const token = try appendToken(rp.c, .StringLiteral, buf);
1756 const node = try rp.c.a().create(ast.Node.StringLiteral);1840 const node = try rp.c.arena.create(ast.Node.StringLiteral);
1757 node.* = .{1841 node.* = .{
1758 .token = token,1842 .token = token,
1759 };1843 };
...@@ -1821,35 +1905,35 @@ fn transCCast(...@@ -1821,35 +1905,35 @@ fn transCCast(
1821 // 2. Bit-cast to correct signed-ness1905 // 2. Bit-cast to correct signed-ness
18221906
1823 // @bitCast(dest_type, intermediate_value)1907 // @bitCast(dest_type, intermediate_value)
1824 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");1908 const cast_node = try rp.c.createBuiltinCall("@bitCast", 2);
1825 try cast_node.params.push(try transQualType(rp, dst_type, loc));1909 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
1826 _ = try appendToken(rp.c, .Comma, ",");1910 _ = try appendToken(rp.c, .Comma, ",");
18271911
1828 switch (cIntTypeCmp(dst_type, src_type)) {1912 switch (cIntTypeCmp(dst_type, src_type)) {
1829 .lt => {1913 .lt => {
1830 // @truncate(SameSignSmallerInt, src_type)1914 // @truncate(SameSignSmallerInt, src_type)
1831 const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate");1915 const trunc_node = try rp.c.createBuiltinCall("@truncate", 2);
1832 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));1916 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
1833 try trunc_node.params.push(ty_node);1917 trunc_node.params()[0] = ty_node;
1834 _ = try appendToken(rp.c, .Comma, ",");1918 _ = try appendToken(rp.c, .Comma, ",");
1835 try trunc_node.params.push(expr);1919 trunc_node.params()[1] = expr;
1836 trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");1920 trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18371921
1838 try cast_node.params.push(&trunc_node.base);1922 cast_node.params()[1] = &trunc_node.base;
1839 },1923 },
1840 .gt => {1924 .gt => {
1841 // @as(SameSignBiggerInt, src_type)1925 // @as(SameSignBiggerInt, src_type)
1842 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");1926 const as_node = try rp.c.createBuiltinCall("@as", 2);
1843 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));1927 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
1844 try as_node.params.push(ty_node);1928 as_node.params()[0] = ty_node;
1845 _ = try appendToken(rp.c, .Comma, ",");1929 _ = try appendToken(rp.c, .Comma, ",");
1846 try as_node.params.push(expr);1930 as_node.params()[1] = expr;
1847 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");1931 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18481932
1849 try cast_node.params.push(&as_node.base);1933 cast_node.params()[1] = &as_node.base;
1850 },1934 },
1851 .eq => {1935 .eq => {
1852 try cast_node.params.push(expr);1936 cast_node.params()[1] = expr;
1853 },1937 },
1854 }1938 }
1855 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1939 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
...@@ -1857,46 +1941,46 @@ fn transCCast(...@@ -1857,46 +1941,46 @@ fn transCCast(
1857 }1941 }
1858 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {1942 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
1859 // @intCast(dest_type, @ptrToInt(val))1943 // @intCast(dest_type, @ptrToInt(val))
1860 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");1944 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
1861 try cast_node.params.push(try transQualType(rp, dst_type, loc));1945 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
1862 _ = try appendToken(rp.c, .Comma, ",");1946 _ = try appendToken(rp.c, .Comma, ",");
1863 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");1947 const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
1864 try builtin_node.params.push(expr);1948 builtin_node.params()[0] = expr;
1865 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1949 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1866 try cast_node.params.push(&builtin_node.base);1950 cast_node.params()[1] = &builtin_node.base;
1867 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1951 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1868 return &cast_node.base;1952 return &cast_node.base;
1869 }1953 }
1870 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {1954 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
1871 // @intToPtr(dest_type, val)1955 // @intToPtr(dest_type, val)
1872 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");1956 const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2);
1873 try builtin_node.params.push(try transQualType(rp, dst_type, loc));1957 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
1874 _ = try appendToken(rp.c, .Comma, ",");1958 _ = try appendToken(rp.c, .Comma, ",");
1875 try builtin_node.params.push(expr);1959 builtin_node.params()[1] = expr;
1876 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1960 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1877 return &builtin_node.base;1961 return &builtin_node.base;
1878 }1962 }
1879 if (cIsFloating(src_type) and cIsFloating(dst_type)) {1963 if (cIsFloating(src_type) and cIsFloating(dst_type)) {
1880 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast");1964 const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2);
1881 try builtin_node.params.push(try transQualType(rp, dst_type, loc));1965 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
1882 _ = try appendToken(rp.c, .Comma, ",");1966 _ = try appendToken(rp.c, .Comma, ",");
1883 try builtin_node.params.push(expr);1967 builtin_node.params()[1] = expr;
1884 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1968 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1885 return &builtin_node.base;1969 return &builtin_node.base;
1886 }1970 }
1887 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {1971 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
1888 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt");1972 const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2);
1889 try builtin_node.params.push(try transQualType(rp, dst_type, loc));1973 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
1890 _ = try appendToken(rp.c, .Comma, ",");1974 _ = try appendToken(rp.c, .Comma, ",");
1891 try builtin_node.params.push(expr);1975 builtin_node.params()[1] = expr;
1892 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1976 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1893 return &builtin_node.base;1977 return &builtin_node.base;
1894 }1978 }
1895 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {1979 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
1896 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat");1980 const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2);
1897 try builtin_node.params.push(try transQualType(rp, dst_type, loc));1981 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
1898 _ = try appendToken(rp.c, .Comma, ",");1982 _ = try appendToken(rp.c, .Comma, ",");
1899 try builtin_node.params.push(expr);1983 builtin_node.params()[1] = expr;
1900 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1984 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1901 return &builtin_node.base;1985 return &builtin_node.base;
1902 }1986 }
...@@ -1904,54 +1988,54 @@ fn transCCast(...@@ -1904,54 +1988,54 @@ fn transCCast(
1904 !ZigClangType_isBooleanType(qualTypeCanon(dst_type)))1988 !ZigClangType_isBooleanType(qualTypeCanon(dst_type)))
1905 {1989 {
1906 // @boolToInt returns either a comptime_int or a u11990 // @boolToInt returns either a comptime_int or a u1
1907 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");1991 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1908 try builtin_node.params.push(expr);1992 builtin_node.params()[0] = expr;
1909 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1993 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19101994
1911 const inner_cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");1995 const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2);
1912 try inner_cast_node.params.push(try transCreateNodeIdentifier(rp.c, "u1"));1996 inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1");
1913 _ = try appendToken(rp.c, .Comma, ",");1997 _ = try appendToken(rp.c, .Comma, ",");
1914 try inner_cast_node.params.push(&builtin_node.base);1998 inner_cast_node.params()[1] = &builtin_node.base;
1915 inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1999 inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19162000
1917 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");2001 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
1918 try cast_node.params.push(try transQualType(rp, dst_type, loc));2002 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
1919 _ = try appendToken(rp.c, .Comma, ",");2003 _ = try appendToken(rp.c, .Comma, ",");
19202004
1921 if (cIsSignedInteger(dst_type)) {2005 if (cIsSignedInteger(dst_type)) {
1922 const bitcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");2006 const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2);
1923 try bitcast_node.params.push(try transCreateNodeIdentifier(rp.c, "i1"));2007 bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1");
1924 _ = try appendToken(rp.c, .Comma, ",");2008 _ = try appendToken(rp.c, .Comma, ",");
1925 try bitcast_node.params.push(&inner_cast_node.base);2009 bitcast_node.params()[1] = &inner_cast_node.base;
1926 bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2010 bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1927 try cast_node.params.push(&bitcast_node.base);2011 cast_node.params()[1] = &bitcast_node.base;
1928 } else {2012 } else {
1929 try cast_node.params.push(&inner_cast_node.base);2013 cast_node.params()[1] = &inner_cast_node.base;
1930 }2014 }
1931 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2015 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19322016
1933 return &cast_node.base;2017 return &cast_node.base;
1934 }2018 }
1935 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) {2019 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) {
1936 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum");2020 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);
1937 try builtin_node.params.push(try transQualType(rp, dst_type, loc));2021 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
1938 _ = try appendToken(rp.c, .Comma, ",");2022 _ = try appendToken(rp.c, .Comma, ",");
1939 try builtin_node.params.push(expr);2023 builtin_node.params()[1] = expr;
1940 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2024 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1941 return &builtin_node.base;2025 return &builtin_node.base;
1942 }2026 }
1943 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and2027 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and
1944 ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum)2028 ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum)
1945 {2029 {
1946 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt");2030 const builtin_node = try rp.c.createBuiltinCall("@enumToInt", 1);
1947 try builtin_node.params.push(expr);2031 builtin_node.params()[0] = expr;
1948 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2032 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1949 return &builtin_node.base;2033 return &builtin_node.base;
1950 }2034 }
1951 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");2035 const cast_node = try rp.c.createBuiltinCall("@as", 2);
1952 try cast_node.params.push(try transQualType(rp, dst_type, loc));2036 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
1953 _ = try appendToken(rp.c, .Comma, ",");2037 _ = try appendToken(rp.c, .Comma, ",");
1954 try cast_node.params.push(expr);2038 cast_node.params()[1] = expr;
1955 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2039 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1956 return &cast_node.base;2040 return &cast_node.base;
1957}2041}
...@@ -2014,7 +2098,10 @@ fn transInitListExprRecord(...@@ -2014,7 +2098,10 @@ fn transInitListExprRecord(
20142098
2015 const ty_node = try transType(rp, ty, loc);2099 const ty_node = try transType(rp, ty, loc);
2016 const init_count = ZigClangInitListExpr_getNumInits(expr);2100 const init_count = ZigClangInitListExpr_getNumInits(expr);
2017 var init_node = try transCreateNodeStructInitializer(rp.c, ty_node);2101 var field_inits = std.ArrayList(*ast.Node).init(rp.c.gpa);
2102 defer field_inits.deinit();
2103
2104 _ = try appendToken(rp.c, .LBrace, "{");
20182105
2019 var init_i: c_uint = 0;2106 var init_i: c_uint = 0;
2020 var it = ZigClangRecordDecl_field_begin(record_def);2107 var it = ZigClangRecordDecl_field_begin(record_def);
...@@ -2038,26 +2125,31 @@ fn transInitListExprRecord(...@@ -2038,26 +2125,31 @@ fn transInitListExprRecord(
2038 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));2125 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
2039 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {2126 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
2040 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;2127 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
2041 raw_name = try mem.dupe(rp.c.a(), u8, name.value);2128 raw_name = try mem.dupe(rp.c.arena, u8, name.value);
2042 }2129 }
2043 const field_name_tok = try appendIdentifier(rp.c, raw_name);2130 const field_name_tok = try appendIdentifier(rp.c, raw_name);
20442131
2045 _ = try appendToken(rp.c, .Equal, "=");2132 _ = try appendToken(rp.c, .Equal, "=");
20462133
2047 const field_init_node = try rp.c.a().create(ast.Node.FieldInitializer);2134 const field_init_node = try rp.c.arena.create(ast.Node.FieldInitializer);
2048 field_init_node.* = .{2135 field_init_node.* = .{
2049 .period_token = period_tok,2136 .period_token = period_tok,
2050 .name_token = field_name_tok,2137 .name_token = field_name_tok,
2051 .expr = try transExpr(rp, scope, elem_expr, .used, .r_value),2138 .expr = try transExpr(rp, scope, elem_expr, .used, .r_value),
2052 };2139 };
20532140
2054 try init_node.op.StructInitializer.push(&field_init_node.base);2141 try field_inits.append(&field_init_node.base);
2055 _ = try appendToken(rp.c, .Comma, ",");2142 _ = try appendToken(rp.c, .Comma, ",");
2056 }2143 }
20572144
2058 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");2145 const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len);
20592146 node.* = .{
2060 return &init_node.base;2147 .lhs = ty_node,
2148 .rtoken = try appendToken(rp.c, .RBrace, "}"),
2149 .list_len = field_inits.items.len,
2150 };
2151 mem.copy(*ast.Node, node.list(), field_inits.items);
2152 return &node.base;
2061}2153}
20622154
2063fn transCreateNodeArrayType(2155fn transCreateNodeArrayType(
...@@ -2100,7 +2192,7 @@ fn transInitListExprArray(...@@ -2100,7 +2192,7 @@ fn transInitListExprArray(
2100 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));2192 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
2101 const leftover_count = all_count - init_count;2193 const leftover_count = all_count - init_count;
21022194
2103 var init_node: *ast.Node.SuffixOp = undefined;2195 var init_node: *ast.Node.ArrayInitializer = undefined;
2104 var cat_tok: ast.TokenIndex = undefined;2196 var cat_tok: ast.TokenIndex = undefined;
2105 if (init_count != 0) {2197 if (init_count != 0) {
2106 const ty_node = try transCreateNodeArrayType(2198 const ty_node = try transCreateNodeArrayType(
...@@ -2109,11 +2201,19 @@ fn transInitListExprArray(...@@ -2109,11 +2201,19 @@ fn transInitListExprArray(
2109 ZigClangQualType_getTypePtr(child_qt),2201 ZigClangQualType_getTypePtr(child_qt),
2110 init_count,2202 init_count,
2111 );2203 );
2112 init_node = try transCreateNodeArrayInitializer(rp.c, ty_node);2204 _ = try appendToken(rp.c, .LBrace, "{");
2205 init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, init_count);
2206 init_node.* = .{
2207 .lhs = ty_node,
2208 .rtoken = undefined,
2209 .list_len = init_count,
2210 };
2211 const init_list = init_node.list();
2212
2113 var i: c_uint = 0;2213 var i: c_uint = 0;
2114 while (i < init_count) : (i += 1) {2214 while (i < init_count) : (i += 1) {
2115 const elem_expr = ZigClangInitListExpr_getInit(expr, i);2215 const elem_expr = ZigClangInitListExpr_getInit(expr, i);
2116 try init_node.op.ArrayInitializer.push(try transExpr(rp, scope, elem_expr, .used, .r_value));2216 init_list[i] = try transExpr(rp, scope, elem_expr, .used, .r_value);
2117 _ = try appendToken(rp.c, .Comma, ",");2217 _ = try appendToken(rp.c, .Comma, ",");
2118 }2218 }
2119 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");2219 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
...@@ -2124,16 +2224,22 @@ fn transInitListExprArray(...@@ -2124,16 +2224,22 @@ fn transInitListExprArray(
2124 }2224 }
21252225
2126 const ty_node = try transCreateNodeArrayType(rp, loc, ZigClangQualType_getTypePtr(child_qt), 1);2226 const ty_node = try transCreateNodeArrayType(rp, loc, ZigClangQualType_getTypePtr(child_qt), 1);
2127 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, ty_node);2227 _ = try appendToken(rp.c, .LBrace, "{");
2228 const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 1);
2229 filler_init_node.* = .{
2230 .lhs = ty_node,
2231 .rtoken = undefined,
2232 .list_len = 1,
2233 };
2128 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);2234 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);
2129 try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value));2235 filler_init_node.list()[0] = try transExpr(rp, scope, filler_val_expr, .used, .r_value);
2130 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");2236 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
21312237
2132 const rhs_node = if (leftover_count == 1)2238 const rhs_node = if (leftover_count == 1)
2133 &filler_init_node.base2239 &filler_init_node.base
2134 else blk: {2240 else blk: {
2135 const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");2241 const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");
2136 const mul_node = try rp.c.a().create(ast.Node.InfixOp);2242 const mul_node = try rp.c.arena.create(ast.Node.InfixOp);
2137 mul_node.* = .{2243 mul_node.* = .{
2138 .op_token = mul_tok,2244 .op_token = mul_tok,
2139 .lhs = &filler_init_node.base,2245 .lhs = &filler_init_node.base,
...@@ -2147,7 +2253,7 @@ fn transInitListExprArray(...@@ -2147,7 +2253,7 @@ fn transInitListExprArray(
2147 return rhs_node;2253 return rhs_node;
2148 }2254 }
21492255
2150 const cat_node = try rp.c.a().create(ast.Node.InfixOp);2256 const cat_node = try rp.c.arena.create(ast.Node.InfixOp);
2151 cat_node.* = .{2257 cat_node.* = .{
2152 .op_token = cat_tok,2258 .op_token = cat_tok,
2153 .lhs = &init_node.base,2259 .lhs = &init_node.base,
...@@ -2266,11 +2372,15 @@ fn transIfStmt(...@@ -2266,11 +2372,15 @@ fn transIfStmt(
2266 // if (c) t else e2372 // if (c) t else e
2267 const if_node = try transCreateNodeIf(rp.c);2373 const if_node = try transCreateNodeIf(rp.c);
22682374
2269 var cond_scope = Scope{2375 var cond_scope = Scope.Condition{
2270 .parent = scope,2376 .base = .{
2271 .id = .Condition,2377 .parent = scope,
2378 .id = .Condition,
2379 },
2272 };2380 };
2273 if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);2381 defer cond_scope.deinit();
2382 const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt));
2383 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
2274 _ = try appendToken(rp.c, .RParen, ")");2384 _ = try appendToken(rp.c, .RParen, ")");
22752385
2276 if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);2386 if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);
...@@ -2290,11 +2400,15 @@ fn transWhileLoop(...@@ -2290,11 +2400,15 @@ fn transWhileLoop(
2290) TransError!*ast.Node {2400) TransError!*ast.Node {
2291 const while_node = try transCreateNodeWhile(rp.c);2401 const while_node = try transCreateNodeWhile(rp.c);
22922402
2293 var cond_scope = Scope{2403 var cond_scope = Scope.Condition{
2294 .parent = scope,2404 .base = .{
2295 .id = .Condition,2405 .parent = scope,
2406 .id = .Condition,
2407 },
2296 };2408 };
2297 while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);2409 defer cond_scope.deinit();
2410 const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt));
2411 while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
2298 _ = try appendToken(rp.c, .RParen, ")");2412 _ = try appendToken(rp.c, .RParen, ")");
22992413
2300 var loop_scope = Scope{2414 var loop_scope = Scope{
...@@ -2323,12 +2437,15 @@ fn transDoWhileLoop(...@@ -2323,12 +2437,15 @@ fn transDoWhileLoop(
23232437
2324 // if (!cond) break;2438 // if (!cond) break;
2325 const if_node = try transCreateNodeIf(rp.c);2439 const if_node = try transCreateNodeIf(rp.c);
2326 var cond_scope = Scope{2440 var cond_scope = Scope.Condition{
2327 .parent = scope,2441 .base = .{
2328 .id = .Condition,2442 .parent = scope,
2443 .id = .Condition,
2444 },
2329 };2445 };
2446 defer cond_scope.deinit();
2330 const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");2447 const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
2331 prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);2448 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
2332 _ = try appendToken(rp.c, .RParen, ")");2449 _ = try appendToken(rp.c, .RParen, ")");
2333 if_node.condition = &prefix_op.base;2450 if_node.condition = &prefix_op.base;
2334 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;2451 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
...@@ -2345,7 +2462,8 @@ fn transDoWhileLoop(...@@ -2345,7 +2462,8 @@ fn transDoWhileLoop(
2345 // zig: b;2462 // zig: b;
2346 // zig: if (!cond) break;2463 // zig: if (!cond) break;
2347 // zig: }2464 // zig: }
2348 break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;2465 const node = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
2466 break :blk node.cast(ast.Node.Block).?;
2349 } else blk: {2467 } else blk: {
2350 // the C statement is without a block, so we need to create a block to contain it.2468 // the C statement is without a block, so we need to create a block to contain it.
2351 // c: do2469 // c: do
...@@ -2356,12 +2474,15 @@ fn transDoWhileLoop(...@@ -2356,12 +2474,15 @@ fn transDoWhileLoop(
2356 // zig: if (!cond) break;2474 // zig: if (!cond) break;
2357 // zig: }2475 // zig: }
2358 new = true;2476 new = true;
2359 const block = try transCreateNodeBlock(rp.c, null);2477 const block = try rp.c.createBlock(null, 2);
2360 try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));2478 block.statements_len = 1; // over-allocated so we can add another below
2479 block.statements()[0] = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
2361 break :blk block;2480 break :blk block;
2362 };2481 };
23632482
2364 try body_node.statements.push(&if_node.base);2483 // In both cases above, we reserved 1 extra statement.
2484 body_node.statements_len += 1;
2485 body_node.statements()[body_node.statements_len - 1] = &if_node.base;
2365 if (new)2486 if (new)
2366 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");2487 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2367 while_node.body = &body_node.base;2488 while_node.body = &body_node.base;
...@@ -2378,24 +2499,26 @@ fn transForLoop(...@@ -2378,24 +2499,26 @@ fn transForLoop(
2378 .id = .Loop,2499 .id = .Loop,
2379 };2500 };
23802501
2381 var block_scope: ?*Scope.Block = null;2502 var block_scope: ?Scope.Block = null;
2503 defer if (block_scope) |*bs| bs.deinit();
2504
2382 if (ZigClangForStmt_getInit(stmt)) |init| {2505 if (ZigClangForStmt_getInit(stmt)) |init| {
2383 block_scope = try Scope.Block.init(rp.c, scope, null);2506 block_scope = try Scope.Block.init(rp.c, scope, null);
2384 const block = try transCreateNodeBlock(rp.c, null);
2385 block_scope.?.block_node = block;
2386 loop_scope.parent = &block_scope.?.base;2507 loop_scope.parent = &block_scope.?.base;
2387 const result = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);2508 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
2388 if (result != &block.base)2509 try block_scope.?.statements.append(init_node);
2389 try block.statements.push(result);
2390 }2510 }
2391 var cond_scope = Scope{2511 var cond_scope = Scope.Condition{
2392 .parent = scope,2512 .base = .{
2393 .id = .Condition,2513 .parent = scope,
2514 .id = .Condition,
2515 },
2394 };2516 };
2517 defer cond_scope.deinit();
23952518
2396 const while_node = try transCreateNodeWhile(rp.c);2519 const while_node = try transCreateNodeWhile(rp.c);
2397 while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|2520 while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|
2398 try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false)2521 try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
2399 else2522 else
2400 try transCreateNodeBoolLiteral(rp.c, true);2523 try transCreateNodeBoolLiteral(rp.c, true);
2401 _ = try appendToken(rp.c, .RParen, ")");2524 _ = try appendToken(rp.c, .RParen, ")");
...@@ -2403,61 +2526,92 @@ fn transForLoop(...@@ -2403,61 +2526,92 @@ fn transForLoop(
2403 if (ZigClangForStmt_getInc(stmt)) |incr| {2526 if (ZigClangForStmt_getInc(stmt)) |incr| {
2404 _ = try appendToken(rp.c, .Colon, ":");2527 _ = try appendToken(rp.c, .Colon, ":");
2405 _ = try appendToken(rp.c, .LParen, "(");2528 _ = try appendToken(rp.c, .LParen, "(");
2406 while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value);2529 while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);
2407 _ = try appendToken(rp.c, .RParen, ")");2530 _ = try appendToken(rp.c, .RParen, ")");
2408 }2531 }
24092532
2410 while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);2533 while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
2411 if (block_scope != null) {2534 if (block_scope) |*bs| {
2412 try block_scope.?.block_node.statements.push(&while_node.base);2535 try bs.statements.append(&while_node.base);
2413 block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");2536 const node = try bs.complete(rp.c);
2414 return &block_scope.?.block_node.base;2537 return &node.base;
2415 } else {2538 } else {
2416 _ = try appendToken(rp.c, .Semicolon, ";");2539 _ = try appendToken(rp.c, .Semicolon, ";");
2417 return &while_node.base;2540 return &while_node.base;
2418 }2541 }
2419}2542}
24202543
2544fn getSwitchCaseCount(stmt: *const ZigClangSwitchStmt) usize {
2545 const body = ZigClangSwitchStmt_getBody(stmt);
2546 assert(ZigClangStmt_getStmtClass(body) == .CompoundStmtClass);
2547 const comp = @ptrCast(*const ZigClangCompoundStmt, body);
2548 // TODO https://github.com/ziglang/zig/issues/1738
2549 // return ZigClangCompoundStmt_body_end(comp) - ZigClangCompoundStmt_body_begin(comp);
2550 const start_addr = @ptrToInt(ZigClangCompoundStmt_body_begin(comp));
2551 const end_addr = @ptrToInt(ZigClangCompoundStmt_body_end(comp));
2552 return (end_addr - start_addr) / @sizeOf(*ZigClangStmt);
2553}
2554
2421fn transSwitch(2555fn transSwitch(
2422 rp: RestorePoint,2556 rp: RestorePoint,
2423 scope: *Scope,2557 scope: *Scope,
2424 stmt: *const ZigClangSwitchStmt,2558 stmt: *const ZigClangSwitchStmt,
2425) TransError!*ast.Node {2559) TransError!*ast.Node {
2426 const switch_node = try transCreateNodeSwitch(rp.c);2560 const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch");
2561 _ = try appendToken(rp.c, .LParen, "(");
2562
2563 const cases_len = getSwitchCaseCount(stmt);
2564
2565 var cond_scope = Scope.Condition{
2566 .base = .{
2567 .parent = scope,
2568 .id = .Condition,
2569 },
2570 };
2571 defer cond_scope.deinit();
2572 const switch_expr = try transExpr(rp, &cond_scope.base, ZigClangSwitchStmt_getCond(stmt), .used, .r_value);
2573 _ = try appendToken(rp.c, .RParen, ")");
2574 _ = try appendToken(rp.c, .LBrace, "{");
2575 // reserve +1 case in case there is no default case
2576 const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1);
2577 switch_node.* = .{
2578 .switch_token = switch_tok,
2579 .expr = switch_expr,
2580 .cases_len = cases_len + 1,
2581 .rbrace = try appendToken(rp.c, .RBrace, "}"),
2582 };
2583
2427 var switch_scope = Scope.Switch{2584 var switch_scope = Scope.Switch{
2428 .base = .{2585 .base = .{
2429 .id = .Switch,2586 .id = .Switch,
2430 .parent = scope,2587 .parent = scope,
2431 },2588 },
2432 .cases = &switch_node.cases,2589 .cases = switch_node.cases(),
2590 .case_index = 0,
2433 .pending_block = undefined,2591 .pending_block = undefined,
2434 };2592 };
24352593
2436 var cond_scope = Scope{
2437 .parent = scope,
2438 .id = .Condition,
2439 };
2440 switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value);
2441 _ = try appendToken(rp.c, .RParen, ")");
2442 _ = try appendToken(rp.c, .LBrace, "{");
2443 switch_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2444
2445 const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
2446 // tmp block that all statements will go before being picked up by a case or default2594 // tmp block that all statements will go before being picked up by a case or default
2447 const block = try transCreateNodeBlock(rp.c, null);2595 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
2448 block_scope.block_node = block;2596 defer block_scope.deinit();
24492597
2450 const switch_block = try transCreateNodeBlock(rp.c, null);2598 // Note that we do not defer a deinit here; the switch_scope.pending_block field
2451 try switch_block.statements.push(&switch_node.base);2599 // has its own memory management. This resource is freed inside `transCase` and
2452 switch_scope.pending_block = switch_block;2600 // then the final pending_block is freed at the bottom of this function with
2601 // pending_block.deinit().
2602 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2603 try switch_scope.pending_block.statements.append(&switch_node.base);
24532604
2454 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);2605 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
2455 _ = try appendToken(rp.c, .Semicolon, ";");2606 _ = try appendToken(rp.c, .Semicolon, ";");
24562607
2457 // take all pending statements2608 // take all pending statements
2458 var it = last.cast(ast.Node.Block).?.statements.iterator(0);2609 const last_block_stmts = last.cast(ast.Node.Block).?.statements();
2459 while (it.next()) |n| {2610 try switch_scope.pending_block.statements.ensureCapacity(
2460 try switch_scope.pending_block.statements.push(n.*);2611 switch_scope.pending_block.statements.items.len + last_block_stmts.len,
2612 );
2613 for (last_block_stmts) |n| {
2614 switch_scope.pending_block.statements.appendAssumeCapacity(n);
2461 }2615 }
24622616
2463 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");2617 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");
...@@ -2466,10 +2620,16 @@ fn transSwitch(...@@ -2466,10 +2620,16 @@ fn transSwitch(
2466 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));2620 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2467 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;2621 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;
2468 _ = try appendToken(rp.c, .Comma, ",");2622 _ = try appendToken(rp.c, .Comma, ",");
2469 try switch_node.cases.push(&else_prong.base);2623 switch_scope.cases[switch_scope.case_index] = &else_prong.base;
2624 switch_scope.case_index += 1;
2470 }2625 }
2471 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");2626 // We overallocated in case there was no default, so now we correct
2472 return &switch_scope.pending_block.base;2627 // the number of cases in the AST node.
2628 switch_node.cases_len = switch_scope.case_index;
2629
2630 const result_node = try switch_scope.pending_block.complete(rp.c);
2631 switch_scope.pending_block.deinit();
2632 return &result_node.base;
2473}2633}
24742634
2475fn transCase(2635fn transCase(
...@@ -2479,7 +2639,7 @@ fn transCase(...@@ -2479,7 +2639,7 @@ fn transCase(
2479) TransError!*ast.Node {2639) TransError!*ast.Node {
2480 const block_scope = scope.findBlockScope(rp.c) catch unreachable;2640 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
2481 const switch_scope = scope.getSwitch();2641 const switch_scope = scope.getSwitch();
2482 const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});2642 const label = try std.fmt.allocPrint(rp.c.arena, "__case_{}", .{switch_scope.case_index - @boolToInt(switch_scope.has_default)});
2483 _ = try appendToken(rp.c, .Semicolon, ";");2643 _ = try appendToken(rp.c, .Semicolon, ";");
24842644
2485 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {2645 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
...@@ -2487,7 +2647,7 @@ fn transCase(...@@ -2487,7 +2647,7 @@ fn transCase(
2487 const ellips = try appendToken(rp.c, .Ellipsis3, "...");2647 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
2488 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);2648 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
24892649
2490 const node = try rp.c.a().create(ast.Node.InfixOp);2650 const node = try rp.c.arena.create(ast.Node.InfixOp);
2491 node.* = .{2651 node.* = .{
2492 .op_token = ellips,2652 .op_token = ellips,
2493 .lhs = lhs_node,2653 .lhs = lhs_node,
...@@ -2501,22 +2661,21 @@ fn transCase(...@@ -2501,22 +2661,21 @@ fn transCase(
2501 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);2661 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
2502 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;2662 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
2503 _ = try appendToken(rp.c, .Comma, ",");2663 _ = try appendToken(rp.c, .Comma, ",");
2504 try switch_scope.cases.push(&switch_prong.base);2664 switch_scope.cases[switch_scope.case_index] = &switch_prong.base;
2665 switch_scope.case_index += 1;
25052666
2506 const block = try transCreateNodeBlock(rp.c, null);
2507 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);2667 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
2508 _ = try appendToken(rp.c, .Colon, ":");2668 _ = try appendToken(rp.c, .Colon, ":");
2509 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
2510 try block.statements.push(&switch_scope.pending_block.base);
25112669
2512 // take all pending statements2670 // take all pending statements
2513 var it = block_scope.block_node.statements.iterator(0);2671 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
2514 while (it.next()) |n| {2672 block_scope.statements.shrink(0);
2515 try switch_scope.pending_block.statements.push(n.*);
2516 }
2517 block_scope.block_node.statements.shrink(0);
25182673
2519 switch_scope.pending_block = block;2674 const pending_node = try switch_scope.pending_block.complete(rp.c);
2675 switch_scope.pending_block.deinit();
2676 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2677
2678 try switch_scope.pending_block.statements.append(&pending_node.base);
25202679
2521 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);2680 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
2522}2681}
...@@ -2535,22 +2694,21 @@ fn transDefault(...@@ -2535,22 +2694,21 @@ fn transDefault(
2535 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));2694 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2536 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;2695 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
2537 _ = try appendToken(rp.c, .Comma, ",");2696 _ = try appendToken(rp.c, .Comma, ",");
2538 try switch_scope.cases.push(&else_prong.base);2697 switch_scope.cases[switch_scope.case_index] = &else_prong.base;
2698 switch_scope.case_index += 1;
25392699
2540 const block = try transCreateNodeBlock(rp.c, null);
2541 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);2700 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
2542 _ = try appendToken(rp.c, .Colon, ":");2701 _ = try appendToken(rp.c, .Colon, ":");
2543 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
2544 try block.statements.push(&switch_scope.pending_block.base);
25452702
2546 // take all pending statements2703 // take all pending statements
2547 var it = block_scope.block_node.statements.iterator(0);2704 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
2548 while (it.next()) |n| {2705 block_scope.statements.shrink(0);
2549 try switch_scope.pending_block.statements.push(n.*);2706
2550 }2707 const pending_node = try switch_scope.pending_block.complete(rp.c);
2551 block_scope.block_node.statements.shrink(0);2708 switch_scope.pending_block.deinit();
2709 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2710 try switch_scope.pending_block.statements.append(&pending_node.base);
25522711
2553 switch_scope.pending_block = block;
2554 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);2712 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
2555}2713}
25562714
...@@ -2565,13 +2723,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr,...@@ -2565,13 +2723,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr,
2565 // See comment in `transIntegerLiteral` for why this code is here.2723 // See comment in `transIntegerLiteral` for why this code is here.
2566 // @as(T, x)2724 // @as(T, x)
2567 const expr_base = @ptrCast(*const ZigClangExpr, expr);2725 const expr_base = @ptrCast(*const ZigClangExpr, expr);
2568 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");2726 const as_node = try rp.c.createBuiltinCall("@as", 2);
2569 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));2727 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
2570 try as_node.params.push(ty_node);2728 as_node.params()[0] = ty_node;
2571 _ = try appendToken(rp.c, .Comma, ",");2729 _ = try appendToken(rp.c, .Comma, ",");
25722730
2573 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val));2731 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val));
2574 try as_node.params.push(int_lit_node);2732 as_node.params()[1] = int_lit_node;
25752733
2576 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");2734 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
25772735
...@@ -2606,7 +2764,7 @@ fn transCharLiteral(...@@ -2606,7 +2764,7 @@ fn transCharLiteral(
2606 }2764 }
2607 var char_buf: [4]u8 = undefined;2765 var char_buf: [4]u8 = undefined;
2608 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});2766 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
2609 const node = try rp.c.a().create(ast.Node.CharLiteral);2767 const node = try rp.c.arena.create(ast.Node.CharLiteral);
2610 node.* = .{2768 node.* = .{
2611 .token = token,2769 .token = token,
2612 };2770 };
...@@ -2627,12 +2785,11 @@ fn transCharLiteral(...@@ -2627,12 +2785,11 @@ fn transCharLiteral(
2627 // See comment in `transIntegerLiteral` for why this code is here.2785 // See comment in `transIntegerLiteral` for why this code is here.
2628 // @as(T, x)2786 // @as(T, x)
2629 const expr_base = @ptrCast(*const ZigClangExpr, stmt);2787 const expr_base = @ptrCast(*const ZigClangExpr, stmt);
2630 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");2788 const as_node = try rp.c.createBuiltinCall("@as", 2);
2631 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));2789 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
2632 try as_node.params.push(ty_node);2790 as_node.params()[0] = ty_node;
2633 _ = try appendToken(rp.c, .Comma, ",");2791 _ = try appendToken(rp.c, .Comma, ",");
26342792 as_node.params()[1] = int_lit_node;
2635 try as_node.params.push(int_lit_node);
26362793
2637 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");2794 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2638 return maybeSuppressResult(rp, scope, result_used, &as_node.base);2795 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
...@@ -2644,27 +2801,25 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,...@@ -2644,27 +2801,25 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
2644 return transCompoundStmt(rp, scope, comp);2801 return transCompoundStmt(rp, scope, comp);
2645 }2802 }
2646 const lparen = try appendToken(rp.c, .LParen, "(");2803 const lparen = try appendToken(rp.c, .LParen, "(");
2647 const block_scope = try Scope.Block.init(rp.c, scope, "blk");2804 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
2648 const block = try transCreateNodeBlock(rp.c, "blk");2805 defer block_scope.deinit();
2649 block_scope.block_node = block;
26502806
2651 var it = ZigClangCompoundStmt_body_begin(comp);2807 var it = ZigClangCompoundStmt_body_begin(comp);
2652 const end_it = ZigClangCompoundStmt_body_end(comp);2808 const end_it = ZigClangCompoundStmt_body_end(comp);
2653 while (it != end_it - 1) : (it += 1) {2809 while (it != end_it - 1) : (it += 1) {
2654 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);2810 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
2655 if (result != &block.base)2811 try block_scope.statements.append(result);
2656 try block.statements.push(result);
2657 }2812 }
2658 const break_node = try transCreateNodeBreak(rp.c, "blk");2813 const break_node = try transCreateNodeBreak(rp.c, "blk");
2659 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);2814 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
2660 _ = try appendToken(rp.c, .Semicolon, ";");2815 _ = try appendToken(rp.c, .Semicolon, ";");
2661 try block.statements.push(&break_node.base);2816 try block_scope.statements.append(&break_node.base);
2662 block.rbrace = try appendToken(rp.c, .RBrace, "}");2817 const block_node = try block_scope.complete(rp.c);
2663 const rparen = try appendToken(rp.c, .RParen, ")");2818 const rparen = try appendToken(rp.c, .RParen, ")");
2664 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);2819 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
2665 grouped_expr.* = .{2820 grouped_expr.* = .{
2666 .lparen = lparen,2821 .lparen = lparen,
2667 .expr = &block.base,2822 .expr = &block_node.base,
2668 .rparen = rparen,2823 .rparen = rparen,
2669 };2824 };
2670 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);2825 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
...@@ -2686,7 +2841,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE...@@ -2686,7 +2841,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE
2686 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);2841 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);
2687 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {2842 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
2688 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;2843 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
2689 break :blk try mem.dupe(rp.c.a(), u8, name.value);2844 break :blk try mem.dupe(rp.c.arena, u8, name.value);
2690 }2845 }
2691 }2846 }
2692 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);2847 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);
...@@ -2720,12 +2875,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS...@@ -2720,12 +2875,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
2720 const is_signed = cIsSignedInteger(qt);2875 const is_signed = cIsSignedInteger(qt);
27212876
2722 if (is_longlong or is_signed) {2877 if (is_longlong or is_signed) {
2723 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");2878 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2724 // check if long long first so that signed long long doesn't just become unsigned long long2879 // check if long long first so that signed long long doesn't just become unsigned long long
2725 var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false);2880 var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false);
2726 try cast_node.params.push(typeid_node);2881 cast_node.params()[0] = typeid_node;
2727 _ = try appendToken(rp.c, .Comma, ",");2882 _ = try appendToken(rp.c, .Comma, ",");
2728 try cast_node.params.push(try transExpr(rp, scope, subscr_expr, .used, .r_value));2883 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);
2729 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2884 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2730 node.rtoken = try appendToken(rp.c, .RBrace, "]");2885 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2731 node.op.ArrayAccess = &cast_node.base;2886 node.op.ArrayAccess = &cast_node.base;
...@@ -2761,17 +2916,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr,...@@ -2761,17 +2916,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr,
2761 break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr);2916 break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr);
2762 } else2917 } else
2763 raw_fn_expr;2918 raw_fn_expr;
2764 const node = try transCreateNodeFnCall(rp.c, fn_expr);
27652919
2766 const num_args = ZigClangCallExpr_getNumArgs(stmt);2920 const num_args = ZigClangCallExpr_getNumArgs(stmt);
2921 const node = try rp.c.createCall(fn_expr, num_args);
2922 const call_params = node.params();
2923
2767 const args = ZigClangCallExpr_getArgs(stmt);2924 const args = ZigClangCallExpr_getArgs(stmt);
2768 var i: usize = 0;2925 var i: usize = 0;
2769 while (i < num_args) : (i += 1) {2926 while (i < num_args) : (i += 1) {
2770 if (i != 0) {2927 if (i != 0) {
2771 _ = try appendToken(rp.c, .Comma, ",");2928 _ = try appendToken(rp.c, .Comma, ",");
2772 }2929 }
2773 const arg = try transExpr(rp, scope, args[i], .used, .r_value);2930 call_params[i] = try transExpr(rp, scope, args[i], .used, .r_value);
2774 try node.op.Call.params.push(arg);
2775 }2931 }
2776 node.rtoken = try appendToken(rp.c, .RParen, ")");2932 node.rtoken = try appendToken(rp.c, .RParen, ")");
27772933
...@@ -2830,8 +2986,8 @@ fn transUnaryExprOrTypeTraitExpr(...@@ -2830,8 +2986,8 @@ fn transUnaryExprOrTypeTraitExpr(
2830 ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt),2986 ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt),
2831 );2987 );
28322988
2833 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf");2989 const builtin_node = try rp.c.createBuiltinCall("@sizeOf", 1);
2834 try builtin_node.params.push(type_node);2990 builtin_node.params()[0] = type_node;
2835 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2991 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2836 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);2992 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
2837}2993}
...@@ -2940,8 +3096,8 @@ fn transCreatePreCrement(...@@ -2940,8 +3096,8 @@ fn transCreatePreCrement(
2940 // zig: _ref.* += 1;3096 // zig: _ref.* += 1;
2941 // zig: break :blk _ref.*3097 // zig: break :blk _ref.*
2942 // zig: })3098 // zig: })
2943 const block_scope = try Scope.Block.init(rp.c, scope, "blk");3099 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
2944 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);3100 defer block_scope.deinit();
2945 const ref = try block_scope.makeMangledName(rp.c, "ref");3101 const ref = try block_scope.makeMangledName(rp.c, "ref");
29463102
2947 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3103 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
...@@ -2950,7 +3106,7 @@ fn transCreatePreCrement(...@@ -2950,7 +3106,7 @@ fn transCreatePreCrement(
2950 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3106 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2951 node.init_node = &rhs_node.base;3107 node.init_node = &rhs_node.base;
2952 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3108 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2953 try block_scope.block_node.statements.push(&node.base);3109 try block_scope.statements.append(&node.base);
29543110
2955 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3111 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
2956 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);3112 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
...@@ -2959,18 +3115,18 @@ fn transCreatePreCrement(...@@ -2959,18 +3115,18 @@ fn transCreatePreCrement(
2959 const one = try transCreateNodeInt(rp.c, 1);3115 const one = try transCreateNodeInt(rp.c, 1);
2960 _ = try appendToken(rp.c, .Semicolon, ";");3116 _ = try appendToken(rp.c, .Semicolon, ";");
2961 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);3117 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
2962 try block_scope.block_node.statements.push(assign);3118 try block_scope.statements.append(assign);
29633119
2964 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3120 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
2965 break_node.rhs = ref_node;3121 break_node.rhs = ref_node;
2966 try block_scope.block_node.statements.push(&break_node.base);3122 try block_scope.statements.append(&break_node.base);
2967 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3123 const block_node = try block_scope.complete(rp.c);
2968 // semicolon must immediately follow rbrace because it is the last token in a block3124 // semicolon must immediately follow rbrace because it is the last token in a block
2969 _ = try appendToken(rp.c, .Semicolon, ";");3125 _ = try appendToken(rp.c, .Semicolon, ";");
2970 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3126 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
2971 grouped_expr.* = .{3127 grouped_expr.* = .{
2972 .lparen = try appendToken(rp.c, .LParen, "("),3128 .lparen = try appendToken(rp.c, .LParen, "("),
2973 .expr = &block_scope.block_node.base,3129 .expr = &block_node.base,
2974 .rparen = try appendToken(rp.c, .RParen, ")"),3130 .rparen = try appendToken(rp.c, .RParen, ")"),
2975 };3131 };
2976 return &grouped_expr.base;3132 return &grouped_expr.base;
...@@ -3006,8 +3162,8 @@ fn transCreatePostCrement(...@@ -3006,8 +3162,8 @@ fn transCreatePostCrement(
3006 // zig: _ref.* += 1;3162 // zig: _ref.* += 1;
3007 // zig: break :blk _tmp3163 // zig: break :blk _tmp
3008 // zig: })3164 // zig: })
3009 const block_scope = try Scope.Block.init(rp.c, scope, "blk");3165 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3010 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);3166 defer block_scope.deinit();
3011 const ref = try block_scope.makeMangledName(rp.c, "ref");3167 const ref = try block_scope.makeMangledName(rp.c, "ref");
30123168
3013 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3169 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
...@@ -3016,7 +3172,7 @@ fn transCreatePostCrement(...@@ -3016,7 +3172,7 @@ fn transCreatePostCrement(
3016 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3172 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3017 node.init_node = &rhs_node.base;3173 node.init_node = &rhs_node.base;
3018 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3174 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3019 try block_scope.block_node.statements.push(&node.base);3175 try block_scope.statements.append(&node.base);
30203176
3021 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3177 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3022 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);3178 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
...@@ -3027,23 +3183,23 @@ fn transCreatePostCrement(...@@ -3027,23 +3183,23 @@ fn transCreatePostCrement(
3027 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");3183 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
3028 tmp_node.init_node = ref_node;3184 tmp_node.init_node = ref_node;
3029 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3185 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3030 try block_scope.block_node.statements.push(&tmp_node.base);3186 try block_scope.statements.append(&tmp_node.base);
30313187
3032 const token = try appendToken(rp.c, op_tok_id, bytes);3188 const token = try appendToken(rp.c, op_tok_id, bytes);
3033 const one = try transCreateNodeInt(rp.c, 1);3189 const one = try transCreateNodeInt(rp.c, 1);
3034 _ = try appendToken(rp.c, .Semicolon, ";");3190 _ = try appendToken(rp.c, .Semicolon, ";");
3035 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);3191 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
3036 try block_scope.block_node.statements.push(assign);3192 try block_scope.statements.append(assign);
30373193
3038 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3194 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3039 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);3195 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
3040 try block_scope.block_node.statements.push(&break_node.base);3196 try block_scope.statements.append(&break_node.base);
3041 _ = try appendToken(rp.c, .Semicolon, ";");3197 _ = try appendToken(rp.c, .Semicolon, ";");
3042 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3198 const block_node = try block_scope.complete(rp.c);
3043 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3199 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3044 grouped_expr.* = .{3200 grouped_expr.* = .{
3045 .lparen = try appendToken(rp.c, .LParen, "("),3201 .lparen = try appendToken(rp.c, .LParen, "("),
3046 .expr = &block_scope.block_node.base,3202 .expr = &block_node.base,
3047 .rparen = try appendToken(rp.c, .RParen, ")"),3203 .rparen = try appendToken(rp.c, .RParen, ")"),
3048 };3204 };
3049 return &grouped_expr.base;3205 return &grouped_expr.base;
...@@ -3106,13 +3262,13 @@ fn transCreateCompoundAssign(...@@ -3106,13 +3262,13 @@ fn transCreateCompoundAssign(
31063262
3107 if ((is_mod or is_div) and is_signed) {3263 if ((is_mod or is_div) and is_signed) {
3108 const op_token = try appendToken(rp.c, .Equal, "=");3264 const op_token = try appendToken(rp.c, .Equal, "=");
3109 const op_node = try rp.c.a().create(ast.Node.InfixOp);3265 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3110 const builtin = if (is_mod) "@rem" else "@divTrunc";3266 const builtin = if (is_mod) "@rem" else "@divTrunc";
3111 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);3267 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3112 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3268 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
3113 try builtin_node.params.push(lhs_node);3269 builtin_node.params()[0] = lhs_node;
3114 _ = try appendToken(rp.c, .Comma, ",");3270 _ = try appendToken(rp.c, .Comma, ",");
3115 try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));3271 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
3116 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3272 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3117 op_node.* = .{3273 op_node.* = .{
3118 .op_token = op_token,3274 .op_token = op_token,
...@@ -3132,11 +3288,11 @@ fn transCreateCompoundAssign(...@@ -3132,11 +3288,11 @@ fn transCreateCompoundAssign(
3132 try transExpr(rp, scope, rhs, .used, .r_value);3288 try transExpr(rp, scope, rhs, .used, .r_value);
31333289
3134 if (is_shift) {3290 if (is_shift) {
3135 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");3291 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
3136 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);3292 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
3137 try cast_node.params.push(rhs_type);3293 cast_node.params()[0] = rhs_type;
3138 _ = try appendToken(rp.c, .Comma, ",");3294 _ = try appendToken(rp.c, .Comma, ",");
3139 try cast_node.params.push(rhs_node);3295 cast_node.params()[1] = rhs_node;
3140 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");3296 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3141 rhs_node = &cast_node.base;3297 rhs_node = &cast_node.base;
3142 }3298 }
...@@ -3151,8 +3307,8 @@ fn transCreateCompoundAssign(...@@ -3151,8 +3307,8 @@ fn transCreateCompoundAssign(
3151 // zig: _ref.* = _ref.* + rhs;3307 // zig: _ref.* = _ref.* + rhs;
3152 // zig: break :blk _ref.*3308 // zig: break :blk _ref.*
3153 // zig: })3309 // zig: })
3154 const block_scope = try Scope.Block.init(rp.c, scope, "blk");3310 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3155 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);3311 defer block_scope.deinit();
3156 const ref = try block_scope.makeMangledName(rp.c, "ref");3312 const ref = try block_scope.makeMangledName(rp.c, "ref");
31573313
3158 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3314 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
...@@ -3161,7 +3317,7 @@ fn transCreateCompoundAssign(...@@ -3161,7 +3317,7 @@ fn transCreateCompoundAssign(
3161 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);3317 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3162 node.init_node = &addr_node.base;3318 node.init_node = &addr_node.base;
3163 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3319 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3164 try block_scope.block_node.statements.push(&node.base);3320 try block_scope.statements.append(&node.base);
31653321
3166 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3322 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3167 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);3323 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
...@@ -3169,12 +3325,12 @@ fn transCreateCompoundAssign(...@@ -3169,12 +3325,12 @@ fn transCreateCompoundAssign(
31693325
3170 if ((is_mod or is_div) and is_signed) {3326 if ((is_mod or is_div) and is_signed) {
3171 const op_token = try appendToken(rp.c, .Equal, "=");3327 const op_token = try appendToken(rp.c, .Equal, "=");
3172 const op_node = try rp.c.a().create(ast.Node.InfixOp);3328 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3173 const builtin = if (is_mod) "@rem" else "@divTrunc";3329 const builtin = if (is_mod) "@rem" else "@divTrunc";
3174 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);3330 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3175 try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node));3331 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);
3176 _ = try appendToken(rp.c, .Comma, ",");3332 _ = try appendToken(rp.c, .Comma, ",");
3177 try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));3333 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
3178 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3334 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3179 _ = try appendToken(rp.c, .Semicolon, ";");3335 _ = try appendToken(rp.c, .Semicolon, ";");
3180 op_node.* = .{3336 op_node.* = .{
...@@ -3184,17 +3340,17 @@ fn transCreateCompoundAssign(...@@ -3184,17 +3340,17 @@ fn transCreateCompoundAssign(
3184 .rhs = &builtin_node.base,3340 .rhs = &builtin_node.base,
3185 };3341 };
3186 _ = try appendToken(rp.c, .Semicolon, ";");3342 _ = try appendToken(rp.c, .Semicolon, ";");
3187 try block_scope.block_node.statements.push(&op_node.base);3343 try block_scope.statements.append(&op_node.base);
3188 } else {3344 } else {
3189 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);3345 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
3190 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);3346 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
31913347
3192 if (is_shift) {3348 if (is_shift) {
3193 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");3349 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
3194 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);3350 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
3195 try cast_node.params.push(rhs_type);3351 cast_node.params()[0] = rhs_type;
3196 _ = try appendToken(rp.c, .Comma, ",");3352 _ = try appendToken(rp.c, .Comma, ",");
3197 try cast_node.params.push(rhs_node);3353 cast_node.params()[1] = rhs_node;
3198 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");3354 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3199 rhs_node = &cast_node.base;3355 rhs_node = &cast_node.base;
3200 }3356 }
...@@ -3204,17 +3360,17 @@ fn transCreateCompoundAssign(...@@ -3204,17 +3360,17 @@ fn transCreateCompoundAssign(
32043360
3205 const eq_token = try appendToken(rp.c, .Equal, "=");3361 const eq_token = try appendToken(rp.c, .Equal, "=");
3206 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);3362 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
3207 try block_scope.block_node.statements.push(assign);3363 try block_scope.statements.append(assign);
3208 }3364 }
32093365
3210 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3366 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3211 break_node.rhs = ref_node;3367 break_node.rhs = ref_node;
3212 try block_scope.block_node.statements.push(&break_node.base);3368 try block_scope.statements.append(&break_node.base);
3213 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3369 const block_node = try block_scope.complete(rp.c);
3214 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3370 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3215 grouped_expr.* = .{3371 grouped_expr.* = .{
3216 .lparen = try appendToken(rp.c, .LParen, "("),3372 .lparen = try appendToken(rp.c, .LParen, "("),
3217 .expr = &block_scope.block_node.base,3373 .expr = &block_node.base,
3218 .rparen = try appendToken(rp.c, .RParen, ")"),3374 .rparen = try appendToken(rp.c, .RParen, ")"),
3219 };3375 };
3220 return &grouped_expr.base;3376 return &grouped_expr.base;
...@@ -3238,43 +3394,43 @@ fn transCPtrCast(...@@ -3238,43 +3394,43 @@ fn transCPtrCast(
3238 !ZigClangQualType_isVolatileQualified(child_type)))3394 !ZigClangQualType_isVolatileQualified(child_type)))
3239 {3395 {
3240 // Casting away const or volatile requires us to use @intToPtr3396 // Casting away const or volatile requires us to use @intToPtr
3241 const inttoptr_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");3397 const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2);
3242 const dst_type_node = try transType(rp, ty, loc);3398 const dst_type_node = try transType(rp, ty, loc);
3243 try inttoptr_node.params.push(dst_type_node);3399 inttoptr_node.params()[0] = dst_type_node;
3244 _ = try appendToken(rp.c, .Comma, ",");3400 _ = try appendToken(rp.c, .Comma, ",");
32453401
3246 const ptrtoint_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");3402 const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
3247 try ptrtoint_node.params.push(expr);3403 ptrtoint_node.params()[0] = expr;
3248 ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")");3404 ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")");
32493405
3250 try inttoptr_node.params.push(&ptrtoint_node.base);3406 inttoptr_node.params()[1] = &ptrtoint_node.base;
3251 inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");3407 inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3252 return &inttoptr_node.base;3408 return &inttoptr_node.base;
3253 } else {3409 } else {
3254 // Implicit downcasting from higher to lower alignment values is forbidden,3410 // Implicit downcasting from higher to lower alignment values is forbidden,
3255 // use @alignCast to side-step this problem3411 // use @alignCast to side-step this problem
3256 const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");3412 const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2);
3257 const dst_type_node = try transType(rp, ty, loc);3413 const dst_type_node = try transType(rp, ty, loc);
3258 try ptrcast_node.params.push(dst_type_node);3414 ptrcast_node.params()[0] = dst_type_node;
3259 _ = try appendToken(rp.c, .Comma, ",");3415 _ = try appendToken(rp.c, .Comma, ",");
32603416
3261 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {3417 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
3262 // void has 1-byte alignment, so @alignCast is not needed3418 // void has 1-byte alignment, so @alignCast is not needed
3263 try ptrcast_node.params.push(expr);3419 ptrcast_node.params()[1] = expr;
3264 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {3420 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {
3265 // For opaque types a ptrCast is enough3421 // For opaque types a ptrCast is enough
3266 try ptrcast_node.params.push(expr);3422 ptrcast_node.params()[1] = expr;
3267 } else {3423 } else {
3268 const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");3424 const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2);
3269 const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");3425 const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1);
3270 const child_type_node = try transQualType(rp, child_type, loc);3426 const child_type_node = try transQualType(rp, child_type, loc);
3271 try alignof_node.params.push(child_type_node);3427 alignof_node.params()[0] = child_type_node;
3272 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");3428 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3273 try aligncast_node.params.push(&alignof_node.base);3429 aligncast_node.params()[0] = &alignof_node.base;
3274 _ = try appendToken(rp.c, .Comma, ",");3430 _ = try appendToken(rp.c, .Comma, ",");
3275 try aligncast_node.params.push(expr);3431 aligncast_node.params()[1] = expr;
3276 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");3432 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3277 try ptrcast_node.params.push(&aligncast_node.base);3433 ptrcast_node.params()[1] = &aligncast_node.base;
3278 }3434 }
3279 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");3435 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
32803436
...@@ -3295,7 +3451,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {...@@ -3295,7 +3451,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
3295fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {3451fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
3296 // TODO use something more accurate3452 // TODO use something more accurate
3297 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);3453 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);
3298 const node = try rp.c.a().create(ast.Node.FloatLiteral);3454 const node = try rp.c.arena.create(ast.Node.FloatLiteral);
3299 node.* = .{3455 node.* = .{
3300 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),3456 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
3301 };3457 };
...@@ -3317,27 +3473,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3317,27 +3473,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3317 // })3473 // })
3318 const lparen = try appendToken(rp.c, .LParen, "(");3474 const lparen = try appendToken(rp.c, .LParen, "(");
33193475
3320 const block_scope = try Scope.Block.init(rp.c, scope, "blk");3476 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3321 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);3477 defer block_scope.deinit();
33223478
3323 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");3479 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
3324 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);3480 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);
3325 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");3481 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");
3326 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);3482 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3327 tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3483 tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3328 try block_scope.block_node.statements.push(&tmp_var.base);3484 try block_scope.statements.append(&tmp_var.base);
33293485
3330 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3486 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
33313487
3332 const if_node = try transCreateNodeIf(rp.c);3488 const if_node = try transCreateNodeIf(rp.c);
3333 var cond_scope = Scope{3489 var cond_scope = Scope.Condition{
3334 .parent = &block_scope.base,3490 .base = .{
3335 .id = .Condition,3491 .parent = &block_scope.base,
3492 .id = .Condition,
3493 },
3336 };3494 };
3495 defer cond_scope.deinit();
3337 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);3496 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);
33383497
3339 const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr));3498 const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr));
3340 const cond_node = try finishBoolExpr(rp, &block_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used);3499 const cond_node = try finishBoolExpr(rp, &cond_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used);
3341 if_node.condition = cond_node;3500 if_node.condition = cond_node;
3342 _ = try appendToken(rp.c, .RParen, ")");3501 _ = try appendToken(rp.c, .RParen, ")");
33433502
...@@ -3348,13 +3507,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3348,13 +3507,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
33483507
3349 break_node.rhs = &if_node.base;3508 break_node.rhs = &if_node.base;
3350 _ = try appendToken(rp.c, .Semicolon, ";");3509 _ = try appendToken(rp.c, .Semicolon, ";");
3351 try block_scope.block_node.statements.push(&break_node.base);3510 try block_scope.statements.append(&break_node.base);
3352 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3511 const block_node = try block_scope.complete(rp.c);
33533512
3354 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3513 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3355 grouped_expr.* = .{3514 grouped_expr.* = .{
3356 .lparen = lparen,3515 .lparen = lparen,
3357 .expr = &block_scope.block_node.base,3516 .expr = &block_node.base,
3358 .rparen = try appendToken(rp.c, .RParen, ")"),3517 .rparen = try appendToken(rp.c, .RParen, ")"),
3359 };3518 };
3360 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);3519 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
...@@ -3364,17 +3523,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla...@@ -3364,17 +3523,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
3364 const grouped = scope.id == .Condition;3523 const grouped = scope.id == .Condition;
3365 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;3524 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
3366 const if_node = try transCreateNodeIf(rp.c);3525 const if_node = try transCreateNodeIf(rp.c);
3367 var cond_scope = Scope{3526 var cond_scope = Scope.Condition{
3368 .parent = scope,3527 .base = .{
3369 .id = .Condition,3528 .parent = scope,
3529 .id = .Condition,
3530 },
3370 };3531 };
3532 defer cond_scope.deinit();
33713533
3372 const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt);3534 const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt);
3373 const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt);3535 const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt);
3374 const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt);3536 const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt);
3375 const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt);3537 const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt);
33763538
3377 if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false);3539 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
3378 _ = try appendToken(rp.c, .RParen, ")");3540 _ = try appendToken(rp.c, .RParen, ")");
33793541
3380 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);3542 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
...@@ -3384,7 +3546,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla...@@ -3384,7 +3546,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
33843546
3385 if (grouped) {3547 if (grouped) {
3386 const rparen = try appendToken(rp.c, .RParen, ")");3548 const rparen = try appendToken(rp.c, .RParen, ")");
3387 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3549 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3388 grouped_expr.* = .{3550 grouped_expr.* = .{
3389 .lparen = lparen,3551 .lparen = lparen,
3390 .expr = &if_node.base,3552 .expr = &if_node.base,
...@@ -3415,7 +3577,7 @@ fn maybeSuppressResult(...@@ -3415,7 +3577,7 @@ fn maybeSuppressResult(
3415 }3577 }
3416 const lhs = try transCreateNodeIdentifier(rp.c, "_");3578 const lhs = try transCreateNodeIdentifier(rp.c, "_");
3417 const op_token = try appendToken(rp.c, .Equal, "=");3579 const op_token = try appendToken(rp.c, .Equal, "=");
3418 const op_node = try rp.c.a().create(ast.Node.InfixOp);3580 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3419 op_node.* = .{3581 op_node.* = .{
3420 .op_token = op_token,3582 .op_token = op_token,
3421 .lhs = lhs,3583 .lhs = lhs,
...@@ -3426,7 +3588,7 @@ fn maybeSuppressResult(...@@ -3426,7 +3588,7 @@ fn maybeSuppressResult(
3426}3588}
34273589
3428fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {3590fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
3429 try c.tree.root_node.decls.push(decl_node);3591 try c.root_decls.append(c.gpa, decl_node);
3430 _ = try c.global_scope.sym_table.put(name, decl_node);3592 _ = try c.global_scope.sym_table.put(name, decl_node);
3431}3593}
34323594
...@@ -3524,7 +3686,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC...@@ -3524,7 +3686,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
3524 if (int_bit_width != 0) {3686 if (int_bit_width != 0) {
3525 // we can perform the log2 now.3687 // we can perform the log2 now.
3526 const cast_bit_width = math.log2_int(u64, int_bit_width);3688 const cast_bit_width = math.log2_int(u64, int_bit_width);
3527 const node = try rp.c.a().create(ast.Node.IntegerLiteral);3689 const node = try rp.c.arena.create(ast.Node.IntegerLiteral);
3528 node.* = .{3690 node.* = .{
3529 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),3691 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
3530 };3692 };
...@@ -3545,19 +3707,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC...@@ -3545,19 +3707,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
3545 // Symbol "Log2Int"3707 // Symbol "Log2Int"
3546 // Symbol <zig_type_node> (var from above)3708 // Symbol <zig_type_node> (var from above)
35473709
3548 const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import");3710 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);
3549 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");3711 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
3550 const std_node = try rp.c.a().create(ast.Node.StringLiteral);3712 const std_node = try rp.c.arena.create(ast.Node.StringLiteral);
3551 std_node.* = .{3713 std_node.* = .{
3552 .token = std_token,3714 .token = std_token,
3553 };3715 };
3554 try import_fn_call.params.push(&std_node.base);3716 import_fn_call.params()[0] = &std_node.base;
3555 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");3717 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
35563718
3557 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");3719 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
3558 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");3720 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
3559 const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access);3721 const log2int_fn_call = try rp.c.createCall(outer_field_access, 1);
3560 try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node);3722 log2int_fn_call.params()[0] = zig_type_node;
3561 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");3723 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
35623724
3563 return &log2int_fn_call.base;3725 return &log2int_fn_call.base;
...@@ -3731,8 +3893,8 @@ fn transCreateNodeAssign(...@@ -3731,8 +3893,8 @@ fn transCreateNodeAssign(
3731 const eq_token = try appendToken(rp.c, .Equal, "=");3893 const eq_token = try appendToken(rp.c, .Equal, "=");
3732 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);3894 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
3733 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {3895 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3734 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");3896 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3735 try builtin_node.params.push(rhs_node);3897 builtin_node.params()[0] = rhs_node;
3736 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3898 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3737 rhs_node = &builtin_node.base;3899 rhs_node = &builtin_node.base;
3738 }3900 }
...@@ -3748,22 +3910,24 @@ fn transCreateNodeAssign(...@@ -3748,22 +3910,24 @@ fn transCreateNodeAssign(
3748 // zig: lhs = _tmp;3910 // zig: lhs = _tmp;
3749 // zig: break :blk _tmp3911 // zig: break :blk _tmp
3750 // zig: })3912 // zig: })
3751 const block_scope = try Scope.Block.init(rp.c, scope, "blk");3913 const label_name = "blk";
3752 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);3914 var block_scope = try Scope.Block.init(rp.c, scope, label_name);
3915 defer block_scope.deinit();
3916
3753 const tmp = try block_scope.makeMangledName(rp.c, "tmp");3917 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
37543918
3755 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);3919 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
3756 node.eq_token = try appendToken(rp.c, .Equal, "=");3920 node.eq_token = try appendToken(rp.c, .Equal, "=");
3757 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);3921 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
3758 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {3922 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3759 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");3923 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3760 try builtin_node.params.push(rhs_node);3924 builtin_node.params()[0] = rhs_node;
3761 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3925 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3762 rhs_node = &builtin_node.base;3926 rhs_node = &builtin_node.base;
3763 }3927 }
3764 node.init_node = rhs_node;3928 node.init_node = rhs_node;
3765 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3929 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3766 try block_scope.block_node.statements.push(&node.base);3930 try block_scope.statements.append(&node.base);
37673931
3768 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);3932 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
3769 const eq_token = try appendToken(rp.c, .Equal, "=");3933 const eq_token = try appendToken(rp.c, .Equal, "=");
...@@ -3771,48 +3935,20 @@ fn transCreateNodeAssign(...@@ -3771,48 +3935,20 @@ fn transCreateNodeAssign(
3771 _ = try appendToken(rp.c, .Semicolon, ";");3935 _ = try appendToken(rp.c, .Semicolon, ";");
37723936
3773 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false);3937 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false);
3774 try block_scope.block_node.statements.push(assign);3938 try block_scope.statements.append(assign);
37753939
3776 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3940 const break_node = try transCreateNodeBreak(rp.c, label_name);
3777 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);3941 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
3778 _ = try appendToken(rp.c, .Semicolon, ";");3942 _ = try appendToken(rp.c, .Semicolon, ";");
3779 try block_scope.block_node.statements.push(&break_node.base);3943 try block_scope.statements.append(&break_node.base);
3780 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3944 const block_node = try block_scope.complete(rp.c);
3781 // semicolon must immediately follow rbrace because it is the last token in a block3945 // semicolon must immediately follow rbrace because it is the last token in a block
3782 _ = try appendToken(rp.c, .Semicolon, ";");3946 _ = try appendToken(rp.c, .Semicolon, ";");
3783 return &block_scope.block_node.base;3947 return &block_node.base;
3784}
3785
3786fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall {
3787 const builtin_token = try appendToken(c, .Builtin, name);
3788 _ = try appendToken(c, .LParen, "(");
3789 const node = try c.a().create(ast.Node.BuiltinCall);
3790 node.* = .{
3791 .builtin_token = builtin_token,
3792 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
3793 .rparen_token = undefined, // set after appending args
3794 };
3795 return node;
3796}
3797
3798fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
3799 _ = try appendToken(c, .LParen, "(");
3800 const node = try c.a().create(ast.Node.SuffixOp);
3801 node.* = .{
3802 .lhs = .{ .node = fn_expr },
3803 .op = .{
3804 .Call = .{
3805 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
3806 .async_token = null,
3807 },
3808 },
3809 .rtoken = undefined, // set after appending args
3810 };
3811 return node;
3812}3948}
38133949
3814fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {3950fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
3815 const field_access_node = try c.a().create(ast.Node.InfixOp);3951 const field_access_node = try c.arena.create(ast.Node.InfixOp);
3816 field_access_node.* = .{3952 field_access_node.* = .{
3817 .op_token = try appendToken(c, .Period, "."),3953 .op_token = try appendToken(c, .Period, "."),
3818 .lhs = container,3954 .lhs = container,
...@@ -3828,7 +3964,7 @@ fn transCreateNodePrefixOp(...@@ -3828,7 +3964,7 @@ fn transCreateNodePrefixOp(
3828 op_tok_id: std.zig.Token.Id,3964 op_tok_id: std.zig.Token.Id,
3829 bytes: []const u8,3965 bytes: []const u8,
3830) !*ast.Node.PrefixOp {3966) !*ast.Node.PrefixOp {
3831 const node = try c.a().create(ast.Node.PrefixOp);3967 const node = try c.arena.create(ast.Node.PrefixOp);
3832 node.* = .{3968 node.* = .{
3833 .op_token = try appendToken(c, op_tok_id, bytes),3969 .op_token = try appendToken(c, op_tok_id, bytes),
3834 .op = op,3970 .op = op,
...@@ -3851,7 +3987,7 @@ fn transCreateNodeInfixOp(...@@ -3851,7 +3987,7 @@ fn transCreateNodeInfixOp(
3851 try appendToken(rp.c, .LParen, "(")3987 try appendToken(rp.c, .LParen, "(")
3852 else3988 else
3853 null;3989 null;
3854 const node = try rp.c.a().create(ast.Node.InfixOp);3990 const node = try rp.c.arena.create(ast.Node.InfixOp);
3855 node.* = .{3991 node.* = .{
3856 .op_token = op_token,3992 .op_token = op_token,
3857 .lhs = lhs_node,3993 .lhs = lhs_node,
...@@ -3860,7 +3996,7 @@ fn transCreateNodeInfixOp(...@@ -3860,7 +3996,7 @@ fn transCreateNodeInfixOp(
3860 };3996 };
3861 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);3997 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
3862 const rparen = try appendToken(rp.c, .RParen, ")");3998 const rparen = try appendToken(rp.c, .RParen, ")");
3863 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3999 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3864 grouped_expr.* = .{4000 grouped_expr.* = .{
3865 .lparen = lparen.?,4001 .lparen = lparen.?,
3866 .expr = &node.base,4002 .expr = &node.base,
...@@ -3904,7 +4040,7 @@ fn transCreateNodePtrType(...@@ -3904,7 +4040,7 @@ fn transCreateNodePtrType(
3904 is_volatile: bool,4040 is_volatile: bool,
3905 op_tok_id: std.zig.Token.Id,4041 op_tok_id: std.zig.Token.Id,
3906) !*ast.Node.PrefixOp {4042) !*ast.Node.PrefixOp {
3907 const node = try c.a().create(ast.Node.PrefixOp);4043 const node = try c.arena.create(ast.Node.PrefixOp);
3908 const op_token = switch (op_tok_id) {4044 const op_token = switch (op_tok_id) {
3909 .LBracket => blk: {4045 .LBracket => blk: {
3910 const lbracket = try appendToken(c, .LBracket, "[");4046 const lbracket = try appendToken(c, .LBracket, "[");
...@@ -3946,8 +4082,8 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {...@@ -3946,8 +4082,8 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
3946 ZigClangAPSInt_free(aps_int);4082 ZigClangAPSInt_free(aps_int);
3947 };4083 };
39484084
3949 const limbs = try c.a().alloc(math.big.Limb, num_limbs);4085 const limbs = try c.arena.alloc(math.big.Limb, num_limbs);
3950 defer c.a().free(limbs);4086 defer c.arena.free(limbs);
39514087
3952 const data = ZigClangAPSInt_getRawData(aps_int);4088 const data = ZigClangAPSInt_getRawData(aps_int);
3953 switch (@sizeOf(math.big.Limb)) {4089 switch (@sizeOf(math.big.Limb)) {
...@@ -3972,12 +4108,12 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {...@@ -3972,12 +4108,12 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
3972 }4108 }
39734109
3974 const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };4110 const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };
3975 const str = big.toStringAlloc(c.a(), 10, false) catch |err| switch (err) {4111 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
3976 error.OutOfMemory => return error.OutOfMemory,4112 error.OutOfMemory => return error.OutOfMemory,
3977 };4113 };
3978 defer c.a().free(str);4114 defer c.arena.free(str);
3979 const token = try appendToken(c, .IntegerLiteral, str);4115 const token = try appendToken(c, .IntegerLiteral, str);
3980 const node = try c.a().create(ast.Node.IntegerLiteral);4116 const node = try c.arena.create(ast.Node.IntegerLiteral);
3981 node.* = .{4117 node.* = .{
3982 .token = token,4118 .token = token,
3983 };4119 };
...@@ -3986,7 +4122,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {...@@ -3986,7 +4122,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39864122
3987fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {4123fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
3988 const ltoken = try appendToken(c, .Keyword_return, "return");4124 const ltoken = try appendToken(c, .Keyword_return, "return");
3989 const node = try c.a().create(ast.Node.ControlFlowExpression);4125 const node = try c.arena.create(ast.Node.ControlFlowExpression);
3990 node.* = .{4126 node.* = .{
3991 .ltoken = ltoken,4127 .ltoken = ltoken,
3992 .kind = .Return,4128 .kind = .Return,
...@@ -3997,7 +4133,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {...@@ -3997,7 +4133,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
39974133
3998fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {4134fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
3999 const token = try appendToken(c, .Keyword_undefined, "undefined");4135 const token = try appendToken(c, .Keyword_undefined, "undefined");
4000 const node = try c.a().create(ast.Node.UndefinedLiteral);4136 const node = try c.arena.create(ast.Node.UndefinedLiteral);
4001 node.* = .{4137 node.* = .{
4002 .token = token,4138 .token = token,
4003 };4139 };
...@@ -4006,7 +4142,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {...@@ -4006,7 +4142,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
40064142
4007fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {4143fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
4008 const token = try appendToken(c, .Keyword_null, "null");4144 const token = try appendToken(c, .Keyword_null, "null");
4009 const node = try c.a().create(ast.Node.NullLiteral);4145 const node = try c.arena.create(ast.Node.NullLiteral);
4010 node.* = .{4146 node.* = .{
4011 .token = token,4147 .token = token,
4012 };4148 };
...@@ -4018,42 +4154,16 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {...@@ -4018,42 +4154,16 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
4018 try appendToken(c, .Keyword_true, "true")4154 try appendToken(c, .Keyword_true, "true")
4019 else4155 else
4020 try appendToken(c, .Keyword_false, "false");4156 try appendToken(c, .Keyword_false, "false");
4021 const node = try c.a().create(ast.Node.BoolLiteral);4157 const node = try c.arena.create(ast.Node.BoolLiteral);
4022 node.* = .{4158 node.* = .{
4023 .token = token,4159 .token = token,
4024 };4160 };
4025 return &node.base;4161 return &node.base;
4026}4162}
40274163
4028fn transCreateNodeArrayInitializer(c: *Context, ty: *ast.Node) !*ast.Node.SuffixOp {
4029 _ = try appendToken(c, .LBrace, "{");
4030 const node = try c.a().create(ast.Node.SuffixOp);
4031 node.* = .{
4032 .lhs = .{ .node = ty },
4033 .op = .{
4034 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()),
4035 },
4036 .rtoken = undefined, // set after appending values
4037 };
4038 return node;
4039}
4040
4041fn transCreateNodeStructInitializer(c: *Context, ty: *ast.Node) !*ast.Node.SuffixOp {
4042 _ = try appendToken(c, .LBrace, "{");
4043 const node = try c.a().create(ast.Node.SuffixOp);
4044 node.* = .{
4045 .lhs = .{ .node = ty },
4046 .op = .{
4047 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()),
4048 },
4049 .rtoken = undefined, // set after appending values
4050 };
4051 return node;
4052}
4053
4054fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {4164fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
4055 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});4165 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
4056 const node = try c.a().create(ast.Node.IntegerLiteral);4166 const node = try c.arena.create(ast.Node.IntegerLiteral);
4057 node.* = .{4167 node.* = .{
4058 .token = token,4168 .token = token,
4059 };4169 };
...@@ -4062,7 +4172,7 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {...@@ -4062,7 +4172,7 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
40624172
4063fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {4173fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
4064 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});4174 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});
4065 const node = try c.a().create(ast.Node.FloatLiteral);4175 const node = try c.arena.create(ast.Node.FloatLiteral);
4066 node.* = .{4176 node.* = .{
4067 .token = token,4177 .token = token,
4068 };4178 };
...@@ -4070,8 +4180,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {...@@ -4070,8 +4180,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
4070}4180}
40714181
4072fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {4182fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
4073 const call_node = try transCreateNodeBuiltinFnCall(c, "@Type");4183 const call_node = try c.createBuiltinCall("@Type", 1);
4074 try call_node.params.push(try transCreateNodeEnumLiteral(c, "Opaque"));4184 call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque");
4075 call_node.rparen_token = try appendToken(c, .RParen, ")");4185 call_node.rparen_token = try appendToken(c, .RParen, ")");
4076 return &call_node.base;4186 return &call_node.base;
4077}4187}
...@@ -4085,39 +4195,36 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4085,39 +4195,36 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4085 const name_tok = try appendIdentifier(c, name);4195 const name_tok = try appendIdentifier(c, name);
4086 _ = try appendToken(c, .LParen, "(");4196 _ = try appendToken(c, .LParen, "(");
40874197
4088 var fn_params = ast.Node.FnProto.ParamList.init(c.a());4198 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
4089 var it = proto_alias.params.iterator(0);4199 defer fn_params.deinit();
4090 while (it.next()) |pn| {4200
4091 if (it.index != 0) {4201 for (proto_alias.params()) |param, i| {
4202 if (i != 0) {
4092 _ = try appendToken(c, .Comma, ",");4203 _ = try appendToken(c, .Comma, ",");
4093 }4204 }
4094 const param = pn.*.cast(ast.Node.ParamDecl).?;
4095
4096 const param_name_tok = param.name_token orelse4205 const param_name_tok = param.name_token orelse
4097 try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()});4206 try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()});
40984207
4099 _ = try appendToken(c, .Colon, ":");4208 _ = try appendToken(c, .Colon, ":");
41004209
4101 const param_node = try c.a().create(ast.Node.ParamDecl);4210 (try fn_params.addOne()).* = .{
4102 param_node.* = .{
4103 .doc_comments = null,4211 .doc_comments = null,
4104 .comptime_token = null,4212 .comptime_token = null,
4105 .noalias_token = param.noalias_token,4213 .noalias_token = param.noalias_token,
4106 .name_token = param_name_tok,4214 .name_token = param_name_tok,
4107 .param_type = param.param_type,4215 .param_type = param.param_type,
4108 };4216 };
4109 try fn_params.push(&param_node.base);
4110 }4217 }
41114218
4112 _ = try appendToken(c, .RParen, ")");4219 _ = try appendToken(c, .RParen, ")");
41134220
4114 const fn_proto = try c.a().create(ast.Node.FnProto);4221 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
4115 fn_proto.* = .{4222 fn_proto.* = .{
4116 .doc_comments = null,4223 .doc_comments = null,
4117 .visib_token = pub_tok,4224 .visib_token = pub_tok,
4118 .fn_token = fn_tok,4225 .fn_token = fn_tok,
4119 .name_token = name_tok,4226 .name_token = name_tok,
4120 .params = fn_params,4227 .params_len = fn_params.items.len,
4121 .return_type = proto_alias.return_type,4228 .return_type = proto_alias.return_type,
4122 .var_args_token = null,4229 .var_args_token = null,
4123 .extern_export_inline_token = inline_tok,4230 .extern_export_inline_token = inline_tok,
...@@ -4127,26 +4234,35 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4127,26 +4234,35 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4127 .section_expr = null,4234 .section_expr = null,
4128 .callconv_expr = null,4235 .callconv_expr = null,
4129 };4236 };
4237 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
41304238
4131 const block = try transCreateNodeBlock(c, null);4239 const block_lbrace = try appendToken(c, .LBrace, "{");
41324240
4133 const return_expr = try transCreateNodeReturnExpr(c);4241 const return_expr = try transCreateNodeReturnExpr(c);
4134 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);4242 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
4135 const call_expr = try transCreateNodeFnCall(c, unwrap_expr);4243
4136 it = fn_params.iterator(0);4244 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
4137 while (it.next()) |pn| {4245 const call_params = call_expr.params();
4138 if (it.index != 0) {4246
4247 for (fn_params.items) |param, i| {
4248 if (i != 0) {
4139 _ = try appendToken(c, .Comma, ",");4249 _ = try appendToken(c, .Comma, ",");
4140 }4250 }
4141 const param = pn.*.cast(ast.Node.ParamDecl).?;4251 call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?));
4142 try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)));
4143 }4252 }
4144 call_expr.rtoken = try appendToken(c, .RParen, ")");4253 call_expr.rtoken = try appendToken(c, .RParen, ")");
4254
4145 return_expr.rhs = &call_expr.base;4255 return_expr.rhs = &call_expr.base;
4146 _ = try appendToken(c, .Semicolon, ";");4256 _ = try appendToken(c, .Semicolon, ";");
41474257
4148 block.rbrace = try appendToken(c, .RBrace, "}");4258 const block = try ast.Node.Block.alloc(c.arena, 1);
4149 try block.statements.push(&return_expr.base);4259 block.* = .{
4260 .label = null,
4261 .lbrace = block_lbrace,
4262 .statements_len = 1,
4263 .rbrace = try appendToken(c, .RBrace, "}"),
4264 };
4265 block.statements()[0] = &return_expr.base;
4150 fn_proto.body_node = &block.base;4266 fn_proto.body_node = &block.base;
4151 return &fn_proto.base;4267 return &fn_proto.base;
4152}4268}
...@@ -4154,17 +4270,17 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4154,17 +4270,17 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4154fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {4270fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
4155 _ = try appendToken(c, .Period, ".");4271 _ = try appendToken(c, .Period, ".");
4156 const qm = try appendToken(c, .QuestionMark, "?");4272 const qm = try appendToken(c, .QuestionMark, "?");
4157 const node = try c.a().create(ast.Node.SuffixOp);4273 const node = try c.arena.create(ast.Node.SuffixOp);
4158 node.* = .{4274 node.* = .{
4159 .op = .UnwrapOptional,4275 .op = .UnwrapOptional,
4160 .lhs = .{ .node = wrapped },4276 .lhs = wrapped,
4161 .rtoken = qm,4277 .rtoken = qm,
4162 };4278 };
4163 return &node.base;4279 return &node.base;
4164}4280}
41654281
4166fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {4282fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
4167 const node = try c.a().create(ast.Node.EnumLiteral);4283 const node = try c.arena.create(ast.Node.EnumLiteral);
4168 node.* = .{4284 node.* = .{
4169 .dot = try appendToken(c, .Period, "."),4285 .dot = try appendToken(c, .Period, "."),
4170 .name = try appendIdentifier(c, name),4286 .name = try appendIdentifier(c, name),
...@@ -4173,7 +4289,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {...@@ -4173,7 +4289,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
4173}4289}
41744290
4175fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {4291fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
4176 const node = try c.a().create(ast.Node.StringLiteral);4292 const node = try c.arena.create(ast.Node.StringLiteral);
4177 node.* = .{4293 node.* = .{
4178 .token = try appendToken(c, .StringLiteral, str),4294 .token = try appendToken(c, .StringLiteral, str),
4179 };4295 };
...@@ -4183,7 +4299,7 @@ fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {...@@ -4183,7 +4299,7 @@ fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
4183fn transCreateNodeIf(c: *Context) !*ast.Node.If {4299fn transCreateNodeIf(c: *Context) !*ast.Node.If {
4184 const if_tok = try appendToken(c, .Keyword_if, "if");4300 const if_tok = try appendToken(c, .Keyword_if, "if");
4185 _ = try appendToken(c, .LParen, "(");4301 _ = try appendToken(c, .LParen, "(");
4186 const node = try c.a().create(ast.Node.If);4302 const node = try c.arena.create(ast.Node.If);
4187 node.* = .{4303 node.* = .{
4188 .if_token = if_tok,4304 .if_token = if_tok,
4189 .condition = undefined,4305 .condition = undefined,
...@@ -4195,7 +4311,7 @@ fn transCreateNodeIf(c: *Context) !*ast.Node.If {...@@ -4195,7 +4311,7 @@ fn transCreateNodeIf(c: *Context) !*ast.Node.If {
4195}4311}
41964312
4197fn transCreateNodeElse(c: *Context) !*ast.Node.Else {4313fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
4198 const node = try c.a().create(ast.Node.Else);4314 const node = try c.arena.create(ast.Node.Else);
4199 node.* = .{4315 node.* = .{
4200 .else_token = try appendToken(c, .Keyword_else, "else"),4316 .else_token = try appendToken(c, .Keyword_else, "else"),
4201 .payload = null,4317 .payload = null,
...@@ -4204,20 +4320,11 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {...@@ -4204,20 +4320,11 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
4204 return node;4320 return node;
4205}4321}
42064322
4207fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {4323fn transCreateNodeBreakToken(c: *Context, label: ?ast.TokenIndex) !*ast.Node.ControlFlowExpression {
4208 const label_node = if (label) |l| blk: {4324 const other_token = label orelse return transCreateNodeBreak(c, null);
4209 const ll = try appendIdentifier(c, l);4325 const loc = c.token_locs.items[other_token];
4210 _ = try appendToken(c, .Colon, ":");4326 const label_name = c.source_buffer.items[loc.start..loc.end];
4211 break :blk ll;4327 return transCreateNodeBreak(c, label_name);
4212 } else null;
4213 const block_node = try c.a().create(ast.Node.Block);
4214 block_node.* = .{
4215 .label = label_node,
4216 .lbrace = try appendToken(c, .LBrace, "{"),
4217 .statements = ast.Node.Block.StatementList.init(c.a()),
4218 .rbrace = undefined,
4219 };
4220 return block_node;
4221}4328}
42224329
4223fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {4330fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {
...@@ -4226,7 +4333,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE...@@ -4226,7 +4333,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
4226 _ = try appendToken(c, .Colon, ":");4333 _ = try appendToken(c, .Colon, ":");
4227 break :blk try transCreateNodeIdentifier(c, l);4334 break :blk try transCreateNodeIdentifier(c, l);
4228 } else null;4335 } else null;
4229 const node = try c.a().create(ast.Node.ControlFlowExpression);4336 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4230 node.* = .{4337 node.* = .{
4231 .ltoken = ltoken,4338 .ltoken = ltoken,
4232 .kind = .{ .Break = label_node },4339 .kind = .{ .Break = label_node },
...@@ -4240,7 +4347,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con...@@ -4240,7 +4347,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con
4240 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");4347 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
4241 const name_tok = try appendIdentifier(c, name);4348 const name_tok = try appendIdentifier(c, name);
42424349
4243 const node = try c.a().create(ast.Node.VarDecl);4350 const node = try c.arena.create(ast.Node.VarDecl);
4244 node.* = .{4351 node.* = .{
4245 .doc_comments = null,4352 .doc_comments = null,
4246 .visib_token = visib_tok,4353 .visib_token = visib_tok,
...@@ -4264,7 +4371,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {...@@ -4264,7 +4371,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
4264 const while_tok = try appendToken(c, .Keyword_while, "while");4371 const while_tok = try appendToken(c, .Keyword_while, "while");
4265 _ = try appendToken(c, .LParen, "(");4372 _ = try appendToken(c, .LParen, "(");
42664373
4267 const node = try c.a().create(ast.Node.While);4374 const node = try c.arena.create(ast.Node.While);
4268 node.* = .{4375 node.* = .{
4269 .label = null,4376 .label = null,
4270 .inline_token = null,4377 .inline_token = null,
...@@ -4280,7 +4387,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {...@@ -4280,7 +4387,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
42804387
4281fn transCreateNodeContinue(c: *Context) !*ast.Node {4388fn transCreateNodeContinue(c: *Context) !*ast.Node {
4282 const ltoken = try appendToken(c, .Keyword_continue, "continue");4389 const ltoken = try appendToken(c, .Keyword_continue, "continue");
4283 const node = try c.a().create(ast.Node.ControlFlowExpression);4390 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4284 node.* = .{4391 node.* = .{
4285 .ltoken = ltoken,4392 .ltoken = ltoken,
4286 .kind = .{ .Continue = null },4393 .kind = .{ .Continue = null },
...@@ -4290,36 +4397,22 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node {...@@ -4290,36 +4397,22 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node {
4290 return &node.base;4397 return &node.base;
4291}4398}
42924399
4293fn transCreateNodeSwitch(c: *Context) !*ast.Node.Switch {
4294 const switch_tok = try appendToken(c, .Keyword_switch, "switch");
4295 _ = try appendToken(c, .LParen, "(");
4296
4297 const node = try c.a().create(ast.Node.Switch);
4298 node.* = .{
4299 .switch_token = switch_tok,
4300 .expr = undefined,
4301 .cases = ast.Node.Switch.CaseList.init(c.a()),
4302 .rbrace = undefined,
4303 };
4304 return node;
4305}
4306
4307fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase {4400fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase {
4308 const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>");4401 const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>");
43094402
4310 const node = try c.a().create(ast.Node.SwitchCase);4403 const node = try ast.Node.SwitchCase.alloc(c.arena, 1);
4311 node.* = .{4404 node.* = .{
4312 .items = ast.Node.SwitchCase.ItemList.init(c.a()),4405 .items_len = 1,
4313 .arrow_token = arrow_tok,4406 .arrow_token = arrow_tok,
4314 .payload = null,4407 .payload = null,
4315 .expr = undefined,4408 .expr = undefined,
4316 };4409 };
4317 try node.items.push(lhs);4410 node.items()[0] = lhs;
4318 return node;4411 return node;
4319}4412}
43204413
4321fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {4414fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {
4322 const node = try c.a().create(ast.Node.SwitchElse);4415 const node = try c.arena.create(ast.Node.SwitchElse);
4323 node.* = .{4416 node.* = .{
4324 .token = try appendToken(c, .Keyword_else, "else"),4417 .token = try appendToken(c, .Keyword_else, "else"),
4325 };4418 };
...@@ -4344,15 +4437,15 @@ fn transCreateNodeShiftOp(...@@ -4344,15 +4437,15 @@ fn transCreateNodeShiftOp(
4344 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);4437 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
4345 const op_token = try appendToken(rp.c, op_tok_id, bytes);4438 const op_token = try appendToken(rp.c, op_tok_id, bytes);
43464439
4347 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");4440 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
4348 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);4441 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
4349 try cast_node.params.push(rhs_type);4442 cast_node.params()[0] = rhs_type;
4350 _ = try appendToken(rp.c, .Comma, ",");4443 _ = try appendToken(rp.c, .Comma, ",");
4351 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);4444 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
4352 try cast_node.params.push(rhs);4445 cast_node.params()[1] = rhs;
4353 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");4446 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
43544447
4355 const node = try rp.c.a().create(ast.Node.InfixOp);4448 const node = try rp.c.arena.create(ast.Node.InfixOp);
4356 node.* = .{4449 node.* = .{
4357 .op_token = op_token,4450 .op_token = op_token,
4358 .lhs = lhs,4451 .lhs = lhs,
...@@ -4364,9 +4457,9 @@ fn transCreateNodeShiftOp(...@@ -4364,9 +4457,9 @@ fn transCreateNodeShiftOp(
4364}4457}
43654458
4366fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {4459fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
4367 const node = try c.a().create(ast.Node.SuffixOp);4460 const node = try c.arena.create(ast.Node.SuffixOp);
4368 node.* = .{4461 node.* = .{
4369 .lhs = .{ .node = lhs },4462 .lhs = lhs,
4370 .op = .Deref,4463 .op = .Deref,
4371 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),4464 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
4372 };4465 };
...@@ -4375,9 +4468,9 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {...@@ -4375,9 +4468,9 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
43754468
4376fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {4469fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {
4377 _ = try appendToken(c, .LBrace, "[");4470 _ = try appendToken(c, .LBrace, "[");
4378 const node = try c.a().create(ast.Node.SuffixOp);4471 const node = try c.arena.create(ast.Node.SuffixOp);
4379 node.* = .{4472 node.* = .{
4380 .lhs = .{ .node = lhs },4473 .lhs = lhs,
4381 .op = .{4474 .op = .{
4382 .ArrayAccess = undefined,4475 .ArrayAccess = undefined,
4383 },4476 },
...@@ -4392,7 +4485,8 @@ const RestorePoint = struct {...@@ -4392,7 +4485,8 @@ const RestorePoint = struct {
4392 src_buf_index: usize,4485 src_buf_index: usize,
43934486
4394 fn activate(self: RestorePoint) void {4487 fn activate(self: RestorePoint) void {
4395 self.c.tree.tokens.shrink(self.token_index);4488 self.c.token_ids.shrink(self.c.gpa, self.token_index);
4489 self.c.token_locs.shrink(self.c.gpa, self.token_index);
4396 self.c.source_buffer.shrink(self.src_buf_index);4490 self.c.source_buffer.shrink(self.src_buf_index);
4397 }4491 }
4398};4492};
...@@ -4400,7 +4494,7 @@ const RestorePoint = struct {...@@ -4400,7 +4494,7 @@ const RestorePoint = struct {
4400fn makeRestorePoint(c: *Context) RestorePoint {4494fn makeRestorePoint(c: *Context) RestorePoint {
4401 return RestorePoint{4495 return RestorePoint{
4402 .c = c,4496 .c = c,
4403 .token_index = c.tree.tokens.len,4497 .token_index = c.token_ids.items.len,
4404 .src_buf_index = c.source_buffer.items.len,4498 .src_buf_index = c.source_buffer.items.len,
4405 };4499 };
4406}4500}
...@@ -4647,8 +4741,10 @@ fn finishTransFnProto(...@@ -4647,8 +4741,10 @@ fn finishTransFnProto(
4647 const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;4741 const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
4648 const lparen_tok = try appendToken(rp.c, .LParen, "(");4742 const lparen_tok = try appendToken(rp.c, .LParen, "(");
46494743
4650 var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a());4744 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa);
4745 defer fn_params.deinit();
4651 const param_count: usize = if (fn_proto_ty != null) ZigClangFunctionProtoType_getNumParams(fn_proto_ty.?) else 0;4746 const param_count: usize = if (fn_proto_ty != null) ZigClangFunctionProtoType_getNumParams(fn_proto_ty.?) else 0;
4747 try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node
46524748
4653 var i: usize = 0;4749 var i: usize = 0;
4654 while (i < param_count) : (i += 1) {4750 while (i < param_count) : (i += 1) {
...@@ -4672,15 +4768,13 @@ fn finishTransFnProto(...@@ -4672,15 +4768,13 @@ fn finishTransFnProto(
46724768
4673 const type_node = try transQualType(rp, param_qt, source_loc);4769 const type_node = try transQualType(rp, param_qt, source_loc);
46744770
4675 const param_node = try rp.c.a().create(ast.Node.ParamDecl);4771 fn_params.addOneAssumeCapacity().* = .{
4676 param_node.* = .{
4677 .doc_comments = null,4772 .doc_comments = null,
4678 .comptime_token = null,4773 .comptime_token = null,
4679 .noalias_token = noalias_tok,4774 .noalias_token = noalias_tok,
4680 .name_token = param_name_tok,4775 .name_token = param_name_tok,
4681 .param_type = .{ .type_expr = type_node },4776 .param_type = .{ .type_expr = type_node },
4682 };4777 };
4683 try fn_params.push(&param_node.base);
46844778
4685 if (i + 1 < param_count) {4779 if (i + 1 < param_count) {
4686 _ = try appendToken(rp.c, .Comma, ",");4780 _ = try appendToken(rp.c, .Comma, ",");
...@@ -4692,15 +4786,13 @@ fn finishTransFnProto(...@@ -4692,15 +4786,13 @@ fn finishTransFnProto(
4692 _ = try appendToken(rp.c, .Comma, ",");4786 _ = try appendToken(rp.c, .Comma, ",");
4693 }4787 }
46944788
4695 const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl);4789 fn_params.addOneAssumeCapacity().* = .{
4696 var_arg_node.* = .{
4697 .doc_comments = null,4790 .doc_comments = null,
4698 .comptime_token = null,4791 .comptime_token = null,
4699 .noalias_token = null,4792 .noalias_token = null,
4700 .name_token = null,4793 .name_token = null,
4701 .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") }4794 .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") }
4702 };4795 };
4703 try fn_params.push(&var_arg_node.base);
4704 }4796 }
47054797
4706 const rparen_tok = try appendToken(rp.c, .RParen, ")");4798 const rparen_tok = try appendToken(rp.c, .RParen, ")");
...@@ -4713,7 +4805,7 @@ fn finishTransFnProto(...@@ -4713,7 +4805,7 @@ fn finishTransFnProto(
4713 _ = try appendToken(rp.c, .LParen, "(");4805 _ = try appendToken(rp.c, .LParen, "(");
4714 const expr = try transCreateNodeStringLiteral(4806 const expr = try transCreateNodeStringLiteral(
4715 rp.c,4807 rp.c,
4716 try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),4808 try std.fmt.allocPrint(rp.c.arena, "\"{}\"", .{str_ptr[0..str_len]}),
4717 );4809 );
4718 _ = try appendToken(rp.c, .RParen, ")");4810 _ = try appendToken(rp.c, .RParen, ")");
47194811
...@@ -4767,13 +4859,13 @@ fn finishTransFnProto(...@@ -4767,13 +4859,13 @@ fn finishTransFnProto(
4767 }4859 }
4768 };4860 };
47694861
4770 const fn_proto = try rp.c.a().create(ast.Node.FnProto);4862 const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len);
4771 fn_proto.* = .{4863 fn_proto.* = .{
4772 .doc_comments = null,4864 .doc_comments = null,
4773 .visib_token = pub_tok,4865 .visib_token = pub_tok,
4774 .fn_token = fn_tok,4866 .fn_token = fn_tok,
4775 .name_token = name_tok,4867 .name_token = name_tok,
4776 .params = fn_params,4868 .params_len = fn_params.items.len,
4777 .return_type = .{ .Explicit = return_type_node },4869 .return_type = .{ .Explicit = return_type_node },
4778 .var_args_token = null, // TODO this field is broken in the AST data model4870 .var_args_token = null, // TODO this field is broken in the AST data model
4779 .extern_export_inline_token = extern_export_inline_tok,4871 .extern_export_inline_token = extern_export_inline_tok,
...@@ -4783,6 +4875,7 @@ fn finishTransFnProto(...@@ -4783,6 +4875,7 @@ fn finishTransFnProto(
4783 .section_expr = linksection_expr,4875 .section_expr = linksection_expr,
4784 .callconv_expr = callconv_expr,4876 .callconv_expr = callconv_expr,
4785 };4877 };
4878 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4786 return fn_proto;4879 return fn_proto;
4787}4880}
47884881
...@@ -4816,20 +4909,20 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp...@@ -4816,20 +4909,20 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
4816 const semi_tok = try appendToken(c, .Semicolon, ";");4909 const semi_tok = try appendToken(c, .Semicolon, ";");
4817 _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)});4910 _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)});
48184911
4819 const msg_node = try c.a().create(ast.Node.StringLiteral);4912 const msg_node = try c.arena.create(ast.Node.StringLiteral);
4820 msg_node.* = .{4913 msg_node.* = .{
4821 .token = msg_tok,4914 .token = msg_tok,
4822 };4915 };
48234916
4824 const call_node = try c.a().create(ast.Node.BuiltinCall);4917 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
4825 call_node.* = .{4918 call_node.* = .{
4826 .builtin_token = builtin_tok,4919 .builtin_token = builtin_tok,
4827 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),4920 .params_len = 1,
4828 .rparen_token = rparen_tok,4921 .rparen_token = rparen_tok,
4829 };4922 };
4830 try call_node.params.push(&msg_node.base);4923 call_node.params()[0] = &msg_node.base;
48314924
4832 const var_decl_node = try c.a().create(ast.Node.VarDecl);4925 const var_decl_node = try c.arena.create(ast.Node.VarDecl);
4833 var_decl_node.* = .{4926 var_decl_node.* = .{
4834 .doc_comments = null,4927 .doc_comments = null,
4835 .visib_token = pub_tok,4928 .visib_token = pub_tok,
...@@ -4856,23 +4949,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd...@@ -4856,23 +4949,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd
48564949
4857fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex {4950fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex {
4858 assert(token_id != .Invalid);4951 assert(token_id != .Invalid);
4859 const start_index = c.source_buffer.items.len;
4860 errdefer c.source_buffer.shrink(start_index);
48614952
4862 try c.source_buffer.outStream().print(format, args);4953 try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1);
4863 const end_index = c.source_buffer.items.len;4954 try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1);
4864 const token_index = c.tree.tokens.len;
4865 const new_token = try c.tree.tokens.addOne();
4866 errdefer c.tree.tokens.shrink(token_index);
48674955
4868 new_token.* = .{4956 const start_index = c.source_buffer.items.len;
4869 .id = token_id,4957 try c.source_buffer.outStream().print(format ++ " ", args);
4958
4959 c.token_ids.appendAssumeCapacity(token_id);
4960 c.token_locs.appendAssumeCapacity(.{
4870 .start = start_index,4961 .start = start_index,
4871 .end = end_index,4962 .end = c.source_buffer.items.len - 1, // back up before the space
4872 };4963 });
4873 try c.source_buffer.append(' ');
48744964
4875 return token_index;4965 return c.token_ids.items.len - 1;
4876}4966}
48774967
4878// TODO hook up with codegen4968// TODO hook up with codegen
...@@ -4931,7 +5021,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {...@@ -4931,7 +5021,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
49315021
4932fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {5022fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
4933 const token_index = try appendIdentifier(c, name);5023 const token_index = try appendIdentifier(c, name);
4934 const identifier = try c.a().create(ast.Node.Identifier);5024 const identifier = try c.arena.create(ast.Node.Identifier);
4935 identifier.* = .{5025 identifier.* = .{
4936 .token = token_index,5026 .token = token_index,
4937 };5027 };
...@@ -4940,7 +5030,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {...@@ -4940,7 +5030,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
49405030
4941fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {5031fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
4942 const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name});5032 const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name});
4943 const identifier = try c.a().create(ast.Node.Identifier);5033 const identifier = try c.arena.create(ast.Node.Identifier);
4944 identifier.* = .{5034 identifier.* = .{
4945 .token = token_index,5035 .token = token_index,
4946 };5036 };
...@@ -4955,7 +5045,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4955,7 +5045,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4955 // TODO if we see #undef, delete it from the table5045 // TODO if we see #undef, delete it from the table
4956 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);5046 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
4957 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);5047 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
4958 var tok_list = CTokenList.init(c.a());5048 var tok_list = CTokenList.init(c.arena);
4959 const scope = c.global_scope;5049 const scope = c.global_scope;
49605050
4961 while (it.I != it_end.I) : (it.I += 1) {5051 while (it.I != it_end.I) : (it.I += 1) {
...@@ -4970,7 +5060,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4970,7 +5060,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4970 const name = try c.str(raw_name);5060 const name = try c.str(raw_name);
4971 // TODO https://github.com/ziglang/zig/issues/37565061 // TODO https://github.com/ziglang/zig/issues/3756
4972 // TODO https://github.com/ziglang/zig/issues/18025062 // TODO https://github.com/ziglang/zig/issues/1802
4973 const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }) else name;5063 const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ name, c.getMangle() }) else name;
4974 if (scope.containsNow(mangled_name)) {5064 if (scope.containsNow(mangled_name)) {
4975 continue;5065 continue;
4976 }5066 }
...@@ -5060,7 +5150,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n...@@ -5060,7 +5150,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
5060}5150}
50615151
5062fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {5152fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
5063 const block_scope = try Scope.Block.init(c, &c.global_scope.base, null);5153 var block_scope = try Scope.Block.init(c, &c.global_scope.base, null);
5154 defer block_scope.deinit();
5064 const scope = &block_scope.base;5155 const scope = &block_scope.base;
50655156
5066 const pub_tok = try appendToken(c, .Keyword_pub, "pub");5157 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
...@@ -5078,7 +5169,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5078,7 +5169,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5078 .{},5169 .{},
5079 );5170 );
5080 }5171 }
5081 var fn_params = ast.Node.FnProto.ParamList.init(c.a());5172
5173 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
5174 defer fn_params.deinit();
5175
5082 while (true) {5176 while (true) {
5083 const param_tok = it.next().?;5177 const param_tok = it.next().?;
5084 if (param_tok.id != .Identifier) {5178 if (param_tok.id != .Identifier) {
...@@ -5096,20 +5190,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5096,20 +5190,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5096 _ = try appendToken(c, .Colon, ":");5190 _ = try appendToken(c, .Colon, ":");
50975191
5098 const token_index = try appendToken(c, .Keyword_var, "var");5192 const token_index = try appendToken(c, .Keyword_var, "var");
5099 const identifier = try c.a().create(ast.Node.Identifier);5193 const identifier = try c.arena.create(ast.Node.Identifier);
5100 identifier.* = .{5194 identifier.* = .{
5101 .token = token_index,5195 .token = token_index,
5102 };5196 };
51035197
5104 const param_node = try c.a().create(ast.Node.ParamDecl);5198 (try fn_params.addOne()).* = .{
5105 param_node.* = .{
5106 .doc_comments = null,5199 .doc_comments = null,
5107 .comptime_token = null,5200 .comptime_token = null,
5108 .noalias_token = null,5201 .noalias_token = null,
5109 .name_token = param_name_tok,5202 .name_token = param_name_tok,
5110 .param_type = .{ .type_expr = &identifier.base },5203 .param_type = .{ .type_expr = &identifier.base },
5111 };5204 };
5112 try fn_params.push(&param_node.base);
51135205
5114 if (it.peek().?.id != .Comma)5206 if (it.peek().?.id != .Comma)
5115 break;5207 break;
...@@ -5129,16 +5221,15 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5129,16 +5221,15 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
51295221
5130 _ = try appendToken(c, .RParen, ")");5222 _ = try appendToken(c, .RParen, ")");
51315223
5132 const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf");5224 const type_of = try c.createBuiltinCall("@TypeOf", 1);
5133 type_of.rparen_token = try appendToken(c, .RParen, ")");
51345225
5135 const fn_proto = try c.a().create(ast.Node.FnProto);5226 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
5136 fn_proto.* = .{5227 fn_proto.* = .{
5137 .visib_token = pub_tok,5228 .visib_token = pub_tok,
5138 .extern_export_inline_token = inline_tok,5229 .extern_export_inline_token = inline_tok,
5139 .fn_token = fn_tok,5230 .fn_token = fn_tok,
5140 .name_token = name_tok,5231 .name_token = name_tok,
5141 .params = fn_params,5232 .params_len = fn_params.items.len,
5142 .return_type = .{ .Explicit = &type_of.base },5233 .return_type = .{ .Explicit = &type_of.base },
5143 .doc_comments = null,5234 .doc_comments = null,
5144 .var_args_token = null,5235 .var_args_token = null,
...@@ -5148,8 +5239,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5148,8 +5239,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5148 .section_expr = null,5239 .section_expr = null,
5149 .callconv_expr = null,5240 .callconv_expr = null,
5150 };5241 };
51515242 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5152 const block = try transCreateNodeBlock(c, null);
51535243
5154 const return_expr = try transCreateNodeReturnExpr(c);5244 const return_expr = try transCreateNodeReturnExpr(c);
5155 const expr = try parseCExpr(c, it, source, source_loc, scope);5245 const expr = try parseCExpr(c, it, source, source_loc, scope);
...@@ -5165,17 +5255,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5165,17 +5255,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5165 _ = try appendToken(c, .Semicolon, ";");5255 _ = try appendToken(c, .Semicolon, ";");
5166 const type_of_arg = if (expr.id != .Block) expr else blk: {5256 const type_of_arg = if (expr.id != .Block) expr else blk: {
5167 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);5257 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
5168 const blk_last = blk.statements.at(blk.statements.len - 1).*;5258 const blk_last = blk.statements()[blk.statements_len - 1];
5169 std.debug.assert(blk_last.id == .ControlFlowExpression);5259 std.debug.assert(blk_last.id == .ControlFlowExpression);
5170 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);5260 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);
5171 break :blk br.rhs.?;5261 break :blk br.rhs.?;
5172 };5262 };
5173 try type_of.params.push(type_of_arg);5263 type_of.params()[0] = type_of_arg;
5264 type_of.rparen_token = try appendToken(c, .RParen, ")");
5174 return_expr.rhs = expr;5265 return_expr.rhs = expr;
51755266
5176 block.rbrace = try appendToken(c, .RBrace, "}");5267 try block_scope.statements.append(&return_expr.base);
5177 try block.statements.push(&return_expr.base);5268 const block_node = try block_scope.complete(c);
5178 fn_proto.body_node = &block.base;5269 fn_proto.body_node = &block_node.base;
5179 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);5270 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
5180}5271}
51815272
...@@ -5207,22 +5298,23 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_...@@ -5207,22 +5298,23 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
5207 },5298 },
5208 .Comma => {5299 .Comma => {
5209 _ = try appendToken(c, .Semicolon, ";");5300 _ = try appendToken(c, .Semicolon, ";");
5210 const block_scope = try Scope.Block.init(c, scope, "blk");5301 const label_name = "blk";
5211 block_scope.block_node = try transCreateNodeBlock(c, block_scope.label);5302 var block_scope = try Scope.Block.init(c, scope, label_name);
5303 defer block_scope.deinit();
52125304
5213 var last = node;5305 var last = node;
5214 while (true) {5306 while (true) {
5215 // suppress result5307 // suppress result
5216 const lhs = try transCreateNodeIdentifier(c, "_");5308 const lhs = try transCreateNodeIdentifier(c, "_");
5217 const op_token = try appendToken(c, .Equal, "=");5309 const op_token = try appendToken(c, .Equal, "=");
5218 const op_node = try c.a().create(ast.Node.InfixOp);5310 const op_node = try c.arena.create(ast.Node.InfixOp);
5219 op_node.* = .{5311 op_node.* = .{
5220 .op_token = op_token,5312 .op_token = op_token,
5221 .lhs = lhs,5313 .lhs = lhs,
5222 .op = .Assign,5314 .op = .Assign,
5223 .rhs = last,5315 .rhs = last,
5224 };5316 };
5225 try block_scope.block_node.statements.push(&op_node.base);5317 try block_scope.statements.append(&op_node.base);
52265318
5227 last = try parseCPrefixOpExpr(c, it, source, source_loc, scope);5319 last = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5228 _ = try appendToken(c, .Semicolon, ";");5320 _ = try appendToken(c, .Semicolon, ";");
...@@ -5232,11 +5324,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_...@@ -5232,11 +5324,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
5232 }5324 }
5233 }5325 }
52345326
5235 const break_node = try transCreateNodeBreak(c, block_scope.label);5327 const break_node = try transCreateNodeBreak(c, label_name);
5236 break_node.rhs = last;5328 break_node.rhs = last;
5237 try block_scope.block_node.statements.push(&break_node.base);5329 try block_scope.statements.append(&break_node.base);
5238 block_scope.block_node.rbrace = try appendToken(c, .RBrace, "}");5330 const block_node = try block_scope.complete(c);
5239 return &block_scope.block_node.base;5331 return &block_node.base;
5240 },5332 },
5241 else => {5333 else => {
5242 _ = it.prev();5334 _ = it.prev();
...@@ -5253,11 +5345,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl...@@ -5253,11 +5345,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
5253 switch (lit_bytes[1]) {5345 switch (lit_bytes[1]) {
5254 '0'...'7' => {5346 '0'...'7' => {
5255 // Octal5347 // Octal
5256 lit_bytes = try std.fmt.allocPrint(c.a(), "0o{}", .{lit_bytes});5348 lit_bytes = try std.fmt.allocPrint(c.arena, "0o{}", .{lit_bytes});
5257 },5349 },
5258 'X' => {5350 'X' => {
5259 // Hexadecimal with capital X, valid in C but not in Zig5351 // Hexadecimal with capital X, valid in C but not in Zig
5260 lit_bytes = try std.fmt.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]});5352 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{}", .{lit_bytes[2..]});
5261 },5353 },
5262 else => {},5354 else => {},
5263 }5355 }
...@@ -5267,15 +5359,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl...@@ -5267,15 +5359,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
5267 return transCreateNodeInt(c, lit_bytes);5359 return transCreateNodeInt(c, lit_bytes);
5268 }5360 }
52695361
5270 const cast_node = try transCreateNodeBuiltinFnCall(c, "@as");5362 const cast_node = try c.createBuiltinCall("@as", 2);
5271 try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) {5363 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) {
5272 .U => "c_uint",5364 .U => "c_uint",
5273 .L => "c_long",5365 .L => "c_long",
5274 .LU => "c_ulong",5366 .LU => "c_ulong",
5275 .LL => "c_longlong",5367 .LL => "c_longlong",
5276 .LLU => "c_ulonglong",5368 .LLU => "c_ulonglong",
5277 else => unreachable,5369 else => unreachable,
5278 }));5370 });
5279 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) {5371 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) {
5280 .U, .L => @as(u8, 1),5372 .U, .L => @as(u8, 1),
5281 .LU, .LL => 2,5373 .LU, .LL => 2,
...@@ -5283,23 +5375,23 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl...@@ -5283,23 +5375,23 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
5283 else => unreachable,5375 else => unreachable,
5284 }];5376 }];
5285 _ = try appendToken(c, .Comma, ",");5377 _ = try appendToken(c, .Comma, ",");
5286 try cast_node.params.push(try transCreateNodeInt(c, lit_bytes));5378 cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes);
5287 cast_node.rparen_token = try appendToken(c, .RParen, ")");5379 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5288 return &cast_node.base;5380 return &cast_node.base;
5289 } else if (tok.id == .FloatLiteral) {5381 } else if (tok.id == .FloatLiteral) {
5290 if (lit_bytes[0] == '.')5382 if (lit_bytes[0] == '.')
5291 lit_bytes = try std.fmt.allocPrint(c.a(), "0{}", .{lit_bytes});5383 lit_bytes = try std.fmt.allocPrint(c.arena, "0{}", .{lit_bytes});
5292 if (tok.id.FloatLiteral == .None) {5384 if (tok.id.FloatLiteral == .None) {
5293 return transCreateNodeFloat(c, lit_bytes);5385 return transCreateNodeFloat(c, lit_bytes);
5294 }5386 }
5295 const cast_node = try transCreateNodeBuiltinFnCall(c, "@as");5387 const cast_node = try c.createBuiltinCall("@as", 2);
5296 try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) {5388 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) {
5297 .F => "f32",5389 .F => "f32",
5298 .L => "c_longdouble",5390 .L => "c_longdouble",
5299 else => unreachable,5391 else => unreachable,
5300 }));5392 });
5301 _ = try appendToken(c, .Comma, ",");5393 _ = try appendToken(c, .Comma, ",");
5302 try cast_node.params.push(try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]));5394 cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]);
5303 cast_node.rparen_token = try appendToken(c, .RParen, ")");5395 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5304 return &cast_node.base;5396 return &cast_node.base;
5305 } else unreachable;5397 } else unreachable;
...@@ -5318,7 +5410,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const...@@ -5318,7 +5410,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
5318 break;5410 break;
5319 }5411 }
5320 } else return source;5412 } else return source;
5321 var bytes = try ctx.a().alloc(u8, source.len * 2);5413 var bytes = try ctx.arena.alloc(u8, source.len * 2);
5322 var state: enum {5414 var state: enum {
5323 Start,5415 Start,
5324 Escape,5416 Escape,
...@@ -5472,14 +5564,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5472,14 +5564,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5472 const first_tok = it.list.at(0);5564 const first_tok = it.list.at(0);
5473 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {5565 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {
5474 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));5566 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5475 const node = try c.a().create(ast.Node.CharLiteral);5567 const node = try c.arena.create(ast.Node.CharLiteral);
5476 node.* = .{5568 node.* = .{
5477 .token = token,5569 .token = token,
5478 };5570 };
5479 return &node.base;5571 return &node.base;
5480 } else {5572 } else {
5481 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start+1..tok.end-1]});5573 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start+1..tok.end-1]});
5482 const node = try c.a().create(ast.Node.IntegerLiteral);5574 const node = try c.arena.create(ast.Node.IntegerLiteral);
5483 node.* = .{5575 node.* = .{
5484 .token = token,5576 .token = token,
5485 };5577 };
...@@ -5489,7 +5581,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5489,7 +5581,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5489 .StringLiteral => {5581 .StringLiteral => {
5490 const first_tok = it.list.at(0);5582 const first_tok = it.list.at(0);
5491 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));5583 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5492 const node = try c.a().create(ast.Node.StringLiteral);5584 const node = try c.arena.create(ast.Node.StringLiteral);
5493 node.* = .{5585 node.* = .{
5494 .token = token,5586 .token = token,
5495 };5587 };
...@@ -5569,10 +5661,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5569,10 +5661,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5569 //else5661 //else
5570 // @as(dest, x) )5662 // @as(dest, x) )
5571 const if_node = try transCreateNodeIf(c);5663 const if_node = try transCreateNodeIf(c);
5572 const type_info_node = try transCreateNodeBuiltinFnCall(c, "@typeInfo");5664 const type_info_node = try c.createBuiltinCall("@typeInfo", 1);
5573 try type_info_node.params.push(inner_node);5665 type_info_node.params()[0] = inner_node;
5574 type_info_node.rparen_token = try appendToken(c, .LParen, ")");5666 type_info_node.rparen_token = try appendToken(c, .LParen, ")");
5575 const cmp_node = try c.a().create(ast.Node.InfixOp);5667 const cmp_node = try c.arena.create(ast.Node.InfixOp);
5576 cmp_node.* = .{5668 cmp_node.* = .{
5577 .op_token = try appendToken(c, .EqualEqual, "=="),5669 .op_token = try appendToken(c, .EqualEqual, "=="),
5578 .lhs = &type_info_node.base,5670 .lhs = &type_info_node.base,
...@@ -5582,22 +5674,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5582,22 +5674,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5582 if_node.condition = &cmp_node.base;5674 if_node.condition = &cmp_node.base;
5583 _ = try appendToken(c, .RParen, ")");5675 _ = try appendToken(c, .RParen, ")");
55845676
5585 const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr");5677 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5586 try int_to_ptr.params.push(inner_node);5678 int_to_ptr.params()[0] = inner_node;
5587 try int_to_ptr.params.push(node_to_cast);5679 int_to_ptr.params()[1] = node_to_cast;
5588 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");5680 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5589 if_node.body = &int_to_ptr.base;5681 if_node.body = &int_to_ptr.base;
55905682
5591 const else_node = try transCreateNodeElse(c);5683 const else_node = try transCreateNodeElse(c);
5592 if_node.@"else" = else_node;5684 if_node.@"else" = else_node;
55935685
5594 const as_node = try transCreateNodeBuiltinFnCall(c, "@as");5686 const as_node = try c.createBuiltinCall("@as", 2);
5595 try as_node.params.push(inner_node);5687 as_node.params()[0] = inner_node;
5596 try as_node.params.push(node_to_cast);5688 as_node.params()[1] = node_to_cast;
5597 as_node.rparen_token = try appendToken(c, .RParen, ")");5689 as_node.rparen_token = try appendToken(c, .RParen, ")");
5598 else_node.body = &as_node.base;5690 else_node.body = &as_node.base;
55995691
5600 const group_node = try c.a().create(ast.Node.GroupedExpression);5692 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5601 group_node.* = .{5693 group_node.* = .{
5602 .lparen = lparen,5694 .lparen = lparen,
5603 .expr = &if_node.base,5695 .expr = &if_node.base,
...@@ -5614,14 +5706,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5614,14 +5706,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5614 // @as(dest, x) )5706 // @as(dest, x) )
56155707
5616 const if_1 = try transCreateNodeIf(c);5708 const if_1 = try transCreateNodeIf(c);
5617 const type_info_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");5709 const type_info_1 = try c.createBuiltinCall("@typeInfo", 1);
5618 const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");5710 const type_of_1 = try c.createBuiltinCall("@TypeOf", 1);
5619 try type_info_1.params.push(&type_of_1.base);5711 type_info_1.params()[0] = &type_of_1.base;
5620 try type_of_1.params.push(node_to_cast);5712 type_of_1.params()[0] = node_to_cast;
5621 type_of_1.rparen_token = try appendToken(c, .RParen, ")");5713 type_of_1.rparen_token = try appendToken(c, .RParen, ")");
5622 type_info_1.rparen_token = try appendToken(c, .RParen, ")");5714 type_info_1.rparen_token = try appendToken(c, .RParen, ")");
56235715
5624 const cmp_1 = try c.a().create(ast.Node.InfixOp);5716 const cmp_1 = try c.arena.create(ast.Node.InfixOp);
5625 cmp_1.* = .{5717 cmp_1.* = .{
5626 .op_token = try appendToken(c, .EqualEqual, "=="),5718 .op_token = try appendToken(c, .EqualEqual, "=="),
5627 .lhs = &type_info_1.base,5719 .lhs = &type_info_1.base,
...@@ -5633,7 +5725,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5633,7 +5725,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56335725
5634 const period_tok = try appendToken(c, .Period, ".");5726 const period_tok = try appendToken(c, .Period, ".");
5635 const child_ident = try transCreateNodeIdentifier(c, "Child");5727 const child_ident = try transCreateNodeIdentifier(c, "Child");
5636 const inner_node_child = try c.a().create(ast.Node.InfixOp);5728 const inner_node_child = try c.arena.create(ast.Node.InfixOp);
5637 inner_node_child.* = .{5729 inner_node_child.* = .{
5638 .op_token = period_tok,5730 .op_token = period_tok,
5639 .lhs = inner_node,5731 .lhs = inner_node,
...@@ -5641,20 +5733,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5641,20 +5733,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5641 .rhs = child_ident,5733 .rhs = child_ident,
5642 };5734 };
56435735
5644 const align_of = try transCreateNodeBuiltinFnCall(c, "@alignOf");5736 const align_of = try c.createBuiltinCall("@alignOf", 1);
5645 try align_of.params.push(&inner_node_child.base);5737 align_of.params()[0] = &inner_node_child.base;
5646 align_of.rparen_token = try appendToken(c, .RParen, ")");5738 align_of.rparen_token = try appendToken(c, .RParen, ")");
5647 // hack to get zig fmt to render a comma in builtin calls5739 // hack to get zig fmt to render a comma in builtin calls
5648 _ = try appendToken(c, .Comma, ",");5740 _ = try appendToken(c, .Comma, ",");
56495741
5650 const align_cast = try transCreateNodeBuiltinFnCall(c, "@alignCast");5742 const align_cast = try c.createBuiltinCall("@alignCast", 2);
5651 try align_cast.params.push(&align_of.base);5743 align_cast.params()[0] = &align_of.base;
5652 try align_cast.params.push(node_to_cast);5744 align_cast.params()[1] = node_to_cast;
5653 align_cast.rparen_token = try appendToken(c, .RParen, ")");5745 align_cast.rparen_token = try appendToken(c, .RParen, ")");
56545746
5655 const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast");5747 const ptr_cast = try c.createBuiltinCall("@ptrCast", 2);
5656 try ptr_cast.params.push(inner_node);5748 ptr_cast.params()[0] = inner_node;
5657 try ptr_cast.params.push(&align_cast.base);5749 ptr_cast.params()[1] = &align_cast.base;
5658 ptr_cast.rparen_token = try appendToken(c, .RParen, ")");5750 ptr_cast.rparen_token = try appendToken(c, .RParen, ")");
5659 if_1.body = &ptr_cast.base;5751 if_1.body = &ptr_cast.base;
56605752
...@@ -5662,14 +5754,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5662,14 +5754,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5662 if_1.@"else" = else_1;5754 if_1.@"else" = else_1;
56635755
5664 const if_2 = try transCreateNodeIf(c);5756 const if_2 = try transCreateNodeIf(c);
5665 const type_info_2 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");5757 const type_info_2 = try c.createBuiltinCall("@typeInfo", 1);
5666 const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");5758 const type_of_2 = try c.createBuiltinCall("@TypeOf", 1);
5667 try type_info_2.params.push(&type_of_2.base);5759 type_info_2.params()[0] = &type_of_2.base;
5668 try type_of_2.params.push(node_to_cast);5760 type_of_2.params()[0] = node_to_cast;
5669 type_of_2.rparen_token = try appendToken(c, .RParen, ")");5761 type_of_2.rparen_token = try appendToken(c, .RParen, ")");
5670 type_info_2.rparen_token = try appendToken(c, .RParen, ")");5762 type_info_2.rparen_token = try appendToken(c, .RParen, ")");
56715763
5672 const cmp_2 = try c.a().create(ast.Node.InfixOp);5764 const cmp_2 = try c.arena.create(ast.Node.InfixOp);
5673 cmp_2.* = .{5765 cmp_2.* = .{
5674 .op_token = try appendToken(c, .EqualEqual, "=="),5766 .op_token = try appendToken(c, .EqualEqual, "=="),
5675 .lhs = &type_info_2.base,5767 .lhs = &type_info_2.base,
...@@ -5677,17 +5769,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5677,17 +5769,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5677 .rhs = try transCreateNodeEnumLiteral(c, "Int"),5769 .rhs = try transCreateNodeEnumLiteral(c, "Int"),
5678 };5770 };
5679 if_2.condition = &cmp_2.base;5771 if_2.condition = &cmp_2.base;
5680 const cmp_4 = try c.a().create(ast.Node.InfixOp);5772 const cmp_4 = try c.arena.create(ast.Node.InfixOp);
5681 cmp_4.* = .{5773 cmp_4.* = .{
5682 .op_token = try appendToken(c, .Keyword_and, "and"),5774 .op_token = try appendToken(c, .Keyword_and, "and"),
5683 .lhs = &cmp_2.base,5775 .lhs = &cmp_2.base,
5684 .op = .BoolAnd,5776 .op = .BoolAnd,
5685 .rhs = undefined,5777 .rhs = undefined,
5686 };5778 };
5687 const type_info_3 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");5779 const type_info_3 = try c.createBuiltinCall("@typeInfo", 1);
5688 try type_info_3.params.push(inner_node);5780 type_info_3.params()[0] = inner_node;
5689 type_info_3.rparen_token = try appendToken(c, .LParen, ")");5781 type_info_3.rparen_token = try appendToken(c, .LParen, ")");
5690 const cmp_3 = try c.a().create(ast.Node.InfixOp);5782 const cmp_3 = try c.arena.create(ast.Node.InfixOp);
5691 cmp_3.* = .{5783 cmp_3.* = .{
5692 .op_token = try appendToken(c, .EqualEqual, "=="),5784 .op_token = try appendToken(c, .EqualEqual, "=="),
5693 .lhs = &type_info_3.base,5785 .lhs = &type_info_3.base,
...@@ -5699,22 +5791,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5699,22 +5791,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5699 else_1.body = &if_2.base;5791 else_1.body = &if_2.base;
5700 _ = try appendToken(c, .RParen, ")");5792 _ = try appendToken(c, .RParen, ")");
57015793
5702 const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr");5794 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5703 try int_to_ptr.params.push(inner_node);5795 int_to_ptr.params()[0] = inner_node;
5704 try int_to_ptr.params.push(node_to_cast);5796 int_to_ptr.params()[1] = node_to_cast;
5705 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");5797 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5706 if_2.body = &int_to_ptr.base;5798 if_2.body = &int_to_ptr.base;
57075799
5708 const else_2 = try transCreateNodeElse(c);5800 const else_2 = try transCreateNodeElse(c);
5709 if_2.@"else" = else_2;5801 if_2.@"else" = else_2;
57105802
5711 const as = try transCreateNodeBuiltinFnCall(c, "@as");5803 const as = try c.createBuiltinCall("@as", 2);
5712 try as.params.push(inner_node);5804 as.params()[0] = inner_node;
5713 try as.params.push(node_to_cast);5805 as.params()[1] = node_to_cast;
5714 as.rparen_token = try appendToken(c, .RParen, ")");5806 as.rparen_token = try appendToken(c, .RParen, ")");
5715 else_2.body = &as.base;5807 else_2.body = &as.base;
57165808
5717 const group_node = try c.a().create(ast.Node.GroupedExpression);5809 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5718 group_node.* = .{5810 group_node.* = .{
5719 .lparen = lparen,5811 .lparen = lparen,
5720 .expr = &if_1.base,5812 .expr = &if_1.base,
...@@ -5740,7 +5832,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5740,7 +5832,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
5740 if (!isBoolRes(node)) {5832 if (!isBoolRes(node)) {
5741 if (node.id != .InfixOp) return node;5833 if (node.id != .InfixOp) return node;
57425834
5743 const group_node = try c.a().create(ast.Node.GroupedExpression);5835 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5744 group_node.* = .{5836 group_node.* = .{
5745 .lparen = try appendToken(c, .LParen, "("),5837 .lparen = try appendToken(c, .LParen, "("),
5746 .expr = node,5838 .expr = node,
...@@ -5749,8 +5841,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5749,8 +5841,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
5749 return &group_node.base;5841 return &group_node.base;
5750 }5842 }
57515843
5752 const builtin_node = try transCreateNodeBuiltinFnCall(c, "@boolToInt");5844 const builtin_node = try c.createBuiltinCall("@boolToInt", 1);
5753 try builtin_node.params.push(node);5845 builtin_node.params()[0] = node;
5754 builtin_node.rparen_token = try appendToken(c, .RParen, ")");5846 builtin_node.rparen_token = try appendToken(c, .RParen, ")");
5755 return &builtin_node.base;5847 return &builtin_node.base;
5756}5848}
...@@ -5759,7 +5851,7 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5759,7 +5851,7 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
5759 if (isBoolRes(node)) {5851 if (isBoolRes(node)) {
5760 if (node.id != .InfixOp) return node;5852 if (node.id != .InfixOp) return node;
57615853
5762 const group_node = try c.a().create(ast.Node.GroupedExpression);5854 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5763 group_node.* = .{5855 group_node.* = .{
5764 .lparen = try appendToken(c, .LParen, "("),5856 .lparen = try appendToken(c, .LParen, "("),
5765 .expr = node,5857 .expr = node,
...@@ -5770,14 +5862,14 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5770,14 +5862,14 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
57705862
5771 const op_token = try appendToken(c, .BangEqual, "!=");5863 const op_token = try appendToken(c, .BangEqual, "!=");
5772 const zero = try transCreateNodeInt(c, 0);5864 const zero = try transCreateNodeInt(c, 0);
5773 const res = try c.a().create(ast.Node.InfixOp);5865 const res = try c.arena.create(ast.Node.InfixOp);
5774 res.* = .{5866 res.* = .{
5775 .op_token = op_token,5867 .op_token = op_token,
5776 .lhs = node,5868 .lhs = node,
5777 .op = .BangEqual,5869 .op = .BangEqual,
5778 .rhs = zero,5870 .rhs = zero,
5779 };5871 };
5780 const group_node = try c.a().create(ast.Node.GroupedExpression);5872 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5781 group_node.* = .{5873 group_node.* = .{
5782 .lparen = try appendToken(c, .LParen, "("),5874 .lparen = try appendToken(c, .LParen, "("),
5783 .expr = &res.base,5875 .expr = &res.base,
...@@ -5928,10 +6020,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5928,10 +6020,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5928 continue;6020 continue;
5929 },6021 },
5930 .LParen => {6022 .LParen => {
5931 const call_node = try transCreateNodeFnCall(c, node);6023 _ = try appendToken(c, .LParen, "(");
6024 var call_params = std.ArrayList(*ast.Node).init(c.gpa);
6025 defer call_params.deinit();
5932 while (true) {6026 while (true) {
5933 const arg = try parseCPrefixOpExpr(c, it, source, source_loc, scope);6027 const arg = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5934 try call_node.op.Call.params.push(arg);6028 try call_params.append(arg);
5935 const next = it.next().?;6029 const next = it.next().?;
5936 if (next.id == .Comma)6030 if (next.id == .Comma)
5937 _ = try appendToken(c, .Comma, ",")6031 _ = try appendToken(c, .Comma, ",")
...@@ -5949,7 +6043,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5949,7 +6043,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5949 return error.ParseError;6043 return error.ParseError;
5950 }6044 }
5951 }6045 }
5952 call_node.rtoken = try appendToken(c, .RParen, ")");6046 const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len);
6047 call_node.* = .{
6048 .lhs = node,
6049 .params_len = call_params.items.len,
6050 .async_token = null,
6051 .rtoken = try appendToken(c, .RParen, ")"),
6052 };
6053 mem.copy(*ast.Node, call_node.params(), call_params.items);
5953 node = &call_node.base;6054 node = &call_node.base;
5954 continue;6055 continue;
5955 },6056 },
...@@ -5989,7 +6090,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5989,7 +6090,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5989 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;6090 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
5990 const lhs_node = try cast_fn(c, node);6091 const lhs_node = try cast_fn(c, node);
5991 const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);6092 const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5992 const op_node = try c.a().create(ast.Node.InfixOp);6093 const op_node = try c.arena.create(ast.Node.InfixOp);
5993 op_node.* = .{6094 op_node.* = .{
5994 .op_token = op_token,6095 .op_token = op_token,
5995 .lhs = lhs_node,6096 .lhs = lhs_node,
...@@ -6037,7 +6138,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -6037,7 +6138,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
6037}6138}
60386139
6039fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {6140fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
6040 const tok = c.tree.tokens.at(token);6141 const tok = c.token_locs.items[token];
6041 const slice = c.source_buffer.span()[tok.start..tok.end];6142 const slice = c.source_buffer.span()[tok.start..tok.end];
6042 return if (mem.startsWith(u8, slice, "@\""))6143 return if (mem.startsWith(u8, slice, "@\""))
6043 slice[2 .. slice.len - 1]6144 slice[2 .. slice.len - 1]
...@@ -6060,9 +6161,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6060,9 +6161,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6060 return null;6161 return null;
6061 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {6162 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6062 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6163 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6063 var it = container.fields_and_decls.iterator(0);6164 for (container.fieldsAndDecls()) |field_ref| {
6064 while (it.next()) |field_ref| {6165 const field = field_ref.cast(ast.Node.ContainerField).?;
6065 const field = field_ref.*.cast(ast.Node.ContainerField).?;
6066 const ident = infix.rhs.cast(ast.Node.Identifier).?;6166 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6067 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {6167 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6068 return getContainer(c, field.type_expr.?);6168 return getContainer(c, field.type_expr.?);
...@@ -6087,9 +6187,8 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6087,9 +6187,8 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6087 return null;6187 return null;
6088 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {6188 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6089 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6189 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6090 var it = container.fields_and_decls.iterator(0);6190 for (container.fieldsAndDecls()) |field_ref| {
6091 while (it.next()) |field_ref| {6191 const field = field_ref.cast(ast.Node.ContainerField).?;
6092 const field = field_ref.*.cast(ast.Node.ContainerField).?;
6093 const ident = infix.rhs.cast(ast.Node.Identifier).?;6192 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6094 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {6193 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6095 return getContainer(c, field.type_expr.?);6194 return getContainer(c, field.type_expr.?);
src/analyze.cpp+18-3
...@@ -3612,6 +3612,12 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {...@@ -3612,6 +3612,12 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
3612 auto entry = decls_scope->decl_table.put_unique(tld->name, tld);3612 auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
3613 if (entry) {3613 if (entry) {
3614 Tld *other_tld = entry->value;3614 Tld *other_tld = entry->value;
3615 if (other_tld->id == TldIdVar) {
3616 ZigVar *var = reinterpret_cast<TldVar *>(other_tld)->var;
3617 if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) {
3618 return; // already reported compile error
3619 }
3620 }
3615 ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name)));3621 ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name)));
3616 add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));3622 add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
3617 return;3623 return;
...@@ -3887,9 +3893,18 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf...@@ -3887,9 +3893,18 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
3887 if (search_scope != nullptr) {3893 if (search_scope != nullptr) {
3888 Tld *tld = find_decl(g, search_scope, name);3894 Tld *tld = find_decl(g, search_scope, name);
3889 if (tld != nullptr && tld != src_tld) {3895 if (tld != nullptr && tld != src_tld) {
3890 ErrorMsg *msg = add_node_error(g, source_node,3896 bool want_err_msg = true;
3891 buf_sprintf("redefinition of '%s'", buf_ptr(name)));3897 if (tld->id == TldIdVar) {
3892 add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));3898 ZigVar *var = reinterpret_cast<TldVar *>(tld)->var;
3899 if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) {
3900 want_err_msg = false;
3901 }
3902 }
3903 if (want_err_msg) {
3904 ErrorMsg *msg = add_node_error(g, source_node,
3905 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
3906 add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
3907 }
3893 variable_entry->var_type = g->builtin_types.entry_invalid;3908 variable_entry->var_type = g->builtin_types.entry_invalid;
3894 }3909 }
3895 }3910 }
src/ir.cpp+12-3
...@@ -5300,9 +5300,18 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s...@@ -5300,9 +5300,18 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
5300 } else {5300 } else {
5301 Tld *tld = find_decl(codegen, parent_scope, name);5301 Tld *tld = find_decl(codegen, parent_scope, name);
5302 if (tld != nullptr) {5302 if (tld != nullptr) {
5303 ErrorMsg *msg = add_node_error(codegen, node,5303 bool want_err_msg = true;
5304 buf_sprintf("redefinition of '%s'", buf_ptr(name)));5304 if (tld->id == TldIdVar) {
5305 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));5305 ZigVar *var = reinterpret_cast<TldVar *>(tld)->var;
5306 if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) {
5307 want_err_msg = false;
5308 }
5309 }
5310 if (want_err_msg) {
5311 ErrorMsg *msg = add_node_error(codegen, node,
5312 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
5313 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
5314 }
5306 variable_entry->var_type = codegen->builtin_types.entry_invalid;5315 variable_entry->var_type = codegen->builtin_types.entry_invalid;
5307 }5316 }
5308 }5317 }