authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 21:11:30-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 21:22:52-04:00
log93384f7428c5186a1b44c6f5f8891ce40bc46e72
tree2baa7d2fcfc0ba0b088d45ccdb01543d480f42ff
parented137d25ef0fb94f2ea0db4f993a0adfcaf63b58

use singly linked lists for std.zig.parse

std.ast uses a singly linked list for lists of things. This is a breaking change to the self-hosted parser API. std.ast.Tree has been separated into a private "Parser" type which represents in-progress parsing, and std.ast.Tree which has only "output" data. This means cleaner, but breaking, API for parse results. Specifically, `tokens` and `errors` are no longer SegmentedList but a slice. The way to iterate over AST nodes has necessarily changed since lists of nodes are now singly linked lists rather than SegmentedList. From these changes, I observe the following on the self-hosted-parser benchmark from ziglang/gotta-go-fast: throughput: 45.6 MiB/s => 55.6 MiB/s maxrss: 359 KB => 342 KB This commit breaks the build; more updates are necessary to fix API usage of the self-hosted parser.

5 files changed, 3386 insertions(+), 3108 deletions(-)

lib/std/linked_list.zig+2-53
...@@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type {
21 next: ?*Node = null,21 next: ?*Node = null,
22 data: T,22 data: T,
2323
24 pub const Data = T;
25
24 pub fn init(data: T) Node {26 pub fn init(data: T) Node {
25 return Node{27 return Node{
26 .data = data,28 .data = data,
...@@ -51,25 +53,6 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -51,25 +53,6 @@ pub fn SinglyLinkedList(comptime T: type) type {
5153
52 first: ?*Node = null,54 first: ?*Node = null,
5355
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 }
63
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 }
72
73 /// Insert a new node at the head.56 /// Insert a new node at the head.
74 ///57 ///
75 /// Arguments:58 /// Arguments:
...@@ -104,40 +87,6 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -104,40 +87,6 @@ pub fn SinglyLinkedList(comptime T: type) type {
104 list.first = first.next;87 list.first = first.next;
105 return first;88 return first;
106 }89 }
107
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;
140 }
141 };90 };
142}91}
14392
lib/std/zig/ast.zig+467-178
...@@ -1,42 +1,39 @@...@@ -1,42 +1,39 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const SegmentedList = std.SegmentedList;4const LinkedList = std.SinglyLinkedList;
5const mem = std.mem;5const mem = std.mem;
6const Token = std.zig.Token;6const Token = std.zig.Token;
77
8pub const TokenIndex = usize;8pub const TokenIndex = usize;
99
10pub const Tree = struct {10pub const Tree = struct {
11 /// Reference to externally-owned data.
11 source: []const u8,12 source: []const u8,
12 tokens: TokenList,13 tokens: []const Token,
1314 errors: []const Error,
14 /// undefined on parse error (errors not empty)15 /// undefined on parse error (when errors field is not empty)
15 root_node: *Node.Root,16 root_node: *Node.Root,
16 arena_allocator: std.heap.ArenaAllocator,17
17 errors: ErrorList,18 arena: std.heap.ArenaAllocator.State,
19 gpa: *mem.Allocator,
1820
19 /// translate-c uses this to avoid having to emit correct newlines21 /// translate-c uses this to avoid having to emit correct newlines
20 /// TODO get rid of this hack22 /// TODO get rid of this hack
21 generated: bool = false,23 generated: bool = false,
2224
23 pub const TokenList = SegmentedList(Token, 64);
24 pub const ErrorList = SegmentedList(Error, 0);
25
26 pub fn deinit(self: *Tree) void {25 pub fn deinit(self: *Tree) void {
27 // Here we copy the arena allocator into stack memory, because26 self.gpa.free(self.tokens);
28 // otherwise it would destroy itself while it was still working.27 self.gpa.free(self.errors);
29 var arena_allocator = self.arena_allocator;28 self.arena.promote(self.gpa).deinit();
30 arena_allocator.deinit();
31 // self is destroyed
32 }29 }
3330
34 pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {31 pub fn renderError(self: *Tree, parse_error: *const Error, stream: var) !void {
35 return parse_error.render(&self.tokens, stream);32 return parse_error.render(self.tokens, stream);
36 }33 }
3734
38 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {35 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {
39 return self.tokenSlicePtr(self.tokens.at(token_index));36 return self.tokenSlicePtr(self.tokens[token_index]);
40 }37 }
4138
42 pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {39 pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {
...@@ -44,8 +41,8 @@ pub const Tree = struct {...@@ -44,8 +41,8 @@ pub const Tree = struct {
44 }41 }
4542
46 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {43 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {
47 const first_token = self.tokens.at(node.firstToken());44 const first_token = self.tokens[node.firstToken()];
48 const last_token = self.tokens.at(node.lastToken());45 const last_token = self.tokens[node.lastToken()];
49 return self.source[first_token.start..last_token.end];46 return self.source[first_token.start..last_token.end];
50 }47 }
5148
...@@ -57,7 +54,7 @@ pub const Tree = struct {...@@ -57,7 +54,7 @@ pub const Tree = struct {
57 };54 };
5855
59 /// Return the Location of the token relative to the offset specified by `start_index`.56 /// 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 {57 pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: Token) Location {
61 var loc = Location{58 var loc = Location{
62 .line = 0,59 .line = 0,
63 .column = 0,60 .column = 0,
...@@ -85,11 +82,11 @@ pub const Tree = struct {...@@ -85,11 +82,11 @@ pub const Tree = struct {
85 }82 }
8683
87 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {84 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {
88 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));85 return self.tokenLocationPtr(start_index, self.tokens[token_index]);
89 }86 }
9087
91 pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {88 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));89 return self.tokensOnSameLinePtr(self.tokens[token1_index], self.tokens[token2_index]);
93 }90 }
9491
95 pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool {92 pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool {
...@@ -103,7 +100,7 @@ pub const Tree = struct {...@@ -103,7 +100,7 @@ pub const Tree = struct {
103 /// Skips over comments100 /// Skips over comments
104 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {101 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
105 var index = token_index - 1;102 var index = token_index - 1;
106 while (self.tokens.at(index).id == Token.Id.LineComment) {103 while (self.tokens[index].id == Token.Id.LineComment) {
107 index -= 1;104 index -= 1;
108 }105 }
109 return index;106 return index;
...@@ -112,7 +109,7 @@ pub const Tree = struct {...@@ -112,7 +109,7 @@ pub const Tree = struct {
112 /// Skips over comments109 /// Skips over comments
113 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {110 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
114 var index = token_index + 1;111 var index = token_index + 1;
115 while (self.tokens.at(index).id == Token.Id.LineComment) {112 while (self.tokens[index].id == Token.Id.LineComment) {
116 index += 1;113 index += 1;
117 }114 }
118 return index;115 return index;
...@@ -169,7 +166,7 @@ pub const Error = union(enum) {...@@ -169,7 +166,7 @@ pub const Error = union(enum) {
169 DeclBetweenFields: DeclBetweenFields,166 DeclBetweenFields: DeclBetweenFields,
170 InvalidAnd: InvalidAnd,167 InvalidAnd: InvalidAnd,
171168
172 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {169 pub fn render(self: *const Error, tokens: []const Token, stream: var) !void {
173 switch (self.*) {170 switch (self.*) {
174 .InvalidToken => |*x| return x.render(tokens, stream),171 .InvalidToken => |*x| return x.render(tokens, stream),
175 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),172 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),
...@@ -324,7 +321,7 @@ pub const Error = union(enum) {...@@ -324,7 +321,7 @@ pub const Error = union(enum) {
324 pub const ExpectedCall = struct {321 pub const ExpectedCall = struct {
325 node: *Node,322 node: *Node,
326323
327 pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void {324 pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {
328 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{325 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{
329 @tagName(self.node.id),326 @tagName(self.node.id),
330 });327 });
...@@ -334,7 +331,7 @@ pub const Error = union(enum) {...@@ -334,7 +331,7 @@ pub const Error = union(enum) {
334 pub const ExpectedCallOrFnProto = struct {331 pub const ExpectedCallOrFnProto = struct {
335 node: *Node,332 node: *Node,
336333
337 pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void {334 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {
338 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++335 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
339 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});336 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
340 }337 }
...@@ -344,8 +341,8 @@ pub const Error = union(enum) {...@@ -344,8 +341,8 @@ pub const Error = union(enum) {
344 token: TokenIndex,341 token: TokenIndex,
345 expected_id: Token.Id,342 expected_id: Token.Id,
346343
347 pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {344 pub fn render(self: *const ExpectedToken, tokens: []const Token, stream: var) !void {
348 const found_token = tokens.at(self.token);345 const found_token = tokens[self.token];
349 switch (found_token.id) {346 switch (found_token.id) {
350 .Invalid => {347 .Invalid => {
351 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});348 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
...@@ -362,8 +359,8 @@ pub const Error = union(enum) {...@@ -362,8 +359,8 @@ pub const Error = union(enum) {
362 token: TokenIndex,359 token: TokenIndex,
363 end_id: Token.Id,360 end_id: Token.Id,
364361
365 pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void {362 pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token, stream: var) !void {
366 const actual_token = tokens.at(self.token);363 const actual_token = tokens[self.token];
367 return stream.print("expected ',' or '{}', found '{}'", .{364 return stream.print("expected ',' or '{}', found '{}'", .{
368 self.end_id.symbol(),365 self.end_id.symbol(),
369 actual_token.id.symbol(),366 actual_token.id.symbol(),
...@@ -377,8 +374,8 @@ pub const Error = union(enum) {...@@ -377,8 +374,8 @@ pub const Error = union(enum) {
377374
378 token: TokenIndex,375 token: TokenIndex,
379376
380 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {377 pub fn render(self: *const ThisError, tokens: []const Token, stream: var) !void {
381 const actual_token = tokens.at(self.token);378 const actual_token = tokens[self.token];
382 return stream.print(msg, .{actual_token.id.symbol()});379 return stream.print(msg, .{actual_token.id.symbol()});
383 }380 }
384 };381 };
...@@ -390,7 +387,7 @@ pub const Error = union(enum) {...@@ -390,7 +387,7 @@ pub const Error = union(enum) {
390387
391 token: TokenIndex,388 token: TokenIndex,
392389
393 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {390 pub fn render(self: *const ThisError, tokens: []const Token, stream: var) !void {
394 return stream.writeAll(msg);391 return stream.writeAll(msg);
395 }392 }
396 };393 };
...@@ -400,6 +397,23 @@ pub const Error = union(enum) {...@@ -400,6 +397,23 @@ pub const Error = union(enum) {
400pub const Node = struct {397pub const Node = struct {
401 id: Id,398 id: Id,
402399
400 /// All the child Node types use this same Iterator state for their iteration.
401 pub const Iterator = struct {
402 parent_node: *const Node,
403 node: ?*LinkedList(*Node).Node,
404 index: usize,
405
406 pub fn next(it: *Iterator) ?*Node {
407 inline for (@typeInfo(Id).Enum.fields) |f| {
408 if (it.parent_node.id == @field(Id, f.name)) {
409 const T = @field(Node, f.name);
410 return @fieldParentPtr(T, "base", it.parent_node).iterateNext(it);
411 }
412 }
413 unreachable;
414 }
415 };
416
403 pub const Id = enum {417 pub const Id = enum {
404 // Top level418 // Top level
405 Root,419 Root,
...@@ -473,11 +487,11 @@ pub const Node = struct {...@@ -473,11 +487,11 @@ pub const Node = struct {
473 return null;487 return null;
474 }488 }
475489
476 pub fn iterate(base: *Node, index: usize) ?*Node {490 pub fn iterate(base: *Node) Iterator {
477 inline for (@typeInfo(Id).Enum.fields) |f| {491 inline for (@typeInfo(Id).Enum.fields) |f| {
478 if (base.id == @field(Id, f.name)) {492 if (base.id == @field(Id, f.name)) {
479 const T = @field(Node, f.name);493 const T = @field(Node, f.name);
480 return @fieldParentPtr(T, "base", base).iterate(index);494 return @fieldParentPtr(T, "base", base).iterate();
481 }495 }
482 }496 }
483 unreachable;497 unreachable;
...@@ -607,21 +621,35 @@ pub const Node = struct {...@@ -607,21 +621,35 @@ pub const Node = struct {
607 decls: DeclList,621 decls: DeclList,
608 eof_token: TokenIndex,622 eof_token: TokenIndex,
609623
610 pub const DeclList = SegmentedList(*Node, 4);624 pub const DeclList = LinkedList(*Node);
611625
612 pub fn iterate(self: *Root, index: usize) ?*Node {626 pub fn iterate(self: *const Root) Node.Iterator {
613 if (index < self.decls.len) {627 return .{ .parent_node = &self.base, .index = 0, .node = self.decls.first };
614 return self.decls.at(index).*;628 }
615 }629
616 return null;630 pub fn iterateNext(self: *const Root, it: *Node.Iterator) ?*Node {
631 const decl = it.node orelse return null;
632 it.node = decl.next;
633 return decl.data;
617 }634 }
618635
619 pub fn firstToken(self: *const Root) TokenIndex {636 pub fn firstToken(self: *const Root) TokenIndex {
620 return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();637 if (self.decls.first) |first| {
638 return first.data.firstToken();
639 } else {
640 return self.eof_token;
641 }
621 }642 }
622643
623 pub fn lastToken(self: *const Root) TokenIndex {644 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();645 if (self.decls.first) |first| {
646 var node = first;
647 while (true) {
648 node = node.next orelse return node.data.lastToken();
649 }
650 } else {
651 return self.eof_token;
652 }
625 }653 }
626 };654 };
627655
...@@ -642,8 +670,13 @@ pub const Node = struct {...@@ -642,8 +670,13 @@ pub const Node = struct {
642 init_node: ?*Node,670 init_node: ?*Node,
643 semicolon_token: TokenIndex,671 semicolon_token: TokenIndex,
644672
645 pub fn iterate(self: *VarDecl, index: usize) ?*Node {673 pub fn iterate(self: *const VarDecl) Node.Iterator {
646 var i = index;674 return .{ .parent_node = &self.base, .index = 0, .node = null };
675 }
676
677 pub fn iterateNext(self: *const VarDecl, it: *Node.Iterator) ?*Node {
678 var i = it.index;
679 it.index += 1;
647680
648 if (self.type_node) |type_node| {681 if (self.type_node) |type_node| {
649 if (i < 1) return type_node;682 if (i < 1) return type_node;
...@@ -668,6 +701,7 @@ pub const Node = struct {...@@ -668,6 +701,7 @@ pub const Node = struct {
668 return null;701 return null;
669 }702 }
670703
704
671 pub fn firstToken(self: *const VarDecl) TokenIndex {705 pub fn firstToken(self: *const VarDecl) TokenIndex {
672 if (self.visib_token) |visib_token| return visib_token;706 if (self.visib_token) |visib_token| return visib_token;
673 if (self.thread_local_token) |thread_local_token| return thread_local_token;707 if (self.thread_local_token) |thread_local_token| return thread_local_token;
...@@ -690,8 +724,13 @@ pub const Node = struct {...@@ -690,8 +724,13 @@ pub const Node = struct {
690 expr: *Node,724 expr: *Node,
691 semicolon_token: TokenIndex,725 semicolon_token: TokenIndex,
692726
693 pub fn iterate(self: *Use, index: usize) ?*Node {727 pub fn iterate(self: *const Use) Node.Iterator {
694 var i = index;728 return .{ .parent_node = &self.base, .index = 0, .node = null };
729 }
730
731 pub fn iterateNext(self: *const Use, it: *Node.Iterator) ?*Node {
732 var i = it.index;
733 it.index += 1;
695734
696 if (i < 1) return self.expr;735 if (i < 1) return self.expr;
697 i -= 1;736 i -= 1;
...@@ -715,15 +754,16 @@ pub const Node = struct {...@@ -715,15 +754,16 @@ pub const Node = struct {
715 decls: DeclList,754 decls: DeclList,
716 rbrace_token: TokenIndex,755 rbrace_token: TokenIndex,
717756
718 pub const DeclList = SegmentedList(*Node, 2);757 pub const DeclList = LinkedList(*Node);
719758
720 pub fn iterate(self: *ErrorSetDecl, index: usize) ?*Node {759 pub fn iterate(self: *const ErrorSetDecl) Node.Iterator {
721 var i = index;760 return .{ .parent_node = &self.base, .index = 0, .node = self.decls.first };
722761 }
723 if (i < self.decls.len) return self.decls.at(i).*;
724 i -= self.decls.len;
725762
726 return null;763 pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {
764 const decl = it.node orelse return null;
765 it.node = decl.next;
766 return decl.data;
727 }767 }
728768
729 pub fn firstToken(self: *const ErrorSetDecl) TokenIndex {769 pub fn firstToken(self: *const ErrorSetDecl) TokenIndex {
...@@ -752,8 +792,13 @@ pub const Node = struct {...@@ -752,8 +792,13 @@ pub const Node = struct {
752 Type: *Node,792 Type: *Node,
753 };793 };
754794
755 pub fn iterate(self: *ContainerDecl, index: usize) ?*Node {795 pub fn iterate(self: *const ContainerDecl) Node.Iterator {
756 var i = index;796 return .{ .parent_node = &self.base, .index = 0, .node = self.fields_and_decls.first };
797 }
798
799 pub fn iterateNext(self: *const ContainerDecl, it: *Node.Iterator) ?*Node {
800 var i = it.index;
801 it.index += 1;
757802
758 switch (self.init_arg_expr) {803 switch (self.init_arg_expr) {
759 .Type => |t| {804 .Type => |t| {
...@@ -763,8 +808,10 @@ pub const Node = struct {...@@ -763,8 +808,10 @@ pub const Node = struct {
763 .None, .Enum => {},808 .None, .Enum => {},
764 }809 }
765810
766 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;811 if (it.node) |child| {
767 i -= self.fields_and_decls.len;812 it.node = child.next;
813 return child.data;
814 }
768815
769 return null;816 return null;
770 }817 }
...@@ -790,8 +837,13 @@ pub const Node = struct {...@@ -790,8 +837,13 @@ pub const Node = struct {
790 value_expr: ?*Node,837 value_expr: ?*Node,
791 align_expr: ?*Node,838 align_expr: ?*Node,
792839
793 pub fn iterate(self: *ContainerField, index: usize) ?*Node {840 pub fn iterate(self: *const ContainerField) Node.Iterator {
794 var i = index;841 return .{ .parent_node = &self.base, .index = 0, .node = null };
842 }
843
844 pub fn iterateNext(self: *const ContainerField, it: *Node.Iterator) ?*Node {
845 var i = it.index;
846 it.index += 1;
795847
796 if (self.type_expr) |type_expr| {848 if (self.type_expr) |type_expr| {
797 if (i < 1) return type_expr;849 if (i < 1) return type_expr;
...@@ -837,8 +889,13 @@ pub const Node = struct {...@@ -837,8 +889,13 @@ pub const Node = struct {
837 doc_comments: ?*DocComment,889 doc_comments: ?*DocComment,
838 name_token: TokenIndex,890 name_token: TokenIndex,
839891
840 pub fn iterate(self: *ErrorTag, index: usize) ?*Node {892 pub fn iterate(self: *const ErrorTag) Node.Iterator {
841 var i = index;893 return .{ .parent_node = &self.base, .index = 0, .node = null };
894 }
895
896 pub fn iterateNext(self: *const ErrorTag, it: *Node.Iterator) ?*Node {
897 var i = it.index;
898 it.index += 1;
842899
843 if (self.doc_comments) |comments| {900 if (self.doc_comments) |comments| {
844 if (i < 1) return &comments.base;901 if (i < 1) return &comments.base;
...@@ -861,7 +918,11 @@ pub const Node = struct {...@@ -861,7 +918,11 @@ pub const Node = struct {
861 base: Node = Node{ .id = .Identifier },918 base: Node = Node{ .id = .Identifier },
862 token: TokenIndex,919 token: TokenIndex,
863920
864 pub fn iterate(self: *Identifier, index: usize) ?*Node {921 pub fn iterate(self: *const Identifier) Node.Iterator {
922 return .{ .parent_node = &self.base, .index = 0, .node = null };
923 }
924
925 pub fn iterateNext(self: *const Identifier, it: *Node.Iterator) ?*Node {
865 return null;926 return null;
866 }927 }
867928
...@@ -892,7 +953,7 @@ pub const Node = struct {...@@ -892,7 +953,7 @@ pub const Node = struct {
892 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is953 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
893 is_async: bool = false, // TODO: remove once async fn rewriting is954 is_async: bool = false, // TODO: remove once async fn rewriting is
894955
895 pub const ParamList = SegmentedList(*Node, 2);956 pub const ParamList = LinkedList(*Node);
896957
897 pub const ReturnType = union(enum) {958 pub const ReturnType = union(enum) {
898 Explicit: *Node,959 Explicit: *Node,
...@@ -900,16 +961,24 @@ pub const Node = struct {...@@ -900,16 +961,24 @@ pub const Node = struct {
900 Invalid: TokenIndex,961 Invalid: TokenIndex,
901 };962 };
902963
903 pub fn iterate(self: *FnProto, index: usize) ?*Node {964 pub fn iterate(self: *const FnProto) Node.Iterator {
904 var i = index;965 return .{ .parent_node = &self.base, .index = 0, .node = self.params.first };
966 }
967
968 pub fn iterateNext(self: *const FnProto, it: *Node.Iterator) ?*Node {
969 var i = it.index;
970 it.index += 1;
905971
906 if (self.lib_name) |lib_name| {972 if (self.lib_name) |lib_name| {
907 if (i < 1) return lib_name;973 if (i < 1) return lib_name;
908 i -= 1;974 i -= 1;
909 }975 }
910976
911 if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;977 if (it.node) |param| {
912 i -= self.params.len;978 it.index -= 1;
979 it.node = param.next;
980 return param.data;
981 }
913982
914 if (self.align_expr) |align_expr| {983 if (self.align_expr) |align_expr| {
915 if (i < 1) return align_expr;984 if (i < 1) return align_expr;
...@@ -963,8 +1032,13 @@ pub const Node = struct {...@@ -963,8 +1032,13 @@ pub const Node = struct {
963 return_type: *Node,1032 return_type: *Node,
964 };1033 };
9651034
966 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {1035 pub fn iterate(self: *const AnyFrameType) Node.Iterator {
967 var i = index;1036 return .{ .parent_node = &self.base, .index = 0, .node = null };
1037 }
1038
1039 pub fn iterateNext(self: *const AnyFrameType, it: *Node.Iterator) ?*Node {
1040 var i = it.index;
1041 it.index += 1;
9681042
969 if (self.result) |result| {1043 if (self.result) |result| {
970 if (i < 1) return result.return_type;1044 if (i < 1) return result.return_type;
...@@ -998,8 +1072,13 @@ pub const Node = struct {...@@ -998,8 +1072,13 @@ pub const Node = struct {
998 type_expr: *Node,1072 type_expr: *Node,
999 };1073 };
10001074
1001 pub fn iterate(self: *ParamDecl, index: usize) ?*Node {1075 pub fn iterate(self: *const ParamDecl) Node.Iterator {
1002 var i = index;1076 return .{ .parent_node = &self.base, .index = 0, .node = null };
1077 }
1078
1079 pub fn iterateNext(self: *const ParamDecl, it: *Node.Iterator) ?*Node {
1080 var i = it.index;
1081 it.index += 1;
10031082
1004 if (i < 1) {1083 if (i < 1) {
1005 switch (self.param_type) {1084 switch (self.param_type) {
...@@ -1039,13 +1118,14 @@ pub const Node = struct {...@@ -1039,13 +1118,14 @@ pub const Node = struct {
10391118
1040 pub const StatementList = Root.DeclList;1119 pub const StatementList = Root.DeclList;
10411120
1042 pub fn iterate(self: *Block, index: usize) ?*Node {1121 pub fn iterate(self: *const Block) Node.Iterator {
1043 var i = index;1122 return .{ .parent_node = &self.base, .index = 0, .node = self.statements.first };
10441123 }
1045 if (i < self.statements.len) return self.statements.at(i).*;
1046 i -= self.statements.len;
10471124
1048 return null;1125 pub fn iterateNext(self: *const Block, it: *Node.Iterator) ?*Node {
1126 const child = it.node orelse return null;
1127 it.node = child.next;
1128 return child.data;
1049 }1129 }
10501130
1051 pub fn firstToken(self: *const Block) TokenIndex {1131 pub fn firstToken(self: *const Block) TokenIndex {
...@@ -1067,8 +1147,13 @@ pub const Node = struct {...@@ -1067,8 +1147,13 @@ pub const Node = struct {
1067 payload: ?*Node,1147 payload: ?*Node,
1068 expr: *Node,1148 expr: *Node,
10691149
1070 pub fn iterate(self: *Defer, index: usize) ?*Node {1150 pub fn iterate(self: *const Defer) Node.Iterator {
1071 var i = index;1151 return .{ .parent_node = &self.base, .index = 0, .node = null };
1152 }
1153
1154 pub fn iterateNext(self: *const Defer, it: *Node.Iterator) ?*Node {
1155 var i = it.index;
1156 it.index += 1;
10721157
1073 if (i < 1) return self.expr;1158 if (i < 1) return self.expr;
1074 i -= 1;1159 i -= 1;
...@@ -1091,8 +1176,13 @@ pub const Node = struct {...@@ -1091,8 +1176,13 @@ pub const Node = struct {
1091 comptime_token: TokenIndex,1176 comptime_token: TokenIndex,
1092 expr: *Node,1177 expr: *Node,
10931178
1094 pub fn iterate(self: *Comptime, index: usize) ?*Node {1179 pub fn iterate(self: *const Comptime) Node.Iterator {
1095 var i = index;1180 return .{ .parent_node = &self.base, .index = 0, .node = null };
1181 }
1182
1183 pub fn iterateNext(self: *const Comptime, it: *Node.Iterator) ?*Node {
1184 var i = it.index;
1185 it.index += 1;
10961186
1097 if (i < 1) return self.expr;1187 if (i < 1) return self.expr;
1098 i -= 1;1188 i -= 1;
...@@ -1114,8 +1204,13 @@ pub const Node = struct {...@@ -1114,8 +1204,13 @@ pub const Node = struct {
1114 nosuspend_token: TokenIndex,1204 nosuspend_token: TokenIndex,
1115 expr: *Node,1205 expr: *Node,
11161206
1117 pub fn iterate(self: *Nosuspend, index: usize) ?*Node {1207 pub fn iterate(self: *const Nosuspend) Node.Iterator {
1118 var i = index;1208 return .{ .parent_node = &self.base, .index = 0, .node = null };
1209 }
1210
1211 pub fn iterateNext(self: *const Nosuspend, it: *Node.Iterator) ?*Node {
1212 var i = it.index;
1213 it.index += 1;
11191214
1120 if (i < 1) return self.expr;1215 if (i < 1) return self.expr;
1121 i -= 1;1216 i -= 1;
...@@ -1138,8 +1233,13 @@ pub const Node = struct {...@@ -1138,8 +1233,13 @@ pub const Node = struct {
1138 error_symbol: *Node,1233 error_symbol: *Node,
1139 rpipe: TokenIndex,1234 rpipe: TokenIndex,
11401235
1141 pub fn iterate(self: *Payload, index: usize) ?*Node {1236 pub fn iterate(self: *const Payload) Node.Iterator {
1142 var i = index;1237 return .{ .parent_node = &self.base, .index = 0, .node = null };
1238 }
1239
1240 pub fn iterateNext(self: *const Payload, it: *Node.Iterator) ?*Node {
1241 var i = it.index;
1242 it.index += 1;
11431243
1144 if (i < 1) return self.error_symbol;1244 if (i < 1) return self.error_symbol;
1145 i -= 1;1245 i -= 1;
...@@ -1163,8 +1263,13 @@ pub const Node = struct {...@@ -1163,8 +1263,13 @@ pub const Node = struct {
1163 value_symbol: *Node,1263 value_symbol: *Node,
1164 rpipe: TokenIndex,1264 rpipe: TokenIndex,
11651265
1166 pub fn iterate(self: *PointerPayload, index: usize) ?*Node {1266 pub fn iterate(self: *const PointerPayload) Node.Iterator {
1167 var i = index;1267 return .{ .parent_node = &self.base, .index = 0, .node = null };
1268 }
1269
1270 pub fn iterateNext(self: *const PointerPayload, it: *Node.Iterator) ?*Node {
1271 var i = it.index;
1272 it.index += 1;
11681273
1169 if (i < 1) return self.value_symbol;1274 if (i < 1) return self.value_symbol;
1170 i -= 1;1275 i -= 1;
...@@ -1189,8 +1294,13 @@ pub const Node = struct {...@@ -1189,8 +1294,13 @@ pub const Node = struct {
1189 index_symbol: ?*Node,1294 index_symbol: ?*Node,
1190 rpipe: TokenIndex,1295 rpipe: TokenIndex,
11911296
1192 pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node {1297 pub fn iterate(self: *const PointerIndexPayload) Node.Iterator {
1193 var i = index;1298 return .{ .parent_node = &self.base, .index = 0, .node = null };
1299 }
1300
1301 pub fn iterateNext(self: *const PointerIndexPayload, it: *Node.Iterator) ?*Node {
1302 var i = it.index;
1303 it.index += 1;
11941304
1195 if (i < 1) return self.value_symbol;1305 if (i < 1) return self.value_symbol;
1196 i -= 1;1306 i -= 1;
...@@ -1218,8 +1328,13 @@ pub const Node = struct {...@@ -1218,8 +1328,13 @@ pub const Node = struct {
1218 payload: ?*Node,1328 payload: ?*Node,
1219 body: *Node,1329 body: *Node,
12201330
1221 pub fn iterate(self: *Else, index: usize) ?*Node {1331 pub fn iterate(self: *const Else) Node.Iterator {
1222 var i = index;1332 return .{ .parent_node = &self.base, .index = 0, .node = null };
1333 }
1334
1335 pub fn iterateNext(self: *const Else, it: *Node.Iterator) ?*Node {
1336 var i = it.index;
1337 it.index += 1;
12231338
1224 if (self.payload) |payload| {1339 if (self.payload) |payload| {
1225 if (i < 1) return payload;1340 if (i < 1) return payload;
...@@ -1250,16 +1365,24 @@ pub const Node = struct {...@@ -1250,16 +1365,24 @@ pub const Node = struct {
1250 cases: CaseList,1365 cases: CaseList,
1251 rbrace: TokenIndex,1366 rbrace: TokenIndex,
12521367
1253 pub const CaseList = SegmentedList(*Node, 2);1368 pub const CaseList = LinkedList(*Node);
1369
1370 pub fn iterate(self: *const Switch) Node.Iterator {
1371 return .{ .parent_node = &self.base, .index = 0, .node = self.cases.first };
1372 }
12541373
1255 pub fn iterate(self: *Switch, index: usize) ?*Node {1374 pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {
1256 var i = index;1375 var i = it.index;
1376 it.index += 1;
12571377
1258 if (i < 1) return self.expr;1378 if (i < 1) return self.expr;
1259 i -= 1;1379 i -= 1;
12601380
1261 if (i < self.cases.len) return self.cases.at(i).*;1381 if (it.node) |child| {
1262 i -= self.cases.len;1382 it.index -= 1;
1383 it.node = child.next;
1384 return child.data;
1385 }
12631386
1264 return null;1387 return null;
1265 }1388 }
...@@ -1280,13 +1403,21 @@ pub const Node = struct {...@@ -1280,13 +1403,21 @@ pub const Node = struct {
1280 payload: ?*Node,1403 payload: ?*Node,
1281 expr: *Node,1404 expr: *Node,
12821405
1283 pub const ItemList = SegmentedList(*Node, 1);1406 pub const ItemList = LinkedList(*Node);
1407
1408 pub fn iterate(self: *const SwitchCase) Node.Iterator {
1409 return .{ .parent_node = &self.base, .index = 0, .node = self.items.first };
1410 }
12841411
1285 pub fn iterate(self: *SwitchCase, index: usize) ?*Node {1412 pub fn iterateNext(self: *const SwitchCase, it: *Node.Iterator) ?*Node {
1286 var i = index;1413 var i = it.index;
1414 it.index += 1;
12871415
1288 if (i < self.items.len) return self.items.at(i).*;1416 if (it.node) |child| {
1289 i -= self.items.len;1417 it.index -= 1;
1418 it.node = child.next;
1419 return child.data;
1420 }
12901421
1291 if (self.payload) |payload| {1422 if (self.payload) |payload| {
1292 if (i < 1) return payload;1423 if (i < 1) return payload;
...@@ -1300,7 +1431,7 @@ pub const Node = struct {...@@ -1300,7 +1431,7 @@ pub const Node = struct {
1300 }1431 }
13011432
1302 pub fn firstToken(self: *const SwitchCase) TokenIndex {1433 pub fn firstToken(self: *const SwitchCase) TokenIndex {
1303 return (self.items.at(0).*).firstToken();1434 return self.items.first.?.data.firstToken();
1304 }1435 }
13051436
1306 pub fn lastToken(self: *const SwitchCase) TokenIndex {1437 pub fn lastToken(self: *const SwitchCase) TokenIndex {
...@@ -1312,7 +1443,11 @@ pub const Node = struct {...@@ -1312,7 +1443,11 @@ pub const Node = struct {
1312 base: Node = Node{ .id = .SwitchElse },1443 base: Node = Node{ .id = .SwitchElse },
1313 token: TokenIndex,1444 token: TokenIndex,
13141445
1315 pub fn iterate(self: *SwitchElse, index: usize) ?*Node {1446 pub fn iterate(self: *const SwitchElse) Node.Iterator {
1447 return .{ .parent_node = &self.base, .index = 0, .node = null };
1448 }
1449
1450 pub fn iterateNext(self: *const SwitchElse, it: *Node.Iterator) ?*Node {
1316 return null;1451 return null;
1317 }1452 }
13181453
...@@ -1336,8 +1471,13 @@ pub const Node = struct {...@@ -1336,8 +1471,13 @@ pub const Node = struct {
1336 body: *Node,1471 body: *Node,
1337 @"else": ?*Else,1472 @"else": ?*Else,
13381473
1339 pub fn iterate(self: *While, index: usize) ?*Node {1474 pub fn iterate(self: *const While) Node.Iterator {
1340 var i = index;1475 return .{ .parent_node = &self.base, .index = 0, .node = null };
1476 }
1477
1478 pub fn iterateNext(self: *const While, it: *Node.Iterator) ?*Node {
1479 var i = it.index;
1480 it.index += 1;
13411481
1342 if (i < 1) return self.condition;1482 if (i < 1) return self.condition;
1343 i -= 1;1483 i -= 1;
...@@ -1394,8 +1534,13 @@ pub const Node = struct {...@@ -1394,8 +1534,13 @@ pub const Node = struct {
1394 body: *Node,1534 body: *Node,
1395 @"else": ?*Else,1535 @"else": ?*Else,
13961536
1397 pub fn iterate(self: *For, index: usize) ?*Node {1537 pub fn iterate(self: *const For) Node.Iterator {
1398 var i = index;1538 return .{ .parent_node = &self.base, .index = 0, .node = null };
1539 }
1540
1541 pub fn iterateNext(self: *const For, it: *Node.Iterator) ?*Node {
1542 var i = it.index;
1543 it.index += 1;
13991544
1400 if (i < 1) return self.array_expr;1545 if (i < 1) return self.array_expr;
1401 i -= 1;1546 i -= 1;
...@@ -1443,8 +1588,13 @@ pub const Node = struct {...@@ -1443,8 +1588,13 @@ pub const Node = struct {
1443 body: *Node,1588 body: *Node,
1444 @"else": ?*Else,1589 @"else": ?*Else,
14451590
1446 pub fn iterate(self: *If, index: usize) ?*Node {1591 pub fn iterate(self: *const If) Node.Iterator {
1447 var i = index;1592 return .{ .parent_node = &self.base, .index = 0, .node = null };
1593 }
1594
1595 pub fn iterateNext(self: *const If, it: *Node.Iterator) ?*Node {
1596 var i = it.index;
1597 it.index += 1;
14481598
1449 if (i < 1) return self.condition;1599 if (i < 1) return self.condition;
1450 i -= 1;1600 i -= 1;
...@@ -1531,8 +1681,13 @@ pub const Node = struct {...@@ -1531,8 +1681,13 @@ pub const Node = struct {
1531 UnwrapOptional,1681 UnwrapOptional,
1532 };1682 };
15331683
1534 pub fn iterate(self: *InfixOp, index: usize) ?*Node {1684 pub fn iterate(self: *const InfixOp) Node.Iterator {
1535 var i = index;1685 return .{ .parent_node = &self.base, .index = 0, .node = null };
1686 }
1687
1688 pub fn iterateNext(self: *const InfixOp, it: *Node.Iterator) ?*Node {
1689 var i = it.index;
1690 it.index += 1;
15361691
1537 if (i < 1) return self.lhs;1692 if (i < 1) return self.lhs;
1538 i -= 1;1693 i -= 1;
...@@ -1649,8 +1804,13 @@ pub const Node = struct {...@@ -1649,8 +1804,13 @@ pub const Node = struct {
1649 };1804 };
1650 };1805 };
16511806
1652 pub fn iterate(self: *PrefixOp, index: usize) ?*Node {1807 pub fn iterate(self: *const PrefixOp) Node.Iterator {
1653 var i = index;1808 return .{ .parent_node = &self.base, .index = 0, .node = null };
1809 }
1810
1811 pub fn iterateNext(self: *const PrefixOp, it: *Node.Iterator) ?*Node {
1812 var i = it.index;
1813 it.index += 1;
16541814
1655 switch (self.op) {1815 switch (self.op) {
1656 .PtrType, .SliceType => |addr_of_info| {1816 .PtrType, .SliceType => |addr_of_info| {
...@@ -1707,8 +1867,13 @@ pub const Node = struct {...@@ -1707,8 +1867,13 @@ pub const Node = struct {
1707 name_token: TokenIndex,1867 name_token: TokenIndex,
1708 expr: *Node,1868 expr: *Node,
17091869
1710 pub fn iterate(self: *FieldInitializer, index: usize) ?*Node {1870 pub fn iterate(self: *const FieldInitializer) Node.Iterator {
1711 var i = index;1871 return .{ .parent_node = &self.base, .index = 0, .node = null };
1872 }
1873
1874 pub fn iterateNext(self: *const FieldInitializer, it: *Node.Iterator) ?*Node {
1875 var i = it.index;
1876 it.index += 1;
17121877
1713 if (i < 1) return self.expr;1878 if (i < 1) return self.expr;
1714 i -= 1;1879 i -= 1;
...@@ -1745,13 +1910,13 @@ pub const Node = struct {...@@ -1745,13 +1910,13 @@ pub const Node = struct {
1745 Deref,1910 Deref,
1746 UnwrapOptional,1911 UnwrapOptional,
17471912
1748 pub const InitList = SegmentedList(*Node, 2);1913 pub const InitList = LinkedList(*Node);
17491914
1750 pub const Call = struct {1915 pub const Call = struct {
1751 params: ParamList,1916 params: ParamList,
1752 async_token: ?TokenIndex,1917 async_token: ?TokenIndex,
17531918
1754 pub const ParamList = SegmentedList(*Node, 2);1919 pub const ParamList = LinkedList(*Node);
1755 };1920 };
17561921
1757 pub const Slice = struct {1922 pub const Slice = struct {
...@@ -1761,8 +1926,20 @@ pub const Node = struct {...@@ -1761,8 +1926,20 @@ pub const Node = struct {
1761 };1926 };
1762 };1927 };
17631928
1764 pub fn iterate(self: *SuffixOp, index: usize) ?*Node {1929 pub fn iterate(self: *const SuffixOp) Node.Iterator {
1765 var i = index;1930 return .{ .parent_node = &self.base, .index = 0,
1931 .node = switch(self.op) {
1932 .Call => |call| call.params.first,
1933 .ArrayInitializer => |ai| ai.first,
1934 .StructInitializer => |si| si.first,
1935 else => null,
1936 },
1937 };
1938 }
1939
1940 pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {
1941 var i = it.index;
1942 it.index += 1;
17661943
1767 switch (self.lhs) {1944 switch (self.lhs) {
1768 .node => |node| {1945 .node => |node| {
...@@ -1773,9 +1950,12 @@ pub const Node = struct {...@@ -1773,9 +1950,12 @@ pub const Node = struct {
1773 }1950 }
17741951
1775 switch (self.op) {1952 switch (self.op) {
1776 .Call => |*call_info| {1953 .Call => |call_info| {
1777 if (i < call_info.params.len) return call_info.params.at(i).*;1954 if (it.node) |child| {
1778 i -= call_info.params.len;1955 it.index -= 1;
1956 it.node = child.next;
1957 return child.data;
1958 }
1779 },1959 },
1780 .ArrayAccess => |index_expr| {1960 .ArrayAccess => |index_expr| {
1781 if (i < 1) return index_expr;1961 if (i < 1) return index_expr;
...@@ -1794,13 +1974,19 @@ pub const Node = struct {...@@ -1794,13 +1974,19 @@ pub const Node = struct {
1794 i -= 1;1974 i -= 1;
1795 }1975 }
1796 },1976 },
1797 .ArrayInitializer => |*exprs| {1977 .ArrayInitializer => |exprs| {
1798 if (i < exprs.len) return exprs.at(i).*;1978 if (it.node) |child| {
1799 i -= exprs.len;1979 it.index -= 1;
1980 it.node = child.next;
1981 return child.data;
1982 }
1800 },1983 },
1801 .StructInitializer => |*fields| {1984 .StructInitializer => |fields| {
1802 if (i < fields.len) return fields.at(i).*;1985 if (it.node) |child| {
1803 i -= fields.len;1986 it.index -= 1;
1987 it.node = child.next;
1988 return child.data;
1989 }
1804 },1990 },
1805 .UnwrapOptional,1991 .UnwrapOptional,
1806 .Deref,1992 .Deref,
...@@ -1832,8 +2018,13 @@ pub const Node = struct {...@@ -1832,8 +2018,13 @@ pub const Node = struct {
1832 expr: *Node,2018 expr: *Node,
1833 rparen: TokenIndex,2019 rparen: TokenIndex,
18342020
1835 pub fn iterate(self: *GroupedExpression, index: usize) ?*Node {2021 pub fn iterate(self: *const GroupedExpression) Node.Iterator {
1836 var i = index;2022 return .{ .parent_node = &self.base, .index = 0, .node = null };
2023 }
2024
2025 pub fn iterateNext(self: *const GroupedExpression, it: *Node.Iterator) ?*Node {
2026 var i = it.index;
2027 it.index += 1;
18372028
1838 if (i < 1) return self.expr;2029 if (i < 1) return self.expr;
1839 i -= 1;2030 i -= 1;
...@@ -1862,8 +2053,13 @@ pub const Node = struct {...@@ -1862,8 +2053,13 @@ pub const Node = struct {
1862 Return,2053 Return,
1863 };2054 };
18642055
1865 pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node {2056 pub fn iterate(self: *const ControlFlowExpression) Node.Iterator {
1866 var i = index;2057 return .{ .parent_node = &self.base, .index = 0, .node = null };
2058 }
2059
2060 pub fn iterateNext(self: *const ControlFlowExpression, it: *Node.Iterator) ?*Node {
2061 var i = it.index;
2062 it.index += 1;
18672063
1868 switch (self.kind) {2064 switch (self.kind) {
1869 .Break, .Continue => |maybe_label| {2065 .Break, .Continue => |maybe_label| {
...@@ -1910,8 +2106,13 @@ pub const Node = struct {...@@ -1910,8 +2106,13 @@ pub const Node = struct {
1910 suspend_token: TokenIndex,2106 suspend_token: TokenIndex,
1911 body: ?*Node,2107 body: ?*Node,
19122108
1913 pub fn iterate(self: *Suspend, index: usize) ?*Node {2109 pub fn iterate(self: *const Suspend) Node.Iterator {
1914 var i = index;2110 return .{ .parent_node = &self.base, .index = 0, .node = null };
2111 }
2112
2113 pub fn iterateNext(self: *const Suspend, it: *Node.Iterator) ?*Node {
2114 var i = it.index;
2115 it.index += 1;
19152116
1916 if (self.body) |body| {2117 if (self.body) |body| {
1917 if (i < 1) return body;2118 if (i < 1) return body;
...@@ -1938,7 +2139,11 @@ pub const Node = struct {...@@ -1938,7 +2139,11 @@ pub const Node = struct {
1938 base: Node = Node{ .id = .IntegerLiteral },2139 base: Node = Node{ .id = .IntegerLiteral },
1939 token: TokenIndex,2140 token: TokenIndex,
19402141
1941 pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {2142 pub fn iterate(self: *const IntegerLiteral) Node.Iterator {
2143 return .{ .parent_node = &self.base, .index = 0, .node = null };
2144 }
2145
2146 pub fn iterateNext(self: *const IntegerLiteral, it: *Node.Iterator) ?*Node {
1942 return null;2147 return null;
1943 }2148 }
19442149
...@@ -1956,7 +2161,11 @@ pub const Node = struct {...@@ -1956,7 +2161,11 @@ pub const Node = struct {
1956 dot: TokenIndex,2161 dot: TokenIndex,
1957 name: TokenIndex,2162 name: TokenIndex,
19582163
1959 pub fn iterate(self: *EnumLiteral, index: usize) ?*Node {2164 pub fn iterate(self: *const EnumLiteral) Node.Iterator {
2165 return .{ .parent_node = &self.base, .index = 0, .node = null };
2166 }
2167
2168 pub fn iterateNext(self: *const EnumLiteral, it: *Node.Iterator) ?*Node {
1960 return null;2169 return null;
1961 }2170 }
19622171
...@@ -1973,7 +2182,11 @@ pub const Node = struct {...@@ -1973,7 +2182,11 @@ pub const Node = struct {
1973 base: Node = Node{ .id = .FloatLiteral },2182 base: Node = Node{ .id = .FloatLiteral },
1974 token: TokenIndex,2183 token: TokenIndex,
19752184
1976 pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {2185 pub fn iterate(self: *const FloatLiteral) Node.Iterator {
2186 return .{ .parent_node = &self.base, .index = 0, .node = null };
2187 }
2188
2189 pub fn iterateNext(self: *const FloatLiteral, it: *Node.Iterator) ?*Node {
1977 return null;2190 return null;
1978 }2191 }
19792192
...@@ -1992,15 +2205,16 @@ pub const Node = struct {...@@ -1992,15 +2205,16 @@ pub const Node = struct {
1992 params: ParamList,2205 params: ParamList,
1993 rparen_token: TokenIndex,2206 rparen_token: TokenIndex,
19942207
1995 pub const ParamList = SegmentedList(*Node, 2);2208 pub const ParamList = LinkedList(*Node);
19962209
1997 pub fn iterate(self: *BuiltinCall, index: usize) ?*Node {2210 pub fn iterate(self: *const BuiltinCall) Node.Iterator {
1998 var i = index;2211 return .{ .parent_node = &self.base, .index = 0, .node = self.params.first };
19992212 }
2000 if (i < self.params.len) return self.params.at(i).*;
2001 i -= self.params.len;
20022213
2003 return null;2214 pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {
2215 const param = it.node orelse return null;
2216 it.node = param.next;
2217 return param.data;
2004 }2218 }
20052219
2006 pub fn firstToken(self: *const BuiltinCall) TokenIndex {2220 pub fn firstToken(self: *const BuiltinCall) TokenIndex {
...@@ -2016,7 +2230,11 @@ pub const Node = struct {...@@ -2016,7 +2230,11 @@ pub const Node = struct {
2016 base: Node = Node{ .id = .StringLiteral },2230 base: Node = Node{ .id = .StringLiteral },
2017 token: TokenIndex,2231 token: TokenIndex,
20182232
2019 pub fn iterate(self: *StringLiteral, index: usize) ?*Node {2233 pub fn iterate(self: *const StringLiteral) Node.Iterator {
2234 return .{ .parent_node = &self.base, .index = 0, .node = null };
2235 }
2236
2237 pub fn iterateNext(self: *const StringLiteral, it: *Node.Iterator) ?*Node {
2020 return null;2238 return null;
2021 }2239 }
20222240
...@@ -2033,18 +2251,25 @@ pub const Node = struct {...@@ -2033,18 +2251,25 @@ pub const Node = struct {
2033 base: Node = Node{ .id = .MultilineStringLiteral },2251 base: Node = Node{ .id = .MultilineStringLiteral },
2034 lines: LineList,2252 lines: LineList,
20352253
2036 pub const LineList = SegmentedList(TokenIndex, 4);2254 pub const LineList = LinkedList(TokenIndex);
2255
2256 pub fn iterate(self: *const MultilineStringLiteral) Node.Iterator {
2257 return .{ .parent_node = &self.base, .index = 0, .node = null };
2258 }
20372259
2038 pub fn iterate(self: *MultilineStringLiteral, index: usize) ?*Node {2260 pub fn iterateNext(self: *const MultilineStringLiteral, it: *Node.Iterator) ?*Node {
2039 return null;2261 return null;
2040 }2262 }
20412263
2042 pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {2264 pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {
2043 return self.lines.at(0).*;2265 return self.lines.first.?.data;
2044 }2266 }
20452267
2046 pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex {2268 pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex {
2047 return self.lines.at(self.lines.len - 1).*;2269 var node = self.lines.first.?;
2270 while (true) {
2271 node = node.next orelse return node.data;
2272 }
2048 }2273 }
2049 };2274 };
20502275
...@@ -2052,7 +2277,11 @@ pub const Node = struct {...@@ -2052,7 +2277,11 @@ pub const Node = struct {
2052 base: Node = Node{ .id = .CharLiteral },2277 base: Node = Node{ .id = .CharLiteral },
2053 token: TokenIndex,2278 token: TokenIndex,
20542279
2055 pub fn iterate(self: *CharLiteral, index: usize) ?*Node {2280 pub fn iterate(self: *const CharLiteral) Node.Iterator {
2281 return .{ .parent_node = &self.base, .index = 0, .node = null };
2282 }
2283
2284 pub fn iterateNext(self: *const CharLiteral, it: *Node.Iterator) ?*Node {
2056 return null;2285 return null;
2057 }2286 }
20582287
...@@ -2069,7 +2298,11 @@ pub const Node = struct {...@@ -2069,7 +2298,11 @@ pub const Node = struct {
2069 base: Node = Node{ .id = .BoolLiteral },2298 base: Node = Node{ .id = .BoolLiteral },
2070 token: TokenIndex,2299 token: TokenIndex,
20712300
2072 pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {2301 pub fn iterate(self: *const BoolLiteral) Node.Iterator {
2302 return .{ .parent_node = &self.base, .index = 0, .node = null };
2303 }
2304
2305 pub fn iterateNext(self: *const BoolLiteral, it: *Node.Iterator) ?*Node {
2073 return null;2306 return null;
2074 }2307 }
20752308
...@@ -2086,7 +2319,11 @@ pub const Node = struct {...@@ -2086,7 +2319,11 @@ pub const Node = struct {
2086 base: Node = Node{ .id = .NullLiteral },2319 base: Node = Node{ .id = .NullLiteral },
2087 token: TokenIndex,2320 token: TokenIndex,
20882321
2089 pub fn iterate(self: *NullLiteral, index: usize) ?*Node {2322 pub fn iterate(self: *const NullLiteral) Node.Iterator {
2323 return .{ .parent_node = &self.base, .index = 0, .node = null };
2324 }
2325
2326 pub fn iterateNext(self: *const NullLiteral, it: *Node.Iterator) ?*Node {
2090 return null;2327 return null;
2091 }2328 }
20922329
...@@ -2103,7 +2340,11 @@ pub const Node = struct {...@@ -2103,7 +2340,11 @@ pub const Node = struct {
2103 base: Node = Node{ .id = .UndefinedLiteral },2340 base: Node = Node{ .id = .UndefinedLiteral },
2104 token: TokenIndex,2341 token: TokenIndex,
21052342
2106 pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {2343 pub fn iterate(self: *const UndefinedLiteral) Node.Iterator {
2344 return .{ .parent_node = &self.base, .index = 0, .node = null };
2345 }
2346
2347 pub fn iterateNext(self: *const UndefinedLiteral, it: *Node.Iterator) ?*Node {
2107 return null;2348 return null;
2108 }2349 }
21092350
...@@ -2129,8 +2370,13 @@ pub const Node = struct {...@@ -2129,8 +2370,13 @@ pub const Node = struct {
2129 Return: *Node,2370 Return: *Node,
2130 };2371 };
21312372
2132 pub fn iterate(self: *AsmOutput, index: usize) ?*Node {2373 pub fn iterate(self: *const AsmOutput) Node.Iterator {
2133 var i = index;2374 return .{ .parent_node = &self.base, .index = 0, .node = null };
2375 }
2376
2377 pub fn iterateNext(self: *const AsmOutput, it: *Node.Iterator) ?*Node {
2378 var i = it.index;
2379 it.index += 1;
21342380
2135 if (i < 1) return self.symbolic_name;2381 if (i < 1) return self.symbolic_name;
2136 i -= 1;2382 i -= 1;
...@@ -2169,8 +2415,13 @@ pub const Node = struct {...@@ -2169,8 +2415,13 @@ pub const Node = struct {
2169 expr: *Node,2415 expr: *Node,
2170 rparen: TokenIndex,2416 rparen: TokenIndex,
21712417
2172 pub fn iterate(self: *AsmInput, index: usize) ?*Node {2418 pub fn iterate(self: *const AsmInput) Node.Iterator {
2173 var i = index;2419 return .{ .parent_node = &self.base, .index = 0, .node = null };
2420 }
2421
2422 pub fn iterateNext(self: *const AsmInput, it: *Node.Iterator) ?*Node {
2423 var i = it.index;
2424 it.index += 1;
21742425
2175 if (i < 1) return self.symbolic_name;2426 if (i < 1) return self.symbolic_name;
2176 i -= 1;2427 i -= 1;
...@@ -2203,18 +2454,31 @@ pub const Node = struct {...@@ -2203,18 +2454,31 @@ pub const Node = struct {
2203 clobbers: ClobberList,2454 clobbers: ClobberList,
2204 rparen: TokenIndex,2455 rparen: TokenIndex,
22052456
2206 pub const OutputList = SegmentedList(*AsmOutput, 2);2457 pub const OutputList = LinkedList(*AsmOutput);
2207 pub const InputList = SegmentedList(*AsmInput, 2);2458 pub const InputList = LinkedList(*AsmInput);
2208 pub const ClobberList = SegmentedList(*Node, 2);2459 pub const ClobberList = LinkedList(*Node);
22092460
2210 pub fn iterate(self: *Asm, index: usize) ?*Node {2461 pub fn iterate(self: *const Asm) Node.Iterator {
2211 var i = index;2462 return .{ .parent_node = &self.base, .index = 0, .node = null};
2463 }
22122464
2213 if (i < self.outputs.len) return &self.outputs.at(i).*.base;2465 pub fn iterateNext(self: *const Asm, it: *Node.Iterator) ?*Node {
2214 i -= self.outputs.len;2466 var i = it.index;
2467 it.index += 1;
22152468
2216 if (i < self.inputs.len) return &self.inputs.at(i).*.base;2469 var output: ?*LinkedList(*AsmOutput).Node = self.outputs.first;
2217 i -= self.inputs.len;2470 while (output) |o| {
2471 if (i < 1) return &o.data.base;
2472 i -= 1;
2473 output = o.next;
2474 }
2475
2476 var input: ?*LinkedList(*AsmInput).Node = self.inputs.first;
2477 while (input) |o| {
2478 if (i < 1) return &o.data.base;
2479 i -= 1;
2480 input = o.next;
2481 }
22182482
2219 return null;2483 return null;
2220 }2484 }
...@@ -2232,7 +2496,11 @@ pub const Node = struct {...@@ -2232,7 +2496,11 @@ pub const Node = struct {
2232 base: Node = Node{ .id = .Unreachable },2496 base: Node = Node{ .id = .Unreachable },
2233 token: TokenIndex,2497 token: TokenIndex,
22342498
2235 pub fn iterate(self: *Unreachable, index: usize) ?*Node {2499 pub fn iterate(self: *const Unreachable) Node.Iterator {
2500 return .{ .parent_node = &self.base, .index = 0, .node = null };
2501 }
2502
2503 pub fn iterateNext(self: *const Unreachable, it: *Node.Iterator) ?*Node {
2236 return null;2504 return null;
2237 }2505 }
22382506
...@@ -2249,7 +2517,11 @@ pub const Node = struct {...@@ -2249,7 +2517,11 @@ pub const Node = struct {
2249 base: Node = Node{ .id = .ErrorType },2517 base: Node = Node{ .id = .ErrorType },
2250 token: TokenIndex,2518 token: TokenIndex,
22512519
2252 pub fn iterate(self: *ErrorType, index: usize) ?*Node {2520 pub fn iterate(self: *const ErrorType) Node.Iterator {
2521 return .{ .parent_node = &self.base, .index = 0, .node = null };
2522 }
2523
2524 pub fn iterateNext(self: *const ErrorType, it: *Node.Iterator) ?*Node {
2253 return null;2525 return null;
2254 }2526 }
22552527
...@@ -2266,7 +2538,11 @@ pub const Node = struct {...@@ -2266,7 +2538,11 @@ pub const Node = struct {
2266 base: Node = Node{ .id = .VarType },2538 base: Node = Node{ .id = .VarType },
2267 token: TokenIndex,2539 token: TokenIndex,
22682540
2269 pub fn iterate(self: *VarType, index: usize) ?*Node {2541 pub fn iterate(self: *const VarType) Node.Iterator {
2542 return .{ .parent_node = &self.base, .index = 0, .node = null };
2543 }
2544
2545 pub fn iterateNext(self: *const VarType, it: *Node.Iterator) ?*Node {
2270 return null;2546 return null;
2271 }2547 }
22722548
...@@ -2283,18 +2559,25 @@ pub const Node = struct {...@@ -2283,18 +2559,25 @@ pub const Node = struct {
2283 base: Node = Node{ .id = .DocComment },2559 base: Node = Node{ .id = .DocComment },
2284 lines: LineList,2560 lines: LineList,
22852561
2286 pub const LineList = SegmentedList(TokenIndex, 4);2562 pub const LineList = LinkedList(TokenIndex);
2563
2564 pub fn iterate(self: *const DocComment) Node.Iterator {
2565 return .{ .parent_node = &self.base, .index = 0, .node = null };
2566 }
22872567
2288 pub fn iterate(self: *DocComment, index: usize) ?*Node {2568 pub fn iterateNext(self: *const DocComment, it: *Node.Iterator) ?*Node {
2289 return null;2569 return null;
2290 }2570 }
22912571
2292 pub fn firstToken(self: *const DocComment) TokenIndex {2572 pub fn firstToken(self: *const DocComment) TokenIndex {
2293 return self.lines.at(0).*;2573 return self.lines.first.?.data;
2294 }2574 }
22952575
2296 pub fn lastToken(self: *const DocComment) TokenIndex {2576 pub fn lastToken(self: *const DocComment) TokenIndex {
2297 return self.lines.at(self.lines.len - 1).*;2577 var node = self.lines.first.?;
2578 while (true) {
2579 node = node.next orelse return node.data;
2580 }
2298 }2581 }
2299 };2582 };
23002583
...@@ -2305,8 +2588,13 @@ pub const Node = struct {...@@ -2305,8 +2588,13 @@ pub const Node = struct {
2305 name: *Node,2588 name: *Node,
2306 body_node: *Node,2589 body_node: *Node,
23072590
2308 pub fn iterate(self: *TestDecl, index: usize) ?*Node {2591 pub fn iterate(self: *const TestDecl) Node.Iterator {
2309 var i = index;2592 return .{ .parent_node = &self.base, .index = 0, .node = null };
2593 }
2594
2595 pub fn iterateNext(self: *const TestDecl, it: *Node.Iterator) ?*Node {
2596 var i = it.index;
2597 it.index += 1;
23102598
2311 if (i < 1) return self.body_node;2599 if (i < 1) return self.body_node;
2312 i -= 1;2600 i -= 1;
...@@ -2331,5 +2619,6 @@ test "iterate" {...@@ -2331,5 +2619,6 @@ test "iterate" {
2331 .eof_token = 0,2619 .eof_token = 0,
2332 };2620 };
2333 var base = &root.base;2621 var base = &root.base;
2334 testing.expect(base.iterate(0) == null);2622 var it = base.iterate();
2623 testing.expect(it.next() == null);
2335}2624}
lib/std/zig/parse.zig+2852-2806
...@@ -7,3303 +7,3349 @@ const Tree = ast.Tree;...@@ -7,3303 +7,3349 @@ const Tree = ast.Tree;
7const AstError = ast.Error;7const AstError = ast.Error;
8const TokenIndex = ast.TokenIndex;8const TokenIndex = ast.TokenIndex;
9const Token = std.zig.Token;9const Token = std.zig.Token;
10const TokenIterator = Tree.TokenList.Iterator;
1110
12pub const Error = error{ParseError} || Allocator.Error;11pub const Error = error{ParseError} || Allocator.Error;
1312
14/// Result should be freed with tree.deinit() when there are13/// Result should be freed with tree.deinit() when there are
15/// no more references to any of the tokens or nodes.14/// no more references to any of the tokens or nodes.
16pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {15pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
17 const tree = blk: {16 // TODO optimization idea: ensureCapacity on the tokens list and
18 // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists17 // then appendAssumeCapacity inside the loop.
19 // from being initialized with a pointer to this `arena`, which is created on18 var tokens = std.ArrayList(Token).init(gpa);
20 // the stack. Following code should instead refer to `&tree.arena_allocator`, a19 defer tokens.deinit();
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);
4020
41 var tokenizer = std.zig.Tokenizer.init(source);21 var tokenizer = std.zig.Tokenizer.init(source);
42 while (true) {22 while (true) {
43 const tree_token = try tree.tokens.addOne();23 const tree_token = try tokens.addOne();
44 tree_token.* = tokenizer.next();24 tree_token.* = tokenizer.next();
45 if (tree_token.id == .Eof) break;25 if (tree_token.id == .Eof) break;
46 }26 }
47 var it = tree.tokens.iterator(0);
4827
49 while (it.peek().?.id == .LineComment) _ = it.next();28 var parser: Parser = .{
29 .source = source,
30 .arena = std.heap.ArenaAllocator.init(gpa),
31 .gpa = gpa,
32 .tokens = tokens.items,
33 .errors = .{},
34 .tok_i = 0,
35 };
36 defer parser.errors.deinit(gpa);
37 errdefer parser.arena.deinit();
5038
51 tree.root_node = try parseRoot(arena, &it, tree);39 while (tokens.items[parser.tok_i].id == .LineComment) parser.tok_i += 1;
5240
53 return tree;41 const root_node = try parser.parseRoot();
54}
5542
56/// Root <- skip ContainerMembers eof43 const tree = try parser.arena.allocator.create(Tree);
57fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {44 tree.* = .{
58 const node = try arena.create(Node.Root);45 .gpa = gpa,
59 node.* = .{46 .source = source,
60 .decls = try parseContainerMembers(arena, it, tree, true),47 .tokens = tokens.toOwnedSlice(),
61 // parseContainerMembers will try to skip as much48 .errors = parser.errors.toOwnedSlice(gpa),
62 // invalid tokens as it can so this can only be the EOF49 .root_node = root_node,
63 .eof_token = eatToken(it, .Eof).?,50 .arena = parser.arena.state,
64 };51 };
65 return node;52 return tree;
66}53}
6754
68/// ContainerMembers55/// Represents in-progress parsing, will be converted to an ast.Tree after completion.
69/// <- TestDecl ContainerMembers56const Parser = struct {
70/// / TopLevelComptime ContainerMembers57 arena: std.heap.ArenaAllocator,
71/// / KEYWORD_pub? TopLevelDecl ContainerMembers58 gpa: *Allocator,
72/// / ContainerField COMMA ContainerMembers59 source: []const u8,
73/// / ContainerField60 tokens: []const Token,
74/// /61 tok_i: TokenIndex,
75fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top_level: bool) !Node.Root.DeclList {62 errors: std.ArrayListUnmanaged(AstError),
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;
8963
90 while (true) {64 /// Root <- skip ContainerMembers eof
91 if (try parseContainerDocComments(arena, it, tree)) |node| {65 fn parseRoot(p: *Parser) Allocator.Error!*Node.Root {
92 try list.push(node);66 const node = try p.arena.allocator.create(Node.Root);
93 continue;67 node.* = .{
94 }68 .decls = try parseContainerMembers(p, true),
69 // parseContainerMembers will try to skip as much
70 // invalid tokens as it can so this can only be the EOF
71 .eof_token = p.eatToken(.Eof).?,
72 };
73 return node;
74 }
9575
96 const doc_comments = try parseDocComment(arena, it, tree);76 fn llpush(
77 p: *Parser,
78 comptime T: type,
79 it: *?*std.SinglyLinkedList(T).Node,
80 data: T,
81 ) !*?*std.SinglyLinkedList(T).Node {
82 const llnode = try p.arena.allocator.create(std.SinglyLinkedList(T).Node);
83 llnode.* = .{ .data = data };
84 it.* = llnode;
85 return &llnode.next;
86 }
87
88 /// ContainerMembers
89 /// <- TestDecl ContainerMembers
90 /// / TopLevelComptime ContainerMembers
91 /// / KEYWORD_pub? TopLevelDecl ContainerMembers
92 /// / ContainerField COMMA ContainerMembers
93 /// / ContainerField
94 /// /
95 fn parseContainerMembers(p: *Parser, top_level: bool) !Node.Root.DeclList {
96 var list = Node.Root.DeclList{};
97 var list_it = &list.first;
98
99 var field_state: union(enum) {
100 /// no fields have been seen
101 none,
102 /// currently parsing fields
103 seen,
104 /// saw fields and then a declaration after them.
105 /// payload is first token of previous declaration.
106 end: TokenIndex,
107 /// ther was a declaration between fields, don't report more errors
108 err,
109 } = .none;
97110
98 if (parseTestDecl(arena, it, tree) catch |err| switch (err) {111 while (true) {
99 error.OutOfMemory => return error.OutOfMemory,112 if (try p.parseContainerDocComments()) |node| {
100 error.ParseError => {113 list_it = try p.llpush(*Node, list_it, node);
101 findNextContainerMember(it);
102 continue;114 continue;
103 },
104 }) |node| {
105 if (field_state == .seen) {
106 field_state = .{ .end = node.firstToken() };
107 }115 }
108 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
109 try list.push(node);
110 continue;
111 }
112116
113 if (parseTopLevelComptime(arena, it, tree) catch |err| switch (err) {117 const doc_comments = try p.parseDocComment();
114 error.OutOfMemory => return error.OutOfMemory,118
115 error.ParseError => {119 if (p.parseTestDecl() catch |err| switch (err) {
116 findNextContainerMember(it);120 error.OutOfMemory => return error.OutOfMemory,
121 error.ParseError => {
122 p.findNextContainerMember();
123 continue;
124 },
125 }) |node| {
126 if (field_state == .seen) {
127 field_state = .{ .end = node.firstToken() };
128 }
129 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
130 list_it = try p.llpush(*Node, list_it, node);
117 continue;131 continue;
118 },
119 }) |node| {
120 if (field_state == .seen) {
121 field_state = .{ .end = node.firstToken() };
122 }132 }
123 node.cast(Node.Comptime).?.doc_comments = doc_comments;
124 try list.push(node);
125 continue;
126 }
127
128 const visib_token = eatToken(it, .Keyword_pub);
129133
130 if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {134 if (p.parseTopLevelComptime() catch |err| switch (err) {
131 error.OutOfMemory => return error.OutOfMemory,135 error.OutOfMemory => return error.OutOfMemory,
132 error.ParseError => {136 error.ParseError => {
133 findNextContainerMember(it);137 p.findNextContainerMember();
138 continue;
139 },
140 }) |node| {
141 if (field_state == .seen) {
142 field_state = .{ .end = node.firstToken() };
143 }
144 node.cast(Node.Comptime).?.doc_comments = doc_comments;
145 list_it = try p.llpush(*Node, list_it, node);
134 continue;146 continue;
135 },
136 }) |node| {
137 if (field_state == .seen) {
138 field_state = .{ .end = visib_token orelse node.firstToken() };
139 }147 }
140 switch (node.id) {148
141 .FnProto => {149 const visib_token = p.eatToken(.Keyword_pub);
142 node.cast(Node.FnProto).?.doc_comments = doc_comments;150
143 node.cast(Node.FnProto).?.visib_token = visib_token;151 if (p.parseTopLevelDecl() catch |err| switch (err) {
144 },152 error.OutOfMemory => return error.OutOfMemory,
145 .VarDecl => {153 error.ParseError => {
146 node.cast(Node.VarDecl).?.doc_comments = doc_comments;154 p.findNextContainerMember();
147 node.cast(Node.VarDecl).?.visib_token = visib_token;155 continue;
148 },
149 .Use => {
150 node.cast(Node.Use).?.doc_comments = doc_comments;
151 node.cast(Node.Use).?.visib_token = visib_token;
152 },156 },
153 else => unreachable,157 }) |node| {
154 }158 if (field_state == .seen) {
155 try list.push(node);159 field_state = .{ .end = visib_token orelse node.firstToken() };
156 if (try parseAppendedDocComment(arena, it, tree, node.lastToken())) |appended_comment| {160 }
157 switch (node.id) {161 switch (node.id) {
158 .FnProto => {},162 .FnProto => {
159 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,163 node.cast(Node.FnProto).?.doc_comments = doc_comments;
160 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,164 node.cast(Node.FnProto).?.visib_token = visib_token;
165 },
166 .VarDecl => {
167 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
168 node.cast(Node.VarDecl).?.visib_token = visib_token;
169 },
170 .Use => {
171 node.cast(Node.Use).?.doc_comments = doc_comments;
172 node.cast(Node.Use).?.visib_token = visib_token;
173 },
161 else => unreachable,174 else => unreachable,
162 }175 }
176 list_it = try p.llpush(*Node, list_it, node);
177 if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| {
178 switch (node.id) {
179 .FnProto => {},
180 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
181 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
182 else => unreachable,
183 }
184 }
185 continue;
163 }186 }
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 }
174187
175 if (parseContainerField(arena, it, tree) catch |err| switch (err) {188 if (visib_token != null) {
176 error.OutOfMemory => return error.OutOfMemory,189 try p.errors.append(p.gpa, .{
177 error.ParseError => {190 .ExpectedPubItem = .{ .token = p.tok_i },
178 // attempt to recover191 });
179 findNextContainerMember(it);192 // ignore this pub
180 continue;193 continue;
181 },
182 }) |node| {
183 switch (field_state) {
184 .none => field_state = .seen,
185 .err, .seen => {},
186 .end => |tok| {
187 try tree.errors.push(.{
188 .DeclBetweenFields = .{ .token = tok },
189 });
190 // continue parsing, error will be reported later
191 field_state = .err;
192 },
193 }194 }
194195
195 const field = node.cast(Node.ContainerField).?;196 if (p.parseContainerField() catch |err| switch (err) {
196 field.doc_comments = doc_comments;197 error.OutOfMemory => return error.OutOfMemory,
197 try list.push(node);198 error.ParseError => {
198 const comma = eatToken(it, .Comma) orelse {199 // attempt to recover
199 // try to continue parsing200 p.findNextContainerMember();
200 const index = it.index;201 continue;
201 findNextContainerMember(it);202 },
202 const next = it.peek().?.id;203 }) |node| {
203 switch (next) {204 switch (field_state) {
204 .Eof => break,205 .none => field_state = .seen,
205 else => {206 .err, .seen => {},
206 if (next == .RBrace) {207 .end => |tok| {
207 if (!top_level) break;208 try p.errors.append(p.gpa, .{
208 _ = nextToken(it);209 .DeclBetweenFields = .{ .token = tok },
209 }
210
211 // add error and continue
212 try tree.errors.push(.{
213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
214 });210 });
215 continue;211 // continue parsing, error will be reported later
212 field_state = .err;
216 },213 },
217 }214 }
218 };
219 if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment|
220 field.doc_comments = appended_comment;
221 continue;
222 }
223215
224 // Dangling doc comment216 const field = node.cast(Node.ContainerField).?;
225 if (doc_comments != null) {217 field.doc_comments = doc_comments;
226 try tree.errors.push(.{218 list_it = try p.llpush(*Node, list_it, node);
227 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },219 const comma = p.eatToken(.Comma) orelse {
228 });220 // try to continue parsing
229 }221 const index = p.tok_i;
222 p.findNextContainerMember();
223 const next = p.tokens[p.tok_i].id;
224 switch (next) {
225 .Eof => break,
226 else => {
227 if (next == .RBrace) {
228 if (!top_level) break;
229 _ = p.nextToken();
230 }
231
232 // add error and continue
233 try p.errors.append(p.gpa, .{
234 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
235 });
236 continue;
237 },
238 }
239 };
240 if (try p.parseAppendedDocComment(comma)) |appended_comment|
241 field.doc_comments = appended_comment;
242 continue;
243 }
230244
231 const next = it.peek().?.id;245 // Dangling doc comment
232 switch (next) {246 if (doc_comments != null) {
233 .Eof => break,247 try p.errors.append(p.gpa, .{
234 .Keyword_comptime => {248 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
235 _ = nextToken(it);
236 try tree.errors.push(.{
237 .ExpectedBlockOrField = .{ .token = it.index },
238 });249 });
239 },250 }
240 else => {
241 const index = it.index;
242 if (next == .RBrace) {
243 if (!top_level) break;
244 _ = nextToken(it);
245 }
246251
247 // this was likely not supposed to end yet,252 const next = p.tokens[p.tok_i].id;
248 // try to find the next declaration253 switch (next) {
249 findNextContainerMember(it);254 .Eof => break,
250 try tree.errors.push(.{255 .Keyword_comptime => {
251 .ExpectedContainerMembers = .{ .token = index },256 _ = p.nextToken();
252 });257 try p.errors.append(p.gpa, .{
253 },258 .ExpectedBlockOrField = .{ .token = p.tok_i },
259 });
260 },
261 else => {
262 const index = p.tok_i;
263 if (next == .RBrace) {
264 if (!top_level) break;
265 _ = p.nextToken();
266 }
267
268 // this was likely not supposed to end yet,
269 // try to find the next declaration
270 p.findNextContainerMember();
271 try p.errors.append(p.gpa, .{
272 .ExpectedContainerMembers = .{ .token = index },
273 });
274 },
275 }
254 }276 }
255 }
256277
257 return list;278 return list;
258}279 }
259280
260/// Attempts to find next container member by searching for certain tokens281 /// Attempts to find next container member by searching for certain tokens
261fn findNextContainerMember(it: *TokenIterator) void {282 fn findNextContainerMember(p: *Parser) void {
262 var level: u32 = 0;283 var level: u32 = 0;
263 while (true) {284 while (true) {
264 const tok = nextToken(it);285 const tok = p.nextToken();
265 switch (tok.ptr.id) {286 switch (tok.ptr.id) {
266 // any of these can start a new top level declaration287 // any of these can start a new top level declaration
267 .Keyword_test,288 .Keyword_test,
268 .Keyword_comptime,289 .Keyword_comptime,
269 .Keyword_pub,290 .Keyword_pub,
270 .Keyword_export,291 .Keyword_export,
271 .Keyword_extern,292 .Keyword_extern,
272 .Keyword_inline,293 .Keyword_inline,
273 .Keyword_noinline,294 .Keyword_noinline,
274 .Keyword_usingnamespace,295 .Keyword_usingnamespace,
275 .Keyword_threadlocal,296 .Keyword_threadlocal,
276 .Keyword_const,297 .Keyword_const,
277 .Keyword_var,298 .Keyword_var,
278 .Keyword_fn,299 .Keyword_fn,
279 .Identifier,300 .Identifier,
280 => {301 => {
281 if (level == 0) {302 if (level == 0) {
282 putBackToken(it, tok.index);303 p.putBackToken(tok.index);
283 return;304 return;
284 }305 }
285 },306 },
286 .Comma, .Semicolon => {307 .Comma, .Semicolon => {
287 // this decl was likely meant to end here308 // this decl was likely meant to end here
288 if (level == 0) {309 if (level == 0) {
289 return;310 return;
290 }311 }
291 },312 },
292 .LParen, .LBracket, .LBrace => level += 1,313 .LParen, .LBracket, .LBrace => level += 1,
293 .RParen, .RBracket => {314 .RParen, .RBracket => {
294 if (level != 0) level -= 1;315 if (level != 0) level -= 1;
295 },316 },
296 .RBrace => {317 .RBrace => {
297 if (level == 0) {318 if (level == 0) {
298 // end of container, exit319 // end of container, exit
299 putBackToken(it, tok.index);320 p.putBackToken(tok.index);
321 return;
322 }
323 level -= 1;
324 },
325 .Eof => {
326 p.putBackToken(tok.index);
300 return;327 return;
301 }328 },
302 level -= 1;329 else => {},
303 },330 }
304 .Eof => {
305 putBackToken(it, tok.index);
306 return;
307 },
308 else => {},
309 }331 }
310 }332 }
311}
312333
313/// Attempts to find the next statement by searching for a semicolon334 /// Attempts to find the next statement by searching for a semicolon
314fn findNextStmt(it: *TokenIterator) void {335 fn findNextStmt(p: *Parser) void {
315 var level: u32 = 0;336 var level: u32 = 0;
316 while (true) {337 while (true) {
317 const tok = nextToken(it);338 const tok = p.nextToken();
318 switch (tok.ptr.id) {339 switch (tok.ptr.id) {
319 .LBrace => level += 1,340 .LBrace => level += 1,
320 .RBrace => {341 .RBrace => {
321 if (level == 0) {342 if (level == 0) {
322 putBackToken(it, tok.index);343 p.putBackToken(tok.index);
323 return;344 return;
324 }345 }
325 level -= 1;346 level -= 1;
326 },347 },
327 .Semicolon => {348 .Semicolon => {
328 if (level == 0) {349 if (level == 0) {
350 return;
351 }
352 },
353 .Eof => {
354 p.putBackToken(tok.index);
329 return;355 return;
330 }356 },
331 },357 else => {},
332 .Eof => {358 }
333 putBackToken(it, tok.index);
334 return;
335 },
336 else => {},
337 }359 }
338 }360 }
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}
397361
398/// TopLevelDecl362 /// Eat a multiline container doc comment
399/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)363 fn parseContainerDocComments(p: *Parser) !?*Node {
400/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl364 var lines = Node.DocComment.LineList{};
401/// / KEYWORD_usingnamespace Expr SEMICOLON365 var lines_it: *?*Node.DocComment.LineList.Node = &lines.first;
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 };
414
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;
428 }
429 return node;
430 }
431366
432 if (extern_export_inline_token) |token| {367 while (p.eatToken(.ContainerDocComment)) |line| {
433 if (tree.tokens.at(token).id == .Keyword_inline or368 lines_it = try p.llpush(TokenIndex, lines_it, line);
434 tree.tokens.at(token).id == .Keyword_noinline)
435 {
436 try tree.errors.push(.{
437 .ExpectedFn = .{ .token = it.index },
438 });
439 return error.ParseError;
440 }369 }
441 }
442370
443 const thread_local_token = eatToken(it, .Keyword_threadlocal);371 if (lines.first == null) return null;
444372
445 if (try parseVarDecl(arena, it, tree)) |node| {373 const node = try p.arena.allocator.create(Node.DocComment);
446 var var_decl = node.cast(Node.VarDecl).?;374 node.* = .{
447 var_decl.*.thread_local_token = thread_local_token;375 .lines = lines,
448 var_decl.*.comptime_token = null;376 };
449 var_decl.*.extern_export_token = extern_export_inline_token;377 return &node.base;
450 var_decl.*.lib_name = lib_name;
451 return node;
452 }378 }
453379
454 if (thread_local_token != null) {380 /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block
455 try tree.errors.push(.{381 fn parseTestDecl(p: *Parser) !?*Node {
456 .ExpectedVarDecl = .{ .token = it.index },382 const test_token = p.eatToken(.Keyword_test) orelse return null;
383 const name_node = try p.expectNode(parseStringLiteralSingle, .{
384 .ExpectedStringLiteral = .{ .token = p.tok_i },
457 });385 });
458 // ignore this and try again;386 const block_node = try p.expectNode(parseBlock, .{
459 return error.ParseError;387 .ExpectedLBrace = .{ .token = p.tok_i },
460 }
461
462 if (extern_export_inline_token) |token| {
463 try tree.errors.push(.{
464 .ExpectedVarDeclOrFn = .{ .token = it.index },
465 });388 });
466 // ignore this and try again;389
467 return error.ParseError;390 const test_node = try p.arena.allocator.create(Node.TestDecl);
391 test_node.* = .{
392 .doc_comments = null,
393 .test_token = test_token,
394 .name = name_node,
395 .body_node = block_node,
396 };
397 return &test_node.base;
468 }398 }
469399
470 return try parseUse(arena, it, tree);400 /// TopLevelComptime <- KEYWORD_comptime BlockExpr
471}401 fn parseTopLevelComptime(p: *Parser) !?*Node {
402 const tok = p.eatToken(.Keyword_comptime) orelse return null;
403 const lbrace = p.eatToken(.LBrace) orelse {
404 p.putBackToken(tok);
405 return null;
406 };
407 p.putBackToken(lbrace);
408 const block_node = try p.expectNode(parseBlockExpr, .{
409 .ExpectedLabelOrLBrace = .{ .token = p.tok_i },
410 });
472411
473/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)412 const comptime_node = try p.arena.allocator.create(Node.Comptime);
474fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {413 comptime_node.* = .{
475 // TODO: Remove once extern/async fn rewriting is414 .doc_comments = null,
476 var is_async = false;415 .comptime_token = tok,
477 var is_extern = false;416 .expr = block_node,
478 const cc_token: ?usize = blk: {417 };
479 if (eatToken(it, .Keyword_extern)) |token| {418 return &comptime_node.base;
480 is_extern = true;419 }
481 break :blk token;420
482 }421 /// TopLevelDecl
483 if (eatToken(it, .Keyword_async)) |token| {422 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
484 is_async = true;423 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
485 break :blk token;424 /// / KEYWORD_usingnamespace Expr SEMICOLON
486 }425 fn parseTopLevelDecl(p: *Parser) !?*Node {
487 break :blk null;426 var lib_name: ?*Node = null;
488 };427 const extern_export_inline_token = blk: {
489 const fn_token = eatToken(it, .Keyword_fn) orelse {428 if (p.eatToken(.Keyword_export)) |token| break :blk token;
490 if (cc_token) |token|429 if (p.eatToken(.Keyword_extern)) |token| {
491 putBackToken(it, token);430 lib_name = try p.parseStringLiteralSingle();
492 return null;431 break :blk token;
493 };432 }
494 const name_token = eatToken(it, .Identifier);433 if (p.eatToken(.Keyword_inline)) |token| break :blk token;
495 const lparen = try expectToken(it, tree, .LParen);434 if (p.eatToken(.Keyword_noinline)) |token| break :blk token;
496 const params = try parseParamDeclList(arena, it, tree);435 break :blk null;
497 const rparen = try expectToken(it, tree, .RParen);436 };
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 };
543437
544 return &fn_proto_node.base;438 if (try p.parseFnProto()) |node| {
545}439 const fn_node = node.cast(Node.FnProto).?;
440 fn_node.*.extern_export_inline_token = extern_export_inline_token;
441 fn_node.*.lib_name = lib_name;
442 if (p.eatToken(.Semicolon)) |_| return node;
443
444 if (try p.expectNodeRecoverable(parseBlock, .{
445 // since parseBlock only return error.ParseError on
446 // a missing '}' we can assume this function was
447 // supposed to end here.
448 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
449 })) |body_node| {
450 fn_node.body_node = body_node;
451 }
452 return node;
453 }
546454
547/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON455 if (extern_export_inline_token) |token| {
548fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {456 if (p.tokens[token].id == .Keyword_inline or
549 const mut_token = eatToken(it, .Keyword_const) orelse457 p.tokens[token].id == .Keyword_noinline)
550 eatToken(it, .Keyword_var) orelse458 {
551 return null;459 try p.errors.append(p.gpa, .{
460 .ExpectedFn = .{ .token = p.tok_i },
461 });
462 return error.ParseError;
463 }
464 }
552465
553 const name_token = try expectToken(it, tree, .Identifier);466 const thread_local_token = p.eatToken(.Keyword_threadlocal);
554 const type_node = if (eatToken(it, .Colon) != null)
555 try expectNode(arena, it, tree, parseTypeExpr, .{
556 .ExpectedTypeExpr = .{ .token = it.index },
557 })
558 else
559 null;
560 const align_node = try parseByteAlign(arena, it, tree);
561 const section_node = try parseLinkSection(arena, it, tree);
562 const eq_token = eatToken(it, .Equal);
563 const init_node = if (eq_token != null) blk: {
564 break :blk try expectNode(arena, it, tree, parseExpr, .{
565 .ExpectedExpr = .{ .token = it.index },
566 });
567 } else null;
568 const semicolon_token = try expectToken(it, tree, .Semicolon);
569
570 const node = try arena.create(Node.VarDecl);
571 node.* = .{
572 .doc_comments = null,
573 .visib_token = null,
574 .thread_local_token = null,
575 .name_token = name_token,
576 .eq_token = eq_token,
577 .mut_token = mut_token,
578 .comptime_token = null,
579 .extern_export_token = null,
580 .lib_name = null,
581 .type_node = type_node,
582 .align_node = align_node,
583 .section_node = section_node,
584 .init_node = init_node,
585 .semicolon_token = semicolon_token,
586 };
587 return &node.base;
588}
589467
590/// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?468 if (try p.parseVarDecl()) |node| {
591fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {469 var var_decl = node.cast(Node.VarDecl).?;
592 const comptime_token = eatToken(it, .Keyword_comptime);470 var_decl.*.thread_local_token = thread_local_token;
593 const name_token = eatToken(it, .Identifier) orelse {471 var_decl.*.comptime_token = null;
594 if (comptime_token) |t| putBackToken(it, t);472 var_decl.*.extern_export_token = extern_export_inline_token;
595 return null;473 var_decl.*.lib_name = lib_name;
596 };474 return node;
475 }
597476
598 var align_expr: ?*Node = null;477 if (thread_local_token != null) {
599 var type_expr: ?*Node = null;478 try p.errors.append(p.gpa, .{
600 if (eatToken(it, .Colon)) |_| {479 .ExpectedVarDecl = .{ .token = p.tok_i },
601 if (eatToken(it, .Keyword_var)) |var_tok| {
602 const node = try arena.create(ast.Node.VarType);
603 node.* = .{ .token = var_tok };
604 type_expr = &node.base;
605 } else {
606 type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
607 .ExpectedTypeExpr = .{ .token = it.index },
608 });480 });
609 align_expr = try parseByteAlign(arena, it, tree);481 // ignore this and try again;
482 return error.ParseError;
610 }483 }
611 }
612
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;
619484
620 const node = try arena.create(Node.ContainerField);485 if (extern_export_inline_token) |token| {
621 node.* = .{486 try p.errors.append(p.gpa, .{
622 .doc_comments = null,487 .ExpectedVarDeclOrFn = .{ .token = p.tok_i },
623 .comptime_token = comptime_token,488 });
624 .name_token = name_token,489 // ignore this and try again;
625 .type_expr = type_expr,490 return error.ParseError;
626 .value_expr = value_expr,491 }
627 .align_expr = align_expr,
628 };
629 return &node.base;
630}
631492
632/// Statement493 return p.parseUse();
633/// <- KEYWORD_comptime? VarDecl
634/// / KEYWORD_comptime BlockExprStatement
635/// / KEYWORD_nosuspend BlockExprStatement
636/// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
637/// / KEYWORD_defer BlockExprStatement
638/// / KEYWORD_errdefer Payload? BlockExprStatement
639/// / IfStatement
640/// / LabeledStatement
641/// / SwitchExpr
642/// / AssignExpr SEMICOLON
643fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
644 const comptime_token = eatToken(it, .Keyword_comptime);
645
646 const var_decl_node = try parseVarDecl(arena, it, tree);
647 if (var_decl_node) |node| {
648 const var_decl = node.cast(Node.VarDecl).?;
649 var_decl.comptime_token = comptime_token;
650 return node;
651 }494 }
652495
653 if (comptime_token) |token| {496 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
654 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{497 fn parseFnProto(p: *Parser) !?*Node {
655 .ExpectedBlockOrAssignment = .{ .token = it.index },498 // TODO: Remove once extern/async fn rewriting is
499 var is_async = false;
500 var is_extern = false;
501 const cc_token: ?TokenIndex = blk: {
502 if (p.eatToken(.Keyword_extern)) |token| {
503 is_extern = true;
504 break :blk token;
505 }
506 if (p.eatToken(.Keyword_async)) |token| {
507 is_async = true;
508 break :blk token;
509 }
510 break :blk null;
511 };
512 const fn_token = p.eatToken(.Keyword_fn) orelse {
513 if (cc_token) |token|
514 p.putBackToken(token);
515 return null;
516 };
517 var var_args_token: ?TokenIndex = null;
518 const name_token = p.eatToken(.Identifier);
519 const lparen = try p.expectToken(.LParen);
520 const params = try p.parseParamDeclList(&var_args_token);
521 const rparen = try p.expectToken(.RParen);
522 const align_expr = try p.parseByteAlign();
523 const section_expr = try p.parseLinkSection();
524 const callconv_expr = try p.parseCallconv();
525 const exclamation_token = p.eatToken(.Bang);
526
527 const return_type_expr = (try p.parseVarType()) orelse
528 try p.expectNodeRecoverable(parseTypeExpr, .{
529 // most likely the user forgot to specify the return type.
530 // Mark return type as invalid and try to continue.
531 .ExpectedReturnType = .{ .token = p.tok_i },
656 });532 });
657533
658 const node = try arena.create(Node.Comptime);534 // TODO https://github.com/ziglang/zig/issues/3750
659 node.* = .{535 const R = Node.FnProto.ReturnType;
536 const return_type = if (return_type_expr == null)
537 R{ .Invalid = rparen }
538 else if (exclamation_token != null)
539 R{ .InferErrorSet = return_type_expr.? }
540 else
541 R{ .Explicit = return_type_expr.? };
542
543 const fn_proto_node = try p.arena.allocator.create(Node.FnProto);
544 fn_proto_node.* = .{
660 .doc_comments = null,545 .doc_comments = null,
661 .comptime_token = token,546 .visib_token = null,
662 .expr = block_expr,547 .fn_token = fn_token,
548 .name_token = name_token,
549 .params = params,
550 .return_type = return_type,
551 .var_args_token = var_args_token,
552 .extern_export_inline_token = null,
553 .body_node = null,
554 .lib_name = null,
555 .align_expr = align_expr,
556 .section_expr = section_expr,
557 .callconv_expr = callconv_expr,
558 .is_extern_prototype = is_extern,
559 .is_async = is_async,
663 };560 };
664 return &node.base;
665 }
666
667 if (eatToken(it, .Keyword_nosuspend)) |nosuspend_token| {
668 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
669 .ExpectedBlockOrAssignment = .{ .token = it.index },
670 });
671561
672 const node = try arena.create(Node.Nosuspend);562 return &fn_proto_node.base;
673 node.* = .{
674 .nosuspend_token = nosuspend_token,
675 .expr = block_expr,
676 };
677 return &node.base;
678 }563 }
679564
680 if (eatToken(it, .Keyword_suspend)) |suspend_token| {565 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
681 const semicolon = eatToken(it, .Semicolon);566 fn parseVarDecl(p: *Parser) !?*Node {
567 const mut_token = p.eatToken(.Keyword_const) orelse
568 p.eatToken(.Keyword_var) orelse
569 return null;
682570
683 const body_node = if (semicolon == null) blk: {571 const name_token = try p.expectToken(.Identifier);
684 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{572 const type_node = if (p.eatToken(.Colon) != null)
685 .ExpectedBlockOrExpression = .{ .token = it.index },573 try p.expectNode(parseTypeExpr, .{
574 .ExpectedTypeExpr = .{ .token = p.tok_i },
575 })
576 else
577 null;
578 const align_node = try p.parseByteAlign();
579 const section_node = try p.parseLinkSection();
580 const eq_token = p.eatToken(.Equal);
581 const init_node = if (eq_token != null) blk: {
582 break :blk try p.expectNode(parseExpr, .{
583 .ExpectedExpr = .{ .token = p.tok_i },
686 });584 });
687 } else null;585 } else null;
586 const semicolon_token = try p.expectToken(.Semicolon);
688587
689 const node = try arena.create(Node.Suspend);588 const node = try p.arena.allocator.create(Node.VarDecl);
690 node.* = .{589 node.* = .{
691 .suspend_token = suspend_token,590 .doc_comments = null,
692 .body = body_node,591 .visib_token = null,
592 .thread_local_token = null,
593 .name_token = name_token,
594 .eq_token = eq_token,
595 .mut_token = mut_token,
596 .comptime_token = null,
597 .extern_export_token = null,
598 .lib_name = null,
599 .type_node = type_node,
600 .align_node = align_node,
601 .section_node = section_node,
602 .init_node = init_node,
603 .semicolon_token = semicolon_token,
693 };604 };
694 return &node.base;605 return &node.base;
695 }606 }
696607
697 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);608 /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
698 if (defer_token) |token| {609 fn parseContainerField(p: *Parser) !?*Node {
699 const payload = if (tree.tokens.at(token).id == .Keyword_errdefer)610 const comptime_token = p.eatToken(.Keyword_comptime);
700 try parsePayload(arena, it, tree)611 const name_token = p.eatToken(.Identifier) orelse {
612 if (comptime_token) |t| p.putBackToken(t);
613 return null;
614 };
615
616 var align_expr: ?*Node = null;
617 var type_expr: ?*Node = null;
618 if (p.eatToken(.Colon)) |_| {
619 if (p.eatToken(.Keyword_var)) |var_tok| {
620 const node = try p.arena.allocator.create(ast.Node.VarType);
621 node.* = .{ .token = var_tok };
622 type_expr = &node.base;
623 } else {
624 type_expr = try p.expectNode(parseTypeExpr, .{
625 .ExpectedTypeExpr = .{ .token = p.tok_i },
626 });
627 align_expr = try p.parseByteAlign();
628 }
629 }
630
631 const value_expr = if (p.eatToken(.Equal)) |_|
632 try p.expectNode(parseExpr, .{
633 .ExpectedExpr = .{ .token = p.tok_i },
634 })
701 else635 else
702 null;636 null;
703 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{637
704 .ExpectedBlockOrExpression = .{ .token = it.index },638 const node = try p.arena.allocator.create(Node.ContainerField);
705 });
706 const node = try arena.create(Node.Defer);
707 node.* = .{639 node.* = .{
708 .defer_token = token,640 .doc_comments = null,
709 .expr = expr_node,641 .comptime_token = comptime_token,
710 .payload = payload,642 .name_token = name_token,
643 .type_expr = type_expr,
644 .value_expr = value_expr,
645 .align_expr = align_expr,
711 };646 };
712 return &node.base;647 return &node.base;
713 }648 }
714649
715 if (try parseIfStatement(arena, it, tree)) |node| return node;650 /// Statement
716 if (try parseLabeledStatement(arena, it, tree)) |node| return node;651 /// <- KEYWORD_comptime? VarDecl
717 if (try parseSwitchExpr(arena, it, tree)) |node| return node;652 /// / KEYWORD_comptime BlockExprStatement
718 if (try parseAssignExpr(arena, it, tree)) |node| {653 /// / KEYWORD_nosuspend BlockExprStatement
719 _ = try expectTokenRecoverable(it, tree, .Semicolon);654 /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
720 return node;655 /// / KEYWORD_defer BlockExprStatement
721 }656 /// / KEYWORD_errdefer Payload? BlockExprStatement
722657 /// / IfStatement
723 return null;658 /// / LabeledStatement
724}659 /// / SwitchExpr
725660 /// / AssignExpr SEMICOLON
726/// IfStatement661 fn parseStatement(p: *Parser) Error!?*Node {
727/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?662 const comptime_token = p.eatToken(.Keyword_comptime);
728/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )663
729fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {664 const var_decl_node = try p.parseVarDecl();
730 const if_node = (try parseIfPrefix(arena, it, tree)) orelse return null;665 if (var_decl_node) |node| {
731 const if_prefix = if_node.cast(Node.If).?;666 const var_decl = node.cast(Node.VarDecl).?;
732667 var_decl.comptime_token = comptime_token;
733 const block_expr = (try parseBlockExpr(arena, it, tree));668 return node;
734 const assign_expr = if (block_expr == null)669 }
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 });
749670
750 const node = try arena.create(Node.Else);671 if (comptime_token) |token| {
751 node.* = .{672 const block_expr = try p.expectNode(parseBlockExprStatement, .{
752 .else_token = else_token,673 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
753 .payload = payload,674 });
754 .body = else_body,
755 };
756675
757 break :blk node;676 const node = try p.arena.allocator.create(Node.Comptime);
758 } else null;677 node.* = .{
678 .doc_comments = null,
679 .comptime_token = token,
680 .expr = block_expr,
681 };
682 return &node.base;
683 }
759684
760 if (block_expr) |body| {685 if (p.eatToken(.Keyword_nosuspend)) |nosuspend_token| {
761 if_prefix.body = body;686 const block_expr = try p.expectNode(parseBlockExprStatement, .{
762 if_prefix.@"else" = else_node;687 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
763 return if_node;688 });
764 }
765689
766 if (assign_expr) |body| {690 const node = try p.arena.allocator.create(Node.Nosuspend);
767 if_prefix.body = body;691 node.* = .{
768 if (semicolon != null) return if_node;692 .nosuspend_token = nosuspend_token,
769 if (else_node != null) {693 .expr = block_expr,
770 if_prefix.@"else" = else_node;694 };
771 return if_node;695 return &node.base;
772 }696 }
773 try tree.errors.push(.{
774 .ExpectedSemiOrElse = .{ .token = it.index },
775 });
776 }
777
778 return if_node;
779}
780697
781/// LabeledStatement <- BlockLabel? (Block / LoopStatement)698 if (p.eatToken(.Keyword_suspend)) |suspend_token| {
782fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {699 const semicolon = p.eatToken(.Semicolon);
783 var colon: TokenIndex = undefined;
784 const label_token = parseBlockLabel(arena, it, tree, &colon);
785700
786 if (try parseBlock(arena, it, tree)) |node| {701 const body_node = if (semicolon == null) blk: {
787 node.cast(Node.Block).?.label = label_token;702 break :blk try p.expectNode(parseBlockExprStatement, .{
788 return node;703 .ExpectedBlockOrExpression = .{ .token = p.tok_i },
789 }704 });
705 } else null;
790706
791 if (try parseLoopStatement(arena, it, tree)) |node| {707 const node = try p.arena.allocator.create(Node.Suspend);
792 if (node.cast(Node.For)) |for_node| {708 node.* = .{
793 for_node.label = label_token;709 .suspend_token = suspend_token,
794 } else if (node.cast(Node.While)) |while_node| {710 .body = body_node,
795 while_node.label = label_token;711 };
796 } else unreachable;712 return &node.base;
797 return node;713 }
798 }
799
800 if (label_token != null) {
801 try tree.errors.push(.{
802 .ExpectedLabelable = .{ .token = it.index },
803 });
804 return error.ParseError;
805 }
806
807 return null;
808}
809714
810/// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)715 const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer);
811fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {716 if (defer_token) |token| {
812 const inline_token = eatToken(it, .Keyword_inline);717 const payload = if (p.tokens[token].id == .Keyword_errdefer)
718 try p.parsePayload()
719 else
720 null;
721 const expr_node = try p.expectNode(parseBlockExprStatement, .{
722 .ExpectedBlockOrExpression = .{ .token = p.tok_i },
723 });
724 const node = try p.arena.allocator.create(Node.Defer);
725 node.* = .{
726 .defer_token = token,
727 .expr = expr_node,
728 .payload = payload,
729 };
730 return &node.base;
731 }
813732
814 if (try parseForStatement(arena, it, tree)) |node| {733 if (try p.parseIfStatement()) |node| return node;
815 node.cast(Node.For).?.inline_token = inline_token;734 if (try p.parseLabeledStatement()) |node| return node;
816 return node;735 if (try p.parseSwitchExpr()) |node| return node;
817 }736 if (try p.parseAssignExpr()) |node| {
737 _ = try p.expectTokenRecoverable(.Semicolon);
738 return node;
739 }
818740
819 if (try parseWhileStatement(arena, it, tree)) |node| {741 return null;
820 node.cast(Node.While).?.inline_token = inline_token;
821 return node;
822 }742 }
823 if (inline_token == null) return null;
824743
825 // If we've seen "inline", there should have been a "for" or "while"744 /// IfStatement
826 try tree.errors.push(.{745 /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
827 .ExpectedInlinable = .{ .token = it.index },746 /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
828 });747 fn parseIfStatement(p: *Parser) !?*Node {
829 return error.ParseError;748 const if_node = (try p.parseIfPrefix()) orelse return null;
830}749 const if_prefix = if_node.cast(Node.If).?;
831750
832/// ForStatement751 const block_expr = (try p.parseBlockExpr());
833/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?752 const assign_expr = if (block_expr == null)
834/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )753 try p.expectNode(parseAssignExpr, .{
835fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {754 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
836 const node = (try parseForPrefix(arena, it, tree)) orelse return null;755 })
837 const for_prefix = node.cast(Node.For).?;756 else
757 null;
838758
839 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {759 const semicolon = if (assign_expr != null) p.eatToken(.Semicolon) else null;
840 for_prefix.body = block_expr_node;
841760
842 if (eatToken(it, .Keyword_else)) |else_token| {761 const else_node = if (semicolon == null) blk: {
843 const statement_node = try expectNode(arena, it, tree, parseStatement, .{762 const else_token = p.eatToken(.Keyword_else) orelse break :blk null;
844 .InvalidToken = .{ .token = it.index },763 const payload = try p.parsePayload();
764 const else_body = try p.expectNode(parseStatement, .{
765 .InvalidToken = .{ .token = p.tok_i },
845 });766 });
846767
847 const else_node = try arena.create(Node.Else);768 const node = try p.arena.allocator.create(Node.Else);
848 else_node.* = .{769 node.* = .{
849 .else_token = else_token,770 .else_token = else_token,
850 .payload = null,771 .payload = payload,
851 .body = statement_node,772 .body = else_body,
852 };773 };
853 for_prefix.@"else" = else_node;
854774
855 return node;775 break :blk node;
776 } else null;
777
778 if (block_expr) |body| {
779 if_prefix.body = body;
780 if_prefix.@"else" = else_node;
781 return if_node;
856 }782 }
857783
858 return node;784 if (assign_expr) |body| {
785 if_prefix.body = body;
786 if (semicolon != null) return if_node;
787 if (else_node != null) {
788 if_prefix.@"else" = else_node;
789 return if_node;
790 }
791 try p.errors.append(p.gpa, .{
792 .ExpectedSemiOrElse = .{ .token = p.tok_i },
793 });
794 }
795
796 return if_node;
859 }797 }
860798
861 if (try parseAssignExpr(arena, it, tree)) |assign_expr| {799 /// LabeledStatement <- BlockLabel? (Block / LoopStatement)
862 for_prefix.body = assign_expr;800 fn parseLabeledStatement(p: *Parser) !?*Node {
801 var colon: TokenIndex = undefined;
802 const label_token = p.parseBlockLabel(&colon);
803
804 if (try p.parseBlock()) |node| {
805 node.cast(Node.Block).?.label = label_token;
806 return node;
807 }
863808
864 if (eatToken(it, .Semicolon) != null) return node;809 if (try p.parseLoopStatement()) |node| {
810 if (node.cast(Node.For)) |for_node| {
811 for_node.label = label_token;
812 } else if (node.cast(Node.While)) |while_node| {
813 while_node.label = label_token;
814 } else unreachable;
815 return node;
816 }
865817
866 if (eatToken(it, .Keyword_else)) |else_token| {818 if (label_token != null) {
867 const statement_node = try expectNode(arena, it, tree, parseStatement, .{819 try p.errors.append(p.gpa, .{
868 .ExpectedStatement = .{ .token = it.index },820 .ExpectedLabelable = .{ .token = p.tok_i },
869 });821 });
822 return error.ParseError;
823 }
870824
871 const else_node = try arena.create(Node.Else);825 return null;
872 else_node.* = .{826 }
873 .else_token = else_token,827
874 .payload = null,828 /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
875 .body = statement_node,829 fn parseLoopStatement(p: *Parser) !?*Node {
876 };830 const inline_token = p.eatToken(.Keyword_inline);
877 for_prefix.@"else" = else_node;831
832 if (try p.parseForStatement()) |node| {
833 node.cast(Node.For).?.inline_token = inline_token;
878 return node;834 return node;
879 }835 }
880836
881 try tree.errors.push(.{837 if (try p.parseWhileStatement()) |node| {
882 .ExpectedSemiOrElse = .{ .token = it.index },838 node.cast(Node.While).?.inline_token = inline_token;
883 });839 return node;
840 }
841 if (inline_token == null) return null;
884842
885 return node;843 // If we've seen "inline", there should have been a "for" or "while"
844 try p.errors.append(p.gpa, .{
845 .ExpectedInlinable = .{ .token = p.tok_i },
846 });
847 return error.ParseError;
886 }848 }
887849
888 return null;850 /// ForStatement
889}851 /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
890852 /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
891/// WhileStatement853 fn parseForStatement(p: *Parser) !?*Node {
892/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?854 const node = (try p.parseForPrefix()) orelse return null;
893/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )855 const for_prefix = node.cast(Node.For).?;
894fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
895 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
896 const while_prefix = node.cast(Node.While).?;
897856
898 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {857 if (try p.parseBlockExpr()) |block_expr_node| {
899 while_prefix.body = block_expr_node;858 for_prefix.body = block_expr_node;
900859
901 if (eatToken(it, .Keyword_else)) |else_token| {860 if (p.eatToken(.Keyword_else)) |else_token| {
902 const payload = try parsePayload(arena, it, tree);861 const statement_node = try p.expectNode(parseStatement, .{
862 .InvalidToken = .{ .token = p.tok_i },
863 });
903864
904 const statement_node = try expectNode(arena, it, tree, parseStatement, .{865 const else_node = try p.arena.allocator.create(Node.Else);
905 .InvalidToken = .{ .token = it.index },866 else_node.* = .{
906 });867 .else_token = else_token,
868 .payload = null,
869 .body = statement_node,
870 };
871 for_prefix.@"else" = else_node;
907872
908 const else_node = try arena.create(Node.Else);873 return node;
909 else_node.* = .{874 }
910 .else_token = else_token,
911 .payload = payload,
912 .body = statement_node,
913 };
914 while_prefix.@"else" = else_node;
915875
916 return node;876 return node;
917 }877 }
918878
919 return node;879 if (try p.parseAssignExpr()) |assign_expr| {
920 }880 for_prefix.body = assign_expr;
921881
922 if (try parseAssignExpr(arena, it, tree)) |assign_expr_node| {882 if (p.eatToken(.Semicolon) != null) return node;
923 while_prefix.body = assign_expr_node;
924883
925 if (eatToken(it, .Semicolon) != null) return node;884 if (p.eatToken(.Keyword_else)) |else_token| {
885 const statement_node = try p.expectNode(parseStatement, .{
886 .ExpectedStatement = .{ .token = p.tok_i },
887 });
926888
927 if (eatToken(it, .Keyword_else)) |else_token| {889 const else_node = try p.arena.allocator.create(Node.Else);
928 const payload = try parsePayload(arena, it, tree);890 else_node.* = .{
891 .else_token = else_token,
892 .payload = null,
893 .body = statement_node,
894 };
895 for_prefix.@"else" = else_node;
896 return node;
897 }
929898
930 const statement_node = try expectNode(arena, it, tree, parseStatement, .{899 try p.errors.append(p.gpa, .{
931 .ExpectedStatement = .{ .token = it.index },900 .ExpectedSemiOrElse = .{ .token = p.tok_i },
932 });901 });
933902
934 const else_node = try arena.create(Node.Else);
935 else_node.* = .{
936 .else_token = else_token,
937 .payload = payload,
938 .body = statement_node,
939 };
940 while_prefix.@"else" = else_node;
941 return node;903 return node;
942 }904 }
943905
944 try tree.errors.push(.{906 return null;
945 .ExpectedSemiOrElse = .{ .token = it.index },
946 });
947
948 return node;
949 }907 }
950908
951 return null;909 /// WhileStatement
952}910 /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
911 /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
912 fn parseWhileStatement(p: *Parser) !?*Node {
913 const node = (try p.parseWhilePrefix()) orelse return null;
914 const while_prefix = node.cast(Node.While).?;
953915
954/// BlockExprStatement916 if (try p.parseBlockExpr()) |block_expr_node| {
955/// <- BlockExpr917 while_prefix.body = block_expr_node;
956/// / AssignExpr SEMICOLON
957fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
958 if (try parseBlockExpr(arena, it, tree)) |node| return node;
959 if (try parseAssignExpr(arena, it, tree)) |node| {
960 _ = try expectTokenRecoverable(it, tree, .Semicolon);
961 return node;
962 }
963 return null;
964}
965918
966/// BlockExpr <- BlockLabel? Block919 if (p.eatToken(.Keyword_else)) |else_token| {
967fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {920 const payload = try p.parsePayload();
968 var colon: TokenIndex = undefined;
969 const label_token = parseBlockLabel(arena, it, tree, &colon);
970 const block_node = (try parseBlock(arena, it, tree)) orelse {
971 if (label_token) |label| {
972 putBackToken(it, label + 1); // ":"
973 putBackToken(it, label); // IDENTIFIER
974 }
975 return null;
976 };
977 block_node.cast(Node.Block).?.label = label_token;
978 return block_node;
979}
980921
981/// AssignExpr <- Expr (AssignOp Expr)?922 const statement_node = try p.expectNode(parseStatement, .{
982fn parseAssignExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {923 .InvalidToken = .{ .token = p.tok_i },
983 return parseBinOpExpr(arena, it, tree, parseAssignOp, parseExpr, .Once);924 });
984}
985925
986/// Expr <- KEYWORD_try* BoolOrExpr926 const else_node = try p.arena.allocator.create(Node.Else);
987fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {927 else_node.* = .{
988 return parsePrefixOpExpr(arena, it, tree, parseTry, parseBoolOrExpr);928 .else_token = else_token,
989}929 .payload = payload,
930 .body = statement_node,
931 };
932 while_prefix.@"else" = else_node;
990933
991/// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*934 return node;
992fn parseBoolOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {935 }
993 return parseBinOpExpr(
994 arena,
995 it,
996 tree,
997 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
998 parseBoolAndExpr,
999 .Infinitely,
1000 );
1001}
1002936
1003/// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*937 return node;
1004fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {938 }
1005 return parseBinOpExpr(
1006 arena,
1007 it,
1008 tree,
1009 SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
1010 parseCompareExpr,
1011 .Infinitely,
1012 );
1013}
1014939
1015/// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?940 if (try p.parseAssignExpr()) |assign_expr_node| {
1016fn parseCompareExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {941 while_prefix.body = assign_expr_node;
1017 return parseBinOpExpr(arena, it, tree, parseCompareOp, parseBitwiseExpr, .Once);
1018}
1019942
1020/// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*943 if (p.eatToken(.Semicolon) != null) return node;
1021fn parseBitwiseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1022 return parseBinOpExpr(arena, it, tree, parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1023}
1024944
1025/// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*945 if (p.eatToken(.Keyword_else)) |else_token| {
1026fn parseBitShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {946 const payload = try p.parsePayload();
1027 return parseBinOpExpr(arena, it, tree, parseBitShiftOp, parseAdditionExpr, .Infinitely);
1028}
1029947
1030/// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*948 const statement_node = try p.expectNode(parseStatement, .{
1031fn parseAdditionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {949 .ExpectedStatement = .{ .token = p.tok_i },
1032 return parseBinOpExpr(arena, it, tree, parseAdditionOp, parseMultiplyExpr, .Infinitely);950 });
1033}
1034951
1035/// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*952 const else_node = try p.arena.allocator.create(Node.Else);
1036fn parseMultiplyExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {953 else_node.* = .{
1037 return parseBinOpExpr(arena, it, tree, parseMultiplyOp, parsePrefixExpr, .Infinitely);954 .else_token = else_token,
1038}955 .payload = payload,
956 .body = statement_node,
957 };
958 while_prefix.@"else" = else_node;
959 return node;
960 }
1039961
1040/// PrefixExpr <- PrefixOp* PrimaryExpr962 try p.errors.append(p.gpa, .{
1041fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {963 .ExpectedSemiOrElse = .{ .token = p.tok_i },
1042 return parsePrefixOpExpr(arena, it, tree, parsePrefixOp, parsePrimaryExpr);964 });
1043}
1044965
1045/// PrimaryExpr966 return node;
1046/// <- AsmExpr967 }
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 }
1072968
1073 if (eatToken(it, .Keyword_comptime)) |token| {969 return null;
1074 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1075 .ExpectedExpr = .{ .token = it.index },
1076 });
1077 const node = try arena.create(Node.Comptime);
1078 node.* = .{
1079 .doc_comments = null,
1080 .comptime_token = token,
1081 .expr = expr_node,
1082 };
1083 return &node.base;
1084 }970 }
1085971
1086 if (eatToken(it, .Keyword_nosuspend)) |token| {972 /// BlockExprStatement
1087 const expr_node = try expectNode(arena, it, tree, parseExpr, .{973 /// <- BlockExpr
1088 .ExpectedExpr = .{ .token = it.index },974 /// / AssignExpr SEMICOLON
1089 });975 fn parseBlockExprStatement(p: *Parser) !?*Node {
1090 const node = try arena.create(Node.Nosuspend);976 if (try p.parseBlockExpr()) |node| return node;
1091 node.* = .{977 if (try p.parseAssignExpr()) |node| {
1092 .nosuspend_token = token,978 _ = try p.expectTokenRecoverable(.Semicolon);
1093 .expr = expr_node,979 return node;
1094 };980 }
1095 return &node.base;981 return null;
1096 }982 }
1097983
1098 if (eatToken(it, .Keyword_continue)) |token| {984 /// BlockExpr <- BlockLabel? Block
1099 const label = try parseBreakLabel(arena, it, tree);985 fn parseBlockExpr(p: *Parser) Error!?*Node {
1100 const node = try arena.create(Node.ControlFlowExpression);986 var colon: TokenIndex = undefined;
1101 node.* = .{987 const label_token = p.parseBlockLabel(&colon);
1102 .ltoken = token,988 const block_node = (try p.parseBlock()) orelse {
1103 .kind = .{ .Continue = label },989 if (label_token) |label| {
1104 .rhs = null,990 p.putBackToken(label + 1); // ":"
991 p.putBackToken(label); // IDENTIFIER
992 }
993 return null;
1105 };994 };
1106 return &node.base;995 block_node.cast(Node.Block).?.label = label_token;
996 return block_node;
1107 }997 }
1108998
1109 if (eatToken(it, .Keyword_resume)) |token| {999 /// AssignExpr <- Expr (AssignOp Expr)?
1110 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1000 fn parseAssignExpr(p: *Parser) !?*Node {
1111 .ExpectedExpr = .{ .token = it.index },1001 return p.parseBinOpExpr(parseAssignOp, parseExpr, .Once);
1112 });
1113 const node = try arena.create(Node.PrefixOp);
1114 node.* = .{
1115 .op_token = token,
1116 .op = .Resume,
1117 .rhs = expr_node,
1118 };
1119 return &node.base;
1120 }1002 }
11211003
1122 if (eatToken(it, .Keyword_return)) |token| {1004 /// Expr <- KEYWORD_try* BoolOrExpr
1123 const expr_node = try parseExpr(arena, it, tree);1005 fn parseExpr(p: *Parser) Error!?*Node {
1124 const node = try arena.create(Node.ControlFlowExpression);1006 return p.parsePrefixOpExpr(parseTry, parseBoolOrExpr);
1125 node.* = .{
1126 .ltoken = token,
1127 .kind = .Return,
1128 .rhs = expr_node,
1129 };
1130 return &node.base;
1131 }1007 }
11321008
1133 var colon: TokenIndex = undefined;1009 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
1134 const label = parseBlockLabel(arena, it, tree, &colon);1010 fn parseBoolOrExpr(p: *Parser) !?*Node {
1135 if (try parseLoopExpr(arena, it, tree)) |node| {1011 return p.parseBinOpExpr(
1136 if (node.cast(Node.For)) |for_node| {1012 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
1137 for_node.label = label;1013 parseBoolAndExpr,
1138 } else if (node.cast(Node.While)) |while_node| {1014 .Infinitely,
1139 while_node.label = label;1015 );
1140 } else unreachable;
1141 return node;
1142 }
1143 if (label) |token| {
1144 putBackToken(it, token + 1); // ":"
1145 putBackToken(it, token); // IDENTIFIER
1146 }1016 }
11471017
1148 if (try parseBlock(arena, it, tree)) |node| return node;1018 /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
1149 if (try parseCurlySuffixExpr(arena, it, tree)) |node| return node;1019 fn parseBoolAndExpr(p: *Parser) !?*Node {
11501020 return p.parseBinOpExpr(
1151 return null;1021 SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
1152}1022 parseCompareExpr,
1023 .Infinitely,
1024 );
1025 }
11531026
1154/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?1027 /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
1155fn parseIfExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1028 fn parseCompareExpr(p: *Parser) !?*Node {
1156 return parseIf(arena, it, tree, parseExpr);1029 return p.parseBinOpExpr(parseCompareOp, parseBitwiseExpr, .Once);
1157}1030 }
11581031
1159/// Block <- LBRACE Statement* RBRACE1032 /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
1160fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1033 fn parseBitwiseExpr(p: *Parser) !?*Node {
1161 const lbrace = eatToken(it, .LBrace) orelse return null;1034 return p.parseBinOpExpr(parseBitwiseOp, parseBitShiftExpr, .Infinitely);
1035 }
11621036
1163 var statements = Node.Block.StatementList.init(arena);1037 /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
1164 while (true) {1038 fn parseBitShiftExpr(p: *Parser) !?*Node {
1165 const statement = (parseStatement(arena, it, tree) catch |err| switch (err) {1039 return p.parseBinOpExpr(parseBitShiftOp, parseAdditionExpr, .Infinitely);
1166 error.OutOfMemory => return error.OutOfMemory,
1167 error.ParseError => {
1168 // try to skip to the next statement
1169 findNextStmt(it);
1170 continue;
1171 },
1172 }) orelse break;
1173 try statements.push(statement);
1174 }1040 }
11751041
1176 const rbrace = try expectToken(it, tree, .RBrace);1042 /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
1043 fn parseAdditionExpr(p: *Parser) !?*Node {
1044 return p.parseBinOpExpr(parseAdditionOp, parseMultiplyExpr, .Infinitely);
1045 }
11771046
1178 const block_node = try arena.create(Node.Block);1047 /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
1179 block_node.* = .{1048 fn parseMultiplyExpr(p: *Parser) !?*Node {
1180 .label = null,1049 return p.parseBinOpExpr(parseMultiplyOp, parsePrefixExpr, .Infinitely);
1181 .lbrace = lbrace,1050 }
1182 .statements = statements,
1183 .rbrace = rbrace,
1184 };
11851051
1186 return &block_node.base;1052 /// PrefixExpr <- PrefixOp* PrimaryExpr
1187}1053 fn parsePrefixExpr(p: *Parser) !?*Node {
1054 return p.parsePrefixOpExpr(parsePrefixOp, parsePrimaryExpr);
1055 }
11881056
1189/// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)1057 /// PrimaryExpr
1190fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1058 /// <- AsmExpr
1191 const inline_token = eatToken(it, .Keyword_inline);1059 /// / IfExpr
1060 /// / KEYWORD_break BreakLabel? Expr?
1061 /// / KEYWORD_comptime Expr
1062 /// / KEYWORD_nosuspend Expr
1063 /// / KEYWORD_continue BreakLabel?
1064 /// / KEYWORD_resume Expr
1065 /// / KEYWORD_return Expr?
1066 /// / BlockLabel? LoopExpr
1067 /// / Block
1068 /// / CurlySuffixExpr
1069 fn parsePrimaryExpr(p: *Parser) !?*Node {
1070 if (try p.parseAsmExpr()) |node| return node;
1071 if (try p.parseIfExpr()) |node| return node;
11921072
1193 if (try parseForExpr(arena, it, tree)) |node| {1073 if (p.eatToken(.Keyword_break)) |token| {
1194 node.cast(Node.For).?.inline_token = inline_token;1074 const label = try p.parseBreakLabel();
1195 return node;1075 const expr_node = try p.parseExpr();
1196 }1076 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1077 node.* = .{
1078 .ltoken = token,
1079 .kind = .{ .Break = label },
1080 .rhs = expr_node,
1081 };
1082 return &node.base;
1083 }
11971084
1198 if (try parseWhileExpr(arena, it, tree)) |node| {1085 if (p.eatToken(.Keyword_comptime)) |token| {
1199 node.cast(Node.While).?.inline_token = inline_token;1086 const expr_node = try p.expectNode(parseExpr, .{
1200 return node;1087 .ExpectedExpr = .{ .token = p.tok_i },
1201 }1088 });
1089 const node = try p.arena.allocator.create(Node.Comptime);
1090 node.* = .{
1091 .doc_comments = null,
1092 .comptime_token = token,
1093 .expr = expr_node,
1094 };
1095 return &node.base;
1096 }
12021097
1203 if (inline_token == null) return null;1098 if (p.eatToken(.Keyword_nosuspend)) |token| {
1099 const expr_node = try p.expectNode(parseExpr, .{
1100 .ExpectedExpr = .{ .token = p.tok_i },
1101 });
1102 const node = try p.arena.allocator.create(Node.Nosuspend);
1103 node.* = .{
1104 .nosuspend_token = token,
1105 .expr = expr_node,
1106 };
1107 return &node.base;
1108 }
12041109
1205 // If we've seen "inline", there should have been a "for" or "while"1110 if (p.eatToken(.Keyword_continue)) |token| {
1206 try tree.errors.push(.{1111 const label = try p.parseBreakLabel();
1207 .ExpectedInlinable = .{ .token = it.index },1112 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1208 });1113 node.* = .{
1209 return error.ParseError;1114 .ltoken = token,
1210}1115 .kind = .{ .Continue = label },
1116 .rhs = null,
1117 };
1118 return &node.base;
1119 }
12111120
1212/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?1121 if (p.eatToken(.Keyword_resume)) |token| {
1213fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1122 const expr_node = try p.expectNode(parseExpr, .{
1214 const node = (try parseForPrefix(arena, it, tree)) orelse return null;1123 .ExpectedExpr = .{ .token = p.tok_i },
1215 const for_prefix = node.cast(Node.For).?;1124 });
1125 const node = try p.arena.allocator.create(Node.PrefixOp);
1126 node.* = .{
1127 .op_token = token,
1128 .op = .Resume,
1129 .rhs = expr_node,
1130 };
1131 return &node.base;
1132 }
12161133
1217 const body_node = try expectNode(arena, it, tree, parseExpr, .{1134 if (p.eatToken(.Keyword_return)) |token| {
1218 .ExpectedExpr = .{ .token = it.index },1135 const expr_node = try p.parseExpr();
1219 });1136 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1220 for_prefix.body = body_node;1137 node.* = .{
1138 .ltoken = token,
1139 .kind = .Return,
1140 .rhs = expr_node,
1141 };
1142 return &node.base;
1143 }
12211144
1222 if (eatToken(it, .Keyword_else)) |else_token| {1145 var colon: TokenIndex = undefined;
1223 const body = try expectNode(arena, it, tree, parseExpr, .{1146 const label = p.parseBlockLabel(&colon);
1224 .ExpectedExpr = .{ .token = it.index },1147 if (try p.parseLoopExpr()) |node| {
1225 });1148 if (node.cast(Node.For)) |for_node| {
1149 for_node.label = label;
1150 } else if (node.cast(Node.While)) |while_node| {
1151 while_node.label = label;
1152 } else unreachable;
1153 return node;
1154 }
1155 if (label) |token| {
1156 p.putBackToken(token + 1); // ":"
1157 p.putBackToken(token); // IDENTIFIER
1158 }
12261159
1227 const else_node = try arena.create(Node.Else);1160 if (try p.parseBlock()) |node| return node;
1228 else_node.* = .{1161 if (try p.parseCurlySuffixExpr()) |node| return node;
1229 .else_token = else_token,
1230 .payload = null,
1231 .body = body,
1232 };
12331162
1234 for_prefix.@"else" = else_node;1163 return null;
1235 }1164 }
12361165
1237 return node;1166 /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
1238}1167 fn parseIfExpr(p: *Parser) !?*Node {
1168 return p.parseIf(parseExpr);
1169 }
12391170
1240/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?1171 /// Block <- LBRACE Statement* RBRACE
1241fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1172 fn parseBlock(p: *Parser) !?*Node {
1242 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;1173 const lbrace = p.eatToken(.LBrace) orelse return null;
1243 const while_prefix = node.cast(Node.While).?;
12441174
1245 const body_node = try expectNode(arena, it, tree, parseExpr, .{1175 var statements = Node.Block.StatementList{};
1246 .ExpectedExpr = .{ .token = it.index },1176 var statements_it = &statements.first;
1247 });1177 while (true) {
1248 while_prefix.body = body_node;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 statements_it = try p.llpush(*Node, statements_it, statement);
1187 }
12491188
1250 if (eatToken(it, .Keyword_else)) |else_token| {1189 const rbrace = try p.expectToken(.RBrace);
1251 const payload = try parsePayload(arena, it, tree);
1252 const body = try expectNode(arena, it, tree, parseExpr, .{
1253 .ExpectedExpr = .{ .token = it.index },
1254 });
12551190
1256 const else_node = try arena.create(Node.Else);1191 const block_node = try p.arena.allocator.create(Node.Block);
1257 else_node.* = .{1192 block_node.* = .{
1258 .else_token = else_token,1193 .label = null,
1259 .payload = payload,1194 .lbrace = lbrace,
1260 .body = body,1195 .statements = statements,
1196 .rbrace = rbrace,
1261 };1197 };
12621198
1263 while_prefix.@"else" = else_node;1199 return &block_node.base;
1264 }1200 }
12651201
1266 return node;1202 /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
1267}1203 fn parseLoopExpr(p: *Parser) !?*Node {
12681204 const inline_token = p.eatToken(.Keyword_inline);
1269/// CurlySuffixExpr <- TypeExpr InitList?
1270fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1271 const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
1272 const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr;
1273 suffix_op.lhs.node = type_expr;
1274 return &suffix_op.base;
1275}
12761205
1277/// InitList1206 if (try p.parseForExpr()) |node| {
1278/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE1207 node.cast(Node.For).?.inline_token = inline_token;
1279/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE1208 return node;
1280/// / LBRACE RBRACE
1281fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp {
1282 const lbrace = eatToken(it, .LBrace) orelse return null;
1283 var init_list = Node.SuffixOp.Op.InitList.init(arena);
1284
1285 const op: Node.SuffixOp.Op = blk: {
1286 if (try parseFieldInit(arena, it, tree)) |field_init| {
1287 try init_list.push(field_init);
1288 while (eatToken(it, .Comma)) |_| {
1289 const next = (try parseFieldInit(arena, it, tree)) orelse break;
1290 try init_list.push(next);
1291 }
1292 break :blk .{ .StructInitializer = init_list };
1293 }1209 }
12941210
1295 if (try parseExpr(arena, it, tree)) |expr| {1211 if (try p.parseWhileExpr()) |node| {
1296 try init_list.push(expr);1212 node.cast(Node.While).?.inline_token = inline_token;
1297 while (eatToken(it, .Comma)) |_| {1213 return node;
1298 const next = (try parseExpr(arena, it, tree)) orelse break;
1299 try init_list.push(next);
1300 }
1301 break :blk .{ .ArrayInitializer = init_list };
1302 }1214 }
13031215
1304 break :blk .{ .StructInitializer = init_list };1216 if (inline_token == null) return null;
1305 };
1306
1307 const node = try arena.create(Node.SuffixOp);
1308 node.* = .{
1309 .lhs = .{ .node = undefined }, // set by caller
1310 .op = op,
1311 .rtoken = try expectToken(it, tree, .RBrace),
1312 };
1313 return node;
1314}
1315
1316/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1317fn parseTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
1318 return parsePrefixOpExpr(arena, it, tree, parsePrefixTypeOp, parseErrorUnionExpr);
1319}
1320
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;
13241217
1325 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| {1218 // If we've seen "inline", there should have been a "for" or "while"
1326 const error_union = node.cast(Node.InfixOp).?;1219 try p.errors.append(p.gpa, .{
1327 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1220 .ExpectedInlinable = .{ .token = p.tok_i },
1328 .ExpectedTypeExpr = .{ .token = it.index },
1329 });1221 });
1330 error_union.lhs = suffix_expr;1222 return error.ParseError;
1331 error_union.rhs = type_expr;
1332 return node;
1333 }1223 }
13341224
1335 return suffix_expr;1225 /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
1336}1226 fn parseForExpr(p: *Parser) !?*Node {
1227 const node = (try p.parseForPrefix()) orelse return null;
1228 const for_prefix = node.cast(Node.For).?;
13371229
1338/// SuffixExpr1230 const body_node = try p.expectNode(parseExpr, .{
1339/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments1231 .ExpectedExpr = .{ .token = p.tok_i },
1340/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1341fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1342 const maybe_async = eatToken(it, .Keyword_async);
1343 if (maybe_async) |async_token| {
1344 const token_fn = eatToken(it, .Keyword_fn);
1345 if (token_fn != null) {
1346 // TODO: remove this hack when async fn rewriting is
1347 // HACK: If we see the keyword `fn`, then we assume that
1348 // we are parsing an async fn proto, and not a call.
1349 // We therefore put back all tokens consumed by the async
1350 // prefix...
1351 putBackToken(it, token_fn.?);
1352 putBackToken(it, async_token);
1353 return parsePrimaryTypeExpr(arena, it, tree);
1354 }
1355 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{
1356 .ExpectedPrimaryTypeExpr = .{ .token = it.index },
1357 });1232 });
1233 for_prefix.body = body_node;
13581234
1359 while (try parseSuffixOp(arena, it, tree)) |node| {1235 if (p.eatToken(.Keyword_else)) |else_token| {
1360 switch (node.id) {1236 const body = try p.expectNode(parseExpr, .{
1361 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },1237 .ExpectedExpr = .{ .token = p.tok_i },
1362 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,1238 });
1363 else => unreachable,1239
1364 }1240 const else_node = try p.arena.allocator.create(Node.Else);
1365 res = node;1241 else_node.* = .{
1242 .else_token = else_token,
1243 .payload = null,
1244 .body = body,
1245 };
1246
1247 for_prefix.@"else" = else_node;
1366 }1248 }
13671249
1368 const params = (try parseFnCallArguments(arena, it, tree)) orelse {1250 return node;
1369 try tree.errors.push(.{
1370 .ExpectedParamList = .{ .token = it.index },
1371 });
1372 // ignore this, continue parsing
1373 return res;
1374 };
1375 const node = try arena.create(Node.SuffixOp);
1376 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 };
1386 return &node.base;
1387 }1251 }
1388 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
1389 var res = expr;
13901252
1391 while (true) {1253 /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
1392 if (try parseSuffixOp(arena, it, tree)) |node| {1254 fn parseWhileExpr(p: *Parser) !?*Node {
1255 const node = (try p.parseWhilePrefix()) orelse return null;
1256 const while_prefix = node.cast(Node.While).?;
1257
1258 const body_node = try p.expectNode(parseExpr, .{
1259 .ExpectedExpr = .{ .token = p.tok_i },
1260 });
1261 while_prefix.body = body_node;
1262
1263 if (p.eatToken(.Keyword_else)) |else_token| {
1264 const payload = try p.parsePayload();
1265 const body = try p.expectNode(parseExpr, .{
1266 .ExpectedExpr = .{ .token = p.tok_i },
1267 });
1268
1269 const else_node = try p.arena.allocator.create(Node.Else);
1270 else_node.* = .{
1271 .else_token = else_token,
1272 .payload = payload,
1273 .body = body,
1274 };
1275
1276 while_prefix.@"else" = else_node;
1277 }
1278
1279 return node;
1280 }
1281
1282 /// CurlySuffixExpr <- TypeExpr InitList?
1283 fn parseCurlySuffixExpr(p: *Parser) !?*Node {
1284 const type_expr = (try p.parseTypeExpr()) orelse return null;
1285 const suffix_op = (try p.parseInitList()) orelse return type_expr;
1286 suffix_op.lhs.node = type_expr;
1287 return &suffix_op.base;
1288 }
1289
1290 /// InitList
1291 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
1292 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
1293 /// / LBRACE RBRACE
1294 fn parseInitList(p: *Parser) !?*Node.SuffixOp {
1295 const lbrace = p.eatToken(.LBrace) orelse return null;
1296 var init_list = Node.SuffixOp.Op.InitList{};
1297 var init_list_it = &init_list.first;
1298
1299 const op: Node.SuffixOp.Op = blk: {
1300 if (try p.parseFieldInit()) |field_init| {
1301 init_list_it = try p.llpush(*Node, init_list_it, field_init);
1302 while (p.eatToken(.Comma)) |_| {
1303 const next = (try p.parseFieldInit()) orelse break;
1304 init_list_it = try p.llpush(*Node, init_list_it, next);
1305 }
1306 break :blk .{ .StructInitializer = init_list };
1307 }
1308
1309 if (try p.parseExpr()) |expr| {
1310 init_list_it = try p.llpush(*Node, init_list_it, expr);
1311 while (p.eatToken(.Comma)) |_| {
1312 const next = (try p.parseExpr()) orelse break;
1313 init_list_it = try p.llpush(*Node, init_list_it, next);
1314 }
1315 break :blk .{ .ArrayInitializer = init_list };
1316 }
1317
1318 break :blk .{ .StructInitializer = init_list };
1319 };
1320
1321 const node = try p.arena.allocator.create(Node.SuffixOp);
1322 node.* = .{
1323 .lhs = .{ .node = undefined }, // set by caller
1324 .op = op,
1325 .rtoken = try p.expectToken(.RBrace),
1326 };
1327 return node;
1328 }
1329
1330 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1331 fn parseTypeExpr(p: *Parser) Error!?*Node {
1332 return p.parsePrefixOpExpr(parsePrefixTypeOp, parseErrorUnionExpr);
1333 }
1334
1335 /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
1336 fn parseErrorUnionExpr(p: *Parser) !?*Node {
1337 const suffix_expr = (try p.parseSuffixExpr()) orelse return null;
1338
1339 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| {
1340 const error_union = node.cast(Node.InfixOp).?;
1341 const type_expr = try p.expectNode(parseTypeExpr, .{
1342 .ExpectedTypeExpr = .{ .token = p.tok_i },
1343 });
1344 error_union.lhs = suffix_expr;
1345 error_union.rhs = type_expr;
1346 return node;
1347 }
1348
1349 return suffix_expr;
1350 }
1351
1352 /// SuffixExpr
1353 /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
1354 /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1355 fn parseSuffixExpr(p: *Parser) !?*Node {
1356 const maybe_async = p.eatToken(.Keyword_async);
1357 if (maybe_async) |async_token| {
1358 const token_fn = p.eatToken(.Keyword_fn);
1359 if (token_fn != null) {
1360 // TODO: remove this hack when async fn rewriting is
1361 // HACK: If we see the keyword `fn`, then we assume that
1362 // we are parsing an async fn proto, and not a call.
1363 // We therefore put back all tokens consumed by the async
1364 // prefix...
1365 p.putBackToken(token_fn.?);
1366 p.putBackToken(async_token);
1367 return p.parsePrimaryTypeExpr();
1368 }
1369 var res = try p.expectNode(parsePrimaryTypeExpr, .{
1370 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
1371 });
1372
1373 while (try p.parseSuffixOp()) |node| {
1393 switch (node.id) {1374 switch (node.id) {
1394 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },1375 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
1395 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,1376 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1396 else => unreachable,1377 else => unreachable,
1397 }1378 }
1398 res = node;1379 res = node;
1399 continue;
1400 }1380 }
1401 if (try parseFnCallArguments(arena, it, tree)) |params| {1381
1402 const call = try arena.create(Node.SuffixOp);1382 const params = (try p.parseFnCallArguments()) orelse {
1403 call.* = .{1383 try p.errors.append(p.gpa, .{
1404 .lhs = .{ .node = res },1384 .ExpectedParamList = .{ .token = p.tok_i },
1405 .op = .{1385 });
1406 .Call = .{1386 // ignore this, continue parsing
1407 .params = params.list,1387 return res;
1408 .async_token = null,1388 };
1409 },1389 const node = try p.arena.allocator.create(Node.SuffixOp);
1390 node.* = .{
1391 .lhs = .{ .node = res },
1392 .op = .{
1393 .Call = .{
1394 .params = params.list,
1395 .async_token = async_token,
1410 },1396 },
1411 .rtoken = params.rparen,1397 },
1412 };1398 .rtoken = params.rparen,
1413 res = &call.base;1399 };
1414 continue;1400 return &node.base;
1401 }
1402 if (try p.parsePrimaryTypeExpr()) |expr| {
1403 var res = expr;
1404
1405 while (true) {
1406 if (try p.parseSuffixOp()) |node| {
1407 switch (node.id) {
1408 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
1409 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1410 else => unreachable,
1411 }
1412 res = node;
1413 continue;
1414 }
1415 if (try p.parseFnCallArguments()) |params| {
1416 const call = try p.arena.allocator.create(Node.SuffixOp);
1417 call.* = .{
1418 .lhs = .{ .node = res },
1419 .op = .{
1420 .Call = .{
1421 .params = params.list,
1422 .async_token = null,
1423 },
1424 },
1425 .rtoken = params.rparen,
1426 };
1427 res = &call.base;
1428 continue;
1429 }
1430 break;
1415 }1431 }
1416 break;1432 return res;
1417 }1433 }
1418 return res;1434
1435 return null;
1419 }1436 }
14201437
1421 return null;1438 /// PrimaryTypeExpr
1422}1439 /// <- BUILTINIDENTIFIER FnCallArguments
1440 /// / CHAR_LITERAL
1441 /// / ContainerDecl
1442 /// / DOT IDENTIFIER
1443 /// / ErrorSetDecl
1444 /// / FLOAT
1445 /// / FnProto
1446 /// / GroupedExpr
1447 /// / LabeledTypeExpr
1448 /// / IDENTIFIER
1449 /// / IfTypeExpr
1450 /// / INTEGER
1451 /// / KEYWORD_comptime TypeExpr
1452 /// / KEYWORD_error DOT IDENTIFIER
1453 /// / KEYWORD_false
1454 /// / KEYWORD_null
1455 /// / KEYWORD_anyframe
1456 /// / KEYWORD_true
1457 /// / KEYWORD_undefined
1458 /// / KEYWORD_unreachable
1459 /// / STRINGLITERAL
1460 /// / SwitchExpr
1461 fn parsePrimaryTypeExpr(p: *Parser) !?*Node {
1462 if (try p.parseBuiltinCall()) |node| return node;
1463 if (p.eatToken(.CharLiteral)) |token| {
1464 const node = try p.arena.allocator.create(Node.CharLiteral);
1465 node.* = .{
1466 .token = token,
1467 };
1468 return &node.base;
1469 }
1470 if (try p.parseContainerDecl()) |node| return node;
1471 if (try p.parseAnonLiteral()) |node| return node;
1472 if (try p.parseErrorSetDecl()) |node| return node;
1473 if (try p.parseFloatLiteral()) |node| return node;
1474 if (try p.parseFnProto()) |node| return node;
1475 if (try p.parseGroupedExpr()) |node| return node;
1476 if (try p.parseLabeledTypeExpr()) |node| return node;
1477 if (try p.parseIdentifier()) |node| return node;
1478 if (try p.parseIfTypeExpr()) |node| return node;
1479 if (try p.parseIntegerLiteral()) |node| return node;
1480 if (p.eatToken(.Keyword_comptime)) |token| {
1481 const expr = (try p.parseTypeExpr()) orelse return null;
1482 const node = try p.arena.allocator.create(Node.Comptime);
1483 node.* = .{
1484 .doc_comments = null,
1485 .comptime_token = token,
1486 .expr = expr,
1487 };
1488 return &node.base;
1489 }
1490 if (p.eatToken(.Keyword_error)) |token| {
1491 const period = try p.expectTokenRecoverable(.Period);
1492 const identifier = try p.expectNodeRecoverable(parseIdentifier, .{
1493 .ExpectedIdentifier = .{ .token = p.tok_i },
1494 });
1495 const global_error_set = try p.createLiteral(Node.ErrorType, token);
1496 if (period == null or identifier == null) return global_error_set;
14231497
1424/// PrimaryTypeExpr1498 const node = try p.arena.allocator.create(Node.InfixOp);
1425/// <- BUILTINIDENTIFIER FnCallArguments1499 node.* = .{
1426/// / CHAR_LITERAL1500 .op_token = period.?,
1427/// / ContainerDecl1501 .lhs = global_error_set,
1428/// / DOT IDENTIFIER1502 .op = .Period,
1429/// / ErrorSetDecl1503 .rhs = identifier.?,
1430/// / FLOAT1504 };
1431/// / FnProto1505 return &node.base;
1432/// / GroupedExpr1506 }
1433/// / LabeledTypeExpr1507 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token);
1434/// / IDENTIFIER1508 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token);
1435/// / IfTypeExpr1509 if (p.eatToken(.Keyword_anyframe)) |token| {
1436/// / INTEGER1510 const node = try p.arena.allocator.create(Node.AnyFrameType);
1437/// / KEYWORD_comptime TypeExpr1511 node.* = .{
1438/// / KEYWORD_error DOT IDENTIFIER1512 .anyframe_token = token,
1439/// / KEYWORD_false1513 .result = null,
1440/// / KEYWORD_null1514 };
1441/// / KEYWORD_anyframe1515 return &node.base;
1442/// / KEYWORD_true1516 }
1443/// / KEYWORD_undefined1517 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token);
1444/// / KEYWORD_unreachable1518 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token);
1445/// / STRINGLITERAL1519 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token);
1446/// / SwitchExpr1520 if (try p.parseStringLiteral()) |node| return node;
1447fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1521 if (try p.parseSwitchExpr()) |node| return node;
1448 if (try parseBuiltinCall(arena, it, tree)) |node| return node;1522
1449 if (eatToken(it, .CharLiteral)) |token| {1523 return null;
1450 const node = try arena.create(Node.CharLiteral);1524 }
1451 node.* = .{1525
1452 .token = token,1526 /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
1527 fn parseContainerDecl(p: *Parser) !?*Node {
1528 const layout_token = p.eatToken(.Keyword_extern) orelse
1529 p.eatToken(.Keyword_packed);
1530
1531 const node = (try p.parseContainerDeclAuto()) orelse {
1532 if (layout_token) |token|
1533 p.putBackToken(token);
1534 return null;
1453 };1535 };
1454 return &node.base;1536 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
1537 return node;
1455 }1538 }
1456 if (try parseContainerDecl(arena, it, tree)) |node| return node;1539
1457 if (try parseAnonLiteral(arena, it, tree)) |node| return node;1540 /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1458 if (try parseErrorSetDecl(arena, it, tree)) |node| return node;1541 fn parseErrorSetDecl(p: *Parser) !?*Node {
1459 if (try parseFloatLiteral(arena, it, tree)) |node| return node;1542 const error_token = p.eatToken(.Keyword_error) orelse return null;
1460 if (try parseFnProto(arena, it, tree)) |node| return node;1543 if (p.eatToken(.LBrace) == null) {
1461 if (try parseGroupedExpr(arena, it, tree)) |node| return node;1544 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1462 if (try parseLabeledTypeExpr(arena, it, tree)) |node| return node;1545 p.putBackToken(error_token);
1463 if (try parseIdentifier(arena, it, tree)) |node| return node;1546 return null;
1464 if (try parseIfTypeExpr(arena, it, tree)) |node| return node;1547 }
1465 if (try parseIntegerLiteral(arena, it, tree)) |node| return node;1548 const decls = try p.parseErrorTagList();
1466 if (eatToken(it, .Keyword_comptime)) |token| {1549 const rbrace = try p.expectToken(.RBrace);
1467 const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;1550
1468 const node = try arena.create(Node.Comptime);1551 const node = try p.arena.allocator.create(Node.ErrorSetDecl);
1469 node.* = .{1552 node.* = .{
1470 .doc_comments = null,1553 .error_token = error_token,
1471 .comptime_token = token,1554 .decls = decls,
1472 .expr = expr,1555 .rbrace_token = rbrace,
1473 };1556 };
1474 return &node.base;1557 return &node.base;
1475 }1558 }
1476 if (eatToken(it, .Keyword_error)) |token| {1559
1477 const period = try expectTokenRecoverable(it, tree, .Period);1560 /// GroupedExpr <- LPAREN Expr RPAREN
1478 const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{1561 fn parseGroupedExpr(p: *Parser) !?*Node {
1479 .ExpectedIdentifier = .{ .token = it.index },1562 const lparen = p.eatToken(.LParen) orelse return null;
1563 const expr = try p.expectNode(parseExpr, .{
1564 .ExpectedExpr = .{ .token = p.tok_i },
1480 });1565 });
1481 const global_error_set = try createLiteral(arena, Node.ErrorType, token);1566 const rparen = try p.expectToken(.RParen);
1482 if (period == null or identifier == null) return global_error_set;
14831567
1484 const node = try arena.create(Node.InfixOp);1568 const node = try p.arena.allocator.create(Node.GroupedExpression);
1485 node.* = .{1569 node.* = .{
1486 .op_token = period.?,1570 .lparen = lparen,
1487 .lhs = global_error_set,1571 .expr = expr,
1488 .op = .Period,1572 .rparen = rparen,
1489 .rhs = identifier.?,
1490 };1573 };
1491 return &node.base;1574 return &node.base;
1492 }1575 }
1493 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);1576
1494 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);1577 /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1495 if (eatToken(it, .Keyword_anyframe)) |token| {1578 fn parseIfTypeExpr(p: *Parser) !?*Node {
1496 const node = try arena.create(Node.AnyFrameType);1579 return p.parseIf(parseTypeExpr);
1497 node.* = .{
1498 .anyframe_token = token,
1499 .result = null,
1500 };
1501 return &node.base;
1502 }1580 }
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;
15081581
1509 return null;1582 /// LabeledTypeExpr
1510}1583 /// <- BlockLabel Block
1584 /// / BlockLabel? LoopTypeExpr
1585 fn parseLabeledTypeExpr(p: *Parser) !?*Node {
1586 var colon: TokenIndex = undefined;
1587 const label = p.parseBlockLabel(&colon);
15111588
1512/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto1589 if (label) |token| {
1513fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1590 if (try p.parseBlock()) |node| {
1514 const layout_token = eatToken(it, .Keyword_extern) orelse1591 node.cast(Node.Block).?.label = token;
1515 eatToken(it, .Keyword_packed);1592 return node;
1593 }
1594 }
15161595
1517 const node = (try parseContainerDeclAuto(arena, it, tree)) orelse {1596 if (try p.parseLoopTypeExpr()) |node| {
1518 if (layout_token) |token|1597 switch (node.id) {
1519 putBackToken(it, token);1598 .For => node.cast(Node.For).?.label = label,
1520 return null;1599 .While => node.cast(Node.While).?.label = label,
1521 };1600 else => unreachable,
1522 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;1601 }
1523 return node;1602 return node;
1524}1603 }
15251604
1526/// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE1605 if (label) |token| {
1527fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1606 p.putBackToken(colon);
1528 const error_token = eatToken(it, .Keyword_error) orelse return null;1607 p.putBackToken(token);
1529 if (eatToken(it, .LBrace) == null) {1608 }
1530 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1531 putBackToken(it, error_token);
1532 return null;1609 return null;
1533 }1610 }
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}
1545
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}
15671611
1568/// LabeledTypeExpr1612 /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1569/// <- BlockLabel Block1613 fn parseLoopTypeExpr(p: *Parser) !?*Node {
1570/// / BlockLabel? LoopTypeExpr1614 const inline_token = p.eatToken(.Keyword_inline);
1571fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1572 var colon: TokenIndex = undefined;
1573 const label = parseBlockLabel(arena, it, tree, &colon);
15741615
1575 if (label) |token| {1616 if (try p.parseForTypeExpr()) |node| {
1576 if (try parseBlock(arena, it, tree)) |node| {1617 node.cast(Node.For).?.inline_token = inline_token;
1577 node.cast(Node.Block).?.label = token;
1578 return node;1618 return node;
1579 }1619 }
1580 }
15811620
1582 if (try parseLoopTypeExpr(arena, it, tree)) |node| {1621 if (try p.parseWhileTypeExpr()) |node| {
1583 switch (node.id) {1622 node.cast(Node.While).?.inline_token = inline_token;
1584 .For => node.cast(Node.For).?.label = label,1623 return node;
1585 .While => node.cast(Node.While).?.label = label,
1586 else => unreachable,
1587 }1624 }
1588 return node;
1589 }
15901625
1591 if (label) |token| {1626 if (inline_token == null) return null;
1592 putBackToken(it, colon);1627
1593 putBackToken(it, token);1628 // If we've seen "inline", there should have been a "for" or "while"
1629 try p.errors.append(p.gpa, .{
1630 .ExpectedInlinable = .{ .token = p.tok_i },
1631 });
1632 return error.ParseError;
1594 }1633 }
1595 return null;
1596}
15971634
1598/// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)1635 /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
1599fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1636 fn parseForTypeExpr(p: *Parser) !?*Node {
1600 const inline_token = eatToken(it, .Keyword_inline);1637 const node = (try p.parseForPrefix()) orelse return null;
1638 const for_prefix = node.cast(Node.For).?;
16011639
1602 if (try parseForTypeExpr(arena, it, tree)) |node| {1640 const type_expr = try p.expectNode(parseTypeExpr, .{
1603 node.cast(Node.For).?.inline_token = inline_token;1641 .ExpectedTypeExpr = .{ .token = p.tok_i },
1604 return node;1642 });
1605 }1643 for_prefix.body = type_expr;
16061644
1607 if (try parseWhileTypeExpr(arena, it, tree)) |node| {1645 if (p.eatToken(.Keyword_else)) |else_token| {
1608 node.cast(Node.While).?.inline_token = inline_token;1646 const else_expr = try p.expectNode(parseTypeExpr, .{
1609 return node;1647 .ExpectedTypeExpr = .{ .token = p.tok_i },
1610 }1648 });
16111649
1612 if (inline_token == null) return null;1650 const else_node = try p.arena.allocator.create(Node.Else);
1651 else_node.* = .{
1652 .else_token = else_token,
1653 .payload = null,
1654 .body = else_expr,
1655 };
16131656
1614 // If we've seen "inline", there should have been a "for" or "while"1657 for_prefix.@"else" = else_node;
1615 try tree.errors.push(.{1658 }
1616 .ExpectedInlinable = .{ .token = it.index },
1617 });
1618 return error.ParseError;
1619}
16201659
1621/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?1660 return node;
1622fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1661 }
1623 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1624 const for_prefix = node.cast(Node.For).?;
16251662
1626 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1663 /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1627 .ExpectedTypeExpr = .{ .token = it.index },1664 fn parseWhileTypeExpr(p: *Parser) !?*Node {
1628 });1665 const node = (try p.parseWhilePrefix()) orelse return null;
1629 for_prefix.body = type_expr;1666 const while_prefix = node.cast(Node.While).?;
16301667
1631 if (eatToken(it, .Keyword_else)) |else_token| {1668 const type_expr = try p.expectNode(parseTypeExpr, .{
1632 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1669 .ExpectedTypeExpr = .{ .token = p.tok_i },
1633 .ExpectedTypeExpr = .{ .token = it.index },
1634 });1670 });
1671 while_prefix.body = type_expr;
16351672
1636 const else_node = try arena.create(Node.Else);1673 if (p.eatToken(.Keyword_else)) |else_token| {
1637 else_node.* = .{1674 const payload = try p.parsePayload();
1638 .else_token = else_token,
1639 .payload = null,
1640 .body = else_expr,
1641 };
16421675
1643 for_prefix.@"else" = else_node;1676 const else_expr = try p.expectNode(parseTypeExpr, .{
1644 }1677 .ExpectedTypeExpr = .{ .token = p.tok_i },
1678 });
16451679
1646 return node;1680 const else_node = try p.arena.allocator.create(Node.Else);
1647}1681 else_node.* = .{
1682 .else_token = else_token,
1683 .payload = null,
1684 .body = else_expr,
1685 };
1686
1687 while_prefix.@"else" = else_node;
1688 }
16481689
1649/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?1690 return node;
1650fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1691 }
1651 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1652 const while_prefix = node.cast(Node.While).?;
16531692
1654 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1693 /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
1655 .ExpectedTypeExpr = .{ .token = it.index },1694 fn parseSwitchExpr(p: *Parser) !?*Node {
1656 });1695 const switch_token = p.eatToken(.Keyword_switch) orelse return null;
1657 while_prefix.body = type_expr;1696 _ = try p.expectToken(.LParen);
1697 const expr_node = try p.expectNode(parseExpr, .{
1698 .ExpectedExpr = .{ .token = p.tok_i },
1699 });
1700 _ = try p.expectToken(.RParen);
1701 _ = try p.expectToken(.LBrace);
1702 const cases = try p.parseSwitchProngList();
1703 const rbrace = try p.expectToken(.RBrace);
16581704
1659 if (eatToken(it, .Keyword_else)) |else_token| {1705 const node = try p.arena.allocator.create(Node.Switch);
1660 const payload = try parsePayload(arena, it, tree);1706 node.* = .{
1707 .switch_token = switch_token,
1708 .expr = expr_node,
1709 .cases = cases,
1710 .rbrace = rbrace,
1711 };
1712 return &node.base;
1713 }
16611714
1662 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{1715 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1663 .ExpectedTypeExpr = .{ .token = it.index },1716 fn parseAsmExpr(p: *Parser) !?*Node {
1717 const asm_token = p.eatToken(.Keyword_asm) orelse return null;
1718 const volatile_token = p.eatToken(.Keyword_volatile);
1719 _ = try p.expectToken(.LParen);
1720 const template = try p.expectNode(parseExpr, .{
1721 .ExpectedExpr = .{ .token = p.tok_i },
1664 });1722 });
16651723
1666 const else_node = try arena.create(Node.Else);1724 const node = try p.arena.allocator.create(Node.Asm);
1667 else_node.* = .{1725 node.* = .{
1668 .else_token = else_token,1726 .asm_token = asm_token,
1669 .payload = null,1727 .volatile_token = volatile_token,
1670 .body = else_expr,1728 .template = template,
1729 .outputs = Node.Asm.OutputList{},
1730 .inputs = Node.Asm.InputList{},
1731 .clobbers = Node.Asm.ClobberList{},
1732 .rparen = undefined,
1671 };1733 };
16721734
1673 while_prefix.@"else" = else_node;1735 try p.parseAsmOutput(node);
1736 node.rparen = try p.expectToken(.RParen);
1737 return &node.base;
1674 }1738 }
16751739
1676 return node;1740 /// DOT IDENTIFIER
1677}1741 fn parseAnonLiteral(p: *Parser) !?*Node {
1742 const dot = p.eatToken(.Period) orelse return null;
16781743
1679/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE1744 // anon enum literal
1680fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1745 if (p.eatToken(.Identifier)) |name| {
1681 const switch_token = eatToken(it, .Keyword_switch) orelse return null;1746 const node = try p.arena.allocator.create(Node.EnumLiteral);
1682 _ = try expectToken(it, tree, .LParen);1747 node.* = .{
1683 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1748 .dot = dot,
1684 .ExpectedExpr = .{ .token = it.index },1749 .name = name,
1685 });1750 };
1686 _ = try expectToken(it, tree, .RParen);1751 return &node.base;
1687 _ = try expectToken(it, tree, .LBrace);1752 }
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}
17001753
1701/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN1754 // anon container literal
1702fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1755 if (try p.parseInitList()) |node| {
1703 const asm_token = eatToken(it, .Keyword_asm) orelse return null;1756 node.lhs = .{ .dot = dot };
1704 const volatile_token = eatToken(it, .Keyword_volatile);1757 return &node.base;
1705 _ = try expectToken(it, tree, .LParen);1758 }
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 };
17201759
1721 try parseAsmOutput(arena, it, tree, node);1760 p.putBackToken(dot);
1722 node.rparen = try expectToken(it, tree, .RParen);1761 return null;
1723 return &node.base;1762 }
1724}1763
1764 /// AsmOutput <- COLON AsmOutputList AsmInput?
1765 fn parseAsmOutput(p: *Parser, asm_node: *Node.Asm) !void {
1766 if (p.eatToken(.Colon) == null) return;
1767 asm_node.outputs = try p.parseAsmOutputList();
1768 try p.parseAsmInput(asm_node);
1769 }
1770
1771 /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1772 fn parseAsmOutputItem(p: *Parser) !?*Node.AsmOutput {
1773 const lbracket = p.eatToken(.LBracket) orelse return null;
1774 const name = try p.expectNode(parseIdentifier, .{
1775 .ExpectedIdentifier = .{ .token = p.tok_i },
1776 });
1777 _ = try p.expectToken(.RBracket);
1778
1779 const constraint = try p.expectNode(parseStringLiteral, .{
1780 .ExpectedStringLiteral = .{ .token = p.tok_i },
1781 });
17251782
1726/// DOT IDENTIFIER1783 _ = try p.expectToken(.LParen);
1727fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1784 const kind: Node.AsmOutput.Kind = blk: {
1728 const dot = eatToken(it, .Period) orelse return null;1785 if (p.eatToken(.Arrow) != null) {
1786 const return_ident = try p.expectNode(parseTypeExpr, .{
1787 .ExpectedTypeExpr = .{ .token = p.tok_i },
1788 });
1789 break :blk .{ .Return = return_ident };
1790 }
1791 const variable = try p.expectNode(parseIdentifier, .{
1792 .ExpectedIdentifier = .{ .token = p.tok_i },
1793 });
1794 break :blk .{ .Variable = variable.cast(Node.Identifier).? };
1795 };
1796 const rparen = try p.expectToken(.RParen);
17291797
1730 // anon enum literal1798 const node = try p.arena.allocator.create(Node.AsmOutput);
1731 if (eatToken(it, .Identifier)) |name| {
1732 const node = try arena.create(Node.EnumLiteral);
1733 node.* = .{1799 node.* = .{
1734 .dot = dot,1800 .lbracket = lbracket,
1735 .name = name,1801 .symbolic_name = name,
1802 .constraint = constraint,
1803 .kind = kind,
1804 .rparen = rparen,
1736 };1805 };
1737 return &node.base;1806 return node;
1738 }1807 }
17391808
1740 // anon container literal1809 /// AsmInput <- COLON AsmInputList AsmClobbers?
1741 if (try parseInitList(arena, it, tree)) |node| {1810 fn parseAsmInput(p: *Parser, asm_node: *Node.Asm) !void {
1742 node.lhs = .{ .dot = dot };1811 if (p.eatToken(.Colon) == null) return;
1743 return &node.base;1812 asm_node.inputs = try p.parseAsmInputList();
1813 try p.parseAsmClobbers(asm_node);
1744 }1814 }
17451815
1746 putBackToken(it, dot);1816 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1747 return null;1817 fn parseAsmInputItem(p: *Parser) !?*Node.AsmInput {
1748}1818 const lbracket = p.eatToken(.LBracket) orelse return null;
17491819 const name = try p.expectNode(parseIdentifier, .{
1750/// AsmOutput <- COLON AsmOutputList AsmInput?1820 .ExpectedIdentifier = .{ .token = p.tok_i },
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}
1756
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 };
1776 }
1777 const variable = try expectNode(arena, it, tree, parseIdentifier, .{
1778 .ExpectedIdentifier = .{ .token = it.index },
1779 });1821 });
1780 break :blk .{ .Variable = variable.cast(Node.Identifier).? };1822 _ = try p.expectToken(.RBracket);
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}
17941823
1795/// AsmInput <- COLON AsmInputList AsmClobbers?1824 const constraint = try p.expectNode(parseStringLiteral, .{
1796fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {1825 .ExpectedStringLiteral = .{ .token = p.tok_i },
1797 if (eatToken(it, .Colon) == null) return;1826 });
1798 asm_node.inputs = try parseAsmInputList(arena, it, tree);
1799 try parseAsmClobbers(arena, it, tree, asm_node);
1800}
18011827
1802/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN1828 _ = try p.expectToken(.LParen);
1803fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {1829 const expr = try p.expectNode(parseExpr, .{
1804 const lbracket = eatToken(it, .LBracket) orelse return null;1830 .ExpectedExpr = .{ .token = p.tok_i },
1805 const name = try expectNode(arena, it, tree, parseIdentifier, .{1831 });
1806 .ExpectedIdentifier = .{ .token = it.index },1832 const rparen = try p.expectToken(.RParen);
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}
18301833
1831/// AsmClobbers <- COLON StringList1834 const node = try p.arena.allocator.create(Node.AsmInput);
1832/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?1835 node.* = .{
1833fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {1836 .lbracket = lbracket,
1834 if (eatToken(it, .Colon) == null) return;1837 .symbolic_name = name,
1835 asm_node.clobbers = try ListParseFn(1838 .constraint = constraint,
1836 Node.Asm.ClobberList,1839 .expr = expr,
1837 parseStringLiteral,1840 .rparen = rparen,
1838 )(arena, it, tree);1841 };
1839}1842 return node;
1843 }
18401844
1841/// BreakLabel <- COLON IDENTIFIER1845 /// AsmClobbers <- COLON StringList
1842fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1846 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
1843 _ = eatToken(it, .Colon) orelse return null;1847 fn parseAsmClobbers(p: *Parser, asm_node: *Node.Asm) !void {
1844 return try expectNode(arena, it, tree, parseIdentifier, .{1848 if (p.eatToken(.Colon) == null) return;
1845 .ExpectedIdentifier = .{ .token = it.index },1849 asm_node.clobbers = try ListParseFn(
1846 });1850 Node.Asm.ClobberList,
1847}1851 parseStringLiteral,
1852 )(p);
1853 }
18481854
1849/// BlockLabel <- IDENTIFIER COLON1855 /// BreakLabel <- COLON IDENTIFIER
1850fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree, colon_token: *TokenIndex) ?TokenIndex {1856 fn parseBreakLabel(p: *Parser) !?*Node {
1851 const identifier = eatToken(it, .Identifier) orelse return null;1857 _ = p.eatToken(.Colon) orelse return null;
1852 if (eatToken(it, .Colon)) |colon| {1858 return p.expectNode(parseIdentifier, .{
1853 colon_token.* = colon;1859 .ExpectedIdentifier = .{ .token = p.tok_i },
1854 return identifier;1860 });
1855 }1861 }
1856 putBackToken(it, identifier);
1857 return null;
1858}
18591862
1860/// FieldInit <- DOT IDENTIFIER EQUAL Expr1863 /// BlockLabel <- IDENTIFIER COLON
1861fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1864 fn parseBlockLabel(p: *Parser, colon_token: *TokenIndex) ?TokenIndex {
1862 const period_token = eatToken(it, .Period) orelse return null;1865 const identifier = p.eatToken(.Identifier) orelse return null;
1863 const name_token = eatToken(it, .Identifier) orelse {1866 if (p.eatToken(.Colon)) |colon| {
1864 // Because of anon literals `.{` is also valid.1867 colon_token.* = colon;
1865 putBackToken(it, period_token);1868 return identifier;
1866 return null;1869 }
1867 };1870 p.putBackToken(identifier);
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;1871 return null;
1873 };1872 }
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}
1886
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}
18971873
1898/// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN1874 /// FieldInit <- DOT IDENTIFIER EQUAL Expr
1899fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1875 fn parseFieldInit(p: *Parser) !?*Node {
1900 _ = eatToken(it, .Keyword_linksection) orelse return null;1876 const period_token = p.eatToken(.Period) orelse return null;
1901 _ = try expectToken(it, tree, .LParen);1877 const name_token = p.eatToken(.Identifier) orelse {
1902 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1878 // Because of anon literals `.{` is also valid.
1903 .ExpectedExpr = .{ .token = it.index },1879 p.putBackToken(period_token);
1904 });1880 return null;
1905 _ = try expectToken(it, tree, .RParen);1881 };
1906 return expr_node;1882 const eq_token = p.eatToken(.Equal) orelse {
1907}1883 // `.Name` may also be an enum literal, which is a later rule.
1884 p.putBackToken(name_token);
1885 p.putBackToken(period_token);
1886 return null;
1887 };
1888 const expr_node = try p.expectNode(parseExpr, .{
1889 .ExpectedExpr = .{ .token = p.tok_i },
1890 });
19081891
1909/// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN1892 const node = try p.arena.allocator.create(Node.FieldInitializer);
1910fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1893 node.* = .{
1911 _ = eatToken(it, .Keyword_callconv) orelse return null;1894 .period_token = period_token,
1912 _ = try expectToken(it, tree, .LParen);1895 .name_token = name_token,
1913 const expr_node = try expectNode(arena, it, tree, parseExpr, .{1896 .expr = expr_node,
1914 .ExpectedExpr = .{ .token = it.index },1897 };
1915 });1898 return &node.base;
1916 _ = try expectToken(it, tree, .RParen);1899 }
1917 return expr_node;
1918}
19191900
1920/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType1901 /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
1921fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1902 fn parseWhileContinueExpr(p: *Parser) !?*Node {
1922 const doc_comments = try parseDocComment(arena, it, tree);1903 _ = p.eatToken(.Colon) orelse return null;
1923 const noalias_token = eatToken(it, .Keyword_noalias);1904 _ = try p.expectToken(.LParen);
1924 const comptime_token = if (noalias_token == null) eatToken(it, .Keyword_comptime) else null;1905 const node = try p.expectNode(parseAssignExpr, .{
1925 const name_token = blk: {1906 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
1926 const identifier = eatToken(it, .Identifier) orelse break :blk null;
1927 if (eatToken(it, .Colon) != null) break :blk identifier;
1928 putBackToken(it, identifier); // ParamType may also be an identifier
1929 break :blk null;
1930 };
1931 const param_type = (try parseParamType(arena, it, tree)) orelse {
1932 // Only return cleanly if no keyword, identifier, or doc comment was found
1933 if (noalias_token == null and
1934 comptime_token == null and
1935 name_token == null and
1936 doc_comments == null) return null;
1937 try tree.errors.push(.{
1938 .ExpectedParamType = .{ .token = it.index },
1939 });1907 });
1940 return error.ParseError;1908 _ = try p.expectToken(.RParen);
1941 };1909 return node;
1910 }
19421911
1943 const param_decl = try arena.create(Node.ParamDecl);1912 /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
1944 param_decl.* = .{1913 fn parseLinkSection(p: *Parser) !?*Node {
1945 .doc_comments = doc_comments,1914 _ = p.eatToken(.Keyword_linksection) orelse return null;
1946 .comptime_token = comptime_token,1915 _ = try p.expectToken(.LParen);
1947 .noalias_token = noalias_token,1916 const expr_node = try p.expectNode(parseExpr, .{
1948 .name_token = name_token,1917 .ExpectedExpr = .{ .token = p.tok_i },
1949 .param_type = param_type,1918 });
1950 };1919 _ = try p.expectToken(.RParen);
1951 return &param_decl.base;1920 return expr_node;
1952}1921 }
19531922
1954/// ParamType1923 /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
1955/// <- KEYWORD_var1924 fn parseCallconv(p: *Parser) !?*Node {
1956/// / DOT31925 _ = p.eatToken(.Keyword_callconv) orelse return null;
1957/// / TypeExpr1926 _ = try p.expectToken(.LParen);
1958fn parseParamType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?Node.ParamDecl.ParamType {1927 const expr_node = try p.expectNode(parseExpr, .{
1959 // TODO cast from tuple to error union is broken1928 .ExpectedExpr = .{ .token = p.tok_i },
1960 const P = Node.ParamDecl.ParamType;1929 });
1961 if (try parseVarType(arena, it, tree)) |node| return P{ .var_type = node };1930 _ = try p.expectToken(.RParen);
1962 if (eatToken(it, .Ellipsis3)) |token| return P{ .var_args = token };1931 return expr_node;
1963 if (try parseTypeExpr(arena, it, tree)) |node| return P{ .type_expr = node };1932 }
1964 return null;1933
1965}1934 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
19661935 fn parseParamDecl(p: *Parser) !?*Node {
1967/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?1936 const doc_comments = try p.parseDocComment();
1968fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1937 const noalias_token = p.eatToken(.Keyword_noalias);
1969 const if_token = eatToken(it, .Keyword_if) orelse return null;1938 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
1970 _ = try expectToken(it, tree, .LParen);1939 const name_token = blk: {
1971 const condition = try expectNode(arena, it, tree, parseExpr, .{1940 const identifier = p.eatToken(.Identifier) orelse break :blk null;
1972 .ExpectedExpr = .{ .token = it.index },1941 if (p.eatToken(.Colon) != null) break :blk identifier;
1973 });1942 p.putBackToken(identifier); // ParamType may also be an identifier
1974 _ = try expectToken(it, tree, .RParen);1943 break :blk null;
1975 const payload = try parsePtrPayload(arena, it, tree);1944 };
19761945 const param_type = (try p.parseParamType()) orelse {
1977 const node = try arena.create(Node.If);1946 // Only return cleanly if no keyword, identifier, or doc comment was found
1978 node.* = .{1947 if (noalias_token == null and
1979 .if_token = if_token,1948 comptime_token == null and
1980 .condition = condition,1949 name_token == null and
1981 .payload = payload,1950 doc_comments == null) return null;
1982 .body = undefined, // set by caller1951 try p.errors.append(p.gpa, .{
1983 .@"else" = null,1952 .ExpectedParamType = .{ .token = p.tok_i },
1984 };1953 });
1985 return &node.base;1954 return error.ParseError;
1986}1955 };
19871956
1988/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?1957 const param_decl = try p.arena.allocator.create(Node.ParamDecl);
1989fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1958 param_decl.* = .{
1990 const while_token = eatToken(it, .Keyword_while) orelse return null;1959 .doc_comments = doc_comments,
19911960 .comptime_token = comptime_token,
1992 _ = try expectToken(it, tree, .LParen);1961 .noalias_token = noalias_token,
1993 const condition = try expectNode(arena, it, tree, parseExpr, .{1962 .name_token = name_token,
1994 .ExpectedExpr = .{ .token = it.index },1963 .param_type = param_type,
1995 });1964 };
1996 _ = try expectToken(it, tree, .RParen);1965 return &param_decl.base;
19971966 }
1998 const payload = try parsePtrPayload(arena, it, tree);1967
1999 const continue_expr = try parseWhileContinueExpr(arena, it, tree);1968 /// ParamType
20001969 /// <- KEYWORD_var
2001 const node = try arena.create(Node.While);1970 /// / DOT3
2002 node.* = .{1971 /// / TypeExpr
2003 .label = null,1972 fn parseParamType(p: *Parser) !?Node.ParamDecl.ParamType {
2004 .inline_token = null,1973 // TODO cast from tuple to error union is broken
2005 .while_token = while_token,1974 const P = Node.ParamDecl.ParamType;
2006 .condition = condition,1975 if (try p.parseVarType()) |node| return P{ .var_type = node };
2007 .payload = payload,1976 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
2008 .continue_expr = continue_expr,1977 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
2009 .body = undefined, // set by caller1978 return null;
2010 .@"else" = null,1979 }
2011 };
2012 return &node.base;
2013}
20141980
2015/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload1981 /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
2016fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1982 fn parseIfPrefix(p: *Parser) !?*Node {
2017 const for_token = eatToken(it, .Keyword_for) orelse return null;1983 const if_token = p.eatToken(.Keyword_if) orelse return null;
20181984 _ = try p.expectToken(.LParen);
2019 _ = try expectToken(it, tree, .LParen);1985 const condition = try p.expectNode(parseExpr, .{
2020 const array_expr = try expectNode(arena, it, tree, parseExpr, .{1986 .ExpectedExpr = .{ .token = p.tok_i },
2021 .ExpectedExpr = .{ .token = it.index },1987 });
2022 });1988 _ = try p.expectToken(.RParen);
2023 _ = try expectToken(it, tree, .RParen);1989 const payload = try p.parsePtrPayload();
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}
20411990
2042/// Payload <- PIPE IDENTIFIER PIPE1991 const node = try p.arena.allocator.create(Node.If);
2043fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1992 node.* = .{
2044 const lpipe = eatToken(it, .Pipe) orelse return null;1993 .if_token = if_token,
2045 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{1994 .condition = condition,
2046 .ExpectedIdentifier = .{ .token = it.index },1995 .payload = payload,
2047 });1996 .body = undefined, // set by caller
2048 const rpipe = try expectToken(it, tree, .Pipe);1997 .@"else" = null,
20491998 };
2050 const node = try arena.create(Node.Payload);1999 return &node.base;
2051 node.* = .{2000 }
2052 .lpipe = lpipe,
2053 .error_symbol = identifier,
2054 .rpipe = rpipe,
2055 };
2056 return &node.base;
2057}
20582001
2059/// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE2002 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2060fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2003 fn parseWhilePrefix(p: *Parser) !?*Node {
2061 const lpipe = eatToken(it, .Pipe) orelse return null;2004 const while_token = p.eatToken(.Keyword_while) 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}
20772005
2078/// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE2006 _ = try p.expectToken(.LParen);
2079fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2007 const condition = try p.expectNode(parseExpr, .{
2080 const lpipe = eatToken(it, .Pipe) orelse return null;2008 .ExpectedExpr = .{ .token = p.tok_i },
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 },
2091 });2009 });
2010 _ = try p.expectToken(.RParen);
20922011
2093 const rpipe = try expectToken(it, tree, .Pipe);2012 const payload = try p.parsePtrPayload();
2013 const continue_expr = try p.parseWhileContinueExpr();
20942014
2095 const node = try arena.create(Node.PointerIndexPayload);2015 const node = try p.arena.allocator.create(Node.While);
2096 node.* = .{2016 node.* = .{
2097 .lpipe = lpipe,2017 .label = null,
2098 .ptr_token = asterisk,2018 .inline_token = null,
2099 .value_symbol = identifier,2019 .while_token = while_token,
2100 .index_symbol = index,2020 .condition = condition,
2101 .rpipe = rpipe,2021 .payload = payload,
2102 };2022 .continue_expr = continue_expr,
2103 return &node.base;2023 .body = undefined, // set by caller
2104}2024 .@"else" = null,
2025 };
2026 return &node.base;
2027 }
21052028
2106/// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr2029 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2107fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2030 fn parseForPrefix(p: *Parser) !?*Node {
2108 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;2031 const for_token = p.eatToken(.Keyword_for) 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}
21222032
2123/// SwitchCase2033 _ = try p.expectToken(.LParen);
2124/// <- SwitchItem (COMMA SwitchItem)* COMMA?2034 const array_expr = try p.expectNode(parseExpr, .{
2125/// / KEYWORD_else2035 .ExpectedExpr = .{ .token = p.tok_i },
2126fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2036 });
2127 var list = Node.SwitchCase.ItemList.init(arena);2037 _ = try p.expectToken(.RParen);
21282038
2129 if (try parseSwitchItem(arena, it, tree)) |first_item| {2039 const payload = try p.expectNode(parsePtrIndexPayload, .{
2130 try list.push(first_item);2040 .ExpectedPayload = .{ .token = p.tok_i },
2131 while (eatToken(it, .Comma) != null) {2041 });
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,
2139 };
2140 try list.push(&else_node.base);
2141 } else return null;
21422042
2143 const node = try arena.create(Node.SwitchCase);2043 const node = try p.arena.allocator.create(Node.For);
2144 node.* = .{2044 node.* = .{
2145 .items = list,2045 .label = null,
2146 .arrow_token = undefined, // set by caller2046 .inline_token = null,
2147 .payload = null,2047 .for_token = for_token,
2148 .expr = undefined, // set by caller2048 .array_expr = array_expr,
2149 };2049 .payload = payload,
2150 return &node.base;2050 .body = undefined, // set by caller
2151}2051 .@"else" = null,
2052 };
2053 return &node.base;
2054 }
21522055
2153/// SwitchItem <- Expr (DOT3 Expr)?2056 /// Payload <- PIPE IDENTIFIER PIPE
2154fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2057 fn parsePayload(p: *Parser) !?*Node {
2155 const expr = (try parseExpr(arena, it, tree)) orelse return null;2058 const lpipe = p.eatToken(.Pipe) orelse return null;
2156 if (eatToken(it, .Ellipsis3)) |token| {2059 const identifier = try p.expectNode(parseIdentifier, .{
2157 const range_end = try expectNode(arena, it, tree, parseExpr, .{2060 .ExpectedIdentifier = .{ .token = p.tok_i },
2158 .ExpectedExpr = .{ .token = it.index },
2159 });2061 });
2062 const rpipe = try p.expectToken(.Pipe);
21602063
2161 const node = try arena.create(Node.InfixOp);2064 const node = try p.arena.allocator.create(Node.Payload);
2162 node.* = .{2065 node.* = .{
2163 .op_token = token,2066 .lpipe = lpipe,
2164 .lhs = expr,2067 .error_symbol = identifier,
2165 .op = .Range,2068 .rpipe = rpipe,
2166 .rhs = range_end,
2167 };2069 };
2168 return &node.base;2070 return &node.base;
2169 }2071 }
2170 return expr;
2171}
21722072
2173/// AssignOp2073 /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
2174/// <- ASTERISKEQUAL2074 fn parsePtrPayload(p: *Parser) !?*Node {
2175/// / SLASHEQUAL2075 const lpipe = p.eatToken(.Pipe) orelse return null;
2176/// / PERCENTEQUAL2076 const asterisk = p.eatToken(.Asterisk);
2177/// / PLUSEQUAL2077 const identifier = try p.expectNode(parseIdentifier, .{
2178/// / MINUSEQUAL2078 .ExpectedIdentifier = .{ .token = p.tok_i },
2179/// / LARROW2EQUAL2079 });
2180/// / RARROW2EQUAL2080 const rpipe = try p.expectToken(.Pipe);
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 };
22102081
2211 const node = try arena.create(Node.InfixOp);2082 const node = try p.arena.allocator.create(Node.PointerPayload);
2212 node.* = .{2083 node.* = .{
2213 .op_token = token.index,2084 .lpipe = lpipe,
2214 .lhs = undefined, // set by caller2085 .ptr_token = asterisk,
2215 .op = op,2086 .value_symbol = identifier,
2216 .rhs = undefined, // set by caller2087 .rpipe = rpipe,
2217 };2088 };
2218 return &node.base;2089 return &node.base;
2219}2090 }
22202091
2221/// CompareOp2092 /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
2222/// <- EQUALEQUAL2093 fn parsePtrIndexPayload(p: *Parser) !?*Node {
2223/// / EXCLAMATIONMARKEQUAL2094 const lpipe = p.eatToken(.Pipe) orelse return null;
2224/// / LARROW2095 const asterisk = p.eatToken(.Asterisk);
2225/// / RARROW2096 const identifier = try p.expectNode(parseIdentifier, .{
2226/// / LARROWEQUAL2097 .ExpectedIdentifier = .{ .token = p.tok_i },
2227/// / RARROWEQUAL2098 });
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 };
22422099
2243 return try createInfixOp(arena, token.index, op);2100 const index = if (p.eatToken(.Comma) == null)
2244}2101 null
2102 else
2103 try p.expectNode(parseIdentifier, .{
2104 .ExpectedIdentifier = .{ .token = p.tok_i },
2105 });
22452106
2246/// BitwiseOp2107 const rpipe = try p.expectToken(.Pipe);
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 };
22652108
2266 return try createInfixOp(arena, token.index, op);2109 const node = try p.arena.allocator.create(Node.PointerIndexPayload);
2267}2110 node.* = .{
2111 .lpipe = lpipe,
2112 .ptr_token = asterisk,
2113 .value_symbol = identifier,
2114 .index_symbol = index,
2115 .rpipe = rpipe,
2116 };
2117 return &node.base;
2118 }
22682119
2269/// BitShiftOp2120 /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
2270/// <- LARROW22121 fn parseSwitchProng(p: *Parser) !?*Node {
2271/// / RARROW22122 const node = (try p.parseSwitchCase()) orelse return null;
2272fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2123 const arrow = try p.expectToken(.EqualAngleBracketRight);
2273 const token = nextToken(it);2124 const payload = try p.parsePtrPayload();
2274 const op: Node.InfixOp.Op = switch (token.ptr.id) {2125 const expr = try p.expectNode(parseAssignExpr, .{
2275 .AngleBracketAngleBracketLeft => .BitShiftLeft,2126 .ExpectedExprOrAssignment = .{ .token = p.tok_i },
2276 .AngleBracketAngleBracketRight => .BitShiftRight,2127 });
2277 else => {
2278 putBackToken(it, token.index);
2279 return null;
2280 },
2281 };
22822128
2283 return try createInfixOp(arena, token.index, op);2129 const switch_case = node.cast(Node.SwitchCase).?;
2284}2130 switch_case.arrow_token = arrow;
2131 switch_case.payload = payload;
2132 switch_case.expr = expr;
22852133
2286/// AdditionOp2134 return node;
2287/// <- PLUS2135 }
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 };
23052136
2306 return try createInfixOp(arena, token.index, op);2137 /// SwitchCase
2307}2138 /// <- SwitchItem (COMMA SwitchItem)* COMMA?
2139 /// / KEYWORD_else
2140 fn parseSwitchCase(p: *Parser) !?*Node {
2141 var list = Node.SwitchCase.ItemList{};
2142 var list_it = &list.first;
23082143
2309/// MultiplyOp2144 if (try p.parseSwitchItem()) |first_item| {
2310/// <- PIPE22145 list_it = try p.llpush(*Node, list_it, first_item);
2311/// / ASTERISK2146 while (p.eatToken(.Comma) != null) {
2312/// / SLASH2147 const next_item = (try p.parseSwitchItem()) orelse break;
2313/// / PERCENT2148 list_it = try p.llpush(*Node, list_it, next_item);
2314/// / ASTERISK22149 }
2315/// / ASTERISKPERCENT2150 } else if (p.eatToken(.Keyword_else)) |else_token| {
2316fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2151 const else_node = try p.arena.allocator.create(Node.SwitchElse);
2317 const token = nextToken(it);2152 else_node.* = .{
2318 const op: Node.InfixOp.Op = switch (token.ptr.id) {2153 .token = else_token,
2319 .PipePipe => .MergeErrorSets,2154 };
2320 .Asterisk => .Mul,2155 list_it = try p.llpush(*Node, list_it, &else_node.base);
2321 .Slash => .Div,2156 } else return null;
2322 .Percent => .Mod,
2323 .AsteriskAsterisk => .ArrayMult,
2324 .AsteriskPercent => .MulWrap,
2325 else => {
2326 putBackToken(it, token.index);
2327 return null;
2328 },
2329 };
23302157
2331 return try createInfixOp(arena, token.index, op);2158 const node = try p.arena.allocator.create(Node.SwitchCase);
2332}2159 node.* = .{
2160 .items = list,
2161 .arrow_token = undefined, // set by caller
2162 .payload = null,
2163 .expr = undefined, // set by caller
2164 };
2165 return &node.base;
2166 }
23332167
2334/// PrefixOp2168 /// SwitchItem <- Expr (DOT3 Expr)?
2335/// <- EXCLAMATIONMARK2169 fn parseSwitchItem(p: *Parser) !?*Node {
2336/// / MINUS2170 const expr = (try p.parseExpr()) orelse return null;
2337/// / TILDE2171 if (p.eatToken(.Ellipsis3)) |token| {
2338/// / MINUSPERCENT2172 const range_end = try p.expectNode(parseExpr, .{
2339/// / AMPERSAND2173 .ExpectedExpr = .{ .token = p.tok_i },
2340/// / KEYWORD_try2174 });
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 };
23572175
2358 const node = try arena.create(Node.PrefixOp);2176 const node = try p.arena.allocator.create(Node.InfixOp);
2359 node.* = .{2177 node.* = .{
2360 .op_token = token.index,2178 .op_token = token,
2361 .op = op,2179 .lhs = expr,
2362 .rhs = undefined, // set by caller2180 .op = .Range,
2363 };2181 .rhs = range_end,
2364 return &node.base;2182 };
2365}2183 return &node.base;
2184 }
2185 return expr;
2186 }
2187
2188 /// AssignOp
2189 /// <- ASTERISKEQUAL
2190 /// / SLASHEQUAL
2191 /// / PERCENTEQUAL
2192 /// / PLUSEQUAL
2193 /// / MINUSEQUAL
2194 /// / LARROW2EQUAL
2195 /// / RARROW2EQUAL
2196 /// / AMPERSANDEQUAL
2197 /// / CARETEQUAL
2198 /// / PIPEEQUAL
2199 /// / ASTERISKPERCENTEQUAL
2200 /// / PLUSPERCENTEQUAL
2201 /// / MINUSPERCENTEQUAL
2202 /// / EQUAL
2203 fn parseAssignOp(p: *Parser) !?*Node {
2204 const token = p.nextToken();
2205 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2206 .AsteriskEqual => .AssignMul,
2207 .SlashEqual => .AssignDiv,
2208 .PercentEqual => .AssignMod,
2209 .PlusEqual => .AssignAdd,
2210 .MinusEqual => .AssignSub,
2211 .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft,
2212 .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight,
2213 .AmpersandEqual => .AssignBitAnd,
2214 .CaretEqual => .AssignBitXor,
2215 .PipeEqual => .AssignBitOr,
2216 .AsteriskPercentEqual => .AssignMulWrap,
2217 .PlusPercentEqual => .AssignAddWrap,
2218 .MinusPercentEqual => .AssignSubWrap,
2219 .Equal => .Assign,
2220 else => {
2221 p.putBackToken(token.index);
2222 return null;
2223 },
2224 };
23662225
2367// TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on2226 const node = try p.arena.allocator.create(Node.InfixOp);
2368// pointers. Consider updating this rule:
2369// ...
2370// / ArrayTypeStart
2371// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2372// / PtrTypeStart ...
2373
2374/// PrefixTypeOp
2375/// <- QUESTIONMARK
2376/// / KEYWORD_anyframe MINUSRARROW
2377/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2378/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2379fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2380 if (eatToken(it, .QuestionMark)) |token| {
2381 const node = try arena.create(Node.PrefixOp);
2382 node.* = .{2227 node.* = .{
2383 .op_token = token,2228 .op_token = token.index,
2384 .op = .OptionalType,2229 .lhs = undefined, // set by caller
2230 .op = op,
2385 .rhs = undefined, // set by caller2231 .rhs = undefined, // set by caller
2386 };2232 };
2387 return &node.base;2233 return &node.base;
2388 }2234 }
23892235
2390 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or2236 /// CompareOp
2391 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).2237 /// <- EQUALEQUAL
2392 // Consider making the AnyFrameType a member of PrefixOp and add a2238 /// / EXCLAMATIONMARKEQUAL
2393 // PrefixOp.AnyFrameType variant?2239 /// / LARROW
2394 if (eatToken(it, .Keyword_anyframe)) |token| {2240 /// / RARROW
2395 const arrow = eatToken(it, .Arrow) orelse {2241 /// / LARROWEQUAL
2396 putBackToken(it, token);2242 /// / RARROWEQUAL
2397 return null;2243 fn parseCompareOp(p: *Parser) !?*Node {
2244 const token = p.nextToken();
2245 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2246 .EqualEqual => .EqualEqual,
2247 .BangEqual => .BangEqual,
2248 .AngleBracketLeft => .LessThan,
2249 .AngleBracketRight => .GreaterThan,
2250 .AngleBracketLeftEqual => .LessOrEqual,
2251 .AngleBracketRightEqual => .GreaterOrEqual,
2252 else => {
2253 p.putBackToken(token.index);
2254 return null;
2255 },
2398 };2256 };
2399 const node = try arena.create(Node.AnyFrameType);2257
2400 node.* = .{2258 return p.createInfixOp(token.index, op);
2401 .anyframe_token = token,2259 }
2402 .result = .{2260
2403 .arrow_token = arrow,2261 /// BitwiseOp
2404 .return_type = undefined, // set by caller2262 /// <- AMPERSAND
2263 /// / CARET
2264 /// / PIPE
2265 /// / KEYWORD_orelse
2266 /// / KEYWORD_catch Payload?
2267 fn parseBitwiseOp(p: *Parser) !?*Node {
2268 const token = p.nextToken();
2269 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2270 .Ampersand => .BitAnd,
2271 .Caret => .BitXor,
2272 .Pipe => .BitOr,
2273 .Keyword_orelse => .UnwrapOptional,
2274 .Keyword_catch => .{ .Catch = try p.parsePayload() },
2275 else => {
2276 p.putBackToken(token.index);
2277 return null;
2278 },
2279 };
2280
2281 return p.createInfixOp(token.index, op);
2282 }
2283
2284 /// BitShiftOp
2285 /// <- LARROW2
2286 /// / RARROW2
2287 fn parseBitShiftOp(p: *Parser) !?*Node {
2288 const token = p.nextToken();
2289 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2290 .AngleBracketAngleBracketLeft => .BitShiftLeft,
2291 .AngleBracketAngleBracketRight => .BitShiftRight,
2292 else => {
2293 p.putBackToken(token.index);
2294 return null;
2295 },
2296 };
2297
2298 return p.createInfixOp(token.index, op);
2299 }
2300
2301 /// AdditionOp
2302 /// <- PLUS
2303 /// / MINUS
2304 /// / PLUS2
2305 /// / PLUSPERCENT
2306 /// / MINUSPERCENT
2307 fn parseAdditionOp(p: *Parser) !?*Node {
2308 const token = p.nextToken();
2309 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2310 .Plus => .Add,
2311 .Minus => .Sub,
2312 .PlusPlus => .ArrayCat,
2313 .PlusPercent => .AddWrap,
2314 .MinusPercent => .SubWrap,
2315 else => {
2316 p.putBackToken(token.index);
2317 return null;
2318 },
2319 };
2320
2321 return p.createInfixOp(token.index, op);
2322 }
2323
2324 /// MultiplyOp
2325 /// <- PIPE2
2326 /// / ASTERISK
2327 /// / SLASH
2328 /// / PERCENT
2329 /// / ASTERISK2
2330 /// / ASTERISKPERCENT
2331 fn parseMultiplyOp(p: *Parser) !?*Node {
2332 const token = p.nextToken();
2333 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2334 .PipePipe => .MergeErrorSets,
2335 .Asterisk => .Mul,
2336 .Slash => .Div,
2337 .Percent => .Mod,
2338 .AsteriskAsterisk => .ArrayMult,
2339 .AsteriskPercent => .MulWrap,
2340 else => {
2341 p.putBackToken(token.index);
2342 return null;
2343 },
2344 };
2345
2346 return p.createInfixOp(token.index, op);
2347 }
2348
2349 /// PrefixOp
2350 /// <- EXCLAMATIONMARK
2351 /// / MINUS
2352 /// / TILDE
2353 /// / MINUSPERCENT
2354 /// / AMPERSAND
2355 /// / KEYWORD_try
2356 /// / KEYWORD_await
2357 fn parsePrefixOp(p: *Parser) !?*Node {
2358 const token = p.nextToken();
2359 const op: Node.PrefixOp.Op = switch (token.ptr.id) {
2360 .Bang => .BoolNot,
2361 .Minus => .Negation,
2362 .Tilde => .BitNot,
2363 .MinusPercent => .NegationWrap,
2364 .Ampersand => .AddressOf,
2365 .Keyword_try => .Try,
2366 .Keyword_await => .Await,
2367 else => {
2368 p.putBackToken(token.index);
2369 return null;
2405 },2370 },
2406 };2371 };
2372
2373 const node = try p.arena.allocator.create(Node.PrefixOp);
2374 node.* = .{
2375 .op_token = token.index,
2376 .op = op,
2377 .rhs = undefined, // set by caller
2378 };
2407 return &node.base;2379 return &node.base;
2408 }2380 }
24092381
2410 if (try parsePtrTypeStart(arena, it, tree)) |node| {2382 // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
2411 // If the token encountered was **, there will be two nodes instead of one.2383 // pointers. Consider updating this rule:
2412 // The attributes should be applied to the rightmost operator.2384 // ...
2413 const prefix_op = node.cast(Node.PrefixOp).?;2385 // / ArrayTypeStart
2414 var ptr_info = if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk)2386 // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2415 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType2387 // / PtrTypeStart ...
2416 else2388
2417 &prefix_op.op.PtrType;2389 /// PrefixTypeOp
2390 /// <- QUESTIONMARK
2391 /// / KEYWORD_anyframe MINUSRARROW
2392 /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2393 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2394 fn parsePrefixTypeOp(p: *Parser) !?*Node {
2395 if (p.eatToken(.QuestionMark)) |token| {
2396 const node = try p.arena.allocator.create(Node.PrefixOp);
2397 node.* = .{
2398 .op_token = token,
2399 .op = .OptionalType,
2400 .rhs = undefined, // set by caller
2401 };
2402 return &node.base;
2403 }
24182404
2419 while (true) {2405 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2420 if (eatToken(it, .Keyword_align)) |align_token| {2406 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2421 const lparen = try expectToken(it, tree, .LParen);2407 // Consider making the AnyFrameType a member of PrefixOp and add a
2422 const expr_node = try expectNode(arena, it, tree, parseExpr, .{2408 // PrefixOp.AnyFrameType variant?
2423 .ExpectedExpr = .{ .token = it.index },2409 if (p.eatToken(.Keyword_anyframe)) |token| {
2424 });2410 const arrow = p.eatToken(.Arrow) orelse {
2411 p.putBackToken(token);
2412 return null;
2413 };
2414 const node = try p.arena.allocator.create(Node.AnyFrameType);
2415 node.* = .{
2416 .anyframe_token = token,
2417 .result = .{
2418 .arrow_token = arrow,
2419 .return_type = undefined, // set by caller
2420 },
2421 };
2422 return &node.base;
2423 }
24252424
2426 // Optional bit range2425 if (try p.parsePtrTypeStart()) |node| {
2427 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {2426 // If the token encountered was **, there will be two nodes instead of one.
2428 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{2427 // The attributes should be applied to the rightmost operator.
2429 .ExpectedIntegerLiteral = .{ .token = it.index },2428 const prefix_op = node.cast(Node.PrefixOp).?;
2430 });2429 var ptr_info = if (p.tokens[prefix_op.op_token].id == .AsteriskAsterisk)
2431 _ = try expectToken(it, tree, .Colon);2430 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2432 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{2431 else
2433 .ExpectedIntegerLiteral = .{ .token = it.index },2432 &prefix_op.op.PtrType;
2433
2434 while (true) {
2435 if (p.eatToken(.Keyword_align)) |align_token| {
2436 const lparen = try p.expectToken(.LParen);
2437 const expr_node = try p.expectNode(parseExpr, .{
2438 .ExpectedExpr = .{ .token = p.tok_i },
2434 });2439 });
24352440
2436 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{2441 // Optional bit range
2437 .start = range_start,2442 const bit_range = if (p.eatToken(.Colon)) |_| bit_range_value: {
2438 .end = range_end,2443 const range_start = try p.expectNode(parseIntegerLiteral, .{
2444 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
2445 });
2446 _ = try p.expectToken(.Colon);
2447 const range_end = try p.expectNode(parseIntegerLiteral, .{
2448 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
2449 });
2450
2451 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
2452 .start = range_start,
2453 .end = range_end,
2454 };
2455 } else null;
2456 _ = try p.expectToken(.RParen);
2457
2458 if (ptr_info.align_info != null) {
2459 try p.errors.append(p.gpa, .{
2460 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2461 });
2462 continue;
2463 }
2464
2465 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
2466 .node = expr_node,
2467 .bit_range = bit_range,
2439 };2468 };
2440 } else null;
2441 _ = try expectToken(it, tree, .RParen);
24422469
2443 if (ptr_info.align_info != null) {
2444 try tree.errors.push(.{
2445 .ExtraAlignQualifier = .{ .token = it.index - 1 },
2446 });
2447 continue;2470 continue;
2448 }2471 }
24492472 if (p.eatToken(.Keyword_const)) |const_token| {
2450 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{2473 if (ptr_info.const_token != null) {
2451 .node = expr_node,2474 try p.errors.append(p.gpa, .{
2452 .bit_range = bit_range,2475 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2453 };2476 });
24542477 continue;
2455 continue;2478 }
2456 }2479 ptr_info.const_token = const_token;
2457 if (eatToken(it, .Keyword_const)) |const_token| {
2458 if (ptr_info.const_token != null) {
2459 try tree.errors.push(.{
2460 .ExtraConstQualifier = .{ .token = it.index - 1 },
2461 });
2462 continue;2480 continue;
2463 }2481 }
2464 ptr_info.const_token = const_token;2482 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2465 continue;2483 if (ptr_info.volatile_token != null) {
2466 }2484 try p.errors.append(p.gpa, .{
2467 if (eatToken(it, .Keyword_volatile)) |volatile_token| {2485 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2468 if (ptr_info.volatile_token != null) {2486 });
2469 try tree.errors.push(.{2487 continue;
2470 .ExtraVolatileQualifier = .{ .token = it.index - 1 },2488 }
2471 });2489 ptr_info.volatile_token = volatile_token;
2472 continue;2490 continue;
2473 }2491 }
2474 ptr_info.volatile_token = volatile_token;2492 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2475 continue;2493 if (ptr_info.allowzero_token != null) {
2476 }2494 try p.errors.append(p.gpa, .{
2477 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {2495 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2478 if (ptr_info.allowzero_token != null) {2496 });
2479 try tree.errors.push(.{2497 continue;
2480 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },2498 }
2481 });2499 ptr_info.allowzero_token = allowzero_token;
2482 continue;2500 continue;
2483 }2501 }
2484 ptr_info.allowzero_token = allowzero_token;2502 break;
2485 continue;
2486 }2503 }
2487 break;
2488 }
24892504
2490 return node;2505 return node;
2491 }2506 }
24922507
2493 if (try parseArrayTypeStart(arena, it, tree)) |node| {2508 if (try p.parseArrayTypeStart()) |node| {
2494 switch (node.cast(Node.PrefixOp).?.op) {2509 switch (node.cast(Node.PrefixOp).?.op) {
2495 .ArrayType => {},2510 .ArrayType => {},
2496 .SliceType => |*slice_type| {2511 .SliceType => |*slice_type| {
2497 // Collect pointer qualifiers in any order, but disallow duplicates2512 // Collect pointer qualifiers in any order, but disallow duplicates
2498 while (true) {2513 while (true) {
2499 if (try parseByteAlign(arena, it, tree)) |align_expr| {2514 if (try p.parseByteAlign()) |align_expr| {
2500 if (slice_type.align_info != null) {2515 if (slice_type.align_info != null) {
2501 try tree.errors.push(.{2516 try p.errors.append(p.gpa, .{
2502 .ExtraAlignQualifier = .{ .token = it.index - 1 },2517 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2503 });2518 });
2519 continue;
2520 }
2521 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2522 .node = align_expr,
2523 .bit_range = null,
2524 };
2504 continue;2525 continue;
2505 }2526 }
2506 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{2527 if (p.eatToken(.Keyword_const)) |const_token| {
2507 .node = align_expr,2528 if (slice_type.const_token != null) {
2508 .bit_range = null,2529 try p.errors.append(p.gpa, .{
2509 };2530 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2510 continue;2531 });
2511 }2532 continue;
2512 if (eatToken(it, .Keyword_const)) |const_token| {2533 }
2513 if (slice_type.const_token != null) {2534 slice_type.const_token = const_token;
2514 try tree.errors.push(.{
2515 .ExtraConstQualifier = .{ .token = it.index - 1 },
2516 });
2517 continue;2535 continue;
2518 }2536 }
2519 slice_type.const_token = const_token;2537 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2520 continue;2538 if (slice_type.volatile_token != null) {
2521 }2539 try p.errors.append(p.gpa, .{
2522 if (eatToken(it, .Keyword_volatile)) |volatile_token| {2540 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2523 if (slice_type.volatile_token != null) {2541 });
2524 try tree.errors.push(.{2542 continue;
2525 .ExtraVolatileQualifier = .{ .token = it.index - 1 },2543 }
2526 });2544 slice_type.volatile_token = volatile_token;
2527 continue;2545 continue;
2528 }2546 }
2529 slice_type.volatile_token = volatile_token;2547 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2530 continue;2548 if (slice_type.allowzero_token != null) {
2549 try p.errors.append(p.gpa, .{
2550 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2551 });
2552 continue;
2553 }
2554 slice_type.allowzero_token = allowzero_token;
2555 continue;
2556 }
2557 break;
2531 }2558 }
2532 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {2559 },
2533 if (slice_type.allowzero_token != null) {2560 else => unreachable,
2534 try tree.errors.push(.{2561 }
2535 .ExtraAllowZeroQualifier = .{ .token = it.index - 1 },2562 return node;
2563 }
2564
2565 return null;
2566 }
2567
2568 /// SuffixOp
2569 /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
2570 /// / DOT IDENTIFIER
2571 /// / DOTASTERISK
2572 /// / DOTQUESTIONMARK
2573 fn parseSuffixOp(p: *Parser) !?*Node {
2574 const OpAndToken = struct {
2575 op: Node.SuffixOp.Op,
2576 token: TokenIndex,
2577 };
2578 const op_and_token: OpAndToken = blk: {
2579 if (p.eatToken(.LBracket)) |_| {
2580 const index_expr = try p.expectNode(parseExpr, .{
2581 .ExpectedExpr = .{ .token = p.tok_i },
2582 });
2583
2584 if (p.eatToken(.Ellipsis2) != null) {
2585 const end_expr = try p.parseExpr();
2586 const sentinel: ?*ast.Node = if (p.eatToken(.Colon) != null)
2587 try p.parseExpr()
2588 else
2589 null;
2590 break :blk .{
2591 .op = .{
2592 .Slice = .{
2593 .start = index_expr,
2594 .end = end_expr,
2595 .sentinel = sentinel,
2596 },
2597 },
2598 .token = try p.expectToken(.RBracket),
2599 };
2600 }
2601
2602 break :blk .{
2603 .op = .{ .ArrayAccess = index_expr },
2604 .token = try p.expectToken(.RBracket),
2605 };
2606 }
2607
2608 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
2609 break :blk .{ .op = .Deref, .token = period_asterisk };
2610 }
2611
2612 if (p.eatToken(.Period)) |period| {
2613 if (try p.parseIdentifier()) |identifier| {
2614 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2615 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should
2616 // this grammar rule be altered?
2617 const node = try p.arena.allocator.create(Node.InfixOp);
2618 node.* = .{
2619 .op_token = period,
2620 .lhs = undefined, // set by caller
2621 .op = .Period,
2622 .rhs = identifier,
2623 };
2624 return &node.base;
2625 }
2626 if (p.eatToken(.QuestionMark)) |question_mark| {
2627 break :blk .{ .op = .UnwrapOptional, .token = question_mark };
2628 }
2629 try p.errors.append(p.gpa, .{
2630 .ExpectedSuffixOp = .{ .token = p.tok_i },
2631 });
2632 return null;
2633 }
2634
2635 return null;
2636 };
2637
2638 const node = try p.arena.allocator.create(Node.SuffixOp);
2639 node.* = .{
2640 .lhs = undefined, // set by caller
2641 .op = op_and_token.op,
2642 .rtoken = op_and_token.token,
2643 };
2644 return &node.base;
2645 }
2646
2647 /// FnCallArguments <- LPAREN ExprList RPAREN
2648 /// ExprList <- (Expr COMMA)* Expr?
2649 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
2650 if (p.eatToken(.LParen) == null) return null;
2651 const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(p);
2652 const rparen = try p.expectToken(.RParen);
2653 return AnnotatedParamList{ .list = list, .rparen = rparen };
2654 }
2655
2656 const AnnotatedParamList = struct {
2657 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)
2658 rparen: TokenIndex,
2659 };
2660
2661 /// ArrayTypeStart <- LBRACKET Expr? RBRACKET
2662 fn parseArrayTypeStart(p: *Parser) !?*Node {
2663 const lbracket = p.eatToken(.LBracket) orelse return null;
2664 const expr = try p.parseExpr();
2665 const sentinel = if (p.eatToken(.Colon)) |_|
2666 try p.expectNode(parseExpr, .{
2667 .ExpectedExpr = .{ .token = p.tok_i },
2668 })
2669 else
2670 null;
2671 const rbracket = try p.expectToken(.RBracket);
2672
2673 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2674 .{
2675 .ArrayType = .{
2676 .len_expr = len_expr,
2677 .sentinel = sentinel,
2678 },
2679 }
2680 else
2681 .{
2682 .SliceType = Node.PrefixOp.PtrInfo{
2683 .allowzero_token = null,
2684 .align_info = null,
2685 .const_token = null,
2686 .volatile_token = null,
2687 .sentinel = sentinel,
2688 },
2689 };
2690
2691 const node = try p.arena.allocator.create(Node.PrefixOp);
2692 node.* = .{
2693 .op_token = lbracket,
2694 .op = op,
2695 .rhs = undefined, // set by caller
2696 };
2697 return &node.base;
2698 }
2699
2700 /// PtrTypeStart
2701 /// <- ASTERISK
2702 /// / ASTERISK2
2703 /// / PTRUNKNOWN
2704 /// / PTRC
2705 fn parsePtrTypeStart(p: *Parser) !?*Node {
2706 if (p.eatToken(.Asterisk)) |asterisk| {
2707 const sentinel = if (p.eatToken(.Colon)) |_|
2708 try p.expectNode(parseExpr, .{
2709 .ExpectedExpr = .{ .token = p.tok_i },
2710 })
2711 else
2712 null;
2713 const node = try p.arena.allocator.create(Node.PrefixOp);
2714 node.* = .{
2715 .op_token = asterisk,
2716 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2717 .rhs = undefined, // set by caller
2718 };
2719 return &node.base;
2720 }
2721
2722 if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
2723 const node = try p.arena.allocator.create(Node.PrefixOp);
2724 node.* = .{
2725 .op_token = double_asterisk,
2726 .op = .{ .PtrType = .{} },
2727 .rhs = undefined, // set by caller
2728 };
2729
2730 // Special case for **, which is its own token
2731 const child = try p.arena.allocator.create(Node.PrefixOp);
2732 child.* = .{
2733 .op_token = double_asterisk,
2734 .op = .{ .PtrType = .{} },
2735 .rhs = undefined, // set by caller
2736 };
2737 node.rhs = &child.base;
2738
2739 return &node.base;
2740 }
2741 if (p.eatToken(.LBracket)) |lbracket| {
2742 const asterisk = p.eatToken(.Asterisk) orelse {
2743 p.putBackToken(lbracket);
2744 return null;
2745 };
2746 if (p.eatToken(.Identifier)) |ident| {
2747 const token_slice = p.source[p.tokens[ident].start..p.tokens[ident].end];
2748 if (!std.mem.eql(u8, token_slice, "c")) {
2749 p.putBackToken(ident);
2750 } else {
2751 _ = try p.expectToken(.RBracket);
2752 const node = try p.arena.allocator.create(Node.PrefixOp);
2753 node.* = .{
2754 .op_token = lbracket,
2755 .op = .{ .PtrType = .{} },
2756 .rhs = undefined, // set by caller
2757 };
2758 return &node.base;
2759 }
2760 }
2761 const sentinel = if (p.eatToken(.Colon)) |_|
2762 try p.expectNode(parseExpr, .{
2763 .ExpectedExpr = .{ .token = p.tok_i },
2764 })
2765 else
2766 null;
2767 _ = try p.expectToken(.RBracket);
2768 const node = try p.arena.allocator.create(Node.PrefixOp);
2769 node.* = .{
2770 .op_token = lbracket,
2771 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2772 .rhs = undefined, // set by caller
2773 };
2774 return &node.base;
2775 }
2776 return null;
2777 }
2778
2779 /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
2780 fn parseContainerDeclAuto(p: *Parser) !?*Node {
2781 const node = (try p.parseContainerDeclType()) orelse return null;
2782 const lbrace = try p.expectToken(.LBrace);
2783 const members = try p.parseContainerMembers(false);
2784 const rbrace = try p.expectToken(.RBrace);
2785
2786 const decl_type = node.cast(Node.ContainerDecl).?;
2787 decl_type.fields_and_decls = members;
2788 decl_type.lbrace_token = lbrace;
2789 decl_type.rbrace_token = rbrace;
2790
2791 return node;
2792 }
2793
2794 /// ContainerDeclType
2795 /// <- KEYWORD_struct
2796 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
2797 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2798 fn parseContainerDeclType(p: *Parser) !?*Node {
2799 const kind_token = p.nextToken();
2800
2801 const init_arg_expr = switch (kind_token.ptr.id) {
2802 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
2803 .Keyword_enum => blk: {
2804 if (p.eatToken(.LParen) != null) {
2805 const expr = try p.expectNode(parseExpr, .{
2806 .ExpectedExpr = .{ .token = p.tok_i },
2807 });
2808 _ = try p.expectToken(.RParen);
2809 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2810 }
2811 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2812 },
2813 .Keyword_union => blk: {
2814 if (p.eatToken(.LParen) != null) {
2815 if (p.eatToken(.Keyword_enum) != null) {
2816 if (p.eatToken(.LParen) != null) {
2817 const expr = try p.expectNode(parseExpr, .{
2818 .ExpectedExpr = .{ .token = p.tok_i },
2536 });2819 });
2537 continue;2820 _ = try p.expectToken(.RParen);
2821 _ = try p.expectToken(.RParen);
2822 break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
2538 }2823 }
2539 slice_type.allowzero_token = allowzero_token;2824 _ = try p.expectToken(.RParen);
2540 continue;2825 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
2826 }
2827 const expr = try p.expectNode(parseExpr, .{
2828 .ExpectedExpr = .{ .token = p.tok_i },
2829 });
2830 _ = try p.expectToken(.RParen);
2831 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2832 }
2833 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2834 },
2835 else => {
2836 p.putBackToken(kind_token.index);
2837 return null;
2838 },
2839 };
2840
2841 const node = try p.arena.allocator.create(Node.ContainerDecl);
2842 node.* = .{
2843 .layout_token = null,
2844 .kind_token = kind_token.index,
2845 .init_arg_expr = init_arg_expr,
2846 .fields_and_decls = undefined, // set by caller
2847 .lbrace_token = undefined, // set by caller
2848 .rbrace_token = undefined, // set by caller
2849 };
2850 return &node.base;
2851 }
2852
2853 /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
2854 fn parseByteAlign(p: *Parser) !?*Node {
2855 _ = p.eatToken(.Keyword_align) orelse return null;
2856 _ = try p.expectToken(.LParen);
2857 const expr = try p.expectNode(parseExpr, .{
2858 .ExpectedExpr = .{ .token = p.tok_i },
2859 });
2860 _ = try p.expectToken(.RParen);
2861 return expr;
2862 }
2863
2864 /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
2865 /// Only ErrorSetDecl parses an IdentifierList
2866 fn parseErrorTagList(p: *Parser) !Node.ErrorSetDecl.DeclList {
2867 return ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(p);
2868 }
2869
2870 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2871 fn parseSwitchProngList(p: *Parser) !Node.Switch.CaseList {
2872 return ListParseFn(Node.Switch.CaseList, parseSwitchProng)(p);
2873 }
2874
2875 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2876 fn parseAsmOutputList(p: *Parser) Error!Node.Asm.OutputList {
2877 return ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(p);
2878 }
2879
2880 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2881 fn parseAsmInputList(p: *Parser) Error!Node.Asm.InputList {
2882 return ListParseFn(Node.Asm.InputList, parseAsmInputItem)(p);
2883 }
2884
2885 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2886 fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) !Node.FnProto.ParamList {
2887 var list = Node.FnProto.ParamList{};
2888 var list_it = &list.first;
2889 var last: ?*Node = null;
2890 while (try p.parseParamDecl()) |node| {
2891 last = node;
2892 list_it = try p.llpush(*Node, list_it, node);
2893
2894 switch (p.tokens[p.tok_i].id) {
2895 .Comma => _ = p.nextToken(),
2896 // all possible delimiters
2897 .Colon, .RParen, .RBrace, .RBracket => break,
2898 else => {
2899 // this is likely just a missing comma,
2900 // continue parsing this list and give an error
2901 try p.errors.append(p.gpa, .{
2902 .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
2903 });
2904 },
2905 }
2906 }
2907 if (last) |node| {
2908 const param_type = node.cast(Node.ParamDecl).?.param_type;
2909 if (param_type == .var_args) {
2910 var_args_token.* = param_type.var_args;
2911 }
2912 }
2913 return list;
2914 }
2915
2916 const NodeParseFn = fn (p: *Parser) Error!?*Node;
2917
2918 fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
2919 return struct {
2920 pub fn parse(p: *Parser) !L {
2921 var list = L{};
2922 var list_it = &list.first;
2923 while (try nodeParseFn(p)) |node| {
2924 list_it = try p.llpush(L.Node.Data, list_it, node);
2925
2926 switch (p.tokens[p.tok_i].id) {
2927 .Comma => _ = p.nextToken(),
2928 // all possible delimiters
2929 .Colon, .RParen, .RBrace, .RBracket => break,
2930 else => {
2931 // this is likely just a missing comma,
2932 // continue parsing this list and give an error
2933 try p.errors.append(p.gpa, .{
2934 .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
2935 });
2936 },
2541 }2937 }
2542 break;
2543 }2938 }
2544 },2939 return list;
2545 else => unreachable,2940 }
2546 }2941 }.parse;
2547 return node;
2548 }2942 }
25492943
2550 return null;2944 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
2551}2945 return struct {
25522946 pub fn parse(p: *Parser) Error!?*Node {
2553/// SuffixOp2947 const op_token = if (token == .Keyword_and) switch (p.tokens[p.tok_i].id) {
2554/// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET2948 .Keyword_and => p.nextToken().index,
2555/// / DOT IDENTIFIER2949 .Invalid_ampersands => blk: {
2556/// / DOTASTERISK2950 try p.errors.append(p.gpa, .{
2557/// / DOTQUESTIONMARK2951 .InvalidAnd = .{ .token = p.tok_i },
2558fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2952 });
2559 const OpAndToken = struct {2953 break :blk p.nextToken().index;
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 });
2568
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,
2581 },
2582 },2954 },
2583 .token = try expectToken(it, tree, .RBracket),2955 else => return null,
2584 };2956 } else p.eatToken(token) orelse return null;
2585 }
2586
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 }
25962957
2597 if (eatToken(it, .Period)) |period| {2958 const node = try p.arena.allocator.create(Node.InfixOp);
2598 if (try parseIdentifier(arena, it, tree)) |identifier| {
2599 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2600 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should
2601 // this grammar rule be altered?
2602 const node = try arena.create(Node.InfixOp);
2603 node.* = .{2959 node.* = .{
2604 .op_token = period,2960 .op_token = op_token,
2605 .lhs = undefined, // set by caller2961 .lhs = undefined, // set by caller
2606 .op = .Period,2962 .op = op,
2607 .rhs = identifier,2963 .rhs = undefined, // set by caller
2608 };2964 };
2609 return &node.base;2965 return &node.base;
2610 }2966 }
2611 if (eatToken(it, .QuestionMark)) |question_mark| {2967 }.parse;
2612 break :blk .{ .op = .UnwrapOptional, .token = question_mark };2968 }
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}
26312969
2632/// FnCallArguments <- LPAREN ExprList RPAREN2970 // Helper parsers not included in the grammar
2633/// ExprList <- (Expr COMMA)* Expr?
2634fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {
2635 if (eatToken(it, .LParen) == null) return null;
2636 const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(arena, it, tree);
2637 const rparen = try expectToken(it, tree, .RParen);
2638 return AnnotatedParamList{ .list = list, .rparen = rparen };
2639}
26402971
2641const AnnotatedParamList = struct {2972 fn parseBuiltinCall(p: *Parser) !?*Node {
2642 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)2973 const token = p.eatToken(.Builtin) orelse return null;
2643 rparen: TokenIndex,2974 const params = (try p.parseFnCallArguments()) orelse {
2644};2975 try p.errors.append(p.gpa, .{
2976 .ExpectedParamList = .{ .token = p.tok_i },
2977 });
26452978
2646/// ArrayTypeStart <- LBRACKET Expr? RBRACKET2979 // lets pretend this was an identifier so we can continue parsing
2647fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2980 const node = try p.arena.allocator.create(Node.Identifier);
2648 const lbracket = eatToken(it, .LBracket) orelse return null;2981 node.* = .{
2649 const expr = try parseExpr(arena, it, tree);2982 .token = token,
2650 const sentinel = if (eatToken(it, .Colon)) |_|2983 };
2651 try expectNode(arena, it, tree, parseExpr, .{2984 return &node.base;
2652 .ExpectedExpr = .{ .token = it.index },
2653 })
2654 else
2655 null;
2656 const rbracket = try expectToken(it, tree, .RBracket);
2657
2658 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2659 .{
2660 .ArrayType = .{
2661 .len_expr = len_expr,
2662 .sentinel = sentinel,
2663 },
2664 }
2665 else
2666 .{
2667 .SliceType = Node.PrefixOp.PtrInfo{
2668 .allowzero_token = null,
2669 .align_info = null,
2670 .const_token = null,
2671 .volatile_token = null,
2672 .sentinel = sentinel,
2673 },
2674 };2985 };
26752986 const node = try p.arena.allocator.create(Node.BuiltinCall);
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);
2699 node.* = .{2987 node.* = .{
2700 .op_token = asterisk,2988 .builtin_token = token,
2701 .op = .{ .PtrType = .{ .sentinel = sentinel } },2989 .params = params.list,
2702 .rhs = undefined, // set by caller2990 .rparen_token = params.rparen,
2703 };2991 };
2704 return &node.base;2992 return &node.base;
2705 }2993 }
27062994
2707 if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| {2995 fn parseErrorTag(p: *Parser) !?*Node {
2708 const node = try arena.create(Node.PrefixOp);2996 const doc_comments = try p.parseDocComment(); // no need to rewind on failure
2997 const token = p.eatToken(.Identifier) orelse return null;
2998
2999 const node = try p.arena.allocator.create(Node.ErrorTag);
2709 node.* = .{3000 node.* = .{
2710 .op_token = double_asterisk,3001 .doc_comments = doc_comments,
2711 .op = .{ .PtrType = .{} },3002 .name_token = token,
2712 .rhs = undefined, // set by caller
2713 };3003 };
3004 return &node.base;
3005 }
27143006
2715 // Special case for **, which is its own token3007 fn parseIdentifier(p: *Parser) !?*Node {
2716 const child = try arena.create(Node.PrefixOp);3008 const token = p.eatToken(.Identifier) orelse return null;
2717 child.* = .{3009 const node = try p.arena.allocator.create(Node.Identifier);
2718 .op_token = double_asterisk,3010 node.* = .{
2719 .op = .{ .PtrType = .{} },3011 .token = token,
2720 .rhs = undefined, // set by caller
2721 };3012 };
2722 node.rhs = &child.base;
2723
2724 return &node.base;3013 return &node.base;
2725 }3014 }
2726 if (eatToken(it, .LBracket)) |lbracket| {3015
2727 const asterisk = eatToken(it, .Asterisk) orelse {3016 fn parseVarType(p: *Parser) !?*Node {
2728 putBackToken(it, lbracket);3017 const token = p.eatToken(.Keyword_var) orelse return null;
2729 return null;3018 const node = try p.arena.allocator.create(Node.VarType);
2730 };
2731 if (eatToken(it, .Identifier)) |ident| {
2732 if (!std.mem.eql(u8, tree.tokenSlice(ident), "c")) {
2733 putBackToken(it, ident);
2734 } else {
2735 _ = try expectToken(it, tree, .RBracket);
2736 const node = try arena.create(Node.PrefixOp);
2737 node.* = .{
2738 .op_token = lbracket,
2739 .op = .{ .PtrType = .{} },
2740 .rhs = undefined, // set by caller
2741 };
2742 return &node.base;
2743 }
2744 }
2745 const sentinel = if (eatToken(it, .Colon)) |_|
2746 try expectNode(arena, it, tree, parseExpr, .{
2747 .ExpectedExpr = .{ .token = it.index },
2748 })
2749 else
2750 null;
2751 _ = try expectToken(it, tree, .RBracket);
2752 const node = try arena.create(Node.PrefixOp);
2753 node.* = .{3019 node.* = .{
2754 .op_token = lbracket,3020 .token = token,
2755 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2756 .rhs = undefined, // set by caller
2757 };3021 };
2758 return &node.base;3022 return &node.base;
2759 }3023 }
2760 return null;
2761}
2762
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);
2769
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;
2774
2775 return node;
2776}
2777
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 };
2810 }
2811 const expr = try expectNode(arena, it, tree, parseExpr, .{
2812 .ExpectedExpr = .{ .token = it.index },
2813 });
2814 _ = try expectToken(it, tree, .RParen);
2815 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2816 }
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}
28473024
2848/// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?3025 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
2849/// Only ErrorSetDecl parses an IdentifierList3026 const result = try p.arena.allocator.create(T);
2850fn parseErrorTagList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.ErrorSetDecl.DeclList {3027 result.* = T{
2851 return try ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(arena, it, tree);3028 .base = Node{ .id = Node.typeToId(T) },
2852}3029 .token = token,
28533030 };
2854/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?3031 return &result.base;
2855fn parseSwitchProngList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Switch.CaseList {3032 }
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}
28773033
2878const NodeParseFn = fn (*Allocator, *TokenIterator, *Tree) Error!?*Node;3034 fn parseStringLiteralSingle(p: *Parser) !?*Node {
28793035 if (p.eatToken(.StringLiteral)) |token| {
2880fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {3036 const node = try p.arena.allocator.create(Node.StringLiteral);
2881 return struct {3037 node.* = .{
2882 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !L {3038 .token = token,
2883 var list = L.init(arena);3039 };
2884 while (try nodeParseFn(arena, it, tree)) |node| {3040 return &node.base;
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 });
2897 },
2898 }
2899 }
2900 return list;
2901 }3041 }
2902 }.parse;3042 return null;
2903}3043 }
29043044
2905fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {3045 // string literal or multiline string literal
2906 return struct {3046 fn parseStringLiteral(p: *Parser) !?*Node {
2907 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {3047 if (try p.parseStringLiteralSingle()) |node| return 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;
29183048
2919 const node = try arena.create(Node.InfixOp);3049 if (p.eatToken(.MultilineStringLiteralLine)) |first_line| {
3050 const node = try p.arena.allocator.create(Node.MultilineStringLiteral);
2920 node.* = .{3051 node.* = .{
2921 .op_token = op_token,3052 .lines = Node.MultilineStringLiteral.LineList{},
2922 .lhs = undefined, // set by caller
2923 .op = op,
2924 .rhs = undefined, // set by caller
2925 };3053 };
3054 var lines_it = &node.lines.first;
3055 lines_it = try p.llpush(TokenIndex, lines_it, first_line);
3056 while (p.eatToken(.MultilineStringLiteralLine)) |line|
3057 lines_it = try p.llpush(TokenIndex, lines_it, line);
3058
2926 return &node.base;3059 return &node.base;
2927 }3060 }
2928 }.parse;
2929}
29303061
2931// Helper parsers not included in the grammar3062 return null;
29323063 }
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 });
29393064
2940 // lets pretend this was an identifier so we can continue parsing3065 fn parseIntegerLiteral(p: *Parser) !?*Node {
2941 const node = try arena.create(Node.Identifier);3066 const token = p.eatToken(.IntegerLiteral) orelse return null;
3067 const node = try p.arena.allocator.create(Node.IntegerLiteral);
2942 node.* = .{3068 node.* = .{
2943 .token = token,3069 .token = token,
2944 };3070 };
2945 return &node.base;3071 return &node.base;
2946 };3072 }
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}
29943073
2995fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3074 fn parseFloatLiteral(p: *Parser) !?*Node {
2996 if (eatToken(it, .StringLiteral)) |token| {3075 const token = p.eatToken(.FloatLiteral) orelse return null;
2997 const node = try arena.create(Node.StringLiteral);3076 const node = try p.arena.allocator.create(Node.FloatLiteral);
2998 node.* = .{3077 node.* = .{
2999 .token = token,3078 .token = token,
3000 };3079 };
3001 return &node.base;3080 return &node.base;
3002 }3081 }
3003 return null;
3004}
30053082
3006// string literal or multiline string literal3083 fn parseTry(p: *Parser) !?*Node {
3007fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3084 const token = p.eatToken(.Keyword_try) orelse return null;
3008 if (try parseStringLiteralSingle(arena, it, tree)) |node| return node;3085 const node = try p.arena.allocator.create(Node.PrefixOp);
3009
3010 if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {
3011 const node = try arena.create(Node.MultilineStringLiteral);
3012 node.* = .{3086 node.* = .{
3013 .lines = Node.MultilineStringLiteral.LineList.init(arena),3087 .op_token = token,
3088 .op = .Try,
3089 .rhs = undefined, // set by caller
3014 };3090 };
3015 try node.lines.push(first_line);3091 return &node.base;
3016 while (eatToken(it, .MultilineStringLiteralLine)) |line|3092 }
3017 try node.lines.push(line);
30183093
3094 fn parseUse(p: *Parser) !?*Node {
3095 const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
3096 const node = try p.arena.allocator.create(Node.Use);
3097 node.* = .{
3098 .doc_comments = null,
3099 .visib_token = null,
3100 .use_token = token,
3101 .expr = try p.expectNode(parseExpr, .{
3102 .ExpectedExpr = .{ .token = p.tok_i },
3103 }),
3104 .semicolon_token = try p.expectToken(.Semicolon),
3105 };
3019 return &node.base;3106 return &node.base;
3020 }3107 }
30213108
3022 return null;3109 /// IfPrefix Body (KEYWORD_else Payload? Body)?
3023}3110 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
3111 const node = (try p.parseIfPrefix()) orelse return null;
3112 const if_prefix = node.cast(Node.If).?;
30243113
3025fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3114 if_prefix.body = try p.expectNode(bodyParseFn, .{
3026 const token = eatToken(it, .IntegerLiteral) orelse return null;3115 .InvalidToken = .{ .token = p.tok_i },
3027 const node = try arena.create(Node.IntegerLiteral);3116 });
3028 node.* = .{
3029 .token = token,
3030 };
3031 return &node.base;
3032}
30333117
3034fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3118 const else_token = p.eatToken(.Keyword_else) orelse return node;
3035 const token = eatToken(it, .FloatLiteral) orelse return null;3119 const payload = try p.parsePayload();
3036 const node = try arena.create(Node.FloatLiteral);3120 const else_expr = try p.expectNode(bodyParseFn, .{
3037 node.* = .{3121 .InvalidToken = .{ .token = p.tok_i },
3038 .token = token,3122 });
3039 };3123 const else_node = try p.arena.allocator.create(Node.Else);
3040 return &node.base;3124 else_node.* = .{
3041}3125 .else_token = else_token,
3126 .payload = payload,
3127 .body = else_expr,
3128 };
3129 if_prefix.@"else" = else_node;
30423130
3043fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3131 return node;
3044 const token = eatToken(it, .Keyword_try) orelse return null;3132 }
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}
30533133
3054fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {3134 /// Eat a multiline doc comment
3055 const token = eatToken(it, .Keyword_usingnamespace) orelse return null;3135 fn parseDocComment(p: *Parser) !?*Node.DocComment {
3056 const node = try arena.create(Node.Use);3136 var lines = Node.DocComment.LineList{};
3057 node.* = .{3137 var lines_it = &lines.first;
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}
30683138
3069/// IfPrefix Body (KEYWORD_else Payload? Body)?3139 while (p.eatToken(.DocComment)) |line| {
3070fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: NodeParseFn) !?*Node {3140 lines_it = try p.llpush(TokenIndex, lines_it, line);
3071 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;3141 }
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;
30903142
3091 return node;3143 if (lines.first == null) return null;
3092}
30933144
3094/// Eat a multiline doc comment3145 const node = try p.arena.allocator.create(Node.DocComment);
3095fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.DocComment {3146 node.* = .{
3096 var lines = Node.DocComment.LineList.init(arena);3147 .lines = lines,
3097 while (eatToken(it, .DocComment)) |line| {3148 };
3098 try lines.push(line);3149 return node;
3099 }3150 }
31003151
3101 if (lines.len == 0) return null;3152 fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool {
3153 return std.mem.indexOfScalar(u8, p.source[p.tokens[token1].end..p.tokens[token2].start], '\n') == null;
3154 }
31023155
3103 const node = try arena.create(Node.DocComment);3156 /// Eat a single-line doc comment on the same line as another node
3104 node.* = .{3157 fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !?*Node.DocComment {
3105 .lines = lines,3158 const comment_token = p.eatToken(.DocComment) orelse return null;
3106 };3159 if (p.tokensOnSameLine(after_token, comment_token)) {
3107 return node;3160 var lines = Node.DocComment.LineList{};
3108}3161 _ = try p.llpush(TokenIndex, &lines.first, comment_token);
31093162
3110/// Eat a single-line doc comment on the same line as another node3163 const node = try p.arena.allocator.create(Node.DocComment);
3111fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, after_token: TokenIndex) !?*Node.DocComment {3164 node.* = .{ .lines = lines };
3112 const comment_token = eatToken(it, .DocComment) orelse return null;3165 return node;
3113 if (tree.tokensOnSameLine(after_token, comment_token)) {3166 }
3114 const node = try arena.create(Node.DocComment);3167 p.putBackToken(comment_token);
3115 node.* = .{3168 return null;
3116 .lines = Node.DocComment.LineList.init(arena),
3117 };
3118 try node.lines.push(comment_token);
3119 return node;
3120 }3169 }
3121 putBackToken(it, comment_token);
3122 return null;
3123}
31243170
3125/// Op* Child3171 /// Op* Child
3126fn parsePrefixOpExpr(3172 fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node {
3127 arena: *Allocator,3173 if (try opParseFn(p)) |first_op| {
3128 it: *TokenIterator,3174 var rightmost_op = first_op;
3129 tree: *Tree,3175 while (true) {
3130 opParseFn: NodeParseFn,3176 switch (rightmost_op.id) {
3131 childParseFn: NodeParseFn,3177 .PrefixOp => {
3132) Error!?*Node {3178 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3133 if (try opParseFn(arena, it, tree)) |first_op| {3179 // If the token encountered was **, there will be two nodes
3134 var rightmost_op = first_op;3180 if (p.tokens[prefix_op.op_token].id == .AsteriskAsterisk) {
3135 while (true) {3181 rightmost_op = prefix_op.rhs;
3182 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3183 }
3184 if (try opParseFn(p)) |rhs| {
3185 prefix_op.rhs = rhs;
3186 rightmost_op = rhs;
3187 } else break;
3188 },
3189 .AnyFrameType => {
3190 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3191 if (try opParseFn(p)) |rhs| {
3192 prom.result.?.return_type = rhs;
3193 rightmost_op = rhs;
3194 } else break;
3195 },
3196 else => unreachable,
3197 }
3198 }
3199
3200 // If any prefix op existed, a child node on the RHS is required
3136 switch (rightmost_op.id) {3201 switch (rightmost_op.id) {
3137 .PrefixOp => {3202 .PrefixOp => {
3138 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;3203 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3139 // If the token encountered was **, there will be two nodes3204 prefix_op.rhs = try p.expectNode(childParseFn, .{
3140 if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) {3205 .InvalidToken = .{ .token = p.tok_i },
3141 rightmost_op = prefix_op.rhs;3206 });
3142 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3143 }
3144 if (try opParseFn(arena, it, tree)) |rhs| {
3145 prefix_op.rhs = rhs;
3146 rightmost_op = rhs;
3147 } else break;
3148 },3207 },
3149 .AnyFrameType => {3208 .AnyFrameType => {
3150 const prom = rightmost_op.cast(Node.AnyFrameType).?;3209 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3151 if (try opParseFn(arena, it, tree)) |rhs| {3210 prom.result.?.return_type = try p.expectNode(childParseFn, .{
3152 prom.result.?.return_type = rhs;3211 .InvalidToken = .{ .token = p.tok_i },
3153 rightmost_op = rhs;3212 });
3154 } else break;
3155 },3213 },
3156 else => unreachable,3214 else => unreachable,
3157 }3215 }
3158 }
31593216
3160 // If any prefix op existed, a child node on the RHS is required3217 return first_op;
3161 switch (rightmost_op.id) {
3162 .PrefixOp => {
3163 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3164 prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{
3165 .InvalidToken = .{ .token = it.index },
3166 });
3167 },
3168 .AnyFrameType => {
3169 const prom = rightmost_op.cast(Node.AnyFrameType).?;
3170 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{
3171 .InvalidToken = .{ .token = it.index },
3172 });
3173 },
3174 else => unreachable,
3175 }3218 }
31763219
3177 return first_op;3220 // Otherwise, the child node is optional
3221 return childParseFn(p);
3178 }3222 }
31793223
3180 // Otherwise, the child node is optional3224 /// Child (Op Child)*
3181 return try childParseFn(arena, it, tree);3225 /// Child (Op Child)?
3182}3226 fn parseBinOpExpr(
3227 p: *Parser,
3228 opParseFn: NodeParseFn,
3229 childParseFn: NodeParseFn,
3230 chain: enum {
3231 Once,
3232 Infinitely,
3233 },
3234 ) Error!?*Node {
3235 var res = (try childParseFn(p)) orelse return null;
31833236
3184/// Child (Op Child)*3237 while (try opParseFn(p)) |node| {
3185/// Child (Op Child)?3238 const right = try p.expectNode(childParseFn, .{
3186fn parseBinOpExpr(3239 .InvalidToken = .{ .token = p.tok_i },
3187 arena: *Allocator,3240 });
3188 it: *TokenIterator,3241 const left = res;
3189 tree: *Tree,3242 res = node;
3190 opParseFn: NodeParseFn,
3191 childParseFn: NodeParseFn,
3192 chain: enum {
3193 Once,
3194 Infinitely,
3195 },
3196) Error!?*Node {
3197 var res = (try childParseFn(arena, it, tree)) orelse return null;
3198
3199 while (try opParseFn(arena, it, tree)) |node| {
3200 const right = try expectNode(arena, it, tree, childParseFn, .{
3201 .InvalidToken = .{ .token = it.index },
3202 });
3203 const left = res;
3204 res = node;
32053243
3206 const op = node.cast(Node.InfixOp).?;3244 const op = node.cast(Node.InfixOp).?;
3207 op.*.lhs = left;3245 op.*.lhs = left;
3208 op.*.rhs = right;3246 op.*.rhs = right;
32093247
3210 switch (chain) {3248 switch (chain) {
3211 .Once => break,3249 .Once => break,
3212 .Infinitely => continue,3250 .Infinitely => continue,
3251 }
3213 }3252 }
3253
3254 return res;
3214 }3255 }
32153256
3216 return res;3257 fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
3217}3258 const node = try p.arena.allocator.create(Node.InfixOp);
3259 node.* = .{
3260 .op_token = index,
3261 .lhs = undefined, // set by caller
3262 .op = op,
3263 .rhs = undefined, // set by caller
3264 };
3265 return &node.base;
3266 }
32183267
3219fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {3268 fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
3220 const node = try arena.create(Node.InfixOp);3269 return if (p.eatAnnotatedToken(id)) |token| token.index else null;
3221 node.* = .{3270 }
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}
32293271
3230fn eatToken(it: *TokenIterator, id: Token.Id) ?TokenIndex {3272 fn eatAnnotatedToken(p: *Parser, id: Token.Id) ?AnnotatedToken {
3231 return if (eatAnnotatedToken(it, id)) |token| token.index else null;3273 return if (p.tokens[p.tok_i].id == id) p.nextToken() else null;
3232}3274 }
32333275
3234fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {3276 fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex {
3235 return if (it.peek().?.id == id) nextToken(it) else null;3277 return (try p.expectTokenRecoverable(id)) orelse
3236}3278 error.ParseError;
3279 }
32373280
3238fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {3281 fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex {
3239 return (try expectTokenRecoverable(it, tree, id)) orelse3282 const token = p.nextToken();
3240 error.ParseError;3283 if (token.ptr.id != id) {
3241}3284 try p.errors.append(p.gpa, .{
3285 .ExpectedToken = .{ .token = token.index, .expected_id = id },
3286 });
3287 // go back so that we can recover properly
3288 p.putBackToken(token.index);
3289 return null;
3290 }
3291 return token.index;
3292 }
32423293
3243fn expectTokenRecoverable(it: *TokenIterator, tree: *Tree, id: Token.Id) !?TokenIndex {3294 fn nextToken(p: *Parser) AnnotatedToken {
3244 const token = nextToken(it);3295 const result = AnnotatedToken{
3245 if (token.ptr.id != id) {3296 .index = p.tok_i,
3246 try tree.errors.push(.{3297 .ptr = &p.tokens[p.tok_i],
3247 .ExpectedToken = .{ .token = token.index, .expected_id = id },3298 };
3248 });3299 if (p.tokens[p.tok_i].id == .Eof) {
3249 // go back so that we can recover properly3300 return result;
3250 putBackToken(it, token.index);3301 }
3251 return null;3302 p.tok_i += 1;
3303 assert(result.ptr.id != .LineComment);
3304
3305 while (true) {
3306 const next_tok = p.tokens[p.tok_i];
3307 if (next_tok.id != .LineComment) return result;
3308 p.tok_i += 1;
3309 }
3310 }
3311
3312 fn putBackToken(p: *Parser, putting_back: TokenIndex) void {
3313 while (p.tok_i > 0) {
3314 p.tok_i -= 1;
3315 const prev_tok = p.tokens[p.tok_i];
3316 if (prev_tok.id == .LineComment) continue;
3317 assert(putting_back == p.tok_i);
3318 return;
3319 }
3252 }3320 }
3253 return token.index;
3254}
32553321
3256fn nextToken(it: *TokenIterator) AnnotatedToken {3322 const AnnotatedToken = struct {
3257 const result = AnnotatedToken{3323 index: TokenIndex,
3258 .index = it.index,3324 ptr: *const Token,
3259 .ptr = it.next().?,
3260 };3325 };
3261 assert(result.ptr.id != .LineComment);
32623326
3263 while (true) {3327 fn expectNode(
3264 const next_tok = it.peek() orelse return result;3328 p: *Parser,
3265 if (next_tok.id != .LineComment) return result;3329 parseFn: NodeParseFn,
3266 _ = it.next();3330 /// if parsing fails
3331 err: AstError,
3332 ) Error!*Node {
3333 return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
3267 }3334 }
3268}
32693335
3270fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {3336 fn expectNodeRecoverable(
3271 while (true) {3337 p: *Parser,
3272 const prev_tok = it.prev() orelse return;3338 parseFn: NodeParseFn,
3273 if (prev_tok.id == .LineComment) continue;3339 /// if parsing fails
3274 assert(it.list.at(putting_back) == prev_tok);3340 err: AstError,
3275 return;3341 ) !?*Node {
3342 return (try parseFn(p)) orelse {
3343 try p.errors.append(p.gpa, err);
3344 return null;
3345 };
3276 }3346 }
3277}
3278
3279const AnnotatedToken = struct {
3280 index: TokenIndex,
3281 ptr: *Token,
3282};3347};
32833348
3284fn expectNode(3349fn ParseFn(comptime T: type) type {
3285 arena: *Allocator,3350 return fn (p: *Parser) Error!T;
3286 it: *TokenIterator,
3287 tree: *Tree,
3288 parseFn: NodeParseFn,
3289 err: AstError, // if parsing fails
3290) Error!*Node {
3291 return (try expectNodeRecoverable(arena, it, tree, parseFn, err)) orelse
3292 return error.ParseError;
3293}3351}
32943352
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}
33073353
3308test "std.zig.parser" {3354test "std.zig.parser" {
3309 _ = @import("parser_test.zig");3355 _ = @import("parser_test.zig");
lib/std/zig/parser_test.zig+3-6
...@@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b...@@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
3180 const tree = try std.zig.parse(allocator, source);3180 const tree = try std.zig.parse(allocator, source);
3181 defer tree.deinit();3181 defer tree.deinit();
31823182
3183 var error_it = tree.errors.iterator(0);3183 for (tree.errors) |*parse_error| {
3184 while (error_it.next()) |parse_error| {3184 const token = tree.tokens[parse_error.loc()];
3185 const token = tree.tokens.at(parse_error.loc());
3186 const loc = tree.tokenLocation(0, parse_error.loc());3185 const loc = tree.tokenLocation(0, parse_error.loc());
3187 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });3186 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
3188 try tree.renderError(parse_error, stderr);3187 try tree.renderError(parse_error, stderr);
...@@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {...@@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {
32713270
3272 std.testing.expect(tree.errors.len == expected_errors.len);3271 std.testing.expect(tree.errors.len == expected_errors.len);
3273 for (expected_errors) |expected, i| {3272 for (expected_errors) |expected, i| {
3274 const err = tree.errors.at(i);3273 std.testing.expect(expected == tree.errors[i]);
3275
3276 std.testing.expect(expected == err.*);
3277 }3274 }
3278}3275}
lib/std/zig/render.zig+62-65
...@@ -67,24 +67,21 @@ fn renderRoot(...@@ -67,24 +67,21 @@ fn renderRoot(
67 stream: var,67 stream: var,
68 tree: *ast.Tree,68 tree: *ast.Tree,
69) (@TypeOf(stream).Error || Error)!void {69) (@TypeOf(stream).Error || Error)!void {
70 var tok_it = tree.tokens.iterator(0);
71
72 // render all the line comments at the beginning of the file70 // render all the line comments at the beginning of the file
73 while (tok_it.next()) |token| {71 for (tree.tokens) |*token, i| {
74 if (token.id != .LineComment) break;72 if (token.id != .LineComment) break;
75 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")});73 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")});
76 if (tok_it.peek()) |next_token| {74 const next_token = &tree.tokens[i + 1];
77 const loc = tree.tokenLocationPtr(token.end, next_token);75 const loc = tree.tokenLocationPtr(token.end, next_token.*);
78 if (loc.line >= 2) {76 if (loc.line >= 2) {
79 try stream.writeByte('\n');77 try stream.writeByte('\n');
80 }
81 }78 }
82 }79 }
8380
84 var start_col: usize = 0;81 var start_col: usize = 0;
85 var it = tree.root_node.decls.iterator(0);82 var it = tree.root_node.decls.first orelse return;
86 while (true) {83 while (true) {
87 var decl = (it.next() orelse return).*;84 var decl = it.data;
8885
89 // This loop does the following:86 // This loop does the following:
90 //87 //
...@@ -103,7 +100,7 @@ fn renderRoot(...@@ -103,7 +100,7 @@ fn renderRoot(
103100
104 while (token_index != 0) {101 while (token_index != 0) {
105 token_index -= 1;102 token_index -= 1;
106 const token = tree.tokens.at(token_index);103 const token = tree.tokens[token_index];
107 switch (token.id) {104 switch (token.id) {
108 .LineComment => {},105 .LineComment => {},
109 .DocComment => {106 .DocComment => {
...@@ -133,17 +130,18 @@ fn renderRoot(...@@ -133,17 +130,18 @@ fn renderRoot(
133 token_index = decl.firstToken();130 token_index = decl.firstToken();
134131
135 while (!fmt_active) {132 while (!fmt_active) {
136 decl = (it.next() orelse {133 it = it.next orelse {
137 // If there's no next reformatted `decl`, just copy the134 // If there's no next reformatted `decl`, just copy the
138 // remaining input tokens and bail out.135 // remaining input tokens and bail out.
139 const start = tree.tokens.at(copy_start_token_index).start;136 const start = tree.tokens[copy_start_token_index].start;
140 try copyFixingWhitespace(stream, tree.source[start..]);137 try copyFixingWhitespace(stream, tree.source[start..]);
141 return;138 return;
142 }).*;139 };
140 decl = it.data;
143 var decl_first_token_index = decl.firstToken();141 var decl_first_token_index = decl.firstToken();
144142
145 while (token_index < decl_first_token_index) : (token_index += 1) {143 while (token_index < decl_first_token_index) : (token_index += 1) {
146 const token = tree.tokens.at(token_index);144 const token = tree.tokens[token_index];
147 switch (token.id) {145 switch (token.id) {
148 .LineComment => {},146 .LineComment => {},
149 .Eof => unreachable,147 .Eof => unreachable,
...@@ -163,7 +161,7 @@ fn renderRoot(...@@ -163,7 +161,7 @@ fn renderRoot(
163 token_index = copy_end_token_index;161 token_index = copy_end_token_index;
164 while (token_index != 0) {162 while (token_index != 0) {
165 token_index -= 1;163 token_index -= 1;
166 const token = tree.tokens.at(token_index);164 const token = tree.tokens[token_index];
167 switch (token.id) {165 switch (token.id) {
168 .LineComment => {},166 .LineComment => {},
169 .DocComment => {167 .DocComment => {
...@@ -174,15 +172,14 @@ fn renderRoot(...@@ -174,15 +172,14 @@ fn renderRoot(
174 }172 }
175 }173 }
176174
177 const start = tree.tokens.at(copy_start_token_index).start;175 const start = tree.tokens[copy_start_token_index].start;
178 const end = tree.tokens.at(copy_end_token_index).start;176 const end = tree.tokens[copy_end_token_index].start;
179 try copyFixingWhitespace(stream, tree.source[start..end]);177 try copyFixingWhitespace(stream, tree.source[start..end]);
180 }178 }
181179
182 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);180 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);
183 if (it.peek()) |next_decl| {181 it = it.next orelse return;
184 try renderExtraNewline(tree, stream, &start_col, next_decl.*);182 try renderExtraNewline(tree, stream, &start_col, it.data);
185 }
186 }183 }
187}184}
188185
...@@ -191,13 +188,13 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as...@@ -191,13 +188,13 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as
191 var prev_token = first_token;188 var prev_token = first_token;
192 if (prev_token == 0) return;189 if (prev_token == 0) return;
193 var newline_threshold: usize = 2;190 var newline_threshold: usize = 2;
194 while (tree.tokens.at(prev_token - 1).id == .DocComment) {191 while (tree.tokens[prev_token - 1].id == .DocComment) {
195 if (tree.tokenLocation(tree.tokens.at(prev_token - 1).end, prev_token).line == 1) {192 if (tree.tokenLocation(tree.tokens[prev_token - 1].end, prev_token).line == 1) {
196 newline_threshold += 1;193 newline_threshold += 1;
197 }194 }
198 prev_token -= 1;195 prev_token -= 1;
199 }196 }
200 const prev_token_end = tree.tokens.at(prev_token - 1).end;197 const prev_token_end = tree.tokens[prev_token - 1].end;
201 const loc = tree.tokenLocation(prev_token_end, first_token);198 const loc = tree.tokenLocation(prev_token_end, first_token);
202 if (loc.line >= newline_threshold) {199 if (loc.line >= newline_threshold) {
203 try stream.writeByte('\n');200 try stream.writeByte('\n');
...@@ -262,7 +259,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,...@@ -262,7 +259,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
262259
263 const src_has_trailing_comma = blk: {260 const src_has_trailing_comma = blk: {
264 const maybe_comma = tree.nextToken(field.lastToken());261 const maybe_comma = tree.nextToken(field.lastToken());
265 break :blk tree.tokens.at(maybe_comma).id == .Comma;262 break :blk tree.tokens[maybe_comma].id == .Comma;
266 };263 };
267264
268 // The trailing comma is emitted at the end, but if it's not present265 // The trailing comma is emitted at the end, but if it's not present
...@@ -426,13 +423,13 @@ fn renderExpression(...@@ -426,13 +423,13 @@ fn renderExpression(
426 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);423 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
427424
428 const after_op_space = blk: {425 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));426 const loc = tree.tokenLocation(tree.tokens[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
430 break :blk if (loc.line == 0) op_space else Space.Newline;427 break :blk if (loc.line == 0) op_space else Space.Newline;
431 };428 };
432429
433 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);430 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
434 if (after_op_space == Space.Newline and431 if (after_op_space == Space.Newline and
435 tree.tokens.at(tree.nextToken(infix_op_node.op_token)).id != .MultilineStringLiteralLine)432 tree.tokens[tree.nextToken(infix_op_node.op_token)].id != .MultilineStringLiteralLine)
436 {433 {
437 try stream.writeByteNTimes(' ', indent + indent_delta);434 try stream.writeByteNTimes(' ', indent + indent_delta);
438 start_col.* = indent + indent_delta;435 start_col.* = indent + indent_delta;
...@@ -453,10 +450,10 @@ fn renderExpression(...@@ -453,10 +450,10 @@ fn renderExpression(
453450
454 switch (prefix_op_node.op) {451 switch (prefix_op_node.op) {
455 .PtrType => |ptr_info| {452 .PtrType => |ptr_info| {
456 const op_tok_id = tree.tokens.at(prefix_op_node.op_token).id;453 const op_tok_id = tree.tokens[prefix_op_node.op_token].id;
457 switch (op_tok_id) {454 switch (op_tok_id) {
458 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),455 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
459 .LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier)456 .LBracket => if (tree.tokens[prefix_op_node.op_token + 2].id == .Identifier)
460 try stream.writeAll("[*c")457 try stream.writeAll("[*c")
461 else458 else
462 try stream.writeAll("[*"),459 try stream.writeAll("[*"),
...@@ -568,8 +565,8 @@ fn renderExpression(...@@ -568,8 +565,8 @@ fn renderExpression(
568565
569 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [566 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
570567
571 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;568 const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment;
572 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;569 const ends_with_comment = tree.tokens[rbracket - 1].id == .LineComment;
573 const new_indent = if (ends_with_comment) indent + indent_delta else indent;570 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
574 const new_space = if (ends_with_comment) Space.Newline else Space.None;571 const new_space = if (ends_with_comment) Space.Newline else Space.None;
575 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);572 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
...@@ -630,7 +627,7 @@ fn renderExpression(...@@ -630,7 +627,7 @@ fn renderExpression(
630627
631 const src_has_trailing_comma = blk: {628 const src_has_trailing_comma = blk: {
632 const maybe_comma = tree.prevToken(suffix_op.rtoken);629 const maybe_comma = tree.prevToken(suffix_op.rtoken);
633 break :blk tree.tokens.at(maybe_comma).id == .Comma;630 break :blk tree.tokens[maybe_comma].id == .Comma;
634 };631 };
635632
636 if (src_has_trailing_comma) {633 if (src_has_trailing_comma) {
...@@ -682,8 +679,8 @@ fn renderExpression(...@@ -682,8 +679,8 @@ fn renderExpression(
682 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);679 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
683 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [680 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
684681
685 const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;682 const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment;
686 const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;683 const ends_with_comment = tree.tokens[rbracket - 1].id == .LineComment;
687 const new_indent = if (ends_with_comment) indent + indent_delta else indent;684 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
688 const new_space = if (ends_with_comment) Space.Newline else Space.None;685 const new_space = if (ends_with_comment) Space.Newline else Space.None;
689 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);686 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
...@@ -750,11 +747,11 @@ fn renderExpression(...@@ -750,11 +747,11 @@ fn renderExpression(
750747
751 const src_has_trailing_comma = blk: {748 const src_has_trailing_comma = blk: {
752 const maybe_comma = tree.prevToken(suffix_op.rtoken);749 const maybe_comma = tree.prevToken(suffix_op.rtoken);
753 break :blk tree.tokens.at(maybe_comma).id == .Comma;750 break :blk tree.tokens[maybe_comma].id == .Comma;
754 };751 };
755752
756 const src_same_line = blk: {753 const src_same_line = blk: {
757 const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken);754 const loc = tree.tokenLocation(tree.tokens[lbrace].end, suffix_op.rtoken);
758 break :blk loc.line == 0;755 break :blk loc.line == 0;
759 };756 };
760757
...@@ -858,7 +855,7 @@ fn renderExpression(...@@ -858,7 +855,7 @@ fn renderExpression(
858 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);855 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
859 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);856 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
860 }857 }
861 if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) {858 if (exprs.len == 1 and tree.tokens[exprs.at(0).*.lastToken() + 1].id == .RBrace) {
862 const expr = exprs.at(0).*;859 const expr = exprs.at(0).*;
863860
864 switch (suffix_op.lhs) {861 switch (suffix_op.lhs) {
...@@ -883,17 +880,17 @@ fn renderExpression(...@@ -883,17 +880,17 @@ fn renderExpression(
883 const expr = it.next().?.*;880 const expr = it.next().?.*;
884 if (it.peek()) |next_expr| {881 if (it.peek()) |next_expr| {
885 const expr_last_token = expr.*.lastToken() + 1;882 const expr_last_token = expr.*.lastToken() + 1;
886 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());883 const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, next_expr.*.firstToken());
887 if (loc.line != 0) break :blk count;884 if (loc.line != 0) break :blk count;
888 count += 1;885 count += 1;
889 } else {886 } else {
890 const expr_last_token = expr.*.lastToken();887 const expr_last_token = expr.*.lastToken();
891 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, suffix_op.rtoken);888 const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, suffix_op.rtoken);
892 if (loc.line == 0) {889 if (loc.line == 0) {
893 // all on one line890 // all on one line
894 const src_has_trailing_comma = trailblk: {891 const src_has_trailing_comma = trailblk: {
895 const maybe_comma = tree.prevToken(suffix_op.rtoken);892 const maybe_comma = tree.prevToken(suffix_op.rtoken);
896 break :trailblk tree.tokens.at(maybe_comma).id == .Comma;893 break :trailblk tree.tokens[maybe_comma].id == .Comma;
897 };894 };
898 if (src_has_trailing_comma) {895 if (src_has_trailing_comma) {
899 break :blk 1; // force row size 1896 break :blk 1; // force row size 1
...@@ -933,7 +930,7 @@ fn renderExpression(...@@ -933,7 +930,7 @@ fn renderExpression(
933930
934 var new_indent = indent + indent_delta;931 var new_indent = indent + indent_delta;
935932
936 if (tree.tokens.at(tree.nextToken(lbrace)).id != .MultilineStringLiteralLine) {933 if (tree.tokens[tree.nextToken(lbrace)].id != .MultilineStringLiteralLine) {
937 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);934 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
938 try stream.writeByteNTimes(' ', new_indent);935 try stream.writeByteNTimes(' ', new_indent);
939 } else {936 } else {
...@@ -961,7 +958,7 @@ fn renderExpression(...@@ -961,7 +958,7 @@ fn renderExpression(
961 }958 }
962 col = 1;959 col = 1;
963960
964 if (tree.tokens.at(tree.nextToken(comma)).id != .MultilineStringLiteralLine) {961 if (tree.tokens[tree.nextToken(comma)].id != .MultilineStringLiteralLine) {
965 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,962 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
966 } else {963 } else {
967 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,964 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
...@@ -1188,9 +1185,9 @@ fn renderExpression(...@@ -1188,9 +1185,9 @@ fn renderExpression(
1188 var maybe_comma = tree.prevToken(container_decl.lastToken());1185 var maybe_comma = tree.prevToken(container_decl.lastToken());
1189 // Doc comments for a field may also appear after the comma, eg.1186 // Doc comments for a field may also appear after the comma, eg.
1190 // field_name: T, // comment attached to field_name1187 // field_name: T, // comment attached to field_name
1191 if (tree.tokens.at(maybe_comma).id == .DocComment)1188 if (tree.tokens[maybe_comma].id == .DocComment)
1192 maybe_comma = tree.prevToken(maybe_comma);1189 maybe_comma = tree.prevToken(maybe_comma);
1193 break :blk tree.tokens.at(maybe_comma).id == .Comma;1190 break :blk tree.tokens[maybe_comma].id == .Comma;
1194 };1191 };
11951192
1196 // Check if the first declaration and the { are on the same line1193 // Check if the first declaration and the { are on the same line
...@@ -1285,7 +1282,7 @@ fn renderExpression(...@@ -1285,7 +1282,7 @@ fn renderExpression(
12851282
1286 const src_has_trailing_comma = blk: {1283 const src_has_trailing_comma = blk: {
1287 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);1284 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1288 break :blk tree.tokens.at(maybe_comma).id == .Comma;1285 break :blk tree.tokens[maybe_comma].id == .Comma;
1289 };1286 };
12901287
1291 if (src_has_trailing_comma) {1288 if (src_has_trailing_comma) {
...@@ -1317,7 +1314,7 @@ fn renderExpression(...@@ -1317,7 +1314,7 @@ fn renderExpression(
1317 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);1314 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
13181315
1319 const comma_token = tree.nextToken(node.*.lastToken());1316 const comma_token = tree.nextToken(node.*.lastToken());
1320 assert(tree.tokens.at(comma_token).id == .Comma);1317 assert(tree.tokens[comma_token].id == .Comma);
1321 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1318 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1322 try renderExtraNewline(tree, stream, start_col, next_node.*);1319 try renderExtraNewline(tree, stream, start_col, next_node.*);
1323 } else {1320 } else {
...@@ -1342,7 +1339,7 @@ fn renderExpression(...@@ -1342,7 +1339,7 @@ fn renderExpression(
1342 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);1339 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
13431340
1344 var skip_first_indent = true;1341 var skip_first_indent = true;
1345 if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != .LineComment) {1342 if (tree.tokens[multiline_str_literal.firstToken() - 1].id != .LineComment) {
1346 try stream.print("\n", .{});1343 try stream.print("\n", .{});
1347 skip_first_indent = false;1344 skip_first_indent = false;
1348 }1345 }
...@@ -1372,7 +1369,7 @@ fn renderExpression(...@@ -1372,7 +1369,7 @@ fn renderExpression(
1372 if (builtin_call.params.len < 2) break :blk false;1369 if (builtin_call.params.len < 2) break :blk false;
1373 const last_node = builtin_call.params.at(builtin_call.params.len - 1).*;1370 const last_node = builtin_call.params.at(builtin_call.params.len - 1).*;
1374 const maybe_comma = tree.nextToken(last_node.lastToken());1371 const maybe_comma = tree.nextToken(last_node.lastToken());
1375 break :blk tree.tokens.at(maybe_comma).id == .Comma;1372 break :blk tree.tokens[maybe_comma].id == .Comma;
1376 };1373 };
13771374
1378 const lparen = tree.nextToken(builtin_call.builtin_token);1375 const lparen = tree.nextToken(builtin_call.builtin_token);
...@@ -1410,7 +1407,7 @@ fn renderExpression(...@@ -1410,7 +1407,7 @@ fn renderExpression(
1410 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);1407 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14111408
1412 if (fn_proto.visib_token) |visib_token_index| {1409 if (fn_proto.visib_token) |visib_token_index| {
1413 const visib_token = tree.tokens.at(visib_token_index);1410 const visib_token = tree.tokens[visib_token_index];
1414 assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export);1411 assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export);
14151412
1416 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub1413 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
...@@ -1433,7 +1430,7 @@ fn renderExpression(...@@ -1433,7 +1430,7 @@ fn renderExpression(
1433 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1430 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1434 break :blk tree.nextToken(fn_proto.fn_token);1431 break :blk tree.nextToken(fn_proto.fn_token);
1435 };1432 };
1436 assert(tree.tokens.at(lparen).id == .LParen);1433 assert(tree.tokens[lparen].id == .LParen);
14371434
1438 const rparen = tree.prevToken(1435 const rparen = tree.prevToken(
1439 // the first token for the annotation expressions is the left1436 // the first token for the annotation expressions is the left
...@@ -1449,10 +1446,10 @@ fn renderExpression(...@@ -1449,10 +1446,10 @@ fn renderExpression(
1449 .InferErrorSet => |node| tree.prevToken(node.firstToken()),1446 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1450 .Invalid => unreachable,1447 .Invalid => unreachable,
1451 });1448 });
1452 assert(tree.tokens.at(rparen).id == .RParen);1449 assert(tree.tokens[rparen].id == .RParen);
14531450
1454 const src_params_trailing_comma = blk: {1451 const src_params_trailing_comma = blk: {
1455 const maybe_comma = tree.tokens.at(rparen - 1).id;1452 const maybe_comma = tree.tokens[rparen - 1].id;
1456 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;1453 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
1457 };1454 };
14581455
...@@ -1591,7 +1588,7 @@ fn renderExpression(...@@ -1591,7 +1588,7 @@ fn renderExpression(
1591 const src_has_trailing_comma = blk: {1588 const src_has_trailing_comma = blk: {
1592 const last_node = switch_case.items.at(switch_case.items.len - 1).*;1589 const last_node = switch_case.items.at(switch_case.items.len - 1).*;
1593 const maybe_comma = tree.nextToken(last_node.lastToken());1590 const maybe_comma = tree.nextToken(last_node.lastToken());
1594 break :blk tree.tokens.at(maybe_comma).id == .Comma;1591 break :blk tree.tokens[maybe_comma].id == .Comma;
1595 };1592 };
15961593
1597 if (switch_case.items.len == 1 or !src_has_trailing_comma) {1594 if (switch_case.items.len == 1 or !src_has_trailing_comma) {
...@@ -1940,7 +1937,7 @@ fn renderExpression(...@@ -1940,7 +1937,7 @@ fn renderExpression(
1940 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1937 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1941 try stream.writeByteNTimes(' ', indent_once);1938 try stream.writeByteNTimes(' ', indent_once);
1942 const comma_or_colon = tree.nextToken(node.lastToken());1939 const comma_or_colon = tree.nextToken(node.lastToken());
1943 break :blk switch (tree.tokens.at(comma_or_colon).id) {1940 break :blk switch (tree.tokens[comma_or_colon].id) {
1944 .Comma => tree.nextToken(comma_or_colon),1941 .Comma => tree.nextToken(comma_or_colon),
1945 else => comma_or_colon,1942 else => comma_or_colon,
1946 };1943 };
...@@ -1978,7 +1975,7 @@ fn renderExpression(...@@ -1978,7 +1975,7 @@ fn renderExpression(
1978 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1975 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1979 try stream.writeByteNTimes(' ', indent_once);1976 try stream.writeByteNTimes(' ', indent_once);
1980 const comma_or_colon = tree.nextToken(node.lastToken());1977 const comma_or_colon = tree.nextToken(node.lastToken());
1981 break :blk switch (tree.tokens.at(comma_or_colon).id) {1978 break :blk switch (tree.tokens[comma_or_colon].id) {
1982 .Comma => tree.nextToken(comma_or_colon),1979 .Comma => tree.nextToken(comma_or_colon),
1983 else => comma_or_colon,1980 else => comma_or_colon,
1984 };1981 };
...@@ -2174,7 +2171,7 @@ fn renderStatement(...@@ -2174,7 +2171,7 @@ fn renderStatement(
2174 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);2171 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
21752172
2176 const semicolon_index = tree.nextToken(base.lastToken());2173 const semicolon_index = tree.nextToken(base.lastToken());
2177 assert(tree.tokens.at(semicolon_index).id == .Semicolon);2174 assert(tree.tokens[semicolon_index].id == .Semicolon);
2178 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);2175 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
2179 } else {2176 } else {
2180 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);2177 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
...@@ -2212,13 +2209,13 @@ fn renderTokenOffset(...@@ -2212,13 +2209,13 @@ fn renderTokenOffset(
2212 return;2209 return;
2213 }2210 }
22142211
2215 var token = tree.tokens.at(token_index);2212 var token = tree.tokens[token_index];
2216 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));2213 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
22172214
2218 if (space == Space.NoComment)2215 if (space == Space.NoComment)
2219 return;2216 return;
22202217
2221 var next_token = tree.tokens.at(token_index + 1);2218 var next_token = tree.tokens[token_index + 1];
22222219
2223 if (space == Space.Comma) switch (next_token.id) {2220 if (space == Space.Comma) switch (next_token.id) {
2224 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),2221 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
...@@ -2227,7 +2224,7 @@ fn renderTokenOffset(...@@ -2227,7 +2224,7 @@ fn renderTokenOffset(
2227 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);2224 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
2228 },2225 },
2229 else => {2226 else => {
2230 if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) {2227 if (token_index + 2 < tree.tokens.len and tree.tokens[token_index + 2].id == .MultilineStringLiteralLine) {
2231 try stream.writeAll(",");2228 try stream.writeAll(",");
2232 return;2229 return;
2233 } else {2230 } else {
...@@ -2244,7 +2241,7 @@ fn renderTokenOffset(...@@ -2244,7 +2241,7 @@ fn renderTokenOffset(
2244 const loc = tree.tokenLocationPtr(token.end, next_token);2241 const loc = tree.tokenLocationPtr(token.end, next_token);
2245 if (loc.line == 0) {2242 if (loc.line == 0) {
2246 offset += 1;2243 offset += 1;
2247 next_token = tree.tokens.at(token_index + offset);2244 next_token = tree.tokens[token_index + offset];
2248 }2245 }
2249 }2246 }
22502247
...@@ -2277,7 +2274,7 @@ fn renderTokenOffset(...@@ -2277,7 +2274,7 @@ fn renderTokenOffset(
2277 Space.Newline => {2274 Space.Newline => {
2278 offset += 1;2275 offset += 1;
2279 token = next_token;2276 token = next_token;
2280 next_token = tree.tokens.at(token_index + offset);2277 next_token = tree.tokens[token_index + offset];
2281 if (next_token.id != .LineComment) {2278 if (next_token.id != .LineComment) {
2282 try stream.writeByte('\n');2279 try stream.writeByte('\n');
2283 start_col.* = 0;2280 start_col.* = 0;
...@@ -2296,12 +2293,12 @@ fn renderTokenOffset(...@@ -2296,12 +2293,12 @@ fn renderTokenOffset(
2296 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")});2293 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")});
2297 offset = 2;2294 offset = 2;
2298 token = next_token;2295 token = next_token;
2299 next_token = tree.tokens.at(token_index + offset);2296 next_token = tree.tokens[token_index + offset];
2300 if (next_token.id != .LineComment) {2297 if (next_token.id != .LineComment) {
2301 switch (space) {2298 switch (space) {
2302 Space.None, Space.Space => {2299 Space.None, Space.Space => {
2303 try stream.writeByte('\n');2300 try stream.writeByte('\n');
2304 const after_comment_token = tree.tokens.at(token_index + offset);2301 const after_comment_token = tree.tokens[token_index + offset];
2305 const next_line_indent = switch (after_comment_token.id) {2302 const next_line_indent = switch (after_comment_token.id) {
2306 .RParen, .RBrace, .RBracket => indent,2303 .RParen, .RBrace, .RBracket => indent,
2307 else => indent + indent_delta,2304 else => indent + indent_delta,
...@@ -2342,7 +2339,7 @@ fn renderTokenOffset(...@@ -2342,7 +2339,7 @@ fn renderTokenOffset(
23422339
2343 offset += 1;2340 offset += 1;
2344 token = next_token;2341 token = next_token;
2345 next_token = tree.tokens.at(token_index + offset);2342 next_token = tree.tokens[token_index + offset];
2346 if (next_token.id != .LineComment) {2343 if (next_token.id != .LineComment) {
2347 switch (space) {2344 switch (space) {
2348 Space.Newline => {2345 Space.Newline => {
...@@ -2357,7 +2354,7 @@ fn renderTokenOffset(...@@ -2357,7 +2354,7 @@ fn renderTokenOffset(
2357 Space.None, Space.Space => {2354 Space.None, Space.Space => {
2358 try stream.writeByte('\n');2355 try stream.writeByte('\n');
23592356
2360 const after_comment_token = tree.tokens.at(token_index + offset);2357 const after_comment_token = tree.tokens[token_index + offset];
2361 const next_line_indent = switch (after_comment_token.id) {2358 const next_line_indent = switch (after_comment_token.id) {
2362 .RParen, .RBrace, .RBracket => blk: {2359 .RParen, .RBrace, .RBracket => blk: {
2363 if (indent > indent_delta) {2360 if (indent > indent_delta) {