authorgravatar for codroid@gmail.comhryx <codroid@gmail.com> 2019-05-12 02:01:45-07:00
committergravatar for codroid@gmail.comhryx <codroid@gmail.com> 2019-05-12 02:01:45-07:00
log3a3a73847812f03fa86fbcab4b3557a37f4c3536
tree1e0d9a9f85e9fbe1c24e2e3f3ffd53bca4294cfc
parent3787f3428625e830fd852a8f5a40c7d8a2d429f6
signature Commit is signed but in an unrecognized format.

Recursive rewrite of stage2 parser, part 3


6 files changed, 2900 insertions(+), 3557 deletions(-)

src-self-hosted/ir.zig+1-3
......@@ -1177,9 +1177,7 @@ pub const Builder = struct {
11771177 ast.Node.Id.Payload => return error.Unimplemented,
11781178 ast.Node.Id.PointerPayload => return error.Unimplemented,
11791179 ast.Node.Id.PointerIndexPayload => return error.Unimplemented,
1180 ast.Node.Id.StructField => return error.Unimplemented,
1181 ast.Node.Id.UnionTag => return error.Unimplemented,
1182 ast.Node.Id.EnumTag => return error.Unimplemented,
1180 ast.Node.Id.ContainerField => return error.Unimplemented,
11831181 ast.Node.Id.ErrorTag => return error.Unimplemented,
11841182 ast.Node.Id.AsmInput => return error.Unimplemented,
11851183 ast.Node.Id.AsmOutput => return error.Unimplemented,
std/zig/ast.zig+33-73
......@@ -113,6 +113,7 @@ pub const Tree = struct {
113113
114114pub const Error = union(enum) {
115115 InvalidToken: InvalidToken,
116 ExpectedContainerMembers: ExpectedContainerMembers,
116117 ExpectedStringLiteral: ExpectedStringLiteral,
117118 ExpectedIntegerLiteral: ExpectedIntegerLiteral,
118119 ExpectedPubItem: ExpectedPubItem,
......@@ -140,22 +141,27 @@ pub const Error = union(enum) {
140141 ExtraVolatileQualifier: ExtraVolatileQualifier,
141142 ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
142143 ExpectedTypeExpr: ExpectedTypeExpr,
144 ExpectedPrimaryTypeExpr: ExpectedPrimaryTypeExpr,
143145 ExpectedParamType: ExpectedParamType,
144146 ExpectedExpr: ExpectedExpr,
145147 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
146148 ExpectedToken: ExpectedToken,
147149 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
148150 ExpectedParamList: ExpectedParamList,
151 ExpectedPayload: ExpectedPayload,
149152 ExpectedBlockOrAssignment: ExpectedBlockOrAssignment,
153 ExpectedBlockOrExpression: ExpectedBlockOrExpression,
150154 ExpectedExprOrAssignment: ExpectedExprOrAssignment,
151 ExpectedPrefixExpr: ExpectedPrefixExpr, // TODO: lame
155 ExpectedPrefixExpr: ExpectedPrefixExpr,
152156 ExpectedLoopExpr: ExpectedLoopExpr,
153157 ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
158 ExpectedSuffixOp: ExpectedSuffixOp,
154159
155160 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
156161 switch (self.*) {
157162 // TODO https://github.com/ziglang/zig/issues/683
158163 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
164 @TagType(Error).ExpectedContainerMembers => |*x| return x.render(tokens, stream),
159165 @TagType(Error).ExpectedStringLiteral => |*x| return x.render(tokens, stream),
160166 @TagType(Error).ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
161167 @TagType(Error).ExpectedPubItem => |*x| return x.render(tokens, stream),
......@@ -183,17 +189,21 @@ pub const Error = union(enum) {
183189 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
184190 @TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
185191 @TagType(Error).ExpectedTypeExpr => |*x| return x.render(tokens, stream),
192 @TagType(Error).ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
186193 @TagType(Error).ExpectedParamType => |*x| return x.render(tokens, stream),
187194 @TagType(Error).ExpectedExpr => |*x| return x.render(tokens, stream),
188195 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
189196 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
190197 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
191198 @TagType(Error).ExpectedParamList => |*x| return x.render(tokens, stream),
199 @TagType(Error).ExpectedPayload => |*x| return x.render(tokens, stream),
192200 @TagType(Error).ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
201 @TagType(Error).ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
193202 @TagType(Error).ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
194203 @TagType(Error).ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
195204 @TagType(Error).ExpectedLoopExpr => |*x| return x.render(tokens, stream),
196205 @TagType(Error).ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
206 @TagType(Error).ExpectedSuffixOp => |*x| return x.render(tokens, stream),
197207 }
198208 }
199209
......@@ -201,6 +211,7 @@ pub const Error = union(enum) {
201211 switch (self.*) {
202212 // TODO https://github.com/ziglang/zig/issues/683
203213 @TagType(Error).InvalidToken => |x| return x.token,
214 @TagType(Error).ExpectedContainerMembers => |x| return x.token,
204215 @TagType(Error).ExpectedStringLiteral => |x| return x.token,
205216 @TagType(Error).ExpectedIntegerLiteral => |x| return x.token,
206217 @TagType(Error).ExpectedPubItem => |x| return x.token,
......@@ -228,21 +239,26 @@ pub const Error = union(enum) {
228239 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
229240 @TagType(Error).ExtraAllowZeroQualifier => |x| return x.token,
230241 @TagType(Error).ExpectedTypeExpr => |x| return x.token,
242 @TagType(Error).ExpectedPrimaryTypeExpr => |x| return x.token,
231243 @TagType(Error).ExpectedParamType => |x| return x.token,
232244 @TagType(Error).ExpectedExpr => |x| return x.token,
233245 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
234246 @TagType(Error).ExpectedToken => |x| return x.token,
235247 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
236248 @TagType(Error).ExpectedParamList => |x| return x.token,
249 @TagType(Error).ExpectedPayload => |x| return x.token,
237250 @TagType(Error).ExpectedBlockOrAssignment => |x| return x.token,
251 @TagType(Error).ExpectedBlockOrExpression => |x| return x.token,
238252 @TagType(Error).ExpectedExprOrAssignment => |x| return x.token,
239253 @TagType(Error).ExpectedPrefixExpr => |x| return x.token,
240254 @TagType(Error).ExpectedLoopExpr => |x| return x.token,
241255 @TagType(Error).ExpectedDerefOrUnwrap => |x| return x.token,
256 @TagType(Error).ExpectedSuffixOp => |x| return x.token,
242257 }
243258 }
244259
245260 pub const InvalidToken = SingleTokenError("Invalid token {}");
261 pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found {}");
246262 pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found {}");
247263 pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found {}");
248264 pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found {}");
......@@ -262,16 +278,20 @@ pub const Error = union(enum) {
262278 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++ @tagName(Token.Id.Identifier) ++ ", found {}");
263279 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
264280 pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found {}");
281 pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found {}");
265282 pub const ExpectedExpr = SingleTokenError("Expected expression, found {}");
266283 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
267284 pub const ExpectedParamList = SingleTokenError("Expected parameter list, found {}");
285 pub const ExpectedPayload = SingleTokenError("Expected loop payload, found {}");
268286 pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found {}");
287 pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found {}");
269288 pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found {}");
270289 pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found {}");
271290 pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found {}");
272291 pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found {}");
292 pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found {}");
273293
274 pub const ExpectedParamType = SimpleError("Expected parameter type'");
294 pub const ExpectedParamType = SimpleError("Expected parameter type");
275295 pub const ExpectedPubItem = SimpleError("Pub must be followed by fn decl, var decl, or container member");
276296 pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
277297 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
......@@ -401,9 +421,7 @@ pub const Node = struct {
401421 Payload,
402422 PointerPayload,
403423 PointerIndexPayload,
404 StructField,
405 UnionTag,
406 EnumTag,
424 ContainerField,
407425 ErrorTag,
408426 AsmInput,
409427 AsmOutput,
......@@ -467,9 +485,7 @@ pub const Node = struct {
467485 while (true) {
468486 switch (n.id) {
469487 Id.Root,
470 Id.StructField,
471 Id.UnionTag,
472 Id.EnumTag,
488 Id.ContainerField,
473489 Id.ParamDecl,
474490 Id.Block,
475491 Id.Payload,
......@@ -730,40 +746,15 @@ pub const Node = struct {
730746 }
731747 };
732748
733 pub const StructField = struct {
749 pub const ContainerField = struct {
734750 base: Node,
735751 doc_comments: ?*DocComment,
736752 visib_token: ?TokenIndex,
737753 name_token: TokenIndex,
738 type_expr: *Node,
739
740 pub fn iterate(self: *StructField, index: usize) ?*Node {
741 var i = index;
742
743 if (i < 1) return self.type_expr;
744 i -= 1;
745
746 return null;
747 }
748
749 pub fn firstToken(self: *const StructField) TokenIndex {
750 if (self.visib_token) |visib_token| return visib_token;
751 return self.name_token;
752 }
753
754 pub fn lastToken(self: *const StructField) TokenIndex {
755 return self.type_expr.lastToken();
756 }
757 };
758
759 pub const UnionTag = struct {
760 base: Node,
761 doc_comments: ?*DocComment,
762 name_token: TokenIndex,
763754 type_expr: ?*Node,
764755 value_expr: ?*Node,
765756
766 pub fn iterate(self: *UnionTag, index: usize) ?*Node {
757 pub fn iterate(self: *ContainerField, index: usize) ?*Node {
767758 var i = index;
768759
769760 if (self.type_expr) |type_expr| {
......@@ -779,11 +770,12 @@ pub const Node = struct {
779770 return null;
780771 }
781772
782 pub fn firstToken(self: *const UnionTag) TokenIndex {
773 pub fn firstToken(self: *const ContainerField) TokenIndex {
774 if (self.visib_token) |visib_token| return visib_token;
783775 return self.name_token;
784776 }
785777
786 pub fn lastToken(self: *const UnionTag) TokenIndex {
778 pub fn lastToken(self: *const ContainerField) TokenIndex {
787779 if (self.value_expr) |value_expr| {
788780 return value_expr.lastToken();
789781 }
......@@ -795,36 +787,6 @@ pub const Node = struct {
795787 }
796788 };
797789
798 pub const EnumTag = struct {
799 base: Node,
800 doc_comments: ?*DocComment,
801 name_token: TokenIndex,
802 value: ?*Node,
803
804 pub fn iterate(self: *EnumTag, index: usize) ?*Node {
805 var i = index;
806
807 if (self.value) |value| {
808 if (i < 1) return value;
809 i -= 1;
810 }
811
812 return null;
813 }
814
815 pub fn firstToken(self: *const EnumTag) TokenIndex {
816 return self.name_token;
817 }
818
819 pub fn lastToken(self: *const EnumTag) TokenIndex {
820 if (self.value) |value| {
821 return value.lastToken();
822 }
823
824 return self.name_token;
825 }
826 };
827
828790 pub const ErrorTag = struct {
829791 base: Node,
830792 doc_comments: ?*DocComment,
......@@ -1379,7 +1341,7 @@ pub const Node = struct {
13791341 inline_token: ?TokenIndex,
13801342 for_token: TokenIndex,
13811343 array_expr: *Node,
1382 payload: ?*Node,
1344 payload: *Node,
13831345 body: *Node,
13841346 @"else": ?*Else,
13851347
......@@ -1389,10 +1351,8 @@ pub const Node = struct {
13891351 if (i < 1) return self.array_expr;
13901352 i -= 1;
13911353
1392 if (self.payload) |payload| {
1393 if (i < 1) return payload;
1394 i -= 1;
1395 }
1354 if (i < 1) return self.payload;
1355 i -= 1;
13961356
13971357 if (i < 1) return self.body;
13981358 i -= 1;
......@@ -2184,7 +2144,7 @@ pub const Node = struct {
21842144
21852145 pub const OutputList = SegmentedList(*AsmOutput, 2);
21862146 pub const InputList = SegmentedList(*AsmInput, 2);
2187 pub const ClobberList = SegmentedList(TokenIndex, 2);
2147 pub const ClobberList = SegmentedList(*Node, 2);
21882148
21892149 pub fn iterate(self: *Asm, index: usize) ?*Node {
21902150 var i = index;
std/zig/parse.zig+2800-3407
......@@ -1,3659 +1,3052 @@
11const std = @import("../std.zig");
22const assert = std.debug.assert;
3const mem = std.mem;
3const Allocator = std.mem.Allocator;
44const ast = std.zig.ast;
5const Tokenizer = std.zig.Tokenizer;
6const Token = std.zig.Token;
5const Node = ast.Node;
6const Tree = ast.Tree;
7const AstError = ast.Error;
78const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;
9const Token = std.zig.Token;
10const TokenIterator = Tree.TokenList.Iterator;
11
12pub const Error = error{ParseError} || Allocator.Error;
913
1014/// Result should be freed with tree.deinit() when there are
1115/// no more references to any of the tokens or nodes.
12pub fn parse(allocator: *mem.Allocator, source: []const u8) !*ast.Tree {
13 var tree_arena = std.heap.ArenaAllocator.init(allocator);
14 errdefer tree_arena.deinit();
15
16 var stack = std.ArrayList(State).init(allocator);
17 defer stack.deinit();
18
19 const arena = &tree_arena.allocator;
20 const root_node = try arena.create(ast.Node.Root);
21 root_node.* = ast.Node.Root{
22 .base = ast.Node{ .id = ast.Node.Id.Root },
23 .decls = ast.Node.Root.DeclList.init(arena),
24 .doc_comments = null,
25 // initialized when we get the eof token
26 .eof_token = undefined,
16pub fn parse(allocator: *Allocator, source: []const u8) !*Tree {
17 const tree = blk: {
18 // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists
19 // from being initialized with a pointer to this `arena`, which is created on
20 // the stack. Following code should instead refer to `&tree.arena_allocator`, a
21 // pointer to data which lives safely on the heap and will outlive `parse`. See:
22 // https://github.com/ziglang/zig/commit/cb4fb14b6e66bd213575f69eec9598be8394fae6
23 var arena = std.heap.ArenaAllocator.init(allocator);
24 errdefer arena.deinit();
25 const tree = try arena.allocator.create(ast.Tree);
26 tree.* = ast.Tree{
27 .source = source,
28 .root_node = undefined,
29 .arena_allocator = arena,
30 .tokens = undefined,
31 .errors = undefined,
32 };
33 break :blk tree;
2734 };
35 errdefer tree.deinit();
36 const arena = &tree.arena_allocator.allocator;
2837
29 const tree = try arena.create(ast.Tree);
30 tree.* = ast.Tree{
31 .source = source,
32 .root_node = root_node,
33 .arena_allocator = tree_arena,
34 .tokens = ast.Tree.TokenList.init(arena),
35 .errors = ast.Tree.ErrorList.init(arena),
36 };
38 tree.tokens = ast.Tree.TokenList.init(arena);
39 tree.errors = ast.Tree.ErrorList.init(arena);
3740
38 var tokenizer = Tokenizer.init(tree.source);
41 var tokenizer = std.zig.Tokenizer.init(source);
3942 while (true) {
40 const token_ptr = try tree.tokens.addOne();
41 token_ptr.* = tokenizer.next();
42 if (token_ptr.id == Token.Id.Eof) break;
43 const tree_token = try tree.tokens.addOne();
44 tree_token.* = tokenizer.next();
45 if (tree_token.id == .Eof) break;
4346 }
44 var tok_it = tree.tokens.iterator(0);
47 var it = tree.tokens.iterator(0);
4548
46 // skip over line comments at the top of the file
47 while (true) {
48 const next_tok = tok_it.peek() orelse break;
49 if (next_tok.id != Token.Id.LineComment) break;
50 _ = tok_it.next();
51 }
49 while (it.peek().?.id == .LineComment) _ = it.next();
50
51 tree.root_node = try parseRoot(arena, &it, tree);
52 return tree;
53}
54
55/// Root <- skip ContainerMembers eof
56fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
57 const node = try arena.create(Node.Root);
58 node.* = Node.Root{
59 .base = Node{ .id = .Root },
60 .decls = undefined,
61 // TODO: Because zig fmt collapses consecutive comments separated by blank lines into
62 // a single multi-line comment, it is currently impossible to have a container-level
63 // doc comment and NO doc comment on the first decl. For now, simply
64 // ignore the problem and assume that there will be no container-level
65 // doc comments.
66 // See: https://github.com/ziglang/zig/issues/2288
67 .doc_comments = null,
68 .eof_token = undefined,
69 };
70 node.decls = parseContainerMembers(arena, it, tree) catch |err| {
71 // TODO: Switch on the error type
72 // https://github.com/ziglang/zig/issues/2473
73 if (err == error.ParseError) return node;
74 assert(err == Allocator.Error.OutOfMemory);
75 return Allocator.Error.OutOfMemory;
76 };
77 node.eof_token = eatToken(it, .Eof) orelse {
78 try tree.errors.push(AstError{
79 .ExpectedContainerMembers = AstError.ExpectedContainerMembers{ .token = it.index },
80 });
81 return node;
82 };
83 return node;
84}
5285
53 try stack.append(State.TopLevel);
86/// ContainerMembers
87/// <- TestDecl ContainerMembers
88/// / TopLevelComptime ContainerMembers
89/// / KEYWORD_pub? TopLevelDecl ContainerMembers
90/// / KEYWORD_pub? ContainerField COMMA ContainerMembers
91/// / KEYWORD_pub? ContainerField
92/// /
93fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList {
94 var list = Node.Root.DeclList.init(arena);
5495
5596 while (true) {
56 // This gives us 1 free push that can't fail
57 const state = stack.pop();
58
59 switch (state) {
60 State.TopLevel => {
61 const comments = try eatDocComments(arena, &tok_it, tree);
62
63 const token = nextToken(&tok_it, tree);
64 const token_index = token.index;
65 const token_ptr = token.ptr;
66 switch (token_ptr.id) {
67 Token.Id.Keyword_test => {
68 stack.append(State.TopLevel) catch unreachable;
69
70 const block = try arena.create(ast.Node.Block);
71 block.* = ast.Node.Block{
72 .base = ast.Node{ .id = ast.Node.Id.Block },
73 .label = null,
74 .lbrace = undefined,
75 .statements = ast.Node.Block.StatementList.init(arena),
76 .rbrace = undefined,
77 };
78 const test_node = try arena.create(ast.Node.TestDecl);
79 test_node.* = ast.Node.TestDecl{
80 .base = ast.Node{ .id = ast.Node.Id.TestDecl },
81 .doc_comments = comments,
82 .test_token = token_index,
83 .name = undefined,
84 .body_node = &block.base,
85 };
86 try root_node.decls.push(&test_node.base);
87 try stack.append(State{ .Block = block });
88 try stack.append(State{
89 .ExpectTokenSave = ExpectTokenSave{
90 .id = Token.Id.LBrace,
91 .ptr = &block.lbrace,
92 },
93 });
94 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });
95 continue;
96 },
97 Token.Id.Eof => {
98 root_node.eof_token = token_index;
99 root_node.doc_comments = comments;
100 return tree;
101 },
102 Token.Id.Keyword_pub => {
103 stack.append(State.TopLevel) catch unreachable;
104 try stack.append(State{
105 .TopLevelExtern = TopLevelDeclCtx{
106 .decls = &root_node.decls,
107 .visib_token = token_index,
108 .extern_export_inline_token = null,
109 .lib_name = null,
110 .comments = comments,
111 },
112 });
113 continue;
114 },
115 Token.Id.Keyword_comptime => {
116 const block = try arena.create(ast.Node.Block);
117 block.* = ast.Node.Block{
118 .base = ast.Node{ .id = ast.Node.Id.Block },
119 .label = null,
120 .lbrace = undefined,
121 .statements = ast.Node.Block.StatementList.init(arena),
122 .rbrace = undefined,
123 };
124 const node = try arena.create(ast.Node.Comptime);
125 node.* = ast.Node.Comptime{
126 .base = ast.Node{ .id = ast.Node.Id.Comptime },
127 .comptime_token = token_index,
128 .expr = &block.base,
129 .doc_comments = comments,
130 };
131 try root_node.decls.push(&node.base);
132
133 stack.append(State.TopLevel) catch unreachable;
134 try stack.append(State{ .Block = block });
135 try stack.append(State{
136 .ExpectTokenSave = ExpectTokenSave{
137 .id = Token.Id.LBrace,
138 .ptr = &block.lbrace,
139 },
140 });
141 continue;
142 },
143 else => {
144 prevToken(&tok_it, tree);
145 stack.append(State.TopLevel) catch unreachable;
146 try stack.append(State{
147 .TopLevelExtern = TopLevelDeclCtx{
148 .decls = &root_node.decls,
149 .visib_token = null,
150 .extern_export_inline_token = null,
151 .lib_name = null,
152 .comments = comments,
153 },
154 });
155 continue;
156 },
157 }
158 },
159 State.TopLevelExtern => |ctx| {
160 const token = nextToken(&tok_it, tree);
161 const token_index = token.index;
162 const token_ptr = token.ptr;
163 switch (token_ptr.id) {
164 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
165 stack.append(State{
166 .TopLevelDecl = TopLevelDeclCtx{
167 .decls = ctx.decls,
168 .visib_token = ctx.visib_token,
169 .extern_export_inline_token = AnnotatedToken{
170 .index = token_index,
171 .ptr = token_ptr,
172 },
173 .lib_name = null,
174 .comments = ctx.comments,
175 },
176 }) catch unreachable;
177 continue;
178 },
179 Token.Id.Keyword_extern => {
180 stack.append(State{
181 .TopLevelLibname = TopLevelDeclCtx{
182 .decls = ctx.decls,
183 .visib_token = ctx.visib_token,
184 .extern_export_inline_token = AnnotatedToken{
185 .index = token_index,
186 .ptr = token_ptr,
187 },
188 .lib_name = null,
189 .comments = ctx.comments,
190 },
191 }) catch unreachable;
192 continue;
193 },
194 else => {
195 prevToken(&tok_it, tree);
196 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;
197 continue;
198 },
199 }
200 },
201 State.TopLevelLibname => |ctx| {
202 const lib_name = blk: {
203 const lib_name_token = nextToken(&tok_it, tree);
204 const lib_name_token_index = lib_name_token.index;
205 const lib_name_token_ptr = lib_name_token.ptr;
206 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, tree)) orelse {
207 prevToken(&tok_it, tree);
208 break :blk null;
209 };
210 };
97 const doc_comments = try parseDocComment(arena, it, tree);
21198
212 stack.append(State{
213 .TopLevelDecl = TopLevelDeclCtx{
214 .decls = ctx.decls,
215 .visib_token = ctx.visib_token,
216 .extern_export_inline_token = ctx.extern_export_inline_token,
217 .lib_name = lib_name,
218 .comments = ctx.comments,
219 },
220 }) catch unreachable;
221 continue;
222 },
223 State.ThreadLocal => |ctx| {
224 const token = nextToken(&tok_it, tree);
225 const token_index = token.index;
226 const token_ptr = token.ptr;
227 switch (token_ptr.id) {
228 Token.Id.Keyword_var, Token.Id.Keyword_const => {
229 try stack.append(State{
230 .VarDecl = VarDeclCtx{
231 .comments = ctx.comments,
232 .visib_token = ctx.visib_token,
233 .thread_local_token = ctx.thread_local_token,
234 .lib_name = ctx.lib_name,
235 .comptime_token = ctx.comptime_token,
236 .extern_export_token = ctx.extern_export_token,
237 .mut_token = token_index,
238 .list = ctx.list,
239 },
240 });
241 continue;
242 },
243 else => {
244 ((try tree.errors.addOne())).* = Error{ .ExpectedVarDecl = Error.ExpectedVarDecl{ .token = token_index } };
245 return tree;
246 },
247 }
248 },
249 State.TopLevelDecl => |ctx| {
250 const token = nextToken(&tok_it, tree);
251 const token_index = token.index;
252 const token_ptr = token.ptr;
253 switch (token_ptr.id) {
254 Token.Id.Keyword_use => {
255 if (ctx.extern_export_inline_token) |annotated_token| {
256 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
257 return tree;
258 }
99 if (try parseTestDecl(arena, it, tree)) |node| {
100 node.cast(Node.TestDecl).?.doc_comments = doc_comments;
101 try list.push(node);
102 continue;
103 }
259104
260 const node = try arena.create(ast.Node.Use);
261 node.* = ast.Node.Use{
262 .base = ast.Node{ .id = ast.Node.Id.Use },
263 .use_token = token_index,
264 .visib_token = ctx.visib_token,
265 .expr = undefined,
266 .semicolon_token = undefined,
267 .doc_comments = ctx.comments,
268 };
269 try ctx.decls.push(&node.base);
270
271 stack.append(State{
272 .ExpectTokenSave = ExpectTokenSave{
273 .id = Token.Id.Semicolon,
274 .ptr = &node.semicolon_token,
275 },
276 }) catch unreachable;
277 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
278 continue;
279 },
280 Token.Id.Keyword_threadlocal => {
281 if (ctx.extern_export_inline_token) |annotated_token| {
282 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
283 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
284 return tree;
285 }
286 }
105 if (try parseTopLevelComptime(arena, it, tree)) |node| {
106 node.cast(Node.Comptime).?.doc_comments = doc_comments;
107 try list.push(node);
108 continue;
109 }
287110
288 try stack.append(State{
289 .ThreadLocal = VarDeclCtx{
290 .comments = ctx.comments,
291 .visib_token = ctx.visib_token,
292 .thread_local_token = token_index,
293 .lib_name = ctx.lib_name,
294 .comptime_token = null,
295 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
296 .mut_token = undefined,
297 .list = ctx.decls,
298 },
299 });
300 continue;
301 },
302 Token.Id.Keyword_var, Token.Id.Keyword_const => {
303 if (ctx.extern_export_inline_token) |annotated_token| {
304 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
305 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
306 return tree;
307 }
308 }
111 const visib_token = eatToken(it, .Keyword_pub);
309112
310 try stack.append(State{
311 .VarDecl = VarDeclCtx{
312 .comments = ctx.comments,
313 .visib_token = ctx.visib_token,
314 .thread_local_token = null,
315 .lib_name = ctx.lib_name,
316 .comptime_token = null,
317 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
318 .mut_token = token_index,
319 .list = ctx.decls,
320 },
321 });
322 continue;
323 },
324 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
325 const fn_proto = try arena.create(ast.Node.FnProto);
326 fn_proto.* = ast.Node.FnProto{
327 .base = ast.Node{ .id = ast.Node.Id.FnProto },
328 .doc_comments = ctx.comments,
329 .visib_token = ctx.visib_token,
330 .name_token = null,
331 .fn_token = undefined,
332 .params = ast.Node.FnProto.ParamList.init(arena),
333 .return_type = undefined,
334 .var_args_token = null,
335 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
336 .cc_token = null,
337 .async_attr = null,
338 .body_node = null,
339 .lib_name = ctx.lib_name,
340 .align_expr = null,
341 .section_expr = null,
342 };
343 try ctx.decls.push(&fn_proto.base);
344 stack.append(State{ .FnDef = fn_proto }) catch unreachable;
345 try stack.append(State{ .FnProto = fn_proto });
346
347 switch (token_ptr.id) {
348 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
349 fn_proto.cc_token = token_index;
350 try stack.append(State{
351 .ExpectTokenSave = ExpectTokenSave{
352 .id = Token.Id.Keyword_fn,
353 .ptr = &fn_proto.fn_token,
354 },
355 });
356 continue;
357 },
358 Token.Id.Keyword_async => {
359 const async_node = try arena.create(ast.Node.AsyncAttribute);
360 async_node.* = ast.Node.AsyncAttribute{
361 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
362 .async_token = token_index,
363 .allocator_type = null,
364 .rangle_bracket = null,
365 };
366 fn_proto.async_attr = async_node;
367
368 try stack.append(State{
369 .ExpectTokenSave = ExpectTokenSave{
370 .id = Token.Id.Keyword_fn,
371 .ptr = &fn_proto.fn_token,
372 },
373 });
374 try stack.append(State{ .AsyncAllocator = async_node });
375 continue;
376 },
377 Token.Id.Keyword_fn => {
378 fn_proto.fn_token = token_index;
379 continue;
380 },
381 else => unreachable,
382 }
383 },
384 else => {
385 ((try tree.errors.addOne())).* = Error{ .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn{ .token = token_index } };
386 return tree;
387 },
113 if (try parseTopLevelDecl(arena, it, tree)) |node| {
114 switch (node.id) {
115 .FnProto => {
116 node.cast(Node.FnProto).?.doc_comments = doc_comments;
117 node.cast(Node.FnProto).?.visib_token = visib_token;
118 },
119 .VarDecl => {
120 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
121 node.cast(Node.VarDecl).?.visib_token = visib_token;
122 },
123 .Use => {
124 node.cast(Node.Use).?.doc_comments = doc_comments;
125 node.cast(Node.Use).?.visib_token = visib_token;
126 },
127 else => unreachable,
128 }
129 try list.push(node);
130 if (try parseAppendedDocComment(arena, it, tree, node.lastToken())) |appended_comment| {
131 switch (node.id) {
132 .FnProto => {},
133 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
134 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
135 else => unreachable,
388136 }
389 },
390 State.TopLevelExternOrField => |ctx| {
391 if (eatToken(&tok_it, tree, Token.Id.Identifier)) |identifier| {
392 const node = try arena.create(ast.Node.StructField);
393 node.* = ast.Node.StructField{
394 .base = ast.Node{ .id = ast.Node.Id.StructField },
395 .doc_comments = ctx.comments,
396 .visib_token = ctx.visib_token,
397 .name_token = identifier,
398 .type_expr = undefined,
399 };
400 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
401 node_ptr.* = &node.base;
137 }
138 continue;
139 }
402140
403 try stack.append(State{
404 .FieldListCommaOrEnd = FieldCtx{
405 .doc_comments = &node.doc_comments,
406 .container_decl = ctx.container_decl,
407 },
408 });
409 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.type_expr } });
410 try stack.append(State{ .ExpectToken = Token.Id.Colon });
411 continue;
412 }
141 if (try parseContainerField(arena, it, tree)) |node| {
142 const field = node.cast(Node.ContainerField).?;
143 field.visib_token = visib_token;
144 field.doc_comments = doc_comments;
145 try list.push(node);
146 const comma = eatToken(it, .Comma) orelse break;
147 if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment|
148 field.doc_comments = appended_comment;
149 continue;
150 }
413151
414 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
415 try stack.append(State{
416 .TopLevelExtern = TopLevelDeclCtx{
417 .decls = &ctx.container_decl.fields_and_decls,
418 .visib_token = ctx.visib_token,
419 .extern_export_inline_token = null,
420 .lib_name = null,
421 .comments = ctx.comments,
422 },
423 });
424 continue;
425 },
152 // Dangling pub
153 if (visib_token != null) {
154 try tree.errors.push(AstError{
155 .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index },
156 });
157 }
426158
427 State.FieldInitValue => |ctx| {
428 const eq_tok = nextToken(&tok_it, tree);
429 const eq_tok_index = eq_tok.index;
430 const eq_tok_ptr = eq_tok.ptr;
431 if (eq_tok_ptr.id != Token.Id.Equal) {
432 prevToken(&tok_it, tree);
433 continue;
434 }
435 stack.append(State{ .Expression = ctx }) catch unreachable;
436 continue;
437 },
159 break;
160 }
438161
439 State.ContainerKind => |ctx| {
440 const token = nextToken(&tok_it, tree);
441 const token_index = token.index;
442 const token_ptr = token.ptr;
443 const node = try arena.create(ast.Node.ContainerDecl);
444 node.* = ast.Node.ContainerDecl{
445 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
446 .layout_token = ctx.layout_token,
447 .kind_token = switch (token_ptr.id) {
448 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => token_index,
449 else => {
450 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };
451 return tree;
452 },
453 },
454 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
455 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
456 .lbrace_token = undefined,
457 .rbrace_token = undefined,
458 };
459 ctx.opt_ctx.store(&node.base);
162 return list;
163}
460164
461 stack.append(State{ .ContainerDecl = node }) catch unreachable;
462 try stack.append(State{
463 .ExpectTokenSave = ExpectTokenSave{
464 .id = Token.Id.LBrace,
465 .ptr = &node.lbrace_token,
466 },
467 });
468 try stack.append(State{ .ContainerInitArgStart = node });
469 continue;
470 },
165/// TestDecl <- KEYWORD_test STRINGLITERAL Block
166fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
167 const test_token = eatToken(it, .Keyword_test) orelse return null;
168 const name_node = try expectNode(arena, it, tree, parseStringLiteral, AstError{
169 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },
170 });
171 const block_node = try expectNode(arena, it, tree, parseBlock, AstError{
172 .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index },
173 });
174
175 const test_node = try arena.create(Node.TestDecl);
176 test_node.* = Node.TestDecl{
177 .base = Node{ .id = .TestDecl },
178 .doc_comments = null,
179 .test_token = test_token,
180 .name = name_node,
181 .body_node = block_node,
182 };
183 return &test_node.base;
184}
471185
472 State.ContainerInitArgStart => |container_decl| {
473 if (eatToken(&tok_it, tree, Token.Id.LParen) == null) {
474 continue;
475 }
186/// TopLevelComptime <- KEYWORD_comptime BlockExpr
187fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
188 const tok = eatToken(it, .Keyword_comptime) orelse return null;
189 const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{
190 .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index },
191 });
476192
477 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
478 try stack.append(State{ .ContainerInitArg = container_decl });
479 continue;
480 },
193 const comptime_node = try arena.create(Node.Comptime);
194 comptime_node.* = Node.Comptime{
195 .base = Node{ .id = .Comptime },
196 .doc_comments = null,
197 .comptime_token = tok,
198 .expr = block_node,
199 };
200 return &comptime_node.base;
201}
481202
482 State.ContainerInitArg => |container_decl| {
483 const init_arg_token = nextToken(&tok_it, tree);
484 const init_arg_token_index = init_arg_token.index;
485 const init_arg_token_ptr = init_arg_token.ptr;
486 switch (init_arg_token_ptr.id) {
487 Token.Id.Keyword_enum => {
488 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Enum = null };
489 const lparen_tok = nextToken(&tok_it, tree);
490 const lparen_tok_index = lparen_tok.index;
491 const lparen_tok_ptr = lparen_tok.ptr;
492 if (lparen_tok_ptr.id == Token.Id.LParen) {
493 try stack.append(State{ .ExpectToken = Token.Id.RParen });
494 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });
495 } else {
496 prevToken(&tok_it, tree);
497 }
498 },
499 else => {
500 prevToken(&tok_it, tree);
501 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };
502 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
503 },
504 }
505 continue;
506 },
203/// TopLevelDecl
204/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block)
205/// / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl
206/// / KEYWORD_use Expr SEMICOLON
207fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
208 var lib_name: ?*Node = null;
209 const extern_export_inline_token = blk: {
210 if (eatToken(it, .Keyword_export)) |token| break :blk token;
211 if (eatToken(it, .Keyword_extern)) |token| {
212 lib_name = try parseStringLiteral(arena, it, tree);
213 break :blk token;
214 }
215 if (eatToken(it, .Keyword_inline)) |token| break :blk token;
216 break :blk null;
217 };
507218
508 State.ContainerDecl => |container_decl| {
509 const comments = try eatDocComments(arena, &tok_it, tree);
510 const token = nextToken(&tok_it, tree);
511 const token_index = token.index;
512 const token_ptr = token.ptr;
513 switch (token_ptr.id) {
514 Token.Id.Identifier => {
515 switch (tree.tokens.at(container_decl.kind_token).id) {
516 Token.Id.Keyword_struct => {
517 const node = try arena.create(ast.Node.StructField);
518 node.* = ast.Node.StructField{
519 .base = ast.Node{ .id = ast.Node.Id.StructField },
520 .doc_comments = comments,
521 .visib_token = null,
522 .name_token = token_index,
523 .type_expr = undefined,
524 };
525 const node_ptr = try container_decl.fields_and_decls.addOne();
526 node_ptr.* = &node.base;
527
528 try stack.append(State{
529 .FieldListCommaOrEnd = FieldCtx{
530 .doc_comments = &node.doc_comments,
531 .container_decl = container_decl,
532 },
533 });
534 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.type_expr } });
535 try stack.append(State{ .ExpectToken = Token.Id.Colon });
536 continue;
537 },
538 Token.Id.Keyword_union => {
539 const node = try arena.create(ast.Node.UnionTag);
540 node.* = ast.Node.UnionTag{
541 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
542 .name_token = token_index,
543 .type_expr = null,
544 .value_expr = null,
545 .doc_comments = comments,
546 };
547 try container_decl.fields_and_decls.push(&node.base);
548
549 try stack.append(State{
550 .FieldListCommaOrEnd = FieldCtx{
551 .doc_comments = &node.doc_comments,
552 .container_decl = container_decl,
553 },
554 });
555 try stack.append(State{ .FieldInitValue = OptionalCtx{ .RequiredNull = &node.value_expr } });
556 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &node.type_expr } });
557 try stack.append(State{ .IfToken = Token.Id.Colon });
558 continue;
559 },
560 Token.Id.Keyword_enum => {
561 const node = try arena.create(ast.Node.EnumTag);
562 node.* = ast.Node.EnumTag{
563 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
564 .name_token = token_index,
565 .value = null,
566 .doc_comments = comments,
567 };
568 try container_decl.fields_and_decls.push(&node.base);
569
570 try stack.append(State{
571 .FieldListCommaOrEnd = FieldCtx{
572 .doc_comments = &node.doc_comments,
573 .container_decl = container_decl,
574 },
575 });
576 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &node.value } });
577 try stack.append(State{ .IfToken = Token.Id.Equal });
578 continue;
579 },
580 else => unreachable,
581 }
582 },
583 Token.Id.Keyword_pub => {
584 switch (tree.tokens.at(container_decl.kind_token).id) {
585 Token.Id.Keyword_struct => {
586 try stack.append(State{
587 .TopLevelExternOrField = TopLevelExternOrFieldCtx{
588 .visib_token = token_index,
589 .container_decl = container_decl,
590 .comments = comments,
591 },
592 });
593 continue;
594 },
595 else => {
596 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
597 try stack.append(State{
598 .TopLevelExtern = TopLevelDeclCtx{
599 .decls = &container_decl.fields_and_decls,
600 .visib_token = token_index,
601 .extern_export_inline_token = null,
602 .lib_name = null,
603 .comments = comments,
604 },
605 });
606 continue;
607 },
608 }
609 },
610 Token.Id.Keyword_export => {
611 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
612 try stack.append(State{
613 .TopLevelExtern = TopLevelDeclCtx{
614 .decls = &container_decl.fields_and_decls,
615 .visib_token = token_index,
616 .extern_export_inline_token = null,
617 .lib_name = null,
618 .comments = comments,
619 },
620 });
621 continue;
622 },
623 Token.Id.Keyword_comptime => {
624 const block = try arena.create(ast.Node.Block);
625 block.* = ast.Node.Block{
626 .base = ast.Node{ .id = ast.Node.Id.Block },
627 .label = null,
628 .lbrace = undefined,
629 .statements = ast.Node.Block.StatementList.init(arena),
630 .rbrace = undefined,
631 };
219 if (try parseFnProto(arena, it, tree)) |node| {
220 const fn_node = node.cast(Node.FnProto).?;
221 fn_node.*.extern_export_inline_token = extern_export_inline_token;
222 fn_node.*.lib_name = lib_name;
223 if (eatToken(it, .Semicolon)) |_| return node;
224 if (try parseBlock(arena, it, tree)) |body_node| {
225 fn_node.body_node = body_node;
226 return node;
227 }
228 try tree.errors.push(AstError{
229 .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index },
230 });
231 return null;
232 }
632233
633 const node = try arena.create(ast.Node.Comptime);
634 node.* = ast.Node.Comptime{
635 .base = ast.Node{ .id = ast.Node.Id.Comptime },
636 .comptime_token = token_index,
637 .expr = &block.base,
638 .doc_comments = comments,
639 };
640 try container_decl.fields_and_decls.push(&node.base);
641
642 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
643 try stack.append(State{ .Block = block });
644 try stack.append(State{
645 .ExpectTokenSave = ExpectTokenSave{
646 .id = Token.Id.LBrace,
647 .ptr = &block.lbrace,
648 },
649 });
650 continue;
651 },
652 Token.Id.RBrace => {
653 if (comments != null) {
654 ((try tree.errors.addOne())).* = Error{ .UnattachedDocComment = Error.UnattachedDocComment{ .token = token_index } };
655 return tree;
656 }
657 container_decl.rbrace_token = token_index;
658 continue;
659 },
660 else => {
661 prevToken(&tok_it, tree);
662 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
663 try stack.append(State{
664 .TopLevelExtern = TopLevelDeclCtx{
665 .decls = &container_decl.fields_and_decls,
666 .visib_token = null,
667 .extern_export_inline_token = null,
668 .lib_name = null,
669 .comments = comments,
670 },
671 });
672 continue;
673 },
674 }
675 },
234 if (extern_export_inline_token) |token| {
235 if (tree.tokens.at(token).id == .Keyword_inline) {
236 putBackToken(it, token);
237 return null;
238 }
239 }
676240
677 State.VarDecl => |ctx| {
678 const var_decl = try arena.create(ast.Node.VarDecl);
679 var_decl.* = ast.Node.VarDecl{
680 .base = ast.Node{ .id = ast.Node.Id.VarDecl },
681 .doc_comments = ctx.comments,
682 .visib_token = ctx.visib_token,
683 .thread_local_token = ctx.thread_local_token,
684 .mut_token = ctx.mut_token,
685 .comptime_token = ctx.comptime_token,
686 .extern_export_token = ctx.extern_export_token,
687 .type_node = null,
688 .align_node = null,
689 .section_node = null,
690 .init_node = null,
691 .lib_name = ctx.lib_name,
692 // initialized later
693 .name_token = undefined,
694 .eq_token = undefined,
695 .semicolon_token = undefined,
696 };
697 try ctx.list.push(&var_decl.base);
698
699 try stack.append(State{ .VarDeclAlign = var_decl });
700 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &var_decl.type_node } });
701 try stack.append(State{ .IfToken = Token.Id.Colon });
702 try stack.append(State{
703 .ExpectTokenSave = ExpectTokenSave{
704 .id = Token.Id.Identifier,
705 .ptr = &var_decl.name_token,
706 },
707 });
708 continue;
709 },
710 State.VarDeclAlign => |var_decl| {
711 try stack.append(State{ .VarDeclSection = var_decl });
712
713 const next_token = nextToken(&tok_it, tree);
714 const next_token_index = next_token.index;
715 const next_token_ptr = next_token.ptr;
716 if (next_token_ptr.id == Token.Id.Keyword_align) {
717 try stack.append(State{ .ExpectToken = Token.Id.RParen });
718 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.align_node } });
719 try stack.append(State{ .ExpectToken = Token.Id.LParen });
720 continue;
721 }
241 const thread_local_token = eatToken(it, .Keyword_threadlocal);
722242
723 prevToken(&tok_it, tree);
724 continue;
725 },
726 State.VarDeclSection => |var_decl| {
727 try stack.append(State{ .VarDeclEq = var_decl });
728
729 const next_token = nextToken(&tok_it, tree);
730 const next_token_index = next_token.index;
731 const next_token_ptr = next_token.ptr;
732 if (next_token_ptr.id == Token.Id.Keyword_linksection) {
733 try stack.append(State{ .ExpectToken = Token.Id.RParen });
734 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.section_node } });
735 try stack.append(State{ .ExpectToken = Token.Id.LParen });
736 continue;
737 }
243 if (try parseVarDecl(arena, it, tree)) |node| {
244 var var_decl = node.cast(Node.VarDecl).?;
245 var_decl.*.thread_local_token = thread_local_token;
246 var_decl.*.comptime_token = null;
247 var_decl.*.extern_export_token = extern_export_inline_token;
248 var_decl.*.lib_name = lib_name;
249 return node;
250 }
738251
739 prevToken(&tok_it, tree);
740 continue;
741 },
742 State.VarDeclEq => |var_decl| {
743 const token = nextToken(&tok_it, tree);
744 const token_index = token.index;
745 const token_ptr = token.ptr;
746 switch (token_ptr.id) {
747 Token.Id.Equal => {
748 var_decl.eq_token = token_index;
749 stack.append(State{ .VarDeclSemiColon = var_decl }) catch unreachable;
750 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.init_node } });
751 continue;
752 },
753 Token.Id.Semicolon => {
754 var_decl.semicolon_token = token_index;
755 continue;
756 },
757 else => {
758 ((try tree.errors.addOne())).* = Error{ .ExpectedEqOrSemi = Error.ExpectedEqOrSemi{ .token = token_index } };
759 return tree;
760 },
761 }
762 },
252 if (thread_local_token != null) {
253 try tree.errors.push(AstError{
254 .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index },
255 });
256 return error.ParseError;
257 }
763258
764 State.VarDeclSemiColon => |var_decl| {
765 const semicolon_token = nextToken(&tok_it, tree);
259 if (extern_export_inline_token) |token| {
260 if (lib_name) |string_literal_node|
261 putBackToken(it, string_literal_node.cast(Node.StringLiteral).?.token);
262 putBackToken(it, token);
263 return null;
264 }
766265
767 if (semicolon_token.ptr.id != Token.Id.Semicolon) {
768 ((try tree.errors.addOne())).* = Error{
769 .ExpectedToken = Error.ExpectedToken{
770 .token = semicolon_token.index,
771 .expected_id = Token.Id.Semicolon,
772 },
773 };
774 return tree;
775 }
266 const use_node = (try parseUse(arena, it, tree)) orelse return null;
267 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
268 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
269 });
270 const semicolon_token = try expectToken(it, tree, .Semicolon);
271 const use_node_raw = use_node.cast(Node.Use).?;
272 use_node_raw.*.expr = expr_node;
273 use_node_raw.*.semicolon_token = semicolon_token;
776274
777 var_decl.semicolon_token = semicolon_token.index;
275 return use_node;
276}
778277
779 if (eatToken(&tok_it, tree, Token.Id.DocComment)) |doc_comment_token| {
780 const loc = tree.tokenLocation(semicolon_token.ptr.end, doc_comment_token);
781 if (loc.line == 0) {
782 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);
783 } else {
784 prevToken(&tok_it, tree);
785 }
786 }
787 },
278/// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
279fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
280 const cc = try parseFnCC(arena, it, tree);
281 const fn_token = eatToken(it, .Keyword_fn) orelse {
282 if (cc == null) return null else return error.ParseError;
283 };
284 const name_token = eatToken(it, .Identifier);
285 const lparen = try expectToken(it, tree, .LParen);
286 const params = try parseParamDeclList(arena, it, tree);
287 const rparen = try expectToken(it, tree, .RParen);
288 const align_expr = try parseByteAlign(arena, it, tree);
289 const section_expr = try parseLinkSection(arena, it, tree);
290 const exclamation_token = eatToken(it, .Bang);
291
292 const return_type_expr = (try parseVarType(arena, it, tree)) orelse
293 try expectNode(arena, it, tree, parseTypeExpr, AstError{
294 .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index },
295 });
296
297 const return_type = if (exclamation_token != null)
298 Node.FnProto.ReturnType{
299 .InferErrorSet = return_type_expr,
300 }
301 else
302 Node.FnProto.ReturnType{
303 .Explicit = return_type_expr,
304 };
305
306 const var_args_token = if (params.len > 0)
307 params.at(params.len - 1).*.cast(Node.ParamDecl).?.var_args_token
308 else
309 null;
310
311 const fn_proto_node = try arena.create(Node.FnProto);
312 fn_proto_node.* = Node.FnProto{
313 .base = Node{ .id = .FnProto },
314 .doc_comments = null,
315 .visib_token = null,
316 .fn_token = fn_token,
317 .name_token = name_token,
318 .params = params,
319 .return_type = return_type,
320 .var_args_token = var_args_token,
321 .extern_export_inline_token = null,
322 .cc_token = null,
323 .async_attr = null,
324 .body_node = null,
325 .lib_name = null,
326 .align_expr = align_expr,
327 .section_expr = section_expr,
328 };
788329
789 State.FnDef => |fn_proto| {
790 const token = nextToken(&tok_it, tree);
791 const token_index = token.index;
792 const token_ptr = token.ptr;
793 switch (token_ptr.id) {
794 Token.Id.LBrace => {
795 const block = try arena.create(ast.Node.Block);
796 block.* = ast.Node.Block{
797 .base = ast.Node{ .id = ast.Node.Id.Block },
798 .label = null,
799 .lbrace = token_index,
800 .statements = ast.Node.Block.StatementList.init(arena),
801 .rbrace = undefined,
802 };
803 fn_proto.body_node = &block.base;
804 stack.append(State{ .Block = block }) catch unreachable;
805 continue;
806 },
807 Token.Id.Semicolon => continue,
808 else => {
809 ((try tree.errors.addOne())).* = Error{ .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace{ .token = token_index } };
810 return tree;
811 },
812 }
813 },
814 State.FnProto => |fn_proto| {
815 stack.append(State{ .FnProtoAlign = fn_proto }) catch unreachable;
816 try stack.append(State{ .ParamDecl = fn_proto });
817 try stack.append(State{ .ExpectToken = Token.Id.LParen });
330 if (cc) |kind| {
331 switch (kind) {
332 .CC => |token| fn_proto_node.cc_token = token,
333 .Extern => |token| fn_proto_node.extern_export_inline_token = token,
334 .Async => |node| fn_proto_node.async_attr = node,
335 }
336 }
818337
819 if (eatToken(&tok_it, tree, Token.Id.Identifier)) |name_token| {
820 fn_proto.name_token = name_token;
821 }
822 continue;
823 },
824 State.FnProtoAlign => |fn_proto| {
825 stack.append(State{ .FnProtoSection = fn_proto }) catch unreachable;
338 return &fn_proto_node.base;
339}
826340
827 if (eatToken(&tok_it, tree, Token.Id.Keyword_align)) |align_token| {
828 try stack.append(State{ .ExpectToken = Token.Id.RParen });
829 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.align_expr } });
830 try stack.append(State{ .ExpectToken = Token.Id.LParen });
831 }
832 continue;
833 },
834 State.FnProtoSection => |fn_proto| {
835 stack.append(State{ .FnProtoReturnType = fn_proto }) catch unreachable;
341/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
342fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
343 const mut_token = eatToken(it, .Keyword_const) orelse
344 eatToken(it, .Keyword_var) orelse
345 return null;
346
347 const name_token = try expectToken(it, tree, .Identifier);
348 const type_node = if (eatToken(it, .Colon) != null)
349 try expectNode(arena, it, tree, parseTypeExpr, AstError{
350 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
351 })
352 else
353 null;
354 const align_node = try parseByteAlign(arena, it, tree);
355 const section_node = try parseLinkSection(arena, it, tree);
356 const eq_token = eatToken(it, .Equal);
357 const init_node = if (eq_token != null) blk: {
358 break :blk try expectNode(arena, it, tree, parseExpr, AstError{
359 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
360 });
361 } else null;
362 const semicolon_token = try expectToken(it, tree, .Semicolon);
363
364 const node = try arena.create(Node.VarDecl);
365 node.* = Node.VarDecl{
366 .base = Node{ .id = .VarDecl },
367 .doc_comments = null,
368 .visib_token = null,
369 .thread_local_token = null,
370 .name_token = name_token,
371 .eq_token = eq_token orelse undefined,
372 .mut_token = mut_token,
373 .comptime_token = null,
374 .extern_export_token = null,
375 .lib_name = null,
376 .type_node = type_node,
377 .align_node = align_node,
378 .section_node = section_node,
379 .init_node = init_node,
380 .semicolon_token = semicolon_token,
381 };
382 return &node.base;
383}
836384
837 if (eatToken(&tok_it, tree, Token.Id.Keyword_linksection)) |align_token| {
838 try stack.append(State{ .ExpectToken = Token.Id.RParen });
839 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.section_expr } });
840 try stack.append(State{ .ExpectToken = Token.Id.LParen });
841 }
842 continue;
843 },
844 State.FnProtoReturnType => |fn_proto| {
845 const token = nextToken(&tok_it, tree);
846 const token_index = token.index;
847 const token_ptr = token.ptr;
848 switch (token_ptr.id) {
849 Token.Id.Bang => {
850 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .InferErrorSet = undefined };
851 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.InferErrorSet } }) catch unreachable;
852 continue;
853 },
854 else => {
855 // TODO: this is a special case. Remove this when #760 is fixed
856 if (token_ptr.id == Token.Id.Keyword_anyerror) {
857 if (tok_it.peek().?.id == Token.Id.LBrace) {
858 const error_type_node = try arena.create(ast.Node.ErrorType);
859 error_type_node.* = ast.Node.ErrorType{
860 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
861 .token = token_index,
862 };
863 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base };
864 continue;
865 }
866 }
385/// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
386fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
387 const name_token = eatToken(it, .Identifier) orelse return null;
388
389 const type_expr = if (eatToken(it, .Colon)) |_|
390 try expectNode(arena, it, tree, parseTypeExpr, AstError{
391 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
392 })
393 else
394 null;
395
396 const value_expr = if (eatToken(it, .Equal)) |_|
397 try expectNode(arena, it, tree, parseExpr, AstError{
398 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
399 })
400 else
401 null;
402
403 const node = try arena.create(Node.ContainerField);
404 node.* = Node.ContainerField{
405 .base = Node{ .id = .ContainerField },
406 .doc_comments = null,
407 .visib_token = null,
408 .name_token = name_token,
409 .type_expr = type_expr,
410 .value_expr = value_expr,
411 };
412 return &node.base;
413}
867414
868 prevToken(&tok_it, tree);
869 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };
870 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;
871 continue;
872 },
873 }
874 },
415/// Statement
416/// <- KEYWORD_comptime? VarDecl
417/// / KEYWORD_comptime BlockExprStatement
418/// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
419/// / KEYWORD_defer BlockExprStatement
420/// / KEYWORD_errdefer BlockExprStatement
421/// / IfStatement
422/// / LabeledStatement
423/// / SwitchExpr
424/// / AssignExpr SEMICOLON
425fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
426 const comptime_token = eatToken(it, .Keyword_comptime);
427
428 const var_decl_node = try parseVarDecl(arena, it, tree);
429 if (var_decl_node) |node| {
430 const var_decl = node.cast(Node.VarDecl).?;
431 var_decl.comptime_token = comptime_token;
432 return node;
433 }
875434
876 State.ParamDecl => |fn_proto| {
877 const comments = try eatDocComments(arena, &tok_it, tree);
878 if (eatToken(&tok_it, tree, Token.Id.RParen)) |_| {
879 continue;
880 }
881 const param_decl = try arena.create(ast.Node.ParamDecl);
882 param_decl.* = ast.Node.ParamDecl{
883 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
884 .doc_comments = comments,
885 .comptime_token = null,
886 .noalias_token = null,
887 .name_token = null,
888 .type_node = undefined,
889 .var_args_token = null,
890 };
891 try fn_proto.params.push(&param_decl.base);
435 if (comptime_token) |token| {
436 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{
437 .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index },
438 });
439
440 const node = try arena.create(Node.Comptime);
441 node.* = Node.Comptime{
442 .base = Node{ .id = .Comptime },
443 .doc_comments = null,
444 .comptime_token = token,
445 .expr = block_expr,
446 };
447 return &node.base;
448 }
892449
893 stack.append(State{
894 .ParamDeclEnd = ParamDeclEndCtx{
895 .param_decl = param_decl,
896 .fn_proto = fn_proto,
897 },
898 }) catch unreachable;
899 try stack.append(State{ .ParamDeclName = param_decl });
900 try stack.append(State{ .ParamDeclAliasOrComptime = param_decl });
901 continue;
902 },
903 State.ParamDeclAliasOrComptime => |param_decl| {
904 if (eatToken(&tok_it, tree, Token.Id.Keyword_comptime)) |comptime_token| {
905 param_decl.comptime_token = comptime_token;
906 } else if (eatToken(&tok_it, tree, Token.Id.Keyword_noalias)) |noalias_token| {
907 param_decl.noalias_token = noalias_token;
908 }
909 continue;
910 },
911 State.ParamDeclName => |param_decl| {
912 // TODO: Here, we eat two tokens in one state. This means that we can't have
913 // comments between these two tokens.
914 if (eatToken(&tok_it, tree, Token.Id.Identifier)) |ident_token| {
915 if (eatToken(&tok_it, tree, Token.Id.Colon)) |_| {
916 param_decl.name_token = ident_token;
917 } else {
918 prevToken(&tok_it, tree);
919 }
920 }
921 continue;
922 },
923 State.ParamDeclEnd => |ctx| {
924 if (eatToken(&tok_it, tree, Token.Id.Ellipsis3)) |ellipsis3| {
925 ctx.param_decl.var_args_token = ellipsis3;
926
927 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RParen)) {
928 ExpectCommaOrEndResult.end_token => |t| {
929 if (t == null) {
930 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
931 continue;
932 }
933 continue;
934 },
935 ExpectCommaOrEndResult.parse_error => |e| {
936 try tree.errors.push(e);
937 return tree;
938 },
939 }
940 }
450 if (eatToken(it, .Keyword_suspend)) |suspend_token| {
451 const semicolon = eatToken(it, .Semicolon);
452
453 const body_node = if (semicolon == null) blk: {
454 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{
455 .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index },
456 });
457 } else null;
458
459 const node = try arena.create(Node.Suspend);
460 node.* = Node.Suspend{
461 .base = Node{ .id = .Suspend },
462 .suspend_token = suspend_token,
463 .body = body_node,
464 };
465 return &node.base;
466 }
941467
942 try stack.append(State{ .ParamDeclComma = ctx.fn_proto });
943 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &ctx.param_decl.type_node } });
944 continue;
945 },
946 State.ParamDeclComma => |fn_proto| {
947 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RParen)) {
948 ExpectCommaOrEndResult.end_token => |t| {
949 if (t == null) {
950 stack.append(State{ .ParamDecl = fn_proto }) catch unreachable;
951 }
952 continue;
953 },
954 ExpectCommaOrEndResult.parse_error => |e| {
955 try tree.errors.push(e);
956 return tree;
957 },
958 }
959 },
468 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);
469 if (defer_token) |token| {
470 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{
471 .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index },
472 });
473 const node = try arena.create(Node.Defer);
474 node.* = Node.Defer{
475 .base = Node{ .id = .Defer },
476 .defer_token = token,
477 .expr = expr_node,
478 };
479 return &node.base;
480 }
960481
961 State.MaybeLabeledExpression => |ctx| {
962 if (eatToken(&tok_it, tree, Token.Id.Colon)) |_| {
963 stack.append(State{
964 .LabeledExpression = LabelCtx{
965 .label = ctx.label,
966 .opt_ctx = ctx.opt_ctx,
967 },
968 }) catch unreachable;
969 continue;
970 }
482 if (try parseIfStatement(arena, it, tree)) |node| return node;
483 if (try parseLabeledStatement(arena, it, tree)) |node| return node;
484 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
485 if (try parseAssignExpr(arena, it, tree)) |node| {
486 _ = try expectToken(it, tree, .Semicolon);
487 return node;
488 }
971489
972 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
973 continue;
974 },
975 State.LabeledExpression => |ctx| {
976 const token = nextToken(&tok_it, tree);
977 const token_index = token.index;
978 const token_ptr = token.ptr;
979 switch (token_ptr.id) {
980 Token.Id.LBrace => {
981 const block = try arena.create(ast.Node.Block);
982 block.* = ast.Node.Block{
983 .base = ast.Node{ .id = ast.Node.Id.Block },
984 .label = ctx.label,
985 .lbrace = token_index,
986 .statements = ast.Node.Block.StatementList.init(arena),
987 .rbrace = undefined,
988 };
989 ctx.opt_ctx.store(&block.base);
990 stack.append(State{ .Block = block }) catch unreachable;
991 continue;
992 },
993 Token.Id.Keyword_while => {
994 stack.append(State{
995 .While = LoopCtx{
996 .label = ctx.label,
997 .inline_token = null,
998 .loop_token = token_index,
999 .opt_ctx = ctx.opt_ctx.toRequired(),
1000 },
1001 }) catch unreachable;
1002 continue;
1003 },
1004 Token.Id.Keyword_for => {
1005 stack.append(State{
1006 .For = LoopCtx{
1007 .label = ctx.label,
1008 .inline_token = null,
1009 .loop_token = token_index,
1010 .opt_ctx = ctx.opt_ctx.toRequired(),
1011 },
1012 }) catch unreachable;
1013 continue;
1014 },
1015 Token.Id.Keyword_inline => {
1016 stack.append(State{
1017 .Inline = InlineCtx{
1018 .label = ctx.label,
1019 .inline_token = token_index,
1020 .opt_ctx = ctx.opt_ctx.toRequired(),
1021 },
1022 }) catch unreachable;
1023 continue;
1024 },
1025 else => {
1026 if (ctx.opt_ctx != OptionalCtx.Optional) {
1027 ((try tree.errors.addOne())).* = Error{ .ExpectedLabelable = Error.ExpectedLabelable{ .token = token_index } };
1028 return tree;
1029 }
490 return null;
491}
1030492
1031 prevToken(&tok_it, tree);
1032 continue;
1033 },
1034 }
1035 },
1036 State.Inline => |ctx| {
1037 const token = nextToken(&tok_it, tree);
1038 const token_index = token.index;
1039 const token_ptr = token.ptr;
1040 switch (token_ptr.id) {
1041 Token.Id.Keyword_while => {
1042 stack.append(State{
1043 .While = LoopCtx{
1044 .inline_token = ctx.inline_token,
1045 .label = ctx.label,
1046 .loop_token = token_index,
1047 .opt_ctx = ctx.opt_ctx.toRequired(),
1048 },
1049 }) catch unreachable;
1050 continue;
1051 },
1052 Token.Id.Keyword_for => {
1053 stack.append(State{
1054 .For = LoopCtx{
1055 .inline_token = ctx.inline_token,
1056 .label = ctx.label,
1057 .loop_token = token_index,
1058 .opt_ctx = ctx.opt_ctx.toRequired(),
1059 },
1060 }) catch unreachable;
1061 continue;
1062 },
1063 else => {
1064 if (ctx.opt_ctx != OptionalCtx.Optional) {
1065 ((try tree.errors.addOne())).* = Error{ .ExpectedInlinable = Error.ExpectedInlinable{ .token = token_index } };
1066 return tree;
1067 }
493/// IfStatement
494/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
495/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
496fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
497 const if_node = (try parseIfPrefix(arena, it, tree)) orelse return null;
498 const if_prefix = if_node.cast(Node.If).?;
499
500 const block_expr = (try parseBlockExpr(arena, it, tree));
501 const assign_expr = if (block_expr == null) blk: {
502 break :blk (try parseAssignExpr(arena, it, tree)) orelse null;
503 } else null;
504
505 if (block_expr == null and assign_expr == null) {
506 try tree.errors.push(AstError{
507 .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index },
508 });
509 return error.ParseError;
510 }
1068511
1069 prevToken(&tok_it, tree);
1070 continue;
1071 },
1072 }
1073 },
1074 State.While => |ctx| {
1075 const node = try arena.create(ast.Node.While);
1076 node.* = ast.Node.While{
1077 .base = ast.Node{ .id = ast.Node.Id.While },
1078 .label = ctx.label,
1079 .inline_token = ctx.inline_token,
1080 .while_token = ctx.loop_token,
1081 .condition = undefined,
1082 .payload = null,
1083 .continue_expr = null,
1084 .body = undefined,
1085 .@"else" = null,
1086 };
1087 ctx.opt_ctx.store(&node.base);
1088 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
1089 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
1090 try stack.append(State{ .WhileContinueExpr = &node.continue_expr });
1091 try stack.append(State{ .IfToken = Token.Id.Colon });
1092 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
1093 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1094 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
1095 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1096 continue;
1097 },
1098 State.WhileContinueExpr => |dest| {
1099 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
1100 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = dest } });
1101 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1102 continue;
1103 },
1104 State.For => |ctx| {
1105 const node = try arena.create(ast.Node.For);
1106 node.* = ast.Node.For{
1107 .base = ast.Node{ .id = ast.Node.Id.For },
1108 .label = ctx.label,
1109 .inline_token = ctx.inline_token,
1110 .for_token = ctx.loop_token,
1111 .array_expr = undefined,
1112 .payload = null,
1113 .body = undefined,
1114 .@"else" = null,
1115 };
1116 ctx.opt_ctx.store(&node.base);
1117 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
1118 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
1119 try stack.append(State{ .PointerIndexPayload = OptionalCtx{ .Optional = &node.payload } });
1120 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1121 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.array_expr } });
1122 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1123 continue;
1124 },
1125 State.Else => |dest| {
1126 if (eatToken(&tok_it, tree, Token.Id.Keyword_else)) |else_token| {
1127 const node = try arena.create(ast.Node.Else);
1128 node.* = ast.Node.Else{
1129 .base = ast.Node{ .id = ast.Node.Id.Else },
1130 .else_token = else_token,
1131 .payload = null,
1132 .body = undefined,
1133 };
1134 dest.* = node;
512 const semicolon = if (assign_expr != null) eatToken(it, .Semicolon) else null;
513
514 const else_node = if (semicolon == null) blk: {
515 const else_token = eatToken(it, .Keyword_else) orelse break :blk null;
516 const payload = try parsePayload(arena, it, tree);
517 const else_body = try expectNode(arena, it, tree, parseStatement, AstError{
518 .InvalidToken = AstError.InvalidToken{ .token = it.index },
519 });
520
521 const node = try arena.create(Node.Else);
522 node.* = Node.Else{
523 .base = Node{ .id = .Else },
524 .else_token = else_token,
525 .payload = payload,
526 .body = else_body,
527 };
528
529 break :blk node;
530 } else null;
531
532 if (block_expr) |body| {
533 if_prefix.body = body;
534 if_prefix.@"else" = else_node;
535 return if_node;
536 }
1135537
1136 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable;
1137 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
1138 continue;
1139 } else {
1140 continue;
1141 }
1142 },
538 if (assign_expr) |body| {
539 if_prefix.body = body;
540 if (semicolon != null) return if_node;
541 if (else_node != null) {
542 if_prefix.@"else" = else_node;
543 return if_node;
544 }
545 try tree.errors.push(AstError{
546 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },
547 });
548 return error.ParseError;
549 }
1143550
1144 State.Block => |block| {
1145 const token = nextToken(&tok_it, tree);
1146 const token_index = token.index;
1147 const token_ptr = token.ptr;
1148 switch (token_ptr.id) {
1149 Token.Id.RBrace => {
1150 block.rbrace = token_index;
1151 continue;
1152 },
1153 else => {
1154 prevToken(&tok_it, tree);
1155 stack.append(State{ .Block = block }) catch unreachable;
551 unreachable;
552}
1156553
1157 try stack.append(State{ .Statement = block });
1158 continue;
1159 },
1160 }
1161 },
1162 State.Statement => |block| {
1163 const token = nextToken(&tok_it, tree);
1164 const token_index = token.index;
1165 const token_ptr = token.ptr;
1166 switch (token_ptr.id) {
1167 Token.Id.Keyword_comptime => {
1168 stack.append(State{
1169 .ComptimeStatement = ComptimeStatementCtx{
1170 .comptime_token = token_index,
1171 .block = block,
1172 },
1173 }) catch unreachable;
1174 continue;
1175 },
1176 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1177 stack.append(State{
1178 .VarDecl = VarDeclCtx{
1179 .comments = null,
1180 .visib_token = null,
1181 .thread_local_token = null,
1182 .comptime_token = null,
1183 .extern_export_token = null,
1184 .lib_name = null,
1185 .mut_token = token_index,
1186 .list = &block.statements,
1187 },
1188 }) catch unreachable;
1189 continue;
1190 },
1191 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1192 const node = try arena.create(ast.Node.Defer);
1193 node.* = ast.Node.Defer{
1194 .base = ast.Node{ .id = ast.Node.Id.Defer },
1195 .defer_token = token_index,
1196 .expr = undefined,
1197 };
1198 const node_ptr = try block.statements.addOne();
1199 node_ptr.* = &node.base;
554/// LabeledStatement <- BlockLabel? (Block / LoopStatement)
555fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
556 const label_token = parseBlockLabel(arena, it, tree);
1200557
1201 stack.append(State{ .Semicolon = node_ptr }) catch unreachable;
1202 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1203 continue;
1204 },
1205 Token.Id.LBrace => {
1206 const inner_block = try arena.create(ast.Node.Block);
1207 inner_block.* = ast.Node.Block{
1208 .base = ast.Node{ .id = ast.Node.Id.Block },
1209 .label = null,
1210 .lbrace = token_index,
1211 .statements = ast.Node.Block.StatementList.init(arena),
1212 .rbrace = undefined,
1213 };
1214 try block.statements.push(&inner_block.base);
558 if (try parseBlock(arena, it, tree)) |node| {
559 node.cast(Node.Block).?.label = label_token;
560 return node;
561 }
1215562
1216 stack.append(State{ .Block = inner_block }) catch unreachable;
1217 continue;
1218 },
1219 else => {
1220 prevToken(&tok_it, tree);
1221 const statement = try block.statements.addOne();
1222 try stack.append(State{ .Semicolon = statement });
1223 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1224 continue;
1225 },
1226 }
1227 },
1228 State.ComptimeStatement => |ctx| {
1229 const token = nextToken(&tok_it, tree);
1230 const token_index = token.index;
1231 const token_ptr = token.ptr;
1232 switch (token_ptr.id) {
1233 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1234 stack.append(State{
1235 .VarDecl = VarDeclCtx{
1236 .comments = null,
1237 .visib_token = null,
1238 .thread_local_token = null,
1239 .comptime_token = ctx.comptime_token,
1240 .extern_export_token = null,
1241 .lib_name = null,
1242 .mut_token = token_index,
1243 .list = &ctx.block.statements,
1244 },
1245 }) catch unreachable;
1246 continue;
1247 },
1248 else => {
1249 prevToken(&tok_it, tree);
1250 prevToken(&tok_it, tree);
1251 const statement = try ctx.block.statements.addOne();
1252 try stack.append(State{ .Semicolon = statement });
1253 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });
1254 continue;
1255 },
1256 }
1257 },
1258 State.Semicolon => |node_ptr| {
1259 const node = node_ptr.*;
1260 if (node.requireSemiColon()) {
1261 stack.append(State{ .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1262 continue;
1263 }
1264 continue;
1265 },
563 if (try parseLoopStatement(arena, it, tree)) |node| {
564 if (node.cast(Node.For)) |for_node| {
565 for_node.label = label_token;
566 } else if (node.cast(Node.While)) |while_node| {
567 while_node.label = label_token;
568 } else unreachable;
569 return node;
570 }
1266571
1267 State.AsmOutputItems => |items| {
1268 const lbracket = nextToken(&tok_it, tree);
1269 const lbracket_index = lbracket.index;
1270 const lbracket_ptr = lbracket.ptr;
1271 if (lbracket_ptr.id != Token.Id.LBracket) {
1272 prevToken(&tok_it, tree);
1273 continue;
1274 }
572 if (label_token != null) {
573 try tree.errors.push(AstError{
574 .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index },
575 });
576 return error.ParseError;
577 }
1275578
1276 const node = try arena.create(ast.Node.AsmOutput);
1277 node.* = ast.Node.AsmOutput{
1278 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1279 .lbracket = lbracket_index,
1280 .symbolic_name = undefined,
1281 .constraint = undefined,
1282 .kind = undefined,
1283 .rparen = undefined,
1284 };
1285 try items.push(node);
1286
1287 stack.append(State{ .AsmOutputItems = items }) catch unreachable;
1288 try stack.append(State{ .IfToken = Token.Id.Comma });
1289 try stack.append(State{
1290 .ExpectTokenSave = ExpectTokenSave{
1291 .id = Token.Id.RParen,
1292 .ptr = &node.rparen,
1293 },
1294 });
1295 try stack.append(State{ .AsmOutputReturnOrType = node });
1296 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1297 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1298 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1299 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1300 continue;
1301 },
1302 State.AsmOutputReturnOrType => |node| {
1303 const token = nextToken(&tok_it, tree);
1304 const token_index = token.index;
1305 const token_ptr = token.ptr;
1306 switch (token_ptr.id) {
1307 Token.Id.Identifier => {
1308 node.kind = ast.Node.AsmOutput.Kind{ .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1309 continue;
1310 },
1311 Token.Id.Arrow => {
1312 node.kind = ast.Node.AsmOutput.Kind{ .Return = undefined };
1313 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.kind.Return } });
1314 continue;
1315 },
1316 else => {
1317 ((try tree.errors.addOne())).* = Error{ .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType{ .token = token_index } };
1318 return tree;
1319 },
1320 }
1321 },
1322 State.AsmInputItems => |items| {
1323 const lbracket = nextToken(&tok_it, tree);
1324 const lbracket_index = lbracket.index;
1325 const lbracket_ptr = lbracket.ptr;
1326 if (lbracket_ptr.id != Token.Id.LBracket) {
1327 prevToken(&tok_it, tree);
1328 continue;
1329 }
579 return null;
580}
1330581
1331 const node = try arena.create(ast.Node.AsmInput);
1332 node.* = ast.Node.AsmInput{
1333 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1334 .lbracket = lbracket_index,
1335 .symbolic_name = undefined,
1336 .constraint = undefined,
1337 .expr = undefined,
1338 .rparen = undefined,
1339 };
1340 try items.push(node);
1341
1342 stack.append(State{ .AsmInputItems = items }) catch unreachable;
1343 try stack.append(State{ .IfToken = Token.Id.Comma });
1344 try stack.append(State{
1345 .ExpectTokenSave = ExpectTokenSave{
1346 .id = Token.Id.RParen,
1347 .ptr = &node.rparen,
1348 },
1349 });
1350 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1351 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1352 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1353 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1354 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1355 continue;
1356 },
1357 State.AsmClobberItems => |items| {
1358 while (eatToken(&tok_it, tree, Token.Id.StringLiteral)) |strlit| {
1359 try items.push(strlit);
1360 if (eatToken(&tok_it, tree, Token.Id.Comma) == null)
1361 break;
1362 }
1363 continue;
1364 },
582/// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
583fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
584 const inline_token = eatToken(it, .Keyword_inline);
1365585
1366 State.ExprListItemOrEnd => |list_state| {
1367 if (eatToken(&tok_it, tree, list_state.end)) |token_index| {
1368 (list_state.ptr).* = token_index;
1369 continue;
1370 }
586 if (try parseForStatement(arena, it, tree)) |node| {
587 node.cast(Node.For).?.inline_token = inline_token;
588 return node;
589 }
1371590
1372 stack.append(State{ .ExprListCommaOrEnd = list_state }) catch unreachable;
1373 try stack.append(State{ .Expression = OptionalCtx{ .Required = try list_state.list.addOne() } });
1374 continue;
1375 },
1376 State.ExprListCommaOrEnd => |list_state| {
1377 switch (expectCommaOrEnd(&tok_it, tree, list_state.end)) {
1378 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1379 (list_state.ptr).* = end;
1380 continue;
1381 } else {
1382 stack.append(State{ .ExprListItemOrEnd = list_state }) catch unreachable;
1383 continue;
1384 },
1385 ExpectCommaOrEndResult.parse_error => |e| {
1386 try tree.errors.push(e);
1387 return tree;
1388 },
1389 }
1390 },
1391 State.FieldInitListItemOrEnd => |list_state| {
1392 if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| {
1393 (list_state.ptr).* = rbrace;
1394 continue;
1395 }
591 if (try parseWhileStatement(arena, it, tree)) |node| {
592 node.cast(Node.While).?.inline_token = inline_token;
593 return node;
594 }
1396595
1397 const node = try arena.create(ast.Node.FieldInitializer);
1398 node.* = ast.Node.FieldInitializer{
1399 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
1400 .period_token = undefined,
1401 .name_token = undefined,
1402 .expr = undefined,
1403 };
1404 try list_state.list.push(&node.base);
1405
1406 stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1407 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1408 try stack.append(State{ .ExpectToken = Token.Id.Equal });
1409 try stack.append(State{
1410 .ExpectTokenSave = ExpectTokenSave{
1411 .id = Token.Id.Identifier,
1412 .ptr = &node.name_token,
1413 },
1414 });
1415 try stack.append(State{
1416 .ExpectTokenSave = ExpectTokenSave{
1417 .id = Token.Id.Period,
1418 .ptr = &node.period_token,
1419 },
1420 });
1421 continue;
1422 },
1423 State.FieldInitListCommaOrEnd => |list_state| {
1424 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) {
1425 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1426 (list_state.ptr).* = end;
1427 continue;
1428 } else {
1429 stack.append(State{ .FieldInitListItemOrEnd = list_state }) catch unreachable;
1430 continue;
1431 },
1432 ExpectCommaOrEndResult.parse_error => |e| {
1433 try tree.errors.push(e);
1434 return tree;
1435 },
1436 }
1437 },
1438 State.FieldListCommaOrEnd => |field_ctx| {
1439 const end_token = nextToken(&tok_it, tree);
1440 const end_token_index = end_token.index;
1441 const end_token_ptr = end_token.ptr;
1442 switch (end_token_ptr.id) {
1443 Token.Id.Comma => {
1444 if (eatToken(&tok_it, tree, Token.Id.DocComment)) |doc_comment_token| {
1445 const loc = tree.tokenLocation(end_token_ptr.end, doc_comment_token);
1446 if (loc.line == 0) {
1447 try pushDocComment(arena, doc_comment_token, field_ctx.doc_comments);
1448 } else {
1449 prevToken(&tok_it, tree);
1450 }
1451 }
596 return null;
597}
1452598
1453 try stack.append(State{ .ContainerDecl = field_ctx.container_decl });
1454 continue;
1455 },
1456 Token.Id.RBrace => {
1457 field_ctx.container_decl.rbrace_token = end_token_index;
1458 continue;
1459 },
1460 else => {
1461 try tree.errors.push(Error{
1462 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd{
1463 .token = end_token_index,
1464 .end_id = end_token_ptr.id,
1465 },
1466 });
1467 return tree;
1468 },
1469 }
1470 },
1471 State.ErrorTagListItemOrEnd => |list_state| {
1472 if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| {
1473 (list_state.ptr).* = rbrace;
1474 continue;
1475 }
599/// ForStatement
600/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
601/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
602fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
603 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
604 const for_prefix = node.cast(Node.For).?;
605
606 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {
607 for_prefix.body = block_expr_node;
608
609 if (eatToken(it, .Keyword_else)) |else_token| {
610 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{
611 .InvalidToken = AstError.InvalidToken{ .token = it.index },
612 });
613
614 const else_node = try arena.create(Node.Else);
615 else_node.* = Node.Else{
616 .base = Node{ .id = .Else },
617 .else_token = else_token,
618 .payload = null,
619 .body = statement_node,
620 };
621 for_prefix.@"else" = else_node;
1476622
1477 const node_ptr = try list_state.list.addOne();
623 return node;
624 }
1478625
1479 try stack.append(State{ .ErrorTagListCommaOrEnd = list_state });
1480 try stack.append(State{ .ErrorTag = node_ptr });
1481 continue;
1482 },
1483 State.ErrorTagListCommaOrEnd => |list_state| {
1484 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) {
1485 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1486 (list_state.ptr).* = end;
1487 continue;
1488 } else {
1489 stack.append(State{ .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1490 continue;
1491 },
1492 ExpectCommaOrEndResult.parse_error => |e| {
1493 try tree.errors.push(e);
1494 return tree;
1495 },
1496 }
1497 },
1498 State.SwitchCaseOrEnd => |list_state| {
1499 if (eatToken(&tok_it, tree, Token.Id.RBrace)) |rbrace| {
1500 (list_state.ptr).* = rbrace;
1501 continue;
1502 }
626 return node;
627 }
1503628
1504 const comments = try eatDocComments(arena, &tok_it, tree);
1505 const node = try arena.create(ast.Node.SwitchCase);
1506 node.* = ast.Node.SwitchCase{
1507 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },
1508 .items = ast.Node.SwitchCase.ItemList.init(arena),
1509 .payload = null,
1510 .expr = undefined,
1511 .arrow_token = undefined,
1512 };
1513 try list_state.list.push(&node.base);
1514 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
1515 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1516 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
1517 try stack.append(State{ .SwitchCaseFirstItem = node });
629 if (try parseAssignExpr(arena, it, tree)) |assign_expr| {
630 for_prefix.body = assign_expr;
1518631
1519 continue;
1520 },
632 if (eatToken(it, .Semicolon) != null) return node;
1521633
1522 State.SwitchCaseCommaOrEnd => |list_state| {
1523 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.RBrace)) {
1524 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1525 (list_state.ptr).* = end;
1526 continue;
1527 } else {
1528 try stack.append(State{ .SwitchCaseOrEnd = list_state });
1529 continue;
1530 },
1531 ExpectCommaOrEndResult.parse_error => |e| {
1532 try tree.errors.push(e);
1533 return tree;
1534 },
1535 }
1536 },
634 if (eatToken(it, .Keyword_else)) |else_token| {
635 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{
636 .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index },
637 });
1537638
1538 State.SwitchCaseFirstItem => |switch_case| {
1539 const token = nextToken(&tok_it, tree);
1540 const token_index = token.index;
1541 const token_ptr = token.ptr;
1542 if (token_ptr.id == Token.Id.Keyword_else) {
1543 const else_node = try arena.create(ast.Node.SwitchElse);
1544 else_node.* = ast.Node.SwitchElse{
1545 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
1546 .token = token_index,
1547 };
1548 try switch_case.items.push(&else_node.base);
639 const else_node = try arena.create(Node.Else);
640 else_node.* = Node.Else{
641 .base = Node{ .id = .Else },
642 .else_token = else_token,
643 .payload = null,
644 .body = statement_node,
645 };
646 for_prefix.@"else" = else_node;
647 return node;
648 }
1549649
1550 try stack.append(State{
1551 .ExpectTokenSave = ExpectTokenSave{
1552 .id = Token.Id.EqualAngleBracketRight,
1553 .ptr = &switch_case.arrow_token,
1554 },
1555 });
1556 continue;
1557 } else {
1558 prevToken(&tok_it, tree);
1559 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1560 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1561 continue;
1562 }
650 try tree.errors.push(AstError{
651 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },
652 });
653 return null;
654 }
655
656 return null;
657}
658
659/// WhileStatement
660/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
661/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
662fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
663 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
664 const while_prefix = node.cast(Node.While).?;
665
666 if (try parseBlockExpr(arena, it, tree)) |block_expr_node| {
667 while_prefix.body = block_expr_node;
668
669 if (eatToken(it, .Keyword_else)) |else_token| {
670 const payload = try parsePayload(arena, it, tree);
671
672 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{
673 .InvalidToken = AstError.InvalidToken{ .token = it.index },
674 });
675
676 const else_node = try arena.create(Node.Else);
677 else_node.* = Node.Else{
678 .base = Node{ .id = .Else },
679 .else_token = else_token,
680 .payload = payload,
681 .body = statement_node,
682 };
683 while_prefix.@"else" = else_node;
684
685 return node;
686 }
687
688 return node;
689 }
690
691 if (try parseAssignExpr(arena, it, tree)) |assign_expr_node| {
692 while_prefix.body = assign_expr_node;
693
694 if (eatToken(it, .Semicolon) != null) return node;
695
696 if (eatToken(it, .Keyword_else)) |else_token| {
697 const payload = try parsePayload(arena, it, tree);
698
699 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{
700 .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index },
701 });
702
703 const else_node = try arena.create(Node.Else);
704 else_node.* = Node.Else{
705 .base = Node{ .id = .Else },
706 .else_token = else_token,
707 .payload = payload,
708 .body = statement_node,
709 };
710 while_prefix.@"else" = else_node;
711 return node;
712 }
713
714 try tree.errors.push(AstError{
715 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },
716 });
717 return null;
718 }
719
720 return null;
721}
722
723/// BlockExprStatement
724/// <- BlockExpr
725/// / AssignExpr SEMICOLON
726fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
727 if (try parseBlockExpr(arena, it, tree)) |node| return node;
728 if (try parseAssignExpr(arena, it, tree)) |node| {
729 _ = try expectToken(it, tree, .Semicolon);
730 return node;
731 }
732 return null;
733}
734
735/// BlockExpr <- BlockLabel? Block
736fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
737 const label_token = parseBlockLabel(arena, it, tree);
738 const block_node = (try parseBlock(arena, it, tree)) orelse {
739 if (label_token) |label| {
740 putBackToken(it, label + 1); // ":"
741 putBackToken(it, label); // IDENTIFIER
742 }
743 return null;
744 };
745 block_node.cast(Node.Block).?.label = label_token;
746 return block_node;
747}
748
749/// AssignExpr <- Expr (AssignOp Expr)?
750fn parseAssignExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
751 return parseBinOpExpr(arena, it, tree, parseAssignOp, parseExpr, .Once);
752}
753
754/// Expr <- KEYWORD_try* BoolOrExpr
755fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
756 return parsePrefixOpExpr(arena, it, tree, parseTry, parseBoolOrExpr);
757}
758
759/// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
760fn parseBoolOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
761 return parseBinOpExpr(
762 arena,
763 it,
764 tree,
765 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
766 parseBoolAndExpr,
767 .Infinitely,
768 );
769}
770
771/// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
772fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
773 return parseBinOpExpr(
774 arena,
775 it,
776 tree,
777 SimpleBinOpParseFn(.Keyword_and, Node.InfixOp.Op.BoolAnd),
778 parseCompareExpr,
779 .Infinitely,
780 );
781}
782
783/// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
784fn parseCompareExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
785 return parseBinOpExpr(arena, it, tree, parseCompareOp, parseBitwiseExpr, .Once);
786}
787
788/// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
789fn parseBitwiseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
790 return parseBinOpExpr(arena, it, tree, parseBitwiseOp, parseBitShiftExpr, .Infinitely);
791}
792
793/// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
794fn parseBitShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
795 return parseBinOpExpr(arena, it, tree, parseBitShiftOp, parseAdditionExpr, .Infinitely);
796}
797
798/// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
799fn parseAdditionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
800 return parseBinOpExpr(arena, it, tree, parseAdditionOp, parseMultiplyExpr, .Infinitely);
801}
802
803/// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
804fn parseMultiplyExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
805 return parseBinOpExpr(arena, it, tree, parseMultiplyOp, parsePrefixExpr, .Infinitely);
806}
807
808/// PrefixExpr <- PrefixOp* PrimaryExpr
809fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
810 return parsePrefixOpExpr(arena, it, tree, parsePrefixOp, parsePrimaryExpr);
811}
812
813/// PrimaryExpr
814/// <- AsmExpr
815/// / IfExpr
816/// / KEYWORD_break BreakLabel? Expr?
817/// / KEYWORD_cancel Expr
818/// / KEYWORD_comptime Expr
819/// / KEYWORD_continue BreakLabel?
820/// / KEYWORD_resume Expr
821/// / KEYWORD_return Expr?
822/// / BlockLabel? LoopExpr
823/// / Block
824/// / CurlySuffixExpr
825fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
826 if (try parseAsmExpr(arena, it, tree)) |node| return node;
827 if (try parseIfExpr(arena, it, tree)) |node| return node;
828
829 if (eatToken(it, .Keyword_break)) |token| {
830 const label = try parseBreakLabel(arena, it, tree);
831 const expr_node = try parseExpr(arena, it, tree);
832 const node = try arena.create(Node.ControlFlowExpression);
833 node.* = Node.ControlFlowExpression{
834 .base = Node{ .id = .ControlFlowExpression },
835 .ltoken = token,
836 .kind = Node.ControlFlowExpression.Kind{ .Break = label },
837 .rhs = expr_node,
838 };
839 return &node.base;
840 }
841
842 if (eatToken(it, .Keyword_cancel)) |token| {
843 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
844 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
845 });
846 const node = try arena.create(Node.PrefixOp);
847 node.* = Node.PrefixOp{
848 .base = Node{ .id = .PrefixOp },
849 .op_token = token,
850 .op = Node.PrefixOp.Op.Cancel,
851 .rhs = expr_node,
852 };
853 return &node.base;
854 }
855
856 if (eatToken(it, .Keyword_comptime)) |token| {
857 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
858 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
859 });
860 const node = try arena.create(Node.Comptime);
861 node.* = Node.Comptime{
862 .base = Node{ .id = .Comptime },
863 .doc_comments = null,
864 .comptime_token = token,
865 .expr = expr_node,
866 };
867 return &node.base;
868 }
869
870 if (eatToken(it, .Keyword_continue)) |token| {
871 const label = try parseBreakLabel(arena, it, tree);
872 const node = try arena.create(Node.ControlFlowExpression);
873 node.* = Node.ControlFlowExpression{
874 .base = Node{ .id = .ControlFlowExpression },
875 .ltoken = token,
876 .kind = Node.ControlFlowExpression.Kind{ .Continue = label },
877 .rhs = null,
878 };
879 return &node.base;
880 }
881
882 if (eatToken(it, .Keyword_resume)) |token| {
883 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
884 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
885 });
886 const node = try arena.create(Node.PrefixOp);
887 node.* = Node.PrefixOp{
888 .base = Node{ .id = .PrefixOp },
889 .op_token = token,
890 .op = Node.PrefixOp.Op.Resume,
891 .rhs = expr_node,
892 };
893 return &node.base;
894 }
895
896 if (eatToken(it, .Keyword_return)) |token| {
897 const expr_node = try parseExpr(arena, it, tree);
898 const node = try arena.create(Node.ControlFlowExpression);
899 node.* = Node.ControlFlowExpression{
900 .base = Node{ .id = .ControlFlowExpression },
901 .ltoken = token,
902 .kind = Node.ControlFlowExpression.Kind.Return,
903 .rhs = expr_node,
904 };
905 return &node.base;
906 }
907
908 const label = parseBlockLabel(arena, it, tree);
909 if (try parseLoopExpr(arena, it, tree)) |node| {
910 if (node.cast(Node.For)) |for_node| {
911 for_node.label = label;
912 } else if (node.cast(Node.While)) |while_node| {
913 while_node.label = label;
914 } else unreachable;
915 return node;
916 }
917 if (label) |token| {
918 putBackToken(it, token + 1); // ":"
919 putBackToken(it, token); // IDENTIFIER
920 }
921
922 if (try parseBlock(arena, it, tree)) |node| return node;
923 if (try parseCurlySuffixExpr(arena, it, tree)) |node| return node;
924
925 return null;
926}
927
928/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
929fn parseIfExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
930 return parseIf(arena, it, tree, parseExpr);
931}
932
933/// Block <- LBRACE Statement* RBRACE
934fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
935 const lbrace = eatToken(it, .LBrace) orelse return null;
936
937 var statements = Node.Block.StatementList.init(arena);
938 while (true) {
939 const statement = (try parseStatement(arena, it, tree)) orelse break;
940 try statements.push(statement);
941 }
942
943 const rbrace = try expectToken(it, tree, .RBrace);
944
945 const block_node = try arena.create(Node.Block);
946 block_node.* = Node.Block{
947 .base = Node{ .id = .Block },
948 .label = null,
949 .lbrace = lbrace,
950 .statements = statements,
951 .rbrace = rbrace,
952 };
953
954 return &block_node.base;
955}
956
957/// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
958fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
959 const inline_token = eatToken(it, .Keyword_inline);
960
961 if (try parseForExpr(arena, it, tree)) |node| {
962 node.cast(Node.For).?.inline_token = inline_token;
963 return node;
964 }
965
966 if (try parseWhileExpr(arena, it, tree)) |node| {
967 node.cast(Node.While).?.inline_token = inline_token;
968 return node;
969 }
970
971 if (inline_token == null) return null;
972
973 // If we've seen "inline", there should have been a "for" or "while"
974 try tree.errors.push(AstError{
975 .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index },
976 });
977 return error.ParseError;
978}
979
980/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
981fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
982 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
983 const for_prefix = node.cast(Node.For).?;
984
985 const body_node = try expectNode(arena, it, tree, parseExpr, AstError{
986 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
987 });
988 for_prefix.body = body_node;
989
990 if (eatToken(it, .Keyword_else)) |else_token| {
991 const body = try expectNode(arena, it, tree, parseExpr, AstError{
992 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
993 });
994
995 const else_node = try arena.create(Node.Else);
996 else_node.* = Node.Else{
997 .base = Node{ .id = .Else },
998 .else_token = else_token,
999 .payload = null,
1000 .body = body,
1001 };
1002
1003 for_prefix.@"else" = else_node;
1004 }
1005
1006 return node;
1007}
1008
1009/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
1010fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1011 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1012 const while_prefix = node.cast(Node.While).?;
1013
1014 const body_node = try expectNode(arena, it, tree, parseExpr, AstError{
1015 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1016 });
1017 while_prefix.body = body_node;
1018
1019 if (eatToken(it, .Keyword_else)) |else_token| {
1020 const payload = try parsePayload(arena, it, tree);
1021 const body = try expectNode(arena, it, tree, parseExpr, AstError{
1022 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1023 });
1024
1025 const else_node = try arena.create(Node.Else);
1026 else_node.* = Node.Else{
1027 .base = Node{ .id = .Else },
1028 .else_token = else_token,
1029 .payload = null,
1030 .body = body,
1031 };
1032
1033 while_prefix.@"else" = else_node;
1034 }
1035
1036 return node;
1037}
1038
1039/// CurlySuffixExpr <- TypeExpr InitList?
1040fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1041 const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
1042 const init_list = (try parseInitList(arena, it, tree)) orelse return type_expr;
1043 init_list.cast(Node.SuffixOp).?.lhs = type_expr;
1044 return init_list;
1045}
1046
1047/// InitList
1048/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
1049/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
1050/// / LBRACE RBRACE
1051fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1052 const lbrace = eatToken(it, .LBrace) orelse return null;
1053 var init_list = Node.SuffixOp.Op.InitList.init(arena);
1054
1055 const op = blk: {
1056 if (try parseFieldInit(arena, it, tree)) |field_init| {
1057 try init_list.push(field_init);
1058 while (eatToken(it, .Comma)) |_| {
1059 const next = (try parseFieldInit(arena, it, tree)) orelse break;
1060 try init_list.push(next);
1061 }
1062 break :blk Node.SuffixOp.Op{ .StructInitializer = init_list };
1063 }
1064
1065 if (try parseExpr(arena, it, tree)) |expr| {
1066 try init_list.push(expr);
1067 while (eatToken(it, .Comma)) |_| {
1068 const next = (try parseExpr(arena, it, tree)) orelse break;
1069 try init_list.push(next);
1070 }
1071 break :blk Node.SuffixOp.Op{ .ArrayInitializer = init_list };
1072 }
1073
1074 break :blk Node.SuffixOp.Op{ .StructInitializer = init_list };
1075 };
1076
1077 const node = try arena.create(Node.SuffixOp);
1078 node.* = Node.SuffixOp{
1079 .base = Node{ .id = .SuffixOp },
1080 .lhs = undefined, // set by caller
1081 .op = op,
1082 .rtoken = try expectToken(it, tree, .RBrace),
1083 };
1084 return &node.base;
1085}
1086
1087/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1088fn parseTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
1089 return parsePrefixOpExpr(arena, it, tree, parsePrefixTypeOp, parseErrorUnionExpr);
1090}
1091
1092/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
1093fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1094 const suffix_expr = (try parseSuffixExpr(arena, it, tree)) orelse return null;
1095
1096 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| {
1097 const error_union = node.cast(Node.InfixOp).?;
1098 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1099 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1100 });
1101 error_union.lhs = suffix_expr;
1102 error_union.rhs = type_expr;
1103 return node;
1104 }
1105
1106 return suffix_expr;
1107}
1108
1109/// SuffixExpr
1110/// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
1111/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1112fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1113 if (try parseAsyncPrefix(arena, it, tree)) |async_node| {
1114 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
1115 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{
1116 .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index },
1117 });
1118
1119 while (try parseSuffixOp(arena, it, tree)) |node| {
1120 switch (node.id) {
1121 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1122 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1123 else => unreachable,
1124 }
1125 res = node;
1126 }
1127
1128 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
1129 try tree.errors.push(AstError{
1130 .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index },
1131 });
1132 return null;
1133 };
1134
1135 const node = try arena.create(Node.SuffixOp);
1136 node.* = Node.SuffixOp{
1137 .base = Node{ .id = .SuffixOp },
1138 .lhs = res,
1139 .op = Node.SuffixOp.Op{
1140 .Call = Node.SuffixOp.Op.Call{
1141 .params = params.list,
1142 .async_attr = async_node.cast(Node.AsyncAttribute).?,
1143 },
15631144 },
1564 State.SwitchCaseItemOrEnd => |switch_case| {
1565 const token = nextToken(&tok_it, tree);
1566 if (token.ptr.id == Token.Id.EqualAngleBracketRight) {
1567 switch_case.arrow_token = token.index;
1568 continue;
1569 } else {
1570 prevToken(&tok_it, tree);
1571 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1572 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1573 continue;
1145 .rtoken = params.rparen,
1146 };
1147 return &node.base;
1148 }
1149
1150 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
1151 var res = expr;
1152
1153 while (true) {
1154 if (try parseSuffixOp(arena, it, tree)) |node| {
1155 switch (node.id) {
1156 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1157 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1158 else => unreachable,
15741159 }
1575 },
1576 State.SwitchCaseItemCommaOrEnd => |switch_case| {
1577 switch (expectCommaOrEnd(&tok_it, tree, Token.Id.EqualAngleBracketRight)) {
1578 ExpectCommaOrEndResult.end_token => |end_token| {
1579 if (end_token) |t| {
1580 switch_case.arrow_token = t;
1581 } else {
1582 stack.append(State{ .SwitchCaseItemOrEnd = switch_case }) catch unreachable;
1583 }
1584 continue;
1585 },
1586 ExpectCommaOrEndResult.parse_error => |e| {
1587 try tree.errors.push(e);
1588 return tree;
1160 res = node;
1161 continue;
1162 }
1163 if (try parseFnCallArguments(arena, it, tree)) |params| {
1164 const call = try arena.create(Node.SuffixOp);
1165 call.* = Node.SuffixOp{
1166 .base = Node{ .id = .SuffixOp },
1167 .lhs = res,
1168 .op = Node.SuffixOp.Op{
1169 .Call = Node.SuffixOp.Op.Call{
1170 .params = params.list,
1171 .async_attr = null,
1172 },
15891173 },
1590 }
1174 .rtoken = params.rparen,
1175 };
1176 res = &call.base;
15911177 continue;
1592 },
1178 }
1179 break;
1180 }
1181 return res;
1182 }
15931183
1594 State.SuspendBody => |suspend_node| {
1595 const token = nextToken(&tok_it, tree);
1596 switch (token.ptr.id) {
1597 Token.Id.Semicolon => {
1598 prevToken(&tok_it, tree);
1599 continue;
1600 },
1601 Token.Id.LBrace => {
1602 prevToken(&tok_it, tree);
1603 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
1604 continue;
1605 },
1606 else => {
1607 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = token.index } };
1608 },
1609 }
1610 },
1611 State.AsyncAllocator => |async_node| {
1612 if (eatToken(&tok_it, tree, Token.Id.AngleBracketLeft) == null) {
1613 continue;
1614 }
1184 return null;
1185}
16151186
1616 async_node.rangle_bracket = TokenIndex(0);
1617 try stack.append(State{
1618 .ExpectTokenSave = ExpectTokenSave{
1619 .id = Token.Id.AngleBracketRight,
1620 .ptr = &async_node.rangle_bracket.?,
1621 },
1622 });
1623 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
1624 continue;
1625 },
1626 State.AsyncEnd => |ctx| {
1627 const node = ctx.ctx.get() orelse continue;
1187/// PrimaryTypeExpr
1188/// <- BUILTINIDENTIFIER FnCallArguments
1189/// / CHAR_LITERAL
1190/// / ContainerDecl
1191/// / DOT IDENTIFIER
1192/// / ErrorSetDecl
1193/// / FLOAT
1194/// / FnProto
1195/// / GroupedExpr
1196/// / LabeledTypeExpr
1197/// / IDENTIFIER
1198/// / IfTypeExpr
1199/// / INTEGER
1200/// / KEYWORD_anyerror
1201/// / KEYWORD_comptime TypeExpr
1202/// / KEYWORD_error DOT IDENTIFIER
1203/// / KEYWORD_false
1204/// / KEYWORD_null
1205/// / KEYWORD_promise
1206/// / KEYWORD_true
1207/// / KEYWORD_undefined
1208/// / KEYWORD_unreachable
1209/// / STRINGLITERAL
1210/// / SwitchExpr
1211fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1212 if (try parseBuiltinCall(arena, it, tree)) |node| return node;
1213 if (eatToken(it, .CharLiteral)) |token| {
1214 const node = try arena.create(Node.CharLiteral);
1215 node.* = Node.CharLiteral{
1216 .base = Node{ .id = .CharLiteral },
1217 .token = token,
1218 };
1219 return &node.base;
1220 }
1221 if (try parseContainerDecl(arena, it, tree)) |node| return node;
1222 if (try parseEnumLiteral(arena, it, tree)) |node| return node;
1223 if (try parseErrorSetDecl(arena, it, tree)) |node| return node;
1224 if (try parseFloatLiteral(arena, it, tree)) |node| return node;
1225 if (try parseFnProto(arena, it, tree)) |node| return node;
1226 if (try parseGroupedExpr(arena, it, tree)) |node| return node;
1227 if (try parseLabeledTypeExpr(arena, it, tree)) |node| return node;
1228 if (try parseIdentifier(arena, it, tree)) |node| return node;
1229 if (try parseIfTypeExpr(arena, it, tree)) |node| return node;
1230 if (try parseIntegerLiteral(arena, it, tree)) |node| return node;
1231 if (eatToken(it, .Keyword_anyerror)) |token| return createLiteral(arena, Node.ErrorType, token);
1232 if (eatToken(it, .Keyword_comptime)) |token| {
1233 const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
1234 const node = try arena.create(Node.Comptime);
1235 node.* = Node.Comptime{
1236 .base = Node{ .id = .Comptime },
1237 .doc_comments = null,
1238 .comptime_token = token,
1239 .expr = expr,
1240 };
1241 return &node.base;
1242 }
1243 if (eatToken(it, .Keyword_error)) |token| {
1244 const period = try expectToken(it, tree, .Period);
1245 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
1246 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1247 });
1248 const global_error_set = try createLiteral(arena, Node.ErrorType, token);
1249 const node = try arena.create(Node.InfixOp);
1250 node.* = Node.InfixOp{
1251 .base = Node{ .id = .InfixOp },
1252 .op_token = period,
1253 .lhs = global_error_set,
1254 .op = Node.InfixOp.Op.Period,
1255 .rhs = identifier,
1256 };
1257 return &node.base;
1258 }
1259 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1260 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1261 if (eatToken(it, .Keyword_promise)) |token| {
1262 const node = try arena.create(Node.PromiseType);
1263 node.* = Node.PromiseType{
1264 .base = Node{ .id = .PromiseType },
1265 .promise_token = token,
1266 .result = null,
1267 };
1268 return &node.base;
1269 }
1270 if (eatToken(it, .Keyword_true)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1271 if (eatToken(it, .Keyword_undefined)) |token| return createLiteral(arena, Node.UndefinedLiteral, token);
1272 if (eatToken(it, .Keyword_unreachable)) |token| return createLiteral(arena, Node.Unreachable, token);
1273 if (try parseStringLiteral(arena, it, tree)) |node| return node;
1274 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
16281275
1629 switch (node.id) {
1630 ast.Node.Id.FnProto => {
1631 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1632 fn_proto.async_attr = ctx.attribute;
1633 continue;
1634 },
1635 ast.Node.Id.SuffixOp => {
1636 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1637 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1638 suffix_op.op.Call.async_attr = ctx.attribute;
1639 continue;
1640 }
1276 return null;
1277}
16411278
1642 ((try tree.errors.addOne())).* = Error{ .ExpectedCall = Error.ExpectedCall{ .node = node } };
1643 return tree;
1644 },
1645 else => {
1646 ((try tree.errors.addOne())).* = Error{ .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto{ .node = node } };
1647 return tree;
1648 },
1649 }
1650 },
1279/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
1280fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1281 const layout_token = eatToken(it, .Keyword_extern) orelse
1282 eatToken(it, .Keyword_packed);
16511283
1652 State.ExternType => |ctx| {
1653 if (eatToken(&tok_it, tree, Token.Id.Keyword_fn)) |fn_token| {
1654 const fn_proto = try arena.create(ast.Node.FnProto);
1655 fn_proto.* = ast.Node.FnProto{
1656 .base = ast.Node{ .id = ast.Node.Id.FnProto },
1657 .doc_comments = ctx.comments,
1658 .visib_token = null,
1659 .name_token = null,
1660 .fn_token = fn_token,
1661 .params = ast.Node.FnProto.ParamList.init(arena),
1662 .return_type = undefined,
1663 .var_args_token = null,
1664 .extern_export_inline_token = ctx.extern_token,
1665 .cc_token = null,
1666 .async_attr = null,
1667 .body_node = null,
1668 .lib_name = null,
1669 .align_expr = null,
1670 .section_expr = null,
1671 };
1672 ctx.opt_ctx.store(&fn_proto.base);
1673 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
1674 continue;
1675 }
1284 const node = (try parseContainerDeclAuto(arena, it, tree)) orelse {
1285 if (layout_token) |token|
1286 putBackToken(it, token);
1287 return null;
1288 };
1289 node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
1290 return node;
1291}
16761292
1677 stack.append(State{
1678 .ContainerKind = ContainerKindCtx{
1679 .opt_ctx = ctx.opt_ctx,
1680 .layout_token = ctx.extern_token,
1681 },
1682 }) catch unreachable;
1683 continue;
1684 },
1685 State.SliceOrArrayAccess => |node| {
1686 const token = nextToken(&tok_it, tree);
1687 const token_index = token.index;
1688 const token_ptr = token.ptr;
1689 switch (token_ptr.id) {
1690 Token.Id.Ellipsis2 => {
1691 const start = node.op.ArrayAccess;
1692 node.op = ast.Node.SuffixOp.Op{
1693 .Slice = ast.Node.SuffixOp.Op.Slice{
1694 .start = start,
1695 .end = null,
1696 },
1697 };
1293/// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1294fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1295 const error_token = eatToken(it, .Keyword_error) orelse return null;
1296 if (eatToken(it, .LBrace) == null) {
1297 // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1298 putBackToken(it, error_token);
1299 return null;
1300 }
1301 const decls = try parseErrorTagList(arena, it, tree);
1302 const rbrace = try expectToken(it, tree, .RBrace);
1303
1304 const node = try arena.create(Node.ErrorSetDecl);
1305 node.* = Node.ErrorSetDecl{
1306 .base = Node{ .id = .ErrorSetDecl },
1307 .error_token = error_token,
1308 .decls = decls,
1309 .rbrace_token = rbrace,
1310 };
1311 return &node.base;
1312}
16981313
1699 stack.append(State{
1700 .ExpectTokenSave = ExpectTokenSave{
1701 .id = Token.Id.RBracket,
1702 .ptr = &node.rtoken,
1703 },
1704 }) catch unreachable;
1705 try stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.op.Slice.end } });
1706 continue;
1707 },
1708 Token.Id.RBracket => {
1709 node.rtoken = token_index;
1710 continue;
1711 },
1712 else => {
1713 ((try tree.errors.addOne())).* = Error{ .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket{ .token = token_index } };
1714 return tree;
1715 },
1716 }
1717 },
1718 State.SliceOrArrayType => |node| {
1719 if (eatToken(&tok_it, tree, Token.Id.RBracket)) |_| {
1720 node.op = ast.Node.PrefixOp.Op{
1721 .SliceType = ast.Node.PrefixOp.PtrInfo{
1722 .align_info = null,
1723 .const_token = null,
1724 .volatile_token = null,
1725 .allowzero_token = null,
1726 },
1727 };
1728 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1729 try stack.append(State{ .PtrTypeModifiers = &node.op.SliceType });
1730 continue;
1731 }
1314/// GroupedExpr <- LPAREN Expr RPAREN
1315fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1316 const lparen = eatToken(it, .LParen) orelse return null;
1317 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
1318 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1319 });
1320 const rparen = try expectToken(it, tree, .RParen);
1321
1322 const node = try arena.create(Node.GroupedExpression);
1323 node.* = Node.GroupedExpression{
1324 .base = Node{ .id = .GroupedExpression },
1325 .lparen = lparen,
1326 .expr = expr,
1327 .rparen = rparen,
1328 };
1329 return &node.base;
1330}
17321331
1733 node.op = ast.Node.PrefixOp.Op{ .ArrayType = undefined };
1734 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1735 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1736 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayType } });
1737 continue;
1738 },
1332/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1333fn parseIfTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1334 return parseIf(arena, it, tree, parseTypeExpr);
1335}
17391336
1740 State.PtrTypeModifiers => |addr_of_info| {
1741 const token = nextToken(&tok_it, tree);
1742 const token_index = token.index;
1743 const token_ptr = token.ptr;
1744 switch (token_ptr.id) {
1745 Token.Id.Keyword_align => {
1746 stack.append(state) catch unreachable;
1747 if (addr_of_info.align_info != null) {
1748 ((try tree.errors.addOne())).* = Error{ .ExtraAlignQualifier = Error.ExtraAlignQualifier{ .token = token_index } };
1749 return tree;
1750 }
1751 addr_of_info.align_info = ast.Node.PrefixOp.PtrInfo.Align{
1752 .node = undefined,
1753 .bit_range = null,
1754 };
1755 // TODO https://github.com/ziglang/zig/issues/1022
1756 const align_info = &addr_of_info.align_info.?;
1337/// LabeledTypeExpr
1338/// <- BlockLabel Block
1339/// / BlockLabel? LoopTypeExpr
1340fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1341 const label = parseBlockLabel(arena, it, tree);
17571342
1758 try stack.append(State{ .AlignBitRange = align_info });
1759 try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
1760 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1761 continue;
1762 },
1763 Token.Id.Keyword_const => {
1764 stack.append(state) catch unreachable;
1765 if (addr_of_info.const_token != null) {
1766 ((try tree.errors.addOne())).* = Error{ .ExtraConstQualifier = Error.ExtraConstQualifier{ .token = token_index } };
1767 return tree;
1768 }
1769 addr_of_info.const_token = token_index;
1770 continue;
1771 },
1772 Token.Id.Keyword_volatile => {
1773 stack.append(state) catch unreachable;
1774 if (addr_of_info.volatile_token != null) {
1775 ((try tree.errors.addOne())).* = Error{ .ExtraVolatileQualifier = Error.ExtraVolatileQualifier{ .token = token_index } };
1776 return tree;
1777 }
1778 addr_of_info.volatile_token = token_index;
1779 continue;
1780 },
1781 Token.Id.Keyword_allowzero => {
1782 stack.append(state) catch unreachable;
1783 if (addr_of_info.allowzero_token != null) {
1784 ((try tree.errors.addOne())).* = Error{ .ExtraAllowZeroQualifier = Error.ExtraAllowZeroQualifier{ .token = token_index } };
1785 return tree;
1786 }
1787 addr_of_info.allowzero_token = token_index;
1788 continue;
1789 },
1790 else => {
1791 prevToken(&tok_it, tree);
1792 continue;
1793 },
1794 }
1795 },
1343 if (label) |token| {
1344 if (try parseBlock(arena, it, tree)) |node| {
1345 node.cast(Node.Block).?.label = token;
1346 return node;
1347 }
1348 }
17961349
1797 State.AlignBitRange => |align_info| {
1798 const token = nextToken(&tok_it, tree);
1799 switch (token.ptr.id) {
1800 Token.Id.Colon => {
1801 align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined);
1802 const bit_range = &align_info.bit_range.?;
1803
1804 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1805 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
1806 try stack.append(State{ .ExpectToken = Token.Id.Colon });
1807 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.start } });
1808 continue;
1809 },
1810 Token.Id.RParen => continue,
1811 else => {
1812 (try tree.errors.addOne()).* = Error{
1813 .ExpectedColonOrRParen = Error.ExpectedColonOrRParen{ .token = token.index },
1814 };
1815 return tree;
1816 },
1817 }
1818 },
1350 if (try parseLoopTypeExpr(arena, it, tree)) |node| {
1351 switch (node.id) {
1352 .For => node.cast(Node.For).?.label = label,
1353 .While => node.cast(Node.While).?.label = label,
1354 else => unreachable,
1355 }
1356 return node;
1357 }
18191358
1820 State.Payload => |opt_ctx| {
1821 const token = nextToken(&tok_it, tree);
1822 const token_index = token.index;
1823 const token_ptr = token.ptr;
1824 if (token_ptr.id != Token.Id.Pipe) {
1825 if (opt_ctx != OptionalCtx.Optional) {
1826 ((try tree.errors.addOne())).* = Error{
1827 .ExpectedToken = Error.ExpectedToken{
1828 .token = token_index,
1829 .expected_id = Token.Id.Pipe,
1830 },
1831 };
1832 return tree;
1833 }
1359 if (label != null) {
1360 // If we saw a label, there should have been a block next
1361 try tree.errors.push(AstError{
1362 .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index },
1363 });
1364 return error.ParseError;
1365 }
1366 return null;
1367}
18341368
1835 prevToken(&tok_it, tree);
1836 continue;
1837 }
1369/// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1370fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1371 const inline_token = eatToken(it, .Keyword_inline);
18381372
1839 const node = try arena.create(ast.Node.Payload);
1840 node.* = ast.Node.Payload{
1841 .base = ast.Node{ .id = ast.Node.Id.Payload },
1842 .lpipe = token_index,
1843 .error_symbol = undefined,
1844 .rpipe = undefined,
1845 };
1846 opt_ctx.store(&node.base);
1373 if (try parseForTypeExpr(arena, it, tree)) |node| {
1374 node.cast(Node.For).?.inline_token = inline_token;
1375 return node;
1376 }
18471377
1848 stack.append(State{
1849 .ExpectTokenSave = ExpectTokenSave{
1850 .id = Token.Id.Pipe,
1851 .ptr = &node.rpipe,
1852 },
1853 }) catch unreachable;
1854 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.error_symbol } });
1855 continue;
1856 },
1857 State.PointerPayload => |opt_ctx| {
1858 const token = nextToken(&tok_it, tree);
1859 const token_index = token.index;
1860 const token_ptr = token.ptr;
1861 if (token_ptr.id != Token.Id.Pipe) {
1862 if (opt_ctx != OptionalCtx.Optional) {
1863 ((try tree.errors.addOne())).* = Error{
1864 .ExpectedToken = Error.ExpectedToken{
1865 .token = token_index,
1866 .expected_id = Token.Id.Pipe,
1867 },
1868 };
1869 return tree;
1870 }
1378 if (try parseWhileTypeExpr(arena, it, tree)) |node| {
1379 node.cast(Node.While).?.inline_token = inline_token;
1380 return node;
1381 }
18711382
1872 prevToken(&tok_it, tree);
1873 continue;
1874 }
1383 if (inline_token == null) return null;
18751384
1876 const node = try arena.create(ast.Node.PointerPayload);
1877 node.* = ast.Node.PointerPayload{
1878 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },
1879 .lpipe = token_index,
1880 .ptr_token = null,
1881 .value_symbol = undefined,
1882 .rpipe = undefined,
1883 };
1884 opt_ctx.store(&node.base);
1385 // If we've seen "inline", there should have been a "for" or "while"
1386 try tree.errors.push(AstError{
1387 .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index },
1388 });
1389 return error.ParseError;
1390}
18851391
1886 try stack.append(State{
1887 .ExpectTokenSave = ExpectTokenSave{
1888 .id = Token.Id.Pipe,
1889 .ptr = &node.rpipe,
1890 },
1891 });
1892 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1893 try stack.append(State{
1894 .OptionalTokenSave = OptionalTokenSave{
1895 .id = Token.Id.Asterisk,
1896 .ptr = &node.ptr_token,
1897 },
1898 });
1899 continue;
1900 },
1901 State.PointerIndexPayload => |opt_ctx| {
1902 const token = nextToken(&tok_it, tree);
1903 const token_index = token.index;
1904 const token_ptr = token.ptr;
1905 if (token_ptr.id != Token.Id.Pipe) {
1906 if (opt_ctx != OptionalCtx.Optional) {
1907 ((try tree.errors.addOne())).* = Error{
1908 .ExpectedToken = Error.ExpectedToken{
1909 .token = token_index,
1910 .expected_id = Token.Id.Pipe,
1911 },
1912 };
1913 return tree;
1914 }
1392/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
1393fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1394 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1395 const for_prefix = node.cast(Node.For).?;
1396
1397 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1398 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1399 });
1400 for_prefix.body = type_expr;
1401
1402 if (eatToken(it, .Keyword_else)) |else_token| {
1403 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1404 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1405 });
1406
1407 const else_node = try arena.create(Node.Else);
1408 else_node.* = Node.Else{
1409 .base = Node{ .id = .Else },
1410 .else_token = else_token,
1411 .payload = null,
1412 .body = else_expr,
1413 };
1414
1415 for_prefix.@"else" = else_node;
1416 }
19151417
1916 prevToken(&tok_it, tree);
1917 continue;
1918 }
1418 return node;
1419}
1420
1421/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
1422fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1423 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1424 const while_prefix = node.cast(Node.While).?;
1425
1426 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1427 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1428 });
1429 while_prefix.body = type_expr;
1430
1431 if (eatToken(it, .Keyword_else)) |else_token| {
1432 const payload = try parsePayload(arena, it, tree);
1433
1434 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1435 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1436 });
1437
1438 const else_node = try arena.create(Node.Else);
1439 else_node.* = Node.Else{
1440 .base = Node{ .id = .Else },
1441 .else_token = else_token,
1442 .payload = null,
1443 .body = else_expr,
1444 };
1445
1446 while_prefix.@"else" = else_node;
1447 }
1448
1449 return node;
1450}
1451
1452/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
1453fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1454 const switch_token = eatToken(it, .Keyword_switch) orelse return null;
1455 _ = try expectToken(it, tree, .LParen);
1456 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
1457 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1458 });
1459 _ = try expectToken(it, tree, .RParen);
1460 _ = try expectToken(it, tree, .LBrace);
1461 const cases = try parseSwitchProngList(arena, it, tree);
1462 const rbrace = try expectToken(it, tree, .RBrace);
1463
1464 const node = try arena.create(Node.Switch);
1465 node.* = Node.Switch{
1466 .base = Node{ .id = .Switch },
1467 .switch_token = switch_token,
1468 .expr = expr_node,
1469 .cases = cases,
1470 .rbrace = rbrace,
1471 };
1472 return &node.base;
1473}
1474
1475/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN
1476fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1477 const asm_token = eatToken(it, .Keyword_asm) orelse return null;
1478 const volatile_token = eatToken(it, .Keyword_volatile);
1479 _ = try expectToken(it, tree, .LParen);
1480 const template = try expectNode(arena, it, tree, parseStringLiteral, AstError{
1481 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },
1482 });
1483
1484 const node = try arena.create(Node.Asm);
1485 node.* = Node.Asm{
1486 .base = Node{ .id = .Asm },
1487 .asm_token = asm_token,
1488 .volatile_token = volatile_token,
1489 .template = template,
1490 .outputs = Node.Asm.OutputList.init(arena),
1491 .inputs = Node.Asm.InputList.init(arena),
1492 .clobbers = Node.Asm.ClobberList.init(arena),
1493 .rparen = undefined,
1494 };
1495
1496 try parseAsmOutput(arena, it, tree, node);
1497 node.rparen = try expectToken(it, tree, .RParen);
1498 return &node.base;
1499}
1500
1501/// DOT IDENTIFIER
1502fn parseEnumLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1503 const dot = eatToken(it, .Period) orelse return null;
1504 const name = try expectToken(it, tree, .Identifier);
1505 const node = try arena.create(Node.EnumLiteral);
1506 node.* = Node.EnumLiteral{
1507 .base = Node{ .id = .EnumLiteral },
1508 .dot = dot,
1509 .name = name,
1510 };
1511 return &node.base;
1512}
1513
1514/// AsmOutput <- COLON AsmOutputList AsmInput?
1515fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1516 if (eatToken(it, .Colon) == null) return;
1517 asm_node.outputs = try parseAsmOutputList(arena, it, tree);
1518 try parseAsmInput(arena, it, tree, asm_node);
1519}
1520
1521/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1522fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput {
1523 const lbracket = eatToken(it, .LBracket) orelse return null;
1524 const name = try expectNode(arena, it, tree, parseIdentifier, AstError{
1525 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1526 });
1527 _ = try expectToken(it, tree, .RBracket);
1528
1529 const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{
1530 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },
1531 });
1532
1533 _ = try expectToken(it, tree, .LParen);
1534 const kind = blk: {
1535 if (eatToken(it, .Arrow) != null) {
1536 const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1537 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1538 });
1539 break :blk Node.AsmOutput.Kind{ .Return = return_ident };
1540 }
1541 const variable = try expectNode(arena, it, tree, parseIdentifier, AstError{
1542 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1543 });
1544 break :blk Node.AsmOutput.Kind{ .Variable = variable.cast(Node.Identifier).? };
1545 };
1546 const rparen = try expectToken(it, tree, .RParen);
1547
1548 const node = try arena.create(Node.AsmOutput);
1549 node.* = Node.AsmOutput{
1550 .base = Node{ .id = .AsmOutput },
1551 .lbracket = lbracket,
1552 .symbolic_name = name,
1553 .constraint = constraint,
1554 .kind = kind,
1555 .rparen = rparen,
1556 };
1557 return node;
1558}
1559
1560/// AsmInput <- COLON AsmInputList AsmClobbers?
1561fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1562 if (eatToken(it, .Colon) == null) return;
1563 asm_node.inputs = try parseAsmInputList(arena, it, tree);
1564 try parseAsmClobbers(arena, it, tree, asm_node);
1565}
1566
1567/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1568fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {
1569 const lbracket = eatToken(it, .LBracket) orelse return null;
1570 const name = try expectNode(arena, it, tree, parseIdentifier, AstError{
1571 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1572 });
1573 _ = try expectToken(it, tree, .RBracket);
1574
1575 const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{
1576 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },
1577 });
1578
1579 _ = try expectToken(it, tree, .LParen);
1580 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
1581 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1582 });
1583 const rparen = try expectToken(it, tree, .RParen);
1584
1585 const node = try arena.create(Node.AsmInput);
1586 node.* = Node.AsmInput{
1587 .base = Node{ .id = .AsmInput },
1588 .lbracket = lbracket,
1589 .symbolic_name = name,
1590 .constraint = constraint,
1591 .expr = expr,
1592 .rparen = rparen,
1593 };
1594 return node;
1595}
19191596
1920 const node = try arena.create(ast.Node.PointerIndexPayload);
1921 node.* = ast.Node.PointerIndexPayload{
1922 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
1923 .lpipe = token_index,
1924 .ptr_token = null,
1925 .value_symbol = undefined,
1926 .index_symbol = null,
1927 .rpipe = undefined,
1928 };
1929 opt_ctx.store(&node.base);
1597/// AsmClobbers <- COLON StringList
1598/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
1599fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void {
1600 if (eatToken(it, .Colon) == null) return;
1601 asm_node.clobbers = try ListParseFn(
1602 Node.Asm.ClobberList,
1603 parseStringLiteral,
1604 )(arena, it, tree);
1605}
19301606
1931 stack.append(State{
1932 .ExpectTokenSave = ExpectTokenSave{
1933 .id = Token.Id.Pipe,
1934 .ptr = &node.rpipe,
1935 },
1936 }) catch unreachable;
1937 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.index_symbol } });
1938 try stack.append(State{ .IfToken = Token.Id.Comma });
1939 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1940 try stack.append(State{
1941 .OptionalTokenSave = OptionalTokenSave{
1942 .id = Token.Id.Asterisk,
1943 .ptr = &node.ptr_token,
1944 },
1945 });
1946 continue;
1947 },
1607/// BreakLabel <- COLON IDENTIFIER
1608fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1609 _ = eatToken(it, .Colon) orelse return null;
1610 return try expectNode(arena, it, tree, parseIdentifier, AstError{
1611 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1612 });
1613}
19481614
1949 State.Expression => |opt_ctx| {
1950 const token = nextToken(&tok_it, tree);
1951 const token_index = token.index;
1952 const token_ptr = token.ptr;
1953 switch (token_ptr.id) {
1954 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1955 const node = try arena.create(ast.Node.ControlFlowExpression);
1956 node.* = ast.Node.ControlFlowExpression{
1957 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
1958 .ltoken = token_index,
1959 .kind = undefined,
1960 .rhs = null,
1961 };
1962 opt_ctx.store(&node.base);
1963
1964 stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable;
1965
1966 switch (token_ptr.id) {
1967 Token.Id.Keyword_break => {
1968 node.kind = ast.Node.ControlFlowExpression.Kind{ .Break = null };
1969 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Break } });
1970 try stack.append(State{ .IfToken = Token.Id.Colon });
1971 },
1972 Token.Id.Keyword_continue => {
1973 node.kind = ast.Node.ControlFlowExpression.Kind{ .Continue = null };
1974 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Continue } });
1975 try stack.append(State{ .IfToken = Token.Id.Colon });
1976 },
1977 Token.Id.Keyword_return => {
1978 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1979 },
1980 else => unreachable,
1981 }
1982 continue;
1983 },
1984 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1985 const node = try arena.create(ast.Node.PrefixOp);
1986 node.* = ast.Node.PrefixOp{
1987 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
1988 .op_token = token_index,
1989 .op = switch (token_ptr.id) {
1990 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
1991 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op{ .Cancel = void{} },
1992 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op{ .Resume = void{} },
1993 else => unreachable,
1994 },
1995 .rhs = undefined,
1996 };
1997 opt_ctx.store(&node.base);
1615/// BlockLabel <- IDENTIFIER COLON
1616fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?TokenIndex {
1617 const identifier = eatToken(it, .Identifier) orelse return null;
1618 if (eatToken(it, .Colon) != null) return identifier;
1619 putBackToken(it, identifier);
1620 return null;
1621}
19981622
1999 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2000 continue;
2001 },
2002 else => {
2003 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr.*, token_index)) {
2004 prevToken(&tok_it, tree);
2005 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
2006 }
2007 continue;
2008 },
2009 }
2010 },
2011 State.RangeExpressionBegin => |opt_ctx| {
2012 stack.append(State{ .RangeExpressionEnd = opt_ctx }) catch unreachable;
2013 try stack.append(State{ .Expression = opt_ctx });
2014 continue;
2015 },
2016 State.RangeExpressionEnd => |opt_ctx| {
2017 const lhs = opt_ctx.get() orelse continue;
2018
2019 if (eatToken(&tok_it, tree, Token.Id.Ellipsis3)) |ellipsis3| {
2020 const node = try arena.create(ast.Node.InfixOp);
2021 node.* = ast.Node.InfixOp{
2022 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2023 .lhs = lhs,
2024 .op_token = ellipsis3,
2025 .op = ast.Node.InfixOp.Op.Range,
2026 .rhs = undefined,
2027 };
2028 opt_ctx.store(&node.base);
2029 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2030 continue;
2031 }
2032 },
2033 State.AssignmentExpressionBegin => |opt_ctx| {
2034 stack.append(State{ .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
2035 try stack.append(State{ .Expression = opt_ctx });
2036 continue;
2037 },
1623/// FieldInit <- DOT IDENTIFIER EQUAL Expr
1624fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1625 const period_token = eatToken(it, .Period) orelse return null;
1626 const name_token = try expectToken(it, tree, .Identifier);
1627 const eq_token = eatToken(it, .Equal) orelse {
1628 // `.Name` may also be an enum literal, which is a later rule.
1629 putBackToken(it, name_token);
1630 putBackToken(it, period_token);
1631 return null;
1632 };
1633 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
1634 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1635 });
1636
1637 const node = try arena.create(Node.FieldInitializer);
1638 node.* = Node.FieldInitializer{
1639 .base = Node{ .id = .FieldInitializer },
1640 .period_token = period_token,
1641 .name_token = name_token,
1642 .expr = expr_node,
1643 };
1644 return &node.base;
1645}
20381646
2039 State.AssignmentExpressionEnd => |opt_ctx| {
2040 const lhs = opt_ctx.get() orelse continue;
2041
2042 const token = nextToken(&tok_it, tree);
2043 const token_index = token.index;
2044 const token_ptr = token.ptr;
2045 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
2046 const node = try arena.create(ast.Node.InfixOp);
2047 node.* = ast.Node.InfixOp{
2048 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2049 .lhs = lhs,
2050 .op_token = token_index,
2051 .op = ass_id,
2052 .rhs = undefined,
2053 };
2054 opt_ctx.store(&node.base);
2055 stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2056 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
2057 continue;
2058 } else {
2059 prevToken(&tok_it, tree);
2060 continue;
2061 }
2062 },
1647/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
1648fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1649 _ = eatToken(it, .Colon) orelse return null;
1650 _ = try expectToken(it, tree, .LParen);
1651 const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{
1652 .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index },
1653 });
1654 _ = try expectToken(it, tree, .RParen);
1655 return node;
1656}
20631657
2064 State.UnwrapExpressionBegin => |opt_ctx| {
2065 stack.append(State{ .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
2066 try stack.append(State{ .BoolOrExpressionBegin = opt_ctx });
2067 continue;
2068 },
1658/// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
1659fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1660 _ = eatToken(it, .Keyword_linksection) orelse return null;
1661 _ = try expectToken(it, tree, .LParen);
1662 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
1663 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1664 });
1665 _ = try expectToken(it, tree, .RParen);
1666 return expr_node;
1667}
20691668
2070 State.UnwrapExpressionEnd => |opt_ctx| {
2071 const lhs = opt_ctx.get() orelse continue;
2072
2073 const token = nextToken(&tok_it, tree);
2074 const token_index = token.index;
2075 const token_ptr = token.ptr;
2076 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
2077 const node = try arena.create(ast.Node.InfixOp);
2078 node.* = ast.Node.InfixOp{
2079 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2080 .lhs = lhs,
2081 .op_token = token_index,
2082 .op = unwrap_id,
2083 .rhs = undefined,
2084 };
2085 opt_ctx.store(&node.base);
1669/// FnCC
1670/// <- KEYWORD_nakedcc
1671/// / KEYWORD_stdcallcc
1672/// / KEYWORD_extern
1673/// / KEYWORD_async (LARROW TypeExpr RARROW)?
1674fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?FnCC {
1675 if (eatToken(it, .Keyword_nakedcc)) |token| return FnCC{ .CC = token };
1676 if (eatToken(it, .Keyword_stdcallcc)) |token| return FnCC{ .CC = token };
1677 if (eatToken(it, .Keyword_extern)) |token| return FnCC{ .Extern = token };
1678 if (eatToken(it, .Keyword_async)) |token| {
1679 const node = try arena.create(Node.AsyncAttribute);
1680 node.* = Node.AsyncAttribute{
1681 .base = Node{ .id = .AsyncAttribute },
1682 .async_token = token,
1683 .allocator_type = null,
1684 .rangle_bracket = null,
1685 };
1686 if (eatToken(it, .AngleBracketLeft)) |_| {
1687 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1688 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1689 });
1690 const rarrow = try expectToken(it, tree, .AngleBracketRight);
1691 node.allocator_type = type_expr;
1692 node.rangle_bracket = rarrow;
1693 }
1694 return FnCC{ .Async = node };
1695 }
1696 return null;
1697}
20861698
2087 stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2088 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
1699const FnCC = union(enum) {
1700 CC: TokenIndex,
1701 Extern: TokenIndex,
1702 Async: *Node.AsyncAttribute,
1703};
20891704
2090 if (node.op == ast.Node.InfixOp.Op.Catch) {
2091 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.op.Catch } });
2092 }
2093 continue;
2094 } else {
2095 prevToken(&tok_it, tree);
2096 continue;
2097 }
2098 },
1705/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
1706fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1707 const doc_comments = try parseDocComment(arena, it, tree);
1708 const noalias_token = eatToken(it, .Keyword_noalias);
1709 const comptime_token = if (noalias_token == null) eatToken(it, .Keyword_comptime) else null;
1710 const name_token = blk: {
1711 const identifier = eatToken(it, .Identifier) orelse break :blk null;
1712 if (eatToken(it, .Colon) != null) break :blk identifier;
1713 putBackToken(it, identifier); // ParamType may also be an identifier
1714 break :blk null;
1715 };
1716 const param_type = (try parseParamType(arena, it, tree)) orelse {
1717 // Only return cleanly if no keyword, identifier, or doc comment was found
1718 if (noalias_token == null and
1719 comptime_token == null and
1720 name_token == null and
1721 doc_comments == null) return null;
1722 try tree.errors.push(AstError{
1723 .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index },
1724 });
1725 return error.ParseError;
1726 };
20991727
2100 State.BoolOrExpressionBegin => |opt_ctx| {
2101 stack.append(State{ .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
2102 try stack.append(State{ .BoolAndExpressionBegin = opt_ctx });
2103 continue;
2104 },
1728 const param_decl = try arena.create(Node.ParamDecl);
1729 param_decl.* = Node.ParamDecl{
1730 .base = Node{ .id = .ParamDecl },
1731 .doc_comments = doc_comments,
1732 .comptime_token = comptime_token,
1733 .noalias_token = noalias_token,
1734 .name_token = name_token,
1735 // TODO: These should be squished into a ParamType enum
1736 .type_node = undefined,
1737 .var_args_token = null,
1738 };
1739 switch (param_type) {
1740 .VarType => |node| param_decl.type_node = node,
1741 .TypeExpr => |node| param_decl.type_node = node,
1742 .VarArgs => |token| param_decl.var_args_token = token,
1743 }
1744 return &param_decl.base;
1745}
21051746
2106 State.BoolOrExpressionEnd => |opt_ctx| {
2107 const lhs = opt_ctx.get() orelse continue;
2108
2109 if (eatToken(&tok_it, tree, Token.Id.Keyword_or)) |or_token| {
2110 const node = try arena.create(ast.Node.InfixOp);
2111 node.* = ast.Node.InfixOp{
2112 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2113 .lhs = lhs,
2114 .op_token = or_token,
2115 .op = ast.Node.InfixOp.Op.BoolOr,
2116 .rhs = undefined,
2117 };
2118 opt_ctx.store(&node.base);
2119 stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2120 try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2121 continue;
2122 }
2123 },
1747/// ParamType
1748/// <- KEYWORD_var
1749/// / DOT3
1750/// / TypeExpr
1751fn parseParamType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?ParamType {
1752 if (try parseVarType(arena, it, tree)) |node| return ParamType{ .VarType = node };
1753 if (eatToken(it, .Ellipsis3)) |token| return ParamType{ .VarArgs = token };
1754 if (try parseTypeExpr(arena, it, tree)) |node| return ParamType{ .TypeExpr = node };
1755 return null;
1756}
21241757
2125 State.BoolAndExpressionBegin => |opt_ctx| {
2126 stack.append(State{ .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
2127 try stack.append(State{ .ComparisonExpressionBegin = opt_ctx });
2128 continue;
2129 },
1758// TODO: Move to ast.Node.ParamDecl.ParamType
1759const ParamType = union(enum) {
1760 VarType: *Node,
1761 VarArgs: TokenIndex,
1762 TypeExpr: *Node,
1763};
21301764
2131 State.BoolAndExpressionEnd => |opt_ctx| {
2132 const lhs = opt_ctx.get() orelse continue;
2133
2134 if (eatToken(&tok_it, tree, Token.Id.Keyword_and)) |and_token| {
2135 const node = try arena.create(ast.Node.InfixOp);
2136 node.* = ast.Node.InfixOp{
2137 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2138 .lhs = lhs,
2139 .op_token = and_token,
2140 .op = ast.Node.InfixOp.Op.BoolAnd,
2141 .rhs = undefined,
2142 };
2143 opt_ctx.store(&node.base);
2144 stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2145 try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2146 continue;
2147 }
2148 },
1765/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
1766fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1767 const if_token = eatToken(it, .Keyword_if) orelse return null;
1768 _ = try expectToken(it, tree, .LParen);
1769 const condition = try expectNode(arena, it, tree, parseExpr, AstError{
1770 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1771 });
1772 _ = try expectToken(it, tree, .RParen);
1773 const payload = try parsePtrPayload(arena, it, tree);
1774
1775 const node = try arena.create(Node.If);
1776 node.* = Node.If{
1777 .base = Node{ .id = .If },
1778 .if_token = if_token,
1779 .condition = condition,
1780 .payload = payload,
1781 .body = undefined, // set by caller
1782 .@"else" = null,
1783 };
1784 return &node.base;
1785}
21491786
2150 State.ComparisonExpressionBegin => |opt_ctx| {
2151 stack.append(State{ .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2152 try stack.append(State{ .BinaryOrExpressionBegin = opt_ctx });
2153 continue;
2154 },
1787/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
1788fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1789 const while_token = eatToken(it, .Keyword_while) orelse return null;
1790
1791 _ = try expectToken(it, tree, .LParen);
1792 const condition = try expectNode(arena, it, tree, parseExpr, AstError{
1793 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1794 });
1795 _ = try expectToken(it, tree, .RParen);
1796
1797 const payload = try parsePtrPayload(arena, it, tree);
1798 const continue_expr = try parseWhileContinueExpr(arena, it, tree);
1799
1800 const node = try arena.create(Node.While);
1801 node.* = Node.While{
1802 .base = Node{ .id = .While },
1803 .label = null,
1804 .inline_token = null,
1805 .while_token = while_token,
1806 .condition = condition,
1807 .payload = payload,
1808 .continue_expr = continue_expr,
1809 .body = undefined, // set by caller
1810 .@"else" = null,
1811 };
1812 return &node.base;
1813}
21551814
2156 State.ComparisonExpressionEnd => |opt_ctx| {
2157 const lhs = opt_ctx.get() orelse continue;
2158
2159 const token = nextToken(&tok_it, tree);
2160 const token_index = token.index;
2161 const token_ptr = token.ptr;
2162 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
2163 const node = try arena.create(ast.Node.InfixOp);
2164 node.* = ast.Node.InfixOp{
2165 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2166 .lhs = lhs,
2167 .op_token = token_index,
2168 .op = comp_id,
2169 .rhs = undefined,
2170 };
2171 opt_ctx.store(&node.base);
2172 stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2173 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2174 continue;
2175 } else {
2176 prevToken(&tok_it, tree);
2177 continue;
2178 }
2179 },
1815/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
1816fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1817 const for_token = eatToken(it, .Keyword_for) orelse return null;
1818
1819 _ = try expectToken(it, tree, .LParen);
1820 const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{
1821 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1822 });
1823 _ = try expectToken(it, tree, .RParen);
1824
1825 const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{
1826 .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index },
1827 });
1828
1829 const node = try arena.create(Node.For);
1830 node.* = Node.For{
1831 .base = Node{ .id = .For },
1832 .label = null,
1833 .inline_token = null,
1834 .for_token = for_token,
1835 .array_expr = array_expr,
1836 .payload = payload,
1837 .body = undefined, // set by caller
1838 .@"else" = null,
1839 };
1840 return &node.base;
1841}
21801842
2181 State.BinaryOrExpressionBegin => |opt_ctx| {
2182 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2183 try stack.append(State{ .BinaryXorExpressionBegin = opt_ctx });
2184 continue;
2185 },
1843/// Payload <- PIPE IDENTIFIER PIPE
1844fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1845 const lpipe = eatToken(it, .Pipe) orelse return null;
1846 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
1847 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1848 });
1849 const rpipe = try expectToken(it, tree, .Pipe);
1850
1851 const node = try arena.create(Node.Payload);
1852 node.* = Node.Payload{
1853 .base = Node{ .id = .Payload },
1854 .lpipe = lpipe,
1855 .error_symbol = identifier,
1856 .rpipe = rpipe,
1857 };
1858 return &node.base;
1859}
21861860
2187 State.BinaryOrExpressionEnd => |opt_ctx| {
2188 const lhs = opt_ctx.get() orelse continue;
2189
2190 if (eatToken(&tok_it, tree, Token.Id.Pipe)) |pipe| {
2191 const node = try arena.create(ast.Node.InfixOp);
2192 node.* = ast.Node.InfixOp{
2193 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2194 .lhs = lhs,
2195 .op_token = pipe,
2196 .op = ast.Node.InfixOp.Op.BitOr,
2197 .rhs = undefined,
2198 };
2199 opt_ctx.store(&node.base);
2200 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2201 try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2202 continue;
2203 }
2204 },
1861/// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
1862fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1863 const lpipe = eatToken(it, .Pipe) orelse return null;
1864 const asterisk = eatToken(it, .Asterisk);
1865 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
1866 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1867 });
1868 const rpipe = try expectToken(it, tree, .Pipe);
1869
1870 const node = try arena.create(Node.PointerPayload);
1871 node.* = Node.PointerPayload{
1872 .base = Node{ .id = .PointerPayload },
1873 .lpipe = lpipe,
1874 .ptr_token = asterisk,
1875 .value_symbol = identifier,
1876 .rpipe = rpipe,
1877 };
1878 return &node.base;
1879}
22051880
2206 State.BinaryXorExpressionBegin => |opt_ctx| {
2207 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2208 try stack.append(State{ .BinaryAndExpressionBegin = opt_ctx });
2209 continue;
2210 },
1881/// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
1882fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1883 const lpipe = eatToken(it, .Pipe) orelse return null;
1884 const asterisk = eatToken(it, .Asterisk);
1885 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
1886 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1887 });
1888
1889 const index = if (eatToken(it, .Comma) == null)
1890 null
1891 else
1892 try expectNode(arena, it, tree, parseIdentifier, AstError{
1893 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },
1894 });
1895
1896 const rpipe = try expectToken(it, tree, .Pipe);
1897
1898 const node = try arena.create(Node.PointerIndexPayload);
1899 node.* = Node.PointerIndexPayload{
1900 .base = Node{ .id = .PointerIndexPayload },
1901 .lpipe = lpipe,
1902 .ptr_token = asterisk,
1903 .value_symbol = identifier,
1904 .index_symbol = index,
1905 .rpipe = rpipe,
1906 };
1907 return &node.base;
1908}
22111909
2212 State.BinaryXorExpressionEnd => |opt_ctx| {
2213 const lhs = opt_ctx.get() orelse continue;
2214
2215 if (eatToken(&tok_it, tree, Token.Id.Caret)) |caret| {
2216 const node = try arena.create(ast.Node.InfixOp);
2217 node.* = ast.Node.InfixOp{
2218 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2219 .lhs = lhs,
2220 .op_token = caret,
2221 .op = ast.Node.InfixOp.Op.BitXor,
2222 .rhs = undefined,
2223 };
2224 opt_ctx.store(&node.base);
2225 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2226 try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2227 continue;
2228 }
2229 },
1910/// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
1911fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1912 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;
1913 const arrow = try expectToken(it, tree, .EqualAngleBracketRight);
1914 const payload = try parsePtrPayload(arena, it, tree);
1915 const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{
1916 .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index },
1917 });
22301918
2231 State.BinaryAndExpressionBegin => |opt_ctx| {
2232 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2233 try stack.append(State{ .BitShiftExpressionBegin = opt_ctx });
2234 continue;
2235 },
1919 const switch_case = node.cast(Node.SwitchCase).?;
1920 switch_case.arrow_token = arrow;
1921 switch_case.payload = payload;
1922 switch_case.expr = expr;
22361923
2237 State.BinaryAndExpressionEnd => |opt_ctx| {
2238 const lhs = opt_ctx.get() orelse continue;
2239
2240 if (eatToken(&tok_it, tree, Token.Id.Ampersand)) |ampersand| {
2241 const node = try arena.create(ast.Node.InfixOp);
2242 node.* = ast.Node.InfixOp{
2243 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2244 .lhs = lhs,
2245 .op_token = ampersand,
2246 .op = ast.Node.InfixOp.Op.BitAnd,
2247 .rhs = undefined,
2248 };
2249 opt_ctx.store(&node.base);
2250 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2251 try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2252 continue;
2253 }
2254 },
1924 return node;
1925}
22551926
2256 State.BitShiftExpressionBegin => |opt_ctx| {
2257 stack.append(State{ .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2258 try stack.append(State{ .AdditionExpressionBegin = opt_ctx });
2259 continue;
2260 },
1927/// SwitchCase
1928/// <- SwitchItem (COMMA SwitchItem)* COMMA?
1929/// / KEYWORD_else
1930fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1931 var list = Node.SwitchCase.ItemList.init(arena);
1932
1933 if (try parseSwitchItem(arena, it, tree)) |first_item| {
1934 try list.push(first_item);
1935 while (eatToken(it, .Comma) != null) {
1936 const next_item = (try parseSwitchItem(arena, it, tree)) orelse break;
1937 try list.push(next_item);
1938 }
1939 } else if (eatToken(it, .Keyword_else)) |else_token| {
1940 const else_node = try arena.create(Node.SwitchElse);
1941 else_node.* = Node.SwitchElse{
1942 .base = Node{ .id = .SwitchElse },
1943 .token = else_token,
1944 };
1945 try list.push(&else_node.base);
1946 } else return null;
1947
1948 const node = try arena.create(Node.SwitchCase);
1949 node.* = Node.SwitchCase{
1950 .base = Node{ .id = .SwitchCase },
1951 .items = list,
1952 .arrow_token = undefined, // set by caller
1953 .payload = null,
1954 .expr = undefined, // set by caller
1955 };
1956 return &node.base;
1957}
22611958
2262 State.BitShiftExpressionEnd => |opt_ctx| {
2263 const lhs = opt_ctx.get() orelse continue;
2264
2265 const token = nextToken(&tok_it, tree);
2266 const token_index = token.index;
2267 const token_ptr = token.ptr;
2268 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2269 const node = try arena.create(ast.Node.InfixOp);
2270 node.* = ast.Node.InfixOp{
2271 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2272 .lhs = lhs,
2273 .op_token = token_index,
2274 .op = bitshift_id,
2275 .rhs = undefined,
2276 };
2277 opt_ctx.store(&node.base);
2278 stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2279 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2280 continue;
2281 } else {
2282 prevToken(&tok_it, tree);
2283 continue;
2284 }
2285 },
1959/// SwitchItem <- Expr (DOT3 Expr)?
1960fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1961 const expr = (try parseExpr(arena, it, tree)) orelse return null;
1962 if (eatToken(it, .Ellipsis3)) |token| {
1963 const range_end = try expectNode(arena, it, tree, parseExpr, AstError{
1964 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1965 });
1966
1967 const node = try arena.create(Node.InfixOp);
1968 node.* = Node.InfixOp{
1969 .base = Node{ .id = .InfixOp },
1970 .op_token = token,
1971 .lhs = expr,
1972 .op = Node.InfixOp.Op{ .Range = {} },
1973 .rhs = range_end,
1974 };
1975 return &node.base;
1976 }
1977 return expr;
1978}
22861979
2287 State.AdditionExpressionBegin => |opt_ctx| {
2288 stack.append(State{ .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2289 try stack.append(State{ .MultiplyExpressionBegin = opt_ctx });
2290 continue;
2291 },
1980/// AssignOp
1981/// <- ASTERISKEQUAL
1982/// / SLASHEQUAL
1983/// / PERCENTEQUAL
1984/// / PLUSEQUAL
1985/// / MINUSEQUAL
1986/// / LARROW2EQUAL
1987/// / RARROW2EQUAL
1988/// / AMPERSANDEQUAL
1989/// / CARETEQUAL
1990/// / PIPEEQUAL
1991/// / ASTERISKPERCENTEQUAL
1992/// / PLUSPERCENTEQUAL
1993/// / MINUSPERCENTEQUAL
1994/// / EQUAL
1995fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1996 const Op = Node.InfixOp.Op;
1997
1998 const token = nextToken(it);
1999 const op = switch (token.ptr.id) {
2000 .AsteriskEqual => Op{ .AssignTimes = {} },
2001 .SlashEqual => Op{ .AssignDiv = {} },
2002 .PercentEqual => Op{ .AssignMod = {} },
2003 .PlusEqual => Op{ .AssignPlus = {} },
2004 .MinusEqual => Op{ .AssignMinus = {} },
2005 .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },
2006 .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },
2007 .AmpersandEqual => Op{ .AssignBitAnd = {} },
2008 .CaretEqual => Op{ .AssignBitXor = {} },
2009 .PipeEqual => Op{ .AssignBitOr = {} },
2010 .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} },
2011 .PlusPercentEqual => Op{ .AssignPlusWrap = {} },
2012 .MinusPercentEqual => Op{ .AssignMinusWrap = {} },
2013 .Equal => Op{ .Assign = {} },
2014 else => {
2015 putBackToken(it, token.index);
2016 return null;
2017 },
2018 };
22922019
2293 State.AdditionExpressionEnd => |opt_ctx| {
2294 const lhs = opt_ctx.get() orelse continue;
2295
2296 const token = nextToken(&tok_it, tree);
2297 const token_index = token.index;
2298 const token_ptr = token.ptr;
2299 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2300 const node = try arena.create(ast.Node.InfixOp);
2301 node.* = ast.Node.InfixOp{
2302 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2303 .lhs = lhs,
2304 .op_token = token_index,
2305 .op = add_id,
2306 .rhs = undefined,
2307 };
2308 opt_ctx.store(&node.base);
2309 stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2310 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2311 continue;
2312 } else {
2313 prevToken(&tok_it, tree);
2314 continue;
2315 }
2316 },
2020 const node = try arena.create(Node.InfixOp);
2021 node.* = Node.InfixOp{
2022 .base = Node{ .id = .InfixOp },
2023 .op_token = token.index,
2024 .lhs = undefined, // set by caller
2025 .op = op,
2026 .rhs = undefined, // set by caller
2027 };
2028 return &node.base;
2029}
23172030
2318 State.MultiplyExpressionBegin => |opt_ctx| {
2319 stack.append(State{ .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2320 try stack.append(State{ .CurlySuffixExpressionBegin = opt_ctx });
2321 continue;
2322 },
2031/// CompareOp
2032/// <- EQUALEQUAL
2033/// / EXCLAMATIONMARKEQUAL
2034/// / LARROW
2035/// / RARROW
2036/// / LARROWEQUAL
2037/// / RARROWEQUAL
2038fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2039 const ops = Node.InfixOp.Op;
2040
2041 const token = nextToken(it);
2042 const op = switch (token.ptr.id) {
2043 .EqualEqual => ops{ .EqualEqual = {} },
2044 .BangEqual => ops{ .BangEqual = {} },
2045 .AngleBracketLeft => ops{ .LessThan = {} },
2046 .AngleBracketRight => ops{ .GreaterThan = {} },
2047 .AngleBracketLeftEqual => ops{ .LessOrEqual = {} },
2048 .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} },
2049 else => {
2050 putBackToken(it, token.index);
2051 return null;
2052 },
2053 };
23232054
2324 State.MultiplyExpressionEnd => |opt_ctx| {
2325 const lhs = opt_ctx.get() orelse continue;
2326
2327 const token = nextToken(&tok_it, tree);
2328 const token_index = token.index;
2329 const token_ptr = token.ptr;
2330 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2331 const node = try arena.create(ast.Node.InfixOp);
2332 node.* = ast.Node.InfixOp{
2333 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2334 .lhs = lhs,
2335 .op_token = token_index,
2336 .op = mult_id,
2337 .rhs = undefined,
2338 };
2339 opt_ctx.store(&node.base);
2340 stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2341 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2342 continue;
2343 } else {
2344 prevToken(&tok_it, tree);
2345 continue;
2346 }
2347 },
2055 return try createInfixOp(arena, token.index, op);
2056}
23482057
2349 State.CurlySuffixExpressionBegin => |opt_ctx| {
2350 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2351 try stack.append(State{ .IfToken = Token.Id.LBrace });
2352 try stack.append(State{ .TypeExprBegin = opt_ctx });
2353 continue;
2354 },
2058/// BitwiseOp
2059/// <- AMPERSAND
2060/// / CARET
2061/// / PIPE
2062/// / KEYWORD_orelse
2063/// / KEYWORD_catch Payload?
2064fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2065 const ops = Node.InfixOp.Op;
2066
2067 const token = nextToken(it);
2068 const op = switch (token.ptr.id) {
2069 .Ampersand => ops{ .BitAnd = {} },
2070 .Caret => ops{ .BitXor = {} },
2071 .Pipe => ops{ .BitOr = {} },
2072 .Keyword_orelse => ops{ .UnwrapOptional = {} },
2073 .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) },
2074 else => {
2075 putBackToken(it, token.index);
2076 return null;
2077 },
2078 };
23552079
2356 State.CurlySuffixExpressionEnd => |opt_ctx| {
2357 const lhs = opt_ctx.get() orelse continue;
2080 return try createInfixOp(arena, token.index, op);
2081}
23582082
2359 if (tok_it.peek().?.id == Token.Id.Period) {
2360 const node = try arena.create(ast.Node.SuffixOp);
2361 node.* = ast.Node.SuffixOp{
2362 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2363 .lhs = lhs,
2364 .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2365 .rtoken = undefined,
2366 };
2367 opt_ctx.store(&node.base);
2368
2369 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2370 try stack.append(State{ .IfToken = Token.Id.LBrace });
2371 try stack.append(State{
2372 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)){
2373 .list = &node.op.StructInitializer,
2374 .ptr = &node.rtoken,
2375 },
2376 });
2377 continue;
2378 }
2083/// BitShiftOp
2084/// <- LARROW2
2085/// / RARROW2
2086fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2087 const ops = Node.InfixOp.Op;
23792088
2380 const node = try arena.create(ast.Node.SuffixOp);
2381 node.* = ast.Node.SuffixOp{
2382 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2383 .lhs = lhs,
2384 .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2385 .rtoken = undefined,
2386 };
2387 opt_ctx.store(&node.base);
2388 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2389 try stack.append(State{ .IfToken = Token.Id.LBrace });
2390 try stack.append(State{
2391 .ExprListItemOrEnd = ExprListCtx{
2392 .list = &node.op.ArrayInitializer,
2393 .end = Token.Id.RBrace,
2394 .ptr = &node.rtoken,
2395 },
2396 });
2397 continue;
2398 },
2089 const token = nextToken(it);
2090 const op = switch (token.ptr.id) {
2091 .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} },
2092 .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} },
2093 else => {
2094 putBackToken(it, token.index);
2095 return null;
2096 },
2097 };
23992098
2400 State.TypeExprBegin => |opt_ctx| {
2401 stack.append(State{ .TypeExprEnd = opt_ctx }) catch unreachable;
2402 try stack.append(State{ .PrefixOpExpression = opt_ctx });
2403 continue;
2404 },
2099 return try createInfixOp(arena, token.index, op);
2100}
24052101
2406 State.TypeExprEnd => |opt_ctx| {
2407 const lhs = opt_ctx.get() orelse continue;
2408
2409 if (eatToken(&tok_it, tree, Token.Id.Bang)) |bang| {
2410 const node = try arena.create(ast.Node.InfixOp);
2411 node.* = ast.Node.InfixOp{
2412 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2413 .lhs = lhs,
2414 .op_token = bang,
2415 .op = ast.Node.InfixOp.Op.ErrorUnion,
2416 .rhs = undefined,
2417 };
2418 opt_ctx.store(&node.base);
2419 stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2420 try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } });
2421 continue;
2422 }
2423 },
2102/// AdditionOp
2103/// <- PLUS
2104/// / MINUS
2105/// / PLUS2
2106/// / PLUSPERCENT
2107/// / MINUSPERCENT
2108fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2109 const ops = Node.InfixOp.Op;
2110
2111 const token = nextToken(it);
2112 const op = switch (token.ptr.id) {
2113 .Plus => ops{ .Add = {} },
2114 .Minus => ops{ .Sub = {} },
2115 .PlusPlus => ops{ .ArrayCat = {} },
2116 .PlusPercent => ops{ .AddWrap = {} },
2117 .MinusPercent => ops{ .SubWrap = {} },
2118 else => {
2119 putBackToken(it, token.index);
2120 return null;
2121 },
2122 };
24242123
2425 State.PrefixOpExpression => |opt_ctx| {
2426 const token = nextToken(&tok_it, tree);
2427 const token_index = token.index;
2428 const token_ptr = token.ptr;
2429 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2430 var node = try arena.create(ast.Node.PrefixOp);
2431 node.* = ast.Node.PrefixOp{
2432 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2433 .op_token = token_index,
2434 .op = prefix_id,
2435 .rhs = undefined,
2436 };
2437 opt_ctx.store(&node.base);
2438
2439 // Treat '**' token as two pointer types
2440 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2441 const child = try arena.create(ast.Node.PrefixOp);
2442 child.* = ast.Node.PrefixOp{
2443 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2444 .op_token = token_index,
2445 .op = prefix_id,
2446 .rhs = undefined,
2447 };
2448 node.rhs = &child.base;
2449 node = child;
2450 }
2124 return try createInfixOp(arena, token.index, op);
2125}
24512126
2452 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2453 if (node.op == ast.Node.PrefixOp.Op.PtrType) {
2454 try stack.append(State{ .PtrTypeModifiers = &node.op.PtrType });
2455 }
2456 continue;
2457 } else {
2458 prevToken(&tok_it, tree);
2459 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2460 continue;
2461 }
2462 },
2127/// MultiplyOp
2128/// <- PIPE2
2129/// / ASTERISK
2130/// / SLASH
2131/// / PERCENT
2132/// / ASTERISK2
2133/// / ASTERISKPERCENT
2134fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2135 const ops = Node.InfixOp.Op;
2136
2137 const token = nextToken(it);
2138 const op = switch (token.ptr.id) {
2139 .PipePipe => ops{ .BoolOr = {} },
2140 .Asterisk => ops{ .Mult = {} },
2141 .Slash => ops{ .Div = {} },
2142 .Percent => ops{ .Mod = {} },
2143 .AsteriskAsterisk => ops{ .ArrayMult = {} },
2144 .AsteriskPercent => ops{ .MultWrap = {} },
2145 else => {
2146 putBackToken(it, token.index);
2147 return null;
2148 },
2149 };
24632150
2464 State.SuffixOpExpressionBegin => |opt_ctx| {
2465 if (eatToken(&tok_it, tree, Token.Id.Keyword_async)) |async_token| {
2466 const async_node = try arena.create(ast.Node.AsyncAttribute);
2467 async_node.* = ast.Node.AsyncAttribute{
2468 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
2469 .async_token = async_token,
2470 .allocator_type = null,
2471 .rangle_bracket = null,
2472 };
2473 stack.append(State{
2474 .AsyncEnd = AsyncEndCtx{
2475 .ctx = opt_ctx,
2476 .attribute = async_node,
2477 },
2478 }) catch unreachable;
2479 try stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2480 try stack.append(State{ .PrimaryExpression = opt_ctx.toRequired() });
2481 try stack.append(State{ .AsyncAllocator = async_node });
2482 continue;
2483 }
2151 return try createInfixOp(arena, token.index, op);
2152}
24842153
2485 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2486 try stack.append(State{ .PrimaryExpression = opt_ctx });
2487 continue;
2488 },
2154/// PrefixOp
2155/// <- EXCLAMATIONMARK
2156/// / MINUS
2157/// / TILDE
2158/// / MINUSPERCENT
2159/// / AMPERSAND
2160/// / KEYWORD_try
2161/// / KEYWORD_await
2162fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2163 const ops = Node.PrefixOp.Op;
2164
2165 const token = nextToken(it);
2166 const op = switch (token.ptr.id) {
2167 .Bang => ops{ .BoolNot = {} },
2168 .Minus => ops{ .Negation = {} },
2169 .Tilde => ops{ .BitNot = {} },
2170 .MinusPercent => ops{ .NegationWrap = {} },
2171 .Ampersand => ops{ .AddressOf = {} },
2172 .Keyword_try => ops{ .Try = {} },
2173 .Keyword_await => ops{ .Await = {} },
2174 else => {
2175 putBackToken(it, token.index);
2176 return null;
2177 },
2178 };
24892179
2490 State.SuffixOpExpressionEnd => |opt_ctx| {
2491 const lhs = opt_ctx.get() orelse continue;
2492
2493 const token = nextToken(&tok_it, tree);
2494 const token_index = token.index;
2495 const token_ptr = token.ptr;
2496 switch (token_ptr.id) {
2497 Token.Id.LParen => {
2498 const node = try arena.create(ast.Node.SuffixOp);
2499 node.* = ast.Node.SuffixOp{
2500 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2501 .lhs = lhs,
2502 .op = ast.Node.SuffixOp.Op{
2503 .Call = ast.Node.SuffixOp.Op.Call{
2504 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2505 .async_attr = null,
2506 },
2507 },
2508 .rtoken = undefined,
2509 };
2510 opt_ctx.store(&node.base);
2511
2512 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2513 try stack.append(State{
2514 .ExprListItemOrEnd = ExprListCtx{
2515 .list = &node.op.Call.params,
2516 .end = Token.Id.RParen,
2517 .ptr = &node.rtoken,
2518 },
2519 });
2520 continue;
2521 },
2522 Token.Id.LBracket => {
2523 const node = try arena.create(ast.Node.SuffixOp);
2524 node.* = ast.Node.SuffixOp{
2525 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2526 .lhs = lhs,
2527 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
2528 .rtoken = undefined,
2529 };
2530 opt_ctx.store(&node.base);
2180 const node = try arena.create(Node.PrefixOp);
2181 node.* = Node.PrefixOp{
2182 .base = Node{ .id = .PrefixOp },
2183 .op_token = token.index,
2184 .op = op,
2185 .rhs = undefined,
2186 };
2187 return &node.base;
2188}
25312189
2532 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2533 try stack.append(State{ .SliceOrArrayAccess = node });
2534 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayAccess } });
2535 continue;
2536 },
2537 Token.Id.Period => {
2538 if (eatToken(&tok_it, tree, Token.Id.Asterisk)) |asterisk_token| {
2539 const node = try arena.create(ast.Node.SuffixOp);
2540 node.* = ast.Node.SuffixOp{
2541 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2542 .lhs = lhs,
2543 .op = ast.Node.SuffixOp.Op.Deref,
2544 .rtoken = asterisk_token,
2545 };
2546 opt_ctx.store(&node.base);
2547 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2548 continue;
2549 }
2550 if (eatToken(&tok_it, tree, Token.Id.QuestionMark)) |question_token| {
2551 const node = try arena.create(ast.Node.SuffixOp);
2552 node.* = ast.Node.SuffixOp{
2553 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2554 .lhs = lhs,
2555 .op = ast.Node.SuffixOp.Op.UnwrapOptional,
2556 .rtoken = question_token,
2557 };
2558 opt_ctx.store(&node.base);
2559 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2560 continue;
2561 }
2562 const node = try arena.create(ast.Node.InfixOp);
2563 node.* = ast.Node.InfixOp{
2564 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2565 .lhs = lhs,
2566 .op_token = token_index,
2567 .op = ast.Node.InfixOp.Op.Period,
2568 .rhs = undefined,
2569 };
2570 opt_ctx.store(&node.base);
2190// TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
2191// pointers. Consider updating this rule:
2192// ...
2193// / ArrayTypeStart
2194// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2195// / PtrTypeStart ...
2196
2197/// PrefixTypeOp
2198/// <- QUESTIONMARK
2199/// / KEYWORD_promise MINUSRARROW
2200/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2201/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2202fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2203 if (eatToken(it, .QuestionMark)) |token| {
2204 const node = try arena.create(Node.PrefixOp);
2205 node.* = Node.PrefixOp{
2206 .base = Node{ .id = .PrefixOp },
2207 .op_token = token,
2208 .op = Node.PrefixOp.Op.OptionalType,
2209 .rhs = undefined, // set by caller
2210 };
2211 return &node.base;
2212 }
25712213
2572 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2573 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } });
2574 continue;
2575 },
2576 else => {
2577 prevToken(&tok_it, tree);
2578 continue;
2579 },
2580 }
2581 },
2214 // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or
2215 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2216 // Consider making the PromiseType a member of PrefixOp and add a
2217 // PrefixOp.PromiseType variant?
2218 if (eatToken(it, .Keyword_promise)) |token| {
2219 const arrow = eatToken(it, .Arrow) orelse {
2220 putBackToken(it, token);
2221 return null;
2222 };
2223 const node = try arena.create(Node.PromiseType);
2224 node.* = Node.PromiseType{
2225 .base = Node{ .id = .PromiseType },
2226 .promise_token = token,
2227 .result = Node.PromiseType.Result{
2228 .arrow_token = arrow,
2229 .return_type = undefined, // set by caller
2230 },
2231 };
2232 return &node.base;
2233 }
25822234
2583 State.PrimaryExpression => |opt_ctx| {
2584 const token = nextToken(&tok_it, tree);
2585 switch (token.ptr.id) {
2586 Token.Id.IntegerLiteral => {
2587 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.IntegerLiteral, token.index);
2588 continue;
2589 },
2590 Token.Id.Period => {
2591 const name_token = nextToken(&tok_it, tree);
2592 if (name_token.ptr.id != Token.Id.Identifier) {
2593 ((try tree.errors.addOne())).* = Error{
2594 .ExpectedToken = Error.ExpectedToken{
2595 .token = name_token.index,
2596 .expected_id = Token.Id.Identifier,
2597 },
2598 };
2599 return tree;
2235 if (try parseArrayTypeStart(arena, it, tree)) |node| {
2236 switch (node.cast(Node.PrefixOp).?.op) {
2237 .ArrayType => {},
2238 .SliceType => |*slice_type| {
2239 // Collect pointer qualifiers in any order, but disallow duplicates
2240 while (true) {
2241 if (try parseByteAlign(arena, it, tree)) |align_expr| {
2242 if (slice_type.align_info != null) {
2243 try tree.errors.push(AstError{
2244 .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index },
2245 });
2246 return error.ParseError;
26002247 }
2601
2602 const node = try arena.create(ast.Node.EnumLiteral);
2603 node.* = ast.Node.EnumLiteral{
2604 .base = ast.Node{ .id = ast.Node.Id.EnumLiteral },
2605 .dot = token.index,
2606 .name = name_token.index,
2248 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2249 .node = align_expr,
2250 .bit_range = null,
26072251 };
2608 opt_ctx.store(&node.base);
2609 continue;
2610 },
2611 Token.Id.FloatLiteral => {
2612 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index);
2613 continue;
2614 },
2615 Token.Id.CharLiteral => {
2616 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token.index);
2617 continue;
2618 },
2619 Token.Id.Keyword_undefined => {
2620 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2621 continue;
2622 },
2623 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2624 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
26252252 continue;
2626 },
2627 Token.Id.Keyword_null => {
2628 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token.index);
2629 continue;
2630 },
2631 Token.Id.Keyword_var => {
2632 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token.index);
2633 continue;
2634 },
2635 Token.Id.Keyword_unreachable => {
2636 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token.index);
2637 continue;
2638 },
2639 Token.Id.Keyword_promise => {
2640 const node = try arena.create(ast.Node.PromiseType);
2641 node.* = ast.Node.PromiseType{
2642 .base = ast.Node{ .id = ast.Node.Id.PromiseType },
2643 .promise_token = token.index,
2644 .result = null,
2645 };
2646 opt_ctx.store(&node.base);
2647 const next_token = nextToken(&tok_it, tree);
2648 const next_token_index = next_token.index;
2649 const next_token_ptr = next_token.ptr;
2650 if (next_token_ptr.id != Token.Id.Arrow) {
2651 prevToken(&tok_it, tree);
2652 continue;
2253 }
2254 if (eatToken(it, .Keyword_const)) |const_token| {
2255 if (slice_type.const_token != null) {
2256 try tree.errors.push(AstError{
2257 .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index },
2258 });
2259 return error.ParseError;
26532260 }
2654 node.result = ast.Node.PromiseType.Result{
2655 .arrow_token = next_token_index,
2656 .return_type = undefined,
2657 };
2658 const return_type_ptr = &node.result.?.return_type;
2659 try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
2660 continue;
2661 },
2662 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2663 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, tree)) orelse unreachable);
2664 continue;
2665 },
2666 Token.Id.LParen => {
2667 const node = try arena.create(ast.Node.GroupedExpression);
2668 node.* = ast.Node.GroupedExpression{
2669 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
2670 .lparen = token.index,
2671 .expr = undefined,
2672 .rparen = undefined,
2673 };
2674 opt_ctx.store(&node.base);
2675
2676 stack.append(State{
2677 .ExpectTokenSave = ExpectTokenSave{
2678 .id = Token.Id.RParen,
2679 .ptr = &node.rparen,
2680 },
2681 }) catch unreachable;
2682 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
2683 continue;
2684 },
2685 Token.Id.Builtin => {
2686 const node = try arena.create(ast.Node.BuiltinCall);
2687 node.* = ast.Node.BuiltinCall{
2688 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
2689 .builtin_token = token.index,
2690 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2691 .rparen_token = undefined,
2692 };
2693 opt_ctx.store(&node.base);
2694
2695 stack.append(State{
2696 .ExprListItemOrEnd = ExprListCtx{
2697 .list = &node.params,
2698 .end = Token.Id.RParen,
2699 .ptr = &node.rparen_token,
2700 },
2701 }) catch unreachable;
2702 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2703 continue;
2704 },
2705 Token.Id.LBracket => {
2706 const node = try arena.create(ast.Node.PrefixOp);
2707 node.* = ast.Node.PrefixOp{
2708 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2709 .op_token = token.index,
2710 .op = undefined,
2711 .rhs = undefined,
2712 };
2713 opt_ctx.store(&node.base);
2714
2715 stack.append(State{ .SliceOrArrayType = node }) catch unreachable;
2716 continue;
2717 },
2718 Token.Id.Keyword_error => {
2719 stack.append(State{
2720 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx{
2721 .error_token = token.index,
2722 .opt_ctx = opt_ctx,
2723 },
2724 }) catch unreachable;
2725 continue;
2726 },
2727 Token.Id.Keyword_anyerror => {
2728 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ErrorType, token.index);
2729 continue;
2730 },
2731 Token.Id.Keyword_packed => {
2732 stack.append(State{
2733 .ContainerKind = ContainerKindCtx{
2734 .opt_ctx = opt_ctx,
2735 .layout_token = token.index,
2736 },
2737 }) catch unreachable;
2738 continue;
2739 },
2740 Token.Id.Keyword_extern => {
2741 stack.append(State{
2742 .ExternType = ExternTypeCtx{
2743 .opt_ctx = opt_ctx,
2744 .extern_token = token.index,
2745 .comments = null,
2746 },
2747 }) catch unreachable;
2748 continue;
2749 },
2750 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2751 prevToken(&tok_it, tree);
2752 stack.append(State{
2753 .ContainerKind = ContainerKindCtx{
2754 .opt_ctx = opt_ctx,
2755 .layout_token = null,
2756 },
2757 }) catch unreachable;
2261 slice_type.const_token = const_token;
27582262 continue;
2759 },
2760 Token.Id.Identifier => {
2761 stack.append(State{
2762 .MaybeLabeledExpression = MaybeLabeledExpressionCtx{
2763 .label = token.index,
2764 .opt_ctx = opt_ctx,
2765 },
2766 }) catch unreachable;
2767 continue;
2768 },
2769 Token.Id.Keyword_fn => {
2770 const fn_proto = try arena.create(ast.Node.FnProto);
2771 fn_proto.* = ast.Node.FnProto{
2772 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2773 .doc_comments = null,
2774 .visib_token = null,
2775 .name_token = null,
2776 .fn_token = token.index,
2777 .params = ast.Node.FnProto.ParamList.init(arena),
2778 .return_type = undefined,
2779 .var_args_token = null,
2780 .extern_export_inline_token = null,
2781 .cc_token = null,
2782 .async_attr = null,
2783 .body_node = null,
2784 .lib_name = null,
2785 .align_expr = null,
2786 .section_expr = null,
2787 };
2788 opt_ctx.store(&fn_proto.base);
2789 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2790 continue;
2791 },
2792 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2793 const fn_proto = try arena.create(ast.Node.FnProto);
2794 fn_proto.* = ast.Node.FnProto{
2795 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2796 .doc_comments = null,
2797 .visib_token = null,
2798 .name_token = null,
2799 .fn_token = undefined,
2800 .params = ast.Node.FnProto.ParamList.init(arena),
2801 .return_type = undefined,
2802 .var_args_token = null,
2803 .extern_export_inline_token = null,
2804 .cc_token = token.index,
2805 .async_attr = null,
2806 .body_node = null,
2807 .lib_name = null,
2808 .align_expr = null,
2809 .section_expr = null,
2810 };
2811 opt_ctx.store(&fn_proto.base);
2812 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2813 try stack.append(State{
2814 .ExpectTokenSave = ExpectTokenSave{
2815 .id = Token.Id.Keyword_fn,
2816 .ptr = &fn_proto.fn_token,
2817 },
2818 });
2819 continue;
2820 },
2821 Token.Id.Keyword_asm => {
2822 const node = try arena.create(ast.Node.Asm);
2823 node.* = ast.Node.Asm{
2824 .base = ast.Node{ .id = ast.Node.Id.Asm },
2825 .asm_token = token.index,
2826 .volatile_token = null,
2827 .template = undefined,
2828 .outputs = ast.Node.Asm.OutputList.init(arena),
2829 .inputs = ast.Node.Asm.InputList.init(arena),
2830 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2831 .rparen = undefined,
2832 };
2833 opt_ctx.store(&node.base);
2834
2835 stack.append(State{
2836 .ExpectTokenSave = ExpectTokenSave{
2837 .id = Token.Id.RParen,
2838 .ptr = &node.rparen,
2839 },
2840 }) catch unreachable;
2841 try stack.append(State{ .AsmClobberItems = &node.clobbers });
2842 try stack.append(State{ .IfToken = Token.Id.Colon });
2843 try stack.append(State{ .AsmInputItems = &node.inputs });
2844 try stack.append(State{ .IfToken = Token.Id.Colon });
2845 try stack.append(State{ .AsmOutputItems = &node.outputs });
2846 try stack.append(State{ .IfToken = Token.Id.Colon });
2847 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.template } });
2848 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2849 try stack.append(State{
2850 .OptionalTokenSave = OptionalTokenSave{
2851 .id = Token.Id.Keyword_volatile,
2852 .ptr = &node.volatile_token,
2853 },
2854 });
2855 },
2856 Token.Id.Keyword_inline => {
2857 stack.append(State{
2858 .Inline = InlineCtx{
2859 .label = null,
2860 .inline_token = token.index,
2861 .opt_ctx = opt_ctx,
2862 },
2863 }) catch unreachable;
2263 }
2264 if (eatToken(it, .Keyword_volatile)) |volatile_token| {
2265 if (slice_type.volatile_token != null) {
2266 try tree.errors.push(AstError{
2267 .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index },
2268 });
2269 return error.ParseError;
2270 }
2271 slice_type.volatile_token = volatile_token;
28642272 continue;
2865 },
2866 else => {
2867 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr.*, token.index)) {
2868 prevToken(&tok_it, tree);
2869 if (opt_ctx != OptionalCtx.Optional) {
2870 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };
2871 return tree;
2872 }
2273 }
2274 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
2275 if (slice_type.allowzero_token != null) {
2276 try tree.errors.push(AstError{
2277 .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index },
2278 });
2279 return error.ParseError;
28732280 }
2281 slice_type.allowzero_token = allowzero_token;
28742282 continue;
2875 },
2876 }
2877 },
2878
2879 State.ErrorTypeOrSetDecl => |ctx| {
2880 if (eatToken(&tok_it, tree, Token.Id.LBrace) == null) {
2881 const node = try arena.create(ast.Node.InfixOp);
2882 node.* = ast.Node.InfixOp{
2883 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2884 .lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base,
2885 .op_token = undefined,
2886 .op = ast.Node.InfixOp.Op.Period,
2887 .rhs = undefined,
2888 };
2889 ctx.opt_ctx.store(&node.base);
2890 stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2891 try stack.append(State{
2892 .ExpectTokenSave = ExpectTokenSave{
2893 .id = Token.Id.Period,
2894 .ptr = &node.op_token,
2895 },
2896 });
2897 continue;
2283 }
2284 break;
28982285 }
2899
2900 const node = try arena.create(ast.Node.ErrorSetDecl);
2901 node.* = ast.Node.ErrorSetDecl{
2902 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
2903 .error_token = ctx.error_token,
2904 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2905 .rbrace_token = undefined,
2906 };
2907 ctx.opt_ctx.store(&node.base);
2908
2909 stack.append(State{
2910 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)){
2911 .list = &node.decls,
2912 .ptr = &node.rbrace_token,
2913 },
2914 }) catch unreachable;
2915 continue;
29162286 },
2917 State.StringLiteral => |opt_ctx| {
2918 const token = nextToken(&tok_it, tree);
2919 const token_index = token.index;
2920 const token_ptr = token.ptr;
2921 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, tree)) orelse {
2922 prevToken(&tok_it, tree);
2923 if (opt_ctx != OptionalCtx.Optional) {
2924 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
2925 return tree;
2926 }
2287 else => unreachable,
2288 }
2289 return node;
2290 }
29272291
2928 continue;
2292 if (try parsePtrTypeStart(arena, it, tree)) |node| {
2293 // If the token encountered was **, there will be two nodes instead of one.
2294 // The attributes should be applied to the rightmost operator.
2295 const prefix_op = node.cast(Node.PrefixOp).?;
2296 var ptr_info = if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk)
2297 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2298 else
2299 &prefix_op.op.PtrType;
2300
2301 while (true) {
2302 if (eatToken(it, .Keyword_align)) |align_token| {
2303 const lparen = try expectToken(it, tree, .LParen);
2304 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
2305 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
29292306 });
2930 },
2931
2932 State.Identifier => |opt_ctx| {
2933 if (eatToken(&tok_it, tree, Token.Id.Identifier)) |ident_token| {
2934 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2935 continue;
2936 }
29372307
2938 if (opt_ctx != OptionalCtx.Optional) {
2939 const token = nextToken(&tok_it, tree);
2940 const token_index = token.index;
2941 const token_ptr = token.ptr;
2942 ((try tree.errors.addOne())).* = Error{
2943 .ExpectedToken = Error.ExpectedToken{
2944 .token = token_index,
2945 .expected_id = Token.Id.Identifier,
2946 },
2947 };
2948 return tree;
2949 }
2950 },
2308 // Optional bit range
2309 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {
2310 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{
2311 .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index },
2312 });
2313 _ = try expectToken(it, tree, .Colon);
2314 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{
2315 .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index },
2316 });
29512317
2952 State.ErrorTag => |node_ptr| {
2953 const comments = try eatDocComments(arena, &tok_it, tree);
2954 const ident_token = nextToken(&tok_it, tree);
2955 const ident_token_index = ident_token.index;
2956 const ident_token_ptr = ident_token.ptr;
2957 if (ident_token_ptr.id != Token.Id.Identifier) {
2958 ((try tree.errors.addOne())).* = Error{
2959 .ExpectedToken = Error.ExpectedToken{
2960 .token = ident_token_index,
2961 .expected_id = Token.Id.Identifier,
2962 },
2318 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
2319 .start = range_start,
2320 .end = range_end,
29632321 };
2964 return tree;
2965 }
2322 } else null;
2323 _ = try expectToken(it, tree, .RParen);
29662324
2967 const node = try arena.create(ast.Node.ErrorTag);
2968 node.* = ast.Node.ErrorTag{
2969 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },
2970 .doc_comments = comments,
2971 .name_token = ident_token_index,
2325 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
2326 .node = expr_node,
2327 .bit_range = bit_range,
29722328 };
2973 node_ptr.* = &node.base;
2974 continue;
2975 },
29762329
2977 State.ExpectToken => |token_id| {
2978 const token = nextToken(&tok_it, tree);
2979 const token_index = token.index;
2980 const token_ptr = token.ptr;
2981 if (token_ptr.id != token_id) {
2982 ((try tree.errors.addOne())).* = Error{
2983 .ExpectedToken = Error.ExpectedToken{
2984 .token = token_index,
2985 .expected_id = token_id,
2986 },
2987 };
2988 return tree;
2989 }
2990 continue;
2991 },
2992 State.ExpectTokenSave => |expect_token_save| {
2993 const token = nextToken(&tok_it, tree);
2994 const token_index = token.index;
2995 const token_ptr = token.ptr;
2996 if (token_ptr.id != expect_token_save.id) {
2997 ((try tree.errors.addOne())).* = Error{
2998 .ExpectedToken = Error.ExpectedToken{
2999 .token = token_index,
3000 .expected_id = expect_token_save.id,
3001 },
3002 };
3003 return tree;
3004 }
3005 expect_token_save.ptr.* = token_index;
30062330 continue;
3007 },
3008 State.IfToken => |token_id| {
3009 if (eatToken(&tok_it, tree, token_id)) |_| {
3010 continue;
3011 }
3012
3013 _ = stack.pop();
2331 }
2332 if (eatToken(it, .Keyword_const)) |const_token| {
2333 ptr_info.const_token = const_token;
30142334 continue;
3015 },
3016 State.IfTokenSave => |if_token_save| {
3017 if (eatToken(&tok_it, tree, if_token_save.id)) |token_index| {
3018 (if_token_save.ptr).* = token_index;
3019 continue;
3020 }
3021
3022 _ = stack.pop();
2335 }
2336 if (eatToken(it, .Keyword_volatile)) |volatile_token| {
2337 ptr_info.volatile_token = volatile_token;
30232338 continue;
3024 },
3025 State.OptionalTokenSave => |optional_token_save| {
3026 if (eatToken(&tok_it, tree, optional_token_save.id)) |token_index| {
3027 (optional_token_save.ptr).* = token_index;
3028 continue;
3029 }
3030
2339 }
2340 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
2341 ptr_info.allowzero_token = allowzero_token;
30312342 continue;
3032 },
2343 }
2344 break;
30332345 }
2346
2347 return node;
30342348 }
3035}
30362349
3037const AnnotatedToken = struct {
3038 ptr: *Token,
3039 index: TokenIndex,
3040};
2350 return null;
2351}
30412352
3042const TopLevelDeclCtx = struct {
3043 decls: *ast.Node.Root.DeclList,
3044 visib_token: ?TokenIndex,
3045 extern_export_inline_token: ?AnnotatedToken,
3046 lib_name: ?*ast.Node,
3047 comments: ?*ast.Node.DocComment,
3048};
2353/// SuffixOp
2354/// <- LBRACKET Expr (DOT2 Expr?)? RBRACKET
2355/// / DOT IDENTIFIER
2356/// / DOTASTERISK
2357/// / DOTQUESTIONMARK
2358fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2359 const Op = Node.SuffixOp.Op;
2360 const OpAndToken = struct {
2361 op: Node.SuffixOp.Op,
2362 token: TokenIndex,
2363 };
2364 const op_and_token = blk: {
2365 if (eatToken(it, .LBracket)) |_| {
2366 const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{
2367 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2368 });
2369
2370 if (eatToken(it, .Ellipsis2) != null) {
2371 const end_expr = try parseExpr(arena, it, tree);
2372 break :blk OpAndToken{
2373 .op = Op{
2374 .Slice = Op.Slice{
2375 .start = index_expr,
2376 .end = end_expr,
2377 },
2378 },
2379 .token = try expectToken(it, tree, .RBracket),
2380 };
2381 }
30492382
3050const VarDeclCtx = struct {
3051 mut_token: TokenIndex,
3052 visib_token: ?TokenIndex,
3053 thread_local_token: ?TokenIndex,
3054 comptime_token: ?TokenIndex,
3055 extern_export_token: ?TokenIndex,
3056 lib_name: ?*ast.Node,
3057 list: *ast.Node.Root.DeclList,
3058 comments: ?*ast.Node.DocComment,
3059};
2383 break :blk OpAndToken{
2384 .op = Op{ .ArrayAccess = index_expr },
2385 .token = try expectToken(it, tree, .RBracket),
2386 };
2387 }
30602388
3061const TopLevelExternOrFieldCtx = struct {
3062 visib_token: TokenIndex,
3063 container_decl: *ast.Node.ContainerDecl,
3064 comments: ?*ast.Node.DocComment,
3065};
2389 if (eatToken(it, .Period)) |period| {
2390 if (try parseIdentifier(arena, it, tree)) |identifier| {
2391 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2392 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should
2393 // this grammar rule be altered?
2394 const node = try arena.create(Node.InfixOp);
2395 node.* = Node.InfixOp{
2396 .base = Node{ .id = .InfixOp },
2397 .op_token = period,
2398 .lhs = undefined, // set by caller
2399 .op = Node.InfixOp.Op.Period,
2400 .rhs = identifier,
2401 };
2402 return &node.base;
2403 }
2404 if (eatToken(it, .Asterisk)) |asterisk| {
2405 break :blk OpAndToken{ .op = Op{ .Deref = {} }, .token = asterisk };
2406 }
2407 if (eatToken(it, .QuestionMark)) |question_mark| {
2408 break :blk OpAndToken{ .op = Op{ .UnwrapOptional = {} }, .token = question_mark };
2409 }
2410 try tree.errors.push(AstError{
2411 .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index },
2412 });
2413 return null;
2414 }
30662415
3067const ExternTypeCtx = struct {
3068 opt_ctx: OptionalCtx,
3069 extern_token: TokenIndex,
3070 comments: ?*ast.Node.DocComment,
3071};
2416 return null;
2417 };
30722418
3073const ContainerKindCtx = struct {
3074 opt_ctx: OptionalCtx,
3075 layout_token: ?TokenIndex,
3076};
2419 const node = try arena.create(Node.SuffixOp);
2420 node.* = Node.SuffixOp{
2421 .base = Node{ .id = .SuffixOp },
2422 .lhs = undefined, // set by caller
2423 .op = op_and_token.op,
2424 .rtoken = op_and_token.token,
2425 };
2426 return &node.base;
2427}
30772428
3078const ExpectTokenSave = struct {
3079 id: Token.Id,
3080 ptr: *TokenIndex,
3081};
2429/// AsyncPrefix <- KEYWORD_async (LARROW PrefixExpr RARROW)?
2430fn parseAsyncPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2431 const async_token = eatToken(it, .Keyword_async) orelse return null;
2432 var rangle_bracket: ?TokenIndex = null;
2433 const expr_node = if (eatToken(it, .AngleBracketLeft)) |_| blk: {
2434 const prefix_expr = try expectNode(arena, it, tree, parsePrefixExpr, AstError{
2435 .ExpectedPrefixExpr = AstError.ExpectedPrefixExpr{ .token = it.index },
2436 });
2437 rangle_bracket = try expectToken(it, tree, .AngleBracketRight);
2438 break :blk prefix_expr;
2439 } else null;
2440
2441 const node = try arena.create(Node.AsyncAttribute);
2442 node.* = Node.AsyncAttribute{
2443 .base = Node{ .id = .AsyncAttribute },
2444 .async_token = async_token,
2445 .allocator_type = expr_node,
2446 .rangle_bracket = rangle_bracket,
2447 };
2448 return &node.base;
2449}
30822450
3083const OptionalTokenSave = struct {
3084 id: Token.Id,
3085 ptr: *?TokenIndex,
3086};
2451/// FnCallArguments <- LPAREN ExprList RPAREN
2452/// ExprList <- (Expr COMMA)* Expr?
2453fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {
2454 if (eatToken(it, .LParen) == null) return null;
2455 const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(arena, it, tree);
2456 const rparen = try expectToken(it, tree, .RParen);
2457 return AnnotatedParamList{ .list = list, .rparen = rparen };
2458}
30872459
3088const ExprListCtx = struct {
3089 list: *ast.Node.SuffixOp.Op.InitList,
3090 end: Token.Id,
3091 ptr: *TokenIndex,
2460const AnnotatedParamList = struct {
2461 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)
2462 rparen: TokenIndex,
30922463};
30932464
3094const FieldCtx = struct {
3095 container_decl: *ast.Node.ContainerDecl,
3096 doc_comments: *?*ast.Node.DocComment,
3097};
2465/// ArrayTypeStart <- LBRACKET Expr? RBRACKET
2466fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2467 const lbracket = eatToken(it, .LBracket) orelse return null;
2468 const expr = try parseExpr(arena, it, tree);
2469 const rbracket = try expectToken(it, tree, .RBracket);
2470
2471 const op = if (expr) |element_type|
2472 Node.PrefixOp.Op{ .ArrayType = element_type }
2473 else
2474 Node.PrefixOp.Op{
2475 .SliceType = Node.PrefixOp.PtrInfo{
2476 .allowzero_token = null,
2477 .align_info = null,
2478 .const_token = null,
2479 .volatile_token = null,
2480 },
2481 };
30982482
3099fn ListSave(comptime List: type) type {
3100 return struct {
3101 list: *List,
3102 ptr: *TokenIndex,
2483 const node = try arena.create(Node.PrefixOp);
2484 node.* = Node.PrefixOp{
2485 .base = Node{ .id = .PrefixOp },
2486 .op_token = lbracket,
2487 .op = op,
2488 .rhs = undefined, // set by caller
31032489 };
2490 return &node.base;
31042491}
31052492
3106const MaybeLabeledExpressionCtx = struct {
3107 label: TokenIndex,
3108 opt_ctx: OptionalCtx,
3109};
2493/// PtrTypeStart
2494/// <- ASTERISK
2495/// / ASTERISK2
2496/// / PTRUNKNOWN
2497/// / PTRC
2498fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2499 const token = eatAnnotatedToken(it, .Asterisk) orelse
2500 eatAnnotatedToken(it, .AsteriskAsterisk) orelse
2501 eatAnnotatedToken(it, .BracketStarBracket) orelse
2502 eatAnnotatedToken(it, .BracketStarCBracket) orelse
2503 return null;
2504
2505 const node = try arena.create(Node.PrefixOp);
2506 node.* = Node.PrefixOp{
2507 .base = Node{ .id = .PrefixOp },
2508 .op_token = token.index,
2509 .op = Node.PrefixOp.Op{
2510 .PtrType = Node.PrefixOp.PtrInfo{
2511 .allowzero_token = null,
2512 .align_info = null,
2513 .const_token = null,
2514 .volatile_token = null,
2515 },
2516 },
2517 .rhs = undefined, // set by caller
2518 };
31102519
3111const LabelCtx = struct {
3112 label: ?TokenIndex,
3113 opt_ctx: OptionalCtx,
3114};
2520 // Special case for **, which is its own token
2521 if (token.ptr.id == .AsteriskAsterisk) {
2522 const child = try arena.create(Node.PrefixOp);
2523 child.* = Node.PrefixOp{
2524 .base = Node{ .id = .PrefixOp },
2525 .op_token = token.index,
2526 .op = Node.PrefixOp.Op{
2527 .PtrType = Node.PrefixOp.PtrInfo{
2528 .allowzero_token = null,
2529 .align_info = null,
2530 .const_token = null,
2531 .volatile_token = null,
2532 },
2533 },
2534 .rhs = undefined, // set by caller
2535 };
2536 node.rhs = &child.base;
2537 }
31152538
3116const InlineCtx = struct {
3117 label: ?TokenIndex,
3118 inline_token: ?TokenIndex,
3119 opt_ctx: OptionalCtx,
3120};
2539 return &node.base;
2540}
31212541
3122const LoopCtx = struct {
3123 label: ?TokenIndex,
3124 inline_token: ?TokenIndex,
3125 loop_token: TokenIndex,
3126 opt_ctx: OptionalCtx,
3127};
2542/// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
2543fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2544 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;
2545 const lbrace = try expectToken(it, tree, .LBrace);
2546 const members = try parseContainerMembers(arena, it, tree);
2547 const rbrace = try expectToken(it, tree, .RBrace);
31282548
3129const AsyncEndCtx = struct {
3130 ctx: OptionalCtx,
3131 attribute: *ast.Node.AsyncAttribute,
3132};
2549 const decl_type = node.cast(Node.ContainerDecl).?;
2550 decl_type.fields_and_decls = members;
2551 decl_type.lbrace_token = lbrace;
2552 decl_type.rbrace_token = rbrace;
31332553
3134const ErrorTypeOrSetDeclCtx = struct {
3135 opt_ctx: OptionalCtx,
3136 error_token: TokenIndex,
3137};
2554 return node;
2555}
31382556
3139const ParamDeclEndCtx = struct {
3140 fn_proto: *ast.Node.FnProto,
3141 param_decl: *ast.Node.ParamDecl,
3142};
2557/// ContainerDeclType
2558/// <- KEYWORD_struct
2559/// / KEYWORD_enum (LPAREN Expr RPAREN)?
2560/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2561fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2562 const kind_token = nextToken(it);
2563
2564 const init_arg_expr = switch (kind_token.ptr.id) {
2565 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
2566 .Keyword_enum => blk: {
2567 if (eatToken(it, .LParen) != null) {
2568 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
2569 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2570 });
2571 _ = try expectToken(it, tree, .RParen);
2572 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2573 }
2574 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2575 },
2576 .Keyword_union => blk: {
2577 if (eatToken(it, .LParen) != null) {
2578 if (eatToken(it, .Keyword_enum) != null) {
2579 if (eatToken(it, .LParen) != null) {
2580 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
2581 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2582 });
2583 _ = try expectToken(it, tree, .RParen);
2584 _ = try expectToken(it, tree, .RParen);
2585 break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
2586 }
2587 _ = try expectToken(it, tree, .RParen);
2588 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
2589 }
2590 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
2591 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2592 });
2593 _ = try expectToken(it, tree, .RParen);
2594 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
2595 }
2596 break :blk Node.ContainerDecl.InitArg{ .None = {} };
2597 },
2598 else => {
2599 putBackToken(it, kind_token.index);
2600 return null;
2601 },
2602 };
31432603
3144const ComptimeStatementCtx = struct {
3145 comptime_token: TokenIndex,
3146 block: *ast.Node.Block,
3147};
2604 const node = try arena.create(Node.ContainerDecl);
2605 node.* = Node.ContainerDecl{
2606 .base = Node{ .id = .ContainerDecl },
2607 .layout_token = null,
2608 .kind_token = kind_token.index,
2609 .init_arg_expr = init_arg_expr,
2610 .fields_and_decls = undefined, // set by caller
2611 .lbrace_token = undefined, // set by caller
2612 .rbrace_token = undefined, // set by caller
2613 };
2614 return &node.base;
2615}
31482616
3149const OptionalCtx = union(enum) {
3150 Optional: *?*ast.Node,
3151 RequiredNull: *?*ast.Node,
3152 Required: **ast.Node,
2617/// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
2618fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2619 _ = eatToken(it, .Keyword_align) orelse return null;
2620 _ = try expectToken(it, tree, .LParen);
2621 const expr = try expectNode(arena, it, tree, parseExpr, AstError{
2622 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2623 });
2624 _ = try expectToken(it, tree, .RParen);
2625 return expr;
2626}
31532627
3154 pub fn store(self: OptionalCtx, value: *ast.Node) void {
3155 switch (self) {
3156 OptionalCtx.Optional => |ptr| ptr.* = value,
3157 OptionalCtx.RequiredNull => |ptr| ptr.* = value,
3158 OptionalCtx.Required => |ptr| ptr.* = value,
3159 }
3160 }
2628/// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
2629/// Only ErrorSetDecl parses an IdentifierList
2630fn parseErrorTagList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.ErrorSetDecl.DeclList {
2631 return try ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(arena, it, tree);
2632}
31612633
3162 pub fn get(self: OptionalCtx) ?*ast.Node {
3163 switch (self) {
3164 OptionalCtx.Optional => |ptr| return ptr.*,
3165 OptionalCtx.RequiredNull => |ptr| return ptr.*.?,
3166 OptionalCtx.Required => |ptr| return ptr.*,
3167 }
3168 }
2634/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2635fn parseSwitchProngList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Switch.CaseList {
2636 return try ListParseFn(Node.Switch.CaseList, parseSwitchProng)(arena, it, tree);
2637}
31692638
3170 pub fn toRequired(self: OptionalCtx) OptionalCtx {
3171 switch (self) {
3172 OptionalCtx.Optional => |ptr| {
3173 return OptionalCtx{ .RequiredNull = ptr };
3174 },
3175 OptionalCtx.RequiredNull => |ptr| return self,
3176 OptionalCtx.Required => |ptr| return self,
3177 }
3178 }
3179};
2639/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2640fn parseAsmOutputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.OutputList {
2641 return try ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(arena, it, tree);
2642}
31802643
3181const AddCommentsCtx = struct {
3182 node_ptr: **ast.Node,
3183 comments: ?*ast.Node.DocComment,
3184};
2644/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2645fn parseAsmInputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.InputList {
2646 return try ListParseFn(Node.Asm.InputList, parseAsmInputItem)(arena, it, tree);
2647}
31852648
3186const State = union(enum) {
3187 TopLevel,
3188 TopLevelExtern: TopLevelDeclCtx,
3189 TopLevelLibname: TopLevelDeclCtx,
3190 TopLevelDecl: TopLevelDeclCtx,
3191 TopLevelExternOrField: TopLevelExternOrFieldCtx,
3192
3193 ContainerKind: ContainerKindCtx,
3194 ContainerInitArgStart: *ast.Node.ContainerDecl,
3195 ContainerInitArg: *ast.Node.ContainerDecl,
3196 ContainerDecl: *ast.Node.ContainerDecl,
3197
3198 ThreadLocal: VarDeclCtx,
3199 VarDecl: VarDeclCtx,
3200 VarDeclAlign: *ast.Node.VarDecl,
3201 VarDeclSection: *ast.Node.VarDecl,
3202 VarDeclEq: *ast.Node.VarDecl,
3203 VarDeclSemiColon: *ast.Node.VarDecl,
3204
3205 FnDef: *ast.Node.FnProto,
3206 FnProto: *ast.Node.FnProto,
3207 FnProtoAlign: *ast.Node.FnProto,
3208 FnProtoSection: *ast.Node.FnProto,
3209 FnProtoReturnType: *ast.Node.FnProto,
3210
3211 ParamDecl: *ast.Node.FnProto,
3212 ParamDeclAliasOrComptime: *ast.Node.ParamDecl,
3213 ParamDeclName: *ast.Node.ParamDecl,
3214 ParamDeclEnd: ParamDeclEndCtx,
3215 ParamDeclComma: *ast.Node.FnProto,
3216
3217 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
3218 LabeledExpression: LabelCtx,
3219 Inline: InlineCtx,
3220 While: LoopCtx,
3221 WhileContinueExpr: *?*ast.Node,
3222 For: LoopCtx,
3223 Else: *?*ast.Node.Else,
3224
3225 Block: *ast.Node.Block,
3226 Statement: *ast.Node.Block,
3227 ComptimeStatement: ComptimeStatementCtx,
3228 Semicolon: **ast.Node,
3229
3230 AsmOutputItems: *ast.Node.Asm.OutputList,
3231 AsmOutputReturnOrType: *ast.Node.AsmOutput,
3232 AsmInputItems: *ast.Node.Asm.InputList,
3233 AsmClobberItems: *ast.Node.Asm.ClobberList,
3234
3235 ExprListItemOrEnd: ExprListCtx,
3236 ExprListCommaOrEnd: ExprListCtx,
3237 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3238 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3239 FieldListCommaOrEnd: FieldCtx,
3240 FieldInitValue: OptionalCtx,
3241 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3242 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3243 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
3244 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
3245 SwitchCaseFirstItem: *ast.Node.SwitchCase,
3246 SwitchCaseItemCommaOrEnd: *ast.Node.SwitchCase,
3247 SwitchCaseItemOrEnd: *ast.Node.SwitchCase,
3248
3249 SuspendBody: *ast.Node.Suspend,
3250 AsyncAllocator: *ast.Node.AsyncAttribute,
3251 AsyncEnd: AsyncEndCtx,
3252
3253 ExternType: ExternTypeCtx,
3254 SliceOrArrayAccess: *ast.Node.SuffixOp,
3255 SliceOrArrayType: *ast.Node.PrefixOp,
3256 PtrTypeModifiers: *ast.Node.PrefixOp.PtrInfo,
3257 AlignBitRange: *ast.Node.PrefixOp.PtrInfo.Align,
3258
3259 Payload: OptionalCtx,
3260 PointerPayload: OptionalCtx,
3261 PointerIndexPayload: OptionalCtx,
3262
3263 Expression: OptionalCtx,
3264 RangeExpressionBegin: OptionalCtx,
3265 RangeExpressionEnd: OptionalCtx,
3266 AssignmentExpressionBegin: OptionalCtx,
3267 AssignmentExpressionEnd: OptionalCtx,
3268 UnwrapExpressionBegin: OptionalCtx,
3269 UnwrapExpressionEnd: OptionalCtx,
3270 BoolOrExpressionBegin: OptionalCtx,
3271 BoolOrExpressionEnd: OptionalCtx,
3272 BoolAndExpressionBegin: OptionalCtx,
3273 BoolAndExpressionEnd: OptionalCtx,
3274 ComparisonExpressionBegin: OptionalCtx,
3275 ComparisonExpressionEnd: OptionalCtx,
3276 BinaryOrExpressionBegin: OptionalCtx,
3277 BinaryOrExpressionEnd: OptionalCtx,
3278 BinaryXorExpressionBegin: OptionalCtx,
3279 BinaryXorExpressionEnd: OptionalCtx,
3280 BinaryAndExpressionBegin: OptionalCtx,
3281 BinaryAndExpressionEnd: OptionalCtx,
3282 BitShiftExpressionBegin: OptionalCtx,
3283 BitShiftExpressionEnd: OptionalCtx,
3284 AdditionExpressionBegin: OptionalCtx,
3285 AdditionExpressionEnd: OptionalCtx,
3286 MultiplyExpressionBegin: OptionalCtx,
3287 MultiplyExpressionEnd: OptionalCtx,
3288 CurlySuffixExpressionBegin: OptionalCtx,
3289 CurlySuffixExpressionEnd: OptionalCtx,
3290 TypeExprBegin: OptionalCtx,
3291 TypeExprEnd: OptionalCtx,
3292 PrefixOpExpression: OptionalCtx,
3293 SuffixOpExpressionBegin: OptionalCtx,
3294 SuffixOpExpressionEnd: OptionalCtx,
3295 PrimaryExpression: OptionalCtx,
3296
3297 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3298 StringLiteral: OptionalCtx,
3299 Identifier: OptionalCtx,
3300 ErrorTag: **ast.Node,
3301
3302 IfToken: Token.Id,
3303 IfTokenSave: ExpectTokenSave,
3304 ExpectToken: Token.Id,
3305 ExpectTokenSave: ExpectTokenSave,
3306 OptionalTokenSave: OptionalTokenSave,
3307};
2649/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2650fn parseParamDeclList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.FnProto.ParamList {
2651 return try ListParseFn(Node.FnProto.ParamList, parseParamDecl)(arena, it, tree);
2652}
33082653
3309fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*ast.Node.DocComment) !void {
3310 const node = blk: {
3311 if (result.*) |comment_node| {
3312 break :blk comment_node;
3313 } else {
3314 const comment_node = try arena.create(ast.Node.DocComment);
3315 comment_node.* = ast.Node.DocComment{
3316 .base = ast.Node{ .id = ast.Node.Id.DocComment },
3317 .lines = ast.Node.DocComment.LineList.init(arena),
3318 };
3319 result.* = comment_node;
3320 break :blk comment_node;
3321 }
3322 };
3323 try node.lines.push(line_comment);
2654fn ParseFn(comptime T: type) type {
2655 return fn (*Allocator, *TokenIterator, *Tree) Error!T;
33242656}
33252657
3326fn eatDocComments(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) !?*ast.Node.DocComment {
3327 var result: ?*ast.Node.DocComment = null;
3328 while (true) {
3329 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3330 try pushDocComment(arena, line_comment, &result);
3331 continue;
2658const NodeParseFn = fn (*Allocator, *TokenIterator, *Tree) Error!?*Node;
2659
2660fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
2661 return struct {
2662 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !L {
2663 var list = L.init(arena);
2664 while (try nodeParseFn(arena, it, tree)) |node| {
2665 try list.push(node);
2666 if (eatToken(it, .Comma) == null) break;
2667 }
2668 return list;
33322669 }
3333 break;
3334 }
3335 return result;
2670 }.parse;
33362671}
33372672
3338fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterator, token_ptr: *const Token, token_index: TokenIndex, tree: *ast.Tree) !?*ast.Node {
3339 switch (token_ptr.id) {
3340 Token.Id.StringLiteral => {
3341 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3342 },
3343 Token.Id.MultilineStringLiteralLine => {
3344 const node = try arena.create(ast.Node.MultilineStringLiteral);
3345 node.* = ast.Node.MultilineStringLiteral{
3346 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
3347 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
2673fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
2674 return struct {
2675 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
2676 const op_token = eatToken(it, token) orelse return null;
2677 const node = try arena.create(Node.InfixOp);
2678 node.* = Node.InfixOp{
2679 .base = Node{ .id = .InfixOp },
2680 .op_token = op_token,
2681 .lhs = undefined, // set by caller
2682 .op = op,
2683 .rhs = undefined, // set by caller
33482684 };
3349 try node.lines.push(token_index);
3350 while (true) {
3351 const multiline_str = nextToken(tok_it, tree);
3352 const multiline_str_index = multiline_str.index;
3353 const multiline_str_ptr = multiline_str.ptr;
3354 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3355 prevToken(tok_it, tree);
3356 break;
3357 }
2685 return &node.base;
2686 }
2687 }.parse;
2688}
33582689
3359 try node.lines.push(multiline_str_index);
3360 }
2690// Helper parsers not included in the grammar
33612691
3362 return &node.base;
3363 },
3364 // TODO: We shouldn't need a cast, but:
3365 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
3366 else => return (?*ast.Node)(null),
3367 }
2692fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2693 const token = eatToken(it, .Builtin) orelse return null;
2694 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
2695 try tree.errors.push(AstError{
2696 .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index },
2697 });
2698 return error.ParseError;
2699 };
2700 const node = try arena.create(Node.BuiltinCall);
2701 node.* = Node.BuiltinCall{
2702 .base = Node{ .id = .BuiltinCall },
2703 .builtin_token = token,
2704 .params = params.list,
2705 .rparen_token = params.rparen,
2706 };
2707 return &node.base;
33682708}
33692709
3370fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool {
3371 switch (token_ptr.id) {
3372 Token.Id.Keyword_suspend => {
3373 const node = try arena.create(ast.Node.Suspend);
3374 node.* = ast.Node.Suspend{
3375 .base = ast.Node{ .id = ast.Node.Id.Suspend },
3376 .suspend_token = token_index,
3377 .body = null,
3378 };
3379 ctx.store(&node.base);
2710fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2711 const doc_comments = try parseDocComment(arena, it, tree); // no need to rewind on failure
2712 const token = eatToken(it, .Identifier) orelse return null;
33802713
3381 stack.append(State{ .SuspendBody = node }) catch unreachable;
3382 return true;
3383 },
3384 Token.Id.Keyword_if => {
3385 const node = try arena.create(ast.Node.If);
3386 node.* = ast.Node.If{
3387 .base = ast.Node{ .id = ast.Node.Id.If },
3388 .if_token = token_index,
3389 .condition = undefined,
3390 .payload = null,
3391 .body = undefined,
3392 .@"else" = null,
3393 };
3394 ctx.store(&node.base);
3395
3396 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
3397 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
3398 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
3399 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3400 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
3401 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3402 return true;
3403 },
3404 Token.Id.Keyword_while => {
3405 stack.append(State{
3406 .While = LoopCtx{
3407 .label = null,
3408 .inline_token = null,
3409 .loop_token = token_index,
3410 .opt_ctx = ctx,
3411 },
3412 }) catch unreachable;
3413 return true;
3414 },
3415 Token.Id.Keyword_for => {
3416 stack.append(State{
3417 .For = LoopCtx{
3418 .label = null,
3419 .inline_token = null,
3420 .loop_token = token_index,
3421 .opt_ctx = ctx,
3422 },
3423 }) catch unreachable;
3424 return true;
3425 },
3426 Token.Id.Keyword_switch => {
3427 const node = try arena.create(ast.Node.Switch);
3428 node.* = ast.Node.Switch{
3429 .base = ast.Node{ .id = ast.Node.Id.Switch },
3430 .switch_token = token_index,
3431 .expr = undefined,
3432 .cases = ast.Node.Switch.CaseList.init(arena),
3433 .rbrace = undefined,
3434 };
3435 ctx.store(&node.base);
2714 const node = try arena.create(Node.ErrorTag);
2715 node.* = Node.ErrorTag{
2716 .base = Node{ .id = .ErrorTag },
2717 .doc_comments = doc_comments,
2718 .name_token = token,
2719 };
2720 return &node.base;
2721}
34362722
3437 stack.append(State{
3438 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)){
3439 .list = &node.cases,
3440 .ptr = &node.rbrace,
3441 },
3442 }) catch unreachable;
3443 try stack.append(State{ .ExpectToken = Token.Id.LBrace });
3444 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3445 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3446 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3447 return true;
3448 },
3449 Token.Id.Keyword_comptime => {
3450 const node = try arena.create(ast.Node.Comptime);
3451 node.* = ast.Node.Comptime{
3452 .base = ast.Node{ .id = ast.Node.Id.Comptime },
3453 .comptime_token = token_index,
3454 .expr = undefined,
3455 .doc_comments = null,
3456 };
3457 ctx.store(&node.base);
2723fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2724 const token = eatToken(it, .Identifier) orelse return null;
2725 const node = try arena.create(Node.Identifier);
2726 node.* = Node.Identifier{
2727 .base = Node{ .id = .Identifier },
2728 .token = token,
2729 };
2730 return &node.base;
2731}
34582732
3459 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3460 return true;
3461 },
3462 Token.Id.LBrace => {
3463 const block = try arena.create(ast.Node.Block);
3464 block.* = ast.Node.Block{
3465 .base = ast.Node{ .id = ast.Node.Id.Block },
3466 .label = null,
3467 .lbrace = token_index,
3468 .statements = ast.Node.Block.StatementList.init(arena),
3469 .rbrace = undefined,
3470 };
3471 ctx.store(&block.base);
3472 stack.append(State{ .Block = block }) catch unreachable;
3473 return true;
3474 },
3475 else => {
3476 return false;
3477 },
3478 }
2733fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2734 const token = eatToken(it, .Keyword_var) orelse return null;
2735 const node = try arena.create(Node.VarType);
2736 node.* = Node.VarType{
2737 .base = Node{ .id = .VarType },
2738 .token = token,
2739 };
2740 return &node.base;
34792741}
34802742
3481const ExpectCommaOrEndResult = union(enum) {
3482 end_token: ?TokenIndex,
3483 parse_error: Error,
3484};
2743fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node {
2744 const result = try arena.create(T);
2745 result.* = T{
2746 .base = Node{ .id = Node.typeToId(T) },
2747 .token = token,
2748 };
2749 return &result.base;
2750}
34852751
3486fn expectCommaOrEnd(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, end: Token.Id) ExpectCommaOrEndResult {
3487 const token = nextToken(tok_it, tree);
3488 const token_index = token.index;
3489 const token_ptr = token.ptr;
3490 switch (token_ptr.id) {
3491 Token.Id.Comma => return ExpectCommaOrEndResult{ .end_token = null },
3492 else => {
3493 if (end == token_ptr.id) {
3494 return ExpectCommaOrEndResult{ .end_token = token_index };
3495 }
2752// string literal or multiline string literal
2753fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2754 if (eatToken(it, .StringLiteral)) |token| {
2755 const node = try arena.create(Node.StringLiteral);
2756 node.* = Node.StringLiteral{
2757 .base = Node{ .id = .StringLiteral },
2758 .token = token,
2759 };
2760 return &node.base;
2761 }
34962762
3497 return ExpectCommaOrEndResult{
3498 .parse_error = Error{
3499 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd{
3500 .token = token_index,
3501 .end_id = end,
3502 },
3503 },
3504 };
3505 },
2763 if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {
2764 const node = try arena.create(Node.MultilineStringLiteral);
2765 node.* = Node.MultilineStringLiteral{
2766 .base = Node{ .id = .MultilineStringLiteral },
2767 .lines = Node.MultilineStringLiteral.LineList.init(arena),
2768 };
2769 try node.lines.push(first_line);
2770 while (eatToken(it, .MultilineStringLiteralLine)) |line|
2771 try node.lines.push(line);
2772
2773 return &node.base;
35062774 }
2775
2776 return null;
35072777}
35082778
3509fn tokenIdToAssignment(id: Token.Id) ?ast.Node.InfixOp.Op {
3510 // TODO: We have to cast all cases because of this:
3511 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3512 return switch (id) {
3513 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op{ .AssignBitAnd = {} },
3514 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op{ .AssignBitShiftLeft = {} },
3515 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op{ .AssignBitShiftRight = {} },
3516 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op{ .AssignTimes = {} },
3517 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op{ .AssignTimesWarp = {} },
3518 Token.Id.CaretEqual => ast.Node.InfixOp.Op{ .AssignBitXor = {} },
3519 Token.Id.Equal => ast.Node.InfixOp.Op{ .Assign = {} },
3520 Token.Id.MinusEqual => ast.Node.InfixOp.Op{ .AssignMinus = {} },
3521 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op{ .AssignMinusWrap = {} },
3522 Token.Id.PercentEqual => ast.Node.InfixOp.Op{ .AssignMod = {} },
3523 Token.Id.PipeEqual => ast.Node.InfixOp.Op{ .AssignBitOr = {} },
3524 Token.Id.PlusEqual => ast.Node.InfixOp.Op{ .AssignPlus = {} },
3525 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op{ .AssignPlusWrap = {} },
3526 Token.Id.SlashEqual => ast.Node.InfixOp.Op{ .AssignDiv = {} },
3527 else => null,
2779fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2780 const token = eatToken(it, .IntegerLiteral) orelse return null;
2781 const node = try arena.create(Node.IntegerLiteral);
2782 node.* = Node.IntegerLiteral{
2783 .base = Node{ .id = .IntegerLiteral },
2784 .token = token,
35282785 };
2786 return &node.base;
35292787}
35302788
3531fn tokenIdToUnwrapExpr(id: Token.Id) ?ast.Node.InfixOp.Op {
3532 return switch (id) {
3533 Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
3534 Token.Id.Keyword_orelse => ast.Node.InfixOp.Op{ .UnwrapOptional = void{} },
3535 else => null,
2789fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2790 const token = eatToken(it, .FloatLiteral) orelse return null;
2791 const node = try arena.create(Node.FloatLiteral);
2792 node.* = Node.FloatLiteral{
2793 .base = Node{ .id = .FloatLiteral },
2794 .token = token,
35362795 };
2796 return &node.base;
35372797}
35382798
3539fn tokenIdToComparison(id: Token.Id) ?ast.Node.InfixOp.Op {
3540 return switch (id) {
3541 Token.Id.BangEqual => ast.Node.InfixOp.Op{ .BangEqual = void{} },
3542 Token.Id.EqualEqual => ast.Node.InfixOp.Op{ .EqualEqual = void{} },
3543 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op{ .LessThan = void{} },
3544 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op{ .LessOrEqual = void{} },
3545 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op{ .GreaterThan = void{} },
3546 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op{ .GreaterOrEqual = void{} },
3547 else => null,
2799fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2800 const token = eatToken(it, .Keyword_try) orelse return null;
2801 const node = try arena.create(Node.PrefixOp);
2802 node.* = Node.PrefixOp{
2803 .base = Node{ .id = .PrefixOp },
2804 .op_token = token,
2805 .op = Node.PrefixOp.Op.Try,
2806 .rhs = undefined, // set by caller
35482807 };
2808 return &node.base;
35492809}
35502810
3551fn tokenIdToBitShift(id: Token.Id) ?ast.Node.InfixOp.Op {
3552 return switch (id) {
3553 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op{ .BitShiftLeft = void{} },
3554 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op{ .BitShiftRight = void{} },
3555 else => null,
2811fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2812 const token = eatToken(it, .Keyword_use) orelse return null;
2813 const node = try arena.create(Node.Use);
2814 node.* = Node.Use{
2815 .base = Node{ .id = .Use },
2816 .doc_comments = null,
2817 .visib_token = null,
2818 .use_token = token,
2819 .expr = undefined,
2820 .semicolon_token = undefined,
35562821 };
2822 return &node.base;
35572823}
35582824
3559fn tokenIdToAddition(id: Token.Id) ?ast.Node.InfixOp.Op {
3560 return switch (id) {
3561 Token.Id.Minus => ast.Node.InfixOp.Op{ .Sub = void{} },
3562 Token.Id.MinusPercent => ast.Node.InfixOp.Op{ .SubWrap = void{} },
3563 Token.Id.Plus => ast.Node.InfixOp.Op{ .Add = void{} },
3564 Token.Id.PlusPercent => ast.Node.InfixOp.Op{ .AddWrap = void{} },
3565 Token.Id.PlusPlus => ast.Node.InfixOp.Op{ .ArrayCat = void{} },
3566 else => null,
2825/// IfPrefix Body (KEYWORD_else Payload? Body)?
2826fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: NodeParseFn) !?*Node {
2827 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;
2828 const if_prefix = node.cast(Node.If).?;
2829
2830 if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{
2831 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2832 });
2833
2834 const else_token = eatToken(it, .Keyword_else) orelse return node;
2835 const payload = try parsePayload(arena, it, tree);
2836 const else_expr = try expectNode(arena, it, tree, parseExpr, AstError{
2837 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2838 });
2839 const else_node = try arena.create(Node.Else);
2840 else_node.* = Node.Else{
2841 .base = Node{ .id = .Else },
2842 .else_token = else_token,
2843 .payload = payload,
2844 .body = else_expr,
35672845 };
2846 if_prefix.@"else" = else_node;
2847
2848 return node;
35682849}
35692850
3570fn tokenIdToMultiply(id: Token.Id) ?ast.Node.InfixOp.Op {
3571 return switch (id) {
3572 Token.Id.Slash => ast.Node.InfixOp.Op{ .Div = void{} },
3573 Token.Id.Asterisk => ast.Node.InfixOp.Op{ .Mult = void{} },
3574 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op{ .ArrayMult = void{} },
3575 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op{ .MultWrap = void{} },
3576 Token.Id.Percent => ast.Node.InfixOp.Op{ .Mod = void{} },
3577 Token.Id.PipePipe => ast.Node.InfixOp.Op{ .MergeErrorSets = void{} },
3578 else => null,
2851/// Eat a multiline doc comment
2852fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.DocComment {
2853 var lines = Node.DocComment.LineList.init(arena);
2854 while (eatToken(it, .DocComment)) |line| {
2855 try lines.push(line);
2856 }
2857
2858 if (lines.len == 0) return null;
2859
2860 const node = try arena.create(Node.DocComment);
2861 node.* = Node.DocComment{
2862 .base = Node{ .id = .DocComment },
2863 .lines = lines,
35792864 };
2865 return node;
35802866}
35812867
3582fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
3583 return switch (id) {
3584 Token.Id.Bang => ast.Node.PrefixOp.Op{ .BoolNot = void{} },
3585 Token.Id.Tilde => ast.Node.PrefixOp.Op{ .BitNot = void{} },
3586 Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} },
3587 Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} },
3588 Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddressOf = void{} },
2868/// Eat a single-line doc comment on the same line as another node
2869fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, after_token: TokenIndex) !?*Node.DocComment {
2870 const comment_token = eatToken(it, .DocComment) orelse return null;
2871 if (tree.tokensOnSameLine(after_token, comment_token)) {
2872 const node = try arena.create(Node.DocComment);
2873 node.* = Node.DocComment{
2874 .base = Node{ .id = .DocComment },
2875 .lines = Node.DocComment.LineList.init(arena),
2876 };
2877 try node.lines.push(comment_token);
2878 return node;
2879 }
2880 putBackToken(it, comment_token);
2881 return null;
2882}
35892883
3590 Token.Id.Asterisk,
3591 Token.Id.AsteriskAsterisk,
3592 Token.Id.BracketStarBracket,
3593 Token.Id.BracketStarCBracket,
3594 => ast.Node.PrefixOp.Op{
3595 .PtrType = ast.Node.PrefixOp.PtrInfo{
3596 .align_info = null,
3597 .const_token = null,
3598 .volatile_token = null,
3599 .allowzero_token = null,
2884/// Op* Child
2885fn parsePrefixOpExpr(
2886 arena: *Allocator,
2887 it: *TokenIterator,
2888 tree: *Tree,
2889 opParseFn: NodeParseFn,
2890 childParseFn: NodeParseFn,
2891) Error!?*Node {
2892 if (try opParseFn(arena, it, tree)) |first_op| {
2893 var rightmost_op = first_op;
2894 while (true) {
2895 switch (rightmost_op.id) {
2896 .PrefixOp => {
2897 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
2898 // If the token encountered was **, there will be two nodes
2899 if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) {
2900 rightmost_op = prefix_op.rhs;
2901 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
2902 }
2903 if (try opParseFn(arena, it, tree)) |rhs| {
2904 prefix_op.rhs = rhs;
2905 rightmost_op = rhs;
2906 } else break;
2907 },
2908 .PromiseType => {
2909 const prom = rightmost_op.cast(Node.PromiseType).?;
2910 if (try opParseFn(arena, it, tree)) |rhs| {
2911 prom.result.?.return_type = rhs;
2912 rightmost_op = rhs;
2913 } else break;
2914 },
2915 else => unreachable,
2916 }
2917 }
2918
2919 // If any prefix op existed, a child node on the RHS is required
2920 switch (rightmost_op.id) {
2921 .PrefixOp => {
2922 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
2923 prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{
2924 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2925 });
36002926 },
3601 },
3602 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
3603 Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
3604 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
3605 else => null,
3606 };
2927 .PromiseType => {
2928 const prom = rightmost_op.cast(Node.PromiseType).?;
2929 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
2930 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2931 });
2932 },
2933 else => unreachable,
2934 }
2935
2936 return first_op;
2937 }
2938
2939 // Otherwise, the child node is optional
2940 return try childParseFn(arena, it, tree);
36072941}
36082942
3609fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {
3610 const result = try arena.create(T);
3611 result.* = T{
3612 .base = ast.Node{ .id = ast.Node.typeToId(T) },
3613 .token = token_index,
3614 };
3615 return result;
2943/// Child (Op Child)*
2944/// Child (Op Child)?
2945fn parseBinOpExpr(
2946 arena: *Allocator,
2947 it: *TokenIterator,
2948 tree: *Tree,
2949 opParseFn: NodeParseFn,
2950 childParseFn: NodeParseFn,
2951 chain: enum {
2952 Once,
2953 Infinitely,
2954 },
2955) Error!?*Node {
2956 var res = (try childParseFn(arena, it, tree)) orelse return null;
2957
2958 while (try opParseFn(arena, it, tree)) |node| {
2959 const right = try expectNode(arena, it, tree, childParseFn, AstError{
2960 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2961 });
2962 const left = res;
2963 res = node;
2964
2965 const op = node.cast(Node.InfixOp).?;
2966 op.*.lhs = left;
2967 op.*.rhs = right;
2968
2969 switch (chain) {
2970 .Once => break,
2971 .Infinitely => continue,
2972 }
2973 }
2974
2975 return res;
36162976}
36172977
3618fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: OptionalCtx, comptime T: type, token_index: TokenIndex) !*T {
3619 const node = try createLiteral(arena, T, token_index);
3620 opt_ctx.store(&node.base);
2978fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
2979 const node = try arena.create(Node.InfixOp);
2980 node.* = Node.InfixOp{
2981 .base = Node{ .id = .InfixOp },
2982 .op_token = index,
2983 .lhs = undefined,
2984 .op = op,
2985 .rhs = undefined,
2986 };
2987 return &node.base;
2988}
36212989
3622 return node;
2990fn eatToken(it: *TokenIterator, id: Token.Id) ?TokenIndex {
2991 return if (eatAnnotatedToken(it, id)) |token| token.index else null;
36232992}
36242993
3625fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: Token.Id) ?TokenIndex {
3626 const token = tok_it.peek().?;
2994fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {
2995 return if (it.peek().?.id == id) nextToken(it) else null;
2996}
36272997
3628 if (token.id == id) {
3629 return nextToken(tok_it, tree).index;
2998fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
2999 const token = nextToken(it);
3000 if (token.ptr.id != id) {
3001 try tree.errors.push(AstError{
3002 .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id },
3003 });
3004 return error.ParseError;
36303005 }
3631
3632 return null;
3006 return token.index;
36333007}
36343008
3635fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken {
3009fn nextToken(it: *TokenIterator) AnnotatedToken {
36363010 const result = AnnotatedToken{
3637 .index = tok_it.index,
3638 .ptr = tok_it.next().?,
3011 .index = it.index,
3012 .ptr = it.next().?,
36393013 };
3640 assert(result.ptr.id != Token.Id.LineComment);
3014 assert(result.ptr.id != .LineComment);
36413015
36423016 while (true) {
3643 const next_tok = tok_it.peek() orelse return result;
3644 if (next_tok.id != Token.Id.LineComment) return result;
3645 _ = tok_it.next();
3017 const next_tok = it.peek() orelse return result;
3018 if (next_tok.id != .LineComment) return result;
3019 _ = it.next();
36463020 }
36473021}
36483022
3649fn prevToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) void {
3023fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {
36503024 while (true) {
3651 const prev_tok = tok_it.prev() orelse return;
3652 if (prev_tok.id == Token.Id.LineComment) continue;
3025 const prev_tok = it.prev() orelse return;
3026 if (prev_tok.id == .LineComment) continue;
3027 assert(it.list.at(putting_back) == prev_tok);
36533028 return;
36543029 }
36553030}
36563031
3032const AnnotatedToken = struct {
3033 index: TokenIndex,
3034 ptr: *Token,
3035};
3036
3037fn expectNode(
3038 arena: *Allocator,
3039 it: *TokenIterator,
3040 tree: *Tree,
3041 parseFn: NodeParseFn,
3042 err: AstError, // if parsing fails
3043) Error!*Node {
3044 return (try parseFn(arena, it, tree)) orelse {
3045 try tree.errors.push(err);
3046 return error.ParseError;
3047 };
3048}
3049
36573050test "std.zig.parser" {
36583051 _ = @import("parser_test.zig");
36593052}
std/zig/parser_test.zig+16-12
......@@ -12,6 +12,21 @@ test "zig fmt: enum literal" {
1212 );
1313}
1414
15test "zig fmt: enum literal inside array literal" {
16 try testCanonical(
17 \\test "enums in arrays" {
18 \\ var colors = []Color{.Green};
19 \\ colors = []Colors{ .Green, .Cyan };
20 \\ colors = []Colors{
21 \\ .Grey,
22 \\ .Green,
23 \\ .Cyan,
24 \\ };
25 \\}
26 \\
27 );
28}
29
1530test "zig fmt: character literal larger than u8" {
1631 try testCanonical(
1732 \\const x = '\U01f4a9';
......@@ -1434,7 +1449,7 @@ test "zig fmt: precedence" {
14341449test "zig fmt: prefix operators" {
14351450 try testCanonical(
14361451 \\test "prefix operators" {
1437 \\ try return --%~!*&0;
1452 \\ try return --%~!&0;
14381453 \\}
14391454 \\
14401455 );
......@@ -1462,8 +1477,6 @@ test "zig fmt: var args" {
14621477test "zig fmt: var type" {
14631478 try testCanonical(
14641479 \\fn print(args: var) var {}
1465 \\const Var = var;
1466 \\const i: var = 0;
14671480 \\
14681481 );
14691482}
......@@ -1827,15 +1840,6 @@ test "zig fmt: while" {
18271840test "zig fmt: for" {
18281841 try testCanonical(
18291842 \\test "for" {
1830 \\ for (a) continue;
1831 \\
1832 \\ for (a)
1833 \\ continue;
1834 \\
1835 \\ for (a) {
1836 \\ continue;
1837 \\ }
1838 \\
18391843 \\ for (a) |v| {
18401844 \\ continue;
18411845 \\ }
std/zig/render.zig+26-62
......@@ -189,61 +189,31 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
189189 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, Space.Newline);
190190 },
191191
192 ast.Node.Id.StructField => {
193 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
192 ast.Node.Id.ContainerField => {
193 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
194194
195195 try renderDocComments(tree, stream, field, indent, start_col);
196
196197 if (field.visib_token) |visib_token| {
197198 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
198199 }
199 try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
200 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
201 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr, Space.Comma); // type,
202 },
203
204 ast.Node.Id.UnionTag => {
205 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
206
207 try renderDocComments(tree, stream, tag, indent, start_col);
208
209 if (tag.type_expr == null and tag.value_expr == null) {
210 return renderToken(tree, stream, tag.name_token, indent, start_col, Space.Comma); // name,
211 }
212
213 if (tag.type_expr == null) {
214 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Space); // name
215 } else {
216 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.None); // name
217 }
218
219 if (tag.type_expr) |type_expr| {
220 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, start_col, Space.Space); // :
221
222 if (tag.value_expr == null) {
223 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.Comma); // type,
224 return;
225 } else {
226 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.Space); // type
227 }
228 }
229
230 const value_expr = tag.value_expr.?;
231 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // =
232 try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value,
233 },
234200
235 ast.Node.Id.EnumTag => {
236 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
237
238 try renderDocComments(tree, stream, tag, indent, start_col);
239
240 if (tag.value) |value| {
241 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Space); // name
242
243 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, start_col, Space.Space); // =
244 try renderExpression(allocator, stream, tree, indent, start_col, value, Space.Comma);
201 if (field.type_expr == null and field.value_expr == null) {
202 return renderToken(tree, stream, field.name_token, indent, start_col, Space.Comma); // name,
203 } else if (field.type_expr != null and field.value_expr == null) {
204 try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
205 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
206 return renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
207 } else if (field.type_expr == null and field.value_expr != null) {
208 try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name
209 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // =
210 return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value
245211 } else {
246 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Comma); // name
212 try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
213 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
214 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type
215 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // =
216 return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value,
247217 }
248218 },
249219
......@@ -1436,18 +1406,14 @@ fn renderExpression(
14361406
14371407 const rparen = tree.nextToken(for_node.array_expr.lastToken());
14381408
1439 const has_payload = for_node.payload != null;
14401409 const body_is_block = for_node.body.id == ast.Node.Id.Block;
14411410 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
14421411 const body_on_same_line = body_is_block or src_one_line_to_body;
14431412
1444 const space_after_rparen = if (has_payload or body_on_same_line) Space.Space else Space.Newline;
1445 try renderToken(tree, stream, rparen, indent, start_col, space_after_rparen); // )
1413 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
14461414
1447 if (for_node.payload) |payload| {
1448 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1449 try renderExpression(allocator, stream, tree, indent, start_col, payload, space_after_payload); // |x|
1450 }
1415 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1416 try renderExpression(allocator, stream, tree, indent, start_col, for_node.payload, space_after_payload); // |x|
14511417
14521418 const space_after_body = blk: {
14531419 if (for_node.@"else") |@"else"| {
......@@ -1668,15 +1634,15 @@ fn renderExpression(
16681634
16691635 var it = asm_node.clobbers.iterator(0);
16701636 while (true) {
1671 const clobber_token = it.next().?;
1637 const clobber_node = it.next().?.*;
16721638
16731639 if (it.peek() == null) {
1674 try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline);
1640 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
16751641 try stream.writeByteNTimes(' ', indent);
16761642 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
16771643 } else {
1678 try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.None);
1679 const comma = tree.nextToken(clobber_token.*);
1644 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.None);
1645 const comma = tree.nextToken(clobber_node.lastToken());
16801646 try renderToken(tree, stream, comma, indent_once, start_col, Space.Space); // ,
16811647 }
16821648 }
......@@ -1723,9 +1689,7 @@ fn renderExpression(
17231689 return renderToken(tree, stream, enum_literal.name, indent, start_col, space); // name
17241690 },
17251691
1726 ast.Node.Id.StructField,
1727 ast.Node.Id.UnionTag,
1728 ast.Node.Id.EnumTag,
1692 ast.Node.Id.ContainerField,
17291693 ast.Node.Id.Root,
17301694 ast.Node.Id.VarDecl,
17311695 ast.Node.Id.Use,
test/stage2/compile_errors.zig+24
......@@ -27,4 +27,28 @@ pub fn addCases(ctx: *TestContext) !void {
2727 \\ return 36893488147419103232;
2828 \\}
2929 , "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
30
31 try ctx.testCompileError(
32 \\comptime {
33 \\ var a: *align(4) align(4) i32 = 0;
34 \\}
35 , "1.zig", 2, 22, "Extra align qualifier");
36
37 try ctx.testCompileError(
38 \\comptime {
39 \\ var b: *const const i32 = 0;
40 \\}
41 , "1.zig", 2, 19, "Extra align qualifier");
42
43 try ctx.testCompileError(
44 \\comptime {
45 \\ var c: *volatile volatile i32 = 0;
46 \\}
47 , "1.zig", 2, 22, "Extra align qualifier");
48
49 try ctx.testCompileError(
50 \\comptime {
51 \\ var d: *allowzero allowzero i32 = 0;
52 \\}
53 , "1.zig", 2, 23, "Extra align qualifier");
3054}