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
signaturebadge-question-mark 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
776776 next_tok_is_fn = false;
777777
778778 const token = tokenizer.next();
779 try writeEscaped(out, src[index..token.start]);
779 try writeEscaped(out, src[index..token.loc.start]);
780780 switch (token.id) {
781781 .Eof => break,
782782
......@@ -827,13 +827,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
827827 .Keyword_while,
828828 => {
829829 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]);
831831 try out.writeAll("</span>");
832832 },
833833
834834 .Keyword_fn => {
835835 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]);
837837 try out.writeAll("</span>");
838838 next_tok_is_fn = true;
839839 },
......@@ -844,7 +844,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
844844 .Keyword_false,
845845 => {
846846 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]);
848848 try out.writeAll("</span>");
849849 },
850850
......@@ -853,13 +853,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
853853 .CharLiteral,
854854 => {
855855 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]);
857857 try out.writeAll("</span>");
858858 },
859859
860860 .Builtin => {
861861 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]);
863863 try out.writeAll("</span>");
864864 },
865865
......@@ -869,34 +869,34 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
869869 .ShebangLine,
870870 => {
871871 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]);
873873 try out.writeAll("</span>");
874874 },
875875
876876 .Identifier => {
877877 if (prev_tok_was_fn) {
878878 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]);
880880 try out.writeAll("</span>");
881881 } else {
882882 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')
884884 break :blk false;
885 var i = token.start + 1;
886 if (i == token.end)
885 var i = token.loc.start + 1;
886 if (i == token.loc.end)
887887 break :blk false;
888 while (i != token.end) : (i += 1) {
888 while (i != token.loc.end) : (i += 1) {
889889 if (src[i] < '0' or src[i] > '9')
890890 break :blk false;
891891 }
892892 break :blk true;
893893 };
894 if (is_int or isType(src[token.start..token.end])) {
894 if (is_int or isType(src[token.loc.start..token.loc.end])) {
895895 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]);
897897 try out.writeAll("</span>");
898898 } else {
899 try writeEscaped(out, src[token.start..token.end]);
899 try writeEscaped(out, src[token.loc.start..token.loc.end]);
900900 }
901901 }
902902 },
......@@ -905,7 +905,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
905905 .FloatLiteral,
906906 => {
907907 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]);
909909 try out.writeAll("</span>");
910910 },
911911
......@@ -963,7 +963,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
963963 .AngleBracketAngleBracketRight,
964964 .AngleBracketAngleBracketRightEqual,
965965 .Tilde,
966 => try writeEscaped(out, src[token.start..token.end]),
966 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
967967
968968 .Invalid, .Invalid_ampersands => return parseError(
969969 docgen_tokenizer,
......@@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
972972 .{},
973973 ),
974974 }
975 index = token.end;
975 index = token.loc.end;
976976 }
977977 try out.writeAll("</code>");
978978}
lib/std/heap/arena_allocator.zig+3-7
......@@ -46,13 +46,9 @@ pub const ArenaAllocator = struct {
4646 }
4747
4848 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
49 const actual_min_size = minimum_size + @sizeOf(BufNode);
50 var len = prev_len;
51 while (true) {
52 len += len / 2;
53 len += mem.page_size - @rem(len, mem.page_size);
54 if (len >= actual_min_size) break;
55 }
49 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
50 const big_enough_len = prev_len + actual_min_size;
51 const len = big_enough_len + big_enough_len / 2;
5652 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
5753 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);
5854 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 {
2121 next: ?*Node = null,
2222 data: T,
2323
24 pub const Data = T;
25
2426 pub fn init(data: T) Node {
2527 return Node{
2628 .data = data,
......@@ -47,28 +49,29 @@ pub fn SinglyLinkedList(comptime T: type) type {
4749 node.next = next_node.next;
4850 return next_node;
4951 }
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.
55 ///
56 /// Returns:
57 /// An empty linked list.
58 pub fn init() Self {
59 return Self{
60 .first = null,
61 };
62 }
62 /// Iterate over each next node, returning the count of all nodes except the starting one.
63 /// This operation is O(N).
64 pub fn countChildren(node: *const Node) usize {
65 var count: usize = 0;
66 var it: ?*const Node = node;
67 while (it) |n| : (it = n.next) {
68 count += 1;
69 }
70 return count;
71 }
72 };
6373
64 /// Insert a new node after an existing one.
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 }
74 first: ?*Node = null,
7275
7376 /// Insert a new node at the head.
7477 ///
......@@ -105,64 +108,33 @@ pub fn SinglyLinkedList(comptime T: type) type {
105108 return first;
106109 }
107110
108 /// Allocate a new node.
109 ///
110 /// Arguments:
111 /// allocator: Dynamic memory allocator.
112 ///
113 /// Returns:
114 /// A pointer to the new node.
115 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
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;
111 /// Iterate over all nodes, returning the count.
112 /// This operation is O(N).
113 pub fn len(list: Self) usize {
114 if (list.first) |n| {
115 return 1 + n.countChildren();
116 } else {
117 return 0;
118 }
140119 }
141120 };
142121}
143122
144123test "basic SinglyLinkedList test" {
145 const allocator = testing.allocator;
146 var list = SinglyLinkedList(u32).init();
124 const L = SinglyLinkedList(u32);
125 var list = L{};
147126
148 var one = try list.createNode(1, allocator);
149 var two = try list.createNode(2, allocator);
150 var three = try list.createNode(3, allocator);
151 var four = try list.createNode(4, allocator);
152 var five = try list.createNode(5, allocator);
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 }
127 var one = L.Node{.data = 1};
128 var two = L.Node{.data = 2};
129 var three = L.Node{.data = 3};
130 var four = L.Node{.data = 4};
131 var five = L.Node{.data = 5};
160132
161 list.prepend(two); // {2}
162 list.insertAfter(two, five); // {2, 5}
163 list.prepend(one); // {1, 2, 5}
164 list.insertAfter(two, three); // {1, 2, 3, 5}
165 list.insertAfter(three, four); // {1, 2, 3, 4, 5}
133 list.prepend(&two); // {2}
134 two.insertAfter(&five); // {2, 5}
135 list.prepend(&one); // {1, 2, 5}
136 two.insertAfter(&three); // {1, 2, 3, 5}
137 three.insertAfter(&four); // {1, 2, 3, 4, 5}
166138
167139 // Traverse forwards.
168140 {
......@@ -175,7 +147,7 @@ test "basic SinglyLinkedList test" {
175147 }
176148
177149 _ = list.popFirst(); // {2, 3, 4, 5}
178 _ = list.remove(five); // {2, 3, 4}
150 _ = list.remove(&five); // {2, 3, 4}
179151 _ = two.removeNext(); // {2, 4}
180152
181153 testing.expect(list.first.?.data == 2);
lib/std/rand.zig+1-1
......@@ -658,7 +658,7 @@ pub const Xoroshiro128 = struct {
658658 self.s[1] = s1;
659659 }
660660
661 fn seed(self: *Xoroshiro128, init_s: u64) void {
661 pub fn seed(self: *Xoroshiro128, init_s: u64) void {
662662 // Xoroshiro requires 128-bits of seed.
663663 var gen = SplitMix64.init(init_s);
664664
lib/std/testing.zig+4-3
......@@ -320,10 +320,11 @@ fn printWithVisibleNewlines(source: []const u8) void {
320320}
321321
322322fn printLine(line: []const u8) void {
323 switch (line[line.len - 1]) {
323 if (line.len != 0) switch (line[line.len - 1]) {
324324 ' ', '\t' => warn("{}⏎\n", .{line}), // Carriage return symbol,
325 else => warn("{}\n", .{line}),
326 }
325 else => {},
326 };
327 warn("{}\n", .{line});
327328}
328329
329330test "" {
lib/std/zig/ast.zig+783-313
......@@ -1,51 +1,50 @@
11const std = @import("../std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
4const SegmentedList = std.SegmentedList;
54const mem = std.mem;
65const Token = std.zig.Token;
76
87pub const TokenIndex = usize;
8pub const NodeIndex = usize;
99
1010pub const Tree = struct {
11 /// Reference to externally-owned data.
1112 source: []const u8,
12 tokens: TokenList,
13
14 /// undefined on parse error (errors not empty)
13 token_ids: []const Token.Id,
14 token_locs: []const Token.Loc,
15 errors: []const Error,
16 /// undefined on parse error (when errors field is not empty)
1517 root_node: *Node.Root,
16 arena_allocator: std.heap.ArenaAllocator,
17 errors: ErrorList,
18
19 arena: std.heap.ArenaAllocator.State,
20 gpa: *mem.Allocator,
1821
1922 /// translate-c uses this to avoid having to emit correct newlines
2023 /// TODO get rid of this hack
2124 generated: bool = false,
2225
23 pub const TokenList = SegmentedList(Token, 64);
24 pub const ErrorList = SegmentedList(Error, 0);
25
2626 pub fn deinit(self: *Tree) void {
27 // Here we copy the arena allocator into stack memory, because
28 // otherwise it would destroy itself while it was still working.
29 var arena_allocator = self.arena_allocator;
30 arena_allocator.deinit();
31 // self is destroyed
27 self.gpa.free(self.token_ids);
28 self.gpa.free(self.token_locs);
29 self.gpa.free(self.errors);
30 self.arena.promote(self.gpa).deinit();
3231 }
3332
34 pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {
35 return parse_error.render(&self.tokens, stream);
33 pub fn renderError(self: *Tree, parse_error: *const Error, stream: var) !void {
34 return parse_error.render(self.token_ids, stream);
3635 }
3736
3837 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]);
4039 }
4140
42 pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {
41 pub fn tokenSliceLoc(self: *Tree, token: Token.Loc) []const u8 {
4342 return self.source[token.start..token.end];
4443 }
4544
4645 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {
47 const first_token = self.tokens.at(node.firstToken());
48 const last_token = self.tokens.at(node.lastToken());
46 const first_token = self.token_locs[node.firstToken()];
47 const last_token = self.token_locs[node.lastToken()];
4948 return self.source[first_token.start..last_token.end];
5049 }
5150
......@@ -57,7 +56,7 @@ pub const Tree = struct {
5756 };
5857
5958 /// 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 {
6160 var loc = Location{
6261 .line = 0,
6362 .column = 0,
......@@ -85,14 +84,14 @@ pub const Tree = struct {
8584 }
8685
8786 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]);
8988 }
9089
9190 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]);
9392 }
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 {
9695 return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;
9796 }
9897
......@@ -103,7 +102,7 @@ pub const Tree = struct {
103102 /// Skips over comments
104103 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
105104 var index = token_index - 1;
106 while (self.tokens.at(index).id == Token.Id.LineComment) {
105 while (self.token_ids[index] == Token.Id.LineComment) {
107106 index -= 1;
108107 }
109108 return index;
......@@ -112,7 +111,7 @@ pub const Tree = struct {
112111 /// Skips over comments
113112 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
114113 var index = token_index + 1;
115 while (self.tokens.at(index).id == Token.Id.LineComment) {
114 while (self.token_ids[index] == Token.Id.LineComment) {
116115 index += 1;
117116 }
118117 return index;
......@@ -169,7 +168,7 @@ pub const Error = union(enum) {
169168 DeclBetweenFields: DeclBetweenFields,
170169 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 {
173172 switch (self.*) {
174173 .InvalidToken => |*x| return x.render(tokens, stream),
175174 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),
......@@ -324,8 +323,8 @@ pub const Error = union(enum) {
324323 pub const ExpectedCall = struct {
325324 node: *Node,
326325
327 pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void {
328 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{
326 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: var) !void {
327 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
329328 @tagName(self.node.id),
330329 });
331330 }
......@@ -334,8 +333,8 @@ pub const Error = union(enum) {
334333 pub const ExpectedCallOrFnProto = struct {
335334 node: *Node,
336335
337 pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void {
338 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
336 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: var) !void {
337 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
339338 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
340339 }
341340 };
......@@ -344,14 +343,14 @@ pub const Error = union(enum) {
344343 token: TokenIndex,
345344 expected_id: Token.Id,
346345
347 pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
348 const found_token = tokens.at(self.token);
349 switch (found_token.id) {
346 pub fn render(self: *const ExpectedToken, tokens: []const Token.Id, stream: var) !void {
347 const found_token = tokens[self.token];
348 switch (found_token) {
350349 .Invalid => {
351350 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
352351 },
353352 else => {
354 const token_name = found_token.id.symbol();
353 const token_name = found_token.symbol();
355354 return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
356355 },
357356 }
......@@ -362,11 +361,11 @@ pub const Error = union(enum) {
362361 token: TokenIndex,
363362 end_id: Token.Id,
364363
365 pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void {
366 const actual_token = tokens.at(self.token);
364 pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token.Id, stream: var) !void {
365 const actual_token = tokens[self.token];
367366 return stream.print("expected ',' or '{}', found '{}'", .{
368367 self.end_id.symbol(),
369 actual_token.id.symbol(),
368 actual_token.symbol(),
370369 });
371370 }
372371 };
......@@ -377,9 +376,9 @@ pub const Error = union(enum) {
377376
378377 token: TokenIndex,
379378
380 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
381 const actual_token = tokens.at(self.token);
382 return stream.print(msg, .{actual_token.id.symbol()});
379 pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void {
380 const actual_token = tokens[self.token];
381 return stream.print(msg, .{actual_token.symbol()});
383382 }
384383 };
385384 }
......@@ -390,7 +389,7 @@ pub const Error = union(enum) {
390389
391390 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 {
394393 return stream.writeAll(msg);
395394 }
396395 };
......@@ -413,7 +412,19 @@ pub const Node = struct {
413412 // Operators
414413 InfixOp,
415414 PrefixOp,
415 /// Not all suffix operations are under this tag. To save memory, some
416 /// suffix operations have dedicated Node tags.
416417 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
418429 // Control flow
419430 Switch,
......@@ -460,9 +471,6 @@ pub const Node = struct {
460471 PointerIndexPayload,
461472 ContainerField,
462473 ErrorTag,
463 AsmInput,
464 AsmOutput,
465 ParamDecl,
466474 FieldInitializer,
467475 };
468476
......@@ -518,7 +526,6 @@ pub const Node = struct {
518526 switch (n.id) {
519527 .Root,
520528 .ContainerField,
521 .ParamDecl,
522529 .Block,
523530 .Payload,
524531 .PointerPayload,
......@@ -602,26 +609,57 @@ pub const Node = struct {
602609 }
603610 }
604611
612 /// The decls data follows this struct in memory as an array of Node pointers.
605613 pub const Root = struct {
606614 base: Node = Node{ .id = .Root },
607 decls: DeclList,
608615 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 {
613 if (index < self.decls.len) {
614 return self.decls.at(index).*;
615 }
637 if (i < self.decls_len) return self.declsConst()[i];
616638 return null;
617639 }
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
619651 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();
621654 }
622655
623656 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);
625663 }
626664 };
627665
......@@ -642,7 +680,7 @@ pub const Node = struct {
642680 init_node: ?*Node,
643681 semicolon_token: TokenIndex,
644682
645 pub fn iterate(self: *VarDecl, index: usize) ?*Node {
683 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
646684 var i = index;
647685
648686 if (self.type_node) |type_node| {
......@@ -668,6 +706,7 @@ pub const Node = struct {
668706 return null;
669707 }
670708
709
671710 pub fn firstToken(self: *const VarDecl) TokenIndex {
672711 if (self.visib_token) |visib_token| return visib_token;
673712 if (self.thread_local_token) |thread_local_token| return thread_local_token;
......@@ -690,7 +729,7 @@ pub const Node = struct {
690729 expr: *Node,
691730 semicolon_token: TokenIndex,
692731
693 pub fn iterate(self: *Use, index: usize) ?*Node {
732 pub fn iterate(self: *const Use, index: usize) ?*Node {
694733 var i = index;
695734
696735 if (i < 1) return self.expr;
......@@ -712,16 +751,25 @@ pub const Node = struct {
712751 pub const ErrorSetDecl = struct {
713752 base: Node = Node{ .id = .ErrorSetDecl },
714753 error_token: TokenIndex,
715 decls: DeclList,
716754 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 {
721769 var i = index;
722770
723 if (i < self.decls.len) return self.decls.at(i).*;
724 i -= self.decls.len;
771 if (i < self.decls_len) return self.declsConst()[i];
772 i -= self.decls_len;
725773
726774 return null;
727775 }
......@@ -733,18 +781,31 @@ pub const Node = struct {
733781 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
734782 return self.rbrace_token;
735783 }
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 }
736798 };
737799
800 /// The fields and decls Node pointers directly follow this struct in memory.
738801 pub const ContainerDecl = struct {
739802 base: Node = Node{ .id = .ContainerDecl },
740 layout_token: ?TokenIndex,
741803 kind_token: TokenIndex,
742 init_arg_expr: InitArg,
743 fields_and_decls: DeclList,
804 layout_token: ?TokenIndex,
744805 lbrace_token: TokenIndex,
745806 rbrace_token: TokenIndex,
746
747 pub const DeclList = Root.DeclList;
807 fields_and_decls_len: NodeIndex,
808 init_arg_expr: InitArg,
748809
749810 pub const InitArg = union(enum) {
750811 None,
......@@ -752,7 +813,18 @@ pub const Node = struct {
752813 Type: *Node,
753814 };
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 {
756828 var i = index;
757829
758830 switch (self.init_arg_expr) {
......@@ -763,8 +835,8 @@ pub const Node = struct {
763835 .None, .Enum => {},
764836 }
765837
766 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
767 i -= self.fields_and_decls.len;
838 if (i < self.fields_and_decls_len) return self.fieldsAndDeclsConst()[i];
839 i -= self.fields_and_decls_len;
768840
769841 return null;
770842 }
......@@ -779,6 +851,20 @@ pub const Node = struct {
779851 pub fn lastToken(self: *const ContainerDecl) TokenIndex {
780852 return self.rbrace_token;
781853 }
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 }
782868 };
783869
784870 pub const ContainerField = struct {
......@@ -790,7 +876,7 @@ pub const Node = struct {
790876 value_expr: ?*Node,
791877 align_expr: ?*Node,
792878
793 pub fn iterate(self: *ContainerField, index: usize) ?*Node {
879 pub fn iterate(self: *const ContainerField, index: usize) ?*Node {
794880 var i = index;
795881
796882 if (self.type_expr) |type_expr| {
......@@ -837,7 +923,7 @@ pub const Node = struct {
837923 doc_comments: ?*DocComment,
838924 name_token: TokenIndex,
839925
840 pub fn iterate(self: *ErrorTag, index: usize) ?*Node {
926 pub fn iterate(self: *const ErrorTag, index: usize) ?*Node {
841927 var i = index;
842928
843929 if (self.doc_comments) |comments| {
......@@ -861,7 +947,7 @@ pub const Node = struct {
861947 base: Node = Node{ .id = .Identifier },
862948 token: TokenIndex,
863949
864 pub fn iterate(self: *Identifier, index: usize) ?*Node {
950 pub fn iterate(self: *const Identifier, index: usize) ?*Node {
865951 return null;
866952 }
867953
......@@ -874,13 +960,14 @@ pub const Node = struct {
874960 }
875961 };
876962
963 /// The params are directly after the FnProto in memory.
877964 pub const FnProto = struct {
878965 base: Node = Node{ .id = .FnProto },
879966 doc_comments: ?*DocComment,
880967 visib_token: ?TokenIndex,
881968 fn_token: TokenIndex,
882969 name_token: ?TokenIndex,
883 params: ParamList,
970 params_len: NodeIndex,
884971 return_type: ReturnType,
885972 var_args_token: ?TokenIndex,
886973 extern_export_inline_token: ?TokenIndex,
......@@ -892,15 +979,69 @@ pub const Node = struct {
892979 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
893980 is_async: bool = false, // TODO: remove once async fn rewriting is
894981
895 pub const ParamList = SegmentedList(*Node, 2);
896
897982 pub const ReturnType = union(enum) {
898983 Explicit: *Node,
899984 InferErrorSet: *Node,
900985 Invalid: TokenIndex,
901986 };
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 {
9041045 var i = index;
9051046
9061047 if (self.lib_name) |lib_name| {
......@@ -908,8 +1049,18 @@ pub const Node = struct {
9081049 i -= 1;
9091050 }
9101051
911 if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;
912 i -= self.params.len;
1052 const params_len = switch (self.paramsConst()[self.params_len - 1].param_type) {
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
9141065 if (self.align_expr) |align_expr| {
9151066 if (i < 1) return align_expr;
......@@ -951,6 +1102,20 @@ pub const Node = struct {
9511102 .Invalid => |tok| return tok,
9521103 }
9531104 }
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 }
9541119 };
9551120
9561121 pub const AnyFrameType = struct {
......@@ -963,7 +1128,7 @@ pub const Node = struct {
9631128 return_type: *Node,
9641129 };
9651130
966 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
1131 pub fn iterate(self: *const AnyFrameType, index: usize) ?*Node {
9671132 var i = index;
9681133
9691134 if (self.result) |result| {
......@@ -984,66 +1149,30 @@ pub const Node = struct {
9841149 }
9851150 };
9861151
987 pub const ParamDecl = struct {
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
1152 /// The statements of the block follow Block directly in memory.
10331153 pub const Block = struct {
10341154 base: Node = Node{ .id = .Block },
1035 label: ?TokenIndex,
1155 statements_len: NodeIndex,
10361156 lbrace: TokenIndex,
1037 statements: StatementList,
10381157 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 {
10431172 var i = index;
10441173
1045 if (i < self.statements.len) return self.statements.at(i).*;
1046 i -= self.statements.len;
1174 if (i < self.statements_len) return self.statementsConst()[i];
1175 i -= self.statements_len;
10471176
10481177 return null;
10491178 }
......@@ -1059,6 +1188,20 @@ pub const Node = struct {
10591188 pub fn lastToken(self: *const Block) TokenIndex {
10601189 return self.rbrace;
10611190 }
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 }
10621205 };
10631206
10641207 pub const Defer = struct {
......@@ -1067,7 +1210,7 @@ pub const Node = struct {
10671210 payload: ?*Node,
10681211 expr: *Node,
10691212
1070 pub fn iterate(self: *Defer, index: usize) ?*Node {
1213 pub fn iterate(self: *const Defer, index: usize) ?*Node {
10711214 var i = index;
10721215
10731216 if (i < 1) return self.expr;
......@@ -1091,7 +1234,7 @@ pub const Node = struct {
10911234 comptime_token: TokenIndex,
10921235 expr: *Node,
10931236
1094 pub fn iterate(self: *Comptime, index: usize) ?*Node {
1237 pub fn iterate(self: *const Comptime, index: usize) ?*Node {
10951238 var i = index;
10961239
10971240 if (i < 1) return self.expr;
......@@ -1114,7 +1257,7 @@ pub const Node = struct {
11141257 nosuspend_token: TokenIndex,
11151258 expr: *Node,
11161259
1117 pub fn iterate(self: *Nosuspend, index: usize) ?*Node {
1260 pub fn iterate(self: *const Nosuspend, index: usize) ?*Node {
11181261 var i = index;
11191262
11201263 if (i < 1) return self.expr;
......@@ -1138,7 +1281,7 @@ pub const Node = struct {
11381281 error_symbol: *Node,
11391282 rpipe: TokenIndex,
11401283
1141 pub fn iterate(self: *Payload, index: usize) ?*Node {
1284 pub fn iterate(self: *const Payload, index: usize) ?*Node {
11421285 var i = index;
11431286
11441287 if (i < 1) return self.error_symbol;
......@@ -1163,7 +1306,7 @@ pub const Node = struct {
11631306 value_symbol: *Node,
11641307 rpipe: TokenIndex,
11651308
1166 pub fn iterate(self: *PointerPayload, index: usize) ?*Node {
1309 pub fn iterate(self: *const PointerPayload, index: usize) ?*Node {
11671310 var i = index;
11681311
11691312 if (i < 1) return self.value_symbol;
......@@ -1189,7 +1332,7 @@ pub const Node = struct {
11891332 index_symbol: ?*Node,
11901333 rpipe: TokenIndex,
11911334
1192 pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node {
1335 pub fn iterate(self: *const PointerIndexPayload, index: usize) ?*Node {
11931336 var i = index;
11941337
11951338 if (i < 1) return self.value_symbol;
......@@ -1218,7 +1361,7 @@ pub const Node = struct {
12181361 payload: ?*Node,
12191362 body: *Node,
12201363
1221 pub fn iterate(self: *Else, index: usize) ?*Node {
1364 pub fn iterate(self: *const Else, index: usize) ?*Node {
12221365 var i = index;
12231366
12241367 if (self.payload) |payload| {
......@@ -1241,25 +1384,34 @@ pub const Node = struct {
12411384 }
12421385 };
12431386
1387 /// The cases node pointers are found in memory after Switch.
1388 /// They must be SwitchCase or SwitchElse nodes.
12441389 pub const Switch = struct {
12451390 base: Node = Node{ .id = .Switch },
12461391 switch_token: TokenIndex,
1392 rbrace: TokenIndex,
1393 cases_len: NodeIndex,
12471394 expr: *Node,
12481395
1249 /// these must be SwitchCase nodes
1250 cases: CaseList,
1251 rbrace: TokenIndex,
1396 /// After this the caller must initialize the fields_and_decls list.
1397 pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch {
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 {
12561408 var i = index;
12571409
12581410 if (i < 1) return self.expr;
12591411 i -= 1;
12601412
1261 if (i < self.cases.len) return self.cases.at(i).*;
1262 i -= self.cases.len;
1413 if (i < self.cases_len) return self.casesConst()[i];
1414 i -= self.cases_len;
12631415
12641416 return null;
12651417 }
......@@ -1271,22 +1423,46 @@ pub const Node = struct {
12711423 pub fn lastToken(self: *const Switch) TokenIndex {
12721424 return self.rbrace;
12731425 }
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 }
12741440 };
12751441
1442 /// Items sub-nodes appear in memory directly following SwitchCase.
12761443 pub const SwitchCase = struct {
12771444 base: Node = Node{ .id = .SwitchCase },
1278 items: ItemList,
12791445 arrow_token: TokenIndex,
12801446 payload: ?*Node,
12811447 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 {
12861462 var i = index;
12871463
1288 if (i < self.items.len) return self.items.at(i).*;
1289 i -= self.items.len;
1464 if (i < self.items_len) return self.itemsConst()[i];
1465 i -= self.items_len;
12901466
12911467 if (self.payload) |payload| {
12921468 if (i < 1) return payload;
......@@ -1300,19 +1476,33 @@ pub const Node = struct {
13001476 }
13011477
13021478 pub fn firstToken(self: *const SwitchCase) TokenIndex {
1303 return (self.items.at(0).*).firstToken();
1479 return self.itemsConst()[0].firstToken();
13041480 }
13051481
13061482 pub fn lastToken(self: *const SwitchCase) TokenIndex {
13071483 return self.expr.lastToken();
13081484 }
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 }
13091499 };
13101500
13111501 pub const SwitchElse = struct {
13121502 base: Node = Node{ .id = .SwitchElse },
13131503 token: TokenIndex,
13141504
1315 pub fn iterate(self: *SwitchElse, index: usize) ?*Node {
1505 pub fn iterate(self: *const SwitchElse, index: usize) ?*Node {
13161506 return null;
13171507 }
13181508
......@@ -1336,7 +1526,7 @@ pub const Node = struct {
13361526 body: *Node,
13371527 @"else": ?*Else,
13381528
1339 pub fn iterate(self: *While, index: usize) ?*Node {
1529 pub fn iterate(self: *const While, index: usize) ?*Node {
13401530 var i = index;
13411531
13421532 if (i < 1) return self.condition;
......@@ -1394,7 +1584,7 @@ pub const Node = struct {
13941584 body: *Node,
13951585 @"else": ?*Else,
13961586
1397 pub fn iterate(self: *For, index: usize) ?*Node {
1587 pub fn iterate(self: *const For, index: usize) ?*Node {
13981588 var i = index;
13991589
14001590 if (i < 1) return self.array_expr;
......@@ -1443,7 +1633,7 @@ pub const Node = struct {
14431633 body: *Node,
14441634 @"else": ?*Else,
14451635
1446 pub fn iterate(self: *If, index: usize) ?*Node {
1636 pub fn iterate(self: *const If, index: usize) ?*Node {
14471637 var i = index;
14481638
14491639 if (i < 1) return self.condition;
......@@ -1531,7 +1721,7 @@ pub const Node = struct {
15311721 UnwrapOptional,
15321722 };
15331723
1534 pub fn iterate(self: *InfixOp, index: usize) ?*Node {
1724 pub fn iterate(self: *const InfixOp, index: usize) ?*Node {
15351725 var i = index;
15361726
15371727 if (i < 1) return self.lhs;
......@@ -1649,7 +1839,7 @@ pub const Node = struct {
16491839 };
16501840 };
16511841
1652 pub fn iterate(self: *PrefixOp, index: usize) ?*Node {
1842 pub fn iterate(self: *const PrefixOp, index: usize) ?*Node {
16531843 var i = index;
16541844
16551845 switch (self.op) {
......@@ -1707,7 +1897,7 @@ pub const Node = struct {
17071897 name_token: TokenIndex,
17081898 expr: *Node,
17091899
1710 pub fn iterate(self: *FieldInitializer, index: usize) ?*Node {
1900 pub fn iterate(self: *const FieldInitializer, index: usize) ?*Node {
17111901 var i = index;
17121902
17131903 if (i < 1) return self.expr;
......@@ -1725,35 +1915,279 @@ pub const Node = struct {
17251915 }
17261916 };
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
17282179 pub const SuffixOp = struct {
17292180 base: Node = Node{ .id = .SuffixOp },
1730 lhs: Lhs,
17312181 op: Op,
2182 lhs: *Node,
17322183 rtoken: TokenIndex,
17332184
1734 pub const Lhs = union(enum) {
1735 node: *Node,
1736 dot: TokenIndex,
1737 };
1738
17392185 pub const Op = union(enum) {
1740 Call: Call,
17412186 ArrayAccess: *Node,
17422187 Slice: Slice,
1743 ArrayInitializer: InitList,
1744 StructInitializer: InitList,
17452188 Deref,
17462189 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
17572191 pub const Slice = struct {
17582192 start: *Node,
17592193 end: ?*Node,
......@@ -1761,22 +2195,13 @@ pub const Node = struct {
17612195 };
17622196 };
17632197
1764 pub fn iterate(self: *SuffixOp, index: usize) ?*Node {
2198 pub fn iterate(self: *const SuffixOp, index: usize) ?*Node {
17652199 var i = index;
17662200
1767 switch (self.lhs) {
1768 .node => |node| {
1769 if (i == 0) return node;
1770 i -= 1;
1771 },
1772 .dot => {},
1773 }
2201 if (i == 0) return self.lhs;
2202 i -= 1;
17742203
17752204 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 },
17802205 .ArrayAccess => |index_expr| {
17812206 if (i < 1) return index_expr;
17822207 i -= 1;
......@@ -1794,14 +2219,6 @@ pub const Node = struct {
17942219 i -= 1;
17952220 }
17962221 },
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 },
18052222 .UnwrapOptional,
18062223 .Deref,
18072224 => {},
......@@ -1811,14 +2228,7 @@ pub const Node = struct {
18112228 }
18122229
18132230 pub fn firstToken(self: *const SuffixOp) TokenIndex {
1814 switch (self.op) {
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 }
2231 return self.lhs.firstToken();
18222232 }
18232233
18242234 pub fn lastToken(self: *const SuffixOp) TokenIndex {
......@@ -1832,7 +2242,7 @@ pub const Node = struct {
18322242 expr: *Node,
18332243 rparen: TokenIndex,
18342244
1835 pub fn iterate(self: *GroupedExpression, index: usize) ?*Node {
2245 pub fn iterate(self: *const GroupedExpression, index: usize) ?*Node {
18362246 var i = index;
18372247
18382248 if (i < 1) return self.expr;
......@@ -1862,7 +2272,7 @@ pub const Node = struct {
18622272 Return,
18632273 };
18642274
1865 pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node {
2275 pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node {
18662276 var i = index;
18672277
18682278 switch (self.kind) {
......@@ -1910,7 +2320,7 @@ pub const Node = struct {
19102320 suspend_token: TokenIndex,
19112321 body: ?*Node,
19122322
1913 pub fn iterate(self: *Suspend, index: usize) ?*Node {
2323 pub fn iterate(self: *const Suspend, index: usize) ?*Node {
19142324 var i = index;
19152325
19162326 if (self.body) |body| {
......@@ -1938,7 +2348,7 @@ pub const Node = struct {
19382348 base: Node = Node{ .id = .IntegerLiteral },
19392349 token: TokenIndex,
19402350
1941 pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {
2351 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
19422352 return null;
19432353 }
19442354
......@@ -1956,7 +2366,7 @@ pub const Node = struct {
19562366 dot: TokenIndex,
19572367 name: TokenIndex,
19582368
1959 pub fn iterate(self: *EnumLiteral, index: usize) ?*Node {
2369 pub fn iterate(self: *const EnumLiteral, index: usize) ?*Node {
19602370 return null;
19612371 }
19622372
......@@ -1973,7 +2383,7 @@ pub const Node = struct {
19732383 base: Node = Node{ .id = .FloatLiteral },
19742384 token: TokenIndex,
19752385
1976 pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {
2386 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
19772387 return null;
19782388 }
19792389
......@@ -1986,19 +2396,29 @@ pub const Node = struct {
19862396 }
19872397 };
19882398
2399 /// Parameters are in memory following BuiltinCall.
19892400 pub const BuiltinCall = struct {
19902401 base: Node = Node{ .id = .BuiltinCall },
2402 params_len: NodeIndex,
19912403 builtin_token: TokenIndex,
1992 params: ParamList,
19932404 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 {
19982418 var i = index;
19992419
2000 if (i < self.params.len) return self.params.at(i).*;
2001 i -= self.params.len;
2420 if (i < self.params_len) return self.paramsConst()[i];
2421 i -= self.params_len;
20022422
20032423 return null;
20042424 }
......@@ -2010,13 +2430,27 @@ pub const Node = struct {
20102430 pub fn lastToken(self: *const BuiltinCall) TokenIndex {
20112431 return self.rparen_token;
20122432 }
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 }
20132447 };
20142448
20152449 pub const StringLiteral = struct {
20162450 base: Node = Node{ .id = .StringLiteral },
20172451 token: TokenIndex,
20182452
2019 pub fn iterate(self: *StringLiteral, index: usize) ?*Node {
2453 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
20202454 return null;
20212455 }
20222456
......@@ -2029,22 +2463,46 @@ pub const Node = struct {
20292463 }
20302464 };
20312465
2466 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
20322467 pub const MultilineStringLiteral = struct {
20332468 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 {
20392483 return null;
20402484 }
20412485
20422486 pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {
2043 return self.lines.at(0).*;
2487 return self.linesConst()[0];
20442488 }
20452489
20462490 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);
20482506 }
20492507 };
20502508
......@@ -2052,7 +2510,7 @@ pub const Node = struct {
20522510 base: Node = Node{ .id = .CharLiteral },
20532511 token: TokenIndex,
20542512
2055 pub fn iterate(self: *CharLiteral, index: usize) ?*Node {
2513 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
20562514 return null;
20572515 }
20582516
......@@ -2069,7 +2527,7 @@ pub const Node = struct {
20692527 base: Node = Node{ .id = .BoolLiteral },
20702528 token: TokenIndex,
20712529
2072 pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {
2530 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
20732531 return null;
20742532 }
20752533
......@@ -2086,7 +2544,7 @@ pub const Node = struct {
20862544 base: Node = Node{ .id = .NullLiteral },
20872545 token: TokenIndex,
20882546
2089 pub fn iterate(self: *NullLiteral, index: usize) ?*Node {
2547 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
20902548 return null;
20912549 }
20922550
......@@ -2103,7 +2561,7 @@ pub const Node = struct {
21032561 base: Node = Node{ .id = .UndefinedLiteral },
21042562 token: TokenIndex,
21052563
2106 pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {
2564 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
21072565 return null;
21082566 }
21092567
......@@ -2116,105 +2574,114 @@ pub const Node = struct {
21162574 }
21172575 };
21182576
2119 pub const AsmOutput = struct {
2120 base: Node = Node{ .id = .AsmOutput },
2121 lbracket: TokenIndex,
2122 symbolic_name: *Node,
2123 constraint: *Node,
2124 kind: Kind,
2577 pub const Asm = struct {
2578 base: Node = Node{ .id = .Asm },
2579 asm_token: TokenIndex,
21252580 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) {
2128 Variable: *Identifier,
2129 Return: *Node,
2130 };
2600 pub fn iterate(self: *const Output, index: usize) ?*Node {
2601 var i = index;
21312602
2132 pub fn iterate(self: *AsmOutput, index: usize) ?*Node {
2133 var i = index;
2603 if (i < 1) return self.symbolic_name;
2604 i -= 1;
21342605
2135 if (i < 1) return self.symbolic_name;
2136 i -= 1;
2606 if (i < 1) return self.constraint;
2607 i -= 1;
21372608
2138 if (i < 1) return self.constraint;
2139 i -= 1;
2609 switch (self.kind) {
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) {
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 },
2620 return null;
21502621 }
21512622
2152 return null;
2153 }
2154
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 };
2623 pub fn firstToken(self: *const Output) TokenIndex {
2624 return self.lbracket;
2625 }
21632626
2164 pub const AsmInput = struct {
2165 base: Node = Node{ .id = .AsmInput },
2166 lbracket: TokenIndex,
2167 symbolic_name: *Node,
2168 constraint: *Node,
2169 expr: *Node,
2170 rparen: TokenIndex,
2627 pub fn lastToken(self: *const Output) TokenIndex {
2628 return self.rparen;
2629 }
2630 };
21712631
2172 pub fn iterate(self: *AsmInput, index: usize) ?*Node {
2173 var i = index;
2632 pub const Input = struct {
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;
2176 i -= 1;
2639 pub fn iterate(self: *const Input, index: usize) ?*Node {
2640 var i = index;
21772641
2178 if (i < 1) return self.constraint;
2179 i -= 1;
2642 if (i < 1) return self.symbolic_name;
2643 i -= 1;
21802644
2181 if (i < 1) return self.expr;
2182 i -= 1;
2645 if (i < 1) return self.constraint;
2646 i -= 1;
21832647
2184 return null;
2185 }
2648 if (i < 1) return self.expr;
2649 i -= 1;
21862650
2187 pub fn firstToken(self: *const AsmInput) TokenIndex {
2188 return self.lbracket;
2189 }
2651 return null;
2652 }
21902653
2191 pub fn lastToken(self: *const AsmInput) TokenIndex {
2192 return self.rparen;
2193 }
2194 };
2654 pub fn firstToken(self: *const Input) TokenIndex {
2655 return self.lbracket;
2656 }
21952657
2196 pub const Asm = struct {
2197 base: Node = Node{ .id = .Asm },
2198 asm_token: TokenIndex,
2199 volatile_token: ?TokenIndex,
2200 template: *Node,
2201 outputs: OutputList,
2202 inputs: InputList,
2203 clobbers: ClobberList,
2204 rparen: TokenIndex,
2658 pub fn lastToken(self: *const Input) TokenIndex {
2659 return self.rparen;
2660 }
2661 };
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 {
22112665 var i = index;
22122666
2213 if (i < self.outputs.len) return &self.outputs.at(i).*.base;
2214 i -= self.outputs.len;
2667 if (i < self.outputs.len * 3) switch (i % 3) {
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;
2217 i -= self.inputs.len;
2678 if (i < self.inputs.len * 3) switch (i % 3) {
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
22192686 return null;
22202687 }
......@@ -2232,7 +2699,7 @@ pub const Node = struct {
22322699 base: Node = Node{ .id = .Unreachable },
22332700 token: TokenIndex,
22342701
2235 pub fn iterate(self: *Unreachable, index: usize) ?*Node {
2702 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
22362703 return null;
22372704 }
22382705
......@@ -2249,7 +2716,7 @@ pub const Node = struct {
22492716 base: Node = Node{ .id = .ErrorType },
22502717 token: TokenIndex,
22512718
2252 pub fn iterate(self: *ErrorType, index: usize) ?*Node {
2719 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
22532720 return null;
22542721 }
22552722
......@@ -2266,7 +2733,7 @@ pub const Node = struct {
22662733 base: Node = Node{ .id = .VarType },
22672734 token: TokenIndex,
22682735
2269 pub fn iterate(self: *VarType, index: usize) ?*Node {
2736 pub fn iterate(self: *const VarType, index: usize) ?*Node {
22702737 return null;
22712738 }
22722739
......@@ -2281,20 +2748,23 @@ pub const Node = struct {
22812748
22822749 pub const DocComment = struct {
22832750 base: Node = Node{ .id = .DocComment },
2284 lines: LineList,
2285
2286 pub const LineList = SegmentedList(TokenIndex, 4);
2751 /// Points to the first doc comment token. API users are expected to iterate over the
2752 /// tokens array, looking for more doc comments, ignoring line comments, and stopping
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 {
22892757 return null;
22902758 }
22912759
22922760 pub fn firstToken(self: *const DocComment) TokenIndex {
2293 return self.lines.at(0).*;
2761 return self.first_line;
22942762 }
22952763
2764 /// Returns the first doc comment line. Be careful, this may not be the desired behavior,
2765 /// which would require the tokens array.
22962766 pub fn lastToken(self: *const DocComment) TokenIndex {
2297 return self.lines.at(self.lines.len - 1).*;
2767 return self.first_line;
22982768 }
22992769 };
23002770
......@@ -2305,7 +2775,7 @@ pub const Node = struct {
23052775 name: *Node,
23062776 body_node: *Node,
23072777
2308 pub fn iterate(self: *TestDecl, index: usize) ?*Node {
2778 pub fn iterate(self: *const TestDecl, index: usize) ?*Node {
23092779 var i = index;
23102780
23112781 if (i < 1) return self.body_node;
......@@ -2327,7 +2797,7 @@ pub const Node = struct {
23272797test "iterate" {
23282798 var root = Node.Root{
23292799 .base = Node{ .id = Node.Id.Root },
2330 .decls = Node.Root.DeclList.init(std.testing.allocator),
2800 .decls_len = 0,
23312801 .eof_token = 0,
23322802 };
23332803 var base = &root.base;
lib/std/zig/parse.zig+2886-2803
......@@ -6,3304 +6,3387 @@ const Node = ast.Node;
66const Tree = ast.Tree;
77const AstError = ast.Error;
88const TokenIndex = ast.TokenIndex;
9const NodeIndex = ast.NodeIndex;
910const Token = std.zig.Token;
10const TokenIterator = Tree.TokenList.Iterator;
1111
1212pub const Error = error{ParseError} || Allocator.Error;
1313
1414/// Result should be freed with tree.deinit() when there are
1515/// no more references to any of the tokens or nodes.
16pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
17 const tree = blk: {
18 // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists
19 // from being initialized with a pointer to this `arena`, which is created on
20 // the stack. Following code should instead refer to `&tree.arena_allocator`, a
21 // pointer to data which lives safely on the heap and will outlive `parse`. See:
22 // https://github.com/ziglang/zig/commit/cb4fb14b6e66bd213575f69eec9598be8394fae6
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);
16pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
17 // TODO optimization idea: ensureCapacity on the tokens list and
18 // then appendAssumeCapacity inside the loop.
19 var token_ids = std.ArrayList(Token.Id).init(gpa);
20 defer token_ids.deinit();
21 var token_locs = std.ArrayList(Token.Loc).init(gpa);
22 defer token_locs.deinit();
4023
4124 var tokenizer = std.zig.Tokenizer.init(source);
4225 while (true) {
43 const tree_token = try tree.tokens.addOne();
44 tree_token.* = tokenizer.next();
45 if (tree_token.id == .Eof) break;
46 }
47 var it = tree.tokens.iterator(0);
48
49 while (it.peek().?.id == .LineComment) _ = it.next();
50
51 tree.root_node = try parseRoot(arena, &it, tree);
52
26 const token = tokenizer.next();
27 try token_ids.append(token.id);
28 try token_locs.append(token.loc);
29 if (token.id == .Eof) break;
30 }
31
32 var parser: Parser = .{
33 .source = source,
34 .arena = std.heap.ArenaAllocator.init(gpa),
35 .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 };
5358 return tree;
5459}
5560
56/// Root <- skip ContainerMembers eof
57fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
58 const node = try arena.create(Node.Root);
59 node.* = .{
60 .decls = try parseContainerMembers(arena, it, tree, true),
61/// Represents in-progress parsing, will be converted to an ast.Tree after completion.
62const Parser = struct {
63 arena: std.heap.ArenaAllocator,
64 gpa: *Allocator,
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
6176 // parseContainerMembers will try to skip as much
6277 // invalid tokens as it can so this can only be the EOF
63 .eof_token = eatToken(it, .Eof).?,
64 };
65 return node;
66}
78 const eof_token = p.eatToken(.Eof).?;
6779
68/// ContainerMembers
69/// <- TestDecl ContainerMembers
70/// / TopLevelComptime ContainerMembers
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;
80 const decls_len = @intCast(NodeIndex, decls.len);
81 const node = try Node.Root.create(&p.arena.allocator, decls_len, eof_token);
82 std.mem.copy(*Node, node.decls(), decls);
8983
90 while (true) {
91 if (try parseContainerDocComments(arena, it, tree)) |node| {
92 try list.push(node);
93 continue;
94 }
84 return node;
85 }
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) {
99 error.OutOfMemory => return error.OutOfMemory,
100 error.ParseError => {
101 findNextContainerMember(it);
110 while (true) {
111 if (try p.parseContainerDocComments()) |node| {
112 try list.append(node);
102113 continue;
103 },
104 }) |node| {
105 if (field_state == .seen) {
106 field_state = .{ .end = node.firstToken() };
107114 }
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) {
114 error.OutOfMemory => return error.OutOfMemory,
115 error.ParseError => {
116 findNextContainerMember(it);
116 const doc_comments = try p.parseDocComment();
117
118 if (p.parseTestDecl() catch |err| switch (err) {
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);
117130 continue;
118 },
119 }) |node| {
120 if (field_state == .seen) {
121 field_state = .{ .end = node.firstToken() };
122131 }
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);
129
130 if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {
131 error.OutOfMemory => return error.OutOfMemory,
132 error.ParseError => {
133 findNextContainerMember(it);
133 if (p.parseTopLevelComptime() catch |err| switch (err) {
134 error.OutOfMemory => return error.OutOfMemory,
135 error.ParseError => {
136 p.findNextContainerMember();
137 continue;
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);
134145 continue;
135 },
136 }) |node| {
137 if (field_state == .seen) {
138 field_state = .{ .end = visib_token orelse node.firstToken() };
139146 }
140 switch (node.id) {
141 .FnProto => {
142 node.cast(Node.FnProto).?.doc_comments = doc_comments;
143 node.cast(Node.FnProto).?.visib_token = visib_token;
144 },
145 .VarDecl => {
146 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
147 node.cast(Node.VarDecl).?.visib_token = visib_token;
148 },
149 .Use => {
150 node.cast(Node.Use).?.doc_comments = doc_comments;
151 node.cast(Node.Use).?.visib_token = visib_token;
147
148 const visib_token = p.eatToken(.Keyword_pub);
149
150 if (p.parseTopLevelDecl() catch |err| switch (err) {
151 error.OutOfMemory => return error.OutOfMemory,
152 error.ParseError => {
153 p.findNextContainerMember();
154 continue;
152155 },
153 else => unreachable,
154 }
155 try list.push(node);
156 if (try parseAppendedDocComment(arena, it, tree, node.lastToken())) |appended_comment| {
156 }) |node| {
157 if (field_state == .seen) {
158 field_state = .{ .end = visib_token orelse node.firstToken() };
159 }
157160 switch (node.id) {
158 .FnProto => {},
159 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
160 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
161 .FnProto => {
162 node.cast(Node.FnProto).?.doc_comments = doc_comments;
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 },
161173 else => unreachable,
162174 }
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;
163185 }
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) {
176 error.OutOfMemory => return error.OutOfMemory,
177 error.ParseError => {
178 // attempt to recover
179 findNextContainerMember(it);
187 if (visib_token != null) {
188 try p.errors.append(p.gpa, .{
189 .ExpectedPubItem = .{ .token = p.tok_i },
190 });
191 // ignore this pub
180192 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 },
193193 }
194194
195 const field = node.cast(Node.ContainerField).?;
196 field.doc_comments = doc_comments;
197 try list.push(node);
198 const comma = eatToken(it, .Comma) orelse {
199 // try to continue parsing
200 const index = it.index;
201 findNextContainerMember(it);
202 const next = it.peek().?.id;
203 switch (next) {
204 .Eof => break,
205 else => {
206 if (next == .RBrace) {
207 if (!top_level) break;
208 _ = nextToken(it);
209 }
210
211 // add error and continue
212 try tree.errors.push(.{
213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
195 if (p.parseContainerField() catch |err| switch (err) {
196 error.OutOfMemory => return error.OutOfMemory,
197 error.ParseError => {
198 // attempt to recover
199 p.findNextContainerMember();
200 continue;
201 },
202 }) |node| {
203 switch (field_state) {
204 .none => field_state = .seen,
205 .err, .seen => {},
206 .end => |tok| {
207 try p.errors.append(p.gpa, .{
208 .DeclBetweenFields = .{ .token = tok },
214209 });
215 continue;
210 // continue parsing, error will be reported later
211 field_state = .err;
216212 },
217213 }
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;
232 switch (next) {
233 .Eof => break,
234 .Keyword_comptime => {
235 _ = nextToken(it);
236 try tree.errors.push(.{
237 .ExpectedBlockOrField = .{ .token = it.index },
238 });
239 },
240 else => {
241 const index = it.index;
242 if (next == .RBrace) {
243 if (!top_level) break;
244 _ = nextToken(it);
245 }
215 const field = node.cast(Node.ContainerField).?;
216 field.doc_comments = doc_comments;
217 try list.append(node);
218 const comma = p.eatToken(.Comma) orelse {
219 // try to continue parsing
220 const index = p.tok_i;
221 p.findNextContainerMember();
222 const next = p.token_ids[p.tok_i];
223 switch (next) {
224 .Eof => break,
225 else => {
226 if (next == .RBrace) {
227 if (!top_level) break;
228 _ = p.nextToken();
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,
248 // try to find the next declaration
249 findNextContainerMember(it);
250 try tree.errors.push(.{
251 .ExpectedContainerMembers = .{ .token = index },
244 // Dangling doc comment
245 if (doc_comments != null) {
246 try p.errors.append(p.gpa, .{
247 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
252248 });
253 },
254 }
255 }
249 }
256250
257 return list;
258}
251 const next = p.token_ids[p.tok_i];
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 tokens
261fn findNextContainerMember(it: *TokenIterator) void {
262 var level: u32 = 0;
263 while (true) {
264 const tok = nextToken(it);
265 switch (tok.ptr.id) {
266 // any of these can start a new top level declaration
267 .Keyword_test,
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 => {},
267 // this was likely not supposed to end yet,
268 // try to find the next declaration
269 p.findNextContainerMember();
270 try p.errors.append(p.gpa, .{
271 .ExpectedContainerMembers = .{ .token = index },
272 });
273 },
274 }
309275 }
276
277 return list.toOwnedSlice();
310278 }
311}
312279
313/// Attempts to find the next statement by searching for a semicolon
314fn findNextStmt(it: *TokenIterator) void {
315 var level: u32 = 0;
316 while (true) {
317 const tok = nextToken(it);
318 switch (tok.ptr.id) {
319 .LBrace => level += 1,
320 .RBrace => {
321 if (level == 0) {
322 putBackToken(it, tok.index);
323 return;
324 }
325 level -= 1;
326 },
327 .Semicolon => {
328 if (level == 0) {
280 /// Attempts to find next container member by searching for certain tokens
281 fn findNextContainerMember(p: *Parser) void {
282 var level: u32 = 0;
283 while (true) {
284 const tok = p.nextToken();
285 switch (p.token_ids[tok]) {
286 // any of these can start a new top level declaration
287 .Keyword_test,
288 .Keyword_comptime,
289 .Keyword_pub,
290 .Keyword_export,
291 .Keyword_extern,
292 .Keyword_inline,
293 .Keyword_noinline,
294 .Keyword_usingnamespace,
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);
329326 return;
330 }
331 },
332 .Eof => {
333 putBackToken(it, tok.index);
334 return;
335 },
336 else => {},
327 },
328 else => {},
329 }
337330 }
338331 }
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| {
416 const fn_node = node.cast(Node.FnProto).?;
417 fn_node.*.extern_export_inline_token = extern_export_inline_token;
418 fn_node.*.lib_name = lib_name;
419 if (eatToken(it, .Semicolon)) |_| return node;
420
421 if (try expectNodeRecoverable(arena, it, tree, parseBlock, .{
422 // since parseBlock only return error.ParseError on
423 // a missing '}' we can assume this function was
424 // supposed to end here.
425 .ExpectedSemiOrLBrace = .{ .token = it.index },
426 })) |body_node| {
427 fn_node.body_node = body_node;
333 /// Attempts to find the next statement by searching for a semicolon
334 fn findNextStmt(p: *Parser) void {
335 var level: u32 = 0;
336 while (true) {
337 const tok = p.nextToken();
338 switch (p.token_ids[tok]) {
339 .LBrace => level += 1,
340 .RBrace => {
341 if (level == 0) {
342 p.putBackToken(tok);
343 return;
344 }
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 }
428358 }
429 return node;
430359 }
431360
432 if (extern_export_inline_token) |token| {
433 if (tree.tokens.at(token).id == .Keyword_inline or
434 tree.tokens.at(token).id == .Keyword_noinline)
435 {
436 try tree.errors.push(.{
437 .ExpectedFn = .{ .token = it.index },
438 });
439 return error.ParseError;
361 /// Eat a multiline container doc comment
362 fn parseContainerDocComments(p: *Parser) !?*Node {
363 if (p.eatToken(.ContainerDocComment)) |first_line| {
364 while (p.eatToken(.ContainerDocComment)) |_| {}
365 const node = try p.arena.allocator.create(Node.DocComment);
366 node.* = .{ .first_line = first_line };
367 return &node.base;
440368 }
369 return null;
441370 }
442371
443 const thread_local_token = eatToken(it, .Keyword_threadlocal);
444
445 if (try parseVarDecl(arena, it, tree)) |node| {
446 var var_decl = node.cast(Node.VarDecl).?;
447 var_decl.*.thread_local_token = thread_local_token;
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 },
372 /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block
373 fn parseTestDecl(p: *Parser) !?*Node {
374 const test_token = p.eatToken(.Keyword_test) orelse return null;
375 const name_node = try p.expectNode(parseStringLiteralSingle, .{
376 .ExpectedStringLiteral = .{ .token = p.tok_i },
457377 });
458 // ignore this and try again;
459 return error.ParseError;
460 }
461
462 if (extern_export_inline_token) |token| {
463 try tree.errors.push(.{
464 .ExpectedVarDeclOrFn = .{ .token = it.index },
378 const block_node = try p.expectNode(parseBlock, .{
379 .ExpectedLBrace = .{ .token = p.tok_i },
465380 });
466 // ignore this and try again;
467 return error.ParseError;
381
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;
468390 }
469391
470 return try parseUse(arena, it, tree);
471}
392 /// TopLevelComptime <- KEYWORD_comptime BlockExpr
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)
474fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
475 // TODO: Remove once extern/async fn rewriting is
476 var is_async = false;
477 var is_extern = false;
478 const cc_token: ?usize = blk: {
479 if (eatToken(it, .Keyword_extern)) |token| {
480 is_extern = true;
481 break :blk token;
482 }
483 if (eatToken(it, .Keyword_async)) |token| {
484 is_async = true;
485 break :blk token;
486 }
487 break :blk null;
488 };
489 const fn_token = eatToken(it, .Keyword_fn) orelse {
490 if (cc_token) |token|
491 putBackToken(it, token);
492 return null;
493 };
494 const name_token = eatToken(it, .Identifier);
495 const lparen = try expectToken(it, tree, .LParen);
496 const params = try parseParamDeclList(arena, it, tree);
497 const rparen = try expectToken(it, tree, .RParen);
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 };
404 const comptime_node = try p.arena.allocator.create(Node.Comptime);
405 comptime_node.* = .{
406 .doc_comments = null,
407 .comptime_token = tok,
408 .expr = block_node,
409 };
410 return &comptime_node.base;
411 }
412
413 /// TopLevelDecl
414 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
415 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
416 /// / KEYWORD_usingnamespace Expr SEMICOLON
417 fn parseTopLevelDecl(p: *Parser) !?*Node {
418 var lib_name: ?*Node = null;
419 const extern_export_inline_token = blk: {
420 if (p.eatToken(.Keyword_export)) |token| break :blk token;
421 if (p.eatToken(.Keyword_extern)) |token| {
422 lib_name = try p.parseStringLiteralSingle();
423 break :blk token;
424 }
425 if (p.eatToken(.Keyword_inline)) |token| break :blk token;
426 if (p.eatToken(.Keyword_noinline)) |token| break :blk token;
427 break :blk null;
428 };
543429
544 return &fn_proto_node.base;
545}
430 if (try p.parseFnProto()) |node| {
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)? SEMICOLON
548fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
549 const mut_token = eatToken(it, .Keyword_const) orelse
550 eatToken(it, .Keyword_var) orelse
551 return null;
447 if (extern_export_inline_token) |token| {
448 if (p.token_ids[token] == .Keyword_inline or
449 p.token_ids[token] == .Keyword_noinline)
450 {
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);
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}
458 const thread_local_token = p.eatToken(.Keyword_threadlocal);
589459
590/// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
591fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
592 const comptime_token = eatToken(it, .Keyword_comptime);
593 const name_token = eatToken(it, .Identifier) orelse {
594 if (comptime_token) |t| putBackToken(it, t);
595 return null;
596 };
460 if (try p.parseVarDecl()) |node| {
461 var var_decl = node.cast(Node.VarDecl).?;
462 var_decl.*.thread_local_token = thread_local_token;
463 var_decl.*.comptime_token = null;
464 var_decl.*.extern_export_token = extern_export_inline_token;
465 var_decl.*.lib_name = lib_name;
466 return node;
467 }
597468
598 var align_expr: ?*Node = null;
599 var type_expr: ?*Node = null;
600 if (eatToken(it, .Colon)) |_| {
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 },
469 if (thread_local_token != null) {
470 try p.errors.append(p.gpa, .{
471 .ExpectedVarDecl = .{ .token = p.tok_i },
608472 });
609 align_expr = try parseByteAlign(arena, it, tree);
473 // ignore this and try again;
474 return error.ParseError;
610475 }
611 }
612476
613 const value_expr = if (eatToken(it, .Equal)) |_|
614 try expectNode(arena, it, tree, parseExpr, .{
615 .ExpectedExpr = .{ .token = it.index },
616 })
617 else
618 null;
619
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}
477 if (extern_export_inline_token) |token| {
478 try p.errors.append(p.gpa, .{
479 .ExpectedVarDeclOrFn = .{ .token = p.tok_i },
480 });
481 // ignore this and try again;
482 return error.ParseError;
483 }
631484
632/// Statement
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;
485 return p.parseUse();
651486 }
652487
653 if (comptime_token) |token| {
654 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
655 .ExpectedBlockOrAssignment = .{ .token = it.index },
488 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
489 fn parseFnProto(p: *Parser) !?*Node {
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 },
656524 });
657525
658 const node = try arena.create(Node.Comptime);
659 node.* = .{
660 .doc_comments = null,
661 .comptime_token = token,
662 .expr = block_expr,
663 };
664 return &node.base;
665 }
526 // TODO https://github.com/ziglang/zig/issues/3750
527 const R = Node.FnProto.ReturnType;
528 const return_type = if (return_type_expr == null)
529 R{ .Invalid = rparen }
530 else if (exclamation_token != null)
531 R{ .InferErrorSet = return_type_expr.? }
532 else
533 R{ .Explicit = return_type_expr.? };
666534
667 if (eatToken(it, .Keyword_nosuspend)) |nosuspend_token| {
668 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
669 .ExpectedBlockOrAssignment = .{ .token = it.index },
670 });
535 const var_args_token = if (params.len > 0) blk: {
536 const param_type = params[params.len - 1].param_type;
537 break :blk if (param_type == .var_args) param_type.var_args else null;
538 } else
539 null;
671540
672 const node = try arena.create(Node.Nosuspend);
673 node.* = .{
674 .nosuspend_token = nosuspend_token,
675 .expr = block_expr,
541 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
542 fn_proto_node.* = .{
543 .doc_comments = null,
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,
676558 };
677 return &node.base;
559 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
560
561 return &fn_proto_node.base;
678562 }
679563
680 if (eatToken(it, .Keyword_suspend)) |suspend_token| {
681 const semicolon = eatToken(it, .Semicolon);
564 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? 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: {
684 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{
685 .ExpectedBlockOrExpression = .{ .token = it.index },
570 const name_token = try p.expectToken(.Identifier);
571 const type_node = if (p.eatToken(.Colon) != null)
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 },
686583 });
687584 } 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);
690588 node.* = .{
691 .suspend_token = suspend_token,
692 .body = body_node,
589 .doc_comments = null,
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,
693603 };
694604 return &node.base;
695605 }
696606
697 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);
698 if (defer_token) |token| {
699 const payload = if (tree.tokens.at(token).id == .Keyword_errdefer)
700 try parsePayload(arena, it, tree)
607 /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
608 fn parseContainerField(p: *Parser) !?*Node {
609 const comptime_token = p.eatToken(.Keyword_comptime);
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 })
701634 else
702635 null;
703 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{
704 .ExpectedBlockOrExpression = .{ .token = it.index },
705 });
706 const node = try arena.create(Node.Defer);
636
637 const node = try p.arena.allocator.create(Node.ContainerField);
707638 node.* = .{
708 .defer_token = token,
709 .expr = expr_node,
710 .payload = payload,
639 .doc_comments = null,
640 .comptime_token = comptime_token,
641 .name_token = name_token,
642 .type_expr = type_expr,
643 .value_expr = value_expr,
644 .align_expr = align_expr,
711645 };
712646 return &node.base;
713647 }
714648
715 if (try parseIfStatement(arena, it, tree)) |node| return node;
716 if (try parseLabeledStatement(arena, it, tree)) |node| return node;
717 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
718 if (try parseAssignExpr(arena, it, tree)) |node| {
719 _ = try expectTokenRecoverable(it, tree, .Semicolon);
720 return node;
721 }
649 /// Statement
650 /// <- KEYWORD_comptime? VarDecl
651 /// / KEYWORD_comptime BlockExprStatement
652 /// / KEYWORD_nosuspend BlockExprStatement
653 /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
654 /// / KEYWORD_defer BlockExprStatement
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;
724}
670 if (comptime_token) |token| {
671 const block_expr = try p.expectNode(parseBlockExprStatement, .{
672 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
673 });
725674
726/// IfStatement
727/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
728/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
729fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
730 const if_node = (try parseIfPrefix(arena, it, tree)) orelse return null;
731 const if_prefix = if_node.cast(Node.If).?;
732
733 const block_expr = (try parseBlockExpr(arena, it, tree));
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 });
675 const node = try p.arena.allocator.create(Node.Comptime);
676 node.* = .{
677 .doc_comments = null,
678 .comptime_token = token,
679 .expr = block_expr,
680 };
681 return &node.base;
682 }
749683
750 const node = try arena.create(Node.Else);
751 node.* = .{
752 .else_token = else_token,
753 .payload = payload,
754 .body = else_body,
755 };
684 if (p.eatToken(.Keyword_nosuspend)) |nosuspend_token| {
685 const block_expr = try p.expectNode(parseBlockExprStatement, .{
686 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
687 });
756688
757 break :blk node;
758 } else null;
689 const node = try p.arena.allocator.create(Node.Nosuspend);
690 node.* = .{
691 .nosuspend_token = nosuspend_token,
692 .expr = block_expr,
693 };
694 return &node.base;
695 }
759696
760 if (block_expr) |body| {
761 if_prefix.body = body;
762 if_prefix.@"else" = else_node;
763 return if_node;
764 }
697 if (p.eatToken(.Keyword_suspend)) |suspend_token| {
698 const semicolon = p.eatToken(.Semicolon);
765699
766 if (assign_expr) |body| {
767 if_prefix.body = body;
768 if (semicolon != null) return if_node;
769 if (else_node != null) {
770 if_prefix.@"else" = else_node;
771 return if_node;
772 }
773 try tree.errors.push(.{
774 .ExpectedSemiOrElse = .{ .token = it.index },
775 });
776 }
777
778 return if_node;
779}
700 const body_node = if (semicolon == null) blk: {
701 break :blk try p.expectNode(parseBlockExprStatement, .{
702 .ExpectedBlockOrExpression = .{ .token = p.tok_i },
703 });
704 } else null;
780705
781/// LabeledStatement <- BlockLabel? (Block / LoopStatement)
782fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
783 var colon: TokenIndex = undefined;
784 const label_token = parseBlockLabel(arena, it, tree, &colon);
706 const node = try p.arena.allocator.create(Node.Suspend);
707 node.* = .{
708 .suspend_token = suspend_token,
709 .body = body_node,
710 };
711 return &node.base;
712 }
785713
786 if (try parseBlock(arena, it, tree)) |node| {
787 node.cast(Node.Block).?.label = label_token;
788 return node;
789 }
714 const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer);
715 if (defer_token) |token| {
716 const payload = if (p.token_ids[token] == .Keyword_errdefer)
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| {
792 if (node.cast(Node.For)) |for_node| {
793 for_node.label = label_token;
794 } else if (node.cast(Node.While)) |while_node| {
795 while_node.label = label_token;
796 } else unreachable;
797 return node;
798 }
732 if (try p.parseIfStatement()) |node| return node;
733 if (try p.parseLabeledStatement()) |node| return node;
734 if (try p.parseSwitchExpr()) |node| return node;
735 if (try p.parseAssignExpr()) |node| {
736 _ = try p.expectTokenRecoverable(.Semicolon);
737 return node;
738 }
799739
800 if (label_token != null) {
801 try tree.errors.push(.{
802 .ExpectedLabelable = .{ .token = it.index },
803 });
804 return error.ParseError;
740 return null;
805741 }
806742
807 return null;
808}
743 /// IfStatement
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)
811fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
812 const inline_token = eatToken(it, .Keyword_inline);
750 const block_expr = (try p.parseBlockExpr());
751 const assign_expr = if (block_expr == null)
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| {
815 node.cast(Node.For).?.inline_token = inline_token;
816 return node;
817 }
758 const semicolon = if (assign_expr != null) p.eatToken(.Semicolon) else null;
818759
819 if (try parseWhileStatement(arena, it, tree)) |node| {
820 node.cast(Node.While).?.inline_token = inline_token;
821 return node;
822 }
823 if (inline_token == null) return null;
760 const else_node = if (semicolon == null) blk: {
761 const else_token = p.eatToken(.Keyword_else) orelse break :blk null;
762 const payload = try p.parsePayload();
763 const else_body = try p.expectNode(parseStatement, .{
764 .InvalidToken = .{ .token = p.tok_i },
765 });
824766
825 // If we've seen "inline", there should have been a "for" or "while"
826 try tree.errors.push(.{
827 .ExpectedInlinable = .{ .token = it.index },
828 });
829 return error.ParseError;
830}
767 const node = try p.arena.allocator.create(Node.Else);
768 node.* = .{
769 .else_token = else_token,
770 .payload = payload,
771 .body = else_body,
772 };
831773
832/// ForStatement
833/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
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).?;
774 break :blk node;
775 } else null;
838776
839 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {
840 for_prefix.body = block_expr_node;
777 if (block_expr) |body| {
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| {
843 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
844 .InvalidToken = .{ .token = it.index },
783 if (assign_expr) |body| {
784 if_prefix.body = body;
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 },
845792 });
793 }
846794
847 const else_node = try arena.create(Node.Else);
848 else_node.* = .{
849 .else_token = else_token,
850 .payload = null,
851 .body = statement_node,
852 };
853 for_prefix.@"else" = else_node;
795 return if_node;
796 }
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;
855805 return node;
856806 }
857807
858 return node;
859 }
808 if (try p.parseLoopStatement()) |node| {
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| {
862 for_prefix.body = assign_expr;
817 if (label_token != null) {
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| {
867 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
868 .ExpectedStatement = .{ .token = it.index },
869 });
827 /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
828 fn parseLoopStatement(p: *Parser) !?*Node {
829 const inline_token = p.eatToken(.Keyword_inline);
870830
871 const else_node = try arena.create(Node.Else);
872 else_node.* = .{
873 .else_token = else_token,
874 .payload = null,
875 .body = statement_node,
876 };
877 for_prefix.@"else" = else_node;
831 if (try p.parseForStatement()) |node| {
832 node.cast(Node.For).?.inline_token = inline_token;
878833 return node;
879834 }
880835
881 try tree.errors.push(.{
882 .ExpectedSemiOrElse = .{ .token = it.index },
883 });
836 if (try p.parseWhileStatement()) |node| {
837 node.cast(Node.While).?.inline_token = inline_token;
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;
886847 }
887848
888 return null;
889}
890
891/// WhileStatement
892/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
893/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
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).?;
849 /// ForStatement
850 /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
851 /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
852 fn parseForStatement(p: *Parser) !?*Node {
853 const node = (try p.parseForPrefix()) orelse return null;
854 const for_prefix = node.cast(Node.For).?;
897855
898 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {
899 while_prefix.body = block_expr_node;
856 if (try p.parseBlockExpr()) |block_expr_node| {
857 for_prefix.body = block_expr_node;
900858
901 if (eatToken(it, .Keyword_else)) |else_token| {
902 const payload = try parsePayload(arena, it, tree);
859 if (p.eatToken(.Keyword_else)) |else_token| {
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, .{
905 .InvalidToken = .{ .token = it.index },
906 });
864 const else_node = try p.arena.allocator.create(Node.Else);
865 else_node.* = .{
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);
909 else_node.* = .{
910 .else_token = else_token,
911 .payload = payload,
912 .body = statement_node,
913 };
914 while_prefix.@"else" = else_node;
872 return node;
873 }
915874
916875 return node;
917876 }
918877
919 return node;
920 }
878 if (try p.parseAssignExpr()) |assign_expr| {
879 for_prefix.body = assign_expr;
921880
922 if (try parseAssignExpr(arena, it, tree)) |assign_expr_node| {
923 while_prefix.body = assign_expr_node;
881 if (p.eatToken(.Semicolon) != null) return 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| {
928 const payload = try parsePayload(arena, it, tree);
888 const else_node = try p.arena.allocator.create(Node.Else);
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, .{
931 .ExpectedStatement = .{ .token = it.index },
898 try p.errors.append(p.gpa, .{
899 .ExpectedSemiOrElse = .{ .token = p.tok_i },
932900 });
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;
941902 return node;
942903 }
943904
944 try tree.errors.push(.{
945 .ExpectedSemiOrElse = .{ .token = it.index },
946 });
947
948 return node;
905 return null;
949906 }
950907
951 return null;
952}
908 /// WhileStatement
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/// BlockExprStatement
955/// <- BlockExpr
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}
915 if (try p.parseBlockExpr()) |block_expr_node| {
916 while_prefix.body = block_expr_node;
965917
966/// BlockExpr <- BlockLabel? Block
967fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
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}
918 if (p.eatToken(.Keyword_else)) |else_token| {
919 const payload = try p.parsePayload();
980920
981/// AssignExpr <- Expr (AssignOp Expr)?
982fn parseAssignExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
983 return parseBinOpExpr(arena, it, tree, parseAssignOp, parseExpr, .Once);
984}
921 const statement_node = try p.expectNode(parseStatement, .{
922 .InvalidToken = .{ .token = p.tok_i },
923 });
985924
986/// Expr <- KEYWORD_try* BoolOrExpr
987fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
988 return parsePrefixOpExpr(arena, it, tree, parseTry, parseBoolOrExpr);
989}
925 const else_node = try p.arena.allocator.create(Node.Else);
926 else_node.* = .{
927 .else_token = else_token,
928 .payload = payload,
929 .body = statement_node,
930 };
931 while_prefix.@"else" = else_node;
990932
991/// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
992fn parseBoolOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
993 return parseBinOpExpr(
994 arena,
995 it,
996 tree,
997 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
998 parseBoolAndExpr,
999 .Infinitely,
1000 );
1001}
933 return node;
934 }
1002935
1003/// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
1004fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1005 return parseBinOpExpr(
1006 arena,
1007 it,
1008 tree,
1009 SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
1010 parseCompareExpr,
1011 .Infinitely,
1012 );
1013}
936 return node;
937 }
1014938
1015/// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
1016fn parseCompareExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1017 return parseBinOpExpr(arena, it, tree, parseCompareOp, parseBitwiseExpr, .Once);
1018}
939 if (try p.parseAssignExpr()) |assign_expr_node| {
940 while_prefix.body = assign_expr_node;
1019941
1020/// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
1021fn parseBitwiseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1022 return parseBinOpExpr(arena, it, tree, parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1023}
942 if (p.eatToken(.Semicolon) != null) return node;
1024943
1025/// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
1026fn parseBitShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1027 return parseBinOpExpr(arena, it, tree, parseBitShiftOp, parseAdditionExpr, .Infinitely);
1028}
944 if (p.eatToken(.Keyword_else)) |else_token| {
945 const payload = try p.parsePayload();
1029946
1030/// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
1031fn parseAdditionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1032 return parseBinOpExpr(arena, it, tree, parseAdditionOp, parseMultiplyExpr, .Infinitely);
1033}
947 const statement_node = try p.expectNode(parseStatement, .{
948 .ExpectedStatement = .{ .token = p.tok_i },
949 });
1034950
1035/// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
1036fn parseMultiplyExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1037 return parseBinOpExpr(arena, it, tree, parseMultiplyOp, parsePrefixExpr, .Infinitely);
1038}
951 const else_node = try p.arena.allocator.create(Node.Else);
952 else_node.* = .{
953 .else_token = else_token,
954 .payload = payload,
955 .body = statement_node,
956 };
957 while_prefix.@"else" = else_node;
958 return node;
959 }
1039960
1040/// PrefixExpr <- PrefixOp* PrimaryExpr
1041fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1042 return parsePrefixOpExpr(arena, it, tree, parsePrefixOp, parsePrimaryExpr);
1043}
961 try p.errors.append(p.gpa, .{
962 .ExpectedSemiOrElse = .{ .token = p.tok_i },
963 });
1044964
1045/// PrimaryExpr
1046/// <- AsmExpr
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 }
965 return node;
966 }
1072967
1073 if (eatToken(it, .Keyword_comptime)) |token| {
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;
968 return null;
1084969 }
1085970
1086 if (eatToken(it, .Keyword_nosuspend)) |token| {
1087 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1088 .ExpectedExpr = .{ .token = it.index },
1089 });
1090 const node = try arena.create(Node.Nosuspend);
1091 node.* = .{
1092 .nosuspend_token = token,
1093 .expr = expr_node,
1094 };
1095 return &node.base;
971 /// BlockExprStatement
972 /// <- BlockExpr
973 /// / AssignExpr SEMICOLON
974 fn parseBlockExprStatement(p: *Parser) !?*Node {
975 if (try p.parseBlockExpr()) |node| return node;
976 if (try p.parseAssignExpr()) |node| {
977 _ = try p.expectTokenRecoverable(.Semicolon);
978 return node;
979 }
980 return null;
1096981 }
1097982
1098 if (eatToken(it, .Keyword_continue)) |token| {
1099 const label = try parseBreakLabel(arena, it, tree);
1100 const node = try arena.create(Node.ControlFlowExpression);
1101 node.* = .{
1102 .ltoken = token,
1103 .kind = .{ .Continue = label },
1104 .rhs = null,
983 /// BlockExpr <- BlockLabel? Block
984 fn parseBlockExpr(p: *Parser) Error!?*Node {
985 var colon: TokenIndex = undefined;
986 const label_token = p.parseBlockLabel(&colon);
987 const block_node = (try p.parseBlock()) orelse {
988 if (label_token) |label| {
989 p.putBackToken(label + 1); // ":"
990 p.putBackToken(label); // IDENTIFIER
991 }
992 return null;
1105993 };
1106 return &node.base;
994 block_node.cast(Node.Block).?.label = label_token;
995 return block_node;
1107996 }
1108997
1109 if (eatToken(it, .Keyword_resume)) |token| {
1110 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1111 .ExpectedExpr = .{ .token = it.index },
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;
998 /// AssignExpr <- Expr (AssignOp Expr)?
999 fn parseAssignExpr(p: *Parser) !?*Node {
1000 return p.parseBinOpExpr(parseAssignOp, parseExpr, .Once);
11201001 }
11211002
1122 if (eatToken(it, .Keyword_return)) |token| {
1123 const expr_node = try parseExpr(arena, it, tree);
1124 const node = try arena.create(Node.ControlFlowExpression);
1125 node.* = .{
1126 .ltoken = token,
1127 .kind = .Return,
1128 .rhs = expr_node,
1129 };
1130 return &node.base;
1003 /// Expr <- KEYWORD_try* BoolOrExpr
1004 fn parseExpr(p: *Parser) Error!?*Node {
1005 return p.parsePrefixOpExpr(parseTry, parseBoolOrExpr);
11311006 }
11321007
1133 var colon: TokenIndex = undefined;
1134 const label = parseBlockLabel(arena, it, tree, &colon);
1135 if (try parseLoopExpr(arena, it, tree)) |node| {
1136 if (node.cast(Node.For)) |for_node| {
1137 for_node.label = label;
1138 } else if (node.cast(Node.While)) |while_node| {
1139 while_node.label = label;
1140 } else unreachable;
1141 return node;
1142 }
1143 if (label) |token| {
1144 putBackToken(it, token + 1); // ":"
1145 putBackToken(it, token); // IDENTIFIER
1008 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
1009 fn parseBoolOrExpr(p: *Parser) !?*Node {
1010 return p.parseBinOpExpr(
1011 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
1012 parseBoolAndExpr,
1013 .Infinitely,
1014 );
11461015 }
11471016
1148 if (try parseBlock(arena, it, tree)) |node| return node;
1149 if (try parseCurlySuffixExpr(arena, it, tree)) |node| return node;
1017 /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
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;
1152}
1026 /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
1027 fn parseCompareExpr(p: *Parser) !?*Node {
1028 return p.parseBinOpExpr(parseCompareOp, parseBitwiseExpr, .Once);
1029 }
11531030
1154/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
1155fn parseIfExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1156 return parseIf(arena, it, tree, parseExpr);
1157}
1031 /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
1032 fn parseBitwiseExpr(p: *Parser) !?*Node {
1033 return p.parseBinOpExpr(parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1034 }
11581035
1159/// Block <- LBRACE Statement* RBRACE
1160fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1161 const lbrace = eatToken(it, .LBrace) orelse return null;
1036 /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
1037 fn parseBitShiftExpr(p: *Parser) !?*Node {
1038 return p.parseBinOpExpr(parseBitShiftOp, parseAdditionExpr, .Infinitely);
1039 }
11621040
1163 var statements = Node.Block.StatementList.init(arena);
1164 while (true) {
1165 const statement = (parseStatement(arena, it, tree) catch |err| switch (err) {
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);
1041 /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
1042 fn parseAdditionExpr(p: *Parser) !?*Node {
1043 return p.parseBinOpExpr(parseAdditionOp, parseMultiplyExpr, .Infinitely);
11741044 }
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);
1179 block_node.* = .{
1180 .label = null,
1181 .lbrace = lbrace,
1182 .statements = statements,
1183 .rbrace = rbrace,
1184 };
1051 /// PrefixExpr <- PrefixOp* PrimaryExpr
1052 fn parsePrefixExpr(p: *Parser) !?*Node {
1053 return p.parsePrefixOpExpr(parsePrefixOp, parsePrimaryExpr);
1054 }
11851055
1186 return &block_node.base;
1187}
1056 /// PrimaryExpr
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)
1190fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1191 const inline_token = eatToken(it, .Keyword_inline);
1072 if (p.eatToken(.Keyword_break)) |token| {
1073 const label = try p.parseBreakLabel();
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| {
1194 node.cast(Node.For).?.inline_token = inline_token;
1195 return node;
1196 }
1084 if (p.eatToken(.Keyword_comptime)) |token| {
1085 const expr_node = try p.expectNode(parseExpr, .{
1086 .ExpectedExpr = .{ .token = p.tok_i },
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| {
1199 node.cast(Node.While).?.inline_token = inline_token;
1200 return node;
1201 }
1097 if (p.eatToken(.Keyword_nosuspend)) |token| {
1098 const expr_node = try p.expectNode(parseExpr, .{
1099 .ExpectedExpr = .{ .token = p.tok_i },
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"
1206 try tree.errors.push(.{
1207 .ExpectedInlinable = .{ .token = it.index },
1208 });
1209 return error.ParseError;
1210}
1120 if (p.eatToken(.Keyword_resume)) |token| {
1121 const expr_node = try p.expectNode(parseExpr, .{
1122 .ExpectedExpr = .{ .token = p.tok_i },
1123 });
1124 const node = try p.arena.allocator.create(Node.PrefixOp);
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)?
1213fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1214 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1215 const for_prefix = node.cast(Node.For).?;
1133 if (p.eatToken(.Keyword_return)) |token| {
1134 const expr_node = try p.parseExpr();
1135 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
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, .{
1218 .ExpectedExpr = .{ .token = it.index },
1219 });
1220 for_prefix.body = body_node;
1144 var colon: TokenIndex = undefined;
1145 const label = p.parseBlockLabel(&colon);
1146 if (try p.parseLoopExpr()) |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| {
1223 const body = try expectNode(arena, it, tree, parseExpr, .{
1224 .ExpectedExpr = .{ .token = it.index },
1225 });
1159 if (try p.parseBlock()) |node| return node;
1160 if (try p.parseCurlySuffixExpr()) |node| return node;
12261161
1227 const else_node = try arena.create(Node.Else);
1228 else_node.* = .{
1229 .else_token = else_token,
1230 .payload = null,
1231 .body = body,
1232 };
1162 return null;
1163 }
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);
12351168 }
12361169
1237 return node;
1238}
1170 /// Block <- LBRACE Statement* RBRACE
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)?
1241fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1242 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1243 const while_prefix = node.cast(Node.While).?;
1177 while (true) {
1178 const statement = (p.parseStatement() catch |err| switch (err) {
1179 error.OutOfMemory => return error.OutOfMemory,
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, .{
1246 .ExpectedExpr = .{ .token = it.index },
1247 });
1248 while_prefix.body = body_node;
1189 const rbrace = try p.expectToken(.RBrace);
12491190
1250 if (eatToken(it, .Keyword_else)) |else_token| {
1251 const payload = try parsePayload(arena, it, tree);
1252 const body = try expectNode(arena, it, tree, parseExpr, .{
1253 .ExpectedExpr = .{ .token = it.index },
1254 });
1191 const statements_len = @intCast(NodeIndex, statements.items.len);
12551192
1256 const else_node = try arena.create(Node.Else);
1257 else_node.* = .{
1258 .else_token = else_token,
1259 .payload = payload,
1260 .body = body,
1193 const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
1194 block_node.* = .{
1195 .label = null,
1196 .lbrace = lbrace,
1197 .statements_len = statements_len,
1198 .rbrace = rbrace,
12611199 };
1200 std.mem.copy(*Node, block_node.statements(), statements.items);
12621201
1263 while_prefix.@"else" = else_node;
1202 return &block_node.base;
12641203 }
12651204
1266 return node;
1267}
1268
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}
1205 /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
1206 fn parseLoopExpr(p: *Parser) !?*Node {
1207 const inline_token = p.eatToken(.Keyword_inline);
12761208
1277/// InitList
1278/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
1279/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
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 };
1209 if (try p.parseForExpr()) |node| {
1210 node.cast(Node.For).?.inline_token = inline_token;
1211 return node;
12931212 }
12941213
1295 if (try parseExpr(arena, it, tree)) |expr| {
1296 try init_list.push(expr);
1297 while (eatToken(it, .Comma)) |_| {
1298 const next = (try parseExpr(arena, it, tree)) orelse break;
1299 try init_list.push(next);
1300 }
1301 break :blk .{ .ArrayInitializer = init_list };
1214 if (try p.parseWhileExpr()) |node| {
1215 node.cast(Node.While).?.inline_token = inline_token;
1216 return node;
13021217 }
13031218
1304 break :blk .{ .StructInitializer = init_list };
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}
1219 if (inline_token == null) return null;
13151220
1316/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1317fn parseTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
1318 return parsePrefixOpExpr(arena, it, tree, parsePrefixTypeOp, parseErrorUnionExpr);
1319}
1221 // If we've seen "inline", there should have been a "for" or "while"
1222 try p.errors.append(p.gpa, .{
1223 .ExpectedInlinable = .{ .token = p.tok_i },
1224 });
1225 return error.ParseError;
1226 }
13201227
1321/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
1322fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1323 const suffix_expr = (try parseSuffixExpr(arena, it, tree)) orelse return null;
1228 /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
1229 fn parseForExpr(p: *Parser) !?*Node {
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| {
1326 const error_union = node.cast(Node.InfixOp).?;
1327 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1328 .ExpectedTypeExpr = .{ .token = it.index },
1233 const body_node = try p.expectNode(parseExpr, .{
1234 .ExpectedExpr = .{ .token = p.tok_i },
13291235 });
1330 error_union.lhs = suffix_expr;
1331 error_union.rhs = type_expr;
1236 for_prefix.body = body_node;
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
13321253 return node;
13331254 }
13341255
1335 return suffix_expr;
1336}
1256 /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
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/// SuffixExpr
1339/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
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 },
1261 const body_node = try p.expectNode(parseExpr, .{
1262 .ExpectedExpr = .{ .token = p.tok_i },
13571263 });
1264 while_prefix.body = body_node;
13581265
1359 while (try parseSuffixOp(arena, it, tree)) |node| {
1360 switch (node.id) {
1361 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
1362 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
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 },
1266 if (p.eatToken(.Keyword_else)) |else_token| {
1267 const payload = try p.parsePayload();
1268 const body = try p.expectNode(parseExpr, .{
1269 .ExpectedExpr = .{ .token = p.tok_i },
13711270 });
1372 // ignore this, continue parsing
1373 return res;
1271
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,
13741338 };
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);
13761384 node.* = .{
1377 .lhs = .{ .node = res },
1378 .op = .{
1379 .Call = .{
1380 .params = params.list,
1381 .async_token = async_token,
1382 },
1383 },
1384 .rtoken = params.rparen,
1385 .dot = dot,
1386 .rtoken = try p.expectToken(.RBrace),
1387 .list_len = 0,
13851388 };
13861389 return &node.base;
13871390 }
1388 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
1389 var res = expr;
13901391
1391 while (true) {
1392 if (try parseSuffixOp(arena, it, tree)) |node| {
1392 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
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| {
13931436 switch (node.id) {
1394 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
1437 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
13951438 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
13961439 else => unreachable,
13971440 }
13981441 res = node;
1399 continue;
14001442 }
1401 if (try parseFnCallArguments(arena, it, tree)) |params| {
1402 const call = try arena.create(Node.SuffixOp);
1403 call.* = .{
1404 .lhs = .{ .node = res },
1405 .op = .{
1406 .Call = .{
1407 .params = params.list,
1408 .async_token = null,
1409 },
1410 },
1411 .rtoken = params.rparen,
1412 };
1413 res = &call.base;
1414 continue;
1443
1444 const params = (try p.parseFnCallArguments()) orelse {
1445 try p.errors.append(p.gpa, .{
1446 .ExpectedParamList = .{ .token = p.tok_i },
1447 });
1448 // ignore this, continue parsing
1449 return res;
1450 };
1451 defer p.gpa.free(params.list);
1452 const node = try Node.Call.alloc(&p.arena.allocator, params.list.len);
1453 node.* = .{
1454 .lhs = res,
1455 .params_len = params.list.len,
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;
14151489 }
1416 break;
1490 return res;
14171491 }
1418 return res;
1492
1493 return null;
14191494 }
14201495
1421 return null;
1422}
1496 /// PrimaryTypeExpr
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/// PrimaryTypeExpr
1425/// <- BUILTINIDENTIFIER FnCallArguments
1426/// / CHAR_LITERAL
1427/// / ContainerDecl
1428/// / DOT IDENTIFIER
1429/// / ErrorSetDecl
1430/// / FLOAT
1431/// / FnProto
1432/// / GroupedExpr
1433/// / LabeledTypeExpr
1434/// / IDENTIFIER
1435/// / IfTypeExpr
1436/// / INTEGER
1437/// / KEYWORD_comptime TypeExpr
1438/// / KEYWORD_error DOT IDENTIFIER
1439/// / KEYWORD_false
1440/// / KEYWORD_null
1441/// / KEYWORD_anyframe
1442/// / KEYWORD_true
1443/// / KEYWORD_undefined
1444/// / KEYWORD_unreachable
1445/// / STRINGLITERAL
1446/// / SwitchExpr
1447fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1448 if (try parseBuiltinCall(arena, it, tree)) |node| return node;
1449 if (eatToken(it, .CharLiteral)) |token| {
1450 const node = try arena.create(Node.CharLiteral);
1451 node.* = .{
1452 .token = token,
1556 const node = try p.arena.allocator.create(Node.InfixOp);
1557 node.* = .{
1558 .op_token = period.?,
1559 .lhs = global_error_set,
1560 .op = .Period,
1561 .rhs = identifier.?,
1562 };
1563 return &node.base;
1564 }
1565 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token);
1566 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token);
1567 if (p.eatToken(.Keyword_anyframe)) |token| {
1568 const node = try p.arena.allocator.create(Node.AnyFrameType);
1569 node.* = .{
1570 .anyframe_token = token,
1571 .result = null,
1572 };
1573 return &node.base;
1574 }
1575 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token);
1576 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token);
1577 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token);
1578 if (try p.parseStringLiteral()) |node| return node;
1579 if (try p.parseSwitchExpr()) |node| return node;
1580
1581 return null;
1582 }
1583
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;
14531593 };
1454 return &node.base;
1594 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
1595 return node;
14551596 }
1456 if (try parseContainerDecl(arena, it, tree)) |node| return node;
1457 if (try parseAnonLiteral(arena, it, tree)) |node| return node;
1458 if (try parseErrorSetDecl(arena, it, tree)) |node| return node;
1459 if (try parseFloatLiteral(arena, it, tree)) |node| return node;
1460 if (try parseFnProto(arena, it, tree)) |node| return node;
1461 if (try parseGroupedExpr(arena, it, tree)) |node| return node;
1462 if (try parseLabeledTypeExpr(arena, it, tree)) |node| return node;
1463 if (try parseIdentifier(arena, it, tree)) |node| return node;
1464 if (try parseIfTypeExpr(arena, it, tree)) |node| return node;
1465 if (try parseIntegerLiteral(arena, it, tree)) |node| return node;
1466 if (eatToken(it, .Keyword_comptime)) |token| {
1467 const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
1468 const node = try arena.create(Node.Comptime);
1597
1598 /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1599 fn parseErrorSetDecl(p: *Parser) !?*Node {
1600 const error_token = p.eatToken(.Keyword_error) orelse return null;
1601 if (p.eatToken(.LBrace) == null) {
1602 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1603 p.putBackToken(error_token);
1604 return null;
1605 }
1606 const decls = try p.parseErrorTagList();
1607 defer p.gpa.free(decls);
1608 const rbrace = try p.expectToken(.RBrace);
1609
1610 const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len);
14691611 node.* = .{
1470 .doc_comments = null,
1471 .comptime_token = token,
1472 .expr = expr,
1612 .error_token = error_token,
1613 .decls_len = decls.len,
1614 .rbrace_token = rbrace,
14731615 };
1616 std.mem.copy(*Node, node.decls(), decls);
14741617 return &node.base;
14751618 }
1476 if (eatToken(it, .Keyword_error)) |token| {
1477 const period = try expectTokenRecoverable(it, tree, .Period);
1478 const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{
1479 .ExpectedIdentifier = .{ .token = it.index },
1619
1620 /// GroupedExpr <- LPAREN Expr RPAREN
1621 fn parseGroupedExpr(p: *Parser) !?*Node {
1622 const lparen = p.eatToken(.LParen) orelse return null;
1623 const expr = try p.expectNode(parseExpr, .{
1624 .ExpectedExpr = .{ .token = p.tok_i },
14801625 });
1481 const global_error_set = try createLiteral(arena, Node.ErrorType, token);
1482 if (period == null or identifier == null) return global_error_set;
1626 const rparen = try p.expectToken(.RParen);
14831627
1484 const node = try arena.create(Node.InfixOp);
1628 const node = try p.arena.allocator.create(Node.GroupedExpression);
14851629 node.* = .{
1486 .op_token = period.?,
1487 .lhs = global_error_set,
1488 .op = .Period,
1489 .rhs = identifier.?,
1630 .lparen = lparen,
1631 .expr = expr,
1632 .rparen = rparen,
14901633 };
14911634 return &node.base;
14921635 }
1493 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1494 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1495 if (eatToken(it, .Keyword_anyframe)) |token| {
1496 const node = try arena.create(Node.AnyFrameType);
1497 node.* = .{
1498 .anyframe_token = token,
1499 .result = null,
1500 };
1501 return &node.base;
1636
1637 /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1638 fn parseIfTypeExpr(p: *Parser) !?*Node {
1639 return p.parseIf(parseTypeExpr);
15021640 }
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;
1510}
1642 /// LabeledTypeExpr
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)? ContainerDeclAuto
1513fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1514 const layout_token = eatToken(it, .Keyword_extern) orelse
1515 eatToken(it, .Keyword_packed);
1649 if (label) |token| {
1650 if (try p.parseBlock()) |node| {
1651 node.cast(Node.Block).?.label = token;
1652 return node;
1653 }
1654 }
15161655
1517 const node = (try parseContainerDeclAuto(arena, it, tree)) orelse {
1518 if (layout_token) |token|
1519 putBackToken(it, token);
1520 return null;
1521 };
1522 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
1523 return node;
1524}
1656 if (try p.parseLoopTypeExpr()) |node| {
1657 switch (node.id) {
1658 .For => node.cast(Node.For).?.label = label,
1659 .While => node.cast(Node.While).?.label = label,
1660 else => unreachable,
1661 }
1662 return node;
1663 }
15251664
1526/// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1527fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1528 const error_token = eatToken(it, .Keyword_error) orelse return null;
1529 if (eatToken(it, .LBrace) == null) {
1530 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1531 putBackToken(it, error_token);
1665 if (label) |token| {
1666 p.putBackToken(colon);
1667 p.putBackToken(token);
1668 }
15321669 return null;
15331670 }
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 RPAREN
1547fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1548 const lparen = eatToken(it, .LParen) orelse return null;
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}
1672 /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1673 fn parseLoopTypeExpr(p: *Parser) !?*Node {
1674 const inline_token = p.eatToken(.Keyword_inline);
15671675
1568/// LabeledTypeExpr
1569/// <- BlockLabel Block
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;
1676 if (try p.parseForTypeExpr()) |node| {
1677 node.cast(Node.For).?.inline_token = inline_token;
15781678 return node;
15791679 }
1580 }
15811680
1582 if (try parseLoopTypeExpr(arena, it, tree)) |node| {
1583 switch (node.id) {
1584 .For => node.cast(Node.For).?.label = label,
1585 .While => node.cast(Node.While).?.label = label,
1586 else => unreachable,
1681 if (try p.parseWhileTypeExpr()) |node| {
1682 node.cast(Node.While).?.inline_token = inline_token;
1683 return node;
15871684 }
1588 return node;
1589 }
15901685
1591 if (label) |token| {
1592 putBackToken(it, colon);
1593 putBackToken(it, token);
1686 if (inline_token == null) return null;
1687
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;
15941693 }
1595 return null;
1596}
15971694
1598/// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1599fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1600 const inline_token = eatToken(it, .Keyword_inline);
1695 /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
1696 fn parseForTypeExpr(p: *Parser) !?*Node {
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| {
1603 node.cast(Node.For).?.inline_token = inline_token;
1604 return node;
1605 }
1700 const type_expr = try p.expectNode(parseTypeExpr, .{
1701 .ExpectedTypeExpr = .{ .token = p.tok_i },
1702 });
1703 for_prefix.body = type_expr;
16061704
1607 if (try parseWhileTypeExpr(arena, it, tree)) |node| {
1608 node.cast(Node.While).?.inline_token = inline_token;
1609 return node;
1610 }
1705 if (p.eatToken(.Keyword_else)) |else_token| {
1706 const else_expr = try p.expectNode(parseTypeExpr, .{
1707 .ExpectedTypeExpr = .{ .token = p.tok_i },
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"
1615 try tree.errors.push(.{
1616 .ExpectedInlinable = .{ .token = it.index },
1617 });
1618 return error.ParseError;
1619}
1717 for_prefix.@"else" = else_node;
1718 }
16201719
1621/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
1622fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1623 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1624 const for_prefix = node.cast(Node.For).?;
1720 return node;
1721 }
16251722
1626 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1627 .ExpectedTypeExpr = .{ .token = it.index },
1628 });
1629 for_prefix.body = type_expr;
1723 /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1724 fn parseWhileTypeExpr(p: *Parser) !?*Node {
1725 const node = (try p.parseWhilePrefix()) orelse return null;
1726 const while_prefix = node.cast(Node.While).?;
16301727
1631 if (eatToken(it, .Keyword_else)) |else_token| {
1632 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1633 .ExpectedTypeExpr = .{ .token = it.index },
1728 const type_expr = try p.expectNode(parseTypeExpr, .{
1729 .ExpectedTypeExpr = .{ .token = p.tok_i },
16341730 });
1731 while_prefix.body = type_expr;
16351732
1636 const else_node = try arena.create(Node.Else);
1637 else_node.* = .{
1638 .else_token = else_token,
1639 .payload = null,
1640 .body = else_expr,
1641 };
1642
1643 for_prefix.@"else" = else_node;
1644 }
1733 if (p.eatToken(.Keyword_else)) |else_token| {
1734 const payload = try p.parsePayload();
16451735
1646 return node;
1647}
1736 const else_expr = try p.expectNode(parseTypeExpr, .{
1737 .ExpectedTypeExpr = .{ .token = p.tok_i },
1738 });
16481739
1649/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1650fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1651 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1652 const while_prefix = node.cast(Node.While).?;
1740 const else_node = try p.arena.allocator.create(Node.Else);
1741 else_node.* = .{
1742 .else_token = else_token,
1743 .payload = null,
1744 .body = else_expr,
1745 };
16531746
1654 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1655 .ExpectedTypeExpr = .{ .token = it.index },
1656 });
1657 while_prefix.body = type_expr;
1747 while_prefix.@"else" = else_node;
1748 }
16581749
1659 if (eatToken(it, .Keyword_else)) |else_token| {
1660 const payload = try parsePayload(arena, it, tree);
1750 return node;
1751 }
16611752
1662 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1663 .ExpectedTypeExpr = .{ .token = it.index },
1753 /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
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 },
16641759 });
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);
1667 else_node.* = .{
1668 .else_token = else_token,
1669 .payload = null,
1670 .body = else_expr,
1766 const node = try Node.Switch.alloc(&p.arena.allocator, cases.len);
1767 node.* = .{
1768 .switch_token = switch_token,
1769 .expr = expr_node,
1770 .cases_len = cases.len,
1771 .rbrace = rbrace,
16711772 };
1672
1673 while_prefix.@"else" = else_node;
1773 std.mem.copy(*Node, node.cases(), cases);
1774 return &node.base;
16741775 }
16751776
1676 return node;
1677}
1777 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
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 RBRACE
1680fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1681 const switch_token = eatToken(it, .Keyword_switch) orelse return null;
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}
1790 var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{};
1791 var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{};
1792 var arena_clobbers: []*Node = &[0]*Node{};
17001793
1701/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1702fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1703 const asm_token = eatToken(it, .Keyword_asm) orelse return null;
1704 const volatile_token = eatToken(it, .Keyword_volatile);
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 };
1794 if (p.eatToken(.Colon) != null) {
1795 const outputs = try p.parseAsmOutputList();
1796 defer p.gpa.free(outputs);
1797 arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs);
17201798
1721 try parseAsmOutput(arena, it, tree, node);
1722 node.rparen = try expectToken(it, tree, .RParen);
1723 return &node.base;
1724}
1799 if (p.eatToken(.Colon) != null) {
1800 const inputs = try p.parseAsmInputList();
1801 defer p.gpa.free(inputs);
1802 arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs);
17251803
1726/// DOT IDENTIFIER
1727fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1728 const dot = eatToken(it, .Period) orelse return null;
1804 if (p.eatToken(.Colon) != null) {
1805 const clobbers = try ListParseFn(*Node, parseStringLiteral)(p);
1806 defer p.gpa.free(clobbers);
1807 arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers);
1808 }
1809 }
1810 }
17291811
1730 // anon enum literal
1731 if (eatToken(it, .Identifier)) |name| {
1732 const node = try arena.create(Node.EnumLiteral);
1812 const node = try p.arena.allocator.create(Node.Asm);
17331813 node.* = .{
1734 .dot = dot,
1735 .name = name,
1814 .asm_token = asm_token,
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),
17361821 };
1737 return &node.base;
1738 }
17391822
1740 // anon container literal
1741 if (try parseInitList(arena, it, tree)) |node| {
1742 node.lhs = .{ .dot = dot };
17431823 return &node.base;
17441824 }
17451825
1746 putBackToken(it, dot);
1747 return null;
1748}
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}
1826 /// DOT IDENTIFIER
1827 fn parseAnonLiteral(p: *Parser) !?*Node {
1828 const dot = p.eatToken(.Period) orelse return null;
17561829
1757/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1758fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput {
1759 const lbracket = eatToken(it, .LBracket) orelse return null;
1760 const name = try expectNode(arena, it, tree, parseIdentifier, .{
1761 .ExpectedIdentifier = .{ .token = it.index },
1762 });
1763 _ = try expectToken(it, tree, .RBracket);
1764
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 };
1830 // anon enum literal
1831 if (p.eatToken(.Identifier)) |name| {
1832 const node = try p.arena.allocator.create(Node.EnumLiteral);
1833 node.* = .{
1834 .dot = dot,
1835 .name = name,
1836 };
1837 return &node.base;
17761838 }
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?
1796fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1797 if (eatToken(it, .Colon) == null) return;
1798 asm_node.inputs = try parseAsmInputList(arena, it, tree);
1799 try parseAsmClobbers(arena, it, tree, asm_node);
1800}
1840 if (try p.parseAnonInitList(dot)) |node| {
1841 return node;
1842 }
18011843
1802/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1803fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {
1804 const lbracket = eatToken(it, .LBracket) orelse return null;
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}
1844 p.putBackToken(dot);
1845 return null;
1846 }
18301847
1831/// AsmClobbers <- COLON StringList
1832/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
1833fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1834 if (eatToken(it, .Colon) == null) return;
1835 asm_node.clobbers = try ListParseFn(
1836 Node.Asm.ClobberList,
1837 parseStringLiteral,
1838 )(arena, it, tree);
1839}
1848 /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1849 fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output {
1850 const lbracket = p.eatToken(.LBracket) orelse return null;
1851 const name = try p.expectNode(parseIdentifier, .{
1852 .ExpectedIdentifier = .{ .token = p.tok_i },
1853 });
1854 _ = try p.expectToken(.RBracket);
18401855
1841/// BreakLabel <- COLON IDENTIFIER
1842fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1843 _ = eatToken(it, .Colon) orelse return null;
1844 return try expectNode(arena, it, tree, parseIdentifier, .{
1845 .ExpectedIdentifier = .{ .token = it.index },
1846 });
1847}
1856 const constraint = try p.expectNode(parseStringLiteral, .{
1857 .ExpectedStringLiteral = .{ .token = p.tok_i },
1858 });
18481859
1849/// BlockLabel <- IDENTIFIER COLON
1850fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree, colon_token: *TokenIndex) ?TokenIndex {
1851 const identifier = eatToken(it, .Identifier) orelse return null;
1852 if (eatToken(it, .Colon)) |colon| {
1853 colon_token.* = colon;
1854 return identifier;
1860 _ = try p.expectToken(.LParen);
1861 const kind: Node.Asm.Output.Kind = blk: {
1862 if (p.eatToken(.Arrow) != null) {
1863 const return_ident = try p.expectNode(parseTypeExpr, .{
1864 .ExpectedTypeExpr = .{ .token = p.tok_i },
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 };
18551882 }
1856 putBackToken(it, identifier);
1857 return null;
1858}
18591883
1860/// FieldInit <- DOT IDENTIFIER EQUAL Expr
1861fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1862 const period_token = eatToken(it, .Period) orelse return null;
1863 const name_token = eatToken(it, .Identifier) orelse {
1864 // Because of anon literals `.{` is also valid.
1865 putBackToken(it, period_token);
1866 return null;
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}
1884 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1885 fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
1886 const lbracket = p.eatToken(.LBracket) orelse return null;
1887 const name = try p.expectNode(parseIdentifier, .{
1888 .ExpectedIdentifier = .{ .token = p.tok_i },
1889 });
1890 _ = try p.expectToken(.RBracket);
18861891
1887/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
1888fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1889 _ = eatToken(it, .Colon) orelse return null;
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}
1892 const constraint = try p.expectNode(parseStringLiteral, .{
1893 .ExpectedStringLiteral = .{ .token = p.tok_i },
1894 });
18971895
1898/// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
1899fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1900 _ = eatToken(it, .Keyword_linksection) orelse return null;
1901 _ = try expectToken(it, tree, .LParen);
1902 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1903 .ExpectedExpr = .{ .token = it.index },
1904 });
1905 _ = try expectToken(it, tree, .RParen);
1906 return expr_node;
1907}
1896 _ = try p.expectToken(.LParen);
1897 const expr = try p.expectNode(parseExpr, .{
1898 .ExpectedExpr = .{ .token = p.tok_i },
1899 });
1900 const rparen = try p.expectToken(.RParen);
19081901
1909/// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
1910fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1911 _ = eatToken(it, .Keyword_callconv) orelse return null;
1912 _ = try expectToken(it, tree, .LParen);
1913 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1914 .ExpectedExpr = .{ .token = it.index },
1915 });
1916 _ = try expectToken(it, tree, .RParen);
1917 return expr_node;
1918}
1902 return Node.Asm.Input{
1903 .lbracket = lbracket,
1904 .symbolic_name = name,
1905 .constraint = constraint,
1906 .expr = expr,
1907 .rparen = rparen,
1908 };
1909 }
19191910
1920/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
1921fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1922 const doc_comments = try parseDocComment(arena, it, tree);
1923 const noalias_token = eatToken(it, .Keyword_noalias);
1924 const comptime_token = if (noalias_token == null) eatToken(it, .Keyword_comptime) else null;
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 },
1911 /// BreakLabel <- COLON IDENTIFIER
1912 fn parseBreakLabel(p: *Parser) !?*Node {
1913 _ = p.eatToken(.Colon) orelse return null;
1914 return p.expectNode(parseIdentifier, .{
1915 .ExpectedIdentifier = .{ .token = p.tok_i },
19391916 });
1940 return error.ParseError;
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}
1917 }
19531918
1954/// ParamType
1955/// <- KEYWORD_var
1956/// / DOT3
1957/// / TypeExpr
1958fn parseParamType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?Node.ParamDecl.ParamType {
1959 // TODO cast from tuple to error union is broken
1960 const P = Node.ParamDecl.ParamType;
1961 if (try parseVarType(arena, it, tree)) |node| return P{ .var_type = node };
1962 if (eatToken(it, .Ellipsis3)) |token| return P{ .var_args = token };
1963 if (try parseTypeExpr(arena, it, tree)) |node| return P{ .type_expr = node };
1964 return null;
1965}
1919 /// BlockLabel <- IDENTIFIER COLON
1920 fn parseBlockLabel(p: *Parser, colon_token: *TokenIndex) ?TokenIndex {
1921 const identifier = p.eatToken(.Identifier) orelse return null;
1922 if (p.eatToken(.Colon)) |colon| {
1923 colon_token.* = colon;
1924 return identifier;
1925 }
1926 p.putBackToken(identifier);
1927 return null;
1928 }
19661929
1967/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
1968fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1969 const if_token = eatToken(it, .Keyword_if) orelse return null;
1970 _ = try expectToken(it, tree, .LParen);
1971 const condition = try expectNode(arena, it, tree, parseExpr, .{
1972 .ExpectedExpr = .{ .token = it.index },
1973 });
1974 _ = try expectToken(it, tree, .RParen);
1975 const payload = try parsePtrPayload(arena, it, tree);
1976
1977 const node = try arena.create(Node.If);
1978 node.* = .{
1979 .if_token = if_token,
1980 .condition = condition,
1981 .payload = payload,
1982 .body = undefined, // set by caller
1983 .@"else" = null,
1984 };
1985 return &node.base;
1986}
1930 /// FieldInit <- DOT IDENTIFIER EQUAL Expr
1931 fn parseFieldInit(p: *Parser) !?*Node {
1932 const period_token = p.eatToken(.Period) orelse return null;
1933 const name_token = p.eatToken(.Identifier) orelse {
1934 // Because of anon literals `.{` is also valid.
1935 p.putBackToken(period_token);
1936 return null;
1937 };
1938 const eq_token = p.eatToken(.Equal) orelse {
1939 // `.Name` may also be an enum literal, which is a later rule.
1940 p.putBackToken(name_token);
1941 p.putBackToken(period_token);
1942 return null;
1943 };
1944 const expr_node = try p.expectNode(parseExpr, .{
1945 .ExpectedExpr = .{ .token = p.tok_i },
1946 });
19871947
1988/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
1989fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1990 const while_token = eatToken(it, .Keyword_while) orelse return null;
1991
1992 _ = try expectToken(it, tree, .LParen);
1993 const condition = try expectNode(arena, it, tree, parseExpr, .{
1994 .ExpectedExpr = .{ .token = it.index },
1995 });
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}
1948 const node = try p.arena.allocator.create(Node.FieldInitializer);
1949 node.* = .{
1950 .period_token = period_token,
1951 .name_token = name_token,
1952 .expr = expr_node,
1953 };
1954 return &node.base;
1955 }
20141956
2015/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2016fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2017 const for_token = eatToken(it, .Keyword_for) orelse return null;
2018
2019 _ = try expectToken(it, tree, .LParen);
2020 const array_expr = try expectNode(arena, it, tree, parseExpr, .{
2021 .ExpectedExpr = .{ .token = it.index },
2022 });
2023 _ = try expectToken(it, tree, .RParen);
2024
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}
1957 /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
1958 fn parseWhileContinueExpr(p: *Parser) !?*Node {
1959 _ = p.eatToken(.Colon) orelse return null;
1960 _ = try p.expectToken(.LParen);
1961 const node = try p.expectNode(parseAssignExpr, .{
1962 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
1963 });
1964 _ = try p.expectToken(.RParen);
1965 return node;
1966 }
20411967
2042/// Payload <- PIPE IDENTIFIER PIPE
2043fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2044 const lpipe = eatToken(it, .Pipe) orelse return null;
2045 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
2046 .ExpectedIdentifier = .{ .token = it.index },
2047 });
2048 const rpipe = try expectToken(it, tree, .Pipe);
2049
2050 const node = try arena.create(Node.Payload);
2051 node.* = .{
2052 .lpipe = lpipe,
2053 .error_symbol = identifier,
2054 .rpipe = rpipe,
2055 };
2056 return &node.base;
2057}
1968 /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
1969 fn parseLinkSection(p: *Parser) !?*Node {
1970 _ = p.eatToken(.Keyword_linksection) orelse return null;
1971 _ = try p.expectToken(.LParen);
1972 const expr_node = try p.expectNode(parseExpr, .{
1973 .ExpectedExpr = .{ .token = p.tok_i },
1974 });
1975 _ = try p.expectToken(.RParen);
1976 return expr_node;
1977 }
20581978
2059/// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
2060fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2061 const lpipe = eatToken(it, .Pipe) orelse return null;
2062 const asterisk = eatToken(it, .Asterisk);
2063 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
2064 .ExpectedIdentifier = .{ .token = it.index },
2065 });
2066 const rpipe = try expectToken(it, tree, .Pipe);
2067
2068 const node = try arena.create(Node.PointerPayload);
2069 node.* = .{
2070 .lpipe = lpipe,
2071 .ptr_token = asterisk,
2072 .value_symbol = identifier,
2073 .rpipe = rpipe,
2074 };
2075 return &node.base;
2076}
1979 /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
1980 fn parseCallconv(p: *Parser) !?*Node {
1981 _ = p.eatToken(.Keyword_callconv) orelse return null;
1982 _ = try p.expectToken(.LParen);
1983 const expr_node = try p.expectNode(parseExpr, .{
1984 .ExpectedExpr = .{ .token = p.tok_i },
1985 });
1986 _ = try p.expectToken(.RParen);
1987 return expr_node;
1988 }
1989
1990 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
1991 fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl {
1992 const doc_comments = try p.parseDocComment();
1993 const noalias_token = p.eatToken(.Keyword_noalias);
1994 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
1995 const name_token = blk: {
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)? PIPE
2079fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2080 const lpipe = eatToken(it, .Pipe) orelse return null;
2081 const asterisk = eatToken(it, .Asterisk);
2082 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
2083 .ExpectedIdentifier = .{ .token = it.index },
2084 });
2085
2086 const index = if (eatToken(it, .Comma) == null)
2087 null
2088 else
2089 try expectNode(arena, it, tree, parseIdentifier, .{
2090 .ExpectedIdentifier = .{ .token = it.index },
2016 return Node.FnProto.ParamDecl{
2017 .doc_comments = doc_comments,
2018 .comptime_token = comptime_token,
2019 .noalias_token = noalias_token,
2020 .name_token = name_token,
2021 .param_type = param_type,
2022 };
2023 }
2024
2025 /// ParamType
2026 /// <- KEYWORD_var
2027 /// / DOT3
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 },
20912044 });
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);
2096 node.* = .{
2097 .lpipe = lpipe,
2098 .ptr_token = asterisk,
2099 .value_symbol = identifier,
2100 .index_symbol = index,
2101 .rpipe = rpipe,
2102 };
2103 return &node.base;
2104}
2059 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2060 fn parseWhilePrefix(p: *Parser) !?*Node {
2061 const while_token = p.eatToken(.Keyword_while) orelse return null;
21052062
2106/// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
2107fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2108 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;
2109 const arrow = try expectToken(it, tree, .EqualAngleBracketRight);
2110 const payload = try parsePtrPayload(arena, it, tree);
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}
2063 _ = try p.expectToken(.LParen);
2064 const condition = try p.expectNode(parseExpr, .{
2065 .ExpectedExpr = .{ .token = p.tok_i },
2066 });
2067 _ = try p.expectToken(.RParen);
21222068
2123/// SwitchCase
2124/// <- SwitchItem (COMMA SwitchItem)* COMMA?
2125/// / KEYWORD_else
2126fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2127 var list = Node.SwitchCase.ItemList.init(arena);
2069 const payload = try p.parsePtrPayload();
2070 const continue_expr = try p.parseWhileContinueExpr();
21282071
2129 if (try parseSwitchItem(arena, it, tree)) |first_item| {
2130 try list.push(first_item);
2131 while (eatToken(it, .Comma) != null) {
2132 const next_item = (try parseSwitchItem(arena, it, tree)) orelse break;
2133 try list.push(next_item);
2134 }
2135 } else if (eatToken(it, .Keyword_else)) |else_token| {
2136 const else_node = try arena.create(Node.SwitchElse);
2137 else_node.* = .{
2138 .token = else_token,
2072 const node = try p.arena.allocator.create(Node.While);
2073 node.* = .{
2074 .label = null,
2075 .inline_token = null,
2076 .while_token = while_token,
2077 .condition = condition,
2078 .payload = payload,
2079 .continue_expr = continue_expr,
2080 .body = undefined, // set by caller
2081 .@"else" = null,
21392082 };
2140 try list.push(&else_node.base);
2141 } else return null;
2083 return &node.base;
2084 }
21422085
2143 const node = try arena.create(Node.SwitchCase);
2144 node.* = .{
2145 .items = list,
2146 .arrow_token = undefined, // set by caller
2147 .payload = null,
2148 .expr = undefined, // set by caller
2149 };
2150 return &node.base;
2151}
2086 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2087 fn parseForPrefix(p: *Parser) !?*Node {
2088 const for_token = p.eatToken(.Keyword_for) orelse return null;
21522089
2153/// SwitchItem <- Expr (DOT3 Expr)?
2154fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2155 const expr = (try parseExpr(arena, it, tree)) orelse return null;
2156 if (eatToken(it, .Ellipsis3)) |token| {
2157 const range_end = try expectNode(arena, it, tree, parseExpr, .{
2158 .ExpectedExpr = .{ .token = it.index },
2090 _ = try p.expectToken(.LParen);
2091 const array_expr = try p.expectNode(parseExpr, .{
2092 .ExpectedExpr = .{ .token = p.tok_i },
21592093 });
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);
21622101 node.* = .{
2163 .op_token = token,
2164 .lhs = expr,
2165 .op = .Range,
2166 .rhs = range_end,
2102 .label = null,
2103 .inline_token = null,
2104 .for_token = for_token,
2105 .array_expr = array_expr,
2106 .payload = payload,
2107 .body = undefined, // set by caller
2108 .@"else" = null,
21672109 };
21682110 return &node.base;
21692111 }
2170 return expr;
2171}
21722112
2173/// AssignOp
2174/// <- ASTERISKEQUAL
2175/// / SLASHEQUAL
2176/// / PERCENTEQUAL
2177/// / PLUSEQUAL
2178/// / MINUSEQUAL
2179/// / LARROW2EQUAL
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 };
2113 /// Payload <- PIPE IDENTIFIER PIPE
2114 fn parsePayload(p: *Parser) !?*Node {
2115 const lpipe = p.eatToken(.Pipe) orelse return null;
2116 const identifier = try p.expectNode(parseIdentifier, .{
2117 .ExpectedIdentifier = .{ .token = p.tok_i },
2118 });
2119 const rpipe = try p.expectToken(.Pipe);
22102120
2211 const node = try arena.create(Node.InfixOp);
2212 node.* = .{
2213 .op_token = token.index,
2214 .lhs = undefined, // set by caller
2215 .op = op,
2216 .rhs = undefined, // set by caller
2217 };
2218 return &node.base;
2219}
2121 const node = try p.arena.allocator.create(Node.Payload);
2122 node.* = .{
2123 .lpipe = lpipe,
2124 .error_symbol = identifier,
2125 .rpipe = rpipe,
2126 };
2127 return &node.base;
2128 }
22202129
2221/// CompareOp
2222/// <- EQUALEQUAL
2223/// / EXCLAMATIONMARKEQUAL
2224/// / LARROW
2225/// / RARROW
2226/// / LARROWEQUAL
2227/// / RARROWEQUAL
2228fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
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 };
2130 /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
2131 fn parsePtrPayload(p: *Parser) !?*Node {
2132 const lpipe = p.eatToken(.Pipe) orelse return null;
2133 const asterisk = p.eatToken(.Asterisk);
2134 const identifier = try p.expectNode(parseIdentifier, .{
2135 .ExpectedIdentifier = .{ .token = p.tok_i },
2136 });
2137 const rpipe = try p.expectToken(.Pipe);
22422138
2243 return try createInfixOp(arena, token.index, op);
2244}
2139 const node = try p.arena.allocator.create(Node.PointerPayload);
2140 node.* = .{
2141 .lpipe = lpipe,
2142 .ptr_token = asterisk,
2143 .value_symbol = identifier,
2144 .rpipe = rpipe,
2145 };
2146 return &node.base;
2147 }
22452148
2246/// BitwiseOp
2247/// <- AMPERSAND
2248/// / CARET
2249/// / PIPE
2250/// / KEYWORD_orelse
2251/// / KEYWORD_catch Payload?
2252fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
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 };
2149 /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
2150 fn parsePtrIndexPayload(p: *Parser) !?*Node {
2151 const lpipe = p.eatToken(.Pipe) orelse return null;
2152 const asterisk = p.eatToken(.Asterisk);
2153 const identifier = try p.expectNode(parseIdentifier, .{
2154 .ExpectedIdentifier = .{ .token = p.tok_i },
2155 });
22652156
2266 return try createInfixOp(arena, token.index, op);
2267}
2157 const index = if (p.eatToken(.Comma) == null)
2158 null
2159 else
2160 try p.expectNode(parseIdentifier, .{
2161 .ExpectedIdentifier = .{ .token = p.tok_i },
2162 });
22682163
2269/// BitShiftOp
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 };
2164 const rpipe = try p.expectToken(.Pipe);
22822165
2283 return try createInfixOp(arena, token.index, op);
2284}
2166 const node = try p.arena.allocator.create(Node.PointerIndexPayload);
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/// AdditionOp
2287/// <- PLUS
2288/// / MINUS
2289/// / PLUS2
2290/// / PLUSPERCENT
2291/// / MINUSPERCENT
2292fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2293 const token = nextToken(it);
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 };
2177 /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
2178 fn parseSwitchProng(p: *Parser) !?*Node {
2179 const node = (try p.parseSwitchCase()) orelse return null;
2180 const arrow = try p.expectToken(.EqualAngleBracketRight);
2181 const payload = try p.parsePtrPayload();
2182 const expr = try p.expectNode(parseAssignExpr, .{
2183 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
2184 });
23052185
2306 return try createInfixOp(arena, token.index, op);
2307}
2186 const switch_case = node.cast(Node.SwitchCase).?;
2187 switch_case.arrow_token = arrow;
2188 switch_case.payload = payload;
2189 switch_case.expr = expr;
23082190
2309/// MultiplyOp
2310/// <- PIPE2
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 };
2191 return node;
2192 }
23302193
2331 return try createInfixOp(arena, token.index, op);
2332}
2194 /// SwitchCase
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/// PrefixOp
2335/// <- EXCLAMATIONMARK
2336/// / MINUS
2337/// / TILDE
2338/// / MINUSPERCENT
2339/// / AMPERSAND
2340/// / KEYWORD_try
2341/// / KEYWORD_await
2342fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2343 const token = nextToken(it);
2344 const op: Node.PrefixOp.Op = switch (token.ptr.id) {
2345 .Bang => .BoolNot,
2346 .Minus => .Negation,
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 };
2201 if (try p.parseSwitchItem()) |first_item| {
2202 try list.append(first_item);
2203 while (p.eatToken(.Comma) != null) {
2204 const next_item = (try p.parseSwitchItem()) orelse break;
2205 try list.append(next_item);
2206 }
2207 } else if (p.eatToken(.Keyword_else)) |else_token| {
2208 const else_node = try p.arena.allocator.create(Node.SwitchElse);
2209 else_node.* = .{
2210 .token = else_token,
2211 };
2212 try list.append(&else_node.base);
2213 } else return null;
23572214
2358 const node = try arena.create(Node.PrefixOp);
2359 node.* = .{
2360 .op_token = token.index,
2361 .op = op,
2362 .rhs = undefined, // set by caller
2363 };
2364 return &node.base;
2365}
2215 const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len);
2216 node.* = .{
2217 .items_len = list.items.len,
2218 .arrow_token = undefined, // set by caller
2219 .payload = null,
2220 .expr = undefined, // set by caller
2221 };
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 on
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);
2284 const node = try p.arena.allocator.create(Node.InfixOp);
23822285 node.* = .{
23832286 .op_token = token,
2384 .op = .OptionalType,
2287 .lhs = undefined, // set by caller
2288 .op = op,
23852289 .rhs = undefined, // set by caller
23862290 };
23872291 return &node.base;
23882292 }
23892293
2390 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2391 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2392 // Consider making the AnyFrameType a member of PrefixOp and add a
2393 // PrefixOp.AnyFrameType variant?
2394 if (eatToken(it, .Keyword_anyframe)) |token| {
2395 const arrow = eatToken(it, .Arrow) orelse {
2396 putBackToken(it, token);
2397 return null;
2294 /// CompareOp
2295 /// <- EQUALEQUAL
2296 /// / EXCLAMATIONMARKEQUAL
2297 /// / LARROW
2298 /// / RARROW
2299 /// / LARROWEQUAL
2300 /// / RARROWEQUAL
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 },
23982314 };
2399 const node = try arena.create(Node.AnyFrameType);
2400 node.* = .{
2401 .anyframe_token = token,
2402 .result = .{
2403 .arrow_token = arrow,
2404 .return_type = undefined, // set by caller
2315
2316 return p.createInfixOp(token, op);
2317 }
2318
2319 /// BitwiseOp
2320 /// <- 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;
24052336 },
24062337 };
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 };
24072437 return &node.base;
24082438 }
24092439
2410 if (try parsePtrTypeStart(arena, it, tree)) |node| {
2411 // If the token encountered was **, there will be two nodes instead of one.
2412 // The attributes should be applied to the rightmost operator.
2413 const prefix_op = node.cast(Node.PrefixOp).?;
2414 var ptr_info = if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk)
2415 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2416 else
2417 &prefix_op.op.PtrType;
2440 // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
2441 // pointers. Consider updating this rule:
2442 // ...
2443 // / ArrayTypeStart
2444 // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2445 // / PtrTypeStart ...
2446
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) {
2420 if (eatToken(it, .Keyword_align)) |align_token| {
2421 const lparen = try expectToken(it, tree, .LParen);
2422 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
2423 .ExpectedExpr = .{ .token = it.index },
2424 });
2463 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2464 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2465 // Consider making the AnyFrameType a member of PrefixOp and add a
2466 // PrefixOp.AnyFrameType variant?
2467 if (p.eatToken(.Keyword_anyframe)) |token| {
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 range
2427 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {
2428 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{
2429 .ExpectedIntegerLiteral = .{ .token = it.index },
2430 });
2431 _ = try expectToken(it, tree, .Colon);
2432 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{
2433 .ExpectedIntegerLiteral = .{ .token = it.index },
2483 if (try p.parsePtrTypeStart()) |node| {
2484 // If the token encountered was **, there will be two nodes instead of one.
2485 // The attributes should be applied to the rightmost operator.
2486 const prefix_op = node.cast(Node.PrefixOp).?;
2487 var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)
2488 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2489 else
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 },
24342497 });
24352498
2436 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
2437 .start = range_start,
2438 .end = range_end,
2499 // Optional bit range
2500 const bit_range = if (p.eatToken(.Colon)) |_| bit_range_value: {
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,
24392526 };
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 });
24472528 continue;
24482529 }
2449
2450 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
2451 .node = expr_node,
2452 .bit_range = bit_range,
2453 };
2454
2455 continue;
2456 }
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 });
2530 if (p.eatToken(.Keyword_const)) |const_token| {
2531 if (ptr_info.const_token != null) {
2532 try p.errors.append(p.gpa, .{
2533 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2534 });
2535 continue;
2536 }
2537 ptr_info.const_token = const_token;
24622538 continue;
24632539 }
2464 ptr_info.const_token = const_token;
2465 continue;
2466 }
2467 if (eatToken(it, .Keyword_volatile)) |volatile_token| {
2468 if (ptr_info.volatile_token != null) {
2469 try tree.errors.push(.{
2470 .ExtraVolatileQualifier = .{ .token = it.index - 1 },
2471 });
2540 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2541 if (ptr_info.volatile_token != null) {
2542 try p.errors.append(p.gpa, .{
2543 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2544 });
2545 continue;
2546 }
2547 ptr_info.volatile_token = volatile_token;
24722548 continue;
24732549 }
2474 ptr_info.volatile_token = volatile_token;
2475 continue;
2476 }
2477 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
2478 if (ptr_info.allowzero_token != null) {
2479 try tree.errors.push(.{
2480 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },
2481 });
2550 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2551 if (ptr_info.allowzero_token != null) {
2552 try p.errors.append(p.gpa, .{
2553 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2554 });
2555 continue;
2556 }
2557 ptr_info.allowzero_token = allowzero_token;
24822558 continue;
24832559 }
2484 ptr_info.allowzero_token = allowzero_token;
2485 continue;
2560 break;
24862561 }
2487 break;
2488 }
24892562
2490 return node;
2491 }
2563 return node;
2564 }
24922565
2493 if (try parseArrayTypeStart(arena, it, tree)) |node| {
2494 switch (node.cast(Node.PrefixOp).?.op) {
2495 .ArrayType => {},
2496 .SliceType => |*slice_type| {
2497 // Collect pointer qualifiers in any order, but disallow duplicates
2498 while (true) {
2499 if (try parseByteAlign(arena, it, tree)) |align_expr| {
2500 if (slice_type.align_info != null) {
2501 try tree.errors.push(.{
2502 .ExtraAlignQualifier = .{ .token = it.index - 1 },
2503 });
2566 if (try p.parseArrayTypeStart()) |node| {
2567 switch (node.cast(Node.PrefixOp).?.op) {
2568 .ArrayType => {},
2569 .SliceType => |*slice_type| {
2570 // Collect pointer qualifiers in any order, but disallow duplicates
2571 while (true) {
2572 if (try p.parseByteAlign()) |align_expr| {
2573 if (slice_type.align_info != null) {
2574 try p.errors.append(p.gpa, .{
2575 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2576 });
2577 continue;
2578 }
2579 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2580 .node = align_expr,
2581 .bit_range = null,
2582 };
25042583 continue;
25052584 }
2506 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2507 .node = align_expr,
2508 .bit_range = null,
2509 };
2510 continue;
2511 }
2512 if (eatToken(it, .Keyword_const)) |const_token| {
2513 if (slice_type.const_token != null) {
2514 try tree.errors.push(.{
2515 .ExtraConstQualifier = .{ .token = it.index - 1 },
2516 });
2585 if (p.eatToken(.Keyword_const)) |const_token| {
2586 if (slice_type.const_token != null) {
2587 try p.errors.append(p.gpa, .{
2588 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2589 });
2590 continue;
2591 }
2592 slice_type.const_token = const_token;
25172593 continue;
25182594 }
2519 slice_type.const_token = const_token;
2520 continue;
2521 }
2522 if (eatToken(it, .Keyword_volatile)) |volatile_token| {
2523 if (slice_type.volatile_token != null) {
2524 try tree.errors.push(.{
2525 .ExtraVolatileQualifier = .{ .token = it.index - 1 },
2526 });
2595 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2596 if (slice_type.volatile_token != null) {
2597 try p.errors.append(p.gpa, .{
2598 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2599 });
2600 continue;
2601 }
2602 slice_type.volatile_token = volatile_token;
25272603 continue;
25282604 }
2529 slice_type.volatile_token = volatile_token;
2530 continue;
2605 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
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;
25312616 }
2532 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
2533 if (slice_type.allowzero_token != null) {
2534 try tree.errors.push(.{
2535 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },
2617 },
2618 else => unreachable,
2619 }
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 },
25362892 });
2537 continue;
2893 _ = try p.expectToken(.RParen);
2894 _ = try p.expectToken(.RParen);
2895 break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
25382896 }
2539 slice_type.allowzero_token = allowzero_token;
2540 continue;
2897 _ = try p.expectToken(.RParen);
2898 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
25412899 }
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 };
25432905 }
2906 break :blk Node.ContainerDecl.InitArg{ .None = {} };
25442907 },
2545 else => unreachable,
2546 }
2547 return node;
2908 else => {
2909 p.putBackToken(kind_token);
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);
25482935 }
25492936
2550 return null;
2551}
2937 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2938 fn parseSwitchProngList(p: *Parser) ![]*Node {
2939 return ListParseFn(*Node, parseSwitchProng)(p);
2940 }
25522941
2553/// SuffixOp
2554/// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
2555/// / DOT IDENTIFIER
2556/// / DOTASTERISK
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 });
2942 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2943 fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
2944 return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
2945 }
25682946
2569 if (eatToken(it, .Ellipsis2) != null) {
2570 const end_expr = try parseExpr(arena, it, tree);
2571 const sentinel: ?*ast.Node = if (eatToken(it, .Colon) != null)
2572 try parseExpr(arena, it, tree)
2573 else
2574 null;
2575 break :blk .{
2576 .op = .{
2577 .Slice = .{
2578 .start = index_expr,
2579 .end = end_expr,
2580 .sentinel = sentinel,
2947 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2948 fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
2949 return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
2950 }
2951
2952 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2953 fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
2954 return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
2955 }
2956
2957 const NodeParseFn = fn (p: *Parser) Error!?*Node;
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 });
25812978 },
2582 },
2583 .token = try expectToken(it, tree, .RBracket),
2584 };
2979 }
2980 }
2981 return list.toOwnedSlice();
25852982 }
2983 }.parse;
2984 }
25862985
2587 break :blk .{
2588 .op = .{ .ArrayAccess = index_expr },
2589 .token = try expectToken(it, tree, .RBracket),
2590 };
2591 }
2592
2593 if (eatToken(it, .PeriodAsterisk)) |period_asterisk| {
2594 break :blk .{ .op = .Deref, .token = period_asterisk };
2595 }
2986 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
2987 return struct {
2988 pub fn parse(p: *Parser) Error!?*Node {
2989 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
2990 .Keyword_and => p.nextToken(),
2991 .Invalid_ampersands => blk: {
2992 try p.errors.append(p.gpa, .{
2993 .InvalidAnd = .{ .token = p.tok_i },
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| {
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);
3000 const node = try p.arena.allocator.create(Node.InfixOp);
26033001 node.* = .{
2604 .op_token = period,
3002 .op_token = op_token,
26053003 .lhs = undefined, // set by caller
2606 .op = .Period,
2607 .rhs = identifier,
3004 .op = op,
3005 .rhs = undefined, // set by caller
26083006 };
26093007 return &node.base;
26103008 }
2611 if (eatToken(it, .QuestionMark)) |question_mark| {
2612 break :blk .{ .op = .UnwrapOptional, .token = question_mark };
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}
3009 }.parse;
3010 }
26313011
2632/// FnCallArguments <- LPAREN ExprList RPAREN
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}
3012 // Helper parsers not included in the grammar
26403013
2641const AnnotatedParamList = struct {
2642 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)
2643 rparen: TokenIndex,
2644};
3014 fn parseBuiltinCall(p: *Parser) !?*Node {
3015 const token = p.eatToken(.Builtin) orelse return null;
3016 const params = (try p.parseFnCallArguments()) orelse {
3017 try p.errors.append(p.gpa, .{
3018 .ExpectedParamList = .{ .token = p.tok_i },
3019 });
26453020
2646/// ArrayTypeStart <- LBRACKET Expr? RBRACKET
2647fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2648 const lbracket = eatToken(it, .LBracket) orelse return null;
2649 const expr = try parseExpr(arena, it, tree);
2650 const sentinel = if (eatToken(it, .Colon)) |_|
2651 try expectNode(arena, it, tree, parseExpr, .{
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 },
3021 // lets pretend this was an identifier so we can continue parsing
3022 const node = try p.arena.allocator.create(Node.Identifier);
3023 node.* = .{
3024 .token = token,
3025 };
3026 return &node.base;
26743027 };
3028 defer p.gpa.free(params.list);
26753029
2676 const node = try arena.create(Node.PrefixOp);
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);
3030 const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len);
26993031 node.* = .{
2700 .op_token = asterisk,
2701 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2702 .rhs = undefined, // set by caller
3032 .builtin_token = token,
3033 .params_len = params.list.len,
3034 .rparen_token = params.rparen,
27033035 };
3036 std.mem.copy(*Node, node.params(), params.list);
27043037 return &node.base;
27053038 }
27063039
2707 if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| {
2708 const node = try arena.create(Node.PrefixOp);
3040 fn parseErrorTag(p: *Parser) !?*Node {
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);
27093045 node.* = .{
2710 .op_token = double_asterisk,
2711 .op = .{ .PtrType = .{} },
2712 .rhs = undefined, // set by caller
3046 .doc_comments = doc_comments,
3047 .name_token = token,
27133048 };
3049 return &node.base;
3050 }
27143051
2715 // Special case for **, which is its own token
2716 const child = try arena.create(Node.PrefixOp);
2717 child.* = .{
2718 .op_token = double_asterisk,
2719 .op = .{ .PtrType = .{} },
2720 .rhs = undefined, // set by caller
3052 fn parseIdentifier(p: *Parser) !?*Node {
3053 const token = p.eatToken(.Identifier) orelse return null;
3054 const node = try p.arena.allocator.create(Node.Identifier);
3055 node.* = .{
3056 .token = token,
27213057 };
2722 node.rhs = &child.base;
2723
27243058 return &node.base;
27253059 }
2726 if (eatToken(it, .LBracket)) |lbracket| {
2727 const asterisk = eatToken(it, .Asterisk) orelse {
2728 putBackToken(it, lbracket);
2729 return null;
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);
3060
3061 fn parseVarType(p: *Parser) !?*Node {
3062 const token = p.eatToken(.Keyword_var) orelse return null;
3063 const node = try p.arena.allocator.create(Node.VarType);
27533064 node.* = .{
2754 .op_token = lbracket,
2755 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2756 .rhs = undefined, // set by caller
3065 .token = token,
27573066 };
27583067 return &node.base;
27593068 }
2760 return null;
2761}
27623069
2763/// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
2764fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2765 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;
2766 const lbrace = try expectToken(it, tree, .LBrace);
2767 const members = try parseContainerMembers(arena, it, tree, false);
2768 const rbrace = try expectToken(it, tree, .RBrace);
3070 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
3071 const result = try p.arena.allocator.create(T);
3072 result.* = T{
3073 .base = Node{ .id = Node.typeToId(T) },
3074 .token = token,
3075 };
3076 return &result.base;
3077 }
27693078
2770 const decl_type = node.cast(Node.ContainerDecl).?;
2771 decl_type.fields_and_decls = members;
2772 decl_type.lbrace_token = lbrace;
2773 decl_type.rbrace_token = rbrace;
3079 fn parseStringLiteralSingle(p: *Parser) !?*Node {
3080 if (p.eatToken(.StringLiteral)) |token| {
3081 const node = try p.arena.allocator.create(Node.StringLiteral);
3082 node.* = .{
3083 .token = token,
3084 };
3085 return &node.base;
3086 }
3087 return null;
3088 }
27743089
2775 return node;
2776}
3090 // string literal or multiline string literal
3091 fn parseStringLiteral(p: *Parser) !?*Node {
3092 if (try p.parseStringLiteralSingle()) |node| return node;
27773093
2778/// ContainerDeclType
2779/// <- KEYWORD_struct
2780/// / KEYWORD_enum (LPAREN Expr RPAREN)?
2781/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2782fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2783 const kind_token = nextToken(it);
2784
2785 const init_arg_expr = switch (kind_token.ptr.id) {
2786 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
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 };
3094 if (p.eatToken(.MultilineStringLiteralLine)) |first_line| {
3095 const start_tok_i = p.tok_i;
3096 var tok_i = start_tok_i;
3097 var count: usize = 1; // including first_line
3098 while (true) : (tok_i += 1) {
3099 switch (p.token_ids[tok_i]) {
3100 .LineComment => continue,
3101 .MultilineStringLiteralLine => count += 1,
3102 else => break,
28103103 }
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 };
28163104 }
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;
2879
2880fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
2881 return struct {
2882 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !L {
2883 var list = L.init(arena);
2884 while (try nodeParseFn(arena, it, tree)) |node| {
2885 try list.push(node);
2886
2887 switch (it.peek().?.id) {
2888 .Comma => _ = nextToken(it),
2889 // all possible delimiters
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 });
3106 const node = try Node.MultilineStringLiteral.alloc(&p.arena.allocator, count);
3107 node.* = .{ .lines_len = count };
3108 const lines = node.lines();
3109 tok_i = start_tok_i;
3110 lines[0] = first_line;
3111 count = 1;
3112 while (true) : (tok_i += 1) {
3113 switch (p.token_ids[tok_i]) {
3114 .LineComment => continue,
3115 .MultilineStringLiteralLine => {
3116 lines[count] = tok_i;
3117 count += 1;
28973118 },
3119 else => break,
28983120 }
28993121 }
2900 return list;
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 };
3122 p.tok_i = tok_i;
29263123 return &node.base;
29273124 }
2928 }.parse;
2929}
2930
2931// Helper parsers not included in the grammar
29323125
2933fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2934 const token = eatToken(it, .Builtin) orelse return null;
2935 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
2936 try tree.errors.push(.{
2937 .ExpectedParamList = .{ .token = it.index },
2938 });
3126 return null;
3127 }
29393128
2940 // lets pretend this was an identifier so we can continue parsing
2941 const node = try arena.create(Node.Identifier);
3129 fn parseIntegerLiteral(p: *Parser) !?*Node {
3130 const token = p.eatToken(.IntegerLiteral) orelse return null;
3131 const node = try p.arena.allocator.create(Node.IntegerLiteral);
29423132 node.* = .{
29433133 .token = token,
29443134 };
29453135 return &node.base;
2946 };
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}
3136 }
29943137
2995fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2996 if (eatToken(it, .StringLiteral)) |token| {
2997 const node = try arena.create(Node.StringLiteral);
3138 fn parseFloatLiteral(p: *Parser) !?*Node {
3139 const token = p.eatToken(.FloatLiteral) orelse return null;
3140 const node = try p.arena.allocator.create(Node.FloatLiteral);
29983141 node.* = .{
29993142 .token = token,
30003143 };
30013144 return &node.base;
30023145 }
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| {
3011 const node = try arena.create(Node.MultilineStringLiteral);
3147 fn parseTry(p: *Parser) !?*Node {
3148 const token = p.eatToken(.Keyword_try) orelse return null;
3149 const node = try p.arena.allocator.create(Node.PrefixOp);
30123150 node.* = .{
3013 .lines = Node.MultilineStringLiteral.LineList.init(arena),
3151 .op_token = token,
3152 .op = .Try,
3153 .rhs = undefined, // set by caller
30143154 };
3015 try node.lines.push(first_line);
3016 while (eatToken(it, .MultilineStringLiteralLine)) |line|
3017 try node.lines.push(line);
3018
30193155 return &node.base;
30203156 }
30213157
3022 return null;
3023}
3024
3025fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
3026 const token = eatToken(it, .IntegerLiteral) orelse return null;
3027 const node = try arena.create(Node.IntegerLiteral);
3028 node.* = .{
3029 .token = token,
3030 };
3031 return &node.base;
3032}
3033
3034fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
3035 const token = eatToken(it, .FloatLiteral) orelse return null;
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}
3158 fn parseUse(p: *Parser) !?*Node {
3159 const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
3160 const node = try p.arena.allocator.create(Node.Use);
3161 node.* = .{
3162 .doc_comments = null,
3163 .visib_token = null,
3164 .use_token = token,
3165 .expr = try p.expectNode(parseExpr, .{
3166 .ExpectedExpr = .{ .token = p.tok_i },
3167 }),
3168 .semicolon_token = try p.expectToken(.Semicolon),
3169 };
3170 return &node.base;
3171 }
30533172
3054fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
3055 const token = eatToken(it, .Keyword_usingnamespace) orelse return null;
3056 const node = try arena.create(Node.Use);
3057 node.* = .{
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}
3173 /// IfPrefix Body (KEYWORD_else Payload? Body)?
3174 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
3175 const node = (try p.parseIfPrefix()) orelse return null;
3176 const if_prefix = node.cast(Node.If).?;
30683177
3069/// IfPrefix Body (KEYWORD_else Payload? Body)?
3070fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: NodeParseFn) !?*Node {
3071 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;
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;
3178 if_prefix.body = try p.expectNode(bodyParseFn, .{
3179 .InvalidToken = .{ .token = p.tok_i },
3180 });
30903181
3091 return node;
3092}
3182 const else_token = p.eatToken(.Keyword_else) orelse return node;
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 comment
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);
3195 return node;
30993196 }
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);
3104 node.* = .{
3105 .lines = lines,
3106 };
3107 return node;
3108}
3209 fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool {
3210 return std.mem.indexOfScalar(u8, p.source[p.token_locs[token1].end..p.token_locs[token2].start], '\n') == null;
3211 }
31093212
3110/// 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 {
3112 const comment_token = eatToken(it, .DocComment) orelse return null;
3113 if (tree.tokensOnSameLine(after_token, comment_token)) {
3114 const node = try arena.create(Node.DocComment);
3115 node.* = .{
3116 .lines = Node.DocComment.LineList.init(arena),
3117 };
3118 try node.lines.push(comment_token);
3119 return node;
3213 /// Eat a single-line doc comment on the same line as another node
3214 fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !?*Node.DocComment {
3215 const comment_token = p.eatToken(.DocComment) orelse return null;
3216 if (p.tokensOnSameLine(after_token, comment_token)) {
3217 const node = try p.arena.allocator.create(Node.DocComment);
3218 node.* = .{ .first_line = comment_token };
3219 return node;
3220 }
3221 p.putBackToken(comment_token);
3222 return null;
31203223 }
3121 putBackToken(it, comment_token);
3122 return null;
3123}
31243224
3125/// Op* Child
3126fn parsePrefixOpExpr(
3127 arena: *Allocator,
3128 it: *TokenIterator,
3129 tree: *Tree,
3130 opParseFn: NodeParseFn,
3131 childParseFn: NodeParseFn,
3132) Error!?*Node {
3133 if (try opParseFn(arena, it, tree)) |first_op| {
3134 var rightmost_op = first_op;
3135 while (true) {
3225 /// Op* Child
3226 fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node {
3227 if (try opParseFn(p)) |first_op| {
3228 var rightmost_op = first_op;
3229 while (true) {
3230 switch (rightmost_op.id) {
3231 .PrefixOp => {
3232 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3233 // If the token encountered was **, there will be two nodes
3234 if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {
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
31363255 switch (rightmost_op.id) {
31373256 .PrefixOp => {
3138 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3139 // If the token encountered was **, there will be two nodes
3140 if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) {
3141 rightmost_op = prefix_op.rhs;
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;
3257 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3258 prefix_op.rhs = try p.expectNode(childParseFn, .{
3259 .InvalidToken = .{ .token = p.tok_i },
3260 });
31483261 },
31493262 .AnyFrameType => {
31503263 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3151 if (try opParseFn(arena, it, tree)) |rhs| {
3152 prom.result.?.return_type = rhs;
3153 rightmost_op = rhs;
3154 } else break;
3264 prom.result.?.return_type = try p.expectNode(childParseFn, .{
3265 .InvalidToken = .{ .token = p.tok_i },
3266 });
31553267 },
31563268 else => unreachable,
31573269 }
3158 }
31593270
3160 // If any prefix op existed, a child node on the RHS is required
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,
3271 return first_op;
31753272 }
31763273
3177 return first_op;
3274 // Otherwise, the child node is optional
3275 return childParseFn(p);
31783276 }
31793277
3180 // Otherwise, the child node is optional
3181 return try childParseFn(arena, it, tree);
3182}
3278 /// Child (Op Child)*
3279 /// Child (Op Child)?
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)*
3185/// Child (Op Child)?
3186fn parseBinOpExpr(
3187 arena: *Allocator,
3188 it: *TokenIterator,
3189 tree: *Tree,
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;
3291 while (try opParseFn(p)) |node| {
3292 const right = try p.expectNode(childParseFn, .{
3293 .InvalidToken = .{ .token = p.tok_i },
3294 });
3295 const left = res;
3296 res = node;
32053297
3206 const op = node.cast(Node.InfixOp).?;
3207 op.*.lhs = left;
3208 op.*.rhs = right;
3298 const op = node.cast(Node.InfixOp).?;
3299 op.*.lhs = left;
3300 op.*.rhs = right;
32093301
3210 switch (chain) {
3211 .Once => break,
3212 .Infinitely => continue,
3302 switch (chain) {
3303 .Once => break,
3304 .Infinitely => continue,
3305 }
32133306 }
3307
3308 return res;
32143309 }
32153310
3216 return res;
3217}
3311 fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
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 {
3220 const node = try arena.create(Node.InfixOp);
3221 node.* = .{
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}
3322 fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
3323 return if (p.token_ids[p.tok_i] == id) p.nextToken() else null;
3324 }
32293325
3230fn eatToken(it: *TokenIterator, id: Token.Id) ?TokenIndex {
3231 return if (eatAnnotatedToken(it, id)) |token| token.index else null;
3232}
3326 fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex {
3327 return (try p.expectTokenRecoverable(id)) orelse error.ParseError;
3328 }
32333329
3234fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {
3235 return if (it.peek().?.id == id) nextToken(it) else null;
3236}
3330 fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex {
3331 const token = p.nextToken();
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 {
3239 return (try expectTokenRecoverable(it, tree, id)) orelse
3240 error.ParseError;
3241}
3343 fn nextToken(p: *Parser) TokenIndex {
3344 const result = p.tok_i;
3345 p.tok_i += 1;
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 {
3244 const token = nextToken(it);
3245 if (token.ptr.id != id) {
3246 try tree.errors.push(.{
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;
3349 while (true) {
3350 if (p.token_ids[p.tok_i] != .LineComment) return result;
3351 p.tok_i += 1;
3352 }
32523353 }
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) {
3264 const next_tok = it.peek() orelse return result;
3265 if (next_tok.id != .LineComment) return result;
3266 _ = it.next();
3355 fn putBackToken(p: *Parser, putting_back: TokenIndex) void {
3356 while (p.tok_i > 0) {
3357 p.tok_i -= 1;
3358 if (p.token_ids[p.tok_i] == .LineComment) continue;
3359 assert(putting_back == p.tok_i);
3360 return;
3361 }
32673362 }
3268}
32693363
3270fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {
3271 while (true) {
3272 const prev_tok = it.prev() orelse return;
3273 if (prev_tok.id == .LineComment) continue;
3274 assert(it.list.at(putting_back) == prev_tok);
3275 return;
3364 fn expectNode(
3365 p: *Parser,
3366 parseFn: NodeParseFn,
3367 /// if parsing fails
3368 err: AstError,
3369 ) Error!*Node {
3370 return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
32763371 }
3277}
32783372
3279const AnnotatedToken = struct {
3280 index: TokenIndex,
3281 ptr: *Token,
3373 fn expectNodeRecoverable(
3374 p: *Parser,
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 }
32823384};
32833385
3284fn expectNode(
3285 arena: *Allocator,
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;
3386fn ParseFn(comptime T: type) type {
3387 return fn (p: *Parser) Error!T;
32933388}
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
33083391test "std.zig.parser" {
33093392 _ = @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
31803180 const tree = try std.zig.parse(allocator, source);
31813181 defer tree.deinit();
31823182
3183 var error_it = tree.errors.iterator(0);
3184 while (error_it.next()) |parse_error| {
3185 const token = tree.tokens.at(parse_error.loc());
3183 for (tree.errors) |*parse_error| {
3184 const token = tree.token_locs[parse_error.loc()];
31863185 const loc = tree.tokenLocation(0, parse_error.loc());
31873186 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
31883187 try tree.renderError(parse_error, stderr);
......@@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {
32713270
32723271 std.testing.expect(tree.errors.len == expected_errors.len);
32733272 for (expected_errors) |expected, i| {
3274 const err = tree.errors.at(i);
3275
3276 std.testing.expect(expected == err.*);
3273 std.testing.expect(expected == tree.errors[i]);
32773274 }
32783275}
lib/std/zig/render.zig+630-573
......@@ -67,24 +67,23 @@ fn renderRoot(
6767 stream: var,
6868 tree: *ast.Tree,
6969) (@TypeOf(stream).Error || Error)!void {
70 var tok_it = tree.tokens.iterator(0);
71
7270 // render all the line comments at the beginning of the file
73 while (tok_it.next()) |token| {
74 if (token.id != .LineComment) break;
75 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")});
76 if (tok_it.peek()) |next_token| {
77 const loc = tree.tokenLocationPtr(token.end, next_token);
78 if (loc.line >= 2) {
79 try stream.writeByte('\n');
80 }
71 for (tree.token_ids) |token_id, i| {
72 if (token_id != .LineComment) break;
73 const token_loc = tree.token_locs[i];
74 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
75 const next_token = tree.token_locs[i + 1];
76 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
77 if (loc.line >= 2) {
78 try stream.writeByte('\n');
8179 }
8280 }
8381
8482 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();
8685 while (true) {
87 var decl = (it.next() orelse return).*;
86 var decl = root_decls[decl_i];
8887
8988 // This loop does the following:
9089 //
......@@ -103,8 +102,8 @@ fn renderRoot(
103102
104103 while (token_index != 0) {
105104 token_index -= 1;
106 const token = tree.tokens.at(token_index);
107 switch (token.id) {
105 const token_id = tree.token_ids[token_index];
106 switch (token_id) {
108107 .LineComment => {},
109108 .DocComment => {
110109 copy_start_token_index = token_index;
......@@ -113,12 +112,13 @@ fn renderRoot(
113112 else => break,
114113 }
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")) {
117117 if (!found_fmt_directive) {
118118 fmt_active = false;
119119 found_fmt_directive = true;
120120 }
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")) {
122122 if (!found_fmt_directive) {
123123 fmt_active = true;
124124 found_fmt_directive = true;
......@@ -133,25 +133,28 @@ fn renderRoot(
133133 token_index = decl.firstToken();
134134
135135 while (!fmt_active) {
136 decl = (it.next() orelse {
136 decl_i += 1;
137 if (decl_i >= root_decls.len) {
137138 // If there's no next reformatted `decl`, just copy the
138139 // 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;
140141 try copyFixingWhitespace(stream, tree.source[start..]);
141142 return;
142 }).*;
143 }
144 decl = root_decls[decl_i];
143145 var decl_first_token_index = decl.firstToken();
144146
145147 while (token_index < decl_first_token_index) : (token_index += 1) {
146 const token = tree.tokens.at(token_index);
147 switch (token.id) {
148 const token_id = tree.token_ids[token_index];
149 switch (token_id) {
148150 .LineComment => {},
149151 .Eof => unreachable,
150152 else => continue,
151153 }
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")) {
153156 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")) {
155158 fmt_active = false;
156159 }
157160 }
......@@ -163,8 +166,8 @@ fn renderRoot(
163166 token_index = copy_end_token_index;
164167 while (token_index != 0) {
165168 token_index -= 1;
166 const token = tree.tokens.at(token_index);
167 switch (token.id) {
169 const token_id = tree.token_ids[token_index];
170 switch (token_id) {
168171 .LineComment => {},
169172 .DocComment => {
170173 copy_end_token_index = token_index;
......@@ -174,30 +177,33 @@ fn renderRoot(
174177 }
175178 }
176179
177 const start = tree.tokens.at(copy_start_token_index).start;
178 const end = tree.tokens.at(copy_end_token_index).start;
180 const start = tree.token_locs[copy_start_token_index].start;
181 const end = tree.token_locs[copy_end_token_index].start;
179182 try copyFixingWhitespace(stream, tree.source[start..end]);
180183 }
181184
182185 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);
183 if (it.peek()) |next_decl| {
184 try renderExtraNewline(tree, stream, &start_col, next_decl.*);
185 }
186 decl_i += 1;
187 if (decl_i >= root_decls.len) return;
188 try renderExtraNewline(tree, stream, &start_col, root_decls[decl_i]);
186189 }
187190}
188191
189192fn 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 {
191197 var prev_token = first_token;
192198 if (prev_token == 0) return;
193199 var newline_threshold: usize = 2;
194 while (tree.tokens.at(prev_token - 1).id == .DocComment) {
195 if (tree.tokenLocation(tree.tokens.at(prev_token - 1).end, prev_token).line == 1) {
200 while (tree.token_ids[prev_token - 1] == .DocComment) {
201 if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) {
196202 newline_threshold += 1;
197203 }
198204 prev_token -= 1;
199205 }
200 const prev_token_end = tree.tokens.at(prev_token - 1).end;
206 const prev_token_end = tree.token_locs[prev_token - 1].end;
201207 const loc = tree.tokenLocation(prev_token_end, first_token);
202208 if (loc.line >= newline_threshold) {
203209 try stream.writeByte('\n');
......@@ -262,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
262268
263269 const src_has_trailing_comma = blk: {
264270 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;
266272 };
267273
268274 // 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,
324330
325331 .DocComment => {
326332 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
327 var it = comment.lines.iterator(0);
328 while (it.next()) |line_token_index| {
329 try renderToken(tree, stream, line_token_index.*, indent, start_col, .Newline);
330 if (it.peek()) |_| {
333 const kind = tree.token_ids[comment.first_line];
334 try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline);
335 var tok_i = comment.first_line + 1;
336 while (true) : (tok_i += 1) {
337 const tok_id = tree.token_ids[tok_i];
338 if (tok_id == kind) {
331339 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;
332345 }
333346 }
334347 },
......@@ -358,20 +371,20 @@ fn renderExpression(
358371 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
359372 }
360373
361 if (block.statements.len == 0) {
374 if (block.statements_len == 0) {
362375 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
363376 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
364377 } else {
365378 const block_indent = indent + indent_delta;
366379 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
367380
368 var it = block.statements.iterator(0);
369 while (it.next()) |statement| {
381 const block_statements = block.statements();
382 for (block_statements) |statement, i| {
370383 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| {
374 try renderExtraNewline(tree, stream, start_col, next_statement.*);
386 if (i + 1 < block_statements.len) {
387 try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]);
375388 }
376389 }
377390
......@@ -426,13 +439,13 @@ fn renderExpression(
426439 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
427440
428441 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));
430443 break :blk if (loc.line == 0) op_space else Space.Newline;
431444 };
432445
433446 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
434447 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)
436449 {
437450 try stream.writeByteNTimes(' ', indent + indent_delta);
438451 start_col.* = indent + indent_delta;
......@@ -453,10 +466,10 @@ fn renderExpression(
453466
454467 switch (prefix_op_node.op) {
455468 .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];
457470 switch (op_tok_id) {
458471 .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)
460473 try stream.writeAll("[*c")
461474 else
462475 try stream.writeAll("[*"),
......@@ -568,8 +581,8 @@ fn renderExpression(
568581
569582 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
570583
571 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;
572 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
584 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
585 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
573586 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
574587 const new_space = if (ends_with_comment) Space.Newline else Space.None;
575588 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
......@@ -610,80 +623,371 @@ fn renderExpression(
610623 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);
611624 },
612625
613 .SuffixOp => {
614 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
615
616 switch (suffix_op.op) {
617 .Call => |*call_info| {
618 if (call_info.async_token) |async_token| {
619 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
620 }
621
622 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
623
624 const lparen = tree.nextToken(suffix_op.lhs.node.lastToken());
626 .ArrayInitializer, .ArrayInitializerDot => {
627 var rtoken: ast.TokenIndex = undefined;
628 var exprs: []*ast.Node = undefined;
629 const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){
630 .ArrayInitializerDot => blk: {
631 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
632 rtoken = casted.rtoken;
633 exprs = casted.list();
634 break :blk .{ .dot = casted.dot };
635 },
636 .ArrayInitializer => blk: {
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) {
627 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
628 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
629 }
645 const lbrace = switch (lhs) {
646 .dot => |dot| tree.nextToken(dot),
647 .node => |node| tree.nextToken(node.lastToken()),
648 };
630649
631 const src_has_trailing_comma = blk: {
632 const maybe_comma = tree.prevToken(suffix_op.rtoken);
633 break :blk tree.tokens.at(maybe_comma).id == .Comma;
634 };
650 if (exprs.len == 0) {
651 switch (lhs) {
652 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
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) {
637 const new_indent = indent + indent_delta;
638 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
659 if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) {
660 const expr = exprs[0];
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);
641 while (true) {
642 const param_node = it.next().?;
670 switch (lhs) {
671 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
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: {
645 break :blk indent;
646 } else blk: {
647 try stream.writeByteNTimes(' ', new_indent);
648 break :blk new_indent;
675 // scan to find row size
676 const maybe_row_size: ?usize = blk: {
677 var count: usize = 1;
678 for (exprs) |expr, i| {
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;
649692 };
650
651 if (it.peek()) |next_node| {
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.*);
693 if (src_has_trailing_comma) {
694 break :blk 1; // force row size 1
656695 } else {
657 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.Comma);
658 try stream.writeByteNTimes(' ', indent);
659 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
696 break :blk null; // no newlines
660697 }
661698 }
699 break :blk count;
662700 }
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);
667 while (it.next()) |param_node| {
668 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);
756 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
757 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
758 } else {
759 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
760 }
669761
670 if (it.peek() != null) {
671 const comma = tree.nextToken(param_node.*.lastToken());
672 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
762 try renderExtraNewline(tree, stream, start_col, next_expr);
763 if (next_expr.id != .MultilineStringLiteral) {
764 try stream.writeByteNTimes(' ', new_indent);
673765 }
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);
674783 }
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 };
676799 },
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) {
678982 .ArrayAccess => |index_expr| {
679 const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken());
983 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
680984 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);
683987 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
684988
685 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;
686 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
989 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
990 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
687991 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
688992 const new_space = if (ends_with_comment) Space.Newline else Space.None;
689993 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
......@@ -697,18 +1001,18 @@ fn renderExpression(
6971001 },
6981002
6991003 .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);
7011005 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
7021006 },
7031007
7041008 .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);
7061010 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
7071011 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
7081012 },
7091013
7101014 .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
7131017 const lbracket = tree.prevToken(range.start.firstToken());
7141018 const dotdot = tree.nextToken(range.start.lastToken());
......@@ -733,269 +1037,6 @@ fn renderExpression(
7331037 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
7341038 },
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 },
9991040 }
10001041 },
10011042
......@@ -1179,7 +1220,7 @@ fn renderExpression(
11791220 },
11801221 }
11811222
1182 if (container_decl.fields_and_decls.len == 0) {
1223 if (container_decl.fields_and_decls_len == 0) {
11831224 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {
11841225 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
11851226 }
......@@ -1188,23 +1229,24 @@ fn renderExpression(
11881229 var maybe_comma = tree.prevToken(container_decl.lastToken());
11891230 // Doc comments for a field may also appear after the comma, eg.
11901231 // 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)
11921233 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;
11941235 };
11951236
1237 const fields_and_decls = container_decl.fieldsAndDecls();
1238
11961239 // Check if the first declaration and the { are on the same line
11971240 const src_has_newline = !tree.tokensOnSameLine(
11981241 container_decl.lbrace_token,
1199 container_decl.fields_and_decls.at(0).*.firstToken(),
1242 fields_and_decls[0].firstToken(),
12001243 );
12011244
12021245 // We can only print all the elements in-line if all the
12031246 // declarations inside are fields
12041247 const src_has_only_fields = blk: {
1205 var it = container_decl.fields_and_decls.iterator(0);
1206 while (it.next()) |decl| {
1207 if (decl.*.id != .ContainerField) break :blk false;
1248 for (fields_and_decls) |decl| {
1249 if (decl.id != .ContainerField) break :blk false;
12081250 }
12091251 break :blk true;
12101252 };
......@@ -1214,13 +1256,12 @@ fn renderExpression(
12141256 const new_indent = indent + indent_delta;
12151257 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {
12161258
1217 var it = container_decl.fields_and_decls.iterator(0);
1218 while (it.next()) |decl| {
1259 for (fields_and_decls) |decl, i| {
12191260 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| {
1223 try renderExtraNewline(tree, stream, start_col, next_decl.*);
1263 if (i + 1 < fields_and_decls.len) {
1264 try renderExtraNewline(tree, stream, start_col, fields_and_decls[i + 1]);
12241265 }
12251266 }
12261267
......@@ -1233,10 +1274,9 @@ fn renderExpression(
12331274 const new_indent = indent + indent_delta;
12341275 try stream.writeByteNTimes(' ', new_indent);
12351276
1236 var it = container_decl.fields_and_decls.iterator(0);
1237 while (it.next()) |decl| {
1238 const space_after_decl: Space = if (it.peek() == null) .Newline else .Space;
1239 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, space_after_decl);
1277 for (fields_and_decls) |decl, i| {
1278 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1279 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, space_after_decl);
12401280 }
12411281
12421282 try stream.writeByteNTimes(' ', indent);
......@@ -1244,9 +1284,8 @@ fn renderExpression(
12441284 // All the declarations on the same line
12451285 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // {
12461286
1247 var it = container_decl.fields_and_decls.iterator(0);
1248 while (it.next()) |decl| {
1249 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl.*, .Space);
1287 for (fields_and_decls) |decl| {
1288 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Space);
12501289 }
12511290 }
12521291
......@@ -1258,14 +1297,14 @@ fn renderExpression(
12581297
12591298 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) {
12621301 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
12631302 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
12641303 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
12651304 }
12661305
1267 if (err_set_decl.decls.len == 1) blk: {
1268 const node = err_set_decl.decls.at(0).*;
1306 if (err_set_decl.decls_len == 1) blk: {
1307 const node = err_set_decl.decls()[0];
12691308
12701309 // if there are any doc comments or same line comments
12711310 // don't try to put it all on one line
......@@ -1285,24 +1324,24 @@ fn renderExpression(
12851324
12861325 const src_has_trailing_comma = blk: {
12871326 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;
12891328 };
12901329
12911330 if (src_has_trailing_comma) {
12921331 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
12931332 const new_indent = indent + indent_delta;
12941333
1295 var it = err_set_decl.decls.iterator(0);
1296 while (it.next()) |node| {
1334 const decls = err_set_decl.decls();
1335 for (decls) |node, i| {
12971336 try stream.writeByteNTimes(' ', new_indent);
12981337
1299 if (it.peek()) |next_node| {
1300 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); // ,
1338 if (i + 1 < decls.len) {
1339 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
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]);
13041343 } 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);
13061345 }
13071346 }
13081347
......@@ -1311,17 +1350,17 @@ fn renderExpression(
13111350 } else {
13121351 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
13131352
1314 var it = err_set_decl.decls.iterator(0);
1315 while (it.next()) |node| {
1316 if (it.peek()) |next_node| {
1317 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1353 const decls = err_set_decl.decls();
1354 for (decls) |node, i| {
1355 if (i + 1 < decls.len) {
1356 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
13181357
1319 const comma_token = tree.nextToken(node.*.lastToken());
1320 assert(tree.tokens.at(comma_token).id == .Comma);
1358 const comma_token = tree.nextToken(node.lastToken());
1359 assert(tree.token_ids[comma_token] == .Comma);
13211360 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]);
13231362 } 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);
13251364 }
13261365 }
13271366
......@@ -1342,14 +1381,12 @@ fn renderExpression(
13421381 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
13431382
13441383 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) {
13461385 try stream.print("\n", .{});
13471386 skip_first_indent = false;
13481387 }
13491388
1350 var i: usize = 0;
1351 while (i < multiline_str_literal.lines.len) : (i += 1) {
1352 const t = multiline_str_literal.lines.at(i).*;
1389 for (multiline_str_literal.lines()) |t| {
13531390 if (!skip_first_indent) {
13541391 try stream.writeByteNTimes(' ', indent + indent_delta);
13551392 }
......@@ -1369,10 +1406,10 @@ fn renderExpression(
13691406 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
13701407
13711408 const src_params_trailing_comma = blk: {
1372 if (builtin_call.params.len < 2) break :blk false;
1373 const last_node = builtin_call.params.at(builtin_call.params.len - 1).*;
1409 if (builtin_call.params_len < 2) break :blk false;
1410 const last_node = builtin_call.params()[builtin_call.params_len - 1];
13741411 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;
13761413 };
13771414
13781415 const lparen = tree.nextToken(builtin_call.builtin_token);
......@@ -1381,12 +1418,12 @@ fn renderExpression(
13811418 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
13821419
13831420 // render all on one line, no trailing comma
1384 var it = builtin_call.params.iterator(0);
1385 while (it.next()) |param_node| {
1386 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);
1421 const params = builtin_call.params();
1422 for (params) |param_node, i| {
1423 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
13871424
1388 if (it.peek() != null) {
1389 const comma_token = tree.nextToken(param_node.*.lastToken());
1425 if (i + 1 < params.len) {
1426 const comma_token = tree.nextToken(param_node.lastToken());
13901427 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
13911428 }
13921429 }
......@@ -1395,10 +1432,9 @@ fn renderExpression(
13951432 const new_indent = indent + indent_delta;
13961433 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
13971434
1398 var it = builtin_call.params.iterator(0);
1399 while (it.next()) |param_node| {
1435 for (builtin_call.params()) |param_node| {
14001436 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);
14021438 }
14031439 try stream.writeByteNTimes(' ', indent);
14041440 }
......@@ -1410,8 +1446,8 @@ fn renderExpression(
14101446 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14111447
14121448 if (fn_proto.visib_token) |visib_token_index| {
1413 const visib_token = tree.tokens.at(visib_token_index);
1414 assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export);
1449 const visib_token = tree.token_ids[visib_token_index];
1450 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14151451
14161452 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
14171453 }
......@@ -1433,7 +1469,7 @@ fn renderExpression(
14331469 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
14341470 break :blk tree.nextToken(fn_proto.fn_token);
14351471 };
1436 assert(tree.tokens.at(lparen).id == .LParen);
1472 assert(tree.token_ids[lparen] == .LParen);
14371473
14381474 const rparen = tree.prevToken(
14391475 // the first token for the annotation expressions is the left
......@@ -1449,10 +1485,10 @@ fn renderExpression(
14491485 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
14501486 .Invalid => unreachable,
14511487 });
1452 assert(tree.tokens.at(rparen).id == .RParen);
1488 assert(tree.token_ids[rparen] == .RParen);
14531489
14541490 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];
14561492 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
14571493 };
14581494
......@@ -1460,12 +1496,11 @@ fn renderExpression(
14601496 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
14611497
14621498 // render all on one line, no trailing comma
1463 var it = fn_proto.params.iterator(0);
1464 while (it.next()) |param_decl_node| {
1465 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node.*, Space.None);
1499 for (fn_proto.params()) |param_decl, i| {
1500 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
14661501
1467 if (it.peek() != null) {
1468 const comma = tree.nextToken(param_decl_node.*.lastToken());
1502 if (i + 1 < fn_proto.params_len) {
1503 const comma = tree.nextToken(param_decl.lastToken());
14691504 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
14701505 }
14711506 }
......@@ -1474,10 +1509,9 @@ fn renderExpression(
14741509 const new_indent = indent + indent_delta;
14751510 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
14761511
1477 var it = fn_proto.params.iterator(0);
1478 while (it.next()) |param_decl_node| {
1512 for (fn_proto.params()) |param_decl| {
14791513 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);
14811515 }
14821516 try stream.writeByteNTimes(' ', indent);
14831517 }
......@@ -1556,7 +1590,7 @@ fn renderExpression(
15561590 const rparen = tree.nextToken(switch_node.expr.lastToken());
15571591 const lbrace = tree.nextToken(rparen);
15581592
1559 if (switch_node.cases.len == 0) {
1593 if (switch_node.cases_len == 0) {
15601594 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
15611595 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
15621596 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
......@@ -1570,13 +1604,13 @@ fn renderExpression(
15701604 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
15711605 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
15721606
1573 var it = switch_node.cases.iterator(0);
1574 while (it.next()) |node| {
1607 const cases = switch_node.cases();
1608 for (cases) |node, i| {
15751609 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| {
1579 try renderExtraNewline(tree, stream, start_col, next_node.*);
1612 if (i + 1 < cases.len) {
1613 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
15801614 }
15811615 }
15821616
......@@ -1587,38 +1621,38 @@ fn renderExpression(
15871621 .SwitchCase => {
15881622 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
15891623
1590 assert(switch_case.items.len != 0);
1624 assert(switch_case.items_len != 0);
15911625 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];
15931627 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;
15951629 };
15961630
1597 if (switch_case.items.len == 1 or !src_has_trailing_comma) {
1598 var it = switch_case.items.iterator(0);
1599 while (it.next()) |node| {
1600 if (it.peek()) |next_node| {
1601 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1631 if (switch_case.items_len == 1 or !src_has_trailing_comma) {
1632 const items = switch_case.items();
1633 for (items) |node, i| {
1634 if (i + 1 < items.len) {
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());
16041638 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]);
16061640 } 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);
16081642 }
16091643 }
16101644 } else {
1611 var it = switch_case.items.iterator(0);
1612 while (it.next()) |node| {
1613 if (it.peek()) |next_node| {
1614 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1645 const items = switch_case.items();
1646 for (items) |node, i| {
1647 if (i + 1 < items.len) {
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());
16171651 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]);
16191653 try stream.writeByteNTimes(' ', indent);
16201654 } 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);
16221656 try stream.writeByteNTimes(' ', indent);
16231657 }
16241658 }
......@@ -1918,34 +1952,31 @@ fn renderExpression(
19181952 } else blk: {
19191953 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
19201954
1921 var it = asm_node.outputs.iterator(0);
1922 while (true) {
1923 const asm_output = it.next().?;
1924 const node = &(asm_output.*).base;
1955 for (asm_node.outputs) |*asm_output, i| {
1956 if (i + 1 < asm_node.outputs.len) {
1957 const next_asm_output = asm_node.outputs[i + 1];
1958 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
19251959
1926 if (it.peek()) |next_asm_output| {
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());
1960 const comma = tree.prevToken(next_asm_output.firstToken());
19311961 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
19341964 try stream.writeByteNTimes(' ', indent_extra);
19351965 } 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);
19371967 try stream.writeByteNTimes(' ', indent);
19381968 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
19391969 } 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);
19411971 try stream.writeByteNTimes(' ', indent_once);
1942 const comma_or_colon = tree.nextToken(node.lastToken());
1943 break :blk switch (tree.tokens.at(comma_or_colon).id) {
1972 const comma_or_colon = tree.nextToken(asm_output.lastToken());
1973 break :blk switch (tree.token_ids[comma_or_colon]) {
19441974 .Comma => tree.nextToken(comma_or_colon),
19451975 else => comma_or_colon,
19461976 };
19471977 }
19481978 }
1979 unreachable;
19491980 };
19501981
19511982 const colon3 = if (asm_node.inputs.len == 0) blk: {
......@@ -1956,43 +1987,37 @@ fn renderExpression(
19561987 } else blk: {
19571988 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
19581989
1959 var it = asm_node.inputs.iterator(0);
1960 while (true) {
1961 const asm_input = it.next().?;
1962 const node = &(asm_input.*).base;
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;
1990 for (asm_node.inputs) |*asm_input, i| {
1991 if (i + 1 < asm_node.inputs.len) {
1992 const next_asm_input = &asm_node.inputs[i + 1];
1993 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
19671994
1968 const comma = tree.prevToken(next_asm_input.*.firstToken());
1995 const comma = tree.prevToken(next_asm_input.firstToken());
19691996 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
19721999 try stream.writeByteNTimes(' ', indent_extra);
19732000 } 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);
19752002 try stream.writeByteNTimes(' ', indent);
19762003 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
19772004 } 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);
19792006 try stream.writeByteNTimes(' ', indent_once);
1980 const comma_or_colon = tree.nextToken(node.lastToken());
1981 break :blk switch (tree.tokens.at(comma_or_colon).id) {
2007 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2008 break :blk switch (tree.token_ids[comma_or_colon]) {
19822009 .Comma => tree.nextToken(comma_or_colon),
19832010 else => comma_or_colon,
19842011 };
19852012 }
19862013 }
2014 unreachable;
19872015 };
19882016
19892017 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
19902018
1991 var it = asm_node.clobbers.iterator(0);
1992 while (true) {
1993 const clobber_node = it.next().?.*;
1994
1995 if (it.peek() == null) {
2019 for (asm_node.clobbers) |clobber_node, i| {
2020 if (i + 1 >= asm_node.clobbers.len) {
19962021 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
19972022 try stream.writeByteNTimes(' ', indent);
19982023 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
......@@ -2004,40 +2029,6 @@ fn renderExpression(
20042029 }
20052030 },
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
20412032 .EnumLiteral => {
20422033 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
20432034
......@@ -2050,11 +2041,56 @@ fn renderExpression(
20502041 .VarDecl,
20512042 .Use,
20522043 .TestDecl,
2053 .ParamDecl,
20542044 => unreachable,
20552045 }
20562046}
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
20582094fn renderVarDecl(
20592095 allocator: *mem.Allocator,
20602096 stream: var,
......@@ -2133,11 +2169,9 @@ fn renderParamDecl(
21332169 tree: *ast.Tree,
21342170 indent: usize,
21352171 start_col: *usize,
2136 base: *ast.Node,
2172 param_decl: ast.Node.FnProto.ParamDecl,
21372173 space: Space,
21382174) (@TypeOf(stream).Error || Error)!void {
2139 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
2140
21412175 try renderDocComments(tree, stream, param_decl, indent, start_col);
21422176
21432177 if (param_decl.comptime_token) |comptime_token| {
......@@ -2174,7 +2208,7 @@ fn renderStatement(
21742208 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
21752209
21762210 const semicolon_index = tree.nextToken(base.lastToken());
2177 assert(tree.tokens.at(semicolon_index).id == .Semicolon);
2211 assert(tree.token_ids[semicolon_index] == .Semicolon);
21782212 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
21792213 } else {
21802214 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
......@@ -2212,22 +2246,25 @@ fn renderTokenOffset(
22122246 return;
22132247 }
22142248
2215 var token = tree.tokens.at(token_index);
2216 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
2249 var token_loc = tree.token_locs[token_index];
2250 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
22172251
22182252 if (space == Space.NoComment)
22192253 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) {
22242259 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
22252260 .LineComment => {
22262261 try stream.writeAll(", ");
22272262 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
22282263 },
22292264 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 {
22312268 try stream.writeAll(",");
22322269 return;
22332270 } else {
......@@ -2240,19 +2277,20 @@ fn renderTokenOffset(
22402277
22412278 // Skip over same line doc comments
22422279 var offset: usize = 1;
2243 if (next_token.id == .DocComment) {
2244 const loc = tree.tokenLocationPtr(token.end, next_token);
2280 if (next_token_id == .DocComment) {
2281 const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
22452282 if (loc.line == 0) {
22462283 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];
22482286 }
22492287 }
22502288
2251 if (next_token.id != .LineComment) blk: {
2289 if (next_token_id != .LineComment) blk: {
22522290 switch (space) {
22532291 Space.None, Space.NoNewline => return,
22542292 Space.Newline => {
2255 if (next_token.id == .MultilineStringLiteralLine) {
2293 if (next_token_id == .MultilineStringLiteralLine) {
22562294 return;
22572295 } else {
22582296 try stream.writeAll("\n");
......@@ -2261,7 +2299,7 @@ fn renderTokenOffset(
22612299 }
22622300 },
22632301 Space.Space, Space.SpaceOrOutdent => {
2264 if (next_token.id == .MultilineStringLiteralLine)
2302 if (next_token_id == .MultilineStringLiteralLine)
22652303 return;
22662304 try stream.writeByte(' ');
22672305 return;
......@@ -2271,14 +2309,15 @@ fn renderTokenOffset(
22712309 }
22722310
22732311 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;
22752313 if (comment_is_empty) {
22762314 switch (space) {
22772315 Space.Newline => {
22782316 offset += 1;
2279 token = next_token;
2280 next_token = tree.tokens.at(token_index + offset);
2281 if (next_token.id != .LineComment) {
2317 token_loc = next_token_loc;
2318 next_token_id = tree.token_ids[token_index + offset];
2319 next_token_loc = tree.token_locs[token_index + offset];
2320 if (next_token_id != .LineComment) {
22822321 try stream.writeByte('\n');
22832322 start_col.* = 0;
22842323 return;
......@@ -2291,18 +2330,19 @@ fn renderTokenOffset(
22912330 }
22922331 }
22932332
2294 var loc = tree.tokenLocationPtr(token.end, next_token);
2333 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
22952334 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), " ")});
22972336 offset = 2;
2298 token = next_token;
2299 next_token = tree.tokens.at(token_index + offset);
2300 if (next_token.id != .LineComment) {
2337 token_loc = next_token_loc;
2338 next_token_loc = tree.token_locs[token_index + offset];
2339 next_token_id = tree.token_ids[token_index + offset];
2340 if (next_token_id != .LineComment) {
23012341 switch (space) {
23022342 Space.None, Space.Space => {
23032343 try stream.writeByte('\n');
2304 const after_comment_token = tree.tokens.at(token_index + offset);
2305 const next_line_indent = switch (after_comment_token.id) {
2344 const after_comment_token = tree.token_ids[token_index + offset];
2345 const next_line_indent = switch (after_comment_token) {
23062346 .RParen, .RBrace, .RBracket => indent,
23072347 else => indent + indent_delta,
23082348 };
......@@ -2315,7 +2355,7 @@ fn renderTokenOffset(
23152355 start_col.* = indent;
23162356 },
23172357 Space.Newline => {
2318 if (next_token.id == .MultilineStringLiteralLine) {
2358 if (next_token_id == .MultilineStringLiteralLine) {
23192359 return;
23202360 } else {
23212361 try stream.writeAll("\n");
......@@ -2328,7 +2368,7 @@ fn renderTokenOffset(
23282368 }
23292369 return;
23302370 }
2331 loc = tree.tokenLocationPtr(token.end, next_token);
2371 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
23322372 }
23332373
23342374 while (true) {
......@@ -2338,15 +2378,16 @@ fn renderTokenOffset(
23382378 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
23392379 try stream.writeByteNTimes('\n', newline_count);
23402380 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
23432383 offset += 1;
2344 token = next_token;
2345 next_token = tree.tokens.at(token_index + offset);
2346 if (next_token.id != .LineComment) {
2384 token_loc = next_token_loc;
2385 next_token_loc = tree.token_locs[token_index + offset];
2386 next_token_id = tree.token_ids[token_index + offset];
2387 if (next_token_id != .LineComment) {
23472388 switch (space) {
23482389 Space.Newline => {
2349 if (next_token.id == .MultilineStringLiteralLine) {
2390 if (next_token_id == .MultilineStringLiteralLine) {
23502391 return;
23512392 } else {
23522393 try stream.writeAll("\n");
......@@ -2357,8 +2398,8 @@ fn renderTokenOffset(
23572398 Space.None, Space.Space => {
23582399 try stream.writeByte('\n');
23592400
2360 const after_comment_token = tree.tokens.at(token_index + offset);
2361 const next_line_indent = switch (after_comment_token.id) {
2401 const after_comment_token = tree.token_ids[token_index + offset];
2402 const next_line_indent = switch (after_comment_token) {
23622403 .RParen, .RBrace, .RBracket => blk: {
23632404 if (indent > indent_delta) {
23642405 break :blk indent - indent_delta;
......@@ -2381,7 +2422,7 @@ fn renderTokenOffset(
23812422 }
23822423 return;
23832424 }
2384 loc = tree.tokenLocationPtr(token.end, next_token);
2425 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
23852426 }
23862427}
23872428
......@@ -2404,16 +2445,32 @@ fn renderDocComments(
24042445 start_col: *usize,
24052446) (@TypeOf(stream).Error || Error)!void {
24062447 const comment = node.doc_comments orelse return;
2407 var it = comment.lines.iterator(0);
2408 const first_token = node.firstToken();
2409 while (it.next()) |line_token_index| {
2410 if (line_token_index.* < first_token) {
2411 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline);
2412 try stream.writeByteNTimes(' ', indent);
2413 } else {
2414 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);
2415 try stream.writeAll("\n");
2416 try stream.writeByteNTimes(' ', indent);
2448 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
2449}
2450
2451fn renderDocCommentsToken(
2452 tree: *ast.Tree,
2453 stream: var,
2454 comment: *ast.Node.DocComment,
2455 first_token: ast.TokenIndex,
2456 indent: usize,
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,
24172474 }
24182475 }
24192476}
lib/std/zig/tokenizer.zig+18-10
......@@ -3,8 +3,12 @@ const mem = std.mem;
33
44pub const Token = struct {
55 id: Id,
6 start: usize,
7 end: usize,
6 loc: Loc,
7
8 pub const Loc = struct {
9 start: usize,
10 end: usize,
11 };
812
913 pub const Keyword = struct {
1014 bytes: []const u8,
......@@ -426,8 +430,10 @@ pub const Tokenizer = struct {
426430 var state: State = .start;
427431 var result = Token{
428432 .id = .Eof,
429 .start = self.index,
430 .end = undefined,
433 .loc = .{
434 .start = self.index,
435 .end = undefined,
436 },
431437 };
432438 var seen_escape_digits: usize = undefined;
433439 var remaining_code_units: usize = undefined;
......@@ -436,7 +442,7 @@ pub const Tokenizer = struct {
436442 switch (state) {
437443 .start => switch (c) {
438444 ' ', '\n', '\t', '\r' => {
439 result.start = self.index + 1;
445 result.loc.start = self.index + 1;
440446 },
441447 '"' => {
442448 state = .string_literal;
......@@ -686,7 +692,7 @@ pub const Tokenizer = struct {
686692 .identifier => switch (c) {
687693 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
688694 else => {
689 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {
695 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
690696 result.id = id;
691697 }
692698 break;
......@@ -1313,7 +1319,7 @@ pub const Tokenizer = struct {
13131319 => {},
13141320
13151321 .identifier => {
1316 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {
1322 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
13171323 result.id = id;
13181324 }
13191325 },
......@@ -1420,7 +1426,7 @@ pub const Tokenizer = struct {
14201426 }
14211427 }
14221428
1423 result.end = self.index;
1429 result.loc.end = self.index;
14241430 return result;
14251431 }
14261432
......@@ -1430,8 +1436,10 @@ pub const Tokenizer = struct {
14301436 if (invalid_length == 0) return;
14311437 self.pending_invalid_token = .{
14321438 .id = .Invalid,
1433 .start = self.index,
1434 .end = self.index + invalid_length,
1439 .loc = .{
1440 .start = self.index,
1441 .end = self.index + invalid_length,
1442 },
14351443 };
14361444 }
14371445
src-self-hosted/clang.zig+11-13
......@@ -22,7 +22,7 @@ pub const struct_ZigClangCompoundStmt = @Type(.Opaque);
2222pub const struct_ZigClangConstantArrayType = @Type(.Opaque);
2323pub const struct_ZigClangContinueStmt = @Type(.Opaque);
2424pub const struct_ZigClangDecayedType = @Type(.Opaque);
25pub const struct_ZigClangDecl = @Type(.Opaque);
25pub const ZigClangDecl = @Type(.Opaque);
2626pub const struct_ZigClangDeclRefExpr = @Type(.Opaque);
2727pub const struct_ZigClangDeclStmt = @Type(.Opaque);
2828pub const struct_ZigClangDefaultStmt = @Type(.Opaque);
......@@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque);
6363pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque);
6464pub const struct_ZigClangSourceManager = @Type(.Opaque);
6565pub const struct_ZigClangSourceRange = @Type(.Opaque);
66pub const struct_ZigClangStmt = @Type(.Opaque);
66pub const ZigClangStmt = @Type(.Opaque);
6767pub const struct_ZigClangStringLiteral = @Type(.Opaque);
6868pub const struct_ZigClangStringRef = @Type(.Opaque);
6969pub const struct_ZigClangSwitchStmt = @Type(.Opaque);
......@@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla
781781pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
782782pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
783783pub 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;
785785pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
786786pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool;
787787pub 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
817817pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;
818818pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;
819819pub 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;
821821pub extern fn ZigClangNamedDecl_getName_bytes_begin(decl: ?*const struct_ZigClangNamedDecl) [*:0]const u8;
822822pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
823823pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
......@@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*
842842pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType;
843843pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType;
844844pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType;
845pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
846pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
847pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
845pub extern fn ZigClangStmt_getBeginLoc(self: *const ZigClangStmt) struct_ZigClangSourceLocation;
846pub extern fn ZigClangStmt_getStmtClass(self: ?*const ZigClangStmt) ZigClangStmtClass;
847pub extern fn ZigClangStmt_classof_Expr(self: ?*const ZigClangStmt) bool;
848848pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;
849849pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;
850850pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
......@@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl
873873pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool;
874874pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass;
875875pub 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;
877877pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool;
878878pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool;
879879pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool;
......@@ -918,7 +918,6 @@ pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt;
918918pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType;
919919pub const ZigClangContinueStmt = struct_ZigClangContinueStmt;
920920pub const ZigClangDecayedType = struct_ZigClangDecayedType;
921pub const ZigClangDecl = struct_ZigClangDecl;
922921pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr;
923922pub const ZigClangDeclStmt = struct_ZigClangDeclStmt;
924923pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt;
......@@ -959,7 +958,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt;
959958pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope;
960959pub const ZigClangSourceManager = struct_ZigClangSourceManager;
961960pub const ZigClangSourceRange = struct_ZigClangSourceRange;
962pub const ZigClangStmt = struct_ZigClangStmt;
963961pub const ZigClangStringLiteral = struct_ZigClangStringLiteral;
964962pub const ZigClangStringRef = struct_ZigClangStringRef;
965963pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt;
......@@ -1016,14 +1014,14 @@ pub extern fn ZigClangLoadFromCommandLine(
10161014) ?*ZigClangASTUnit;
10171015
10181016pub 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
10231021pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
10241022pub 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
10281026pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
10291027pub 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 {
600600 };
601601 defer tree.deinit();
602602
603 var error_it = tree.errors.iterator(0);
604 while (error_it.next()) |parse_error| {
603 for (tree.errors) |parse_error| {
605604 try printErrMsgToFile(gpa, parse_error, tree, "<stdin>", stderr_file, color);
606605 }
607606 if (tree.errors.len != 0) {
......@@ -701,8 +700,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
701700 };
702701 defer tree.deinit();
703702
704 var error_it = tree.errors.iterator(0);
705 while (error_it.next()) |parse_error| {
703 for (tree.errors) |parse_error| {
706704 try printErrMsgToFile(fmt.gpa, parse_error, tree, file_path, std.io.getStdErr(), fmt.color);
707705 }
708706 if (tree.errors.len != 0) {
......@@ -730,7 +728,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
730728
731729fn printErrMsgToFile(
732730 gpa: *mem.Allocator,
733 parse_error: *const ast.Error,
731 parse_error: ast.Error,
734732 tree: *ast.Tree,
735733 path: []const u8,
736734 file: fs.File,
......@@ -745,15 +743,15 @@ fn printErrMsgToFile(
745743 const span_first = lok_token;
746744 const span_last = lok_token;
747745
748 const first_token = tree.tokens.at(span_first);
749 const last_token = tree.tokens.at(span_last);
750 const start_loc = tree.tokenLocationPtr(0, first_token);
751 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
746 const first_token = tree.token_locs[span_first];
747 const last_token = tree.token_locs[span_last];
748 const start_loc = tree.tokenLocationLoc(0, first_token);
749 const end_loc = tree.tokenLocationLoc(first_token.end, last_token);
752750
753751 var text_buf = std.ArrayList(u8).init(gpa);
754752 defer text_buf.deinit();
755753 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);
757755 const text = text_buf.span();
758756
759757 const stream = file.outStream();
src-self-hosted/translate_c.zig+877-778
......@@ -37,10 +37,10 @@ fn addrEql(a: usize, b: usize) bool {
3737}
3838
3939const SymbolTable = std.StringHashMap(*ast.Node);
40const AliasList = std.SegmentedList(struct {
40const AliasList = std.ArrayList(struct {
4141 alias: []const u8,
4242 name: []const u8,
43}, 4);
43});
4444
4545const Scope = struct {
4646 id: Id,
......@@ -54,50 +54,99 @@ const Scope = struct {
5454 Loop,
5555 };
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.
5760 const Switch = struct {
5861 base: Scope,
59 pending_block: *ast.Node.Block,
60 cases: *ast.Node.Switch.CaseList,
62 pending_block: Block,
63 cases: []*ast.Node,
64 case_index: usize,
6165 has_default: bool = false,
6266 };
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.
6489 const Block = struct {
6590 base: Scope,
66 block_node: *ast.Node.Block,
91 statements: std.ArrayList(*ast.Node),
6792 variables: AliasList,
68 label: ?[]const u8,
93 label: ?ast.TokenIndex,
6994 mangle_count: u32 = 0,
95 lbrace: ast.TokenIndex,
7096
71 /// Don't forget to set rbrace token and block_node later
72 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block {
73 const block = try c.a().create(Block);
74 block.* = .{
97 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block {
98 return Block{
7599 .base = .{
76100 .id = .Block,
77101 .parent = parent,
78102 },
79 .block_node = undefined,
80 .variables = AliasList.init(c.a()),
81 .label = label,
103 .statements = std.ArrayList(*ast.Node).init(c.gpa),
104 .variables = AliasList.init(c.gpa),
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, "{"),
82111 };
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;
84133 }
85134
86135 /// Given the desired name, return a name that does not shadow anything from outer scopes.
87136 /// Inserts the returned name into the scope.
88137 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;
90140 while (scope.contains(proposed_name)) {
91141 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 });
93143 }
94 try scope.variables.push(.{ .name = name, .alias = proposed_name });
144 try scope.variables.append(.{ .name = name_copy, .alias = proposed_name });
95145 return proposed_name;
96146 }
97147
98148 fn getAlias(scope: *Block, name: []const u8) []const u8 {
99 var it = scope.variables.iterator(0);
100 while (it.next()) |p| {
149 for (scope.variables.items) |p| {
101150 if (mem.eql(u8, p.name, name))
102151 return p.alias;
103152 }
......@@ -105,8 +154,7 @@ const Scope = struct {
105154 }
106155
107156 fn localContains(scope: *Block, name: []const u8) bool {
108 var it = scope.variables.iterator(0);
109 while (it.next()) |p| {
157 for (scope.variables.items) |p| {
110158 if (mem.eql(u8, p.name, name))
111159 return true;
112160 }
......@@ -132,8 +180,8 @@ const Scope = struct {
132180 .id = .Root,
133181 .parent = null,
134182 },
135 .sym_table = SymbolTable.init(c.a()),
136 .macro_table = SymbolTable.init(c.a()),
183 .sym_table = SymbolTable.init(c.arena),
184 .macro_table = SymbolTable.init(c.arena),
137185 .context = c,
138186 };
139187 }
......@@ -158,10 +206,7 @@ const Scope = struct {
158206 switch (scope.id) {
159207 .Root => unreachable,
160208 .Block => return @fieldParentPtr(Block, "base", scope),
161 .Condition => {
162 // comma operator used
163 return try Block.init(c, scope, "blk");
164 },
209 .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),
165210 else => scope = scope.parent.?,
166211 }
167212 }
......@@ -208,7 +253,11 @@ const Scope = struct {
208253};
209254
210255pub 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),
212261 source_buffer: *std.ArrayList(u8),
213262 err: Error,
214263 source_manager: *ZigClangSourceManager,
......@@ -217,6 +266,7 @@ pub const Context = struct {
217266 global_scope: *Scope.Root,
218267 clang_context: *ZigClangASTContext,
219268 mangle_count: u32 = 0,
269 root_decls: std.ArrayListUnmanaged(*ast.Node),
220270
221271 /// This one is different than the root scope's name table. This contains
222272 /// a list of names that we found by visiting all the top level decls without
......@@ -229,13 +279,9 @@ pub const Context = struct {
229279 return c.mangle_count;
230280 }
231281
232 fn a(c: *Context) *mem.Allocator {
233 return &c.tree.arena_allocator.allocator;
234 }
235
236282 /// Convert a null-terminated C string to a slice allocated in the arena
237283 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));
239285 }
240286
241287 /// Convert a clang source location to a file:line:column string
......@@ -246,12 +292,52 @@ pub const Context = struct {
246292
247293 const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc);
248294 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;
250336 }
251337};
252338
253339pub fn translate(
254 backing_allocator: *mem.Allocator,
340 gpa: *mem.Allocator,
255341 args_begin: [*]?[*]const u8,
256342 args_end: [*]?[*]const u8,
257343 errors: *[]ClangErrMsg,
......@@ -269,47 +355,38 @@ pub fn translate(
269355 };
270356 defer ZigClangASTUnit_delete(ast_unit);
271357
272 const tree = blk: {
273 var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
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 };
358 var source_buffer = std.ArrayList(u8).init(gpa);
359 defer source_buffer.deinit();
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
301366 var context = Context{
302 .tree = tree,
367 .gpa = gpa,
368 .arena = &arena.allocator,
303369 .source_buffer = &source_buffer,
304370 .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),
305371 .err = undefined,
306 .decl_table = DeclTable.init(arena),
307 .alias_list = AliasList.init(arena),
308 .global_scope = try arena.create(Scope.Root),
372 .decl_table = DeclTable.init(gpa),
373 .alias_list = AliasList.init(gpa),
374 .global_scope = try arena.allocator.create(Scope.Root),
309375 .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 = .{},
311381 };
312382 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
314391 try prepopulateGlobalNameTable(ast_unit, &context);
315392
......@@ -320,23 +397,34 @@ pub fn translate(
320397 try transPreprocessorEntities(&context, ast_unit);
321398
322399 try addMacros(&context);
323 var it = context.alias_list.iterator(0);
324 while (it.next()) |alias| {
400 for (context.alias_list.items) |alias| {
325401 if (!context.global_scope.sym_table.contains(alias.alias)) {
326402 try createAlias(&context, alias);
327403 }
328404 }
329405
330 tree.root_node.eof_token = try appendToken(&context, .Eof, "");
331 tree.source = source_buffer.toOwnedSlice();
406 const eof_token = try appendToken(&context, .Eof, "");
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
332410 if (false) {
333 std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{tree.source});
334 var i: usize = 0;
335 while (i < tree.tokens.len) : (i += 1) {
336 const token = tree.tokens.at(i);
411 std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{source_buffer.items});
412 for (context.token_ids.items) |token| {
337413 std.debug.warn("{}\n", .{token});
338414 }
339415 }
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 };
340428 return tree;
341429}
342430
......@@ -490,42 +578,35 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
490578
491579 // actual function definition with body
492580 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();
494583 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);
499585 var param_id: c_uint = 0;
500 while (it.next()) |p| {
501 const param = @fieldParentPtr(ast.Node.ParamDecl, "base", p.*);
586 for (proto_node.params()) |*param, i| {
502587 const param_name = if (param.name_token) |name_tok|
503588 tokenSlice(c, name_tok)
504589 else if (param.param_type == .var_args) {
505 assert(it.next() == null);
506 _ = proto_node.params.pop();
590 assert(i + 1 == proto_node.params_len);
591 proto_node.params_len -= 1;
507592 break;
508593 } else
509594 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
513596 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
514597 const qual_type = ZigClangParmVarDecl_getOriginalType(c_param);
515598 const is_const = ZigClangQualType_isConstQualified(qual_type);
516599
517 const arg_name = blk: {
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 };
600 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
522601
523602 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);
524605 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);
525606 node.eq_token = try appendToken(c, .Equal, "=");
526607 node.init_node = try transCreateNodeIdentifier(c, arg_name);
527608 node.semicolon_token = try appendToken(c, .Semicolon, ";");
528 try block_node.statements.push(&node.base);
609 try block_scope.statements.append(&node.base);
529610 param.name_token = try appendIdentifier(c, arg_name);
530611 _ = try appendToken(c, .Colon, ":");
531612 }
......@@ -533,14 +614,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
533614 param_id += 1;
534615 }
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) {
537619 error.OutOfMemory => |e| return e,
538620 error.UnsupportedTranslation,
539621 error.UnsupportedType,
540622 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
541623 };
542 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
543 proto_node.body_node = &block_node.base;
624 const body_node = try block_scope.complete(rp.c);
625 proto_node.body_node = &body_node.base;
544626 return addTopLevelDecl(c, fn_name, &proto_node.base);
545627}
546628
......@@ -560,7 +642,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
560642
561643 // TODO https://github.com/ziglang/zig/issues/3756
562644 // 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;
564646 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
565647
566648 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
......@@ -620,7 +702,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
620702 _ = try appendToken(rp.c, .LParen, "(");
621703 const expr = try transCreateNodeStringLiteral(
622704 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]}),
624706 );
625707 _ = try appendToken(rp.c, .RParen, ")");
626708
......@@ -643,7 +725,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
643725 break :blk null;
644726 };
645727
646 const node = try c.a().create(ast.Node.VarDecl);
728 const node = try c.arena.create(ast.Node.VarDecl);
647729 node.* = .{
648730 .doc_comments = null,
649731 .visib_token = visib_tok,
......@@ -702,7 +784,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
702784
703785 // TODO https://github.com/ziglang/zig/issues/3756
704786 // 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;
706788 if (checkForBuiltinTypedef(checked_name)) |builtin| {
707789 return transTypeDefAsBuiltin(c, typedef_decl, builtin);
708790 }
......@@ -745,7 +827,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
745827 // Record declarations such as `struct {...} x` have no name but they're not
746828 // anonymous hence here isAnonymousStructOrUnion is not needed
747829 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()});
749831 is_unnamed = true;
750832 }
751833
......@@ -762,7 +844,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
762844 return null;
763845 }
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 });
766848 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
767849
768850 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
......@@ -785,15 +867,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
785867 const container_tok = try appendToken(c, container_kind, container_kind_name);
786868 const lbrace_token = try appendToken(c, .LBrace, "{");
787869
788 const container_node = try c.a().create(ast.Node.ContainerDecl);
789 container_node.* = .{
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 };
870 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
871 defer fields_and_decls.deinit();
797872
798873 var unnamed_field_count: u32 = 0;
799874 var it = ZigClangRecordDecl_field_begin(record_def);
......@@ -821,7 +896,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
821896 var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
822897 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) {
823898 // 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});
825900 unnamed_field_count += 1;
826901 is_anon = true;
827902 }
......@@ -851,7 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
851926 break :blk null;
852927 };
853928
854 const field_node = try c.a().create(ast.Node.ContainerField);
929 const field_node = try c.arena.create(ast.Node.ContainerField);
855930 field_node.* = .{
856931 .doc_comments = null,
857932 .comptime_token = null,
......@@ -868,10 +943,19 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
868943 );
869944 }
870945
871 try container_node.fields_and_decls.push(&field_node.base);
946 try fields_and_decls.append(&field_node.base);
872947 _ = try appendToken(c, .Comma, ",");
873948 }
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);
875959 semicolon = try appendToken(c, .Semicolon, ";");
876960 break :blk &container_node.base;
877961 };
......@@ -879,7 +963,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
879963
880964 try addTopLevelDecl(c, name, &node.base);
881965 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 });
883967 return transCreateNodeIdentifier(c, name);
884968}
885969
......@@ -892,11 +976,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
892976 var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl)));
893977 var is_unnamed = false;
894978 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()});
896980 is_unnamed = true;
897981 }
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});
900984 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
901985 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
902986 node.eq_token = try appendToken(c, .Equal, "=");
......@@ -916,15 +1000,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9161000 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
9171001 const container_tok = try appendToken(c, .Keyword_enum, "enum");
9181002
919 const container_node = try c.a().create(ast.Node.ContainerDecl);
920 container_node.* = .{
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 };
1003 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
1004 defer fields_and_decls.deinit();
9281005
9291006 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
9301007 // 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
9331010
9341011 // default to c_int since msvc and gcc default to different types
9351012 _ = try appendToken(c, .LParen, "(");
936 container_node.init_arg_expr = .{
1013 const init_arg_expr = ast.Node.ContainerDecl.InitArg{
9371014 .Type = if (int_type.ptr != null and
9381015 !isCBuiltinType(int_type, .UInt) and
9391016 !isCBuiltinType(int_type, .Int))
......@@ -949,7 +1026,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9491026 };
9501027 _ = try appendToken(c, .RParen, ")");
9511028
952 container_node.lbrace_token = try appendToken(c, .LBrace, "{");
1029 const lbrace_token = try appendToken(c, .LBrace, "{");
9531030
9541031 it = ZigClangEnumDecl_enumerator_begin(enum_def);
9551032 end_it = ZigClangEnumDecl_enumerator_end(enum_def);
......@@ -971,7 +1048,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9711048 } else
9721049 null;
9731050
974 const field_node = try c.a().create(ast.Node.ContainerField);
1051 const field_node = try c.arena.create(ast.Node.ContainerField);
9751052 field_node.* = .{
9761053 .doc_comments = null,
9771054 .comptime_token = null,
......@@ -981,32 +1058,32 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9811058 .align_expr = null,
9821059 };
9831060
984 try container_node.fields_and_decls.push(&field_node.base);
1061 try fields_and_decls.append(&field_node.base);
9851062 _ = try appendToken(c, .Comma, ",");
9861063
9871064 // In C each enum value is in the global namespace. So we put them there too.
9881065 // At this point we can rely on the enum emitting successfully.
9891066 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
9901067 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);
9921069 const enum_ident = try transCreateNodeIdentifier(c, name);
9931070 const period_tok = try appendToken(c, .Period, ".");
9941071 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);
9961073 field_access_node.* = .{
9971074 .op_token = period_tok,
9981075 .lhs = enum_ident,
9991076 .op = .Period,
10001077 .rhs = field_ident,
10011078 };
1002 try cast_node.params.push(&field_access_node.base);
1079 cast_node.params()[0] = &field_access_node.base;
10031080 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
10041081 tld_node.init_node = &cast_node.base;
10051082 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
10061083 try addTopLevelDecl(c, field_name, &tld_node.base);
10071084 }
10081085 // 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);
10101087 field_node.* = .{
10111088 .doc_comments = null,
10121089 .comptime_token = null,
......@@ -1016,10 +1093,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10161093 .align_expr = null,
10171094 };
10181095
1019 try container_node.fields_and_decls.push(&field_node.base);
1096 try fields_and_decls.append(&field_node.base);
10201097 _ = try appendToken(c, .Comma, ",");
1021 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
1022
1098 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
1099 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);
10231108 break :blk &container_node.base;
10241109 } else
10251110 try transCreateNodeOpaqueType(c);
......@@ -1028,7 +1113,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10281113
10291114 try addTopLevelDecl(c, name, &node.base);
10301115 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 });
10321117 return transCreateNodeIdentifier(c, name);
10331118}
10341119
......@@ -1071,7 +1156,7 @@ fn transStmt(
10711156 .ParenExprClass => {
10721157 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue);
10731158 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);
10751160 node.* = .{
10761161 .lparen = try appendToken(rp.c, .LParen, "("),
10771162 .expr = expr,
......@@ -1085,7 +1170,7 @@ fn transStmt(
10851170 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
10861171 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
10871172 .NullStmtClass => {
1088 const block = try transCreateNodeBlock(rp.c, null);
1173 const block = try rp.c.createBlock(null, 0);
10891174 block.rbrace = try appendToken(rp.c, .RBrace, "}");
10901175 return &block.base;
10911176 },
......@@ -1116,7 +1201,7 @@ fn transStmt(
11161201 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;
11171202 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);
11181203 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);
11201205 node.* = .{
11211206 .lparen = try appendToken(rp.c, .LParen, "("),
11221207 .expr = expr,
......@@ -1147,31 +1232,27 @@ fn transBinaryOperator(
11471232 var op_token: ast.TokenIndex = undefined;
11481233 var op_id: ast.Node.InfixOp.Op = undefined;
11491234 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)),
11511236 .Comma => {
11521237 const block_scope = try scope.findBlockScope(rp.c);
11531238 const expr = block_scope.base.parent == scope;
1154 const lparen = if (expr) blk: {
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;
1239 const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined;
11591240
11601241 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
11631244 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
11641245 if (expr) {
11651246 _ = 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);
11671248 break_node.rhs = rhs;
1168 try block_scope.block_node.statements.push(&break_node.base);
1169 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1249 try block_scope.statements.append(&break_node.base);
1250 const block_node = try block_scope.complete(rp.c);
11701251 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);
11721253 grouped_expr.* = .{
11731254 .lparen = lparen,
1174 .expr = &block_scope.block_node.base,
1255 .expr = &block_node.base,
11751256 .rparen = rparen,
11761257 };
11771258 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
......@@ -1182,11 +1263,11 @@ fn transBinaryOperator(
11821263 .Div => {
11831264 if (cIsSignedInteger(qt)) {
11841265 // signed integer division uses @divTrunc
1185 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
1186 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
1266 const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2);
1267 div_trunc_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
11871268 _ = try appendToken(rp.c, .Comma, ",");
11881269 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;
11901271 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
11911272 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
11921273 }
......@@ -1194,11 +1275,11 @@ fn transBinaryOperator(
11941275 .Rem => {
11951276 if (cIsSignedInteger(qt)) {
11961277 // signed integer division uses @rem
1197 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
1198 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
1278 const rem_node = try rp.c.createBuiltinCall("@rem", 2);
1279 rem_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
11991280 _ = try appendToken(rp.c, .Comma, ",");
12001281 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;
12021283 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
12031284 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
12041285 }
......@@ -1302,15 +1383,15 @@ fn transBinaryOperator(
13021383 const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
13031384
13041385 const lhs = if (isBoolRes(lhs_node)) init: {
1305 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1306 try cast_node.params.push(lhs_node);
1386 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1387 cast_node.params()[0] = lhs_node;
13071388 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
13081389 break :init &cast_node.base;
13091390 } else lhs_node;
13101391
13111392 const rhs = if (isBoolRes(rhs_node)) init: {
1312 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1313 try cast_node.params.push(rhs_node);
1393 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1394 cast_node.params()[0] = rhs_node;
13141395 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
13151396 break :init &cast_node.base;
13161397 } else rhs_node;
......@@ -1322,23 +1403,22 @@ fn transCompoundStmtInline(
13221403 rp: RestorePoint,
13231404 parent_scope: *Scope,
13241405 stmt: *const ZigClangCompoundStmt,
1325 block_node: *ast.Node.Block,
1406 block: *Scope.Block,
13261407) TransError!void {
13271408 var it = ZigClangCompoundStmt_body_begin(stmt);
13281409 const end_it = ZigClangCompoundStmt_body_end(stmt);
13291410 while (it != end_it) : (it += 1) {
13301411 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
1331 if (result != &block_node.base)
1332 try block_node.statements.push(result);
1412 try block.statements.append(result);
13331413 }
13341414}
13351415
13361416fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
1337 const block_scope = try Scope.Block.init(rp.c, scope, null);
1338 block_scope.block_node = try transCreateNodeBlock(rp.c, null);
1339 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
1340 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1341 return &block_scope.block_node.base;
1417 var block_scope = try Scope.Block.init(rp.c, scope, null);
1418 defer block_scope.deinit();
1419 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
1420 const node = try block_scope.complete(rp.c);
1421 return &node.base;
13421422}
13431423
13441424fn transCStyleCastExprClass(
......@@ -1360,77 +1440,83 @@ fn transCStyleCastExprClass(
13601440 return maybeSuppressResult(rp, scope, result_used, cast_node);
13611441}
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 {
13641444 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
13671507 var it = ZigClangDeclStmt_decl_begin(stmt);
13681508 const end_it = ZigClangDeclStmt_decl_end(stmt);
1369 while (it != end_it) : (it += 1) {
1370 switch (ZigClangDecl_getKind(it[0])) {
1371 .Var => {
1372 const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]);
1509 assert(it != end_it);
1510 while (true) : (it += 1) {
1511 const node = try transDeclStmtOne(rp, scope, it[0], block_scope);
13731512
1374 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
1375 null
1376 else
1377 try appendToken(c, .Keyword_threadlocal, "threadlocal");
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 ),
1513 if (it + 1 == end_it) {
1514 return node;
1515 } else {
1516 try block_scope.statements.append(node);
14311517 }
14321518 }
1433 return &block_scope.block_node.base;
1519 unreachable;
14341520}
14351521
14361522fn transDeclRefExpr(
......@@ -1458,7 +1544,7 @@ fn transImplicitCastExpr(
14581544 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {
14591545 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
14601546 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);
14621548 },
14631549 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {
14641550 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
......@@ -1480,8 +1566,8 @@ fn transImplicitCastExpr(
14801566 },
14811567 .PointerToBoolean => {
14821568 // @ptrToInt(val) != 0
1483 const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
1484 try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value));
1569 const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1);
1570 ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value);
14851571 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
14861572
14871573 const op_token = try appendToken(rp.c, .BangEqual, "!=");
......@@ -1539,7 +1625,7 @@ fn transBoolExpr(
15391625
15401626 if (grouped) {
15411627 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);
15431629 grouped_expr.* = .{
15441630 .lparen = lparen,
15451631 .expr = node,
......@@ -1705,13 +1791,11 @@ fn transIntegerLiteral(
17051791
17061792 // @as(T, x)
17071793 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);
17091795 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;
17111797 _ = try appendToken(rp.c, .Comma, ",");
1712
1713 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1714 try as_node.params.push(int_lit_node);
1798 as_node.params()[1] = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
17151799
17161800 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
17171801 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
......@@ -1747,13 +1831,13 @@ fn transStringLiteral(
17471831 len = 0;
17481832 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);
17511835 buf[0] = '"';
17521836 writeEscapedString(buf[1..], str);
17531837 buf[buf.len - 1] = '"';
17541838
17551839 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);
17571841 node.* = .{
17581842 .token = token,
17591843 };
......@@ -1821,35 +1905,35 @@ fn transCCast(
18211905 // 2. Bit-cast to correct signed-ness
18221906
18231907 // @bitCast(dest_type, intermediate_value)
1824 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
1825 try cast_node.params.push(try transQualType(rp, dst_type, loc));
1908 const cast_node = try rp.c.createBuiltinCall("@bitCast", 2);
1909 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
18261910 _ = try appendToken(rp.c, .Comma, ",");
18271911
18281912 switch (cIntTypeCmp(dst_type, src_type)) {
18291913 .lt => {
18301914 // @truncate(SameSignSmallerInt, src_type)
1831 const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate");
1915 const trunc_node = try rp.c.createBuiltinCall("@truncate", 2);
18321916 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;
18341918 _ = try appendToken(rp.c, .Comma, ",");
1835 try trunc_node.params.push(expr);
1919 trunc_node.params()[1] = expr;
18361920 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;
18391923 },
18401924 .gt => {
18411925 // @as(SameSignBiggerInt, src_type)
1842 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1926 const as_node = try rp.c.createBuiltinCall("@as", 2);
18431927 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;
18451929 _ = try appendToken(rp.c, .Comma, ",");
1846 try as_node.params.push(expr);
1930 as_node.params()[1] = expr;
18471931 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;
18501934 },
18511935 .eq => {
1852 try cast_node.params.push(expr);
1936 cast_node.params()[1] = expr;
18531937 },
18541938 }
18551939 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
......@@ -1857,46 +1941,46 @@ fn transCCast(
18571941 }
18581942 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
18591943 // @intCast(dest_type, @ptrToInt(val))
1860 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
1861 try cast_node.params.push(try transQualType(rp, dst_type, loc));
1944 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
1945 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
18621946 _ = try appendToken(rp.c, .Comma, ",");
1863 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
1864 try builtin_node.params.push(expr);
1947 const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
1948 builtin_node.params()[0] = expr;
18651949 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;
18671951 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18681952 return &cast_node.base;
18691953 }
18701954 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
18711955 // @intToPtr(dest_type, val)
1872 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");
1873 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1956 const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2);
1957 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
18741958 _ = try appendToken(rp.c, .Comma, ",");
1875 try builtin_node.params.push(expr);
1959 builtin_node.params()[1] = expr;
18761960 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18771961 return &builtin_node.base;
18781962 }
18791963 if (cIsFloating(src_type) and cIsFloating(dst_type)) {
1880 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast");
1881 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1964 const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2);
1965 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
18821966 _ = try appendToken(rp.c, .Comma, ",");
1883 try builtin_node.params.push(expr);
1967 builtin_node.params()[1] = expr;
18841968 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18851969 return &builtin_node.base;
18861970 }
18871971 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
1888 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt");
1889 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1972 const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2);
1973 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
18901974 _ = try appendToken(rp.c, .Comma, ",");
1891 try builtin_node.params.push(expr);
1975 builtin_node.params()[1] = expr;
18921976 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
18931977 return &builtin_node.base;
18941978 }
18951979 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
1896 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat");
1897 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1980 const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2);
1981 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
18981982 _ = try appendToken(rp.c, .Comma, ",");
1899 try builtin_node.params.push(expr);
1983 builtin_node.params()[1] = expr;
19001984 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19011985 return &builtin_node.base;
19021986 }
......@@ -1904,54 +1988,54 @@ fn transCCast(
19041988 !ZigClangType_isBooleanType(qualTypeCanon(dst_type)))
19051989 {
19061990 // @boolToInt returns either a comptime_int or a u1
1907 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1908 try builtin_node.params.push(expr);
1991 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1992 builtin_node.params()[0] = expr;
19091993 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19101994
1911 const inner_cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
1912 try inner_cast_node.params.push(try transCreateNodeIdentifier(rp.c, "u1"));
1995 const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2);
1996 inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1");
19131997 _ = try appendToken(rp.c, .Comma, ",");
1914 try inner_cast_node.params.push(&builtin_node.base);
1998 inner_cast_node.params()[1] = &builtin_node.base;
19151999 inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19162000
1917 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
1918 try cast_node.params.push(try transQualType(rp, dst_type, loc));
2001 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2002 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
19192003 _ = try appendToken(rp.c, .Comma, ",");
19202004
19212005 if (cIsSignedInteger(dst_type)) {
1922 const bitcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
1923 try bitcast_node.params.push(try transCreateNodeIdentifier(rp.c, "i1"));
2006 const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2);
2007 bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1");
19242008 _ = try appendToken(rp.c, .Comma, ",");
1925 try bitcast_node.params.push(&inner_cast_node.base);
2009 bitcast_node.params()[1] = &inner_cast_node.base;
19262010 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;
19282012 } else {
1929 try cast_node.params.push(&inner_cast_node.base);
2013 cast_node.params()[1] = &inner_cast_node.base;
19302014 }
19312015 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19322016
19332017 return &cast_node.base;
19342018 }
19352019 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) {
1936 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum");
1937 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
2020 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);
2021 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
19382022 _ = try appendToken(rp.c, .Comma, ",");
1939 try builtin_node.params.push(expr);
2023 builtin_node.params()[1] = expr;
19402024 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19412025 return &builtin_node.base;
19422026 }
19432027 if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and
19442028 ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum)
19452029 {
1946 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt");
1947 try builtin_node.params.push(expr);
2030 const builtin_node = try rp.c.createBuiltinCall("@enumToInt", 1);
2031 builtin_node.params()[0] = expr;
19482032 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19492033 return &builtin_node.base;
19502034 }
1951 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1952 try cast_node.params.push(try transQualType(rp, dst_type, loc));
2035 const cast_node = try rp.c.createBuiltinCall("@as", 2);
2036 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
19532037 _ = try appendToken(rp.c, .Comma, ",");
1954 try cast_node.params.push(expr);
2038 cast_node.params()[1] = expr;
19552039 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19562040 return &cast_node.base;
19572041}
......@@ -2014,7 +2098,10 @@ fn transInitListExprRecord(
20142098
20152099 const ty_node = try transType(rp, ty, loc);
20162100 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
20192106 var init_i: c_uint = 0;
20202107 var it = ZigClangRecordDecl_field_begin(record_def);
......@@ -2038,26 +2125,31 @@ fn transInitListExprRecord(
20382125 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
20392126 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
20402127 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);
20422129 }
20432130 const field_name_tok = try appendIdentifier(rp.c, raw_name);
20442131
20452132 _ = 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);
20482135 field_init_node.* = .{
20492136 .period_token = period_tok,
20502137 .name_token = field_name_tok,
20512138 .expr = try transExpr(rp, scope, elem_expr, .used, .r_value),
20522139 };
20532140
2054 try init_node.op.StructInitializer.push(&field_init_node.base);
2141 try field_inits.append(&field_init_node.base);
20552142 _ = try appendToken(rp.c, .Comma, ",");
20562143 }
20572144
2058 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
2059
2060 return &init_node.base;
2145 const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len);
2146 node.* = .{
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;
20612153}
20622154
20632155fn transCreateNodeArrayType(
......@@ -2100,7 +2192,7 @@ fn transInitListExprArray(
21002192 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
21012193 const leftover_count = all_count - init_count;
21022194
2103 var init_node: *ast.Node.SuffixOp = undefined;
2195 var init_node: *ast.Node.ArrayInitializer = undefined;
21042196 var cat_tok: ast.TokenIndex = undefined;
21052197 if (init_count != 0) {
21062198 const ty_node = try transCreateNodeArrayType(
......@@ -2109,11 +2201,19 @@ fn transInitListExprArray(
21092201 ZigClangQualType_getTypePtr(child_qt),
21102202 init_count,
21112203 );
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
21132213 var i: c_uint = 0;
21142214 while (i < init_count) : (i += 1) {
21152215 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);
21172217 _ = try appendToken(rp.c, .Comma, ",");
21182218 }
21192219 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
......@@ -2124,16 +2224,22 @@ fn transInitListExprArray(
21242224 }
21252225
21262226 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 };
21282234 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);
21302236 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
21312237
21322238 const rhs_node = if (leftover_count == 1)
21332239 &filler_init_node.base
21342240 else blk: {
21352241 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);
21372243 mul_node.* = .{
21382244 .op_token = mul_tok,
21392245 .lhs = &filler_init_node.base,
......@@ -2147,7 +2253,7 @@ fn transInitListExprArray(
21472253 return rhs_node;
21482254 }
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);
21512257 cat_node.* = .{
21522258 .op_token = cat_tok,
21532259 .lhs = &init_node.base,
......@@ -2266,11 +2372,15 @@ fn transIfStmt(
22662372 // if (c) t else e
22672373 const if_node = try transCreateNodeIf(rp.c);
22682374
2269 var cond_scope = Scope{
2270 .parent = scope,
2271 .id = .Condition,
2375 var cond_scope = Scope.Condition{
2376 .base = .{
2377 .parent = scope,
2378 .id = .Condition,
2379 },
22722380 };
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);
22742384 _ = try appendToken(rp.c, .RParen, ")");
22752385
22762386 if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);
......@@ -2290,11 +2400,15 @@ fn transWhileLoop(
22902400) TransError!*ast.Node {
22912401 const while_node = try transCreateNodeWhile(rp.c);
22922402
2293 var cond_scope = Scope{
2294 .parent = scope,
2295 .id = .Condition,
2403 var cond_scope = Scope.Condition{
2404 .base = .{
2405 .parent = scope,
2406 .id = .Condition,
2407 },
22962408 };
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);
22982412 _ = try appendToken(rp.c, .RParen, ")");
22992413
23002414 var loop_scope = Scope{
......@@ -2323,12 +2437,15 @@ fn transDoWhileLoop(
23232437
23242438 // if (!cond) break;
23252439 const if_node = try transCreateNodeIf(rp.c);
2326 var cond_scope = Scope{
2327 .parent = scope,
2328 .id = .Condition,
2440 var cond_scope = Scope.Condition{
2441 .base = .{
2442 .parent = scope,
2443 .id = .Condition,
2444 },
23292445 };
2446 defer cond_scope.deinit();
23302447 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);
23322449 _ = try appendToken(rp.c, .RParen, ")");
23332450 if_node.condition = &prefix_op.base;
23342451 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
......@@ -2345,7 +2462,8 @@ fn transDoWhileLoop(
23452462 // zig: b;
23462463 // zig: if (!cond) break;
23472464 // 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).?;
23492467 } else blk: {
23502468 // the C statement is without a block, so we need to create a block to contain it.
23512469 // c: do
......@@ -2356,12 +2474,15 @@ fn transDoWhileLoop(
23562474 // zig: if (!cond) break;
23572475 // zig: }
23582476 new = true;
2359 const block = try transCreateNodeBlock(rp.c, null);
2360 try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));
2477 const block = try rp.c.createBlock(null, 2);
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);
23612480 break :blk block;
23622481 };
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;
23652486 if (new)
23662487 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
23672488 while_node.body = &body_node.base;
......@@ -2378,24 +2499,26 @@ fn transForLoop(
23782499 .id = .Loop,
23792500 };
23802501
2381 var block_scope: ?*Scope.Block = null;
2502 var block_scope: ?Scope.Block = null;
2503 defer if (block_scope) |*bs| bs.deinit();
2504
23822505 if (ZigClangForStmt_getInit(stmt)) |init| {
23832506 block_scope = try Scope.Block.init(rp.c, scope, null);
2384 const block = try transCreateNodeBlock(rp.c, null);
2385 block_scope.?.block_node = block;
23862507 loop_scope.parent = &block_scope.?.base;
2387 const result = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
2388 if (result != &block.base)
2389 try block.statements.push(result);
2508 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
2509 try block_scope.?.statements.append(init_node);
23902510 }
2391 var cond_scope = Scope{
2392 .parent = scope,
2393 .id = .Condition,
2511 var cond_scope = Scope.Condition{
2512 .base = .{
2513 .parent = scope,
2514 .id = .Condition,
2515 },
23942516 };
2517 defer cond_scope.deinit();
23952518
23962519 const while_node = try transCreateNodeWhile(rp.c);
23972520 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)
23992522 else
24002523 try transCreateNodeBoolLiteral(rp.c, true);
24012524 _ = try appendToken(rp.c, .RParen, ")");
......@@ -2403,61 +2526,92 @@ fn transForLoop(
24032526 if (ZigClangForStmt_getInc(stmt)) |incr| {
24042527 _ = try appendToken(rp.c, .Colon, ":");
24052528 _ = 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);
24072530 _ = try appendToken(rp.c, .RParen, ")");
24082531 }
24092532
24102533 while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
2411 if (block_scope != null) {
2412 try block_scope.?.block_node.statements.push(&while_node.base);
2413 block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2414 return &block_scope.?.block_node.base;
2534 if (block_scope) |*bs| {
2535 try bs.statements.append(&while_node.base);
2536 const node = try bs.complete(rp.c);
2537 return &node.base;
24152538 } else {
24162539 _ = try appendToken(rp.c, .Semicolon, ";");
24172540 return &while_node.base;
24182541 }
24192542}
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
24212555fn transSwitch(
24222556 rp: RestorePoint,
24232557 scope: *Scope,
24242558 stmt: *const ZigClangSwitchStmt,
24252559) 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
24272584 var switch_scope = Scope.Switch{
24282585 .base = .{
24292586 .id = .Switch,
24302587 .parent = scope,
24312588 },
2432 .cases = &switch_node.cases,
2589 .cases = switch_node.cases(),
2590 .case_index = 0,
24332591 .pending_block = undefined,
24342592 };
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);
24462594 // tmp block that all statements will go before being picked up by a case or default
2447 const block = try transCreateNodeBlock(rp.c, null);
2448 block_scope.block_node = block;
2595 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
2596 defer block_scope.deinit();
24492597
2450 const switch_block = try transCreateNodeBlock(rp.c, null);
2451 try switch_block.statements.push(&switch_node.base);
2452 switch_scope.pending_block = switch_block;
2598 // Note that we do not defer a deinit here; the switch_scope.pending_block field
2599 // has its own memory management. This resource is freed inside `transCase` and
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
24542605 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
24552606 _ = try appendToken(rp.c, .Semicolon, ";");
24562607
24572608 // take all pending statements
2458 var it = last.cast(ast.Node.Block).?.statements.iterator(0);
2459 while (it.next()) |n| {
2460 try switch_scope.pending_block.statements.push(n.*);
2609 const last_block_stmts = last.cast(ast.Node.Block).?.statements();
2610 try switch_scope.pending_block.statements.ensureCapacity(
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);
24612615 }
24622616
24632617 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");
......@@ -2466,10 +2620,16 @@ fn transSwitch(
24662620 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
24672621 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;
24682622 _ = 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;
24702625 }
2471 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
2472 return &switch_scope.pending_block.base;
2626 // We overallocated in case there was no default, so now we correct
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;
24732633}
24742634
24752635fn transCase(
......@@ -2479,7 +2639,7 @@ fn transCase(
24792639) TransError!*ast.Node {
24802640 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
24812641 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)});
24832643 _ = try appendToken(rp.c, .Semicolon, ";");
24842644
24852645 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
......@@ -2487,7 +2647,7 @@ fn transCase(
24872647 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
24882648 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);
24912651 node.* = .{
24922652 .op_token = ellips,
24932653 .lhs = lhs_node,
......@@ -2501,22 +2661,21 @@ fn transCase(
25012661 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
25022662 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
25032663 _ = 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);
25072667 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
25082668 _ = 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
25122670 // take all pending statements
2513 var it = block_scope.block_node.statements.iterator(0);
2514 while (it.next()) |n| {
2515 try switch_scope.pending_block.statements.push(n.*);
2516 }
2517 block_scope.block_node.statements.shrink(0);
2671 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
2672 block_scope.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
25212680 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
25222681}
......@@ -2535,22 +2694,21 @@ fn transDefault(
25352694 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
25362695 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
25372696 _ = 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);
25412700 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
25422701 _ = 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
25462703 // take all pending statements
2547 var it = block_scope.block_node.statements.iterator(0);
2548 while (it.next()) |n| {
2549 try switch_scope.pending_block.statements.push(n.*);
2550 }
2551 block_scope.block_node.statements.shrink(0);
2704 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
2705 block_scope.statements.shrink(0);
2706
2707 const pending_node = try switch_scope.pending_block.complete(rp.c);
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;
25542712 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
25552713}
25562714
......@@ -2565,13 +2723,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr,
25652723 // See comment in `transIntegerLiteral` for why this code is here.
25662724 // @as(T, x)
25672725 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);
25692727 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;
25712729 _ = try appendToken(rp.c, .Comma, ",");
25722730
25732731 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
25762734 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
25772735
......@@ -2606,7 +2764,7 @@ fn transCharLiteral(
26062764 }
26072765 var char_buf: [4]u8 = undefined;
26082766 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);
26102768 node.* = .{
26112769 .token = token,
26122770 };
......@@ -2627,12 +2785,11 @@ fn transCharLiteral(
26272785 // See comment in `transIntegerLiteral` for why this code is here.
26282786 // @as(T, x)
26292787 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);
26312789 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;
26332791 _ = try appendToken(rp.c, .Comma, ",");
2634
2635 try as_node.params.push(int_lit_node);
2792 as_node.params()[1] = int_lit_node;
26362793
26372794 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
26382795 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
......@@ -2644,27 +2801,25 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
26442801 return transCompoundStmt(rp, scope, comp);
26452802 }
26462803 const lparen = try appendToken(rp.c, .LParen, "(");
2647 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2648 const block = try transCreateNodeBlock(rp.c, "blk");
2649 block_scope.block_node = block;
2804 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
2805 defer block_scope.deinit();
26502806
26512807 var it = ZigClangCompoundStmt_body_begin(comp);
26522808 const end_it = ZigClangCompoundStmt_body_end(comp);
26532809 while (it != end_it - 1) : (it += 1) {
26542810 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
2655 if (result != &block.base)
2656 try block.statements.push(result);
2811 try block_scope.statements.append(result);
26572812 }
26582813 const break_node = try transCreateNodeBreak(rp.c, "blk");
26592814 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
26602815 _ = try appendToken(rp.c, .Semicolon, ";");
2661 try block.statements.push(&break_node.base);
2662 block.rbrace = try appendToken(rp.c, .RBrace, "}");
2816 try block_scope.statements.append(&break_node.base);
2817 const block_node = try block_scope.complete(rp.c);
26632818 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);
26652820 grouped_expr.* = .{
26662821 .lparen = lparen,
2667 .expr = &block.base,
2822 .expr = &block_node.base,
26682823 .rparen = rparen,
26692824 };
26702825 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
......@@ -2686,7 +2841,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE
26862841 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);
26872842 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
26882843 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);
26902845 }
26912846 }
26922847 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);
......@@ -2720,12 +2875,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
27202875 const is_signed = cIsSignedInteger(qt);
27212876
27222877 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);
27242879 // check if long long first so that signed long long doesn't just become unsigned long long
27252880 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;
27272882 _ = 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);
27292884 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
27302885 node.rtoken = try appendToken(rp.c, .RBrace, "]");
27312886 node.op.ArrayAccess = &cast_node.base;
......@@ -2761,17 +2916,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr,
27612916 break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr);
27622917 } else
27632918 raw_fn_expr;
2764 const node = try transCreateNodeFnCall(rp.c, fn_expr);
27652919
27662920 const num_args = ZigClangCallExpr_getNumArgs(stmt);
2921 const node = try rp.c.createCall(fn_expr, num_args);
2922 const call_params = node.params();
2923
27672924 const args = ZigClangCallExpr_getArgs(stmt);
27682925 var i: usize = 0;
27692926 while (i < num_args) : (i += 1) {
27702927 if (i != 0) {
27712928 _ = try appendToken(rp.c, .Comma, ",");
27722929 }
2773 const arg = try transExpr(rp, scope, args[i], .used, .r_value);
2774 try node.op.Call.params.push(arg);
2930 call_params[i] = try transExpr(rp, scope, args[i], .used, .r_value);
27752931 }
27762932 node.rtoken = try appendToken(rp.c, .RParen, ")");
27772933
......@@ -2830,8 +2986,8 @@ fn transUnaryExprOrTypeTraitExpr(
28302986 ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt),
28312987 );
28322988
2833 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf");
2834 try builtin_node.params.push(type_node);
2989 const builtin_node = try rp.c.createBuiltinCall("@sizeOf", 1);
2990 builtin_node.params()[0] = type_node;
28352991 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
28362992 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
28372993}
......@@ -2940,8 +3096,8 @@ fn transCreatePreCrement(
29403096 // zig: _ref.* += 1;
29413097 // zig: break :blk _ref.*
29423098 // zig: })
2943 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2944 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
3099 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3100 defer block_scope.deinit();
29453101 const ref = try block_scope.makeMangledName(rp.c, "ref");
29463102
29473103 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
......@@ -2950,7 +3106,7 @@ fn transCreatePreCrement(
29503106 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
29513107 node.init_node = &rhs_node.base;
29523108 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
29553111 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
29563112 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
......@@ -2959,18 +3115,18 @@ fn transCreatePreCrement(
29593115 const one = try transCreateNodeInt(rp.c, 1);
29603116 _ = try appendToken(rp.c, .Semicolon, ";");
29613117 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);
29653121 break_node.rhs = ref_node;
2966 try block_scope.block_node.statements.push(&break_node.base);
2967 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3122 try block_scope.statements.append(&break_node.base);
3123 const block_node = try block_scope.complete(rp.c);
29683124 // semicolon must immediately follow rbrace because it is the last token in a block
29693125 _ = 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);
29713127 grouped_expr.* = .{
29723128 .lparen = try appendToken(rp.c, .LParen, "("),
2973 .expr = &block_scope.block_node.base,
3129 .expr = &block_node.base,
29743130 .rparen = try appendToken(rp.c, .RParen, ")"),
29753131 };
29763132 return &grouped_expr.base;
......@@ -3006,8 +3162,8 @@ fn transCreatePostCrement(
30063162 // zig: _ref.* += 1;
30073163 // zig: break :blk _tmp
30083164 // zig: })
3009 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
3010 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
3165 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3166 defer block_scope.deinit();
30113167 const ref = try block_scope.makeMangledName(rp.c, "ref");
30123168
30133169 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
......@@ -3016,7 +3172,7 @@ fn transCreatePostCrement(
30163172 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
30173173 node.init_node = &rhs_node.base;
30183174 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
30213177 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
30223178 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
......@@ -3027,23 +3183,23 @@ fn transCreatePostCrement(
30273183 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
30283184 tmp_node.init_node = ref_node;
30293185 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
30323188 const token = try appendToken(rp.c, op_tok_id, bytes);
30333189 const one = try transCreateNodeInt(rp.c, 1);
30343190 _ = try appendToken(rp.c, .Semicolon, ";");
30353191 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);
30393195 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);
30413197 _ = try appendToken(rp.c, .Semicolon, ";");
3042 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3043 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
3198 const block_node = try block_scope.complete(rp.c);
3199 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
30443200 grouped_expr.* = .{
30453201 .lparen = try appendToken(rp.c, .LParen, "("),
3046 .expr = &block_scope.block_node.base,
3202 .expr = &block_node.base,
30473203 .rparen = try appendToken(rp.c, .RParen, ")"),
30483204 };
30493205 return &grouped_expr.base;
......@@ -3106,13 +3262,13 @@ fn transCreateCompoundAssign(
31063262
31073263 if ((is_mod or is_div) and is_signed) {
31083264 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);
31103266 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);
31123268 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;
31143270 _ = 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);
31163272 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
31173273 op_node.* = .{
31183274 .op_token = op_token,
......@@ -3132,11 +3288,11 @@ fn transCreateCompoundAssign(
31323288 try transExpr(rp, scope, rhs, .used, .r_value);
31333289
31343290 if (is_shift) {
3135 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
3291 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
31363292 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;
31383294 _ = try appendToken(rp.c, .Comma, ",");
3139 try cast_node.params.push(rhs_node);
3295 cast_node.params()[1] = rhs_node;
31403296 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
31413297 rhs_node = &cast_node.base;
31423298 }
......@@ -3151,8 +3307,8 @@ fn transCreateCompoundAssign(
31513307 // zig: _ref.* = _ref.* + rhs;
31523308 // zig: break :blk _ref.*
31533309 // zig: })
3154 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
3155 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
3310 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3311 defer block_scope.deinit();
31563312 const ref = try block_scope.makeMangledName(rp.c, "ref");
31573313
31583314 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
......@@ -3161,7 +3317,7 @@ fn transCreateCompoundAssign(
31613317 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
31623318 node.init_node = &addr_node.base;
31633319 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
31663322 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
31673323 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
......@@ -3169,12 +3325,12 @@ fn transCreateCompoundAssign(
31693325
31703326 if ((is_mod or is_div) and is_signed) {
31713327 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);
31733329 const builtin = if (is_mod) "@rem" else "@divTrunc";
3174 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
3175 try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node));
3330 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3331 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);
31763332 _ = 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);
31783334 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
31793335 _ = try appendToken(rp.c, .Semicolon, ";");
31803336 op_node.* = .{
......@@ -3184,17 +3340,17 @@ fn transCreateCompoundAssign(
31843340 .rhs = &builtin_node.base,
31853341 };
31863342 _ = 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);
31883344 } else {
31893345 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
31903346 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
31913347
31923348 if (is_shift) {
3193 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
3349 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
31943350 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;
31963352 _ = try appendToken(rp.c, .Comma, ",");
3197 try cast_node.params.push(rhs_node);
3353 cast_node.params()[1] = rhs_node;
31983354 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
31993355 rhs_node = &cast_node.base;
32003356 }
......@@ -3204,17 +3360,17 @@ fn transCreateCompoundAssign(
32043360
32053361 const eq_token = try appendToken(rp.c, .Equal, "=");
32063362 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);
32083364 }
32093365
3210 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
3366 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
32113367 break_node.rhs = ref_node;
3212 try block_scope.block_node.statements.push(&break_node.base);
3213 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3214 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
3368 try block_scope.statements.append(&break_node.base);
3369 const block_node = try block_scope.complete(rp.c);
3370 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
32153371 grouped_expr.* = .{
32163372 .lparen = try appendToken(rp.c, .LParen, "("),
3217 .expr = &block_scope.block_node.base,
3373 .expr = &block_node.base,
32183374 .rparen = try appendToken(rp.c, .RParen, ")"),
32193375 };
32203376 return &grouped_expr.base;
......@@ -3238,43 +3394,43 @@ fn transCPtrCast(
32383394 !ZigClangQualType_isVolatileQualified(child_type)))
32393395 {
32403396 // 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);
32423398 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;
32443400 _ = try appendToken(rp.c, .Comma, ",");
32453401
3246 const ptrtoint_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
3247 try ptrtoint_node.params.push(expr);
3402 const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
3403 ptrtoint_node.params()[0] = expr;
32483404 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;
32513407 inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");
32523408 return &inttoptr_node.base;
32533409 } else {
32543410 // Implicit downcasting from higher to lower alignment values is forbidden,
32553411 // 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);
32573413 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;
32593415 _ = try appendToken(rp.c, .Comma, ",");
32603416
32613417 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
32623418 // void has 1-byte alignment, so @alignCast is not needed
3263 try ptrcast_node.params.push(expr);
3419 ptrcast_node.params()[1] = expr;
32643420 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {
32653421 // For opaque types a ptrCast is enough
3266 try ptrcast_node.params.push(expr);
3422 ptrcast_node.params()[1] = expr;
32673423 } else {
3268 const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");
3269 const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");
3424 const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2);
3425 const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1);
32703426 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;
32723428 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;
32743430 _ = try appendToken(rp.c, .Comma, ",");
3275 try aligncast_node.params.push(expr);
3431 aligncast_node.params()[1] = expr;
32763432 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;
32783434 }
32793435 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
32803436
......@@ -3295,7 +3451,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
32953451fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
32963452 // TODO use something more accurate
32973453 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);
32993455 node.* = .{
33003456 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
33013457 };
......@@ -3317,27 +3473,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
33173473 // })
33183474 const lparen = try appendToken(rp.c, .LParen, "(");
33193475
3320 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
3321 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
3476 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3477 defer block_scope.deinit();
33223478
33233479 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
33243480 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);
33253481 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");
33263482 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
33273483 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
33323488 const if_node = try transCreateNodeIf(rp.c);
3333 var cond_scope = Scope{
3334 .parent = &block_scope.base,
3335 .id = .Condition,
3489 var cond_scope = Scope.Condition{
3490 .base = .{
3491 .parent = &block_scope.base,
3492 .id = .Condition,
3493 },
33363494 };
3495 defer cond_scope.deinit();
33373496 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);
33383497
33393498 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);
33413500 if_node.condition = cond_node;
33423501 _ = try appendToken(rp.c, .RParen, ")");
33433502
......@@ -3348,13 +3507,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
33483507
33493508 break_node.rhs = &if_node.base;
33503509 _ = try appendToken(rp.c, .Semicolon, ";");
3351 try block_scope.block_node.statements.push(&break_node.base);
3352 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3510 try block_scope.statements.append(&break_node.base);
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);
33553514 grouped_expr.* = .{
33563515 .lparen = lparen,
3357 .expr = &block_scope.block_node.base,
3516 .expr = &block_node.base,
33583517 .rparen = try appendToken(rp.c, .RParen, ")"),
33593518 };
33603519 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
......@@ -3364,17 +3523,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
33643523 const grouped = scope.id == .Condition;
33653524 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
33663525 const if_node = try transCreateNodeIf(rp.c);
3367 var cond_scope = Scope{
3368 .parent = scope,
3369 .id = .Condition,
3526 var cond_scope = Scope.Condition{
3527 .base = .{
3528 .parent = scope,
3529 .id = .Condition,
3530 },
33703531 };
3532 defer cond_scope.deinit();
33713533
33723534 const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt);
33733535 const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt);
33743536 const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt);
33753537 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);
33783540 _ = try appendToken(rp.c, .RParen, ")");
33793541
33803542 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
33843546
33853547 if (grouped) {
33863548 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);
33883550 grouped_expr.* = .{
33893551 .lparen = lparen,
33903552 .expr = &if_node.base,
......@@ -3415,7 +3577,7 @@ fn maybeSuppressResult(
34153577 }
34163578 const lhs = try transCreateNodeIdentifier(rp.c, "_");
34173579 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);
34193581 op_node.* = .{
34203582 .op_token = op_token,
34213583 .lhs = lhs,
......@@ -3426,7 +3588,7 @@ fn maybeSuppressResult(
34263588}
34273589
34283590fn 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);
34303592 _ = try c.global_scope.sym_table.put(name, decl_node);
34313593}
34323594
......@@ -3524,7 +3686,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
35243686 if (int_bit_width != 0) {
35253687 // we can perform the log2 now.
35263688 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);
35283690 node.* = .{
35293691 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
35303692 };
......@@ -3545,19 +3707,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
35453707 // Symbol "Log2Int"
35463708 // 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);
35493711 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);
35513713 std_node.* = .{
35523714 .token = std_token,
35533715 };
3554 try import_fn_call.params.push(&std_node.base);
3716 import_fn_call.params()[0] = &std_node.base;
35553717 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
35563718
35573719 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
35583720 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
3559 const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access);
3560 try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node);
3721 const log2int_fn_call = try rp.c.createCall(outer_field_access, 1);
3722 log2int_fn_call.params()[0] = zig_type_node;
35613723 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
35623724
35633725 return &log2int_fn_call.base;
......@@ -3731,8 +3893,8 @@ fn transCreateNodeAssign(
37313893 const eq_token = try appendToken(rp.c, .Equal, "=");
37323894 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
37333895 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3734 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
3735 try builtin_node.params.push(rhs_node);
3896 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3897 builtin_node.params()[0] = rhs_node;
37363898 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
37373899 rhs_node = &builtin_node.base;
37383900 }
......@@ -3748,22 +3910,24 @@ fn transCreateNodeAssign(
37483910 // zig: lhs = _tmp;
37493911 // zig: break :blk _tmp
37503912 // zig: })
3751 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
3752 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
3913 const label_name = "blk";
3914 var block_scope = try Scope.Block.init(rp.c, scope, label_name);
3915 defer block_scope.deinit();
3916
37533917 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
37543918
37553919 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
37563920 node.eq_token = try appendToken(rp.c, .Equal, "=");
37573921 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
37583922 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3759 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
3760 try builtin_node.params.push(rhs_node);
3923 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3924 builtin_node.params()[0] = rhs_node;
37613925 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
37623926 rhs_node = &builtin_node.base;
37633927 }
37643928 node.init_node = rhs_node;
37653929 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
37683932 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
37693933 const eq_token = try appendToken(rp.c, .Equal, "=");
......@@ -3771,48 +3935,20 @@ fn transCreateNodeAssign(
37713935 _ = try appendToken(rp.c, .Semicolon, ";");
37723936
37733937 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);
37773941 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
37783942 _ = try appendToken(rp.c, .Semicolon, ";");
3779 try block_scope.block_node.statements.push(&break_node.base);
3780 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3943 try block_scope.statements.append(&break_node.base);
3944 const block_node = try block_scope.complete(rp.c);
37813945 // semicolon must immediately follow rbrace because it is the last token in a block
37823946 _ = try appendToken(rp.c, .Semicolon, ";");
3783 return &block_scope.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;
3947 return &block_node.base;
38123948}
38133949
38143950fn 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);
38163952 field_access_node.* = .{
38173953 .op_token = try appendToken(c, .Period, "."),
38183954 .lhs = container,
......@@ -3828,7 +3964,7 @@ fn transCreateNodePrefixOp(
38283964 op_tok_id: std.zig.Token.Id,
38293965 bytes: []const u8,
38303966) !*ast.Node.PrefixOp {
3831 const node = try c.a().create(ast.Node.PrefixOp);
3967 const node = try c.arena.create(ast.Node.PrefixOp);
38323968 node.* = .{
38333969 .op_token = try appendToken(c, op_tok_id, bytes),
38343970 .op = op,
......@@ -3851,7 +3987,7 @@ fn transCreateNodeInfixOp(
38513987 try appendToken(rp.c, .LParen, "(")
38523988 else
38533989 null;
3854 const node = try rp.c.a().create(ast.Node.InfixOp);
3990 const node = try rp.c.arena.create(ast.Node.InfixOp);
38553991 node.* = .{
38563992 .op_token = op_token,
38573993 .lhs = lhs_node,
......@@ -3860,7 +3996,7 @@ fn transCreateNodeInfixOp(
38603996 };
38613997 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
38623998 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);
38644000 grouped_expr.* = .{
38654001 .lparen = lparen.?,
38664002 .expr = &node.base,
......@@ -3904,7 +4040,7 @@ fn transCreateNodePtrType(
39044040 is_volatile: bool,
39054041 op_tok_id: std.zig.Token.Id,
39064042) !*ast.Node.PrefixOp {
3907 const node = try c.a().create(ast.Node.PrefixOp);
4043 const node = try c.arena.create(ast.Node.PrefixOp);
39084044 const op_token = switch (op_tok_id) {
39094045 .LBracket => blk: {
39104046 const lbracket = try appendToken(c, .LBracket, "[");
......@@ -3946,8 +4082,8 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39464082 ZigClangAPSInt_free(aps_int);
39474083 };
39484084
3949 const limbs = try c.a().alloc(math.big.Limb, num_limbs);
3950 defer c.a().free(limbs);
4085 const limbs = try c.arena.alloc(math.big.Limb, num_limbs);
4086 defer c.arena.free(limbs);
39514087
39524088 const data = ZigClangAPSInt_getRawData(aps_int);
39534089 switch (@sizeOf(math.big.Limb)) {
......@@ -3972,12 +4108,12 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39724108 }
39734109
39744110 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) {
39764112 error.OutOfMemory => return error.OutOfMemory,
39774113 };
3978 defer c.a().free(str);
4114 defer c.arena.free(str);
39794115 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);
39814117 node.* = .{
39824118 .token = token,
39834119 };
......@@ -3986,7 +4122,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39864122
39874123fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
39884124 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);
39904126 node.* = .{
39914127 .ltoken = ltoken,
39924128 .kind = .Return,
......@@ -3997,7 +4133,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
39974133
39984134fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
39994135 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);
40014137 node.* = .{
40024138 .token = token,
40034139 };
......@@ -4006,7 +4142,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
40064142
40074143fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
40084144 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);
40104146 node.* = .{
40114147 .token = token,
40124148 };
......@@ -4018,42 +4154,16 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
40184154 try appendToken(c, .Keyword_true, "true")
40194155 else
40204156 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);
40224158 node.* = .{
40234159 .token = token,
40244160 };
40254161 return &node.base;
40264162}
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
40544164fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
40554165 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);
40574167 node.* = .{
40584168 .token = token,
40594169 };
......@@ -4062,7 +4172,7 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
40624172
40634173fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
40644174 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);
40664176 node.* = .{
40674177 .token = token,
40684178 };
......@@ -4070,8 +4180,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
40704180}
40714181
40724182fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
4073 const call_node = try transCreateNodeBuiltinFnCall(c, "@Type");
4074 try call_node.params.push(try transCreateNodeEnumLiteral(c, "Opaque"));
4183 const call_node = try c.createBuiltinCall("@Type", 1);
4184 call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque");
40754185 call_node.rparen_token = try appendToken(c, .RParen, ")");
40764186 return &call_node.base;
40774187}
......@@ -4085,39 +4195,36 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
40854195 const name_tok = try appendIdentifier(c, name);
40864196 _ = try appendToken(c, .LParen, "(");
40874197
4088 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
4089 var it = proto_alias.params.iterator(0);
4090 while (it.next()) |pn| {
4091 if (it.index != 0) {
4198 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
4199 defer fn_params.deinit();
4200
4201 for (proto_alias.params()) |param, i| {
4202 if (i != 0) {
40924203 _ = try appendToken(c, .Comma, ",");
40934204 }
4094 const param = pn.*.cast(ast.Node.ParamDecl).?;
4095
40964205 const param_name_tok = param.name_token orelse
40974206 try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()});
40984207
40994208 _ = try appendToken(c, .Colon, ":");
41004209
4101 const param_node = try c.a().create(ast.Node.ParamDecl);
4102 param_node.* = .{
4210 (try fn_params.addOne()).* = .{
41034211 .doc_comments = null,
41044212 .comptime_token = null,
41054213 .noalias_token = param.noalias_token,
41064214 .name_token = param_name_tok,
41074215 .param_type = param.param_type,
41084216 };
4109 try fn_params.push(&param_node.base);
41104217 }
41114218
41124219 _ = 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);
41154222 fn_proto.* = .{
41164223 .doc_comments = null,
41174224 .visib_token = pub_tok,
41184225 .fn_token = fn_tok,
41194226 .name_token = name_tok,
4120 .params = fn_params,
4227 .params_len = fn_params.items.len,
41214228 .return_type = proto_alias.return_type,
41224229 .var_args_token = null,
41234230 .extern_export_inline_token = inline_tok,
......@@ -4127,26 +4234,35 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
41274234 .section_expr = null,
41284235 .callconv_expr = null,
41294236 };
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
41334241 const return_expr = try transCreateNodeReturnExpr(c);
41344242 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
4135 const call_expr = try transCreateNodeFnCall(c, unwrap_expr);
4136 it = fn_params.iterator(0);
4137 while (it.next()) |pn| {
4138 if (it.index != 0) {
4243
4244 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
4245 const call_params = call_expr.params();
4246
4247 for (fn_params.items) |param, i| {
4248 if (i != 0) {
41394249 _ = try appendToken(c, .Comma, ",");
41404250 }
4141 const param = pn.*.cast(ast.Node.ParamDecl).?;
4142 try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)));
4251 call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?));
41434252 }
41444253 call_expr.rtoken = try appendToken(c, .RParen, ")");
4254
41454255 return_expr.rhs = &call_expr.base;
41464256 _ = try appendToken(c, .Semicolon, ";");
41474257
4148 block.rbrace = try appendToken(c, .RBrace, "}");
4149 try block.statements.push(&return_expr.base);
4258 const block = try ast.Node.Block.alloc(c.arena, 1);
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;
41504266 fn_proto.body_node = &block.base;
41514267 return &fn_proto.base;
41524268}
......@@ -4154,17 +4270,17 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
41544270fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
41554271 _ = try appendToken(c, .Period, ".");
41564272 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);
41584274 node.* = .{
41594275 .op = .UnwrapOptional,
4160 .lhs = .{ .node = wrapped },
4276 .lhs = wrapped,
41614277 .rtoken = qm,
41624278 };
41634279 return &node.base;
41644280}
41654281
41664282fn 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);
41684284 node.* = .{
41694285 .dot = try appendToken(c, .Period, "."),
41704286 .name = try appendIdentifier(c, name),
......@@ -4173,7 +4289,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
41734289}
41744290
41754291fn 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);
41774293 node.* = .{
41784294 .token = try appendToken(c, .StringLiteral, str),
41794295 };
......@@ -4183,7 +4299,7 @@ fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
41834299fn transCreateNodeIf(c: *Context) !*ast.Node.If {
41844300 const if_tok = try appendToken(c, .Keyword_if, "if");
41854301 _ = try appendToken(c, .LParen, "(");
4186 const node = try c.a().create(ast.Node.If);
4302 const node = try c.arena.create(ast.Node.If);
41874303 node.* = .{
41884304 .if_token = if_tok,
41894305 .condition = undefined,
......@@ -4195,7 +4311,7 @@ fn transCreateNodeIf(c: *Context) !*ast.Node.If {
41954311}
41964312
41974313fn 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);
41994315 node.* = .{
42004316 .else_token = try appendToken(c, .Keyword_else, "else"),
42014317 .payload = null,
......@@ -4204,20 +4320,11 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
42044320 return node;
42054321}
42064322
4207fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {
4208 const label_node = if (label) |l| blk: {
4209 const ll = try appendIdentifier(c, l);
4210 _ = try appendToken(c, .Colon, ":");
4211 break :blk ll;
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;
4323fn transCreateNodeBreakToken(c: *Context, label: ?ast.TokenIndex) !*ast.Node.ControlFlowExpression {
4324 const other_token = label orelse return transCreateNodeBreak(c, null);
4325 const loc = c.token_locs.items[other_token];
4326 const label_name = c.source_buffer.items[loc.start..loc.end];
4327 return transCreateNodeBreak(c, label_name);
42214328}
42224329
42234330fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {
......@@ -4226,7 +4333,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
42264333 _ = try appendToken(c, .Colon, ":");
42274334 break :blk try transCreateNodeIdentifier(c, l);
42284335 } else null;
4229 const node = try c.a().create(ast.Node.ControlFlowExpression);
4336 const node = try c.arena.create(ast.Node.ControlFlowExpression);
42304337 node.* = .{
42314338 .ltoken = ltoken,
42324339 .kind = .{ .Break = label_node },
......@@ -4240,7 +4347,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con
42404347 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
42414348 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);
42444351 node.* = .{
42454352 .doc_comments = null,
42464353 .visib_token = visib_tok,
......@@ -4264,7 +4371,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
42644371 const while_tok = try appendToken(c, .Keyword_while, "while");
42654372 _ = 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);
42684375 node.* = .{
42694376 .label = null,
42704377 .inline_token = null,
......@@ -4280,7 +4387,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
42804387
42814388fn transCreateNodeContinue(c: *Context) !*ast.Node {
42824389 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);
42844391 node.* = .{
42854392 .ltoken = ltoken,
42864393 .kind = .{ .Continue = null },
......@@ -4290,36 +4397,22 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node {
42904397 return &node.base;
42914398}
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
43074400fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase {
43084401 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);
43114404 node.* = .{
4312 .items = ast.Node.SwitchCase.ItemList.init(c.a()),
4405 .items_len = 1,
43134406 .arrow_token = arrow_tok,
43144407 .payload = null,
43154408 .expr = undefined,
43164409 };
4317 try node.items.push(lhs);
4410 node.items()[0] = lhs;
43184411 return node;
43194412}
43204413
43214414fn 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);
43234416 node.* = .{
43244417 .token = try appendToken(c, .Keyword_else, "else"),
43254418 };
......@@ -4344,15 +4437,15 @@ fn transCreateNodeShiftOp(
43444437 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
43454438 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);
43484441 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;
43504443 _ = try appendToken(rp.c, .Comma, ",");
43514444 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
4352 try cast_node.params.push(rhs);
4445 cast_node.params()[1] = rhs;
43534446 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);
43564449 node.* = .{
43574450 .op_token = op_token,
43584451 .lhs = lhs,
......@@ -4364,9 +4457,9 @@ fn transCreateNodeShiftOp(
43644457}
43654458
43664459fn 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);
43684461 node.* = .{
4369 .lhs = .{ .node = lhs },
4462 .lhs = lhs,
43704463 .op = .Deref,
43714464 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
43724465 };
......@@ -4375,9 +4468,9 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
43754468
43764469fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {
43774470 _ = try appendToken(c, .LBrace, "[");
4378 const node = try c.a().create(ast.Node.SuffixOp);
4471 const node = try c.arena.create(ast.Node.SuffixOp);
43794472 node.* = .{
4380 .lhs = .{ .node = lhs },
4473 .lhs = lhs,
43814474 .op = .{
43824475 .ArrayAccess = undefined,
43834476 },
......@@ -4392,7 +4485,8 @@ const RestorePoint = struct {
43924485 src_buf_index: usize,
43934486
43944487 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);
43964490 self.c.source_buffer.shrink(self.src_buf_index);
43974491 }
43984492};
......@@ -4400,7 +4494,7 @@ const RestorePoint = struct {
44004494fn makeRestorePoint(c: *Context) RestorePoint {
44014495 return RestorePoint{
44024496 .c = c,
4403 .token_index = c.tree.tokens.len,
4497 .token_index = c.token_ids.items.len,
44044498 .src_buf_index = c.source_buffer.items.len,
44054499 };
44064500}
......@@ -4647,8 +4741,10 @@ fn finishTransFnProto(
46474741 const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
46484742 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();
46514746 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
46534749 var i: usize = 0;
46544750 while (i < param_count) : (i += 1) {
......@@ -4672,15 +4768,13 @@ fn finishTransFnProto(
46724768
46734769 const type_node = try transQualType(rp, param_qt, source_loc);
46744770
4675 const param_node = try rp.c.a().create(ast.Node.ParamDecl);
4676 param_node.* = .{
4771 fn_params.addOneAssumeCapacity().* = .{
46774772 .doc_comments = null,
46784773 .comptime_token = null,
46794774 .noalias_token = noalias_tok,
46804775 .name_token = param_name_tok,
46814776 .param_type = .{ .type_expr = type_node },
46824777 };
4683 try fn_params.push(&param_node.base);
46844778
46854779 if (i + 1 < param_count) {
46864780 _ = try appendToken(rp.c, .Comma, ",");
......@@ -4692,15 +4786,13 @@ fn finishTransFnProto(
46924786 _ = try appendToken(rp.c, .Comma, ",");
46934787 }
46944788
4695 const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl);
4696 var_arg_node.* = .{
4789 fn_params.addOneAssumeCapacity().* = .{
46974790 .doc_comments = null,
46984791 .comptime_token = null,
46994792 .noalias_token = null,
47004793 .name_token = null,
47014794 .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") }
47024795 };
4703 try fn_params.push(&var_arg_node.base);
47044796 }
47054797
47064798 const rparen_tok = try appendToken(rp.c, .RParen, ")");
......@@ -4713,7 +4805,7 @@ fn finishTransFnProto(
47134805 _ = try appendToken(rp.c, .LParen, "(");
47144806 const expr = try transCreateNodeStringLiteral(
47154807 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]}),
47174809 );
47184810 _ = try appendToken(rp.c, .RParen, ")");
47194811
......@@ -4767,13 +4859,13 @@ fn finishTransFnProto(
47674859 }
47684860 };
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);
47714863 fn_proto.* = .{
47724864 .doc_comments = null,
47734865 .visib_token = pub_tok,
47744866 .fn_token = fn_tok,
47754867 .name_token = name_tok,
4776 .params = fn_params,
4868 .params_len = fn_params.items.len,
47774869 .return_type = .{ .Explicit = return_type_node },
47784870 .var_args_token = null, // TODO this field is broken in the AST data model
47794871 .extern_export_inline_token = extern_export_inline_tok,
......@@ -4783,6 +4875,7 @@ fn finishTransFnProto(
47834875 .section_expr = linksection_expr,
47844876 .callconv_expr = callconv_expr,
47854877 };
4878 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
47864879 return fn_proto;
47874880}
47884881
......@@ -4816,20 +4909,20 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
48164909 const semi_tok = try appendToken(c, .Semicolon, ";");
48174910 _ = 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);
48204913 msg_node.* = .{
48214914 .token = msg_tok,
48224915 };
48234916
4824 const call_node = try c.a().create(ast.Node.BuiltinCall);
4917 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
48254918 call_node.* = .{
48264919 .builtin_token = builtin_tok,
4827 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
4920 .params_len = 1,
48284921 .rparen_token = rparen_tok,
48294922 };
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);
48334926 var_decl_node.* = .{
48344927 .doc_comments = null,
48354928 .visib_token = pub_tok,
......@@ -4856,23 +4949,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd
48564949
48574950fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex {
48584951 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);
4863 const end_index = c.source_buffer.items.len;
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);
4953 try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1);
4954 try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1);
48674955
4868 new_token.* = .{
4869 .id = token_id,
4956 const start_index = c.source_buffer.items.len;
4957 try c.source_buffer.outStream().print(format ++ " ", args);
4958
4959 c.token_ids.appendAssumeCapacity(token_id);
4960 c.token_locs.appendAssumeCapacity(.{
48704961 .start = start_index,
4871 .end = end_index,
4872 };
4873 try c.source_buffer.append(' ');
4962 .end = c.source_buffer.items.len - 1, // back up before the space
4963 });
48744964
4875 return token_index;
4965 return c.token_ids.items.len - 1;
48764966}
48774967
48784968// TODO hook up with codegen
......@@ -4931,7 +5021,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
49315021
49325022fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
49335023 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);
49355025 identifier.* = .{
49365026 .token = token_index,
49375027 };
......@@ -4940,7 +5030,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
49405030
49415031fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
49425032 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);
49445034 identifier.* = .{
49455035 .token = token_index,
49465036 };
......@@ -4955,7 +5045,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
49555045 // TODO if we see #undef, delete it from the table
49565046 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
49575047 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
4958 var tok_list = CTokenList.init(c.a());
5048 var tok_list = CTokenList.init(c.arena);
49595049 const scope = c.global_scope;
49605050
49615051 while (it.I != it_end.I) : (it.I += 1) {
......@@ -4970,7 +5060,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
49705060 const name = try c.str(raw_name);
49715061 // TODO https://github.com/ziglang/zig/issues/3756
49725062 // 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;
49745064 if (scope.containsNow(mangled_name)) {
49755065 continue;
49765066 }
......@@ -5060,7 +5150,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
50605150}
50615151
50625152fn 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();
50645155 const scope = &block_scope.base;
50655156
50665157 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
......@@ -5078,7 +5169,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
50785169 .{},
50795170 );
50805171 }
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
50825176 while (true) {
50835177 const param_tok = it.next().?;
50845178 if (param_tok.id != .Identifier) {
......@@ -5096,20 +5190,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
50965190 _ = try appendToken(c, .Colon, ":");
50975191
50985192 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);
51005194 identifier.* = .{
51015195 .token = token_index,
51025196 };
51035197
5104 const param_node = try c.a().create(ast.Node.ParamDecl);
5105 param_node.* = .{
5198 (try fn_params.addOne()).* = .{
51065199 .doc_comments = null,
51075200 .comptime_token = null,
51085201 .noalias_token = null,
51095202 .name_token = param_name_tok,
51105203 .param_type = .{ .type_expr = &identifier.base },
51115204 };
5112 try fn_params.push(&param_node.base);
51135205
51145206 if (it.peek().?.id != .Comma)
51155207 break;
......@@ -5129,16 +5221,15 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
51295221
51305222 _ = try appendToken(c, .RParen, ")");
51315223
5132 const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
5133 type_of.rparen_token = try appendToken(c, .RParen, ")");
5224 const type_of = try c.createBuiltinCall("@TypeOf", 1);
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);
51365227 fn_proto.* = .{
51375228 .visib_token = pub_tok,
51385229 .extern_export_inline_token = inline_tok,
51395230 .fn_token = fn_tok,
51405231 .name_token = name_tok,
5141 .params = fn_params,
5232 .params_len = fn_params.items.len,
51425233 .return_type = .{ .Explicit = &type_of.base },
51435234 .doc_comments = null,
51445235 .var_args_token = null,
......@@ -5148,8 +5239,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
51485239 .section_expr = null,
51495240 .callconv_expr = null,
51505241 };
5151
5152 const block = try transCreateNodeBlock(c, null);
5242 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
51535243
51545244 const return_expr = try transCreateNodeReturnExpr(c);
51555245 const expr = try parseCExpr(c, it, source, source_loc, scope);
......@@ -5165,17 +5255,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
51655255 _ = try appendToken(c, .Semicolon, ";");
51665256 const type_of_arg = if (expr.id != .Block) expr else blk: {
51675257 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];
51695259 std.debug.assert(blk_last.id == .ControlFlowExpression);
51705260 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);
51715261 break :blk br.rhs.?;
51725262 };
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, ")");
51745265 return_expr.rhs = expr;
51755266
5176 block.rbrace = try appendToken(c, .RBrace, "}");
5177 try block.statements.push(&return_expr.base);
5178 fn_proto.body_node = &block.base;
5267 try block_scope.statements.append(&return_expr.base);
5268 const block_node = try block_scope.complete(c);
5269 fn_proto.body_node = &block_node.base;
51795270 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
51805271}
51815272
......@@ -5207,22 +5298,23 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
52075298 },
52085299 .Comma => {
52095300 _ = try appendToken(c, .Semicolon, ";");
5210 const block_scope = try Scope.Block.init(c, scope, "blk");
5211 block_scope.block_node = try transCreateNodeBlock(c, block_scope.label);
5301 const label_name = "blk";
5302 var block_scope = try Scope.Block.init(c, scope, label_name);
5303 defer block_scope.deinit();
52125304
52135305 var last = node;
52145306 while (true) {
52155307 // suppress result
52165308 const lhs = try transCreateNodeIdentifier(c, "_");
52175309 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);
52195311 op_node.* = .{
52205312 .op_token = op_token,
52215313 .lhs = lhs,
52225314 .op = .Assign,
52235315 .rhs = last,
52245316 };
5225 try block_scope.block_node.statements.push(&op_node.base);
5317 try block_scope.statements.append(&op_node.base);
52265318
52275319 last = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
52285320 _ = try appendToken(c, .Semicolon, ";");
......@@ -5232,11 +5324,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
52325324 }
52335325 }
52345326
5235 const break_node = try transCreateNodeBreak(c, block_scope.label);
5327 const break_node = try transCreateNodeBreak(c, label_name);
52365328 break_node.rhs = last;
5237 try block_scope.block_node.statements.push(&break_node.base);
5238 block_scope.block_node.rbrace = try appendToken(c, .RBrace, "}");
5239 return &block_scope.block_node.base;
5329 try block_scope.statements.append(&break_node.base);
5330 const block_node = try block_scope.complete(c);
5331 return &block_node.base;
52405332 },
52415333 else => {
52425334 _ = it.prev();
......@@ -5253,11 +5345,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
52535345 switch (lit_bytes[1]) {
52545346 '0'...'7' => {
52555347 // 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});
52575349 },
52585350 'X' => {
52595351 // 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..]});
52615353 },
52625354 else => {},
52635355 }
......@@ -5267,15 +5359,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
52675359 return transCreateNodeInt(c, lit_bytes);
52685360 }
52695361
5270 const cast_node = try transCreateNodeBuiltinFnCall(c, "@as");
5271 try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) {
5362 const cast_node = try c.createBuiltinCall("@as", 2);
5363 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) {
52725364 .U => "c_uint",
52735365 .L => "c_long",
52745366 .LU => "c_ulong",
52755367 .LL => "c_longlong",
52765368 .LLU => "c_ulonglong",
52775369 else => unreachable,
5278 }));
5370 });
52795371 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) {
52805372 .U, .L => @as(u8, 1),
52815373 .LU, .LL => 2,
......@@ -5283,23 +5375,23 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
52835375 else => unreachable,
52845376 }];
52855377 _ = 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);
52875379 cast_node.rparen_token = try appendToken(c, .RParen, ")");
52885380 return &cast_node.base;
52895381 } else if (tok.id == .FloatLiteral) {
52905382 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});
52925384 if (tok.id.FloatLiteral == .None) {
52935385 return transCreateNodeFloat(c, lit_bytes);
52945386 }
5295 const cast_node = try transCreateNodeBuiltinFnCall(c, "@as");
5296 try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) {
5387 const cast_node = try c.createBuiltinCall("@as", 2);
5388 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) {
52975389 .F => "f32",
52985390 .L => "c_longdouble",
52995391 else => unreachable,
5300 }));
5392 });
53015393 _ = 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]);
53035395 cast_node.rparen_token = try appendToken(c, .RParen, ")");
53045396 return &cast_node.base;
53055397 } else unreachable;
......@@ -5318,7 +5410,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
53185410 break;
53195411 }
53205412 } 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);
53225414 var state: enum {
53235415 Start,
53245416 Escape,
......@@ -5472,14 +5564,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
54725564 const first_tok = it.list.at(0);
54735565 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {
54745566 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);
54765568 node.* = .{
54775569 .token = token,
54785570 };
54795571 return &node.base;
54805572 } else {
54815573 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);
54835575 node.* = .{
54845576 .token = token,
54855577 };
......@@ -5489,7 +5581,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
54895581 .StringLiteral => {
54905582 const first_tok = it.list.at(0);
54915583 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);
54935585 node.* = .{
54945586 .token = token,
54955587 };
......@@ -5569,10 +5661,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
55695661 //else
55705662 // @as(dest, x) )
55715663 const if_node = try transCreateNodeIf(c);
5572 const type_info_node = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
5573 try type_info_node.params.push(inner_node);
5664 const type_info_node = try c.createBuiltinCall("@typeInfo", 1);
5665 type_info_node.params()[0] = inner_node;
55745666 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);
55765668 cmp_node.* = .{
55775669 .op_token = try appendToken(c, .EqualEqual, "=="),
55785670 .lhs = &type_info_node.base,
......@@ -5582,22 +5674,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
55825674 if_node.condition = &cmp_node.base;
55835675 _ = try appendToken(c, .RParen, ")");
55845676
5585 const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr");
5586 try int_to_ptr.params.push(inner_node);
5587 try int_to_ptr.params.push(node_to_cast);
5677 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5678 int_to_ptr.params()[0] = inner_node;
5679 int_to_ptr.params()[1] = node_to_cast;
55885680 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
55895681 if_node.body = &int_to_ptr.base;
55905682
55915683 const else_node = try transCreateNodeElse(c);
55925684 if_node.@"else" = else_node;
55935685
5594 const as_node = try transCreateNodeBuiltinFnCall(c, "@as");
5595 try as_node.params.push(inner_node);
5596 try as_node.params.push(node_to_cast);
5686 const as_node = try c.createBuiltinCall("@as", 2);
5687 as_node.params()[0] = inner_node;
5688 as_node.params()[1] = node_to_cast;
55975689 as_node.rparen_token = try appendToken(c, .RParen, ")");
55985690 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);
56015693 group_node.* = .{
56025694 .lparen = lparen,
56035695 .expr = &if_node.base,
......@@ -5614,14 +5706,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56145706 // @as(dest, x) )
56155707
56165708 const if_1 = try transCreateNodeIf(c);
5617 const type_info_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
5618 const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
5619 try type_info_1.params.push(&type_of_1.base);
5620 try type_of_1.params.push(node_to_cast);
5709 const type_info_1 = try c.createBuiltinCall("@typeInfo", 1);
5710 const type_of_1 = try c.createBuiltinCall("@TypeOf", 1);
5711 type_info_1.params()[0] = &type_of_1.base;
5712 type_of_1.params()[0] = node_to_cast;
56215713 type_of_1.rparen_token = try appendToken(c, .RParen, ")");
56225714 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);
56255717 cmp_1.* = .{
56265718 .op_token = try appendToken(c, .EqualEqual, "=="),
56275719 .lhs = &type_info_1.base,
......@@ -5633,7 +5725,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56335725
56345726 const period_tok = try appendToken(c, .Period, ".");
56355727 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);
56375729 inner_node_child.* = .{
56385730 .op_token = period_tok,
56395731 .lhs = inner_node,
......@@ -5641,20 +5733,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56415733 .rhs = child_ident,
56425734 };
56435735
5644 const align_of = try transCreateNodeBuiltinFnCall(c, "@alignOf");
5645 try align_of.params.push(&inner_node_child.base);
5736 const align_of = try c.createBuiltinCall("@alignOf", 1);
5737 align_of.params()[0] = &inner_node_child.base;
56465738 align_of.rparen_token = try appendToken(c, .RParen, ")");
56475739 // hack to get zig fmt to render a comma in builtin calls
56485740 _ = try appendToken(c, .Comma, ",");
56495741
5650 const align_cast = try transCreateNodeBuiltinFnCall(c, "@alignCast");
5651 try align_cast.params.push(&align_of.base);
5652 try align_cast.params.push(node_to_cast);
5742 const align_cast = try c.createBuiltinCall("@alignCast", 2);
5743 align_cast.params()[0] = &align_of.base;
5744 align_cast.params()[1] = node_to_cast;
56535745 align_cast.rparen_token = try appendToken(c, .RParen, ")");
56545746
5655 const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast");
5656 try ptr_cast.params.push(inner_node);
5657 try ptr_cast.params.push(&align_cast.base);
5747 const ptr_cast = try c.createBuiltinCall("@ptrCast", 2);
5748 ptr_cast.params()[0] = inner_node;
5749 ptr_cast.params()[1] = &align_cast.base;
56585750 ptr_cast.rparen_token = try appendToken(c, .RParen, ")");
56595751 if_1.body = &ptr_cast.base;
56605752
......@@ -5662,14 +5754,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56625754 if_1.@"else" = else_1;
56635755
56645756 const if_2 = try transCreateNodeIf(c);
5665 const type_info_2 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
5666 const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
5667 try type_info_2.params.push(&type_of_2.base);
5668 try type_of_2.params.push(node_to_cast);
5757 const type_info_2 = try c.createBuiltinCall("@typeInfo", 1);
5758 const type_of_2 = try c.createBuiltinCall("@TypeOf", 1);
5759 type_info_2.params()[0] = &type_of_2.base;
5760 type_of_2.params()[0] = node_to_cast;
56695761 type_of_2.rparen_token = try appendToken(c, .RParen, ")");
56705762 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);
56735765 cmp_2.* = .{
56745766 .op_token = try appendToken(c, .EqualEqual, "=="),
56755767 .lhs = &type_info_2.base,
......@@ -5677,17 +5769,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56775769 .rhs = try transCreateNodeEnumLiteral(c, "Int"),
56785770 };
56795771 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);
56815773 cmp_4.* = .{
56825774 .op_token = try appendToken(c, .Keyword_and, "and"),
56835775 .lhs = &cmp_2.base,
56845776 .op = .BoolAnd,
56855777 .rhs = undefined,
56865778 };
5687 const type_info_3 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
5688 try type_info_3.params.push(inner_node);
5779 const type_info_3 = try c.createBuiltinCall("@typeInfo", 1);
5780 type_info_3.params()[0] = inner_node;
56895781 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);
56915783 cmp_3.* = .{
56925784 .op_token = try appendToken(c, .EqualEqual, "=="),
56935785 .lhs = &type_info_3.base,
......@@ -5699,22 +5791,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56995791 else_1.body = &if_2.base;
57005792 _ = try appendToken(c, .RParen, ")");
57015793
5702 const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr");
5703 try int_to_ptr.params.push(inner_node);
5704 try int_to_ptr.params.push(node_to_cast);
5794 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5795 int_to_ptr.params()[0] = inner_node;
5796 int_to_ptr.params()[1] = node_to_cast;
57055797 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
57065798 if_2.body = &int_to_ptr.base;
57075799
57085800 const else_2 = try transCreateNodeElse(c);
57095801 if_2.@"else" = else_2;
57105802
5711 const as = try transCreateNodeBuiltinFnCall(c, "@as");
5712 try as.params.push(inner_node);
5713 try as.params.push(node_to_cast);
5803 const as = try c.createBuiltinCall("@as", 2);
5804 as.params()[0] = inner_node;
5805 as.params()[1] = node_to_cast;
57145806 as.rparen_token = try appendToken(c, .RParen, ")");
57155807 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);
57185810 group_node.* = .{
57195811 .lparen = lparen,
57205812 .expr = &if_1.base,
......@@ -5740,7 +5832,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
57405832 if (!isBoolRes(node)) {
57415833 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);
57445836 group_node.* = .{
57455837 .lparen = try appendToken(c, .LParen, "("),
57465838 .expr = node,
......@@ -5749,8 +5841,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
57495841 return &group_node.base;
57505842 }
57515843
5752 const builtin_node = try transCreateNodeBuiltinFnCall(c, "@boolToInt");
5753 try builtin_node.params.push(node);
5844 const builtin_node = try c.createBuiltinCall("@boolToInt", 1);
5845 builtin_node.params()[0] = node;
57545846 builtin_node.rparen_token = try appendToken(c, .RParen, ")");
57555847 return &builtin_node.base;
57565848}
......@@ -5759,7 +5851,7 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
57595851 if (isBoolRes(node)) {
57605852 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);
57635855 group_node.* = .{
57645856 .lparen = try appendToken(c, .LParen, "("),
57655857 .expr = node,
......@@ -5770,14 +5862,14 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
57705862
57715863 const op_token = try appendToken(c, .BangEqual, "!=");
57725864 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);
57745866 res.* = .{
57755867 .op_token = op_token,
57765868 .lhs = node,
57775869 .op = .BangEqual,
57785870 .rhs = zero,
57795871 };
5780 const group_node = try c.a().create(ast.Node.GroupedExpression);
5872 const group_node = try c.arena.create(ast.Node.GroupedExpression);
57815873 group_node.* = .{
57825874 .lparen = try appendToken(c, .LParen, "("),
57835875 .expr = &res.base,
......@@ -5928,10 +6020,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
59286020 continue;
59296021 },
59306022 .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();
59326026 while (true) {
59336027 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);
59356029 const next = it.next().?;
59366030 if (next.id == .Comma)
59376031 _ = try appendToken(c, .Comma, ",")
......@@ -5949,7 +6043,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
59496043 return error.ParseError;
59506044 }
59516045 }
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);
59536054 node = &call_node.base;
59546055 continue;
59556056 },
......@@ -5989,7 +6090,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
59896090 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
59906091 const lhs_node = try cast_fn(c, node);
59916092 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);
59936094 op_node.* = .{
59946095 .op_token = op_token,
59956096 .lhs = lhs_node,
......@@ -6037,7 +6138,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
60376138}
60386139
60396140fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
6040 const tok = c.tree.tokens.at(token);
6141 const tok = c.token_locs.items[token];
60416142 const slice = c.source_buffer.span()[tok.start..tok.end];
60426143 return if (mem.startsWith(u8, slice, "@\""))
60436144 slice[2 .. slice.len - 1]
......@@ -6060,9 +6161,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60606161 return null;
60616162 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
60626163 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6063 var it = container.fields_and_decls.iterator(0);
6064 while (it.next()) |field_ref| {
6065 const field = field_ref.*.cast(ast.Node.ContainerField).?;
6164 for (container.fieldsAndDecls()) |field_ref| {
6165 const field = field_ref.cast(ast.Node.ContainerField).?;
60666166 const ident = infix.rhs.cast(ast.Node.Identifier).?;
60676167 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
60686168 return getContainer(c, field.type_expr.?);
......@@ -6087,9 +6187,8 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60876187 return null;
60886188 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
60896189 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6090 var it = container.fields_and_decls.iterator(0);
6091 while (it.next()) |field_ref| {
6092 const field = field_ref.*.cast(ast.Node.ContainerField).?;
6190 for (container.fieldsAndDecls()) |field_ref| {
6191 const field = field_ref.cast(ast.Node.ContainerField).?;
60936192 const ident = infix.rhs.cast(ast.Node.Identifier).?;
60946193 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
60956194 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) {
36123612 auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
36133613 if (entry) {
36143614 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 }
36153621 ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name)));
36163622 add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
36173623 return;
......@@ -3887,9 +3893,18 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
38873893 if (search_scope != nullptr) {
38883894 Tld *tld = find_decl(g, search_scope, name);
38893895 if (tld != nullptr && tld != src_tld) {
3890 ErrorMsg *msg = add_node_error(g, source_node,
3891 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
3892 add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
3896 bool want_err_msg = true;
3897 if (tld->id == TldIdVar) {
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 }
38933908 variable_entry->var_type = g->builtin_types.entry_invalid;
38943909 }
38953910 }
src/ir.cpp+12-3
......@@ -5300,9 +5300,18 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
53005300 } else {
53015301 Tld *tld = find_decl(codegen, parent_scope, name);
53025302 if (tld != nullptr) {
5303 ErrorMsg *msg = add_node_error(codegen, node,
5304 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
5305 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
5303 bool want_err_msg = true;
5304 if (tld->id == TldIdVar) {
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 }
53065315 variable_entry->var_type = codegen->builtin_types.entry_invalid;
53075316 }
53085317 }