authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-09 22:17:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-09 22:17:47-04:00
log4438c5e09bdb5a180a930ac5c5f48941053900f7
tree9b329af200c6c6128b195ce9e400c734528a730b
parentbf21747a426887ed2ac866c9a9d317f64b22da79
parentbbae6267fe47d6848068938f1a1a83d545f4818f

Merge branch 'rework-parser'


12 files changed, 5467 insertions(+), 5114 deletions(-)

CMakeLists.txt+2-1
...@@ -576,7 +576,8 @@ set(ZIG_STD_FILES...@@ -576,7 +576,8 @@ set(ZIG_STD_FILES
576 "unicode.zig"576 "unicode.zig"
577 "zig/ast.zig"577 "zig/ast.zig"
578 "zig/index.zig"578 "zig/index.zig"
579 "zig/parser.zig"579 "zig/parse.zig"
580 "zig/render.zig"
580 "zig/tokenizer.zig"581 "zig/tokenizer.zig"
581)582)
582583
src-self-hosted/main.zig+29-18
...@@ -671,34 +671,45 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {...@@ -671,34 +671,45 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
671 };671 };
672 defer allocator.free(source_code);672 defer allocator.free(source_code);
673673
674 var tokenizer = std.zig.Tokenizer.init(source_code);674 var tree = std.zig.parse(allocator, source_code) catch |err| {
675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
676 defer parser.deinit();
677
678 var tree = parser.parse() catch |err| {
679 try stderr.print("error parsing file '{}': {}\n", file_path, err);675 try stderr.print("error parsing file '{}': {}\n", file_path, err);
680 continue;676 continue;
681 };677 };
682 defer tree.deinit();678 defer tree.deinit();
683679
684 var original_file_backup = try Buffer.init(allocator, file_path);
685 defer original_file_backup.deinit();
686 try original_file_backup.append(".backup");
687680
688 try os.rename(allocator, file_path, original_file_backup.toSliceConst());681 var error_it = tree.errors.iterator(0);
682 while (error_it.next()) |parse_error| {
683 const token = tree.tokens.at(parse_error.loc());
684 const loc = tree.tokenLocation(0, parse_error.loc());
685 try stderr.print("{}:{}:{}: error: ", file_path, loc.line + 1, loc.column + 1);
686 try tree.renderError(parse_error, stderr);
687 try stderr.print("\n{}\n", source_code[loc.line_start..loc.line_end]);
688 {
689 var i: usize = 0;
690 while (i < loc.column) : (i += 1) {
691 try stderr.write(" ");
692 }
693 }
694 {
695 const caret_count = token.end - token.start;
696 var i: usize = 0;
697 while (i < caret_count) : (i += 1) {
698 try stderr.write("~");
699 }
700 }
701 try stderr.write("\n");
702 }
703 if (tree.errors.len != 0) {
704 continue;
705 }
689706
690 try stderr.print("{}\n", file_path);707 try stderr.print("{}\n", file_path);
691708
692 // TODO: BufferedAtomicFile has some access problems.709 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
693 var out_file = try os.File.openWrite(allocator, file_path);710 defer baf.destroy();
694 defer out_file.close();
695711
696 var out_file_stream = io.FileOutStream.init(&out_file);712 try std.zig.render(allocator, baf.stream(), &tree);
697 try parser.renderSource(out_file_stream.stream, tree.root_node);
698
699 if (!flags.present("keep-backups")) {
700 try os.deleteFile(allocator, original_file_backup.toSliceConst());
701 }
702 }713 }
703}714}
704715
src-self-hosted/module.zig+2-21
...@@ -8,9 +8,7 @@ const c = @import("c.zig");...@@ -8,9 +8,7 @@ const c = @import("c.zig");
8const builtin = @import("builtin");8const builtin = @import("builtin");
9const Target = @import("target.zig").Target;9const Target = @import("target.zig").Target;
10const warn = std.debug.warn;10const warn = std.debug.warn;
11const Tokenizer = std.zig.Tokenizer;
12const Token = std.zig.Token;11const Token = std.zig.Token;
13const Parser = std.zig.Parser;
14const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
1513
16pub const Module = struct {14pub const Module = struct {
...@@ -246,34 +244,17 @@ pub const Module = struct {...@@ -246,34 +244,17 @@ pub const Module = struct {
246244
247 warn("{}", source_code);245 warn("{}", source_code);
248246
249 warn("====tokenization:====\n");
250 {
251 var tokenizer = Tokenizer.init(source_code);
252 while (true) {
253 const token = tokenizer.next();
254 tokenizer.dump(token);
255 if (token.id == Token.Id.Eof) {
256 break;
257 }
258 }
259 }
260
261 warn("====parse:====\n");247 warn("====parse:====\n");
262248
263 var tokenizer = Tokenizer.init(source_code);249 var tree = try std.zig.parse(self.allocator, source_code);
264 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
265 defer parser.deinit();
266
267 var tree = try parser.parse();
268 defer tree.deinit();250 defer tree.deinit();
269251
270 var stderr_file = try std.io.getStdErr();252 var stderr_file = try std.io.getStdErr();
271 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);253 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
272 const out_stream = &stderr_file_out_stream.stream;254 const out_stream = &stderr_file_out_stream.stream;
273 try parser.renderAst(out_stream, tree.root_node);
274255
275 warn("====fmt:====\n");256 warn("====fmt:====\n");
276 try parser.renderSource(out_stream, tree.root_node);257 try std.zig.render(self.allocator, out_stream, &tree);
277258
278 warn("====ir:====\n");259 warn("====ir:====\n");
279 warn("TODO\n\n");260 warn("TODO\n\n");
src/ir.cpp+1-1
...@@ -14709,7 +14709,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source...@@ -14709,7 +14709,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
14709 }14709 }
1471014710
14711 if (value->value.type->id != TypeTableEntryIdUnion) {14711 if (value->value.type->id != TypeTableEntryIdUnion) {
14712 ir_add_error(ira, source_instr,14712 ir_add_error(ira, value,
14713 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));14713 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
14714 return ira->codegen->invalid_instruction;14714 return ira->codegen->invalid_instruction;
14715 }14715 }
std/segmented_list.zig+11
...@@ -91,6 +91,8 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -91,6 +91,8 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
91 allocator: &Allocator,91 allocator: &Allocator,
92 len: usize,92 len: usize,
9393
94 pub const prealloc_count = prealloc_item_count;
95
94 /// Deinitialize with `deinit`96 /// Deinitialize with `deinit`
95 pub fn init(allocator: &Allocator) Self {97 pub fn init(allocator: &Allocator) Self {
96 return Self {98 return Self {
...@@ -287,6 +289,15 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -287,6 +289,15 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
287289
288 return &it.list.dynamic_segments[it.shelf_index][it.box_index];290 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
289 }291 }
292
293 pub fn peek(it: &Iterator) ?&T {
294 if (it.index >= it.list.len)
295 return null;
296 if (it.index < prealloc_item_count)
297 return &it.list.prealloc_segment[it.index];
298
299 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
300 }
290 };301 };
291302
292 pub fn iterator(self: &Self, start_index: usize) Iterator {303 pub fn iterator(self: &Self, start_index: usize) Iterator {
std/zig/ast.zig+563-247
...@@ -1,12 +1,227 @@...@@ -1,12 +1,227 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;3const SegmentedList = std.SegmentedList;
4const Token = std.zig.Token;
5const mem = std.mem;4const mem = std.mem;
5const Token = std.zig.Token;
6
7pub const TokenIndex = usize;
8
9pub const Tree = struct {
10 source: []const u8,
11 tokens: TokenList,
12 root_node: &Node.Root,
13 arena_allocator: std.heap.ArenaAllocator,
14 errors: ErrorList,
15
16 pub const TokenList = SegmentedList(Token, 64);
17 pub const ErrorList = SegmentedList(Error, 0);
18
19 pub fn deinit(self: &Tree) void {
20 self.arena_allocator.deinit();
21 }
22
23 pub fn renderError(self: &Tree, parse_error: &Error, stream: var) !void {
24 return parse_error.render(&self.tokens, stream);
25 }
26
27 pub fn tokenSlice(self: &Tree, token_index: TokenIndex) []const u8 {
28 return self.tokenSlicePtr(self.tokens.at(token_index));
29 }
30
31 pub fn tokenSlicePtr(self: &Tree, token: &const Token) []const u8 {
32 return self.source[token.start..token.end];
33 }
34
35 pub const Location = struct {
36 line: usize,
37 column: usize,
38 line_start: usize,
39 line_end: usize,
40 };
41
42 pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {
43 var loc = Location {
44 .line = 0,
45 .column = 0,
46 .line_start = start_index,
47 .line_end = self.source.len,
48 };
49 const token_start = token.start;
50 for (self.source[start_index..]) |c, i| {
51 if (i + start_index == token_start) {
52 loc.line_end = i + start_index;
53 while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') : (loc.line_end += 1) {}
54 return loc;
55 }
56 if (c == '\n') {
57 loc.line += 1;
58 loc.column = 0;
59 loc.line_start = i + 1;
60 } else {
61 loc.column += 1;
62 }
63 }
64 return loc;
65 }
66
67 pub fn tokenLocation(self: &Tree, start_index: usize, token_index: TokenIndex) Location {
68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
69 }
70};
71
72pub const Error = union(enum) {
73 InvalidToken: InvalidToken,
74 ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
75 ExpectedAggregateKw: ExpectedAggregateKw,
76 UnattachedDocComment: UnattachedDocComment,
77 ExpectedEqOrSemi: ExpectedEqOrSemi,
78 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
79 ExpectedLabelable: ExpectedLabelable,
80 ExpectedInlinable: ExpectedInlinable,
81 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
82 ExpectedCall: ExpectedCall,
83 ExpectedCallOrFnProto: ExpectedCallOrFnProto,
84 ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
85 ExtraAlignQualifier: ExtraAlignQualifier,
86 ExtraConstQualifier: ExtraConstQualifier,
87 ExtraVolatileQualifier: ExtraVolatileQualifier,
88 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
89 ExpectedToken: ExpectedToken,
90 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
91
92 pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
93 switch (*self) {
94 // TODO https://github.com/zig-lang/zig/issues/683
95 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
96 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
97 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
98 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
99 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
100 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
101 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
102 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
103 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
104 @TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
105 @TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
106 @TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
107 @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
108 @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
109 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
110 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
111 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
112 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
113 }
114 }
115
116 pub fn loc(self: &Error) TokenIndex {
117 switch (*self) {
118 // TODO https://github.com/zig-lang/zig/issues/683
119 @TagType(Error).InvalidToken => |x| return x.token,
120 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
121 @TagType(Error).ExpectedAggregateKw => |x| return x.token,
122 @TagType(Error).UnattachedDocComment => |x| return x.token,
123 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
124 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
125 @TagType(Error).ExpectedLabelable => |x| return x.token,
126 @TagType(Error).ExpectedInlinable => |x| return x.token,
127 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
128 @TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
129 @TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
130 @TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
131 @TagType(Error).ExtraAlignQualifier => |x| return x.token,
132 @TagType(Error).ExtraConstQualifier => |x| return x.token,
133 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
134 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
135 @TagType(Error).ExpectedToken => |x| return x.token,
136 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
137 }
138 }
139
140 pub const InvalidToken = SingleTokenError("Invalid token {}");
141 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
142 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++
143 @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++
144 @tagName(Token.Id.Keyword_enum) ++ ", found {}");
145 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
146 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
147 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
148 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
149 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++
150 @tagName(Token.Id.Identifier) ++ ", found {}");
151 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
152 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
153
154 pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
155 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
156 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
157 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
158
159 pub const ExpectedCall = struct {
160 node: &Node,
161
162 pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
163 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}",
164 @tagName(self.node.id));
165 }
166 };
167
168 pub const ExpectedCallOrFnProto = struct {
169 node: &Node,
170
171 pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
172 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
173 @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
174 }
175 };
176
177 pub const ExpectedToken = struct {
178 token: TokenIndex,
179 expected_id: @TagType(Token.Id),
180
181 pub fn render(self: &ExpectedToken, tokens: &Tree.TokenList, stream: var) !void {
182 const token_name = @tagName(tokens.at(self.token).id);
183 return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
184 }
185 };
186
187 pub const ExpectedCommaOrEnd = struct {
188 token: TokenIndex,
189 end_id: @TagType(Token.Id),
190
191 pub fn render(self: &ExpectedCommaOrEnd, tokens: &Tree.TokenList, stream: var) !void {
192 const token_name = @tagName(tokens.at(self.token).id);
193 return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name);
194 }
195 };
196
197 fn SingleTokenError(comptime msg: []const u8) type {
198 return struct {
199 const ThisError = this;
200
201 token: TokenIndex,
202
203 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
204 const token_name = @tagName(tokens.at(self.token).id);
205 return stream.print(msg, token_name);
206 }
207 };
208 }
209
210 fn SimpleError(comptime msg: []const u8) type {
211 return struct {
212 const ThisError = this;
213
214 token: TokenIndex,
215
216 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
217 return stream.write(msg);
218 }
219 };
220 }
221};
6222
7pub const Node = struct {223pub const Node = struct {
8 id: Id,224 id: Id,
9 same_line_comment: ?&Token,
10225
11 pub const Id = enum {226 pub const Id = enum {
12 // Top level227 // Top level
...@@ -95,7 +310,7 @@ pub const Node = struct {...@@ -95,7 +310,7 @@ pub const Node = struct {
95 unreachable;310 unreachable;
96 }311 }
97312
98 pub fn firstToken(base: &Node) Token {313 pub fn firstToken(base: &Node) TokenIndex {
99 comptime var i = 0;314 comptime var i = 0;
100 inline while (i < @memberCount(Id)) : (i += 1) {315 inline while (i < @memberCount(Id)) : (i += 1) {
101 if (base.id == @field(Id, @memberName(Id, i))) {316 if (base.id == @field(Id, @memberName(Id, i))) {
...@@ -106,7 +321,7 @@ pub const Node = struct {...@@ -106,7 +321,7 @@ pub const Node = struct {
106 unreachable;321 unreachable;
107 }322 }
108323
109 pub fn lastToken(base: &Node) Token {324 pub fn lastToken(base: &Node) TokenIndex {
110 comptime var i = 0;325 comptime var i = 0;
111 inline while (i < @memberCount(Id)) : (i += 1) {326 inline while (i < @memberCount(Id)) : (i += 1) {
112 if (base.id == @field(Id, @memberName(Id, i))) {327 if (base.id == @field(Id, @memberName(Id, i))) {
...@@ -127,11 +342,87 @@ pub const Node = struct {...@@ -127,11 +342,87 @@ pub const Node = struct {
127 unreachable;342 unreachable;
128 }343 }
129344
345 pub fn requireSemiColon(base: &const Node) bool {
346 var n = base;
347 while (true) {
348 switch (n.id) {
349 Id.Root,
350 Id.StructField,
351 Id.UnionTag,
352 Id.EnumTag,
353 Id.ParamDecl,
354 Id.Block,
355 Id.Payload,
356 Id.PointerPayload,
357 Id.PointerIndexPayload,
358 Id.Switch,
359 Id.SwitchCase,
360 Id.SwitchElse,
361 Id.FieldInitializer,
362 Id.DocComment,
363 Id.LineComment,
364 Id.TestDecl => return false,
365 Id.While => {
366 const while_node = @fieldParentPtr(While, "base", n);
367 if (while_node.@"else") |@"else"| {
368 n = @"else".base;
369 continue;
370 }
371
372 return while_node.body.id != Id.Block;
373 },
374 Id.For => {
375 const for_node = @fieldParentPtr(For, "base", n);
376 if (for_node.@"else") |@"else"| {
377 n = @"else".base;
378 continue;
379 }
380
381 return for_node.body.id != Id.Block;
382 },
383 Id.If => {
384 const if_node = @fieldParentPtr(If, "base", n);
385 if (if_node.@"else") |@"else"| {
386 n = @"else".base;
387 continue;
388 }
389
390 return if_node.body.id != Id.Block;
391 },
392 Id.Else => {
393 const else_node = @fieldParentPtr(Else, "base", n);
394 n = else_node.body;
395 continue;
396 },
397 Id.Defer => {
398 const defer_node = @fieldParentPtr(Defer, "base", n);
399 return defer_node.expr.id != Id.Block;
400 },
401 Id.Comptime => {
402 const comptime_node = @fieldParentPtr(Comptime, "base", n);
403 return comptime_node.expr.id != Id.Block;
404 },
405 Id.Suspend => {
406 const suspend_node = @fieldParentPtr(Suspend, "base", n);
407 if (suspend_node.body) |body| {
408 return body.id != Id.Block;
409 }
410
411 return true;
412 },
413 else => return true,
414 }
415 }
416 }
417
418
130 pub const Root = struct {419 pub const Root = struct {
131 base: Node,420 base: Node,
132 doc_comments: ?&DocComment,421 doc_comments: ?&DocComment,
133 decls: ArrayList(&Node),422 decls: DeclList,
134 eof_token: Token,423 eof_token: TokenIndex,
424
425 pub const DeclList = SegmentedList(&Node, 4);
135426
136 pub fn iterate(self: &Root, index: usize) ?&Node {427 pub fn iterate(self: &Root, index: usize) ?&Node {
137 if (index < self.decls.len) {428 if (index < self.decls.len) {
...@@ -140,29 +431,29 @@ pub const Node = struct {...@@ -140,29 +431,29 @@ pub const Node = struct {
140 return null;431 return null;
141 }432 }
142433
143 pub fn firstToken(self: &Root) Token {434 pub fn firstToken(self: &Root) TokenIndex {
144 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();435 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(0)).firstToken();
145 }436 }
146437
147 pub fn lastToken(self: &Root) Token {438 pub fn lastToken(self: &Root) TokenIndex {
148 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();439 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(self.decls.len - 1)).lastToken();
149 }440 }
150 };441 };
151442
152 pub const VarDecl = struct {443 pub const VarDecl = struct {
153 base: Node,444 base: Node,
154 doc_comments: ?&DocComment,445 doc_comments: ?&DocComment,
155 visib_token: ?Token,446 visib_token: ?TokenIndex,
156 name_token: Token,447 name_token: TokenIndex,
157 eq_token: Token,448 eq_token: TokenIndex,
158 mut_token: Token,449 mut_token: TokenIndex,
159 comptime_token: ?Token,450 comptime_token: ?TokenIndex,
160 extern_export_token: ?Token,451 extern_export_token: ?TokenIndex,
161 lib_name: ?&Node,452 lib_name: ?&Node,
162 type_node: ?&Node,453 type_node: ?&Node,
163 align_node: ?&Node,454 align_node: ?&Node,
164 init_node: ?&Node,455 init_node: ?&Node,
165 semicolon_token: Token,456 semicolon_token: TokenIndex,
166457
167 pub fn iterate(self: &VarDecl, index: usize) ?&Node {458 pub fn iterate(self: &VarDecl, index: usize) ?&Node {
168 var i = index;459 var i = index;
...@@ -185,7 +476,7 @@ pub const Node = struct {...@@ -185,7 +476,7 @@ pub const Node = struct {
185 return null;476 return null;
186 }477 }
187478
188 pub fn firstToken(self: &VarDecl) Token {479 pub fn firstToken(self: &VarDecl) TokenIndex {
189 if (self.visib_token) |visib_token| return visib_token;480 if (self.visib_token) |visib_token| return visib_token;
190 if (self.comptime_token) |comptime_token| return comptime_token;481 if (self.comptime_token) |comptime_token| return comptime_token;
191 if (self.extern_export_token) |extern_export_token| return extern_export_token;482 if (self.extern_export_token) |extern_export_token| return extern_export_token;
...@@ -193,7 +484,7 @@ pub const Node = struct {...@@ -193,7 +484,7 @@ pub const Node = struct {
193 return self.mut_token;484 return self.mut_token;
194 }485 }
195486
196 pub fn lastToken(self: &VarDecl) Token {487 pub fn lastToken(self: &VarDecl) TokenIndex {
197 return self.semicolon_token;488 return self.semicolon_token;
198 }489 }
199 };490 };
...@@ -201,9 +492,9 @@ pub const Node = struct {...@@ -201,9 +492,9 @@ pub const Node = struct {
201 pub const Use = struct {492 pub const Use = struct {
202 base: Node,493 base: Node,
203 doc_comments: ?&DocComment,494 doc_comments: ?&DocComment,
204 visib_token: ?Token,495 visib_token: ?TokenIndex,
205 expr: &Node,496 expr: &Node,
206 semicolon_token: Token,497 semicolon_token: TokenIndex,
207498
208 pub fn iterate(self: &Use, index: usize) ?&Node {499 pub fn iterate(self: &Use, index: usize) ?&Node {
209 var i = index;500 var i = index;
...@@ -214,48 +505,52 @@ pub const Node = struct {...@@ -214,48 +505,52 @@ pub const Node = struct {
214 return null;505 return null;
215 }506 }
216507
217 pub fn firstToken(self: &Use) Token {508 pub fn firstToken(self: &Use) TokenIndex {
218 if (self.visib_token) |visib_token| return visib_token;509 if (self.visib_token) |visib_token| return visib_token;
219 return self.expr.firstToken();510 return self.expr.firstToken();
220 }511 }
221512
222 pub fn lastToken(self: &Use) Token {513 pub fn lastToken(self: &Use) TokenIndex {
223 return self.semicolon_token;514 return self.semicolon_token;
224 }515 }
225 };516 };
226517
227 pub const ErrorSetDecl = struct {518 pub const ErrorSetDecl = struct {
228 base: Node,519 base: Node,
229 error_token: Token,520 error_token: TokenIndex,
230 decls: ArrayList(&Node),521 decls: DeclList,
231 rbrace_token: Token,522 rbrace_token: TokenIndex,
523
524 pub const DeclList = SegmentedList(&Node, 2);
232525
233 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {526 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
234 var i = index;527 var i = index;
235528
236 if (i < self.decls.len) return self.decls.at(i);529 if (i < self.decls.len) return *self.decls.at(i);
237 i -= self.decls.len;530 i -= self.decls.len;
238531
239 return null;532 return null;
240 }533 }
241534
242 pub fn firstToken(self: &ErrorSetDecl) Token {535 pub fn firstToken(self: &ErrorSetDecl) TokenIndex {
243 return self.error_token;536 return self.error_token;
244 }537 }
245538
246 pub fn lastToken(self: &ErrorSetDecl) Token {539 pub fn lastToken(self: &ErrorSetDecl) TokenIndex {
247 return self.rbrace_token;540 return self.rbrace_token;
248 }541 }
249 };542 };
250543
251 pub const ContainerDecl = struct {544 pub const ContainerDecl = struct {
252 base: Node,545 base: Node,
253 ltoken: Token,546 ltoken: TokenIndex,
254 layout: Layout,547 layout: Layout,
255 kind: Kind,548 kind: Kind,
256 init_arg_expr: InitArg,549 init_arg_expr: InitArg,
257 fields_and_decls: ArrayList(&Node),550 fields_and_decls: DeclList,
258 rbrace_token: Token,551 rbrace_token: TokenIndex,
552
553 pub const DeclList = Root.DeclList;
259554
260 const Layout = enum {555 const Layout = enum {
261 Auto,556 Auto,
...@@ -287,17 +582,17 @@ pub const Node = struct {...@@ -287,17 +582,17 @@ pub const Node = struct {
287 InitArg.Enum => { }582 InitArg.Enum => { }
288 }583 }
289584
290 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);585 if (i < self.fields_and_decls.len) return *self.fields_and_decls.at(i);
291 i -= self.fields_and_decls.len;586 i -= self.fields_and_decls.len;
292587
293 return null;588 return null;
294 }589 }
295590
296 pub fn firstToken(self: &ContainerDecl) Token {591 pub fn firstToken(self: &ContainerDecl) TokenIndex {
297 return self.ltoken;592 return self.ltoken;
298 }593 }
299594
300 pub fn lastToken(self: &ContainerDecl) Token {595 pub fn lastToken(self: &ContainerDecl) TokenIndex {
301 return self.rbrace_token;596 return self.rbrace_token;
302 }597 }
303 };598 };
...@@ -305,8 +600,8 @@ pub const Node = struct {...@@ -305,8 +600,8 @@ pub const Node = struct {
305 pub const StructField = struct {600 pub const StructField = struct {
306 base: Node,601 base: Node,
307 doc_comments: ?&DocComment,602 doc_comments: ?&DocComment,
308 visib_token: ?Token,603 visib_token: ?TokenIndex,
309 name_token: Token,604 name_token: TokenIndex,
310 type_expr: &Node,605 type_expr: &Node,
311606
312 pub fn iterate(self: &StructField, index: usize) ?&Node {607 pub fn iterate(self: &StructField, index: usize) ?&Node {
...@@ -318,12 +613,12 @@ pub const Node = struct {...@@ -318,12 +613,12 @@ pub const Node = struct {
318 return null;613 return null;
319 }614 }
320615
321 pub fn firstToken(self: &StructField) Token {616 pub fn firstToken(self: &StructField) TokenIndex {
322 if (self.visib_token) |visib_token| return visib_token;617 if (self.visib_token) |visib_token| return visib_token;
323 return self.name_token;618 return self.name_token;
324 }619 }
325620
326 pub fn lastToken(self: &StructField) Token {621 pub fn lastToken(self: &StructField) TokenIndex {
327 return self.type_expr.lastToken();622 return self.type_expr.lastToken();
328 }623 }
329 };624 };
...@@ -331,7 +626,7 @@ pub const Node = struct {...@@ -331,7 +626,7 @@ pub const Node = struct {
331 pub const UnionTag = struct {626 pub const UnionTag = struct {
332 base: Node,627 base: Node,
333 doc_comments: ?&DocComment,628 doc_comments: ?&DocComment,
334 name_token: Token,629 name_token: TokenIndex,
335 type_expr: ?&Node,630 type_expr: ?&Node,
336 value_expr: ?&Node,631 value_expr: ?&Node,
337632
...@@ -351,11 +646,11 @@ pub const Node = struct {...@@ -351,11 +646,11 @@ pub const Node = struct {
351 return null;646 return null;
352 }647 }
353648
354 pub fn firstToken(self: &UnionTag) Token {649 pub fn firstToken(self: &UnionTag) TokenIndex {
355 return self.name_token;650 return self.name_token;
356 }651 }
357652
358 pub fn lastToken(self: &UnionTag) Token {653 pub fn lastToken(self: &UnionTag) TokenIndex {
359 if (self.value_expr) |value_expr| {654 if (self.value_expr) |value_expr| {
360 return value_expr.lastToken();655 return value_expr.lastToken();
361 }656 }
...@@ -370,7 +665,7 @@ pub const Node = struct {...@@ -370,7 +665,7 @@ pub const Node = struct {
370 pub const EnumTag = struct {665 pub const EnumTag = struct {
371 base: Node,666 base: Node,
372 doc_comments: ?&DocComment,667 doc_comments: ?&DocComment,
373 name_token: Token,668 name_token: TokenIndex,
374 value: ?&Node,669 value: ?&Node,
375670
376 pub fn iterate(self: &EnumTag, index: usize) ?&Node {671 pub fn iterate(self: &EnumTag, index: usize) ?&Node {
...@@ -384,11 +679,11 @@ pub const Node = struct {...@@ -384,11 +679,11 @@ pub const Node = struct {
384 return null;679 return null;
385 }680 }
386681
387 pub fn firstToken(self: &EnumTag) Token {682 pub fn firstToken(self: &EnumTag) TokenIndex {
388 return self.name_token;683 return self.name_token;
389 }684 }
390685
391 pub fn lastToken(self: &EnumTag) Token {686 pub fn lastToken(self: &EnumTag) TokenIndex {
392 if (self.value) |value| {687 if (self.value) |value| {
393 return value.lastToken();688 return value.lastToken();
394 }689 }
...@@ -400,7 +695,7 @@ pub const Node = struct {...@@ -400,7 +695,7 @@ pub const Node = struct {
400 pub const ErrorTag = struct {695 pub const ErrorTag = struct {
401 base: Node,696 base: Node,
402 doc_comments: ?&DocComment,697 doc_comments: ?&DocComment,
403 name_token: Token,698 name_token: TokenIndex,
404699
405 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {700 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {
406 var i = index;701 var i = index;
...@@ -413,37 +708,37 @@ pub const Node = struct {...@@ -413,37 +708,37 @@ pub const Node = struct {
413 return null;708 return null;
414 }709 }
415710
416 pub fn firstToken(self: &ErrorTag) Token {711 pub fn firstToken(self: &ErrorTag) TokenIndex {
417 return self.name_token;712 return self.name_token;
418 }713 }
419714
420 pub fn lastToken(self: &ErrorTag) Token {715 pub fn lastToken(self: &ErrorTag) TokenIndex {
421 return self.name_token;716 return self.name_token;
422 }717 }
423 };718 };
424719
425 pub const Identifier = struct {720 pub const Identifier = struct {
426 base: Node,721 base: Node,
427 token: Token,722 token: TokenIndex,
428723
429 pub fn iterate(self: &Identifier, index: usize) ?&Node {724 pub fn iterate(self: &Identifier, index: usize) ?&Node {
430 return null;725 return null;
431 }726 }
432727
433 pub fn firstToken(self: &Identifier) Token {728 pub fn firstToken(self: &Identifier) TokenIndex {
434 return self.token;729 return self.token;
435 }730 }
436731
437 pub fn lastToken(self: &Identifier) Token {732 pub fn lastToken(self: &Identifier) TokenIndex {
438 return self.token;733 return self.token;
439 }734 }
440 };735 };
441736
442 pub const AsyncAttribute = struct {737 pub const AsyncAttribute = struct {
443 base: Node,738 base: Node,
444 async_token: Token,739 async_token: TokenIndex,
445 allocator_type: ?&Node,740 allocator_type: ?&Node,
446 rangle_bracket: ?Token,741 rangle_bracket: ?TokenIndex,
447742
448 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {743 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {
449 var i = index;744 var i = index;
...@@ -456,11 +751,11 @@ pub const Node = struct {...@@ -456,11 +751,11 @@ pub const Node = struct {
456 return null;751 return null;
457 }752 }
458753
459 pub fn firstToken(self: &AsyncAttribute) Token {754 pub fn firstToken(self: &AsyncAttribute) TokenIndex {
460 return self.async_token;755 return self.async_token;
461 }756 }
462757
463 pub fn lastToken(self: &AsyncAttribute) Token {758 pub fn lastToken(self: &AsyncAttribute) TokenIndex {
464 if (self.rangle_bracket) |rangle_bracket| {759 if (self.rangle_bracket) |rangle_bracket| {
465 return rangle_bracket;760 return rangle_bracket;
466 }761 }
...@@ -472,19 +767,21 @@ pub const Node = struct {...@@ -472,19 +767,21 @@ pub const Node = struct {
472 pub const FnProto = struct {767 pub const FnProto = struct {
473 base: Node,768 base: Node,
474 doc_comments: ?&DocComment,769 doc_comments: ?&DocComment,
475 visib_token: ?Token,770 visib_token: ?TokenIndex,
476 fn_token: Token,771 fn_token: TokenIndex,
477 name_token: ?Token,772 name_token: ?TokenIndex,
478 params: ArrayList(&Node),773 params: ParamList,
479 return_type: ReturnType,774 return_type: ReturnType,
480 var_args_token: ?Token,775 var_args_token: ?TokenIndex,
481 extern_export_inline_token: ?Token,776 extern_export_inline_token: ?TokenIndex,
482 cc_token: ?Token,777 cc_token: ?TokenIndex,
483 async_attr: ?&AsyncAttribute,778 async_attr: ?&AsyncAttribute,
484 body_node: ?&Node,779 body_node: ?&Node,
485 lib_name: ?&Node, // populated if this is an extern declaration780 lib_name: ?&Node, // populated if this is an extern declaration
486 align_expr: ?&Node, // populated if align(A) is present781 align_expr: ?&Node, // populated if align(A) is present
487782
783 pub const ParamList = SegmentedList(&Node, 2);
784
488 pub const ReturnType = union(enum) {785 pub const ReturnType = union(enum) {
489 Explicit: &Node,786 Explicit: &Node,
490 InferErrorSet: &Node,787 InferErrorSet: &Node,
...@@ -526,7 +823,7 @@ pub const Node = struct {...@@ -526,7 +823,7 @@ pub const Node = struct {
526 return null;823 return null;
527 }824 }
528825
529 pub fn firstToken(self: &FnProto) Token {826 pub fn firstToken(self: &FnProto) TokenIndex {
530 if (self.visib_token) |visib_token| return visib_token;827 if (self.visib_token) |visib_token| return visib_token;
531 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;828 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
532 assert(self.lib_name == null);829 assert(self.lib_name == null);
...@@ -534,7 +831,7 @@ pub const Node = struct {...@@ -534,7 +831,7 @@ pub const Node = struct {
534 return self.fn_token;831 return self.fn_token;
535 }832 }
536833
537 pub fn lastToken(self: &FnProto) Token {834 pub fn lastToken(self: &FnProto) TokenIndex {
538 if (self.body_node) |body_node| return body_node.lastToken();835 if (self.body_node) |body_node| return body_node.lastToken();
539 switch (self.return_type) {836 switch (self.return_type) {
540 // TODO allow this and next prong to share bodies since the types are the same837 // TODO allow this and next prong to share bodies since the types are the same
...@@ -546,11 +843,11 @@ pub const Node = struct {...@@ -546,11 +843,11 @@ pub const Node = struct {
546843
547 pub const PromiseType = struct {844 pub const PromiseType = struct {
548 base: Node,845 base: Node,
549 promise_token: Token,846 promise_token: TokenIndex,
550 result: ?Result,847 result: ?Result,
551848
552 pub const Result = struct {849 pub const Result = struct {
553 arrow_token: Token,850 arrow_token: TokenIndex,
554 return_type: &Node,851 return_type: &Node,
555 };852 };
556853
...@@ -565,11 +862,11 @@ pub const Node = struct {...@@ -565,11 +862,11 @@ pub const Node = struct {
565 return null;862 return null;
566 }863 }
567864
568 pub fn firstToken(self: &PromiseType) Token {865 pub fn firstToken(self: &PromiseType) TokenIndex {
569 return self.promise_token;866 return self.promise_token;
570 }867 }
571868
572 pub fn lastToken(self: &PromiseType) Token {869 pub fn lastToken(self: &PromiseType) TokenIndex {
573 if (self.result) |result| return result.return_type.lastToken();870 if (self.result) |result| return result.return_type.lastToken();
574 return self.promise_token;871 return self.promise_token;
575 }872 }
...@@ -577,11 +874,11 @@ pub const Node = struct {...@@ -577,11 +874,11 @@ pub const Node = struct {
577874
578 pub const ParamDecl = struct {875 pub const ParamDecl = struct {
579 base: Node,876 base: Node,
580 comptime_token: ?Token,877 comptime_token: ?TokenIndex,
581 noalias_token: ?Token,878 noalias_token: ?TokenIndex,
582 name_token: ?Token,879 name_token: ?TokenIndex,
583 type_node: &Node,880 type_node: &Node,
584 var_args_token: ?Token,881 var_args_token: ?TokenIndex,
585882
586 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {883 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {
587 var i = index;884 var i = index;
...@@ -592,14 +889,14 @@ pub const Node = struct {...@@ -592,14 +889,14 @@ pub const Node = struct {
592 return null;889 return null;
593 }890 }
594891
595 pub fn firstToken(self: &ParamDecl) Token {892 pub fn firstToken(self: &ParamDecl) TokenIndex {
596 if (self.comptime_token) |comptime_token| return comptime_token;893 if (self.comptime_token) |comptime_token| return comptime_token;
597 if (self.noalias_token) |noalias_token| return noalias_token;894 if (self.noalias_token) |noalias_token| return noalias_token;
598 if (self.name_token) |name_token| return name_token;895 if (self.name_token) |name_token| return name_token;
599 return self.type_node.firstToken();896 return self.type_node.firstToken();
600 }897 }
601898
602 pub fn lastToken(self: &ParamDecl) Token {899 pub fn lastToken(self: &ParamDecl) TokenIndex {
603 if (self.var_args_token) |var_args_token| return var_args_token;900 if (self.var_args_token) |var_args_token| return var_args_token;
604 return self.type_node.lastToken();901 return self.type_node.lastToken();
605 }902 }
...@@ -607,10 +904,12 @@ pub const Node = struct {...@@ -607,10 +904,12 @@ pub const Node = struct {
607904
608 pub const Block = struct {905 pub const Block = struct {
609 base: Node,906 base: Node,
610 label: ?Token,907 label: ?TokenIndex,
611 lbrace: Token,908 lbrace: TokenIndex,
612 statements: ArrayList(&Node),909 statements: StatementList,
613 rbrace: Token,910 rbrace: TokenIndex,
911
912 pub const StatementList = Root.DeclList;
614913
615 pub fn iterate(self: &Block, index: usize) ?&Node {914 pub fn iterate(self: &Block, index: usize) ?&Node {
616 var i = index;915 var i = index;
...@@ -621,7 +920,7 @@ pub const Node = struct {...@@ -621,7 +920,7 @@ pub const Node = struct {
621 return null;920 return null;
622 }921 }
623922
624 pub fn firstToken(self: &Block) Token {923 pub fn firstToken(self: &Block) TokenIndex {
625 if (self.label) |label| {924 if (self.label) |label| {
626 return label;925 return label;
627 }926 }
...@@ -629,14 +928,14 @@ pub const Node = struct {...@@ -629,14 +928,14 @@ pub const Node = struct {
629 return self.lbrace;928 return self.lbrace;
630 }929 }
631930
632 pub fn lastToken(self: &Block) Token {931 pub fn lastToken(self: &Block) TokenIndex {
633 return self.rbrace;932 return self.rbrace;
634 }933 }
635 };934 };
636935
637 pub const Defer = struct {936 pub const Defer = struct {
638 base: Node,937 base: Node,
639 defer_token: Token,938 defer_token: TokenIndex,
640 kind: Kind,939 kind: Kind,
641 expr: &Node,940 expr: &Node,
642941
...@@ -654,11 +953,11 @@ pub const Node = struct {...@@ -654,11 +953,11 @@ pub const Node = struct {
654 return null;953 return null;
655 }954 }
656955
657 pub fn firstToken(self: &Defer) Token {956 pub fn firstToken(self: &Defer) TokenIndex {
658 return self.defer_token;957 return self.defer_token;
659 }958 }
660959
661 pub fn lastToken(self: &Defer) Token {960 pub fn lastToken(self: &Defer) TokenIndex {
662 return self.expr.lastToken();961 return self.expr.lastToken();
663 }962 }
664 };963 };
...@@ -666,7 +965,7 @@ pub const Node = struct {...@@ -666,7 +965,7 @@ pub const Node = struct {
666 pub const Comptime = struct {965 pub const Comptime = struct {
667 base: Node,966 base: Node,
668 doc_comments: ?&DocComment,967 doc_comments: ?&DocComment,
669 comptime_token: Token,968 comptime_token: TokenIndex,
670 expr: &Node,969 expr: &Node,
671970
672 pub fn iterate(self: &Comptime, index: usize) ?&Node {971 pub fn iterate(self: &Comptime, index: usize) ?&Node {
...@@ -678,20 +977,20 @@ pub const Node = struct {...@@ -678,20 +977,20 @@ pub const Node = struct {
678 return null;977 return null;
679 }978 }
680979
681 pub fn firstToken(self: &Comptime) Token {980 pub fn firstToken(self: &Comptime) TokenIndex {
682 return self.comptime_token;981 return self.comptime_token;
683 }982 }
684983
685 pub fn lastToken(self: &Comptime) Token {984 pub fn lastToken(self: &Comptime) TokenIndex {
686 return self.expr.lastToken();985 return self.expr.lastToken();
687 }986 }
688 };987 };
689988
690 pub const Payload = struct {989 pub const Payload = struct {
691 base: Node,990 base: Node,
692 lpipe: Token,991 lpipe: TokenIndex,
693 error_symbol: &Node,992 error_symbol: &Node,
694 rpipe: Token,993 rpipe: TokenIndex,
695994
696 pub fn iterate(self: &Payload, index: usize) ?&Node {995 pub fn iterate(self: &Payload, index: usize) ?&Node {
697 var i = index;996 var i = index;
...@@ -702,21 +1001,21 @@ pub const Node = struct {...@@ -702,21 +1001,21 @@ pub const Node = struct {
702 return null;1001 return null;
703 }1002 }
7041003
705 pub fn firstToken(self: &Payload) Token {1004 pub fn firstToken(self: &Payload) TokenIndex {
706 return self.lpipe;1005 return self.lpipe;
707 }1006 }
7081007
709 pub fn lastToken(self: &Payload) Token {1008 pub fn lastToken(self: &Payload) TokenIndex {
710 return self.rpipe;1009 return self.rpipe;
711 }1010 }
712 };1011 };
7131012
714 pub const PointerPayload = struct {1013 pub const PointerPayload = struct {
715 base: Node,1014 base: Node,
716 lpipe: Token,1015 lpipe: TokenIndex,
717 ptr_token: ?Token,1016 ptr_token: ?TokenIndex,
718 value_symbol: &Node,1017 value_symbol: &Node,
719 rpipe: Token,1018 rpipe: TokenIndex,
7201019
721 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {1020 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {
722 var i = index;1021 var i = index;
...@@ -727,22 +1026,22 @@ pub const Node = struct {...@@ -727,22 +1026,22 @@ pub const Node = struct {
727 return null;1026 return null;
728 }1027 }
7291028
730 pub fn firstToken(self: &PointerPayload) Token {1029 pub fn firstToken(self: &PointerPayload) TokenIndex {
731 return self.lpipe;1030 return self.lpipe;
732 }1031 }
7331032
734 pub fn lastToken(self: &PointerPayload) Token {1033 pub fn lastToken(self: &PointerPayload) TokenIndex {
735 return self.rpipe;1034 return self.rpipe;
736 }1035 }
737 };1036 };
7381037
739 pub const PointerIndexPayload = struct {1038 pub const PointerIndexPayload = struct {
740 base: Node,1039 base: Node,
741 lpipe: Token,1040 lpipe: TokenIndex,
742 ptr_token: ?Token,1041 ptr_token: ?TokenIndex,
743 value_symbol: &Node,1042 value_symbol: &Node,
744 index_symbol: ?&Node,1043 index_symbol: ?&Node,
745 rpipe: Token,1044 rpipe: TokenIndex,
7461045
747 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {1046 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {
748 var i = index;1047 var i = index;
...@@ -758,18 +1057,18 @@ pub const Node = struct {...@@ -758,18 +1057,18 @@ pub const Node = struct {
758 return null;1057 return null;
759 }1058 }
7601059
761 pub fn firstToken(self: &PointerIndexPayload) Token {1060 pub fn firstToken(self: &PointerIndexPayload) TokenIndex {
762 return self.lpipe;1061 return self.lpipe;
763 }1062 }
7641063
765 pub fn lastToken(self: &PointerIndexPayload) Token {1064 pub fn lastToken(self: &PointerIndexPayload) TokenIndex {
766 return self.rpipe;1065 return self.rpipe;
767 }1066 }
768 };1067 };
7691068
770 pub const Else = struct {1069 pub const Else = struct {
771 base: Node,1070 base: Node,
772 else_token: Token,1071 else_token: TokenIndex,
773 payload: ?&Node,1072 payload: ?&Node,
774 body: &Node,1073 body: &Node,
7751074
...@@ -787,22 +1086,24 @@ pub const Node = struct {...@@ -787,22 +1086,24 @@ pub const Node = struct {
787 return null;1086 return null;
788 }1087 }
7891088
790 pub fn firstToken(self: &Else) Token {1089 pub fn firstToken(self: &Else) TokenIndex {
791 return self.else_token;1090 return self.else_token;
792 }1091 }
7931092
794 pub fn lastToken(self: &Else) Token {1093 pub fn lastToken(self: &Else) TokenIndex {
795 return self.body.lastToken();1094 return self.body.lastToken();
796 }1095 }
797 };1096 };
7981097
799 pub const Switch = struct {1098 pub const Switch = struct {
800 base: Node,1099 base: Node,
801 switch_token: Token,1100 switch_token: TokenIndex,
802 expr: &Node,1101 expr: &Node,
803 /// these can be SwitchCase nodes or LineComment nodes1102 /// these can be SwitchCase nodes or LineComment nodes
804 cases: ArrayList(&Node),1103 cases: CaseList,
805 rbrace: Token,1104 rbrace: TokenIndex,
1105
1106 pub const CaseList = SegmentedList(&Node, 2);
8061107
807 pub fn iterate(self: &Switch, index: usize) ?&Node {1108 pub fn iterate(self: &Switch, index: usize) ?&Node {
808 var i = index;1109 var i = index;
...@@ -810,31 +1111,33 @@ pub const Node = struct {...@@ -810,31 +1111,33 @@ pub const Node = struct {
810 if (i < 1) return self.expr;1111 if (i < 1) return self.expr;
811 i -= 1;1112 i -= 1;
8121113
813 if (i < self.cases.len) return self.cases.at(i);1114 if (i < self.cases.len) return *self.cases.at(i);
814 i -= self.cases.len;1115 i -= self.cases.len;
8151116
816 return null;1117 return null;
817 }1118 }
8181119
819 pub fn firstToken(self: &Switch) Token {1120 pub fn firstToken(self: &Switch) TokenIndex {
820 return self.switch_token;1121 return self.switch_token;
821 }1122 }
8221123
823 pub fn lastToken(self: &Switch) Token {1124 pub fn lastToken(self: &Switch) TokenIndex {
824 return self.rbrace;1125 return self.rbrace;
825 }1126 }
826 };1127 };
8271128
828 pub const SwitchCase = struct {1129 pub const SwitchCase = struct {
829 base: Node,1130 base: Node,
830 items: ArrayList(&Node),1131 items: ItemList,
831 payload: ?&Node,1132 payload: ?&Node,
832 expr: &Node,1133 expr: &Node,
8331134
1135 pub const ItemList = SegmentedList(&Node, 1);
1136
834 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {1137 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
835 var i = index;1138 var i = index;
8361139
837 if (i < self.items.len) return self.items.at(i);1140 if (i < self.items.len) return *self.items.at(i);
838 i -= self.items.len;1141 i -= self.items.len;
8391142
840 if (self.payload) |payload| {1143 if (self.payload) |payload| {
...@@ -848,37 +1151,37 @@ pub const Node = struct {...@@ -848,37 +1151,37 @@ pub const Node = struct {
848 return null;1151 return null;
849 }1152 }
8501153
851 pub fn firstToken(self: &SwitchCase) Token {1154 pub fn firstToken(self: &SwitchCase) TokenIndex {
852 return self.items.at(0).firstToken();1155 return (*self.items.at(0)).firstToken();
853 }1156 }
8541157
855 pub fn lastToken(self: &SwitchCase) Token {1158 pub fn lastToken(self: &SwitchCase) TokenIndex {
856 return self.expr.lastToken();1159 return self.expr.lastToken();
857 }1160 }
858 };1161 };
8591162
860 pub const SwitchElse = struct {1163 pub const SwitchElse = struct {
861 base: Node,1164 base: Node,
862 token: Token,1165 token: TokenIndex,
8631166
864 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {1167 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {
865 return null;1168 return null;
866 }1169 }
8671170
868 pub fn firstToken(self: &SwitchElse) Token {1171 pub fn firstToken(self: &SwitchElse) TokenIndex {
869 return self.token;1172 return self.token;
870 }1173 }
8711174
872 pub fn lastToken(self: &SwitchElse) Token {1175 pub fn lastToken(self: &SwitchElse) TokenIndex {
873 return self.token;1176 return self.token;
874 }1177 }
875 };1178 };
8761179
877 pub const While = struct {1180 pub const While = struct {
878 base: Node,1181 base: Node,
879 label: ?Token,1182 label: ?TokenIndex,
880 inline_token: ?Token,1183 inline_token: ?TokenIndex,
881 while_token: Token,1184 while_token: TokenIndex,
882 condition: &Node,1185 condition: &Node,
883 payload: ?&Node,1186 payload: ?&Node,
884 continue_expr: ?&Node,1187 continue_expr: ?&Node,
...@@ -912,7 +1215,7 @@ pub const Node = struct {...@@ -912,7 +1215,7 @@ pub const Node = struct {
912 return null;1215 return null;
913 }1216 }
9141217
915 pub fn firstToken(self: &While) Token {1218 pub fn firstToken(self: &While) TokenIndex {
916 if (self.label) |label| {1219 if (self.label) |label| {
917 return label;1220 return label;
918 }1221 }
...@@ -924,7 +1227,7 @@ pub const Node = struct {...@@ -924,7 +1227,7 @@ pub const Node = struct {
924 return self.while_token;1227 return self.while_token;
925 }1228 }
9261229
927 pub fn lastToken(self: &While) Token {1230 pub fn lastToken(self: &While) TokenIndex {
928 if (self.@"else") |@"else"| {1231 if (self.@"else") |@"else"| {
929 return @"else".body.lastToken();1232 return @"else".body.lastToken();
930 }1233 }
...@@ -935,9 +1238,9 @@ pub const Node = struct {...@@ -935,9 +1238,9 @@ pub const Node = struct {
9351238
936 pub const For = struct {1239 pub const For = struct {
937 base: Node,1240 base: Node,
938 label: ?Token,1241 label: ?TokenIndex,
939 inline_token: ?Token,1242 inline_token: ?TokenIndex,
940 for_token: Token,1243 for_token: TokenIndex,
941 array_expr: &Node,1244 array_expr: &Node,
942 payload: ?&Node,1245 payload: ?&Node,
943 body: &Node,1246 body: &Node,
...@@ -965,7 +1268,7 @@ pub const Node = struct {...@@ -965,7 +1268,7 @@ pub const Node = struct {
965 return null;1268 return null;
966 }1269 }
9671270
968 pub fn firstToken(self: &For) Token {1271 pub fn firstToken(self: &For) TokenIndex {
969 if (self.label) |label| {1272 if (self.label) |label| {
970 return label;1273 return label;
971 }1274 }
...@@ -977,7 +1280,7 @@ pub const Node = struct {...@@ -977,7 +1280,7 @@ pub const Node = struct {
977 return self.for_token;1280 return self.for_token;
978 }1281 }
9791282
980 pub fn lastToken(self: &For) Token {1283 pub fn lastToken(self: &For) TokenIndex {
981 if (self.@"else") |@"else"| {1284 if (self.@"else") |@"else"| {
982 return @"else".body.lastToken();1285 return @"else".body.lastToken();
983 }1286 }
...@@ -988,7 +1291,7 @@ pub const Node = struct {...@@ -988,7 +1291,7 @@ pub const Node = struct {
9881291
989 pub const If = struct {1292 pub const If = struct {
990 base: Node,1293 base: Node,
991 if_token: Token,1294 if_token: TokenIndex,
992 condition: &Node,1295 condition: &Node,
993 payload: ?&Node,1296 payload: ?&Node,
994 body: &Node,1297 body: &Node,
...@@ -1016,11 +1319,11 @@ pub const Node = struct {...@@ -1016,11 +1319,11 @@ pub const Node = struct {
1016 return null;1319 return null;
1017 }1320 }
10181321
1019 pub fn firstToken(self: &If) Token {1322 pub fn firstToken(self: &If) TokenIndex {
1020 return self.if_token;1323 return self.if_token;
1021 }1324 }
10221325
1023 pub fn lastToken(self: &If) Token {1326 pub fn lastToken(self: &If) TokenIndex {
1024 if (self.@"else") |@"else"| {1327 if (self.@"else") |@"else"| {
1025 return @"else".body.lastToken();1328 return @"else".body.lastToken();
1026 }1329 }
...@@ -1031,7 +1334,7 @@ pub const Node = struct {...@@ -1031,7 +1334,7 @@ pub const Node = struct {
10311334
1032 pub const InfixOp = struct {1335 pub const InfixOp = struct {
1033 base: Node,1336 base: Node,
1034 op_token: Token,1337 op_token: TokenIndex,
1035 lhs: &Node,1338 lhs: &Node,
1036 op: Op,1339 op: Op,
1037 rhs: &Node,1340 rhs: &Node,
...@@ -1146,18 +1449,18 @@ pub const Node = struct {...@@ -1146,18 +1449,18 @@ pub const Node = struct {
1146 return null;1449 return null;
1147 }1450 }
11481451
1149 pub fn firstToken(self: &InfixOp) Token {1452 pub fn firstToken(self: &InfixOp) TokenIndex {
1150 return self.lhs.firstToken();1453 return self.lhs.firstToken();
1151 }1454 }
11521455
1153 pub fn lastToken(self: &InfixOp) Token {1456 pub fn lastToken(self: &InfixOp) TokenIndex {
1154 return self.rhs.lastToken();1457 return self.rhs.lastToken();
1155 }1458 }
1156 };1459 };
11571460
1158 pub const PrefixOp = struct {1461 pub const PrefixOp = struct {
1159 base: Node,1462 base: Node,
1160 op_token: Token,1463 op_token: TokenIndex,
1161 op: Op,1464 op: Op,
1162 rhs: &Node,1465 rhs: &Node,
11631466
...@@ -1180,10 +1483,10 @@ pub const Node = struct {...@@ -1180,10 +1483,10 @@ pub const Node = struct {
11801483
1181 const AddrOfInfo = struct {1484 const AddrOfInfo = struct {
1182 align_expr: ?&Node,1485 align_expr: ?&Node,
1183 bit_offset_start_token: ?Token,1486 bit_offset_start_token: ?TokenIndex,
1184 bit_offset_end_token: ?Token,1487 bit_offset_end_token: ?TokenIndex,
1185 const_token: ?Token,1488 const_token: ?TokenIndex,
1186 volatile_token: ?Token,1489 volatile_token: ?TokenIndex,
1187 };1490 };
11881491
1189 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {1492 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
...@@ -1225,19 +1528,19 @@ pub const Node = struct {...@@ -1225,19 +1528,19 @@ pub const Node = struct {
1225 return null;1528 return null;
1226 }1529 }
12271530
1228 pub fn firstToken(self: &PrefixOp) Token {1531 pub fn firstToken(self: &PrefixOp) TokenIndex {
1229 return self.op_token;1532 return self.op_token;
1230 }1533 }
12311534
1232 pub fn lastToken(self: &PrefixOp) Token {1535 pub fn lastToken(self: &PrefixOp) TokenIndex {
1233 return self.rhs.lastToken();1536 return self.rhs.lastToken();
1234 }1537 }
1235 };1538 };
12361539
1237 pub const FieldInitializer = struct {1540 pub const FieldInitializer = struct {
1238 base: Node,1541 base: Node,
1239 period_token: Token,1542 period_token: TokenIndex,
1240 name_token: Token,1543 name_token: TokenIndex,
1241 expr: &Node,1544 expr: &Node,
12421545
1243 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {1546 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {
...@@ -1249,11 +1552,11 @@ pub const Node = struct {...@@ -1249,11 +1552,11 @@ pub const Node = struct {
1249 return null;1552 return null;
1250 }1553 }
12511554
1252 pub fn firstToken(self: &FieldInitializer) Token {1555 pub fn firstToken(self: &FieldInitializer) TokenIndex {
1253 return self.period_token;1556 return self.period_token;
1254 }1557 }
12551558
1256 pub fn lastToken(self: &FieldInitializer) Token {1559 pub fn lastToken(self: &FieldInitializer) TokenIndex {
1257 return self.expr.lastToken();1560 return self.expr.lastToken();
1258 }1561 }
1259 };1562 };
...@@ -1262,24 +1565,28 @@ pub const Node = struct {...@@ -1262,24 +1565,28 @@ pub const Node = struct {
1262 base: Node,1565 base: Node,
1263 lhs: &Node,1566 lhs: &Node,
1264 op: Op,1567 op: Op,
1265 rtoken: Token,1568 rtoken: TokenIndex,
12661569
1267 const Op = union(enum) {1570 pub const Op = union(enum) {
1268 Call: CallInfo,1571 Call: Call,
1269 ArrayAccess: &Node,1572 ArrayAccess: &Node,
1270 Slice: SliceRange,1573 Slice: Slice,
1271 ArrayInitializer: ArrayList(&Node),1574 ArrayInitializer: InitList,
1272 StructInitializer: ArrayList(&Node),1575 StructInitializer: InitList,
1273 };
12741576
1275 const CallInfo = struct {1577 pub const InitList = SegmentedList(&Node, 2);
1276 params: ArrayList(&Node),1578
1277 async_attr: ?&AsyncAttribute,1579 pub const Call = struct {
1278 };1580 params: ParamList,
1581 async_attr: ?&AsyncAttribute,
1582
1583 pub const ParamList = SegmentedList(&Node, 2);
1584 };
12791585
1280 const SliceRange = struct {1586 pub const Slice = struct {
1281 start: &Node,1587 start: &Node,
1282 end: ?&Node,1588 end: ?&Node,
1589 };
1283 };1590 };
12841591
1285 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {1592 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {
...@@ -1290,7 +1597,7 @@ pub const Node = struct {...@@ -1290,7 +1597,7 @@ pub const Node = struct {
12901597
1291 switch (self.op) {1598 switch (self.op) {
1292 Op.Call => |call_info| {1599 Op.Call => |call_info| {
1293 if (i < call_info.params.len) return call_info.params.at(i);1600 if (i < call_info.params.len) return *call_info.params.at(i);
1294 i -= call_info.params.len;1601 i -= call_info.params.len;
1295 },1602 },
1296 Op.ArrayAccess => |index_expr| {1603 Op.ArrayAccess => |index_expr| {
...@@ -1307,11 +1614,11 @@ pub const Node = struct {...@@ -1307,11 +1614,11 @@ pub const Node = struct {
1307 }1614 }
1308 },1615 },
1309 Op.ArrayInitializer => |exprs| {1616 Op.ArrayInitializer => |exprs| {
1310 if (i < exprs.len) return exprs.at(i);1617 if (i < exprs.len) return *exprs.at(i);
1311 i -= exprs.len;1618 i -= exprs.len;
1312 },1619 },
1313 Op.StructInitializer => |fields| {1620 Op.StructInitializer => |fields| {
1314 if (i < fields.len) return fields.at(i);1621 if (i < fields.len) return *fields.at(i);
1315 i -= fields.len;1622 i -= fields.len;
1316 },1623 },
1317 }1624 }
...@@ -1319,20 +1626,20 @@ pub const Node = struct {...@@ -1319,20 +1626,20 @@ pub const Node = struct {
1319 return null;1626 return null;
1320 }1627 }
13211628
1322 pub fn firstToken(self: &SuffixOp) Token {1629 pub fn firstToken(self: &SuffixOp) TokenIndex {
1323 return self.lhs.firstToken();1630 return self.lhs.firstToken();
1324 }1631 }
13251632
1326 pub fn lastToken(self: &SuffixOp) Token {1633 pub fn lastToken(self: &SuffixOp) TokenIndex {
1327 return self.rtoken;1634 return self.rtoken;
1328 }1635 }
1329 };1636 };
13301637
1331 pub const GroupedExpression = struct {1638 pub const GroupedExpression = struct {
1332 base: Node,1639 base: Node,
1333 lparen: Token,1640 lparen: TokenIndex,
1334 expr: &Node,1641 expr: &Node,
1335 rparen: Token,1642 rparen: TokenIndex,
13361643
1337 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {1644 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {
1338 var i = index;1645 var i = index;
...@@ -1343,18 +1650,18 @@ pub const Node = struct {...@@ -1343,18 +1650,18 @@ pub const Node = struct {
1343 return null;1650 return null;
1344 }1651 }
13451652
1346 pub fn firstToken(self: &GroupedExpression) Token {1653 pub fn firstToken(self: &GroupedExpression) TokenIndex {
1347 return self.lparen;1654 return self.lparen;
1348 }1655 }
13491656
1350 pub fn lastToken(self: &GroupedExpression) Token {1657 pub fn lastToken(self: &GroupedExpression) TokenIndex {
1351 return self.rparen;1658 return self.rparen;
1352 }1659 }
1353 };1660 };
13541661
1355 pub const ControlFlowExpression = struct {1662 pub const ControlFlowExpression = struct {
1356 base: Node,1663 base: Node,
1357 ltoken: Token,1664 ltoken: TokenIndex,
1358 kind: Kind,1665 kind: Kind,
1359 rhs: ?&Node,1666 rhs: ?&Node,
13601667
...@@ -1391,11 +1698,11 @@ pub const Node = struct {...@@ -1391,11 +1698,11 @@ pub const Node = struct {
1391 return null;1698 return null;
1392 }1699 }
13931700
1394 pub fn firstToken(self: &ControlFlowExpression) Token {1701 pub fn firstToken(self: &ControlFlowExpression) TokenIndex {
1395 return self.ltoken;1702 return self.ltoken;
1396 }1703 }
13971704
1398 pub fn lastToken(self: &ControlFlowExpression) Token {1705 pub fn lastToken(self: &ControlFlowExpression) TokenIndex {
1399 if (self.rhs) |rhs| {1706 if (self.rhs) |rhs| {
1400 return rhs.lastToken();1707 return rhs.lastToken();
1401 }1708 }
...@@ -1420,8 +1727,8 @@ pub const Node = struct {...@@ -1420,8 +1727,8 @@ pub const Node = struct {
14201727
1421 pub const Suspend = struct {1728 pub const Suspend = struct {
1422 base: Node,1729 base: Node,
1423 label: ?Token,1730 label: ?TokenIndex,
1424 suspend_token: Token,1731 suspend_token: TokenIndex,
1425 payload: ?&Node,1732 payload: ?&Node,
1426 body: ?&Node,1733 body: ?&Node,
14271734
...@@ -1441,12 +1748,12 @@ pub const Node = struct {...@@ -1441,12 +1748,12 @@ pub const Node = struct {
1441 return null;1748 return null;
1442 }1749 }
14431750
1444 pub fn firstToken(self: &Suspend) Token {1751 pub fn firstToken(self: &Suspend) TokenIndex {
1445 if (self.label) |label| return label;1752 if (self.label) |label| return label;
1446 return self.suspend_token;1753 return self.suspend_token;
1447 }1754 }
14481755
1449 pub fn lastToken(self: &Suspend) Token {1756 pub fn lastToken(self: &Suspend) TokenIndex {
1450 if (self.body) |body| {1757 if (self.body) |body| {
1451 return body.lastToken();1758 return body.lastToken();
1452 }1759 }
...@@ -1461,177 +1768,181 @@ pub const Node = struct {...@@ -1461,177 +1768,181 @@ pub const Node = struct {
14611768
1462 pub const IntegerLiteral = struct {1769 pub const IntegerLiteral = struct {
1463 base: Node,1770 base: Node,
1464 token: Token,1771 token: TokenIndex,
14651772
1466 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {1773 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {
1467 return null;1774 return null;
1468 }1775 }
14691776
1470 pub fn firstToken(self: &IntegerLiteral) Token {1777 pub fn firstToken(self: &IntegerLiteral) TokenIndex {
1471 return self.token;1778 return self.token;
1472 }1779 }
14731780
1474 pub fn lastToken(self: &IntegerLiteral) Token {1781 pub fn lastToken(self: &IntegerLiteral) TokenIndex {
1475 return self.token;1782 return self.token;
1476 }1783 }
1477 };1784 };
14781785
1479 pub const FloatLiteral = struct {1786 pub const FloatLiteral = struct {
1480 base: Node,1787 base: Node,
1481 token: Token,1788 token: TokenIndex,
14821789
1483 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {1790 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {
1484 return null;1791 return null;
1485 }1792 }
14861793
1487 pub fn firstToken(self: &FloatLiteral) Token {1794 pub fn firstToken(self: &FloatLiteral) TokenIndex {
1488 return self.token;1795 return self.token;
1489 }1796 }
14901797
1491 pub fn lastToken(self: &FloatLiteral) Token {1798 pub fn lastToken(self: &FloatLiteral) TokenIndex {
1492 return self.token;1799 return self.token;
1493 }1800 }
1494 };1801 };
14951802
1496 pub const BuiltinCall = struct {1803 pub const BuiltinCall = struct {
1497 base: Node,1804 base: Node,
1498 builtin_token: Token,1805 builtin_token: TokenIndex,
1499 params: ArrayList(&Node),1806 params: ParamList,
1500 rparen_token: Token,1807 rparen_token: TokenIndex,
1808
1809 pub const ParamList = SegmentedList(&Node, 2);
15011810
1502 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {1811 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
1503 var i = index;1812 var i = index;
15041813
1505 if (i < self.params.len) return self.params.at(i);1814 if (i < self.params.len) return *self.params.at(i);
1506 i -= self.params.len;1815 i -= self.params.len;
15071816
1508 return null;1817 return null;
1509 }1818 }
15101819
1511 pub fn firstToken(self: &BuiltinCall) Token {1820 pub fn firstToken(self: &BuiltinCall) TokenIndex {
1512 return self.builtin_token;1821 return self.builtin_token;
1513 }1822 }
15141823
1515 pub fn lastToken(self: &BuiltinCall) Token {1824 pub fn lastToken(self: &BuiltinCall) TokenIndex {
1516 return self.rparen_token;1825 return self.rparen_token;
1517 }1826 }
1518 };1827 };
15191828
1520 pub const StringLiteral = struct {1829 pub const StringLiteral = struct {
1521 base: Node,1830 base: Node,
1522 token: Token,1831 token: TokenIndex,
15231832
1524 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {1833 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {
1525 return null;1834 return null;
1526 }1835 }
15271836
1528 pub fn firstToken(self: &StringLiteral) Token {1837 pub fn firstToken(self: &StringLiteral) TokenIndex {
1529 return self.token;1838 return self.token;
1530 }1839 }
15311840
1532 pub fn lastToken(self: &StringLiteral) Token {1841 pub fn lastToken(self: &StringLiteral) TokenIndex {
1533 return self.token;1842 return self.token;
1534 }1843 }
1535 };1844 };
15361845
1537 pub const MultilineStringLiteral = struct {1846 pub const MultilineStringLiteral = struct {
1538 base: Node,1847 base: Node,
1539 tokens: ArrayList(Token),1848 lines: LineList,
1849
1850 pub const LineList = SegmentedList(TokenIndex, 4);
15401851
1541 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {1852 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {
1542 return null;1853 return null;
1543 }1854 }
15441855
1545 pub fn firstToken(self: &MultilineStringLiteral) Token {1856 pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {
1546 return self.tokens.at(0);1857 return *self.lines.at(0);
1547 }1858 }
15481859
1549 pub fn lastToken(self: &MultilineStringLiteral) Token {1860 pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {
1550 return self.tokens.at(self.tokens.len - 1);1861 return *self.lines.at(self.lines.len - 1);
1551 }1862 }
1552 };1863 };
15531864
1554 pub const CharLiteral = struct {1865 pub const CharLiteral = struct {
1555 base: Node,1866 base: Node,
1556 token: Token,1867 token: TokenIndex,
15571868
1558 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {1869 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {
1559 return null;1870 return null;
1560 }1871 }
15611872
1562 pub fn firstToken(self: &CharLiteral) Token {1873 pub fn firstToken(self: &CharLiteral) TokenIndex {
1563 return self.token;1874 return self.token;
1564 }1875 }
15651876
1566 pub fn lastToken(self: &CharLiteral) Token {1877 pub fn lastToken(self: &CharLiteral) TokenIndex {
1567 return self.token;1878 return self.token;
1568 }1879 }
1569 };1880 };
15701881
1571 pub const BoolLiteral = struct {1882 pub const BoolLiteral = struct {
1572 base: Node,1883 base: Node,
1573 token: Token,1884 token: TokenIndex,
15741885
1575 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {1886 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {
1576 return null;1887 return null;
1577 }1888 }
15781889
1579 pub fn firstToken(self: &BoolLiteral) Token {1890 pub fn firstToken(self: &BoolLiteral) TokenIndex {
1580 return self.token;1891 return self.token;
1581 }1892 }
15821893
1583 pub fn lastToken(self: &BoolLiteral) Token {1894 pub fn lastToken(self: &BoolLiteral) TokenIndex {
1584 return self.token;1895 return self.token;
1585 }1896 }
1586 };1897 };
15871898
1588 pub const NullLiteral = struct {1899 pub const NullLiteral = struct {
1589 base: Node,1900 base: Node,
1590 token: Token,1901 token: TokenIndex,
15911902
1592 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {1903 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {
1593 return null;1904 return null;
1594 }1905 }
15951906
1596 pub fn firstToken(self: &NullLiteral) Token {1907 pub fn firstToken(self: &NullLiteral) TokenIndex {
1597 return self.token;1908 return self.token;
1598 }1909 }
15991910
1600 pub fn lastToken(self: &NullLiteral) Token {1911 pub fn lastToken(self: &NullLiteral) TokenIndex {
1601 return self.token;1912 return self.token;
1602 }1913 }
1603 };1914 };
16041915
1605 pub const UndefinedLiteral = struct {1916 pub const UndefinedLiteral = struct {
1606 base: Node,1917 base: Node,
1607 token: Token,1918 token: TokenIndex,
16081919
1609 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {1920 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {
1610 return null;1921 return null;
1611 }1922 }
16121923
1613 pub fn firstToken(self: &UndefinedLiteral) Token {1924 pub fn firstToken(self: &UndefinedLiteral) TokenIndex {
1614 return self.token;1925 return self.token;
1615 }1926 }
16161927
1617 pub fn lastToken(self: &UndefinedLiteral) Token {1928 pub fn lastToken(self: &UndefinedLiteral) TokenIndex {
1618 return self.token;1929 return self.token;
1619 }1930 }
1620 };1931 };
16211932
1622 pub const ThisLiteral = struct {1933 pub const ThisLiteral = struct {
1623 base: Node,1934 base: Node,
1624 token: Token,1935 token: TokenIndex,
16251936
1626 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {1937 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {
1627 return null;1938 return null;
1628 }1939 }
16291940
1630 pub fn firstToken(self: &ThisLiteral) Token {1941 pub fn firstToken(self: &ThisLiteral) TokenIndex {
1631 return self.token;1942 return self.token;
1632 }1943 }
16331944
1634 pub fn lastToken(self: &ThisLiteral) Token {1945 pub fn lastToken(self: &ThisLiteral) TokenIndex {
1635 return self.token;1946 return self.token;
1636 }1947 }
1637 };1948 };
...@@ -1670,11 +1981,11 @@ pub const Node = struct {...@@ -1670,11 +1981,11 @@ pub const Node = struct {
1670 return null;1981 return null;
1671 }1982 }
16721983
1673 pub fn firstToken(self: &AsmOutput) Token {1984 pub fn firstToken(self: &AsmOutput) TokenIndex {
1674 return self.symbolic_name.firstToken();1985 return self.symbolic_name.firstToken();
1675 }1986 }
16761987
1677 pub fn lastToken(self: &AsmOutput) Token {1988 pub fn lastToken(self: &AsmOutput) TokenIndex {
1678 return switch (self.kind) {1989 return switch (self.kind) {
1679 Kind.Variable => |variable_name| variable_name.lastToken(),1990 Kind.Variable => |variable_name| variable_name.lastToken(),
1680 Kind.Return => |return_type| return_type.lastToken(),1991 Kind.Return => |return_type| return_type.lastToken(),
...@@ -1703,139 +2014,144 @@ pub const Node = struct {...@@ -1703,139 +2014,144 @@ pub const Node = struct {
1703 return null;2014 return null;
1704 }2015 }
17052016
1706 pub fn firstToken(self: &AsmInput) Token {2017 pub fn firstToken(self: &AsmInput) TokenIndex {
1707 return self.symbolic_name.firstToken();2018 return self.symbolic_name.firstToken();
1708 }2019 }
17092020
1710 pub fn lastToken(self: &AsmInput) Token {2021 pub fn lastToken(self: &AsmInput) TokenIndex {
1711 return self.expr.lastToken();2022 return self.expr.lastToken();
1712 }2023 }
1713 };2024 };
17142025
1715 pub const Asm = struct {2026 pub const Asm = struct {
1716 base: Node,2027 base: Node,
1717 asm_token: Token,2028 asm_token: TokenIndex,
1718 volatile_token: ?Token,2029 volatile_token: ?TokenIndex,
1719 template: &Node,2030 template: &Node,
1720 //tokens: ArrayList(AsmToken),2031 outputs: OutputList,
1721 outputs: ArrayList(&AsmOutput),2032 inputs: InputList,
1722 inputs: ArrayList(&AsmInput),2033 clobbers: ClobberList,
1723 cloppers: ArrayList(&Node),2034 rparen: TokenIndex,
1724 rparen: Token,2035
2036 const OutputList = SegmentedList(&AsmOutput, 2);
2037 const InputList = SegmentedList(&AsmInput, 2);
2038 const ClobberList = SegmentedList(&Node, 2);
17252039
1726 pub fn iterate(self: &Asm, index: usize) ?&Node {2040 pub fn iterate(self: &Asm, index: usize) ?&Node {
1727 var i = index;2041 var i = index;
17282042
1729 if (i < self.outputs.len) return &self.outputs.at(index).base;2043 if (i < self.outputs.len) return &(*self.outputs.at(index)).base;
1730 i -= self.outputs.len;2044 i -= self.outputs.len;
17312045
1732 if (i < self.inputs.len) return &self.inputs.at(index).base;2046 if (i < self.inputs.len) return &(*self.inputs.at(index)).base;
1733 i -= self.inputs.len;2047 i -= self.inputs.len;
17342048
1735 if (i < self.cloppers.len) return self.cloppers.at(index);2049 if (i < self.clobbers.len) return *self.clobbers.at(index);
1736 i -= self.cloppers.len;2050 i -= self.clobbers.len;
17372051
1738 return null;2052 return null;
1739 }2053 }
17402054
1741 pub fn firstToken(self: &Asm) Token {2055 pub fn firstToken(self: &Asm) TokenIndex {
1742 return self.asm_token;2056 return self.asm_token;
1743 }2057 }
17442058
1745 pub fn lastToken(self: &Asm) Token {2059 pub fn lastToken(self: &Asm) TokenIndex {
1746 return self.rparen;2060 return self.rparen;
1747 }2061 }
1748 };2062 };
17492063
1750 pub const Unreachable = struct {2064 pub const Unreachable = struct {
1751 base: Node,2065 base: Node,
1752 token: Token,2066 token: TokenIndex,
17532067
1754 pub fn iterate(self: &Unreachable, index: usize) ?&Node {2068 pub fn iterate(self: &Unreachable, index: usize) ?&Node {
1755 return null;2069 return null;
1756 }2070 }
17572071
1758 pub fn firstToken(self: &Unreachable) Token {2072 pub fn firstToken(self: &Unreachable) TokenIndex {
1759 return self.token;2073 return self.token;
1760 }2074 }
17612075
1762 pub fn lastToken(self: &Unreachable) Token {2076 pub fn lastToken(self: &Unreachable) TokenIndex {
1763 return self.token;2077 return self.token;
1764 }2078 }
1765 };2079 };
17662080
1767 pub const ErrorType = struct {2081 pub const ErrorType = struct {
1768 base: Node,2082 base: Node,
1769 token: Token,2083 token: TokenIndex,
17702084
1771 pub fn iterate(self: &ErrorType, index: usize) ?&Node {2085 pub fn iterate(self: &ErrorType, index: usize) ?&Node {
1772 return null;2086 return null;
1773 }2087 }
17742088
1775 pub fn firstToken(self: &ErrorType) Token {2089 pub fn firstToken(self: &ErrorType) TokenIndex {
1776 return self.token;2090 return self.token;
1777 }2091 }
17782092
1779 pub fn lastToken(self: &ErrorType) Token {2093 pub fn lastToken(self: &ErrorType) TokenIndex {
1780 return self.token;2094 return self.token;
1781 }2095 }
1782 };2096 };
17832097
1784 pub const VarType = struct {2098 pub const VarType = struct {
1785 base: Node,2099 base: Node,
1786 token: Token,2100 token: TokenIndex,
17872101
1788 pub fn iterate(self: &VarType, index: usize) ?&Node {2102 pub fn iterate(self: &VarType, index: usize) ?&Node {
1789 return null;2103 return null;
1790 }2104 }
17912105
1792 pub fn firstToken(self: &VarType) Token {2106 pub fn firstToken(self: &VarType) TokenIndex {
1793 return self.token;2107 return self.token;
1794 }2108 }
17952109
1796 pub fn lastToken(self: &VarType) Token {2110 pub fn lastToken(self: &VarType) TokenIndex {
1797 return self.token;2111 return self.token;
1798 }2112 }
1799 };2113 };
18002114
1801 pub const LineComment = struct {2115 pub const LineComment = struct {
1802 base: Node,2116 base: Node,
1803 token: Token,2117 token: TokenIndex,
18042118
1805 pub fn iterate(self: &LineComment, index: usize) ?&Node {2119 pub fn iterate(self: &LineComment, index: usize) ?&Node {
1806 return null;2120 return null;
1807 }2121 }
18082122
1809 pub fn firstToken(self: &LineComment) Token {2123 pub fn firstToken(self: &LineComment) TokenIndex {
1810 return self.token;2124 return self.token;
1811 }2125 }
18122126
1813 pub fn lastToken(self: &LineComment) Token {2127 pub fn lastToken(self: &LineComment) TokenIndex {
1814 return self.token;2128 return self.token;
1815 }2129 }
1816 };2130 };
18172131
1818 pub const DocComment = struct {2132 pub const DocComment = struct {
1819 base: Node,2133 base: Node,
1820 lines: ArrayList(Token),2134 lines: LineList,
2135
2136 pub const LineList = SegmentedList(TokenIndex, 4);
18212137
1822 pub fn iterate(self: &DocComment, index: usize) ?&Node {2138 pub fn iterate(self: &DocComment, index: usize) ?&Node {
1823 return null;2139 return null;
1824 }2140 }
18252141
1826 pub fn firstToken(self: &DocComment) Token {2142 pub fn firstToken(self: &DocComment) TokenIndex {
1827 return self.lines.at(0);2143 return *self.lines.at(0);
1828 }2144 }
18292145
1830 pub fn lastToken(self: &DocComment) Token {2146 pub fn lastToken(self: &DocComment) TokenIndex {
1831 return self.lines.at(self.lines.len - 1);2147 return *self.lines.at(self.lines.len - 1);
1832 }2148 }
1833 };2149 };
18342150
1835 pub const TestDecl = struct {2151 pub const TestDecl = struct {
1836 base: Node,2152 base: Node,
1837 doc_comments: ?&DocComment,2153 doc_comments: ?&DocComment,
1838 test_token: Token,2154 test_token: TokenIndex,
1839 name: &Node,2155 name: &Node,
1840 body_node: &Node,2156 body_node: &Node,
18412157
...@@ -1848,11 +2164,11 @@ pub const Node = struct {...@@ -1848,11 +2164,11 @@ pub const Node = struct {
1848 return null;2164 return null;
1849 }2165 }
18502166
1851 pub fn firstToken(self: &TestDecl) Token {2167 pub fn firstToken(self: &TestDecl) TokenIndex {
1852 return self.test_token;2168 return self.test_token;
1853 }2169 }
18542170
1855 pub fn lastToken(self: &TestDecl) Token {2171 pub fn lastToken(self: &TestDecl) TokenIndex {
1856 return self.body_node.lastToken();2172 return self.body_node.lastToken();
1857 }2173 }
1858 };2174 };
std/zig/index.zig+5-3
...@@ -1,11 +1,13 @@...@@ -1,11 +1,13 @@
1const tokenizer = @import("tokenizer.zig");1const tokenizer = @import("tokenizer.zig");
2pub const Token = tokenizer.Token;2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;3pub const Tokenizer = tokenizer.Tokenizer;
4pub const Parser = @import("parser.zig").Parser;4pub const parse = @import("parse.zig").parse;
5pub const render = @import("render.zig").render;
5pub const ast = @import("ast.zig");6pub const ast = @import("ast.zig");
67
7test "std.zig tests" {8test "std.zig tests" {
8 _ = @import("tokenizer.zig");
9 _ = @import("parser.zig");
10 _ = @import("ast.zig");9 _ = @import("ast.zig");
10 _ = @import("parse.zig");
11 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");
11}13}
std/zig/parse.zig created+3503
...@@ -0,0 +1,3503 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Tokenizer = std.zig.Tokenizer;
6const Token = std.zig.Token;
7const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;
9
10/// Returns an AST tree, allocated with the parser's allocator.
11/// Result should be freed with tree.deinit() when there are
12/// no more references to any AST nodes of the tree.
13pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
14 var tree_arena = std.heap.ArenaAllocator.init(allocator);
15 errdefer tree_arena.deinit();
16
17 var stack = std.ArrayList(State).init(allocator);
18 defer stack.deinit();
19
20 const arena = &tree_arena.allocator;
21 const root_node = try createNode(arena, ast.Node.Root,
22 ast.Node.Root {
23 .base = undefined,
24 .decls = ast.Node.Root.DeclList.init(arena),
25 .doc_comments = null,
26 // initialized when we get the eof token
27 .eof_token = undefined,
28 }
29 );
30
31 var tree = ast.Tree {
32 .source = source,
33 .root_node = root_node,
34 .arena_allocator = tree_arena,
35 .tokens = ast.Tree.TokenList.init(arena),
36 .errors = ast.Tree.ErrorList.init(arena),
37 };
38
39 var tokenizer = Tokenizer.init(tree.source);
40 while (true) {
41 const token_ptr = try tree.tokens.addOne();
42 *token_ptr = tokenizer.next();
43 if (token_ptr.id == Token.Id.Eof)
44 break;
45 }
46 var tok_it = tree.tokens.iterator(0);
47
48 try stack.append(State.TopLevel);
49
50 while (true) {
51 // This gives us 1 free push that can't fail
52 const state = stack.pop();
53
54 switch (state) {
55 State.TopLevel => {
56 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
57 try root_node.decls.push(&line_comment.base);
58 }
59
60 const comments = try eatDocComments(arena, &tok_it, &tree);
61
62 const token = nextToken(&tok_it, &tree);
63 const token_index = token.index;
64 const token_ptr = token.ptr;
65 switch (token_ptr.id) {
66 Token.Id.Keyword_test => {
67 stack.append(State.TopLevel) catch unreachable;
68
69 const block = try arena.construct(ast.Node.Block {
70 .base = ast.Node {
71 .id = ast.Node.Id.Block,
72 },
73 .label = null,
74 .lbrace = undefined,
75 .statements = ast.Node.Block.StatementList.init(arena),
76 .rbrace = undefined,
77 });
78 const test_node = try arena.construct(ast.Node.TestDecl {
79 .base = ast.Node {
80 .id = ast.Node.Id.TestDecl,
81 },
82 .doc_comments = comments,
83 .test_token = token_index,
84 .name = undefined,
85 .body_node = &block.base,
86 });
87 try root_node.decls.push(&test_node.base);
88 try stack.append(State { .Block = block });
89 try stack.append(State {
90 .ExpectTokenSave = ExpectTokenSave {
91 .id = Token.Id.LBrace,
92 .ptr = &block.rbrace,
93 }
94 });
95 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
96 continue;
97 },
98 Token.Id.Eof => {
99 root_node.eof_token = token_index;
100 root_node.doc_comments = comments;
101 return tree;
102 },
103 Token.Id.Keyword_pub => {
104 stack.append(State.TopLevel) catch unreachable;
105 try stack.append(State {
106 .TopLevelExtern = TopLevelDeclCtx {
107 .decls = &root_node.decls,
108 .visib_token = token_index,
109 .extern_export_inline_token = null,
110 .lib_name = null,
111 .comments = comments,
112 }
113 });
114 continue;
115 },
116 Token.Id.Keyword_comptime => {
117 const block = try createNode(arena, ast.Node.Block,
118 ast.Node.Block {
119 .base = undefined,
120 .label = null,
121 .lbrace = undefined,
122 .statements = ast.Node.Block.StatementList.init(arena),
123 .rbrace = undefined,
124 }
125 );
126 const node = try arena.construct(ast.Node.Comptime {
127 .base = ast.Node {
128 .id = ast.Node.Id.Comptime,
129 },
130 .comptime_token = token_index,
131 .expr = &block.base,
132 .doc_comments = comments,
133 });
134 try root_node.decls.push(&node.base);
135
136 stack.append(State.TopLevel) catch unreachable;
137 try stack.append(State { .Block = block });
138 try stack.append(State {
139 .ExpectTokenSave = ExpectTokenSave {
140 .id = Token.Id.LBrace,
141 .ptr = &block.rbrace,
142 }
143 });
144 continue;
145 },
146 else => {
147 putBackToken(&tok_it, &tree);
148 stack.append(State.TopLevel) catch unreachable;
149 try stack.append(State {
150 .TopLevelExtern = TopLevelDeclCtx {
151 .decls = &root_node.decls,
152 .visib_token = null,
153 .extern_export_inline_token = null,
154 .lib_name = null,
155 .comments = comments,
156 }
157 });
158 continue;
159 },
160 }
161 },
162 State.TopLevelExtern => |ctx| {
163 const token = nextToken(&tok_it, &tree);
164 const token_index = token.index;
165 const token_ptr = token.ptr;
166 switch (token_ptr.id) {
167 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
168 stack.append(State {
169 .TopLevelDecl = TopLevelDeclCtx {
170 .decls = ctx.decls,
171 .visib_token = ctx.visib_token,
172 .extern_export_inline_token = AnnotatedToken {
173 .index = token_index,
174 .ptr = token_ptr,
175 },
176 .lib_name = null,
177 .comments = ctx.comments,
178 },
179 }) catch unreachable;
180 continue;
181 },
182 Token.Id.Keyword_extern => {
183 stack.append(State {
184 .TopLevelLibname = TopLevelDeclCtx {
185 .decls = ctx.decls,
186 .visib_token = ctx.visib_token,
187 .extern_export_inline_token = AnnotatedToken {
188 .index = token_index,
189 .ptr = token_ptr,
190 },
191 .lib_name = null,
192 .comments = ctx.comments,
193 },
194 }) catch unreachable;
195 continue;
196 },
197 else => {
198 putBackToken(&tok_it, &tree);
199 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
200 continue;
201 }
202 }
203 },
204 State.TopLevelLibname => |ctx| {
205 const lib_name = blk: {
206 const lib_name_token = nextToken(&tok_it, &tree);
207 const lib_name_token_index = lib_name_token.index;
208 const lib_name_token_ptr = lib_name_token.ptr;
209 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
210 putBackToken(&tok_it, &tree);
211 break :blk null;
212 };
213 };
214
215 stack.append(State {
216 .TopLevelDecl = TopLevelDeclCtx {
217 .decls = ctx.decls,
218 .visib_token = ctx.visib_token,
219 .extern_export_inline_token = ctx.extern_export_inline_token,
220 .lib_name = lib_name,
221 .comments = ctx.comments,
222 },
223 }) catch unreachable;
224 continue;
225 },
226 State.TopLevelDecl => |ctx| {
227 const token = nextToken(&tok_it, &tree);
228 const token_index = token.index;
229 const token_ptr = token.ptr;
230 switch (token_ptr.id) {
231 Token.Id.Keyword_use => {
232 if (ctx.extern_export_inline_token) |annotated_token| {
233 *(try tree.errors.addOne()) = Error {
234 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
235 };
236 return tree;
237 }
238
239 const node = try arena.construct(ast.Node.Use {
240 .base = ast.Node {.id = ast.Node.Id.Use },
241 .visib_token = ctx.visib_token,
242 .expr = undefined,
243 .semicolon_token = undefined,
244 .doc_comments = ctx.comments,
245 });
246 try ctx.decls.push(&node.base);
247
248 stack.append(State {
249 .ExpectTokenSave = ExpectTokenSave {
250 .id = Token.Id.Semicolon,
251 .ptr = &node.semicolon_token,
252 }
253 }) catch unreachable;
254 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
255 continue;
256 },
257 Token.Id.Keyword_var, Token.Id.Keyword_const => {
258 if (ctx.extern_export_inline_token) |annotated_token| {
259 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
260 *(try tree.errors.addOne()) = Error {
261 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
262 };
263 return tree;
264 }
265 }
266
267 try stack.append(State {
268 .VarDecl = VarDeclCtx {
269 .comments = ctx.comments,
270 .visib_token = ctx.visib_token,
271 .lib_name = ctx.lib_name,
272 .comptime_token = null,
273 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
274 .mut_token = token_index,
275 .list = ctx.decls
276 }
277 });
278 continue;
279 },
280 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
281 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
282 const fn_proto = try arena.construct(ast.Node.FnProto {
283 .base = ast.Node {
284 .id = ast.Node.Id.FnProto,
285 },
286 .doc_comments = ctx.comments,
287 .visib_token = ctx.visib_token,
288 .name_token = null,
289 .fn_token = undefined,
290 .params = ast.Node.FnProto.ParamList.init(arena),
291 .return_type = undefined,
292 .var_args_token = null,
293 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
294 .cc_token = null,
295 .async_attr = null,
296 .body_node = null,
297 .lib_name = ctx.lib_name,
298 .align_expr = null,
299 });
300 try ctx.decls.push(&fn_proto.base);
301 stack.append(State { .FnDef = fn_proto }) catch unreachable;
302 try stack.append(State { .FnProto = fn_proto });
303
304 switch (token_ptr.id) {
305 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
306 fn_proto.cc_token = token_index;
307 try stack.append(State {
308 .ExpectTokenSave = ExpectTokenSave {
309 .id = Token.Id.Keyword_fn,
310 .ptr = &fn_proto.fn_token,
311 }
312 });
313 continue;
314 },
315 Token.Id.Keyword_async => {
316 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
317 ast.Node.AsyncAttribute {
318 .base = undefined,
319 .async_token = token_index,
320 .allocator_type = null,
321 .rangle_bracket = null,
322 }
323 );
324 fn_proto.async_attr = async_node;
325
326 try stack.append(State {
327 .ExpectTokenSave = ExpectTokenSave {
328 .id = Token.Id.Keyword_fn,
329 .ptr = &fn_proto.fn_token,
330 }
331 });
332 try stack.append(State { .AsyncAllocator = async_node });
333 continue;
334 },
335 Token.Id.Keyword_fn => {
336 fn_proto.fn_token = token_index;
337 continue;
338 },
339 else => unreachable,
340 }
341 },
342 else => {
343 *(try tree.errors.addOne()) = Error {
344 .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn { .token = token_index },
345 };
346 return tree;
347 },
348 }
349 },
350 State.TopLevelExternOrField => |ctx| {
351 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
352 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
353 const node = try arena.construct(ast.Node.StructField {
354 .base = ast.Node {
355 .id = ast.Node.Id.StructField,
356 },
357 .doc_comments = ctx.comments,
358 .visib_token = ctx.visib_token,
359 .name_token = identifier,
360 .type_expr = undefined,
361 });
362 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
363 *node_ptr = &node.base;
364
365 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
366 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
367 try stack.append(State { .ExpectToken = Token.Id.Colon });
368 continue;
369 }
370
371 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
372 try stack.append(State {
373 .TopLevelExtern = TopLevelDeclCtx {
374 .decls = &ctx.container_decl.fields_and_decls,
375 .visib_token = ctx.visib_token,
376 .extern_export_inline_token = null,
377 .lib_name = null,
378 .comments = ctx.comments,
379 }
380 });
381 continue;
382 },
383
384 State.FieldInitValue => |ctx| {
385 const eq_tok = nextToken(&tok_it, &tree);
386 const eq_tok_index = eq_tok.index;
387 const eq_tok_ptr = eq_tok.ptr;
388 if (eq_tok_ptr.id != Token.Id.Equal) {
389 putBackToken(&tok_it, &tree);
390 continue;
391 }
392 stack.append(State { .Expression = ctx }) catch unreachable;
393 continue;
394 },
395
396 State.ContainerKind => |ctx| {
397 const token = nextToken(&tok_it, &tree);
398 const token_index = token.index;
399 const token_ptr = token.ptr;
400 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
401 ast.Node.ContainerDecl {
402 .base = undefined,
403 .ltoken = ctx.ltoken,
404 .layout = ctx.layout,
405 .kind = switch (token_ptr.id) {
406 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
407 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
408 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
409 else => {
410 *(try tree.errors.addOne()) = Error {
411 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
412 };
413 return tree;
414 },
415 },
416 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
417 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
418 .rbrace_token = undefined,
419 }
420 );
421
422 stack.append(State { .ContainerDecl = node }) catch unreachable;
423 try stack.append(State { .ExpectToken = Token.Id.LBrace });
424 try stack.append(State { .ContainerInitArgStart = node });
425 continue;
426 },
427
428 State.ContainerInitArgStart => |container_decl| {
429 if (eatToken(&tok_it, &tree, Token.Id.LParen) == null) {
430 continue;
431 }
432
433 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
434 try stack.append(State { .ContainerInitArg = container_decl });
435 continue;
436 },
437
438 State.ContainerInitArg => |container_decl| {
439 const init_arg_token = nextToken(&tok_it, &tree);
440 const init_arg_token_index = init_arg_token.index;
441 const init_arg_token_ptr = init_arg_token.ptr;
442 switch (init_arg_token_ptr.id) {
443 Token.Id.Keyword_enum => {
444 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
445 const lparen_tok = nextToken(&tok_it, &tree);
446 const lparen_tok_index = lparen_tok.index;
447 const lparen_tok_ptr = lparen_tok.ptr;
448 if (lparen_tok_ptr.id == Token.Id.LParen) {
449 try stack.append(State { .ExpectToken = Token.Id.RParen } );
450 try stack.append(State { .Expression = OptionalCtx {
451 .RequiredNull = &container_decl.init_arg_expr.Enum,
452 } });
453 } else {
454 putBackToken(&tok_it, &tree);
455 }
456 },
457 else => {
458 putBackToken(&tok_it, &tree);
459 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
460 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
461 },
462 }
463 continue;
464 },
465
466 State.ContainerDecl => |container_decl| {
467 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
468 try container_decl.fields_and_decls.push(&line_comment.base);
469 }
470
471 const comments = try eatDocComments(arena, &tok_it, &tree);
472 const token = nextToken(&tok_it, &tree);
473 const token_index = token.index;
474 const token_ptr = token.ptr;
475 switch (token_ptr.id) {
476 Token.Id.Identifier => {
477 switch (container_decl.kind) {
478 ast.Node.ContainerDecl.Kind.Struct => {
479 const node = try arena.construct(ast.Node.StructField {
480 .base = ast.Node {
481 .id = ast.Node.Id.StructField,
482 },
483 .doc_comments = comments,
484 .visib_token = null,
485 .name_token = token_index,
486 .type_expr = undefined,
487 });
488 const node_ptr = try container_decl.fields_and_decls.addOne();
489 *node_ptr = &node.base;
490
491 try stack.append(State { .FieldListCommaOrEnd = container_decl });
492 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
493 try stack.append(State { .ExpectToken = Token.Id.Colon });
494 continue;
495 },
496 ast.Node.ContainerDecl.Kind.Union => {
497 const node = try arena.construct(ast.Node.UnionTag {
498 .base = ast.Node {.id = ast.Node.Id.UnionTag },
499 .name_token = token_index,
500 .type_expr = null,
501 .value_expr = null,
502 .doc_comments = comments,
503 });
504 try container_decl.fields_and_decls.push(&node.base);
505
506 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
507 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
508 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
509 try stack.append(State { .IfToken = Token.Id.Colon });
510 continue;
511 },
512 ast.Node.ContainerDecl.Kind.Enum => {
513 const node = try arena.construct(ast.Node.EnumTag {
514 .base = ast.Node { .id = ast.Node.Id.EnumTag },
515 .name_token = token_index,
516 .value = null,
517 .doc_comments = comments,
518 });
519 try container_decl.fields_and_decls.push(&node.base);
520
521 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
522 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
523 try stack.append(State { .IfToken = Token.Id.Equal });
524 continue;
525 },
526 }
527 },
528 Token.Id.Keyword_pub => {
529 switch (container_decl.kind) {
530 ast.Node.ContainerDecl.Kind.Struct => {
531 try stack.append(State {
532 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
533 .visib_token = token_index,
534 .container_decl = container_decl,
535 .comments = comments,
536 }
537 });
538 continue;
539 },
540 else => {
541 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
542 try stack.append(State {
543 .TopLevelExtern = TopLevelDeclCtx {
544 .decls = &container_decl.fields_and_decls,
545 .visib_token = token_index,
546 .extern_export_inline_token = null,
547 .lib_name = null,
548 .comments = comments,
549 }
550 });
551 continue;
552 }
553 }
554 },
555 Token.Id.Keyword_export => {
556 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
557 try stack.append(State {
558 .TopLevelExtern = TopLevelDeclCtx {
559 .decls = &container_decl.fields_and_decls,
560 .visib_token = token_index,
561 .extern_export_inline_token = null,
562 .lib_name = null,
563 .comments = comments,
564 }
565 });
566 continue;
567 },
568 Token.Id.RBrace => {
569 if (comments != null) {
570 *(try tree.errors.addOne()) = Error {
571 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
572 };
573 return tree;
574 }
575 container_decl.rbrace_token = token_index;
576 continue;
577 },
578 else => {
579 putBackToken(&tok_it, &tree);
580 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
581 try stack.append(State {
582 .TopLevelExtern = TopLevelDeclCtx {
583 .decls = &container_decl.fields_and_decls,
584 .visib_token = null,
585 .extern_export_inline_token = null,
586 .lib_name = null,
587 .comments = comments,
588 }
589 });
590 continue;
591 }
592 }
593 },
594
595
596 State.VarDecl => |ctx| {
597 const var_decl = try arena.construct(ast.Node.VarDecl {
598 .base = ast.Node {
599 .id = ast.Node.Id.VarDecl,
600 },
601 .doc_comments = ctx.comments,
602 .visib_token = ctx.visib_token,
603 .mut_token = ctx.mut_token,
604 .comptime_token = ctx.comptime_token,
605 .extern_export_token = ctx.extern_export_token,
606 .type_node = null,
607 .align_node = null,
608 .init_node = null,
609 .lib_name = ctx.lib_name,
610 // initialized later
611 .name_token = undefined,
612 .eq_token = undefined,
613 .semicolon_token = undefined,
614 });
615 try ctx.list.push(&var_decl.base);
616
617 try stack.append(State { .VarDeclAlign = var_decl });
618 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
619 try stack.append(State { .IfToken = Token.Id.Colon });
620 try stack.append(State {
621 .ExpectTokenSave = ExpectTokenSave {
622 .id = Token.Id.Identifier,
623 .ptr = &var_decl.name_token,
624 }
625 });
626 continue;
627 },
628 State.VarDeclAlign => |var_decl| {
629 try stack.append(State { .VarDeclEq = var_decl });
630
631 const next_token = nextToken(&tok_it, &tree);
632 const next_token_index = next_token.index;
633 const next_token_ptr = next_token.ptr;
634 if (next_token_ptr.id == Token.Id.Keyword_align) {
635 try stack.append(State { .ExpectToken = Token.Id.RParen });
636 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
637 try stack.append(State { .ExpectToken = Token.Id.LParen });
638 continue;
639 }
640
641 putBackToken(&tok_it, &tree);
642 continue;
643 },
644 State.VarDeclEq => |var_decl| {
645 const token = nextToken(&tok_it, &tree);
646 const token_index = token.index;
647 const token_ptr = token.ptr;
648 switch (token_ptr.id) {
649 Token.Id.Equal => {
650 var_decl.eq_token = token_index;
651 stack.append(State {
652 .ExpectTokenSave = ExpectTokenSave {
653 .id = Token.Id.Semicolon,
654 .ptr = &var_decl.semicolon_token,
655 },
656 }) catch unreachable;
657 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
658 continue;
659 },
660 Token.Id.Semicolon => {
661 var_decl.semicolon_token = token_index;
662 continue;
663 },
664 else => {
665 *(try tree.errors.addOne()) = Error {
666 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
667 };
668 return tree;
669 }
670 }
671 },
672
673
674 State.FnDef => |fn_proto| {
675 const token = nextToken(&tok_it, &tree);
676 const token_index = token.index;
677 const token_ptr = token.ptr;
678 switch(token_ptr.id) {
679 Token.Id.LBrace => {
680 const block = try arena.construct(ast.Node.Block {
681 .base = ast.Node { .id = ast.Node.Id.Block },
682 .label = null,
683 .lbrace = token_index,
684 .statements = ast.Node.Block.StatementList.init(arena),
685 .rbrace = undefined,
686 });
687 fn_proto.body_node = &block.base;
688 stack.append(State { .Block = block }) catch unreachable;
689 continue;
690 },
691 Token.Id.Semicolon => continue,
692 else => {
693 *(try tree.errors.addOne()) = Error {
694 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
695 };
696 return tree;
697 },
698 }
699 },
700 State.FnProto => |fn_proto| {
701 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
702 try stack.append(State { .ParamDecl = fn_proto });
703 try stack.append(State { .ExpectToken = Token.Id.LParen });
704
705 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {
706 fn_proto.name_token = name_token;
707 }
708 continue;
709 },
710 State.FnProtoAlign => |fn_proto| {
711 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
712
713 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {
714 try stack.append(State { .ExpectToken = Token.Id.RParen });
715 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
716 try stack.append(State { .ExpectToken = Token.Id.LParen });
717 }
718 continue;
719 },
720 State.FnProtoReturnType => |fn_proto| {
721 const token = nextToken(&tok_it, &tree);
722 const token_index = token.index;
723 const token_ptr = token.ptr;
724 switch (token_ptr.id) {
725 Token.Id.Bang => {
726 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
727 stack.append(State {
728 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
729 }) catch unreachable;
730 continue;
731 },
732 else => {
733 // TODO: this is a special case. Remove this when #760 is fixed
734 if (token_ptr.id == Token.Id.Keyword_error) {
735 if ((??tok_it.peek()).id == Token.Id.LBrace) {
736 const error_type_node = try arena.construct(ast.Node.ErrorType {
737 .base = ast.Node { .id = ast.Node.Id.ErrorType },
738 .token = token_index,
739 });
740 fn_proto.return_type = ast.Node.FnProto.ReturnType {
741 .Explicit = &error_type_node.base,
742 };
743 continue;
744 }
745 }
746
747 putBackToken(&tok_it, &tree);
748 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
749 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
750 continue;
751 },
752 }
753 },
754
755
756 State.ParamDecl => |fn_proto| {
757 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
758 continue;
759 }
760 const param_decl = try arena.construct(ast.Node.ParamDecl {
761 .base = ast.Node {.id = ast.Node.Id.ParamDecl },
762 .comptime_token = null,
763 .noalias_token = null,
764 .name_token = null,
765 .type_node = undefined,
766 .var_args_token = null,
767 });
768 try fn_proto.params.push(&param_decl.base);
769
770 stack.append(State {
771 .ParamDeclEnd = ParamDeclEndCtx {
772 .param_decl = param_decl,
773 .fn_proto = fn_proto,
774 }
775 }) catch unreachable;
776 try stack.append(State { .ParamDeclName = param_decl });
777 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
778 continue;
779 },
780 State.ParamDeclAliasOrComptime => |param_decl| {
781 if (eatToken(&tok_it, &tree, Token.Id.Keyword_comptime)) |comptime_token| {
782 param_decl.comptime_token = comptime_token;
783 } else if (eatToken(&tok_it, &tree, Token.Id.Keyword_noalias)) |noalias_token| {
784 param_decl.noalias_token = noalias_token;
785 }
786 continue;
787 },
788 State.ParamDeclName => |param_decl| {
789 // TODO: Here, we eat two tokens in one state. This means that we can't have
790 // comments between these two tokens.
791 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
792 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
793 param_decl.name_token = ident_token;
794 } else {
795 putBackToken(&tok_it, &tree);
796 }
797 }
798 continue;
799 },
800 State.ParamDeclEnd => |ctx| {
801 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
802 ctx.param_decl.var_args_token = ellipsis3;
803 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
804 continue;
805 }
806
807 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
808 try stack.append(State {
809 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
810 });
811 continue;
812 },
813 State.ParamDeclComma => |fn_proto| {
814 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
815 ExpectCommaOrEndResult.end_token => |t| {
816 if (t == null) {
817 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
818 }
819 continue;
820 },
821 ExpectCommaOrEndResult.parse_error => |e| {
822 try tree.errors.push(e);
823 return tree;
824 },
825 }
826 },
827
828 State.MaybeLabeledExpression => |ctx| {
829 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
830 stack.append(State {
831 .LabeledExpression = LabelCtx {
832 .label = ctx.label,
833 .opt_ctx = ctx.opt_ctx,
834 }
835 }) catch unreachable;
836 continue;
837 }
838
839 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
840 continue;
841 },
842 State.LabeledExpression => |ctx| {
843 const token = nextToken(&tok_it, &tree);
844 const token_index = token.index;
845 const token_ptr = token.ptr;
846 switch (token_ptr.id) {
847 Token.Id.LBrace => {
848 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
849 ast.Node.Block {
850 .base = undefined,
851 .label = ctx.label,
852 .lbrace = token_index,
853 .statements = ast.Node.Block.StatementList.init(arena),
854 .rbrace = undefined,
855 }
856 );
857 stack.append(State { .Block = block }) catch unreachable;
858 continue;
859 },
860 Token.Id.Keyword_while => {
861 stack.append(State {
862 .While = LoopCtx {
863 .label = ctx.label,
864 .inline_token = null,
865 .loop_token = token_index,
866 .opt_ctx = ctx.opt_ctx.toRequired(),
867 }
868 }) catch unreachable;
869 continue;
870 },
871 Token.Id.Keyword_for => {
872 stack.append(State {
873 .For = LoopCtx {
874 .label = ctx.label,
875 .inline_token = null,
876 .loop_token = token_index,
877 .opt_ctx = ctx.opt_ctx.toRequired(),
878 }
879 }) catch unreachable;
880 continue;
881 },
882 Token.Id.Keyword_suspend => {
883 const node = try arena.construct(ast.Node.Suspend {
884 .base = ast.Node {
885 .id = ast.Node.Id.Suspend,
886 },
887 .label = ctx.label,
888 .suspend_token = token_index,
889 .payload = null,
890 .body = null,
891 });
892 ctx.opt_ctx.store(&node.base);
893 stack.append(State { .SuspendBody = node }) catch unreachable;
894 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
895 continue;
896 },
897 Token.Id.Keyword_inline => {
898 stack.append(State {
899 .Inline = InlineCtx {
900 .label = ctx.label,
901 .inline_token = token_index,
902 .opt_ctx = ctx.opt_ctx.toRequired(),
903 }
904 }) catch unreachable;
905 continue;
906 },
907 else => {
908 if (ctx.opt_ctx != OptionalCtx.Optional) {
909 *(try tree.errors.addOne()) = Error {
910 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
911 };
912 return tree;
913 }
914
915 putBackToken(&tok_it, &tree);
916 continue;
917 },
918 }
919 },
920 State.Inline => |ctx| {
921 const token = nextToken(&tok_it, &tree);
922 const token_index = token.index;
923 const token_ptr = token.ptr;
924 switch (token_ptr.id) {
925 Token.Id.Keyword_while => {
926 stack.append(State {
927 .While = LoopCtx {
928 .inline_token = ctx.inline_token,
929 .label = ctx.label,
930 .loop_token = token_index,
931 .opt_ctx = ctx.opt_ctx.toRequired(),
932 }
933 }) catch unreachable;
934 continue;
935 },
936 Token.Id.Keyword_for => {
937 stack.append(State {
938 .For = LoopCtx {
939 .inline_token = ctx.inline_token,
940 .label = ctx.label,
941 .loop_token = token_index,
942 .opt_ctx = ctx.opt_ctx.toRequired(),
943 }
944 }) catch unreachable;
945 continue;
946 },
947 else => {
948 if (ctx.opt_ctx != OptionalCtx.Optional) {
949 *(try tree.errors.addOne()) = Error {
950 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
951 };
952 return tree;
953 }
954
955 putBackToken(&tok_it, &tree);
956 continue;
957 },
958 }
959 },
960 State.While => |ctx| {
961 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
962 ast.Node.While {
963 .base = undefined,
964 .label = ctx.label,
965 .inline_token = ctx.inline_token,
966 .while_token = ctx.loop_token,
967 .condition = undefined,
968 .payload = null,
969 .continue_expr = null,
970 .body = undefined,
971 .@"else" = null,
972 }
973 );
974 stack.append(State { .Else = &node.@"else" }) catch unreachable;
975 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
976 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
977 try stack.append(State { .IfToken = Token.Id.Colon });
978 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
979 try stack.append(State { .ExpectToken = Token.Id.RParen });
980 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
981 try stack.append(State { .ExpectToken = Token.Id.LParen });
982 continue;
983 },
984 State.WhileContinueExpr => |dest| {
985 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
986 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
987 try stack.append(State { .ExpectToken = Token.Id.LParen });
988 continue;
989 },
990 State.For => |ctx| {
991 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
992 ast.Node.For {
993 .base = undefined,
994 .label = ctx.label,
995 .inline_token = ctx.inline_token,
996 .for_token = ctx.loop_token,
997 .array_expr = undefined,
998 .payload = null,
999 .body = undefined,
1000 .@"else" = null,
1001 }
1002 );
1003 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1004 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1005 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1006 try stack.append(State { .ExpectToken = Token.Id.RParen });
1007 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1008 try stack.append(State { .ExpectToken = Token.Id.LParen });
1009 continue;
1010 },
1011 State.Else => |dest| {
1012 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
1013 const node = try createNode(arena, ast.Node.Else,
1014 ast.Node.Else {
1015 .base = undefined,
1016 .else_token = else_token,
1017 .payload = null,
1018 .body = undefined,
1019 }
1020 );
1021 *dest = node;
1022
1023 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1024 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1025 continue;
1026 } else {
1027 continue;
1028 }
1029 },
1030
1031
1032 State.Block => |block| {
1033 const token = nextToken(&tok_it, &tree);
1034 const token_index = token.index;
1035 const token_ptr = token.ptr;
1036 switch (token_ptr.id) {
1037 Token.Id.RBrace => {
1038 block.rbrace = token_index;
1039 continue;
1040 },
1041 else => {
1042 putBackToken(&tok_it, &tree);
1043 stack.append(State { .Block = block }) catch unreachable;
1044
1045 var any_comments = false;
1046 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1047 try block.statements.push(&line_comment.base);
1048 any_comments = true;
1049 }
1050 if (any_comments) continue;
1051
1052 try stack.append(State { .Statement = block });
1053 continue;
1054 },
1055 }
1056 },
1057 State.Statement => |block| {
1058 const token = nextToken(&tok_it, &tree);
1059 const token_index = token.index;
1060 const token_ptr = token.ptr;
1061 switch (token_ptr.id) {
1062 Token.Id.Keyword_comptime => {
1063 stack.append(State {
1064 .ComptimeStatement = ComptimeStatementCtx {
1065 .comptime_token = token_index,
1066 .block = block,
1067 }
1068 }) catch unreachable;
1069 continue;
1070 },
1071 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1072 stack.append(State {
1073 .VarDecl = VarDeclCtx {
1074 .comments = null,
1075 .visib_token = null,
1076 .comptime_token = null,
1077 .extern_export_token = null,
1078 .lib_name = null,
1079 .mut_token = token_index,
1080 .list = &block.statements,
1081 }
1082 }) catch unreachable;
1083 continue;
1084 },
1085 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1086 const node = try arena.construct(ast.Node.Defer {
1087 .base = ast.Node {
1088 .id = ast.Node.Id.Defer,
1089 },
1090 .defer_token = token_index,
1091 .kind = switch (token_ptr.id) {
1092 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1093 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1094 else => unreachable,
1095 },
1096 .expr = undefined,
1097 });
1098 const node_ptr = try block.statements.addOne();
1099 *node_ptr = &node.base;
1100
1101 stack.append(State { .Semicolon = node_ptr }) catch unreachable;
1102 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1103 continue;
1104 },
1105 Token.Id.LBrace => {
1106 const inner_block = try arena.construct(ast.Node.Block {
1107 .base = ast.Node { .id = ast.Node.Id.Block },
1108 .label = null,
1109 .lbrace = token_index,
1110 .statements = ast.Node.Block.StatementList.init(arena),
1111 .rbrace = undefined,
1112 });
1113 try block.statements.push(&inner_block.base);
1114
1115 stack.append(State { .Block = inner_block }) catch unreachable;
1116 continue;
1117 },
1118 else => {
1119 putBackToken(&tok_it, &tree);
1120 const statement = try block.statements.addOne();
1121 try stack.append(State { .Semicolon = statement });
1122 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1123 continue;
1124 }
1125 }
1126 },
1127 State.ComptimeStatement => |ctx| {
1128 const token = nextToken(&tok_it, &tree);
1129 const token_index = token.index;
1130 const token_ptr = token.ptr;
1131 switch (token_ptr.id) {
1132 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1133 stack.append(State {
1134 .VarDecl = VarDeclCtx {
1135 .comments = null,
1136 .visib_token = null,
1137 .comptime_token = ctx.comptime_token,
1138 .extern_export_token = null,
1139 .lib_name = null,
1140 .mut_token = token_index,
1141 .list = &ctx.block.statements,
1142 }
1143 }) catch unreachable;
1144 continue;
1145 },
1146 else => {
1147 putBackToken(&tok_it, &tree);
1148 putBackToken(&tok_it, &tree);
1149 const statement = try ctx.block.statements.addOne();
1150 try stack.append(State { .Semicolon = statement });
1151 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1152 continue;
1153 }
1154 }
1155 },
1156 State.Semicolon => |node_ptr| {
1157 const node = *node_ptr;
1158 if (node.requireSemiColon()) {
1159 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1160 continue;
1161 }
1162 continue;
1163 },
1164
1165 State.AsmOutputItems => |items| {
1166 const lbracket = nextToken(&tok_it, &tree);
1167 const lbracket_index = lbracket.index;
1168 const lbracket_ptr = lbracket.ptr;
1169 if (lbracket_ptr.id != Token.Id.LBracket) {
1170 putBackToken(&tok_it, &tree);
1171 continue;
1172 }
1173
1174 const node = try createNode(arena, ast.Node.AsmOutput,
1175 ast.Node.AsmOutput {
1176 .base = undefined,
1177 .symbolic_name = undefined,
1178 .constraint = undefined,
1179 .kind = undefined,
1180 }
1181 );
1182 try items.push(node);
1183
1184 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1185 try stack.append(State { .IfToken = Token.Id.Comma });
1186 try stack.append(State { .ExpectToken = Token.Id.RParen });
1187 try stack.append(State { .AsmOutputReturnOrType = node });
1188 try stack.append(State { .ExpectToken = Token.Id.LParen });
1189 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1190 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1191 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1192 continue;
1193 },
1194 State.AsmOutputReturnOrType => |node| {
1195 const token = nextToken(&tok_it, &tree);
1196 const token_index = token.index;
1197 const token_ptr = token.ptr;
1198 switch (token_ptr.id) {
1199 Token.Id.Identifier => {
1200 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1201 continue;
1202 },
1203 Token.Id.Arrow => {
1204 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1205 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1206 continue;
1207 },
1208 else => {
1209 *(try tree.errors.addOne()) = Error {
1210 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1211 .token = token_index,
1212 },
1213 };
1214 return tree;
1215 },
1216 }
1217 },
1218 State.AsmInputItems => |items| {
1219 const lbracket = nextToken(&tok_it, &tree);
1220 const lbracket_index = lbracket.index;
1221 const lbracket_ptr = lbracket.ptr;
1222 if (lbracket_ptr.id != Token.Id.LBracket) {
1223 putBackToken(&tok_it, &tree);
1224 continue;
1225 }
1226
1227 const node = try createNode(arena, ast.Node.AsmInput,
1228 ast.Node.AsmInput {
1229 .base = undefined,
1230 .symbolic_name = undefined,
1231 .constraint = undefined,
1232 .expr = undefined,
1233 }
1234 );
1235 try items.push(node);
1236
1237 stack.append(State { .AsmInputItems = items }) catch unreachable;
1238 try stack.append(State { .IfToken = Token.Id.Comma });
1239 try stack.append(State { .ExpectToken = Token.Id.RParen });
1240 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1241 try stack.append(State { .ExpectToken = Token.Id.LParen });
1242 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1243 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1244 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1245 continue;
1246 },
1247 State.AsmClobberItems => |items| {
1248 stack.append(State { .AsmClobberItems = items }) catch unreachable;
1249 try stack.append(State { .IfToken = Token.Id.Comma });
1250 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1251 continue;
1252 },
1253
1254
1255 State.ExprListItemOrEnd => |list_state| {
1256 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {
1257 *list_state.ptr = token_index;
1258 continue;
1259 }
1260
1261 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1262 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1263 continue;
1264 },
1265 State.ExprListCommaOrEnd => |list_state| {
1266 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {
1267 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1268 *list_state.ptr = end;
1269 continue;
1270 } else {
1271 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1272 continue;
1273 },
1274 ExpectCommaOrEndResult.parse_error => |e| {
1275 try tree.errors.push(e);
1276 return tree;
1277 },
1278 }
1279 },
1280 State.FieldInitListItemOrEnd => |list_state| {
1281 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1282 try list_state.list.push(&line_comment.base);
1283 }
1284
1285 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1286 *list_state.ptr = rbrace;
1287 continue;
1288 }
1289
1290 const node = try arena.construct(ast.Node.FieldInitializer {
1291 .base = ast.Node {
1292 .id = ast.Node.Id.FieldInitializer,
1293 },
1294 .period_token = undefined,
1295 .name_token = undefined,
1296 .expr = undefined,
1297 });
1298 try list_state.list.push(&node.base);
1299
1300 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1301 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1302 try stack.append(State { .ExpectToken = Token.Id.Equal });
1303 try stack.append(State {
1304 .ExpectTokenSave = ExpectTokenSave {
1305 .id = Token.Id.Identifier,
1306 .ptr = &node.name_token,
1307 }
1308 });
1309 try stack.append(State {
1310 .ExpectTokenSave = ExpectTokenSave {
1311 .id = Token.Id.Period,
1312 .ptr = &node.period_token,
1313 }
1314 });
1315 continue;
1316 },
1317 State.FieldInitListCommaOrEnd => |list_state| {
1318 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1319 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1320 *list_state.ptr = end;
1321 continue;
1322 } else {
1323 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1324 continue;
1325 },
1326 ExpectCommaOrEndResult.parse_error => |e| {
1327 try tree.errors.push(e);
1328 return tree;
1329 },
1330 }
1331 },
1332 State.FieldListCommaOrEnd => |container_decl| {
1333 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1334 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1335 container_decl.rbrace_token = end;
1336 continue;
1337 } else {
1338 try stack.append(State { .ContainerDecl = container_decl });
1339 continue;
1340 },
1341 ExpectCommaOrEndResult.parse_error => |e| {
1342 try tree.errors.push(e);
1343 return tree;
1344 },
1345 }
1346 },
1347 State.ErrorTagListItemOrEnd => |list_state| {
1348 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1349 try list_state.list.push(&line_comment.base);
1350 }
1351
1352 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1353 *list_state.ptr = rbrace;
1354 continue;
1355 }
1356
1357 const node_ptr = try list_state.list.addOne();
1358
1359 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1360 try stack.append(State { .ErrorTag = node_ptr });
1361 continue;
1362 },
1363 State.ErrorTagListCommaOrEnd => |list_state| {
1364 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1365 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1366 *list_state.ptr = end;
1367 continue;
1368 } else {
1369 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1370 continue;
1371 },
1372 ExpectCommaOrEndResult.parse_error => |e| {
1373 try tree.errors.push(e);
1374 return tree;
1375 },
1376 }
1377 },
1378 State.SwitchCaseOrEnd => |list_state| {
1379 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1380 try list_state.list.push(&line_comment.base);
1381 }
1382
1383 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1384 *list_state.ptr = rbrace;
1385 continue;
1386 }
1387
1388 const comments = try eatDocComments(arena, &tok_it, &tree);
1389 const node = try arena.construct(ast.Node.SwitchCase {
1390 .base = ast.Node {
1391 .id = ast.Node.Id.SwitchCase,
1392 },
1393 .items = ast.Node.SwitchCase.ItemList.init(arena),
1394 .payload = null,
1395 .expr = undefined,
1396 });
1397 try list_state.list.push(&node.base);
1398 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1399 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1400 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1401 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1402
1403 continue;
1404 },
1405
1406 State.SwitchCaseCommaOrEnd => |list_state| {
1407 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
1408 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1409 *list_state.ptr = end;
1410 continue;
1411 } else {
1412 try stack.append(State { .SwitchCaseOrEnd = list_state });
1413 continue;
1414 },
1415 ExpectCommaOrEndResult.parse_error => |e| {
1416 try tree.errors.push(e);
1417 return tree;
1418 },
1419 }
1420 },
1421
1422 State.SwitchCaseFirstItem => |case_items| {
1423 const token = nextToken(&tok_it, &tree);
1424 const token_index = token.index;
1425 const token_ptr = token.ptr;
1426 if (token_ptr.id == Token.Id.Keyword_else) {
1427 const else_node = try arena.construct(ast.Node.SwitchElse {
1428 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},
1429 .token = token_index,
1430 });
1431 try case_items.push(&else_node.base);
1432
1433 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1434 continue;
1435 } else {
1436 putBackToken(&tok_it, &tree);
1437 try stack.append(State { .SwitchCaseItem = case_items });
1438 continue;
1439 }
1440 },
1441 State.SwitchCaseItem => |case_items| {
1442 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1443 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1444 },
1445 State.SwitchCaseItemCommaOrEnd => |case_items| {
1446 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1447 ExpectCommaOrEndResult.end_token => |t| {
1448 if (t == null) {
1449 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1450 }
1451 continue;
1452 },
1453 ExpectCommaOrEndResult.parse_error => |e| {
1454 try tree.errors.push(e);
1455 return tree;
1456 },
1457 }
1458 continue;
1459 },
1460
1461
1462 State.SuspendBody => |suspend_node| {
1463 if (suspend_node.payload != null) {
1464 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1465 }
1466 continue;
1467 },
1468 State.AsyncAllocator => |async_node| {
1469 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
1470 continue;
1471 }
1472
1473 async_node.rangle_bracket = TokenIndex(0);
1474 try stack.append(State {
1475 .ExpectTokenSave = ExpectTokenSave {
1476 .id = Token.Id.AngleBracketRight,
1477 .ptr = &??async_node.rangle_bracket,
1478 }
1479 });
1480 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1481 continue;
1482 },
1483 State.AsyncEnd => |ctx| {
1484 const node = ctx.ctx.get() ?? continue;
1485
1486 switch (node.id) {
1487 ast.Node.Id.FnProto => {
1488 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1489 fn_proto.async_attr = ctx.attribute;
1490 continue;
1491 },
1492 ast.Node.Id.SuffixOp => {
1493 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1494 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1495 suffix_op.op.Call.async_attr = ctx.attribute;
1496 continue;
1497 }
1498
1499 *(try tree.errors.addOne()) = Error {
1500 .ExpectedCall = Error.ExpectedCall { .node = node },
1501 };
1502 return tree;
1503 },
1504 else => {
1505 *(try tree.errors.addOne()) = Error {
1506 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1507 };
1508 return tree;
1509 }
1510 }
1511 },
1512
1513
1514 State.ExternType => |ctx| {
1515 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1516 const fn_proto = try arena.construct(ast.Node.FnProto {
1517 .base = ast.Node {
1518 .id = ast.Node.Id.FnProto,
1519 },
1520 .doc_comments = ctx.comments,
1521 .visib_token = null,
1522 .name_token = null,
1523 .fn_token = fn_token,
1524 .params = ast.Node.FnProto.ParamList.init(arena),
1525 .return_type = undefined,
1526 .var_args_token = null,
1527 .extern_export_inline_token = ctx.extern_token,
1528 .cc_token = null,
1529 .async_attr = null,
1530 .body_node = null,
1531 .lib_name = null,
1532 .align_expr = null,
1533 });
1534 ctx.opt_ctx.store(&fn_proto.base);
1535 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1536 continue;
1537 }
1538
1539 stack.append(State {
1540 .ContainerKind = ContainerKindCtx {
1541 .opt_ctx = ctx.opt_ctx,
1542 .ltoken = ctx.extern_token,
1543 .layout = ast.Node.ContainerDecl.Layout.Extern,
1544 },
1545 }) catch unreachable;
1546 continue;
1547 },
1548 State.SliceOrArrayAccess => |node| {
1549 const token = nextToken(&tok_it, &tree);
1550 const token_index = token.index;
1551 const token_ptr = token.ptr;
1552 switch (token_ptr.id) {
1553 Token.Id.Ellipsis2 => {
1554 const start = node.op.ArrayAccess;
1555 node.op = ast.Node.SuffixOp.Op {
1556 .Slice = ast.Node.SuffixOp.Op.Slice {
1557 .start = start,
1558 .end = null,
1559 }
1560 };
1561
1562 stack.append(State {
1563 .ExpectTokenSave = ExpectTokenSave {
1564 .id = Token.Id.RBracket,
1565 .ptr = &node.rtoken,
1566 }
1567 }) catch unreachable;
1568 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1569 continue;
1570 },
1571 Token.Id.RBracket => {
1572 node.rtoken = token_index;
1573 continue;
1574 },
1575 else => {
1576 *(try tree.errors.addOne()) = Error {
1577 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1578 };
1579 return tree;
1580 }
1581 }
1582 },
1583 State.SliceOrArrayType => |node| {
1584 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {
1585 node.op = ast.Node.PrefixOp.Op {
1586 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1587 .align_expr = null,
1588 .bit_offset_start_token = null,
1589 .bit_offset_end_token = null,
1590 .const_token = null,
1591 .volatile_token = null,
1592 }
1593 };
1594 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1595 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1596 continue;
1597 }
1598
1599 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1600 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1601 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1602 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1603 continue;
1604 },
1605 State.AddrOfModifiers => |addr_of_info| {
1606 const token = nextToken(&tok_it, &tree);
1607 const token_index = token.index;
1608 const token_ptr = token.ptr;
1609 switch (token_ptr.id) {
1610 Token.Id.Keyword_align => {
1611 stack.append(state) catch unreachable;
1612 if (addr_of_info.align_expr != null) {
1613 *(try tree.errors.addOne()) = Error {
1614 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1615 };
1616 return tree;
1617 }
1618 try stack.append(State { .ExpectToken = Token.Id.RParen });
1619 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1620 try stack.append(State { .ExpectToken = Token.Id.LParen });
1621 continue;
1622 },
1623 Token.Id.Keyword_const => {
1624 stack.append(state) catch unreachable;
1625 if (addr_of_info.const_token != null) {
1626 *(try tree.errors.addOne()) = Error {
1627 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1628 };
1629 return tree;
1630 }
1631 addr_of_info.const_token = token_index;
1632 continue;
1633 },
1634 Token.Id.Keyword_volatile => {
1635 stack.append(state) catch unreachable;
1636 if (addr_of_info.volatile_token != null) {
1637 *(try tree.errors.addOne()) = Error {
1638 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1639 };
1640 return tree;
1641 }
1642 addr_of_info.volatile_token = token_index;
1643 continue;
1644 },
1645 else => {
1646 putBackToken(&tok_it, &tree);
1647 continue;
1648 },
1649 }
1650 },
1651
1652
1653 State.Payload => |opt_ctx| {
1654 const token = nextToken(&tok_it, &tree);
1655 const token_index = token.index;
1656 const token_ptr = token.ptr;
1657 if (token_ptr.id != Token.Id.Pipe) {
1658 if (opt_ctx != OptionalCtx.Optional) {
1659 *(try tree.errors.addOne()) = Error {
1660 .ExpectedToken = Error.ExpectedToken {
1661 .token = token_index,
1662 .expected_id = Token.Id.Pipe,
1663 },
1664 };
1665 return tree;
1666 }
1667
1668 putBackToken(&tok_it, &tree);
1669 continue;
1670 }
1671
1672 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1673 ast.Node.Payload {
1674 .base = undefined,
1675 .lpipe = token_index,
1676 .error_symbol = undefined,
1677 .rpipe = undefined
1678 }
1679 );
1680
1681 stack.append(State {
1682 .ExpectTokenSave = ExpectTokenSave {
1683 .id = Token.Id.Pipe,
1684 .ptr = &node.rpipe,
1685 }
1686 }) catch unreachable;
1687 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1688 continue;
1689 },
1690 State.PointerPayload => |opt_ctx| {
1691 const token = nextToken(&tok_it, &tree);
1692 const token_index = token.index;
1693 const token_ptr = token.ptr;
1694 if (token_ptr.id != Token.Id.Pipe) {
1695 if (opt_ctx != OptionalCtx.Optional) {
1696 *(try tree.errors.addOne()) = Error {
1697 .ExpectedToken = Error.ExpectedToken {
1698 .token = token_index,
1699 .expected_id = Token.Id.Pipe,
1700 },
1701 };
1702 return tree;
1703 }
1704
1705 putBackToken(&tok_it, &tree);
1706 continue;
1707 }
1708
1709 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1710 ast.Node.PointerPayload {
1711 .base = undefined,
1712 .lpipe = token_index,
1713 .ptr_token = null,
1714 .value_symbol = undefined,
1715 .rpipe = undefined
1716 }
1717 );
1718
1719 try stack.append(State {
1720 .ExpectTokenSave = ExpectTokenSave {
1721 .id = Token.Id.Pipe,
1722 .ptr = &node.rpipe,
1723 }
1724 });
1725 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1726 try stack.append(State {
1727 .OptionalTokenSave = OptionalTokenSave {
1728 .id = Token.Id.Asterisk,
1729 .ptr = &node.ptr_token,
1730 }
1731 });
1732 continue;
1733 },
1734 State.PointerIndexPayload => |opt_ctx| {
1735 const token = nextToken(&tok_it, &tree);
1736 const token_index = token.index;
1737 const token_ptr = token.ptr;
1738 if (token_ptr.id != Token.Id.Pipe) {
1739 if (opt_ctx != OptionalCtx.Optional) {
1740 *(try tree.errors.addOne()) = Error {
1741 .ExpectedToken = Error.ExpectedToken {
1742 .token = token_index,
1743 .expected_id = Token.Id.Pipe,
1744 },
1745 };
1746 return tree;
1747 }
1748
1749 putBackToken(&tok_it, &tree);
1750 continue;
1751 }
1752
1753 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1754 ast.Node.PointerIndexPayload {
1755 .base = undefined,
1756 .lpipe = token_index,
1757 .ptr_token = null,
1758 .value_symbol = undefined,
1759 .index_symbol = null,
1760 .rpipe = undefined
1761 }
1762 );
1763
1764 stack.append(State {
1765 .ExpectTokenSave = ExpectTokenSave {
1766 .id = Token.Id.Pipe,
1767 .ptr = &node.rpipe,
1768 }
1769 }) catch unreachable;
1770 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1771 try stack.append(State { .IfToken = Token.Id.Comma });
1772 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1773 try stack.append(State {
1774 .OptionalTokenSave = OptionalTokenSave {
1775 .id = Token.Id.Asterisk,
1776 .ptr = &node.ptr_token,
1777 }
1778 });
1779 continue;
1780 },
1781
1782
1783 State.Expression => |opt_ctx| {
1784 const token = nextToken(&tok_it, &tree);
1785 const token_index = token.index;
1786 const token_ptr = token.ptr;
1787 switch (token_ptr.id) {
1788 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1789 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1790 ast.Node.ControlFlowExpression {
1791 .base = undefined,
1792 .ltoken = token_index,
1793 .kind = undefined,
1794 .rhs = null,
1795 }
1796 );
1797
1798 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1799
1800 switch (token_ptr.id) {
1801 Token.Id.Keyword_break => {
1802 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1803 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1804 try stack.append(State { .IfToken = Token.Id.Colon });
1805 },
1806 Token.Id.Keyword_continue => {
1807 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1808 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1809 try stack.append(State { .IfToken = Token.Id.Colon });
1810 },
1811 Token.Id.Keyword_return => {
1812 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1813 },
1814 else => unreachable,
1815 }
1816 continue;
1817 },
1818 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1819 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1820 ast.Node.PrefixOp {
1821 .base = undefined,
1822 .op_token = token_index,
1823 .op = switch (token_ptr.id) {
1824 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1825 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1826 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1827 else => unreachable,
1828 },
1829 .rhs = undefined,
1830 }
1831 );
1832
1833 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1834 continue;
1835 },
1836 else => {
1837 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1838 putBackToken(&tok_it, &tree);
1839 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1840 }
1841 continue;
1842 }
1843 }
1844 },
1845 State.RangeExpressionBegin => |opt_ctx| {
1846 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1847 try stack.append(State { .Expression = opt_ctx });
1848 continue;
1849 },
1850 State.RangeExpressionEnd => |opt_ctx| {
1851 const lhs = opt_ctx.get() ?? continue;
1852
1853 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1854 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1855 ast.Node.InfixOp {
1856 .base = undefined,
1857 .lhs = lhs,
1858 .op_token = ellipsis3,
1859 .op = ast.Node.InfixOp.Op.Range,
1860 .rhs = undefined,
1861 }
1862 );
1863 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1864 continue;
1865 }
1866 },
1867 State.AssignmentExpressionBegin => |opt_ctx| {
1868 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1869 try stack.append(State { .Expression = opt_ctx });
1870 continue;
1871 },
1872
1873 State.AssignmentExpressionEnd => |opt_ctx| {
1874 const lhs = opt_ctx.get() ?? continue;
1875
1876 const token = nextToken(&tok_it, &tree);
1877 const token_index = token.index;
1878 const token_ptr = token.ptr;
1879 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1880 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1881 ast.Node.InfixOp {
1882 .base = undefined,
1883 .lhs = lhs,
1884 .op_token = token_index,
1885 .op = ass_id,
1886 .rhs = undefined,
1887 }
1888 );
1889 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1890 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1891 continue;
1892 } else {
1893 putBackToken(&tok_it, &tree);
1894 continue;
1895 }
1896 },
1897
1898 State.UnwrapExpressionBegin => |opt_ctx| {
1899 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1900 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1901 continue;
1902 },
1903
1904 State.UnwrapExpressionEnd => |opt_ctx| {
1905 const lhs = opt_ctx.get() ?? continue;
1906
1907 const token = nextToken(&tok_it, &tree);
1908 const token_index = token.index;
1909 const token_ptr = token.ptr;
1910 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1911 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1912 ast.Node.InfixOp {
1913 .base = undefined,
1914 .lhs = lhs,
1915 .op_token = token_index,
1916 .op = unwrap_id,
1917 .rhs = undefined,
1918 }
1919 );
1920
1921 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1922 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1923
1924 if (node.op == ast.Node.InfixOp.Op.Catch) {
1925 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1926 }
1927 continue;
1928 } else {
1929 putBackToken(&tok_it, &tree);
1930 continue;
1931 }
1932 },
1933
1934 State.BoolOrExpressionBegin => |opt_ctx| {
1935 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1936 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1937 continue;
1938 },
1939
1940 State.BoolOrExpressionEnd => |opt_ctx| {
1941 const lhs = opt_ctx.get() ?? continue;
1942
1943 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1944 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1945 ast.Node.InfixOp {
1946 .base = undefined,
1947 .lhs = lhs,
1948 .op_token = or_token,
1949 .op = ast.Node.InfixOp.Op.BoolOr,
1950 .rhs = undefined,
1951 }
1952 );
1953 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1954 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1955 continue;
1956 }
1957 },
1958
1959 State.BoolAndExpressionBegin => |opt_ctx| {
1960 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1961 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1962 continue;
1963 },
1964
1965 State.BoolAndExpressionEnd => |opt_ctx| {
1966 const lhs = opt_ctx.get() ?? continue;
1967
1968 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1969 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1970 ast.Node.InfixOp {
1971 .base = undefined,
1972 .lhs = lhs,
1973 .op_token = and_token,
1974 .op = ast.Node.InfixOp.Op.BoolAnd,
1975 .rhs = undefined,
1976 }
1977 );
1978 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1979 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1980 continue;
1981 }
1982 },
1983
1984 State.ComparisonExpressionBegin => |opt_ctx| {
1985 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1986 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
1987 continue;
1988 },
1989
1990 State.ComparisonExpressionEnd => |opt_ctx| {
1991 const lhs = opt_ctx.get() ?? continue;
1992
1993 const token = nextToken(&tok_it, &tree);
1994 const token_index = token.index;
1995 const token_ptr = token.ptr;
1996 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1997 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1998 ast.Node.InfixOp {
1999 .base = undefined,
2000 .lhs = lhs,
2001 .op_token = token_index,
2002 .op = comp_id,
2003 .rhs = undefined,
2004 }
2005 );
2006 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2007 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2008 continue;
2009 } else {
2010 putBackToken(&tok_it, &tree);
2011 continue;
2012 }
2013 },
2014
2015 State.BinaryOrExpressionBegin => |opt_ctx| {
2016 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2017 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2018 continue;
2019 },
2020
2021 State.BinaryOrExpressionEnd => |opt_ctx| {
2022 const lhs = opt_ctx.get() ?? continue;
2023
2024 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
2025 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2026 ast.Node.InfixOp {
2027 .base = undefined,
2028 .lhs = lhs,
2029 .op_token = pipe,
2030 .op = ast.Node.InfixOp.Op.BitOr,
2031 .rhs = undefined,
2032 }
2033 );
2034 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2035 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2036 continue;
2037 }
2038 },
2039
2040 State.BinaryXorExpressionBegin => |opt_ctx| {
2041 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2042 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2043 continue;
2044 },
2045
2046 State.BinaryXorExpressionEnd => |opt_ctx| {
2047 const lhs = opt_ctx.get() ?? continue;
2048
2049 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2050 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2051 ast.Node.InfixOp {
2052 .base = undefined,
2053 .lhs = lhs,
2054 .op_token = caret,
2055 .op = ast.Node.InfixOp.Op.BitXor,
2056 .rhs = undefined,
2057 }
2058 );
2059 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2060 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2061 continue;
2062 }
2063 },
2064
2065 State.BinaryAndExpressionBegin => |opt_ctx| {
2066 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2067 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2068 continue;
2069 },
2070
2071 State.BinaryAndExpressionEnd => |opt_ctx| {
2072 const lhs = opt_ctx.get() ?? continue;
2073
2074 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2075 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2076 ast.Node.InfixOp {
2077 .base = undefined,
2078 .lhs = lhs,
2079 .op_token = ampersand,
2080 .op = ast.Node.InfixOp.Op.BitAnd,
2081 .rhs = undefined,
2082 }
2083 );
2084 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2085 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2086 continue;
2087 }
2088 },
2089
2090 State.BitShiftExpressionBegin => |opt_ctx| {
2091 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2092 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2093 continue;
2094 },
2095
2096 State.BitShiftExpressionEnd => |opt_ctx| {
2097 const lhs = opt_ctx.get() ?? continue;
2098
2099 const token = nextToken(&tok_it, &tree);
2100 const token_index = token.index;
2101 const token_ptr = token.ptr;
2102 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2103 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2104 ast.Node.InfixOp {
2105 .base = undefined,
2106 .lhs = lhs,
2107 .op_token = token_index,
2108 .op = bitshift_id,
2109 .rhs = undefined,
2110 }
2111 );
2112 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2113 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2114 continue;
2115 } else {
2116 putBackToken(&tok_it, &tree);
2117 continue;
2118 }
2119 },
2120
2121 State.AdditionExpressionBegin => |opt_ctx| {
2122 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2123 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2124 continue;
2125 },
2126
2127 State.AdditionExpressionEnd => |opt_ctx| {
2128 const lhs = opt_ctx.get() ?? continue;
2129
2130 const token = nextToken(&tok_it, &tree);
2131 const token_index = token.index;
2132 const token_ptr = token.ptr;
2133 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2134 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2135 ast.Node.InfixOp {
2136 .base = undefined,
2137 .lhs = lhs,
2138 .op_token = token_index,
2139 .op = add_id,
2140 .rhs = undefined,
2141 }
2142 );
2143 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2144 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2145 continue;
2146 } else {
2147 putBackToken(&tok_it, &tree);
2148 continue;
2149 }
2150 },
2151
2152 State.MultiplyExpressionBegin => |opt_ctx| {
2153 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2154 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2155 continue;
2156 },
2157
2158 State.MultiplyExpressionEnd => |opt_ctx| {
2159 const lhs = opt_ctx.get() ?? continue;
2160
2161 const token = nextToken(&tok_it, &tree);
2162 const token_index = token.index;
2163 const token_ptr = token.ptr;
2164 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2165 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2166 ast.Node.InfixOp {
2167 .base = undefined,
2168 .lhs = lhs,
2169 .op_token = token_index,
2170 .op = mult_id,
2171 .rhs = undefined,
2172 }
2173 );
2174 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2175 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2176 continue;
2177 } else {
2178 putBackToken(&tok_it, &tree);
2179 continue;
2180 }
2181 },
2182
2183 State.CurlySuffixExpressionBegin => |opt_ctx| {
2184 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2185 try stack.append(State { .IfToken = Token.Id.LBrace });
2186 try stack.append(State { .TypeExprBegin = opt_ctx });
2187 continue;
2188 },
2189
2190 State.CurlySuffixExpressionEnd => |opt_ctx| {
2191 const lhs = opt_ctx.get() ?? continue;
2192
2193 if ((??tok_it.peek()).id == Token.Id.Period) {
2194 const node = try arena.construct(ast.Node.SuffixOp {
2195 .base = ast.Node { .id = ast.Node.Id.SuffixOp },
2196 .lhs = lhs,
2197 .op = ast.Node.SuffixOp.Op {
2198 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2199 },
2200 .rtoken = undefined,
2201 });
2202 opt_ctx.store(&node.base);
2203
2204 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2205 try stack.append(State { .IfToken = Token.Id.LBrace });
2206 try stack.append(State {
2207 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {
2208 .list = &node.op.StructInitializer,
2209 .ptr = &node.rtoken,
2210 }
2211 });
2212 continue;
2213 }
2214
2215 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2216 ast.Node.SuffixOp {
2217 .base = undefined,
2218 .lhs = lhs,
2219 .op = ast.Node.SuffixOp.Op {
2220 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2221 },
2222 .rtoken = undefined,
2223 }
2224 );
2225 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2226 try stack.append(State { .IfToken = Token.Id.LBrace });
2227 try stack.append(State {
2228 .ExprListItemOrEnd = ExprListCtx {
2229 .list = &node.op.ArrayInitializer,
2230 .end = Token.Id.RBrace,
2231 .ptr = &node.rtoken,
2232 }
2233 });
2234 continue;
2235 },
2236
2237 State.TypeExprBegin => |opt_ctx| {
2238 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2239 try stack.append(State { .PrefixOpExpression = opt_ctx });
2240 continue;
2241 },
2242
2243 State.TypeExprEnd => |opt_ctx| {
2244 const lhs = opt_ctx.get() ?? continue;
2245
2246 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2247 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2248 ast.Node.InfixOp {
2249 .base = undefined,
2250 .lhs = lhs,
2251 .op_token = bang,
2252 .op = ast.Node.InfixOp.Op.ErrorUnion,
2253 .rhs = undefined,
2254 }
2255 );
2256 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2257 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2258 continue;
2259 }
2260 },
2261
2262 State.PrefixOpExpression => |opt_ctx| {
2263 const token = nextToken(&tok_it, &tree);
2264 const token_index = token.index;
2265 const token_ptr = token.ptr;
2266 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2267 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2268 ast.Node.PrefixOp {
2269 .base = undefined,
2270 .op_token = token_index,
2271 .op = prefix_id,
2272 .rhs = undefined,
2273 }
2274 );
2275
2276 // Treat '**' token as two derefs
2277 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2278 const child = try createNode(arena, ast.Node.PrefixOp,
2279 ast.Node.PrefixOp {
2280 .base = undefined,
2281 .op_token = token_index,
2282 .op = prefix_id,
2283 .rhs = undefined,
2284 }
2285 );
2286 node.rhs = &child.base;
2287 node = child;
2288 }
2289
2290 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2291 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2292 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2293 }
2294 continue;
2295 } else {
2296 putBackToken(&tok_it, &tree);
2297 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2298 continue;
2299 }
2300 },
2301
2302 State.SuffixOpExpressionBegin => |opt_ctx| {
2303 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2304 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
2305 ast.Node.AsyncAttribute {
2306 .base = undefined,
2307 .async_token = async_token,
2308 .allocator_type = null,
2309 .rangle_bracket = null,
2310 }
2311 );
2312 stack.append(State {
2313 .AsyncEnd = AsyncEndCtx {
2314 .ctx = opt_ctx,
2315 .attribute = async_node,
2316 }
2317 }) catch unreachable;
2318 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2319 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2320 try stack.append(State { .AsyncAllocator = async_node });
2321 continue;
2322 }
2323
2324 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2325 try stack.append(State { .PrimaryExpression = opt_ctx });
2326 continue;
2327 },
2328
2329 State.SuffixOpExpressionEnd => |opt_ctx| {
2330 const lhs = opt_ctx.get() ?? continue;
2331
2332 const token = nextToken(&tok_it, &tree);
2333 const token_index = token.index;
2334 const token_ptr = token.ptr;
2335 switch (token_ptr.id) {
2336 Token.Id.LParen => {
2337 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2338 ast.Node.SuffixOp {
2339 .base = undefined,
2340 .lhs = lhs,
2341 .op = ast.Node.SuffixOp.Op {
2342 .Call = ast.Node.SuffixOp.Op.Call {
2343 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2344 .async_attr = null,
2345 }
2346 },
2347 .rtoken = undefined,
2348 }
2349 );
2350 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2351 try stack.append(State {
2352 .ExprListItemOrEnd = ExprListCtx {
2353 .list = &node.op.Call.params,
2354 .end = Token.Id.RParen,
2355 .ptr = &node.rtoken,
2356 }
2357 });
2358 continue;
2359 },
2360 Token.Id.LBracket => {
2361 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2362 ast.Node.SuffixOp {
2363 .base = undefined,
2364 .lhs = lhs,
2365 .op = ast.Node.SuffixOp.Op {
2366 .ArrayAccess = undefined,
2367 },
2368 .rtoken = undefined
2369 }
2370 );
2371 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2372 try stack.append(State { .SliceOrArrayAccess = node });
2373 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2374 continue;
2375 },
2376 Token.Id.Period => {
2377 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2378 ast.Node.InfixOp {
2379 .base = undefined,
2380 .lhs = lhs,
2381 .op_token = token_index,
2382 .op = ast.Node.InfixOp.Op.Period,
2383 .rhs = undefined,
2384 }
2385 );
2386 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2387 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2388 continue;
2389 },
2390 else => {
2391 putBackToken(&tok_it, &tree);
2392 continue;
2393 },
2394 }
2395 },
2396
2397 State.PrimaryExpression => |opt_ctx| {
2398 const token = nextToken(&tok_it, &tree);
2399 switch (token.ptr.id) {
2400 Token.Id.IntegerLiteral => {
2401 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token.index);
2402 continue;
2403 },
2404 Token.Id.FloatLiteral => {
2405 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index);
2406 continue;
2407 },
2408 Token.Id.CharLiteral => {
2409 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token.index);
2410 continue;
2411 },
2412 Token.Id.Keyword_undefined => {
2413 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2414 continue;
2415 },
2416 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2417 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
2418 continue;
2419 },
2420 Token.Id.Keyword_null => {
2421 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token.index);
2422 continue;
2423 },
2424 Token.Id.Keyword_this => {
2425 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token.index);
2426 continue;
2427 },
2428 Token.Id.Keyword_var => {
2429 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token.index);
2430 continue;
2431 },
2432 Token.Id.Keyword_unreachable => {
2433 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token.index);
2434 continue;
2435 },
2436 Token.Id.Keyword_promise => {
2437 const node = try arena.construct(ast.Node.PromiseType {
2438 .base = ast.Node {
2439 .id = ast.Node.Id.PromiseType,
2440 },
2441 .promise_token = token.index,
2442 .result = null,
2443 });
2444 opt_ctx.store(&node.base);
2445 const next_token = nextToken(&tok_it, &tree);
2446 const next_token_index = next_token.index;
2447 const next_token_ptr = next_token.ptr;
2448 if (next_token_ptr.id != Token.Id.Arrow) {
2449 putBackToken(&tok_it, &tree);
2450 continue;
2451 }
2452 node.result = ast.Node.PromiseType.Result {
2453 .arrow_token = next_token_index,
2454 .return_type = undefined,
2455 };
2456 const return_type_ptr = &((??node.result).return_type);
2457 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2458 continue;
2459 },
2460 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2461 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
2462 continue;
2463 },
2464 Token.Id.LParen => {
2465 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2466 ast.Node.GroupedExpression {
2467 .base = undefined,
2468 .lparen = token.index,
2469 .expr = undefined,
2470 .rparen = undefined,
2471 }
2472 );
2473 stack.append(State {
2474 .ExpectTokenSave = ExpectTokenSave {
2475 .id = Token.Id.RParen,
2476 .ptr = &node.rparen,
2477 }
2478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2480 continue;
2481 },
2482 Token.Id.Builtin => {
2483 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2484 ast.Node.BuiltinCall {
2485 .base = undefined,
2486 .builtin_token = token.index,
2487 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2488 .rparen_token = undefined,
2489 }
2490 );
2491 stack.append(State {
2492 .ExprListItemOrEnd = ExprListCtx {
2493 .list = &node.params,
2494 .end = Token.Id.RParen,
2495 .ptr = &node.rparen_token,
2496 }
2497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2499 continue;
2500 },
2501 Token.Id.LBracket => {
2502 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2503 ast.Node.PrefixOp {
2504 .base = undefined,
2505 .op_token = token.index,
2506 .op = undefined,
2507 .rhs = undefined,
2508 }
2509 );
2510 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2511 continue;
2512 },
2513 Token.Id.Keyword_error => {
2514 stack.append(State {
2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2516 .error_token = token.index,
2517 .opt_ctx = opt_ctx
2518 }
2519 }) catch unreachable;
2520 continue;
2521 },
2522 Token.Id.Keyword_packed => {
2523 stack.append(State {
2524 .ContainerKind = ContainerKindCtx {
2525 .opt_ctx = opt_ctx,
2526 .ltoken = token.index,
2527 .layout = ast.Node.ContainerDecl.Layout.Packed,
2528 },
2529 }) catch unreachable;
2530 continue;
2531 },
2532 Token.Id.Keyword_extern => {
2533 stack.append(State {
2534 .ExternType = ExternTypeCtx {
2535 .opt_ctx = opt_ctx,
2536 .extern_token = token.index,
2537 .comments = null,
2538 },
2539 }) catch unreachable;
2540 continue;
2541 },
2542 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2543 putBackToken(&tok_it, &tree);
2544 stack.append(State {
2545 .ContainerKind = ContainerKindCtx {
2546 .opt_ctx = opt_ctx,
2547 .ltoken = token.index,
2548 .layout = ast.Node.ContainerDecl.Layout.Auto,
2549 },
2550 }) catch unreachable;
2551 continue;
2552 },
2553 Token.Id.Identifier => {
2554 stack.append(State {
2555 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2556 .label = token.index,
2557 .opt_ctx = opt_ctx
2558 }
2559 }) catch unreachable;
2560 continue;
2561 },
2562 Token.Id.Keyword_fn => {
2563 const fn_proto = try arena.construct(ast.Node.FnProto {
2564 .base = ast.Node {
2565 .id = ast.Node.Id.FnProto,
2566 },
2567 .doc_comments = null,
2568 .visib_token = null,
2569 .name_token = null,
2570 .fn_token = token.index,
2571 .params = ast.Node.FnProto.ParamList.init(arena),
2572 .return_type = undefined,
2573 .var_args_token = null,
2574 .extern_export_inline_token = null,
2575 .cc_token = null,
2576 .async_attr = null,
2577 .body_node = null,
2578 .lib_name = null,
2579 .align_expr = null,
2580 });
2581 opt_ctx.store(&fn_proto.base);
2582 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2583 continue;
2584 },
2585 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2586 const fn_proto = try arena.construct(ast.Node.FnProto {
2587 .base = ast.Node {
2588 .id = ast.Node.Id.FnProto,
2589 },
2590 .doc_comments = null,
2591 .visib_token = null,
2592 .name_token = null,
2593 .fn_token = undefined,
2594 .params = ast.Node.FnProto.ParamList.init(arena),
2595 .return_type = undefined,
2596 .var_args_token = null,
2597 .extern_export_inline_token = null,
2598 .cc_token = token.index,
2599 .async_attr = null,
2600 .body_node = null,
2601 .lib_name = null,
2602 .align_expr = null,
2603 });
2604 opt_ctx.store(&fn_proto.base);
2605 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2606 try stack.append(State {
2607 .ExpectTokenSave = ExpectTokenSave {
2608 .id = Token.Id.Keyword_fn,
2609 .ptr = &fn_proto.fn_token
2610 }
2611 });
2612 continue;
2613 },
2614 Token.Id.Keyword_asm => {
2615 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2616 ast.Node.Asm {
2617 .base = undefined,
2618 .asm_token = token.index,
2619 .volatile_token = null,
2620 .template = undefined,
2621 .outputs = ast.Node.Asm.OutputList.init(arena),
2622 .inputs = ast.Node.Asm.InputList.init(arena),
2623 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2624 .rparen = undefined,
2625 }
2626 );
2627 stack.append(State {
2628 .ExpectTokenSave = ExpectTokenSave {
2629 .id = Token.Id.RParen,
2630 .ptr = &node.rparen,
2631 }
2632 }) catch unreachable;
2633 try stack.append(State { .AsmClobberItems = &node.clobbers });
2634 try stack.append(State { .IfToken = Token.Id.Colon });
2635 try stack.append(State { .AsmInputItems = &node.inputs });
2636 try stack.append(State { .IfToken = Token.Id.Colon });
2637 try stack.append(State { .AsmOutputItems = &node.outputs });
2638 try stack.append(State { .IfToken = Token.Id.Colon });
2639 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2640 try stack.append(State { .ExpectToken = Token.Id.LParen });
2641 try stack.append(State {
2642 .OptionalTokenSave = OptionalTokenSave {
2643 .id = Token.Id.Keyword_volatile,
2644 .ptr = &node.volatile_token,
2645 }
2646 });
2647 },
2648 Token.Id.Keyword_inline => {
2649 stack.append(State {
2650 .Inline = InlineCtx {
2651 .label = null,
2652 .inline_token = token.index,
2653 .opt_ctx = opt_ctx,
2654 }
2655 }) catch unreachable;
2656 continue;
2657 },
2658 else => {
2659 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2660 putBackToken(&tok_it, &tree);
2661 if (opt_ctx != OptionalCtx.Optional) {
2662 *(try tree.errors.addOne()) = Error {
2663 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token.index },
2664 };
2665 return tree;
2666 }
2667 }
2668 continue;
2669 }
2670 }
2671 },
2672
2673
2674 State.ErrorTypeOrSetDecl => |ctx| {
2675 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
2676 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2677 continue;
2678 }
2679
2680 const node = try arena.construct(ast.Node.ErrorSetDecl {
2681 .base = ast.Node {
2682 .id = ast.Node.Id.ErrorSetDecl,
2683 },
2684 .error_token = ctx.error_token,
2685 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2686 .rbrace_token = undefined,
2687 });
2688 ctx.opt_ctx.store(&node.base);
2689
2690 stack.append(State {
2691 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {
2692 .list = &node.decls,
2693 .ptr = &node.rbrace_token,
2694 }
2695 }) catch unreachable;
2696 continue;
2697 },
2698 State.StringLiteral => |opt_ctx| {
2699 const token = nextToken(&tok_it, &tree);
2700 const token_index = token.index;
2701 const token_ptr = token.ptr;
2702 opt_ctx.store(
2703 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2704 putBackToken(&tok_it, &tree);
2705 if (opt_ctx != OptionalCtx.Optional) {
2706 *(try tree.errors.addOne()) = Error {
2707 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2708 };
2709 return tree;
2710 }
2711
2712 continue;
2713 }
2714 );
2715 },
2716
2717 State.Identifier => |opt_ctx| {
2718 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
2719 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2720 continue;
2721 }
2722
2723 if (opt_ctx != OptionalCtx.Optional) {
2724 const token = nextToken(&tok_it, &tree);
2725 const token_index = token.index;
2726 const token_ptr = token.ptr;
2727 *(try tree.errors.addOne()) = Error {
2728 .ExpectedToken = Error.ExpectedToken {
2729 .token = token_index,
2730 .expected_id = Token.Id.Identifier,
2731 },
2732 };
2733 return tree;
2734 }
2735 },
2736
2737 State.ErrorTag => |node_ptr| {
2738 const comments = try eatDocComments(arena, &tok_it, &tree);
2739 const ident_token = nextToken(&tok_it, &tree);
2740 const ident_token_index = ident_token.index;
2741 const ident_token_ptr = ident_token.ptr;
2742 if (ident_token_ptr.id != Token.Id.Identifier) {
2743 *(try tree.errors.addOne()) = Error {
2744 .ExpectedToken = Error.ExpectedToken {
2745 .token = ident_token_index,
2746 .expected_id = Token.Id.Identifier,
2747 },
2748 };
2749 return tree;
2750 }
2751
2752 const node = try arena.construct(ast.Node.ErrorTag {
2753 .base = ast.Node {
2754 .id = ast.Node.Id.ErrorTag,
2755 },
2756 .doc_comments = comments,
2757 .name_token = ident_token_index,
2758 });
2759 *node_ptr = &node.base;
2760 continue;
2761 },
2762
2763 State.ExpectToken => |token_id| {
2764 const token = nextToken(&tok_it, &tree);
2765 const token_index = token.index;
2766 const token_ptr = token.ptr;
2767 if (token_ptr.id != token_id) {
2768 *(try tree.errors.addOne()) = Error {
2769 .ExpectedToken = Error.ExpectedToken {
2770 .token = token_index,
2771 .expected_id = token_id,
2772 },
2773 };
2774 return tree;
2775 }
2776 continue;
2777 },
2778 State.ExpectTokenSave => |expect_token_save| {
2779 const token = nextToken(&tok_it, &tree);
2780 const token_index = token.index;
2781 const token_ptr = token.ptr;
2782 if (token_ptr.id != expect_token_save.id) {
2783 *(try tree.errors.addOne()) = Error {
2784 .ExpectedToken = Error.ExpectedToken {
2785 .token = token_index,
2786 .expected_id = expect_token_save.id,
2787 },
2788 };
2789 return tree;
2790 }
2791 *expect_token_save.ptr = token_index;
2792 continue;
2793 },
2794 State.IfToken => |token_id| {
2795 if (eatToken(&tok_it, &tree, token_id)) |_| {
2796 continue;
2797 }
2798
2799 _ = stack.pop();
2800 continue;
2801 },
2802 State.IfTokenSave => |if_token_save| {
2803 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {
2804 *if_token_save.ptr = token_index;
2805 continue;
2806 }
2807
2808 _ = stack.pop();
2809 continue;
2810 },
2811 State.OptionalTokenSave => |optional_token_save| {
2812 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {
2813 *optional_token_save.ptr = token_index;
2814 continue;
2815 }
2816
2817 continue;
2818 },
2819 }
2820 }
2821}
2822
2823const AnnotatedToken = struct {
2824 ptr: &Token,
2825 index: TokenIndex,
2826};
2827
2828const TopLevelDeclCtx = struct {
2829 decls: &ast.Node.Root.DeclList,
2830 visib_token: ?TokenIndex,
2831 extern_export_inline_token: ?AnnotatedToken,
2832 lib_name: ?&ast.Node,
2833 comments: ?&ast.Node.DocComment,
2834};
2835
2836const VarDeclCtx = struct {
2837 mut_token: TokenIndex,
2838 visib_token: ?TokenIndex,
2839 comptime_token: ?TokenIndex,
2840 extern_export_token: ?TokenIndex,
2841 lib_name: ?&ast.Node,
2842 list: &ast.Node.Root.DeclList,
2843 comments: ?&ast.Node.DocComment,
2844};
2845
2846const TopLevelExternOrFieldCtx = struct {
2847 visib_token: TokenIndex,
2848 container_decl: &ast.Node.ContainerDecl,
2849 comments: ?&ast.Node.DocComment,
2850};
2851
2852const ExternTypeCtx = struct {
2853 opt_ctx: OptionalCtx,
2854 extern_token: TokenIndex,
2855 comments: ?&ast.Node.DocComment,
2856};
2857
2858const ContainerKindCtx = struct {
2859 opt_ctx: OptionalCtx,
2860 ltoken: TokenIndex,
2861 layout: ast.Node.ContainerDecl.Layout,
2862};
2863
2864const ExpectTokenSave = struct {
2865 id: @TagType(Token.Id),
2866 ptr: &TokenIndex,
2867};
2868
2869const OptionalTokenSave = struct {
2870 id: @TagType(Token.Id),
2871 ptr: &?TokenIndex,
2872};
2873
2874const ExprListCtx = struct {
2875 list: &ast.Node.SuffixOp.Op.InitList,
2876 end: Token.Id,
2877 ptr: &TokenIndex,
2878};
2879
2880fn ListSave(comptime List: type) type {
2881 return struct {
2882 list: &List,
2883 ptr: &TokenIndex,
2884 };
2885}
2886
2887const MaybeLabeledExpressionCtx = struct {
2888 label: TokenIndex,
2889 opt_ctx: OptionalCtx,
2890};
2891
2892const LabelCtx = struct {
2893 label: ?TokenIndex,
2894 opt_ctx: OptionalCtx,
2895};
2896
2897const InlineCtx = struct {
2898 label: ?TokenIndex,
2899 inline_token: ?TokenIndex,
2900 opt_ctx: OptionalCtx,
2901};
2902
2903const LoopCtx = struct {
2904 label: ?TokenIndex,
2905 inline_token: ?TokenIndex,
2906 loop_token: TokenIndex,
2907 opt_ctx: OptionalCtx,
2908};
2909
2910const AsyncEndCtx = struct {
2911 ctx: OptionalCtx,
2912 attribute: &ast.Node.AsyncAttribute,
2913};
2914
2915const ErrorTypeOrSetDeclCtx = struct {
2916 opt_ctx: OptionalCtx,
2917 error_token: TokenIndex,
2918};
2919
2920const ParamDeclEndCtx = struct {
2921 fn_proto: &ast.Node.FnProto,
2922 param_decl: &ast.Node.ParamDecl,
2923};
2924
2925const ComptimeStatementCtx = struct {
2926 comptime_token: TokenIndex,
2927 block: &ast.Node.Block,
2928};
2929
2930const OptionalCtx = union(enum) {
2931 Optional: &?&ast.Node,
2932 RequiredNull: &?&ast.Node,
2933 Required: &&ast.Node,
2934
2935 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2936 switch (*self) {
2937 OptionalCtx.Optional => |ptr| *ptr = value,
2938 OptionalCtx.RequiredNull => |ptr| *ptr = value,
2939 OptionalCtx.Required => |ptr| *ptr = value,
2940 }
2941 }
2942
2943 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2944 switch (*self) {
2945 OptionalCtx.Optional => |ptr| return *ptr,
2946 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
2947 OptionalCtx.Required => |ptr| return *ptr,
2948 }
2949 }
2950
2951 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2952 switch (*self) {
2953 OptionalCtx.Optional => |ptr| {
2954 return OptionalCtx { .RequiredNull = ptr };
2955 },
2956 OptionalCtx.RequiredNull => |ptr| return *self,
2957 OptionalCtx.Required => |ptr| return *self,
2958 }
2959 }
2960};
2961
2962const AddCommentsCtx = struct {
2963 node_ptr: &&ast.Node,
2964 comments: ?&ast.Node.DocComment,
2965};
2966
2967const State = union(enum) {
2968 TopLevel,
2969 TopLevelExtern: TopLevelDeclCtx,
2970 TopLevelLibname: TopLevelDeclCtx,
2971 TopLevelDecl: TopLevelDeclCtx,
2972 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2973
2974 ContainerKind: ContainerKindCtx,
2975 ContainerInitArgStart: &ast.Node.ContainerDecl,
2976 ContainerInitArg: &ast.Node.ContainerDecl,
2977 ContainerDecl: &ast.Node.ContainerDecl,
2978
2979 VarDecl: VarDeclCtx,
2980 VarDeclAlign: &ast.Node.VarDecl,
2981 VarDeclEq: &ast.Node.VarDecl,
2982
2983 FnDef: &ast.Node.FnProto,
2984 FnProto: &ast.Node.FnProto,
2985 FnProtoAlign: &ast.Node.FnProto,
2986 FnProtoReturnType: &ast.Node.FnProto,
2987
2988 ParamDecl: &ast.Node.FnProto,
2989 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
2990 ParamDeclName: &ast.Node.ParamDecl,
2991 ParamDeclEnd: ParamDeclEndCtx,
2992 ParamDeclComma: &ast.Node.FnProto,
2993
2994 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2995 LabeledExpression: LabelCtx,
2996 Inline: InlineCtx,
2997 While: LoopCtx,
2998 WhileContinueExpr: &?&ast.Node,
2999 For: LoopCtx,
3000 Else: &?&ast.Node.Else,
3001
3002 Block: &ast.Node.Block,
3003 Statement: &ast.Node.Block,
3004 ComptimeStatement: ComptimeStatementCtx,
3005 Semicolon: &&ast.Node,
3006
3007 AsmOutputItems: &ast.Node.Asm.OutputList,
3008 AsmOutputReturnOrType: &ast.Node.AsmOutput,
3009 AsmInputItems: &ast.Node.Asm.InputList,
3010 AsmClobberItems: &ast.Node.Asm.ClobberList,
3011
3012 ExprListItemOrEnd: ExprListCtx,
3013 ExprListCommaOrEnd: ExprListCtx,
3014 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3015 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3016 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
3017 FieldInitValue: OptionalCtx,
3018 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3019 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3020 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
3021 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
3022 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
3023 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
3024 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
3025
3026 SuspendBody: &ast.Node.Suspend,
3027 AsyncAllocator: &ast.Node.AsyncAttribute,
3028 AsyncEnd: AsyncEndCtx,
3029
3030 ExternType: ExternTypeCtx,
3031 SliceOrArrayAccess: &ast.Node.SuffixOp,
3032 SliceOrArrayType: &ast.Node.PrefixOp,
3033 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
3034
3035 Payload: OptionalCtx,
3036 PointerPayload: OptionalCtx,
3037 PointerIndexPayload: OptionalCtx,
3038
3039 Expression: OptionalCtx,
3040 RangeExpressionBegin: OptionalCtx,
3041 RangeExpressionEnd: OptionalCtx,
3042 AssignmentExpressionBegin: OptionalCtx,
3043 AssignmentExpressionEnd: OptionalCtx,
3044 UnwrapExpressionBegin: OptionalCtx,
3045 UnwrapExpressionEnd: OptionalCtx,
3046 BoolOrExpressionBegin: OptionalCtx,
3047 BoolOrExpressionEnd: OptionalCtx,
3048 BoolAndExpressionBegin: OptionalCtx,
3049 BoolAndExpressionEnd: OptionalCtx,
3050 ComparisonExpressionBegin: OptionalCtx,
3051 ComparisonExpressionEnd: OptionalCtx,
3052 BinaryOrExpressionBegin: OptionalCtx,
3053 BinaryOrExpressionEnd: OptionalCtx,
3054 BinaryXorExpressionBegin: OptionalCtx,
3055 BinaryXorExpressionEnd: OptionalCtx,
3056 BinaryAndExpressionBegin: OptionalCtx,
3057 BinaryAndExpressionEnd: OptionalCtx,
3058 BitShiftExpressionBegin: OptionalCtx,
3059 BitShiftExpressionEnd: OptionalCtx,
3060 AdditionExpressionBegin: OptionalCtx,
3061 AdditionExpressionEnd: OptionalCtx,
3062 MultiplyExpressionBegin: OptionalCtx,
3063 MultiplyExpressionEnd: OptionalCtx,
3064 CurlySuffixExpressionBegin: OptionalCtx,
3065 CurlySuffixExpressionEnd: OptionalCtx,
3066 TypeExprBegin: OptionalCtx,
3067 TypeExprEnd: OptionalCtx,
3068 PrefixOpExpression: OptionalCtx,
3069 SuffixOpExpressionBegin: OptionalCtx,
3070 SuffixOpExpressionEnd: OptionalCtx,
3071 PrimaryExpression: OptionalCtx,
3072
3073 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3074 StringLiteral: OptionalCtx,
3075 Identifier: OptionalCtx,
3076 ErrorTag: &&ast.Node,
3077
3078
3079 IfToken: @TagType(Token.Id),
3080 IfTokenSave: ExpectTokenSave,
3081 ExpectToken: @TagType(Token.Id),
3082 ExpectTokenSave: ExpectTokenSave,
3083 OptionalTokenSave: OptionalTokenSave,
3084};
3085
3086fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment {
3087 var result: ?&ast.Node.DocComment = null;
3088 while (true) {
3089 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3090 const node = blk: {
3091 if (result) |comment_node| {
3092 break :blk comment_node;
3093 } else {
3094 const comment_node = try arena.construct(ast.Node.DocComment {
3095 .base = ast.Node {
3096 .id = ast.Node.Id.DocComment,
3097 },
3098 .lines = ast.Node.DocComment.LineList.init(arena),
3099 });
3100 result = comment_node;
3101 break :blk comment_node;
3102 }
3103 };
3104 try node.lines.push(line_comment);
3105 continue;
3106 }
3107 break;
3108 }
3109 return result;
3110}
3111
3112fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.LineComment {
3113 const token = eatToken(tok_it, tree, Token.Id.LineComment) ?? return null;
3114 return try arena.construct(ast.Node.LineComment {
3115 .base = ast.Node {
3116 .id = ast.Node.Id.LineComment,
3117 },
3118 .token = token,
3119 });
3120}
3121
3122fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3123 token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node
3124{
3125 switch (token_ptr.id) {
3126 Token.Id.StringLiteral => {
3127 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3128 },
3129 Token.Id.MultilineStringLiteralLine => {
3130 const node = try arena.construct(ast.Node.MultilineStringLiteral {
3131 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },
3132 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3133 });
3134 try node.lines.push(token_index);
3135 while (true) {
3136 const multiline_str = nextToken(tok_it, tree);
3137 const multiline_str_index = multiline_str.index;
3138 const multiline_str_ptr = multiline_str.ptr;
3139 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3140 putBackToken(tok_it, tree);
3141 break;
3142 }
3143
3144 try node.lines.push(multiline_str_index);
3145 }
3146
3147 return &node.base;
3148 },
3149 // TODO: We shouldn't need a cast, but:
3150 // 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.
3151 else => return (?&ast.Node)(null),
3152 }
3153}
3154
3155fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx,
3156 token_ptr: &const Token, token_index: TokenIndex) !bool {
3157 switch (token_ptr.id) {
3158 Token.Id.Keyword_suspend => {
3159 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,
3160 ast.Node.Suspend {
3161 .base = undefined,
3162 .label = null,
3163 .suspend_token = token_index,
3164 .payload = null,
3165 .body = null,
3166 }
3167 );
3168
3169 stack.append(State { .SuspendBody = node }) catch unreachable;
3170 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3171 return true;
3172 },
3173 Token.Id.Keyword_if => {
3174 const node = try createToCtxNode(arena, ctx, ast.Node.If,
3175 ast.Node.If {
3176 .base = undefined,
3177 .if_token = token_index,
3178 .condition = undefined,
3179 .payload = null,
3180 .body = undefined,
3181 .@"else" = null,
3182 }
3183 );
3184
3185 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3186 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3187 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3188 try stack.append(State { .ExpectToken = Token.Id.RParen });
3189 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3190 try stack.append(State { .ExpectToken = Token.Id.LParen });
3191 return true;
3192 },
3193 Token.Id.Keyword_while => {
3194 stack.append(State {
3195 .While = LoopCtx {
3196 .label = null,
3197 .inline_token = null,
3198 .loop_token = token_index,
3199 .opt_ctx = *ctx,
3200 }
3201 }) catch unreachable;
3202 return true;
3203 },
3204 Token.Id.Keyword_for => {
3205 stack.append(State {
3206 .For = LoopCtx {
3207 .label = null,
3208 .inline_token = null,
3209 .loop_token = token_index,
3210 .opt_ctx = *ctx,
3211 }
3212 }) catch unreachable;
3213 return true;
3214 },
3215 Token.Id.Keyword_switch => {
3216 const node = try arena.construct(ast.Node.Switch {
3217 .base = ast.Node {
3218 .id = ast.Node.Id.Switch,
3219 },
3220 .switch_token = token_index,
3221 .expr = undefined,
3222 .cases = ast.Node.Switch.CaseList.init(arena),
3223 .rbrace = undefined,
3224 });
3225 ctx.store(&node.base);
3226
3227 stack.append(State {
3228 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {
3229 .list = &node.cases,
3230 .ptr = &node.rbrace,
3231 },
3232 }) catch unreachable;
3233 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3234 try stack.append(State { .ExpectToken = Token.Id.RParen });
3235 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3236 try stack.append(State { .ExpectToken = Token.Id.LParen });
3237 return true;
3238 },
3239 Token.Id.Keyword_comptime => {
3240 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,
3241 ast.Node.Comptime {
3242 .base = undefined,
3243 .comptime_token = token_index,
3244 .expr = undefined,
3245 .doc_comments = null,
3246 }
3247 );
3248 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3249 return true;
3250 },
3251 Token.Id.LBrace => {
3252 const block = try arena.construct(ast.Node.Block {
3253 .base = ast.Node {.id = ast.Node.Id.Block },
3254 .label = null,
3255 .lbrace = token_index,
3256 .statements = ast.Node.Block.StatementList.init(arena),
3257 .rbrace = undefined,
3258 });
3259 ctx.store(&block.base);
3260 stack.append(State { .Block = block }) catch unreachable;
3261 return true;
3262 },
3263 else => {
3264 return false;
3265 }
3266 }
3267}
3268
3269const ExpectCommaOrEndResult = union(enum) {
3270 end_token: ?TokenIndex,
3271 parse_error: Error,
3272};
3273
3274fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3275 const token = nextToken(tok_it, tree);
3276 const token_index = token.index;
3277 const token_ptr = token.ptr;
3278 switch (token_ptr.id) {
3279 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},
3280 else => {
3281 if (end == token_ptr.id) {
3282 return ExpectCommaOrEndResult { .end_token = token_index };
3283 }
3284
3285 return ExpectCommaOrEndResult {
3286 .parse_error = Error {
3287 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {
3288 .token = token_index,
3289 .end_id = end,
3290 },
3291 },
3292 };
3293 },
3294 }
3295}
3296
3297fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3298 // TODO: We have to cast all cases because of this:
3299 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3300 return switch (*id) {
3301 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },
3302 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },
3303 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },
3304 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },
3305 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },
3306 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },
3307 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },
3308 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },
3309 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },
3310 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },
3311 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },
3312 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },
3313 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },
3314 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },
3315 else => null,
3316 };
3317}
3318
3319fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3320 return switch (id) {
3321 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3322 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3323 else => null,
3324 };
3325}
3326
3327fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3328 return switch (id) {
3329 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3330 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3331 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3332 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3333 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3334 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3335 else => null,
3336 };
3337}
3338
3339fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3340 return switch (id) {
3341 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3342 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3343 else => null,
3344 };
3345}
3346
3347fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3348 return switch (id) {
3349 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3350 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3351 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3352 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3353 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3354 else => null,
3355 };
3356}
3357
3358fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3359 return switch (id) {
3360 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3361 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3362 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3363 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3364 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3365 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3366 else => null,
3367 };
3368}
3369
3370fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3371 return switch (id) {
3372 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3373 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3374 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3375 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3376 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3377 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3378 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3379 .align_expr = null,
3380 .bit_offset_start_token = null,
3381 .bit_offset_end_token = null,
3382 .const_token = null,
3383 .volatile_token = null,
3384 },
3385 },
3386 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3387 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3388 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3389 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3390 else => null,
3391 };
3392}
3393
3394fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3395 const node = try arena.create(T);
3396 *node = *init_to;
3397 node.base = blk: {
3398 const id = ast.Node.typeToId(T);
3399 break :blk ast.Node {
3400 .id = id,
3401 };
3402 };
3403
3404 return node;
3405}
3406
3407fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3408 const node = try createNode(arena, T, init_to);
3409 opt_ctx.store(&node.base);
3410
3411 return node;
3412}
3413
3414fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3415 return createNode(arena, T,
3416 T {
3417 .base = undefined,
3418 .token = token_index,
3419 }
3420 );
3421}
3422
3423fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
3424 const node = try createLiteral(arena, T, token_index);
3425 opt_ctx.store(&node.base);
3426
3427 return node;
3428}
3429
3430fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3431 const token = nextToken(tok_it, tree);
3432
3433 if (token.ptr.id == id)
3434 return token.index;
3435
3436 putBackToken(tok_it, tree);
3437 return null;
3438}
3439
3440fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedToken {
3441 const result = AnnotatedToken {
3442 .index = tok_it.index,
3443 .ptr = ??tok_it.next(),
3444 };
3445 // possibly skip a following same line token
3446 const token = tok_it.next() ?? return result;
3447 if (token.id != Token.Id.LineComment) {
3448 putBackToken(tok_it, tree);
3449 return result;
3450 }
3451 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3452 if (loc.line != 0) {
3453 putBackToken(tok_it, tree);
3454 }
3455 return result;
3456}
3457
3458fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3459 const prev_tok = ??tok_it.prev();
3460 if (prev_tok.id == Token.Id.LineComment) {
3461 const minus2_tok = tok_it.prev() ?? return;
3462 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);
3463 if (loc.line != 0) {
3464 _ = tok_it.next();
3465 }
3466 }
3467}
3468
3469const RenderAstFrame = struct {
3470 node: &ast.Node,
3471 indent: usize,
3472};
3473
3474pub fn renderAst(allocator: &mem.Allocator, tree: &const ast.Tree, stream: var) !void {
3475 var stack = std.ArrayList(State).init(allocator);
3476 defer stack.deinit();
3477
3478 try stack.append(RenderAstFrame {
3479 .node = &root_node.base,
3480 .indent = 0,
3481 });
3482
3483 while (stack.popOrNull()) |frame| {
3484 {
3485 var i: usize = 0;
3486 while (i < frame.indent) : (i += 1) {
3487 try stream.print(" ");
3488 }
3489 }
3490 try stream.print("{}\n", @tagName(frame.node.id));
3491 var child_i: usize = 0;
3492 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3493 try stack.append(RenderAstFrame {
3494 .node = child,
3495 .indent = frame.indent + 2,
3496 });
3497 }
3498 }
3499}
3500
3501test "std.zig.parser" {
3502 _ = @import("parser_test.zig");
3503}
std/zig/parser.zig deleted-4729
...@@ -1,4729 +0,0 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Tokenizer = std.zig.Tokenizer;
7const Token = std.zig.Token;
8const builtin = @import("builtin");
9const io = std.io;
10
11// TODO when we make parse errors into error types instead of printing directly,
12// get rid of this
13const warn = std.debug.warn;
14
15pub const Parser = struct {
16 util_allocator: &mem.Allocator,
17 tokenizer: &Tokenizer,
18 put_back_tokens: [2]Token,
19 put_back_count: usize,
20 source_file_name: []const u8,
21
22 pub const Tree = struct {
23 root_node: &ast.Node.Root,
24 arena_allocator: std.heap.ArenaAllocator,
25
26 pub fn deinit(self: &Tree) void {
27 self.arena_allocator.deinit();
28 }
29 };
30
31 // This memory contents are used only during a function call. It's used to repurpose memory;
32 // we reuse the same bytes for the stack data structure used by parsing, tree rendering, and
33 // source rendering.
34 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );
35 utility_bytes: []align(utility_bytes_align) u8,
36
37 /// allocator must outlive the returned Parser and all the parse trees you create with it.
38 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser {
39 return Parser {
40 .util_allocator = allocator,
41 .tokenizer = tokenizer,
42 .put_back_tokens = undefined,
43 .put_back_count = 0,
44 .source_file_name = source_file_name,
45 .utility_bytes = []align(utility_bytes_align) u8{},
46 };
47 }
48
49 pub fn deinit(self: &Parser) void {
50 self.util_allocator.free(self.utility_bytes);
51 }
52
53 const TopLevelDeclCtx = struct {
54 decls: &ArrayList(&ast.Node),
55 visib_token: ?Token,
56 extern_export_inline_token: ?Token,
57 lib_name: ?&ast.Node,
58 comments: ?&ast.Node.DocComment,
59 };
60
61 const VarDeclCtx = struct {
62 mut_token: Token,
63 visib_token: ?Token,
64 comptime_token: ?Token,
65 extern_export_token: ?Token,
66 lib_name: ?&ast.Node,
67 list: &ArrayList(&ast.Node),
68 comments: ?&ast.Node.DocComment,
69 };
70
71 const TopLevelExternOrFieldCtx = struct {
72 visib_token: Token,
73 container_decl: &ast.Node.ContainerDecl,
74 comments: ?&ast.Node.DocComment,
75 };
76
77 const ExternTypeCtx = struct {
78 opt_ctx: OptionalCtx,
79 extern_token: Token,
80 comments: ?&ast.Node.DocComment,
81 };
82
83 const ContainerKindCtx = struct {
84 opt_ctx: OptionalCtx,
85 ltoken: Token,
86 layout: ast.Node.ContainerDecl.Layout,
87 };
88
89 const ExpectTokenSave = struct {
90 id: Token.Id,
91 ptr: &Token,
92 };
93
94 const OptionalTokenSave = struct {
95 id: Token.Id,
96 ptr: &?Token,
97 };
98
99 const ExprListCtx = struct {
100 list: &ArrayList(&ast.Node),
101 end: Token.Id,
102 ptr: &Token,
103 };
104
105 fn ListSave(comptime T: type) type {
106 return struct {
107 list: &ArrayList(T),
108 ptr: &Token,
109 };
110 }
111
112 const MaybeLabeledExpressionCtx = struct {
113 label: Token,
114 opt_ctx: OptionalCtx,
115 };
116
117 const LabelCtx = struct {
118 label: ?Token,
119 opt_ctx: OptionalCtx,
120 };
121
122 const InlineCtx = struct {
123 label: ?Token,
124 inline_token: ?Token,
125 opt_ctx: OptionalCtx,
126 };
127
128 const LoopCtx = struct {
129 label: ?Token,
130 inline_token: ?Token,
131 loop_token: Token,
132 opt_ctx: OptionalCtx,
133 };
134
135 const AsyncEndCtx = struct {
136 ctx: OptionalCtx,
137 attribute: &ast.Node.AsyncAttribute,
138 };
139
140 const ErrorTypeOrSetDeclCtx = struct {
141 opt_ctx: OptionalCtx,
142 error_token: Token,
143 };
144
145 const ParamDeclEndCtx = struct {
146 fn_proto: &ast.Node.FnProto,
147 param_decl: &ast.Node.ParamDecl,
148 };
149
150 const ComptimeStatementCtx = struct {
151 comptime_token: Token,
152 block: &ast.Node.Block,
153 };
154
155 const OptionalCtx = union(enum) {
156 Optional: &?&ast.Node,
157 RequiredNull: &?&ast.Node,
158 Required: &&ast.Node,
159
160 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
161 switch (*self) {
162 OptionalCtx.Optional => |ptr| *ptr = value,
163 OptionalCtx.RequiredNull => |ptr| *ptr = value,
164 OptionalCtx.Required => |ptr| *ptr = value,
165 }
166 }
167
168 pub fn get(self: &const OptionalCtx) ?&ast.Node {
169 switch (*self) {
170 OptionalCtx.Optional => |ptr| return *ptr,
171 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
172 OptionalCtx.Required => |ptr| return *ptr,
173 }
174 }
175
176 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
177 switch (*self) {
178 OptionalCtx.Optional => |ptr| {
179 return OptionalCtx { .RequiredNull = ptr };
180 },
181 OptionalCtx.RequiredNull => |ptr| return *self,
182 OptionalCtx.Required => |ptr| return *self,
183 }
184 }
185 };
186
187 const AddCommentsCtx = struct {
188 node_ptr: &&ast.Node,
189 comments: ?&ast.Node.DocComment,
190 };
191
192 const State = union(enum) {
193 TopLevel,
194 TopLevelExtern: TopLevelDeclCtx,
195 TopLevelLibname: TopLevelDeclCtx,
196 TopLevelDecl: TopLevelDeclCtx,
197 TopLevelExternOrField: TopLevelExternOrFieldCtx,
198
199 ContainerKind: ContainerKindCtx,
200 ContainerInitArgStart: &ast.Node.ContainerDecl,
201 ContainerInitArg: &ast.Node.ContainerDecl,
202 ContainerDecl: &ast.Node.ContainerDecl,
203
204 VarDecl: VarDeclCtx,
205 VarDeclAlign: &ast.Node.VarDecl,
206 VarDeclEq: &ast.Node.VarDecl,
207
208 FnDef: &ast.Node.FnProto,
209 FnProto: &ast.Node.FnProto,
210 FnProtoAlign: &ast.Node.FnProto,
211 FnProtoReturnType: &ast.Node.FnProto,
212
213 ParamDecl: &ast.Node.FnProto,
214 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
215 ParamDeclName: &ast.Node.ParamDecl,
216 ParamDeclEnd: ParamDeclEndCtx,
217 ParamDeclComma: &ast.Node.FnProto,
218
219 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
220 LabeledExpression: LabelCtx,
221 Inline: InlineCtx,
222 While: LoopCtx,
223 WhileContinueExpr: &?&ast.Node,
224 For: LoopCtx,
225 Else: &?&ast.Node.Else,
226
227 Block: &ast.Node.Block,
228 Statement: &ast.Node.Block,
229 ComptimeStatement: ComptimeStatementCtx,
230 Semicolon: &&ast.Node,
231 LookForSameLineComment: &&ast.Node,
232 LookForSameLineCommentDirect: &ast.Node,
233
234 AsmOutputItems: &ArrayList(&ast.Node.AsmOutput),
235 AsmOutputReturnOrType: &ast.Node.AsmOutput,
236 AsmInputItems: &ArrayList(&ast.Node.AsmInput),
237 AsmClopperItems: &ArrayList(&ast.Node),
238
239 ExprListItemOrEnd: ExprListCtx,
240 ExprListCommaOrEnd: ExprListCtx,
241 FieldInitListItemOrEnd: ListSave(&ast.Node),
242 FieldInitListCommaOrEnd: ListSave(&ast.Node),
243 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
244 FieldInitValue: OptionalCtx,
245 ErrorTagListItemOrEnd: ListSave(&ast.Node),
246 ErrorTagListCommaOrEnd: ListSave(&ast.Node),
247 SwitchCaseOrEnd: ListSave(&ast.Node),
248 SwitchCaseCommaOrEnd: ListSave(&ast.Node),
249 SwitchCaseFirstItem: &ArrayList(&ast.Node),
250 SwitchCaseItem: &ArrayList(&ast.Node),
251 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
252
253 SuspendBody: &ast.Node.Suspend,
254 AsyncAllocator: &ast.Node.AsyncAttribute,
255 AsyncEnd: AsyncEndCtx,
256
257 ExternType: ExternTypeCtx,
258 SliceOrArrayAccess: &ast.Node.SuffixOp,
259 SliceOrArrayType: &ast.Node.PrefixOp,
260 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
261
262 Payload: OptionalCtx,
263 PointerPayload: OptionalCtx,
264 PointerIndexPayload: OptionalCtx,
265
266 Expression: OptionalCtx,
267 RangeExpressionBegin: OptionalCtx,
268 RangeExpressionEnd: OptionalCtx,
269 AssignmentExpressionBegin: OptionalCtx,
270 AssignmentExpressionEnd: OptionalCtx,
271 UnwrapExpressionBegin: OptionalCtx,
272 UnwrapExpressionEnd: OptionalCtx,
273 BoolOrExpressionBegin: OptionalCtx,
274 BoolOrExpressionEnd: OptionalCtx,
275 BoolAndExpressionBegin: OptionalCtx,
276 BoolAndExpressionEnd: OptionalCtx,
277 ComparisonExpressionBegin: OptionalCtx,
278 ComparisonExpressionEnd: OptionalCtx,
279 BinaryOrExpressionBegin: OptionalCtx,
280 BinaryOrExpressionEnd: OptionalCtx,
281 BinaryXorExpressionBegin: OptionalCtx,
282 BinaryXorExpressionEnd: OptionalCtx,
283 BinaryAndExpressionBegin: OptionalCtx,
284 BinaryAndExpressionEnd: OptionalCtx,
285 BitShiftExpressionBegin: OptionalCtx,
286 BitShiftExpressionEnd: OptionalCtx,
287 AdditionExpressionBegin: OptionalCtx,
288 AdditionExpressionEnd: OptionalCtx,
289 MultiplyExpressionBegin: OptionalCtx,
290 MultiplyExpressionEnd: OptionalCtx,
291 CurlySuffixExpressionBegin: OptionalCtx,
292 CurlySuffixExpressionEnd: OptionalCtx,
293 TypeExprBegin: OptionalCtx,
294 TypeExprEnd: OptionalCtx,
295 PrefixOpExpression: OptionalCtx,
296 SuffixOpExpressionBegin: OptionalCtx,
297 SuffixOpExpressionEnd: OptionalCtx,
298 PrimaryExpression: OptionalCtx,
299
300 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
301 StringLiteral: OptionalCtx,
302 Identifier: OptionalCtx,
303 ErrorTag: &&ast.Node,
304
305
306 IfToken: @TagType(Token.Id),
307 IfTokenSave: ExpectTokenSave,
308 ExpectToken: @TagType(Token.Id),
309 ExpectTokenSave: ExpectTokenSave,
310 OptionalTokenSave: OptionalTokenSave,
311 };
312
313 /// Returns an AST tree, allocated with the parser's allocator.
314 /// Result should be freed with tree.deinit() when there are
315 /// no more references to any AST nodes of the tree.
316 pub fn parse(self: &Parser) !Tree {
317 var stack = self.initUtilityArrayList(State);
318 defer self.deinitUtilityArrayList(stack);
319
320 var arena_allocator = std.heap.ArenaAllocator.init(self.util_allocator);
321 errdefer arena_allocator.deinit();
322
323 const arena = &arena_allocator.allocator;
324 const root_node = try self.createNode(arena, ast.Node.Root,
325 ast.Node.Root {
326 .base = undefined,
327 .decls = ArrayList(&ast.Node).init(arena),
328 .doc_comments = null,
329 // initialized when we get the eof token
330 .eof_token = undefined,
331 }
332 );
333
334 try stack.append(State.TopLevel);
335
336 while (true) {
337 //{
338 // const token = self.getNextToken();
339 // warn("{} ", @tagName(token.id));
340 // self.putBackToken(token);
341 // var i: usize = stack.len;
342 // while (i != 0) {
343 // i -= 1;
344 // warn("{} ", @tagName(stack.items[i]));
345 // }
346 // warn("\n");
347 //}
348
349 // This gives us 1 free append that can't fail
350 const state = stack.pop();
351
352 switch (state) {
353 State.TopLevel => {
354 while (try self.eatLineComment(arena)) |line_comment| {
355 try root_node.decls.append(&line_comment.base);
356 }
357
358 const comments = try self.eatDocComments(arena);
359 const token = self.getNextToken();
360 switch (token.id) {
361 Token.Id.Keyword_test => {
362 stack.append(State.TopLevel) catch unreachable;
363
364 const block = try arena.construct(ast.Node.Block {
365 .base = ast.Node {
366 .id = ast.Node.Id.Block,
367 .same_line_comment = null,
368 },
369 .label = null,
370 .lbrace = undefined,
371 .statements = ArrayList(&ast.Node).init(arena),
372 .rbrace = undefined,
373 });
374 const test_node = try arena.construct(ast.Node.TestDecl {
375 .base = ast.Node {
376 .id = ast.Node.Id.TestDecl,
377 .same_line_comment = null,
378 },
379 .doc_comments = comments,
380 .test_token = token,
381 .name = undefined,
382 .body_node = &block.base,
383 });
384 try root_node.decls.append(&test_node.base);
385 try stack.append(State { .Block = block });
386 try stack.append(State {
387 .ExpectTokenSave = ExpectTokenSave {
388 .id = Token.Id.LBrace,
389 .ptr = &block.rbrace,
390 }
391 });
392 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
393 continue;
394 },
395 Token.Id.Eof => {
396 root_node.eof_token = token;
397 root_node.doc_comments = comments;
398 return Tree {
399 .root_node = root_node,
400 .arena_allocator = arena_allocator,
401 };
402 },
403 Token.Id.Keyword_pub => {
404 stack.append(State.TopLevel) catch unreachable;
405 try stack.append(State {
406 .TopLevelExtern = TopLevelDeclCtx {
407 .decls = &root_node.decls,
408 .visib_token = token,
409 .extern_export_inline_token = null,
410 .lib_name = null,
411 .comments = comments,
412 }
413 });
414 continue;
415 },
416 Token.Id.Keyword_comptime => {
417 const block = try self.createNode(arena, ast.Node.Block,
418 ast.Node.Block {
419 .base = undefined,
420 .label = null,
421 .lbrace = undefined,
422 .statements = ArrayList(&ast.Node).init(arena),
423 .rbrace = undefined,
424 }
425 );
426 const node = try self.createAttachNode(arena, &root_node.decls, ast.Node.Comptime,
427 ast.Node.Comptime {
428 .base = undefined,
429 .comptime_token = token,
430 .expr = &block.base,
431 .doc_comments = comments,
432 }
433 );
434 stack.append(State.TopLevel) catch unreachable;
435 try stack.append(State { .Block = block });
436 try stack.append(State {
437 .ExpectTokenSave = ExpectTokenSave {
438 .id = Token.Id.LBrace,
439 .ptr = &block.rbrace,
440 }
441 });
442 continue;
443 },
444 else => {
445 self.putBackToken(token);
446 stack.append(State.TopLevel) catch unreachable;
447 try stack.append(State {
448 .TopLevelExtern = TopLevelDeclCtx {
449 .decls = &root_node.decls,
450 .visib_token = null,
451 .extern_export_inline_token = null,
452 .lib_name = null,
453 .comments = comments,
454 }
455 });
456 continue;
457 },
458 }
459 },
460 State.TopLevelExtern => |ctx| {
461 const token = self.getNextToken();
462 switch (token.id) {
463 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
464 stack.append(State {
465 .TopLevelDecl = TopLevelDeclCtx {
466 .decls = ctx.decls,
467 .visib_token = ctx.visib_token,
468 .extern_export_inline_token = token,
469 .lib_name = null,
470 .comments = ctx.comments,
471 },
472 }) catch unreachable;
473 continue;
474 },
475 Token.Id.Keyword_extern => {
476 stack.append(State {
477 .TopLevelLibname = TopLevelDeclCtx {
478 .decls = ctx.decls,
479 .visib_token = ctx.visib_token,
480 .extern_export_inline_token = token,
481 .lib_name = null,
482 .comments = ctx.comments,
483 },
484 }) catch unreachable;
485 continue;
486 },
487 else => {
488 self.putBackToken(token);
489 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
490 continue;
491 }
492 }
493 },
494 State.TopLevelLibname => |ctx| {
495 const lib_name = blk: {
496 const lib_name_token = self.getNextToken();
497 break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? {
498 self.putBackToken(lib_name_token);
499 break :blk null;
500 };
501 };
502
503 stack.append(State {
504 .TopLevelDecl = TopLevelDeclCtx {
505 .decls = ctx.decls,
506 .visib_token = ctx.visib_token,
507 .extern_export_inline_token = ctx.extern_export_inline_token,
508 .lib_name = lib_name,
509 .comments = ctx.comments,
510 },
511 }) catch unreachable;
512 continue;
513 },
514 State.TopLevelDecl => |ctx| {
515 const token = self.getNextToken();
516 switch (token.id) {
517 Token.Id.Keyword_use => {
518 if (ctx.extern_export_inline_token != null) {
519 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
520 }
521
522 const node = try self.createAttachNode(arena, ctx.decls, ast.Node.Use,
523 ast.Node.Use {
524 .base = undefined,
525 .visib_token = ctx.visib_token,
526 .expr = undefined,
527 .semicolon_token = undefined,
528 .doc_comments = ctx.comments,
529 }
530 );
531 stack.append(State {
532 .ExpectTokenSave = ExpectTokenSave {
533 .id = Token.Id.Semicolon,
534 .ptr = &node.semicolon_token,
535 }
536 }) catch unreachable;
537 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
538 continue;
539 },
540 Token.Id.Keyword_var, Token.Id.Keyword_const => {
541 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
542 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
543 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
544 }
545 }
546
547 try stack.append(State {
548 .VarDecl = VarDeclCtx {
549 .comments = ctx.comments,
550 .visib_token = ctx.visib_token,
551 .lib_name = ctx.lib_name,
552 .comptime_token = null,
553 .extern_export_token = ctx.extern_export_inline_token,
554 .mut_token = token,
555 .list = ctx.decls
556 }
557 });
558 continue;
559 },
560 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
561 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
562 const fn_proto = try arena.construct(ast.Node.FnProto {
563 .base = ast.Node {
564 .id = ast.Node.Id.FnProto,
565 .same_line_comment = null,
566 },
567 .doc_comments = ctx.comments,
568 .visib_token = ctx.visib_token,
569 .name_token = null,
570 .fn_token = undefined,
571 .params = ArrayList(&ast.Node).init(arena),
572 .return_type = undefined,
573 .var_args_token = null,
574 .extern_export_inline_token = ctx.extern_export_inline_token,
575 .cc_token = null,
576 .async_attr = null,
577 .body_node = null,
578 .lib_name = ctx.lib_name,
579 .align_expr = null,
580 });
581 try ctx.decls.append(&fn_proto.base);
582 stack.append(State { .FnDef = fn_proto }) catch unreachable;
583 try stack.append(State { .FnProto = fn_proto });
584
585 switch (token.id) {
586 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
587 fn_proto.cc_token = token;
588 try stack.append(State {
589 .ExpectTokenSave = ExpectTokenSave {
590 .id = Token.Id.Keyword_fn,
591 .ptr = &fn_proto.fn_token,
592 }
593 });
594 continue;
595 },
596 Token.Id.Keyword_async => {
597 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
598 ast.Node.AsyncAttribute {
599 .base = undefined,
600 .async_token = token,
601 .allocator_type = null,
602 .rangle_bracket = null,
603 }
604 );
605 fn_proto.async_attr = async_node;
606
607 try stack.append(State {
608 .ExpectTokenSave = ExpectTokenSave {
609 .id = Token.Id.Keyword_fn,
610 .ptr = &fn_proto.fn_token,
611 }
612 });
613 try stack.append(State { .AsyncAllocator = async_node });
614 continue;
615 },
616 Token.Id.Keyword_fn => {
617 fn_proto.fn_token = token;
618 continue;
619 },
620 else => unreachable,
621 }
622 },
623 else => {
624 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
625 },
626 }
627 },
628 State.TopLevelExternOrField => |ctx| {
629 if (self.eatToken(Token.Id.Identifier)) |identifier| {
630 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
631 const node = try arena.construct(ast.Node.StructField {
632 .base = ast.Node {
633 .id = ast.Node.Id.StructField,
634 .same_line_comment = null,
635 },
636 .doc_comments = ctx.comments,
637 .visib_token = ctx.visib_token,
638 .name_token = identifier,
639 .type_expr = undefined,
640 });
641 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
642 *node_ptr = &node.base;
643
644 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
645 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
646 try stack.append(State { .ExpectToken = Token.Id.Colon });
647 continue;
648 }
649
650 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
651 try stack.append(State {
652 .TopLevelExtern = TopLevelDeclCtx {
653 .decls = &ctx.container_decl.fields_and_decls,
654 .visib_token = ctx.visib_token,
655 .extern_export_inline_token = null,
656 .lib_name = null,
657 .comments = ctx.comments,
658 }
659 });
660 continue;
661 },
662
663 State.FieldInitValue => |ctx| {
664 const eq_tok = self.getNextToken();
665 if (eq_tok.id != Token.Id.Equal) {
666 self.putBackToken(eq_tok);
667 continue;
668 }
669 stack.append(State { .Expression = ctx }) catch unreachable;
670 continue;
671 },
672
673 State.ContainerKind => |ctx| {
674 const token = self.getNextToken();
675 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
676 ast.Node.ContainerDecl {
677 .base = undefined,
678 .ltoken = ctx.ltoken,
679 .layout = ctx.layout,
680 .kind = switch (token.id) {
681 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
682 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
683 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
684 else => {
685 return self.parseError(token, "expected {}, {} or {}, found {}",
686 @tagName(Token.Id.Keyword_struct),
687 @tagName(Token.Id.Keyword_union),
688 @tagName(Token.Id.Keyword_enum),
689 @tagName(token.id));
690 },
691 },
692 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
693 .fields_and_decls = ArrayList(&ast.Node).init(arena),
694 .rbrace_token = undefined,
695 }
696 );
697
698 stack.append(State { .ContainerDecl = node }) catch unreachable;
699 try stack.append(State { .ExpectToken = Token.Id.LBrace });
700 try stack.append(State { .ContainerInitArgStart = node });
701 continue;
702 },
703
704 State.ContainerInitArgStart => |container_decl| {
705 if (self.eatToken(Token.Id.LParen) == null) {
706 continue;
707 }
708
709 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
710 try stack.append(State { .ContainerInitArg = container_decl });
711 continue;
712 },
713
714 State.ContainerInitArg => |container_decl| {
715 const init_arg_token = self.getNextToken();
716 switch (init_arg_token.id) {
717 Token.Id.Keyword_enum => {
718 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
719 const lparen_tok = self.getNextToken();
720 if (lparen_tok.id == Token.Id.LParen) {
721 try stack.append(State { .ExpectToken = Token.Id.RParen } );
722 try stack.append(State { .Expression = OptionalCtx {
723 .RequiredNull = &container_decl.init_arg_expr.Enum,
724 } });
725 } else {
726 self.putBackToken(lparen_tok);
727 }
728 },
729 else => {
730 self.putBackToken(init_arg_token);
731 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
732 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
733 },
734 }
735 continue;
736 },
737
738 State.ContainerDecl => |container_decl| {
739 while (try self.eatLineComment(arena)) |line_comment| {
740 try container_decl.fields_and_decls.append(&line_comment.base);
741 }
742
743 const comments = try self.eatDocComments(arena);
744 const token = self.getNextToken();
745 switch (token.id) {
746 Token.Id.Identifier => {
747 switch (container_decl.kind) {
748 ast.Node.ContainerDecl.Kind.Struct => {
749 const node = try arena.construct(ast.Node.StructField {
750 .base = ast.Node {
751 .id = ast.Node.Id.StructField,
752 .same_line_comment = null,
753 },
754 .doc_comments = comments,
755 .visib_token = null,
756 .name_token = token,
757 .type_expr = undefined,
758 });
759 const node_ptr = try container_decl.fields_and_decls.addOne();
760 *node_ptr = &node.base;
761
762 try stack.append(State { .FieldListCommaOrEnd = container_decl });
763 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
764 try stack.append(State { .ExpectToken = Token.Id.Colon });
765 continue;
766 },
767 ast.Node.ContainerDecl.Kind.Union => {
768 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.UnionTag,
769 ast.Node.UnionTag {
770 .base = undefined,
771 .name_token = token,
772 .type_expr = null,
773 .value_expr = null,
774 .doc_comments = comments,
775 }
776 );
777
778 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
779 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
780 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
781 try stack.append(State { .IfToken = Token.Id.Colon });
782 continue;
783 },
784 ast.Node.ContainerDecl.Kind.Enum => {
785 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.EnumTag,
786 ast.Node.EnumTag {
787 .base = undefined,
788 .name_token = token,
789 .value = null,
790 .doc_comments = comments,
791 }
792 );
793
794 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
795 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
796 try stack.append(State { .IfToken = Token.Id.Equal });
797 continue;
798 },
799 }
800 },
801 Token.Id.Keyword_pub => {
802 switch (container_decl.kind) {
803 ast.Node.ContainerDecl.Kind.Struct => {
804 try stack.append(State {
805 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
806 .visib_token = token,
807 .container_decl = container_decl,
808 .comments = comments,
809 }
810 });
811 continue;
812 },
813 else => {
814 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
815 try stack.append(State {
816 .TopLevelExtern = TopLevelDeclCtx {
817 .decls = &container_decl.fields_and_decls,
818 .visib_token = token,
819 .extern_export_inline_token = null,
820 .lib_name = null,
821 .comments = comments,
822 }
823 });
824 continue;
825 }
826 }
827 },
828 Token.Id.Keyword_export => {
829 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
830 try stack.append(State {
831 .TopLevelExtern = TopLevelDeclCtx {
832 .decls = &container_decl.fields_and_decls,
833 .visib_token = token,
834 .extern_export_inline_token = null,
835 .lib_name = null,
836 .comments = comments,
837 }
838 });
839 continue;
840 },
841 Token.Id.RBrace => {
842 if (comments != null) {
843 return self.parseError(token, "doc comments must be attached to a node");
844 }
845 container_decl.rbrace_token = token;
846 continue;
847 },
848 else => {
849 self.putBackToken(token);
850 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
851 try stack.append(State {
852 .TopLevelExtern = TopLevelDeclCtx {
853 .decls = &container_decl.fields_and_decls,
854 .visib_token = null,
855 .extern_export_inline_token = null,
856 .lib_name = null,
857 .comments = comments,
858 }
859 });
860 continue;
861 }
862 }
863 },
864
865
866 State.VarDecl => |ctx| {
867 const var_decl = try arena.construct(ast.Node.VarDecl {
868 .base = ast.Node {
869 .id = ast.Node.Id.VarDecl,
870 .same_line_comment = null,
871 },
872 .doc_comments = ctx.comments,
873 .visib_token = ctx.visib_token,
874 .mut_token = ctx.mut_token,
875 .comptime_token = ctx.comptime_token,
876 .extern_export_token = ctx.extern_export_token,
877 .type_node = null,
878 .align_node = null,
879 .init_node = null,
880 .lib_name = ctx.lib_name,
881 // initialized later
882 .name_token = undefined,
883 .eq_token = undefined,
884 .semicolon_token = undefined,
885 });
886 try ctx.list.append(&var_decl.base);
887
888 try stack.append(State { .LookForSameLineCommentDirect = &var_decl.base });
889 try stack.append(State { .VarDeclAlign = var_decl });
890 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
891 try stack.append(State { .IfToken = Token.Id.Colon });
892 try stack.append(State {
893 .ExpectTokenSave = ExpectTokenSave {
894 .id = Token.Id.Identifier,
895 .ptr = &var_decl.name_token,
896 }
897 });
898 continue;
899 },
900 State.VarDeclAlign => |var_decl| {
901 try stack.append(State { .VarDeclEq = var_decl });
902
903 const next_token = self.getNextToken();
904 if (next_token.id == Token.Id.Keyword_align) {
905 try stack.append(State { .ExpectToken = Token.Id.RParen });
906 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
907 try stack.append(State { .ExpectToken = Token.Id.LParen });
908 continue;
909 }
910
911 self.putBackToken(next_token);
912 continue;
913 },
914 State.VarDeclEq => |var_decl| {
915 const token = self.getNextToken();
916 switch (token.id) {
917 Token.Id.Equal => {
918 var_decl.eq_token = token;
919 stack.append(State {
920 .ExpectTokenSave = ExpectTokenSave {
921 .id = Token.Id.Semicolon,
922 .ptr = &var_decl.semicolon_token,
923 },
924 }) catch unreachable;
925 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
926 continue;
927 },
928 Token.Id.Semicolon => {
929 var_decl.semicolon_token = token;
930 continue;
931 },
932 else => {
933 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
934 }
935 }
936 },
937
938
939 State.FnDef => |fn_proto| {
940 const token = self.getNextToken();
941 switch(token.id) {
942 Token.Id.LBrace => {
943 const block = try self.createNode(arena, ast.Node.Block,
944 ast.Node.Block {
945 .base = undefined,
946 .label = null,
947 .lbrace = token,
948 .statements = ArrayList(&ast.Node).init(arena),
949 .rbrace = undefined,
950 }
951 );
952 fn_proto.body_node = &block.base;
953 stack.append(State { .Block = block }) catch unreachable;
954 continue;
955 },
956 Token.Id.Semicolon => continue,
957 else => {
958 return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
959 },
960 }
961 },
962 State.FnProto => |fn_proto| {
963 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
964 try stack.append(State { .ParamDecl = fn_proto });
965 try stack.append(State { .ExpectToken = Token.Id.LParen });
966
967 if (self.eatToken(Token.Id.Identifier)) |name_token| {
968 fn_proto.name_token = name_token;
969 }
970 continue;
971 },
972 State.FnProtoAlign => |fn_proto| {
973 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
974
975 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
976 try stack.append(State { .ExpectToken = Token.Id.RParen });
977 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
978 try stack.append(State { .ExpectToken = Token.Id.LParen });
979 }
980 continue;
981 },
982 State.FnProtoReturnType => |fn_proto| {
983 const token = self.getNextToken();
984 switch (token.id) {
985 Token.Id.Bang => {
986 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
987 stack.append(State {
988 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
989 }) catch unreachable;
990 continue;
991 },
992 else => {
993 // TODO: this is a special case. Remove this when #760 is fixed
994 if (token.id == Token.Id.Keyword_error) {
995 if (self.isPeekToken(Token.Id.LBrace)) {
996 fn_proto.return_type = ast.Node.FnProto.ReturnType {
997 .Explicit = &(try self.createLiteral(arena, ast.Node.ErrorType, token)).base
998 };
999 continue;
1000 }
1001 }
1002
1003 self.putBackToken(token);
1004 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
1005 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
1006 continue;
1007 },
1008 }
1009 },
1010
1011
1012 State.ParamDecl => |fn_proto| {
1013 if (self.eatToken(Token.Id.RParen)) |_| {
1014 continue;
1015 }
1016 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.Node.ParamDecl,
1017 ast.Node.ParamDecl {
1018 .base = undefined,
1019 .comptime_token = null,
1020 .noalias_token = null,
1021 .name_token = null,
1022 .type_node = undefined,
1023 .var_args_token = null,
1024 },
1025 );
1026
1027 stack.append(State {
1028 .ParamDeclEnd = ParamDeclEndCtx {
1029 .param_decl = param_decl,
1030 .fn_proto = fn_proto,
1031 }
1032 }) catch unreachable;
1033 try stack.append(State { .ParamDeclName = param_decl });
1034 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
1035 continue;
1036 },
1037 State.ParamDeclAliasOrComptime => |param_decl| {
1038 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
1039 param_decl.comptime_token = comptime_token;
1040 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
1041 param_decl.noalias_token = noalias_token;
1042 }
1043 continue;
1044 },
1045 State.ParamDeclName => |param_decl| {
1046 // TODO: Here, we eat two tokens in one state. This means that we can't have
1047 // comments between these two tokens.
1048 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
1049 if (self.eatToken(Token.Id.Colon)) |_| {
1050 param_decl.name_token = ident_token;
1051 } else {
1052 self.putBackToken(ident_token);
1053 }
1054 }
1055 continue;
1056 },
1057 State.ParamDeclEnd => |ctx| {
1058 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1059 ctx.param_decl.var_args_token = ellipsis3;
1060 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1061 continue;
1062 }
1063
1064 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
1065 try stack.append(State {
1066 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
1067 });
1068 continue;
1069 },
1070 State.ParamDeclComma => |fn_proto| {
1071 if ((try self.expectCommaOrEnd(Token.Id.RParen)) == null) {
1072 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
1073 }
1074 continue;
1075 },
1076
1077 State.MaybeLabeledExpression => |ctx| {
1078 if (self.eatToken(Token.Id.Colon)) |_| {
1079 stack.append(State {
1080 .LabeledExpression = LabelCtx {
1081 .label = ctx.label,
1082 .opt_ctx = ctx.opt_ctx,
1083 }
1084 }) catch unreachable;
1085 continue;
1086 }
1087
1088 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
1089 continue;
1090 },
1091 State.LabeledExpression => |ctx| {
1092 const token = self.getNextToken();
1093 switch (token.id) {
1094 Token.Id.LBrace => {
1095 const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
1096 ast.Node.Block {
1097 .base = undefined,
1098 .label = ctx.label,
1099 .lbrace = token,
1100 .statements = ArrayList(&ast.Node).init(arena),
1101 .rbrace = undefined,
1102 }
1103 );
1104 stack.append(State { .Block = block }) catch unreachable;
1105 continue;
1106 },
1107 Token.Id.Keyword_while => {
1108 stack.append(State {
1109 .While = LoopCtx {
1110 .label = ctx.label,
1111 .inline_token = null,
1112 .loop_token = token,
1113 .opt_ctx = ctx.opt_ctx.toRequired(),
1114 }
1115 }) catch unreachable;
1116 continue;
1117 },
1118 Token.Id.Keyword_for => {
1119 stack.append(State {
1120 .For = LoopCtx {
1121 .label = ctx.label,
1122 .inline_token = null,
1123 .loop_token = token,
1124 .opt_ctx = ctx.opt_ctx.toRequired(),
1125 }
1126 }) catch unreachable;
1127 continue;
1128 },
1129 Token.Id.Keyword_suspend => {
1130 const node = try arena.construct(ast.Node.Suspend {
1131 .base = ast.Node {
1132 .id = ast.Node.Id.Suspend,
1133 .same_line_comment = null,
1134 },
1135 .label = ctx.label,
1136 .suspend_token = token,
1137 .payload = null,
1138 .body = null,
1139 });
1140 ctx.opt_ctx.store(&node.base);
1141 stack.append(State { .SuspendBody = node }) catch unreachable;
1142 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1143 continue;
1144 },
1145 Token.Id.Keyword_inline => {
1146 stack.append(State {
1147 .Inline = InlineCtx {
1148 .label = ctx.label,
1149 .inline_token = token,
1150 .opt_ctx = ctx.opt_ctx.toRequired(),
1151 }
1152 }) catch unreachable;
1153 continue;
1154 },
1155 else => {
1156 if (ctx.opt_ctx != OptionalCtx.Optional) {
1157 return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
1158 }
1159
1160 self.putBackToken(token);
1161 continue;
1162 },
1163 }
1164 },
1165 State.Inline => |ctx| {
1166 const token = self.getNextToken();
1167 switch (token.id) {
1168 Token.Id.Keyword_while => {
1169 stack.append(State {
1170 .While = LoopCtx {
1171 .inline_token = ctx.inline_token,
1172 .label = ctx.label,
1173 .loop_token = token,
1174 .opt_ctx = ctx.opt_ctx.toRequired(),
1175 }
1176 }) catch unreachable;
1177 continue;
1178 },
1179 Token.Id.Keyword_for => {
1180 stack.append(State {
1181 .For = LoopCtx {
1182 .inline_token = ctx.inline_token,
1183 .label = ctx.label,
1184 .loop_token = token,
1185 .opt_ctx = ctx.opt_ctx.toRequired(),
1186 }
1187 }) catch unreachable;
1188 continue;
1189 },
1190 else => {
1191 if (ctx.opt_ctx != OptionalCtx.Optional) {
1192 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1193 }
1194
1195 self.putBackToken(token);
1196 continue;
1197 },
1198 }
1199 },
1200 State.While => |ctx| {
1201 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
1202 ast.Node.While {
1203 .base = undefined,
1204 .label = ctx.label,
1205 .inline_token = ctx.inline_token,
1206 .while_token = ctx.loop_token,
1207 .condition = undefined,
1208 .payload = null,
1209 .continue_expr = null,
1210 .body = undefined,
1211 .@"else" = null,
1212 }
1213 );
1214 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1215 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1216 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
1217 try stack.append(State { .IfToken = Token.Id.Colon });
1218 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1219 try stack.append(State { .ExpectToken = Token.Id.RParen });
1220 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
1221 try stack.append(State { .ExpectToken = Token.Id.LParen });
1222 continue;
1223 },
1224 State.WhileContinueExpr => |dest| {
1225 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1226 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
1227 try stack.append(State { .ExpectToken = Token.Id.LParen });
1228 continue;
1229 },
1230 State.For => |ctx| {
1231 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
1232 ast.Node.For {
1233 .base = undefined,
1234 .label = ctx.label,
1235 .inline_token = ctx.inline_token,
1236 .for_token = ctx.loop_token,
1237 .array_expr = undefined,
1238 .payload = null,
1239 .body = undefined,
1240 .@"else" = null,
1241 }
1242 );
1243 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1244 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1245 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1246 try stack.append(State { .ExpectToken = Token.Id.RParen });
1247 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1248 try stack.append(State { .ExpectToken = Token.Id.LParen });
1249 continue;
1250 },
1251 State.Else => |dest| {
1252 if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
1253 const node = try self.createNode(arena, ast.Node.Else,
1254 ast.Node.Else {
1255 .base = undefined,
1256 .else_token = else_token,
1257 .payload = null,
1258 .body = undefined,
1259 }
1260 );
1261 *dest = node;
1262
1263 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1264 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1265 continue;
1266 } else {
1267 continue;
1268 }
1269 },
1270
1271
1272 State.Block => |block| {
1273 const token = self.getNextToken();
1274 switch (token.id) {
1275 Token.Id.RBrace => {
1276 block.rbrace = token;
1277 continue;
1278 },
1279 else => {
1280 self.putBackToken(token);
1281 stack.append(State { .Block = block }) catch unreachable;
1282
1283 var any_comments = false;
1284 while (try self.eatLineComment(arena)) |line_comment| {
1285 try block.statements.append(&line_comment.base);
1286 any_comments = true;
1287 }
1288 if (any_comments) continue;
1289
1290 try stack.append(State { .Statement = block });
1291 continue;
1292 },
1293 }
1294 },
1295 State.Statement => |block| {
1296 const token = self.getNextToken();
1297 switch (token.id) {
1298 Token.Id.Keyword_comptime => {
1299 stack.append(State {
1300 .ComptimeStatement = ComptimeStatementCtx {
1301 .comptime_token = token,
1302 .block = block,
1303 }
1304 }) catch unreachable;
1305 continue;
1306 },
1307 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1308 stack.append(State {
1309 .VarDecl = VarDeclCtx {
1310 .comments = null,
1311 .visib_token = null,
1312 .comptime_token = null,
1313 .extern_export_token = null,
1314 .lib_name = null,
1315 .mut_token = token,
1316 .list = &block.statements,
1317 }
1318 }) catch unreachable;
1319 continue;
1320 },
1321 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1322 const node = try arena.construct(ast.Node.Defer {
1323 .base = ast.Node {
1324 .id = ast.Node.Id.Defer,
1325 .same_line_comment = null,
1326 },
1327 .defer_token = token,
1328 .kind = switch (token.id) {
1329 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1330 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1331 else => unreachable,
1332 },
1333 .expr = undefined,
1334 });
1335 const node_ptr = try block.statements.addOne();
1336 *node_ptr = &node.base;
1337
1338 stack.append(State { .Semicolon = node_ptr }) catch unreachable;
1339 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1340 continue;
1341 },
1342 Token.Id.LBrace => {
1343 const inner_block = try self.createAttachNode(arena, &block.statements, ast.Node.Block,
1344 ast.Node.Block {
1345 .base = undefined,
1346 .label = null,
1347 .lbrace = token,
1348 .statements = ArrayList(&ast.Node).init(arena),
1349 .rbrace = undefined,
1350 }
1351 );
1352 stack.append(State { .Block = inner_block }) catch unreachable;
1353 continue;
1354 },
1355 else => {
1356 self.putBackToken(token);
1357 const statement = try block.statements.addOne();
1358 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1359 try stack.append(State { .Semicolon = statement });
1360 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1361 continue;
1362 }
1363 }
1364 },
1365 State.ComptimeStatement => |ctx| {
1366 const token = self.getNextToken();
1367 switch (token.id) {
1368 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1369 stack.append(State {
1370 .VarDecl = VarDeclCtx {
1371 .comments = null,
1372 .visib_token = null,
1373 .comptime_token = ctx.comptime_token,
1374 .extern_export_token = null,
1375 .lib_name = null,
1376 .mut_token = token,
1377 .list = &ctx.block.statements,
1378 }
1379 }) catch unreachable;
1380 continue;
1381 },
1382 else => {
1383 self.putBackToken(token);
1384 self.putBackToken(ctx.comptime_token);
1385 const statement = try ctx.block.statements.addOne();
1386 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1387 try stack.append(State { .Semicolon = statement });
1388 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1389 continue;
1390 }
1391 }
1392 },
1393 State.Semicolon => |node_ptr| {
1394 const node = *node_ptr;
1395 if (requireSemiColon(node)) {
1396 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1397 continue;
1398 }
1399 continue;
1400 },
1401
1402 State.LookForSameLineComment => |node_ptr| {
1403 try self.lookForSameLineComment(arena, *node_ptr);
1404 continue;
1405 },
1406
1407 State.LookForSameLineCommentDirect => |node| {
1408 try self.lookForSameLineComment(arena, node);
1409 continue;
1410 },
1411
1412
1413 State.AsmOutputItems => |items| {
1414 const lbracket = self.getNextToken();
1415 if (lbracket.id != Token.Id.LBracket) {
1416 self.putBackToken(lbracket);
1417 continue;
1418 }
1419
1420 const node = try self.createNode(arena, ast.Node.AsmOutput,
1421 ast.Node.AsmOutput {
1422 .base = undefined,
1423 .symbolic_name = undefined,
1424 .constraint = undefined,
1425 .kind = undefined,
1426 }
1427 );
1428 try items.append(node);
1429
1430 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1431 try stack.append(State { .IfToken = Token.Id.Comma });
1432 try stack.append(State { .ExpectToken = Token.Id.RParen });
1433 try stack.append(State { .AsmOutputReturnOrType = node });
1434 try stack.append(State { .ExpectToken = Token.Id.LParen });
1435 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1436 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1437 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1438 continue;
1439 },
1440 State.AsmOutputReturnOrType => |node| {
1441 const token = self.getNextToken();
1442 switch (token.id) {
1443 Token.Id.Identifier => {
1444 node.kind = ast.Node.AsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.Node.Identifier, token) };
1445 continue;
1446 },
1447 Token.Id.Arrow => {
1448 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1449 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1450 continue;
1451 },
1452 else => {
1453 return self.parseError(token, "expected '->' or {}, found {}",
1454 @tagName(Token.Id.Identifier),
1455 @tagName(token.id));
1456 },
1457 }
1458 },
1459 State.AsmInputItems => |items| {
1460 const lbracket = self.getNextToken();
1461 if (lbracket.id != Token.Id.LBracket) {
1462 self.putBackToken(lbracket);
1463 continue;
1464 }
1465
1466 const node = try self.createNode(arena, ast.Node.AsmInput,
1467 ast.Node.AsmInput {
1468 .base = undefined,
1469 .symbolic_name = undefined,
1470 .constraint = undefined,
1471 .expr = undefined,
1472 }
1473 );
1474 try items.append(node);
1475
1476 stack.append(State { .AsmInputItems = items }) catch unreachable;
1477 try stack.append(State { .IfToken = Token.Id.Comma });
1478 try stack.append(State { .ExpectToken = Token.Id.RParen });
1479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1480 try stack.append(State { .ExpectToken = Token.Id.LParen });
1481 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1482 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1483 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1484 continue;
1485 },
1486 State.AsmClopperItems => |items| {
1487 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1488 try stack.append(State { .IfToken = Token.Id.Comma });
1489 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1490 continue;
1491 },
1492
1493
1494 State.ExprListItemOrEnd => |list_state| {
1495 if (self.eatToken(list_state.end)) |token| {
1496 *list_state.ptr = token;
1497 continue;
1498 }
1499
1500 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1501 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1502 continue;
1503 },
1504 State.ExprListCommaOrEnd => |list_state| {
1505 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1506 *list_state.ptr = end;
1507 continue;
1508 } else {
1509 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1510 continue;
1511 }
1512 },
1513 State.FieldInitListItemOrEnd => |list_state| {
1514 while (try self.eatLineComment(arena)) |line_comment| {
1515 try list_state.list.append(&line_comment.base);
1516 }
1517
1518 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1519 *list_state.ptr = rbrace;
1520 continue;
1521 }
1522
1523 const node = try arena.construct(ast.Node.FieldInitializer {
1524 .base = ast.Node {
1525 .id = ast.Node.Id.FieldInitializer,
1526 .same_line_comment = null,
1527 },
1528 .period_token = undefined,
1529 .name_token = undefined,
1530 .expr = undefined,
1531 });
1532 try list_state.list.append(&node.base);
1533
1534 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1535 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1536 try stack.append(State { .ExpectToken = Token.Id.Equal });
1537 try stack.append(State {
1538 .ExpectTokenSave = ExpectTokenSave {
1539 .id = Token.Id.Identifier,
1540 .ptr = &node.name_token,
1541 }
1542 });
1543 try stack.append(State {
1544 .ExpectTokenSave = ExpectTokenSave {
1545 .id = Token.Id.Period,
1546 .ptr = &node.period_token,
1547 }
1548 });
1549 continue;
1550 },
1551 State.FieldInitListCommaOrEnd => |list_state| {
1552 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1553 *list_state.ptr = end;
1554 continue;
1555 } else {
1556 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1557 continue;
1558 }
1559 },
1560 State.FieldListCommaOrEnd => |container_decl| {
1561 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1562 container_decl.rbrace_token = end;
1563 continue;
1564 }
1565
1566 try self.lookForSameLineComment(arena, container_decl.fields_and_decls.toSlice()[container_decl.fields_and_decls.len - 1]);
1567 try stack.append(State { .ContainerDecl = container_decl });
1568 continue;
1569 },
1570 State.ErrorTagListItemOrEnd => |list_state| {
1571 while (try self.eatLineComment(arena)) |line_comment| {
1572 try list_state.list.append(&line_comment.base);
1573 }
1574
1575 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1576 *list_state.ptr = rbrace;
1577 continue;
1578 }
1579
1580 const node_ptr = try list_state.list.addOne();
1581
1582 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1583 try stack.append(State { .ErrorTag = node_ptr });
1584 continue;
1585 },
1586 State.ErrorTagListCommaOrEnd => |list_state| {
1587 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1588 *list_state.ptr = end;
1589 continue;
1590 } else {
1591 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1592 continue;
1593 }
1594 },
1595 State.SwitchCaseOrEnd => |list_state| {
1596 while (try self.eatLineComment(arena)) |line_comment| {
1597 try list_state.list.append(&line_comment.base);
1598 }
1599
1600 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1601 *list_state.ptr = rbrace;
1602 continue;
1603 }
1604
1605 const comments = try self.eatDocComments(arena);
1606 const node = try arena.construct(ast.Node.SwitchCase {
1607 .base = ast.Node {
1608 .id = ast.Node.Id.SwitchCase,
1609 .same_line_comment = null,
1610 },
1611 .items = ArrayList(&ast.Node).init(arena),
1612 .payload = null,
1613 .expr = undefined,
1614 });
1615 try list_state.list.append(&node.base);
1616 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1617 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1618 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1619 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1620
1621 continue;
1622 },
1623
1624 State.SwitchCaseCommaOrEnd => |list_state| {
1625 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1626 *list_state.ptr = end;
1627 continue;
1628 }
1629
1630 const node = list_state.list.toSlice()[list_state.list.len - 1];
1631 try self.lookForSameLineComment(arena, node);
1632 try stack.append(State { .SwitchCaseOrEnd = list_state });
1633 continue;
1634 },
1635
1636 State.SwitchCaseFirstItem => |case_items| {
1637 const token = self.getNextToken();
1638 if (token.id == Token.Id.Keyword_else) {
1639 const else_node = try self.createAttachNode(arena, case_items, ast.Node.SwitchElse,
1640 ast.Node.SwitchElse {
1641 .base = undefined,
1642 .token = token,
1643 }
1644 );
1645 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1646 continue;
1647 } else {
1648 self.putBackToken(token);
1649 try stack.append(State { .SwitchCaseItem = case_items });
1650 continue;
1651 }
1652 },
1653 State.SwitchCaseItem => |case_items| {
1654 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1655 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1656 },
1657 State.SwitchCaseItemCommaOrEnd => |case_items| {
1658 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1659 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1660 }
1661 continue;
1662 },
1663
1664
1665 State.SuspendBody => |suspend_node| {
1666 if (suspend_node.payload != null) {
1667 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1668 }
1669 continue;
1670 },
1671 State.AsyncAllocator => |async_node| {
1672 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
1673 continue;
1674 }
1675
1676 async_node.rangle_bracket = Token(undefined);
1677 try stack.append(State {
1678 .ExpectTokenSave = ExpectTokenSave {
1679 .id = Token.Id.AngleBracketRight,
1680 .ptr = &??async_node.rangle_bracket,
1681 }
1682 });
1683 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1684 continue;
1685 },
1686 State.AsyncEnd => |ctx| {
1687 const node = ctx.ctx.get() ?? continue;
1688
1689 switch (node.id) {
1690 ast.Node.Id.FnProto => {
1691 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1692 fn_proto.async_attr = ctx.attribute;
1693 continue;
1694 },
1695 ast.Node.Id.SuffixOp => {
1696 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1697 if (suffix_op.op == ast.Node.SuffixOp.Op.Call) {
1698 suffix_op.op.Call.async_attr = ctx.attribute;
1699 continue;
1700 }
1701
1702 return self.parseError(node.firstToken(), "expected {}, found {}.",
1703 @tagName(ast.Node.SuffixOp.Op.Call),
1704 @tagName(suffix_op.op));
1705 },
1706 else => {
1707 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1708 @tagName(ast.Node.SuffixOp.Op.Call),
1709 @tagName(ast.Node.Id.FnProto),
1710 @tagName(node.id));
1711 }
1712 }
1713 },
1714
1715
1716 State.ExternType => |ctx| {
1717 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1718 const fn_proto = try arena.construct(ast.Node.FnProto {
1719 .base = ast.Node {
1720 .id = ast.Node.Id.FnProto,
1721 .same_line_comment = null,
1722 },
1723 .doc_comments = ctx.comments,
1724 .visib_token = null,
1725 .name_token = null,
1726 .fn_token = fn_token,
1727 .params = ArrayList(&ast.Node).init(arena),
1728 .return_type = undefined,
1729 .var_args_token = null,
1730 .extern_export_inline_token = ctx.extern_token,
1731 .cc_token = null,
1732 .async_attr = null,
1733 .body_node = null,
1734 .lib_name = null,
1735 .align_expr = null,
1736 });
1737 ctx.opt_ctx.store(&fn_proto.base);
1738 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1739 continue;
1740 }
1741
1742 stack.append(State {
1743 .ContainerKind = ContainerKindCtx {
1744 .opt_ctx = ctx.opt_ctx,
1745 .ltoken = ctx.extern_token,
1746 .layout = ast.Node.ContainerDecl.Layout.Extern,
1747 },
1748 }) catch unreachable;
1749 continue;
1750 },
1751 State.SliceOrArrayAccess => |node| {
1752 var token = self.getNextToken();
1753 switch (token.id) {
1754 Token.Id.Ellipsis2 => {
1755 const start = node.op.ArrayAccess;
1756 node.op = ast.Node.SuffixOp.Op {
1757 .Slice = ast.Node.SuffixOp.SliceRange {
1758 .start = start,
1759 .end = null,
1760 }
1761 };
1762
1763 stack.append(State {
1764 .ExpectTokenSave = ExpectTokenSave {
1765 .id = Token.Id.RBracket,
1766 .ptr = &node.rtoken,
1767 }
1768 }) catch unreachable;
1769 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1770 continue;
1771 },
1772 Token.Id.RBracket => {
1773 node.rtoken = token;
1774 continue;
1775 },
1776 else => {
1777 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1778 }
1779 }
1780 },
1781 State.SliceOrArrayType => |node| {
1782 if (self.eatToken(Token.Id.RBracket)) |_| {
1783 node.op = ast.Node.PrefixOp.Op {
1784 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1785 .align_expr = null,
1786 .bit_offset_start_token = null,
1787 .bit_offset_end_token = null,
1788 .const_token = null,
1789 .volatile_token = null,
1790 }
1791 };
1792 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1793 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1794 continue;
1795 }
1796
1797 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1798 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1799 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1800 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1801 continue;
1802 },
1803 State.AddrOfModifiers => |addr_of_info| {
1804 var token = self.getNextToken();
1805 switch (token.id) {
1806 Token.Id.Keyword_align => {
1807 stack.append(state) catch unreachable;
1808 if (addr_of_info.align_expr != null) {
1809 return self.parseError(token, "multiple align qualifiers");
1810 }
1811 try stack.append(State { .ExpectToken = Token.Id.RParen });
1812 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1813 try stack.append(State { .ExpectToken = Token.Id.LParen });
1814 continue;
1815 },
1816 Token.Id.Keyword_const => {
1817 stack.append(state) catch unreachable;
1818 if (addr_of_info.const_token != null) {
1819 return self.parseError(token, "duplicate qualifier: const");
1820 }
1821 addr_of_info.const_token = token;
1822 continue;
1823 },
1824 Token.Id.Keyword_volatile => {
1825 stack.append(state) catch unreachable;
1826 if (addr_of_info.volatile_token != null) {
1827 return self.parseError(token, "duplicate qualifier: volatile");
1828 }
1829 addr_of_info.volatile_token = token;
1830 continue;
1831 },
1832 else => {
1833 self.putBackToken(token);
1834 continue;
1835 },
1836 }
1837 },
1838
1839
1840 State.Payload => |opt_ctx| {
1841 const token = self.getNextToken();
1842 if (token.id != Token.Id.Pipe) {
1843 if (opt_ctx != OptionalCtx.Optional) {
1844 return self.parseError(token, "expected {}, found {}.",
1845 @tagName(Token.Id.Pipe),
1846 @tagName(token.id));
1847 }
1848
1849 self.putBackToken(token);
1850 continue;
1851 }
1852
1853 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1854 ast.Node.Payload {
1855 .base = undefined,
1856 .lpipe = token,
1857 .error_symbol = undefined,
1858 .rpipe = undefined
1859 }
1860 );
1861
1862 stack.append(State {
1863 .ExpectTokenSave = ExpectTokenSave {
1864 .id = Token.Id.Pipe,
1865 .ptr = &node.rpipe,
1866 }
1867 }) catch unreachable;
1868 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1869 continue;
1870 },
1871 State.PointerPayload => |opt_ctx| {
1872 const token = self.getNextToken();
1873 if (token.id != Token.Id.Pipe) {
1874 if (opt_ctx != OptionalCtx.Optional) {
1875 return self.parseError(token, "expected {}, found {}.",
1876 @tagName(Token.Id.Pipe),
1877 @tagName(token.id));
1878 }
1879
1880 self.putBackToken(token);
1881 continue;
1882 }
1883
1884 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1885 ast.Node.PointerPayload {
1886 .base = undefined,
1887 .lpipe = token,
1888 .ptr_token = null,
1889 .value_symbol = undefined,
1890 .rpipe = undefined
1891 }
1892 );
1893
1894 stack.append(State {.LookForSameLineCommentDirect = &node.base }) catch unreachable;
1895 try stack.append(State {
1896 .ExpectTokenSave = ExpectTokenSave {
1897 .id = Token.Id.Pipe,
1898 .ptr = &node.rpipe,
1899 }
1900 });
1901 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1902 try stack.append(State {
1903 .OptionalTokenSave = OptionalTokenSave {
1904 .id = Token.Id.Asterisk,
1905 .ptr = &node.ptr_token,
1906 }
1907 });
1908 continue;
1909 },
1910 State.PointerIndexPayload => |opt_ctx| {
1911 const token = self.getNextToken();
1912 if (token.id != Token.Id.Pipe) {
1913 if (opt_ctx != OptionalCtx.Optional) {
1914 return self.parseError(token, "expected {}, found {}.",
1915 @tagName(Token.Id.Pipe),
1916 @tagName(token.id));
1917 }
1918
1919 self.putBackToken(token);
1920 continue;
1921 }
1922
1923 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1924 ast.Node.PointerIndexPayload {
1925 .base = undefined,
1926 .lpipe = token,
1927 .ptr_token = null,
1928 .value_symbol = undefined,
1929 .index_symbol = null,
1930 .rpipe = undefined
1931 }
1932 );
1933
1934 stack.append(State {
1935 .ExpectTokenSave = ExpectTokenSave {
1936 .id = Token.Id.Pipe,
1937 .ptr = &node.rpipe,
1938 }
1939 }) catch unreachable;
1940 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1941 try stack.append(State { .IfToken = Token.Id.Comma });
1942 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1943 try stack.append(State {
1944 .OptionalTokenSave = OptionalTokenSave {
1945 .id = Token.Id.Asterisk,
1946 .ptr = &node.ptr_token,
1947 }
1948 });
1949 continue;
1950 },
1951
1952
1953 State.Expression => |opt_ctx| {
1954 const token = self.getNextToken();
1955 switch (token.id) {
1956 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1957 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1958 ast.Node.ControlFlowExpression {
1959 .base = undefined,
1960 .ltoken = token,
1961 .kind = undefined,
1962 .rhs = null,
1963 }
1964 );
1965
1966 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1967
1968 switch (token.id) {
1969 Token.Id.Keyword_break => {
1970 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1971 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1972 try stack.append(State { .IfToken = Token.Id.Colon });
1973 },
1974 Token.Id.Keyword_continue => {
1975 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1976 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1977 try stack.append(State { .IfToken = Token.Id.Colon });
1978 },
1979 Token.Id.Keyword_return => {
1980 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1981 },
1982 else => unreachable,
1983 }
1984 continue;
1985 },
1986 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1987 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1988 ast.Node.PrefixOp {
1989 .base = undefined,
1990 .op_token = token,
1991 .op = switch (token.id) {
1992 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1993 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1994 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1995 else => unreachable,
1996 },
1997 .rhs = undefined,
1998 }
1999 );
2000
2001 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2002 continue;
2003 },
2004 else => {
2005 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2006 self.putBackToken(token);
2007 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
2008 }
2009 continue;
2010 }
2011 }
2012 },
2013 State.RangeExpressionBegin => |opt_ctx| {
2014 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
2015 try stack.append(State { .Expression = opt_ctx });
2016 continue;
2017 },
2018 State.RangeExpressionEnd => |opt_ctx| {
2019 const lhs = opt_ctx.get() ?? continue;
2020
2021 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
2022 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2023 ast.Node.InfixOp {
2024 .base = undefined,
2025 .lhs = lhs,
2026 .op_token = ellipsis3,
2027 .op = ast.Node.InfixOp.Op.Range,
2028 .rhs = undefined,
2029 }
2030 );
2031 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2032 continue;
2033 }
2034 },
2035 State.AssignmentExpressionBegin => |opt_ctx| {
2036 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
2037 try stack.append(State { .Expression = opt_ctx });
2038 continue;
2039 },
2040
2041 State.AssignmentExpressionEnd => |opt_ctx| {
2042 const lhs = opt_ctx.get() ?? continue;
2043
2044 const token = self.getNextToken();
2045 if (tokenIdToAssignment(token.id)) |ass_id| {
2046 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2047 ast.Node.InfixOp {
2048 .base = undefined,
2049 .lhs = lhs,
2050 .op_token = token,
2051 .op = ass_id,
2052 .rhs = undefined,
2053 }
2054 );
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 self.putBackToken(token);
2060 continue;
2061 }
2062 },
2063
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 },
2069
2070 State.UnwrapExpressionEnd => |opt_ctx| {
2071 const lhs = opt_ctx.get() ?? continue;
2072
2073 const token = self.getNextToken();
2074 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
2075 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2076 ast.Node.InfixOp {
2077 .base = undefined,
2078 .lhs = lhs,
2079 .op_token = token,
2080 .op = unwrap_id,
2081 .rhs = undefined,
2082 }
2083 );
2084
2085 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2086 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
2087
2088 if (node.op == ast.Node.InfixOp.Op.Catch) {
2089 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
2090 }
2091 continue;
2092 } else {
2093 self.putBackToken(token);
2094 continue;
2095 }
2096 },
2097
2098 State.BoolOrExpressionBegin => |opt_ctx| {
2099 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
2100 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
2101 continue;
2102 },
2103
2104 State.BoolOrExpressionEnd => |opt_ctx| {
2105 const lhs = opt_ctx.get() ?? continue;
2106
2107 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
2108 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2109 ast.Node.InfixOp {
2110 .base = undefined,
2111 .lhs = lhs,
2112 .op_token = or_token,
2113 .op = ast.Node.InfixOp.Op.BoolOr,
2114 .rhs = undefined,
2115 }
2116 );
2117 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2118 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2119 continue;
2120 }
2121 },
2122
2123 State.BoolAndExpressionBegin => |opt_ctx| {
2124 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
2125 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
2126 continue;
2127 },
2128
2129 State.BoolAndExpressionEnd => |opt_ctx| {
2130 const lhs = opt_ctx.get() ?? continue;
2131
2132 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
2133 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2134 ast.Node.InfixOp {
2135 .base = undefined,
2136 .lhs = lhs,
2137 .op_token = and_token,
2138 .op = ast.Node.InfixOp.Op.BoolAnd,
2139 .rhs = undefined,
2140 }
2141 );
2142 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2143 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2144 continue;
2145 }
2146 },
2147
2148 State.ComparisonExpressionBegin => |opt_ctx| {
2149 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2150 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
2151 continue;
2152 },
2153
2154 State.ComparisonExpressionEnd => |opt_ctx| {
2155 const lhs = opt_ctx.get() ?? continue;
2156
2157 const token = self.getNextToken();
2158 if (tokenIdToComparison(token.id)) |comp_id| {
2159 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2160 ast.Node.InfixOp {
2161 .base = undefined,
2162 .lhs = lhs,
2163 .op_token = token,
2164 .op = comp_id,
2165 .rhs = undefined,
2166 }
2167 );
2168 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2169 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2170 continue;
2171 } else {
2172 self.putBackToken(token);
2173 continue;
2174 }
2175 },
2176
2177 State.BinaryOrExpressionBegin => |opt_ctx| {
2178 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2179 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2180 continue;
2181 },
2182
2183 State.BinaryOrExpressionEnd => |opt_ctx| {
2184 const lhs = opt_ctx.get() ?? continue;
2185
2186 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2187 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2188 ast.Node.InfixOp {
2189 .base = undefined,
2190 .lhs = lhs,
2191 .op_token = pipe,
2192 .op = ast.Node.InfixOp.Op.BitOr,
2193 .rhs = undefined,
2194 }
2195 );
2196 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2197 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2198 continue;
2199 }
2200 },
2201
2202 State.BinaryXorExpressionBegin => |opt_ctx| {
2203 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2204 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2205 continue;
2206 },
2207
2208 State.BinaryXorExpressionEnd => |opt_ctx| {
2209 const lhs = opt_ctx.get() ?? continue;
2210
2211 if (self.eatToken(Token.Id.Caret)) |caret| {
2212 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2213 ast.Node.InfixOp {
2214 .base = undefined,
2215 .lhs = lhs,
2216 .op_token = caret,
2217 .op = ast.Node.InfixOp.Op.BitXor,
2218 .rhs = undefined,
2219 }
2220 );
2221 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2222 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2223 continue;
2224 }
2225 },
2226
2227 State.BinaryAndExpressionBegin => |opt_ctx| {
2228 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2229 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2230 continue;
2231 },
2232
2233 State.BinaryAndExpressionEnd => |opt_ctx| {
2234 const lhs = opt_ctx.get() ?? continue;
2235
2236 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2237 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2238 ast.Node.InfixOp {
2239 .base = undefined,
2240 .lhs = lhs,
2241 .op_token = ampersand,
2242 .op = ast.Node.InfixOp.Op.BitAnd,
2243 .rhs = undefined,
2244 }
2245 );
2246 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2247 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2248 continue;
2249 }
2250 },
2251
2252 State.BitShiftExpressionBegin => |opt_ctx| {
2253 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2254 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2255 continue;
2256 },
2257
2258 State.BitShiftExpressionEnd => |opt_ctx| {
2259 const lhs = opt_ctx.get() ?? continue;
2260
2261 const token = self.getNextToken();
2262 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2263 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2264 ast.Node.InfixOp {
2265 .base = undefined,
2266 .lhs = lhs,
2267 .op_token = token,
2268 .op = bitshift_id,
2269 .rhs = undefined,
2270 }
2271 );
2272 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2273 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2274 continue;
2275 } else {
2276 self.putBackToken(token);
2277 continue;
2278 }
2279 },
2280
2281 State.AdditionExpressionBegin => |opt_ctx| {
2282 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2283 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2284 continue;
2285 },
2286
2287 State.AdditionExpressionEnd => |opt_ctx| {
2288 const lhs = opt_ctx.get() ?? continue;
2289
2290 const token = self.getNextToken();
2291 if (tokenIdToAddition(token.id)) |add_id| {
2292 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2293 ast.Node.InfixOp {
2294 .base = undefined,
2295 .lhs = lhs,
2296 .op_token = token,
2297 .op = add_id,
2298 .rhs = undefined,
2299 }
2300 );
2301 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2302 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2303 continue;
2304 } else {
2305 self.putBackToken(token);
2306 continue;
2307 }
2308 },
2309
2310 State.MultiplyExpressionBegin => |opt_ctx| {
2311 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2312 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2313 continue;
2314 },
2315
2316 State.MultiplyExpressionEnd => |opt_ctx| {
2317 const lhs = opt_ctx.get() ?? continue;
2318
2319 const token = self.getNextToken();
2320 if (tokenIdToMultiply(token.id)) |mult_id| {
2321 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2322 ast.Node.InfixOp {
2323 .base = undefined,
2324 .lhs = lhs,
2325 .op_token = token,
2326 .op = mult_id,
2327 .rhs = undefined,
2328 }
2329 );
2330 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2331 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2332 continue;
2333 } else {
2334 self.putBackToken(token);
2335 continue;
2336 }
2337 },
2338
2339 State.CurlySuffixExpressionBegin => |opt_ctx| {
2340 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2341 try stack.append(State { .IfToken = Token.Id.LBrace });
2342 try stack.append(State { .TypeExprBegin = opt_ctx });
2343 continue;
2344 },
2345
2346 State.CurlySuffixExpressionEnd => |opt_ctx| {
2347 const lhs = opt_ctx.get() ?? continue;
2348
2349 if (self.isPeekToken(Token.Id.Period)) {
2350 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2351 ast.Node.SuffixOp {
2352 .base = undefined,
2353 .lhs = lhs,
2354 .op = ast.Node.SuffixOp.Op {
2355 .StructInitializer = ArrayList(&ast.Node).init(arena),
2356 },
2357 .rtoken = undefined,
2358 }
2359 );
2360 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2361 try stack.append(State { .IfToken = Token.Id.LBrace });
2362 try stack.append(State {
2363 .FieldInitListItemOrEnd = ListSave(&ast.Node) {
2364 .list = &node.op.StructInitializer,
2365 .ptr = &node.rtoken,
2366 }
2367 });
2368 continue;
2369 }
2370
2371 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2372 ast.Node.SuffixOp {
2373 .base = undefined,
2374 .lhs = lhs,
2375 .op = ast.Node.SuffixOp.Op {
2376 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2377 },
2378 .rtoken = undefined,
2379 }
2380 );
2381 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2382 try stack.append(State { .IfToken = Token.Id.LBrace });
2383 try stack.append(State {
2384 .ExprListItemOrEnd = ExprListCtx {
2385 .list = &node.op.ArrayInitializer,
2386 .end = Token.Id.RBrace,
2387 .ptr = &node.rtoken,
2388 }
2389 });
2390 continue;
2391 },
2392
2393 State.TypeExprBegin => |opt_ctx| {
2394 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2395 try stack.append(State { .PrefixOpExpression = opt_ctx });
2396 continue;
2397 },
2398
2399 State.TypeExprEnd => |opt_ctx| {
2400 const lhs = opt_ctx.get() ?? continue;
2401
2402 if (self.eatToken(Token.Id.Bang)) |bang| {
2403 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2404 ast.Node.InfixOp {
2405 .base = undefined,
2406 .lhs = lhs,
2407 .op_token = bang,
2408 .op = ast.Node.InfixOp.Op.ErrorUnion,
2409 .rhs = undefined,
2410 }
2411 );
2412 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2413 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2414 continue;
2415 }
2416 },
2417
2418 State.PrefixOpExpression => |opt_ctx| {
2419 const token = self.getNextToken();
2420 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2421 var node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2422 ast.Node.PrefixOp {
2423 .base = undefined,
2424 .op_token = token,
2425 .op = prefix_id,
2426 .rhs = undefined,
2427 }
2428 );
2429
2430 // Treat '**' token as two derefs
2431 if (token.id == Token.Id.AsteriskAsterisk) {
2432 const child = try self.createNode(arena, ast.Node.PrefixOp,
2433 ast.Node.PrefixOp {
2434 .base = undefined,
2435 .op_token = token,
2436 .op = prefix_id,
2437 .rhs = undefined,
2438 }
2439 );
2440 node.rhs = &child.base;
2441 node = child;
2442 }
2443
2444 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2445 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2446 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2447 }
2448 continue;
2449 } else {
2450 self.putBackToken(token);
2451 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2452 continue;
2453 }
2454 },
2455
2456 State.SuffixOpExpressionBegin => |opt_ctx| {
2457 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2458 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
2459 ast.Node.AsyncAttribute {
2460 .base = undefined,
2461 .async_token = async_token,
2462 .allocator_type = null,
2463 .rangle_bracket = null,
2464 }
2465 );
2466 stack.append(State {
2467 .AsyncEnd = AsyncEndCtx {
2468 .ctx = opt_ctx,
2469 .attribute = async_node,
2470 }
2471 }) catch unreachable;
2472 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2473 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2474 try stack.append(State { .AsyncAllocator = async_node });
2475 continue;
2476 }
2477
2478 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2479 try stack.append(State { .PrimaryExpression = opt_ctx });
2480 continue;
2481 },
2482
2483 State.SuffixOpExpressionEnd => |opt_ctx| {
2484 const lhs = opt_ctx.get() ?? continue;
2485
2486 const token = self.getNextToken();
2487 switch (token.id) {
2488 Token.Id.LParen => {
2489 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2490 ast.Node.SuffixOp {
2491 .base = undefined,
2492 .lhs = lhs,
2493 .op = ast.Node.SuffixOp.Op {
2494 .Call = ast.Node.SuffixOp.CallInfo {
2495 .params = ArrayList(&ast.Node).init(arena),
2496 .async_attr = null,
2497 }
2498 },
2499 .rtoken = undefined,
2500 }
2501 );
2502 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2503 try stack.append(State {
2504 .ExprListItemOrEnd = ExprListCtx {
2505 .list = &node.op.Call.params,
2506 .end = Token.Id.RParen,
2507 .ptr = &node.rtoken,
2508 }
2509 });
2510 continue;
2511 },
2512 Token.Id.LBracket => {
2513 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2514 ast.Node.SuffixOp {
2515 .base = undefined,
2516 .lhs = lhs,
2517 .op = ast.Node.SuffixOp.Op {
2518 .ArrayAccess = undefined,
2519 },
2520 .rtoken = undefined
2521 }
2522 );
2523 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2524 try stack.append(State { .SliceOrArrayAccess = node });
2525 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2526 continue;
2527 },
2528 Token.Id.Period => {
2529 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2530 ast.Node.InfixOp {
2531 .base = undefined,
2532 .lhs = lhs,
2533 .op_token = token,
2534 .op = ast.Node.InfixOp.Op.Period,
2535 .rhs = undefined,
2536 }
2537 );
2538 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2539 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2540 continue;
2541 },
2542 else => {
2543 self.putBackToken(token);
2544 continue;
2545 },
2546 }
2547 },
2548
2549 State.PrimaryExpression => |opt_ctx| {
2550 const token = self.getNextToken();
2551 switch (token.id) {
2552 Token.Id.IntegerLiteral => {
2553 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token);
2554 continue;
2555 },
2556 Token.Id.FloatLiteral => {
2557 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token);
2558 continue;
2559 },
2560 Token.Id.CharLiteral => {
2561 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token);
2562 continue;
2563 },
2564 Token.Id.Keyword_undefined => {
2565 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token);
2566 continue;
2567 },
2568 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2569 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token);
2570 continue;
2571 },
2572 Token.Id.Keyword_null => {
2573 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token);
2574 continue;
2575 },
2576 Token.Id.Keyword_this => {
2577 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token);
2578 continue;
2579 },
2580 Token.Id.Keyword_var => {
2581 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token);
2582 continue;
2583 },
2584 Token.Id.Keyword_unreachable => {
2585 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
2586 continue;
2587 },
2588 Token.Id.Keyword_promise => {
2589 const node = try arena.construct(ast.Node.PromiseType {
2590 .base = ast.Node {
2591 .id = ast.Node.Id.PromiseType,
2592 .same_line_comment = null,
2593 },
2594 .promise_token = token,
2595 .result = null,
2596 });
2597 opt_ctx.store(&node.base);
2598 const next_token = self.getNextToken();
2599 if (next_token.id != Token.Id.Arrow) {
2600 self.putBackToken(next_token);
2601 continue;
2602 }
2603 node.result = ast.Node.PromiseType.Result {
2604 .arrow_token = next_token,
2605 .return_type = undefined,
2606 };
2607 const return_type_ptr = &((??node.result).return_type);
2608 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2609 continue;
2610 },
2611 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2612 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2613 continue;
2614 },
2615 Token.Id.LParen => {
2616 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2617 ast.Node.GroupedExpression {
2618 .base = undefined,
2619 .lparen = token,
2620 .expr = undefined,
2621 .rparen = undefined,
2622 }
2623 );
2624 stack.append(State {
2625 .ExpectTokenSave = ExpectTokenSave {
2626 .id = Token.Id.RParen,
2627 .ptr = &node.rparen,
2628 }
2629 }) catch unreachable;
2630 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2631 continue;
2632 },
2633 Token.Id.Builtin => {
2634 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2635 ast.Node.BuiltinCall {
2636 .base = undefined,
2637 .builtin_token = token,
2638 .params = ArrayList(&ast.Node).init(arena),
2639 .rparen_token = undefined,
2640 }
2641 );
2642 stack.append(State {
2643 .ExprListItemOrEnd = ExprListCtx {
2644 .list = &node.params,
2645 .end = Token.Id.RParen,
2646 .ptr = &node.rparen_token,
2647 }
2648 }) catch unreachable;
2649 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2650 continue;
2651 },
2652 Token.Id.LBracket => {
2653 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2654 ast.Node.PrefixOp {
2655 .base = undefined,
2656 .op_token = token,
2657 .op = undefined,
2658 .rhs = undefined,
2659 }
2660 );
2661 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2662 continue;
2663 },
2664 Token.Id.Keyword_error => {
2665 stack.append(State {
2666 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2667 .error_token = token,
2668 .opt_ctx = opt_ctx
2669 }
2670 }) catch unreachable;
2671 continue;
2672 },
2673 Token.Id.Keyword_packed => {
2674 stack.append(State {
2675 .ContainerKind = ContainerKindCtx {
2676 .opt_ctx = opt_ctx,
2677 .ltoken = token,
2678 .layout = ast.Node.ContainerDecl.Layout.Packed,
2679 },
2680 }) catch unreachable;
2681 continue;
2682 },
2683 Token.Id.Keyword_extern => {
2684 stack.append(State {
2685 .ExternType = ExternTypeCtx {
2686 .opt_ctx = opt_ctx,
2687 .extern_token = token,
2688 .comments = null,
2689 },
2690 }) catch unreachable;
2691 continue;
2692 },
2693 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2694 self.putBackToken(token);
2695 stack.append(State {
2696 .ContainerKind = ContainerKindCtx {
2697 .opt_ctx = opt_ctx,
2698 .ltoken = token,
2699 .layout = ast.Node.ContainerDecl.Layout.Auto,
2700 },
2701 }) catch unreachable;
2702 continue;
2703 },
2704 Token.Id.Identifier => {
2705 stack.append(State {
2706 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2707 .label = token,
2708 .opt_ctx = opt_ctx
2709 }
2710 }) catch unreachable;
2711 continue;
2712 },
2713 Token.Id.Keyword_fn => {
2714 const fn_proto = try arena.construct(ast.Node.FnProto {
2715 .base = ast.Node {
2716 .id = ast.Node.Id.FnProto,
2717 .same_line_comment = null,
2718 },
2719 .doc_comments = null,
2720 .visib_token = null,
2721 .name_token = null,
2722 .fn_token = token,
2723 .params = ArrayList(&ast.Node).init(arena),
2724 .return_type = undefined,
2725 .var_args_token = null,
2726 .extern_export_inline_token = null,
2727 .cc_token = null,
2728 .async_attr = null,
2729 .body_node = null,
2730 .lib_name = null,
2731 .align_expr = null,
2732 });
2733 opt_ctx.store(&fn_proto.base);
2734 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2735 continue;
2736 },
2737 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2738 const fn_proto = try arena.construct(ast.Node.FnProto {
2739 .base = ast.Node {
2740 .id = ast.Node.Id.FnProto,
2741 .same_line_comment = null,
2742 },
2743 .doc_comments = null,
2744 .visib_token = null,
2745 .name_token = null,
2746 .fn_token = undefined,
2747 .params = ArrayList(&ast.Node).init(arena),
2748 .return_type = undefined,
2749 .var_args_token = null,
2750 .extern_export_inline_token = null,
2751 .cc_token = token,
2752 .async_attr = null,
2753 .body_node = null,
2754 .lib_name = null,
2755 .align_expr = null,
2756 });
2757 opt_ctx.store(&fn_proto.base);
2758 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2759 try stack.append(State {
2760 .ExpectTokenSave = ExpectTokenSave {
2761 .id = Token.Id.Keyword_fn,
2762 .ptr = &fn_proto.fn_token
2763 }
2764 });
2765 continue;
2766 },
2767 Token.Id.Keyword_asm => {
2768 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2769 ast.Node.Asm {
2770 .base = undefined,
2771 .asm_token = token,
2772 .volatile_token = null,
2773 .template = undefined,
2774 //.tokens = ArrayList(ast.Node.Asm.AsmToken).init(arena),
2775 .outputs = ArrayList(&ast.Node.AsmOutput).init(arena),
2776 .inputs = ArrayList(&ast.Node.AsmInput).init(arena),
2777 .cloppers = ArrayList(&ast.Node).init(arena),
2778 .rparen = undefined,
2779 }
2780 );
2781 stack.append(State {
2782 .ExpectTokenSave = ExpectTokenSave {
2783 .id = Token.Id.RParen,
2784 .ptr = &node.rparen,
2785 }
2786 }) catch unreachable;
2787 try stack.append(State { .AsmClopperItems = &node.cloppers });
2788 try stack.append(State { .IfToken = Token.Id.Colon });
2789 try stack.append(State { .AsmInputItems = &node.inputs });
2790 try stack.append(State { .IfToken = Token.Id.Colon });
2791 try stack.append(State { .AsmOutputItems = &node.outputs });
2792 try stack.append(State { .IfToken = Token.Id.Colon });
2793 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2794 try stack.append(State { .ExpectToken = Token.Id.LParen });
2795 try stack.append(State {
2796 .OptionalTokenSave = OptionalTokenSave {
2797 .id = Token.Id.Keyword_volatile,
2798 .ptr = &node.volatile_token,
2799 }
2800 });
2801 },
2802 Token.Id.Keyword_inline => {
2803 stack.append(State {
2804 .Inline = InlineCtx {
2805 .label = null,
2806 .inline_token = token,
2807 .opt_ctx = opt_ctx,
2808 }
2809 }) catch unreachable;
2810 continue;
2811 },
2812 else => {
2813 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2814 self.putBackToken(token);
2815 if (opt_ctx != OptionalCtx.Optional) {
2816 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2817 }
2818 }
2819 continue;
2820 }
2821 }
2822 },
2823
2824
2825 State.ErrorTypeOrSetDecl => |ctx| {
2826 if (self.eatToken(Token.Id.LBrace) == null) {
2827 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2828 continue;
2829 }
2830
2831 const node = try arena.construct(ast.Node.ErrorSetDecl {
2832 .base = ast.Node {
2833 .id = ast.Node.Id.ErrorSetDecl,
2834 .same_line_comment = null,
2835 },
2836 .error_token = ctx.error_token,
2837 .decls = ArrayList(&ast.Node).init(arena),
2838 .rbrace_token = undefined,
2839 });
2840 ctx.opt_ctx.store(&node.base);
2841
2842 stack.append(State {
2843 .ErrorTagListItemOrEnd = ListSave(&ast.Node) {
2844 .list = &node.decls,
2845 .ptr = &node.rbrace_token,
2846 }
2847 }) catch unreachable;
2848 continue;
2849 },
2850 State.StringLiteral => |opt_ctx| {
2851 const token = self.getNextToken();
2852 opt_ctx.store(
2853 (try self.parseStringLiteral(arena, token)) ?? {
2854 self.putBackToken(token);
2855 if (opt_ctx != OptionalCtx.Optional) {
2856 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2857 }
2858
2859 continue;
2860 }
2861 );
2862 },
2863
2864 State.Identifier => |opt_ctx| {
2865 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2866 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2867 continue;
2868 }
2869
2870 if (opt_ctx != OptionalCtx.Optional) {
2871 const token = self.getNextToken();
2872 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2873 }
2874 },
2875
2876 State.ErrorTag => |node_ptr| {
2877 const comments = try self.eatDocComments(arena);
2878 const ident_token = self.getNextToken();
2879 if (ident_token.id != Token.Id.Identifier) {
2880 return self.parseError(ident_token, "expected {}, found {}",
2881 @tagName(Token.Id.Identifier), @tagName(ident_token.id));
2882 }
2883
2884 const node = try arena.construct(ast.Node.ErrorTag {
2885 .base = ast.Node {
2886 .id = ast.Node.Id.ErrorTag,
2887 .same_line_comment = null,
2888 },
2889 .doc_comments = comments,
2890 .name_token = ident_token,
2891 });
2892 *node_ptr = &node.base;
2893 continue;
2894 },
2895
2896 State.ExpectToken => |token_id| {
2897 _ = try self.expectToken(token_id);
2898 continue;
2899 },
2900 State.ExpectTokenSave => |expect_token_save| {
2901 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2902 continue;
2903 },
2904 State.IfToken => |token_id| {
2905 if (self.eatToken(token_id)) |_| {
2906 continue;
2907 }
2908
2909 _ = stack.pop();
2910 continue;
2911 },
2912 State.IfTokenSave => |if_token_save| {
2913 if (self.eatToken(if_token_save.id)) |token| {
2914 *if_token_save.ptr = token;
2915 continue;
2916 }
2917
2918 _ = stack.pop();
2919 continue;
2920 },
2921 State.OptionalTokenSave => |optional_token_save| {
2922 if (self.eatToken(optional_token_save.id)) |token| {
2923 *optional_token_save.ptr = token;
2924 continue;
2925 }
2926
2927 continue;
2928 },
2929 }
2930 }
2931 }
2932
2933 fn eatDocComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.DocComment {
2934 var result: ?&ast.Node.DocComment = null;
2935 while (true) {
2936 if (self.eatToken(Token.Id.DocComment)) |line_comment| {
2937 const node = blk: {
2938 if (result) |comment_node| {
2939 break :blk comment_node;
2940 } else {
2941 const comment_node = try arena.construct(ast.Node.DocComment {
2942 .base = ast.Node {
2943 .id = ast.Node.Id.DocComment,
2944 .same_line_comment = null,
2945 },
2946 .lines = ArrayList(Token).init(arena),
2947 });
2948 result = comment_node;
2949 break :blk comment_node;
2950 }
2951 };
2952 try node.lines.append(line_comment);
2953 continue;
2954 }
2955 break;
2956 }
2957 return result;
2958 }
2959
2960 fn eatLineComment(self: &Parser, arena: &mem.Allocator) !?&ast.Node.LineComment {
2961 const token = self.eatToken(Token.Id.LineComment) ?? return null;
2962 return try arena.construct(ast.Node.LineComment {
2963 .base = ast.Node {
2964 .id = ast.Node.Id.LineComment,
2965 .same_line_comment = null,
2966 },
2967 .token = token,
2968 });
2969 }
2970
2971 fn requireSemiColon(node: &const ast.Node) bool {
2972 var n = node;
2973 while (true) {
2974 switch (n.id) {
2975 ast.Node.Id.Root,
2976 ast.Node.Id.StructField,
2977 ast.Node.Id.UnionTag,
2978 ast.Node.Id.EnumTag,
2979 ast.Node.Id.ParamDecl,
2980 ast.Node.Id.Block,
2981 ast.Node.Id.Payload,
2982 ast.Node.Id.PointerPayload,
2983 ast.Node.Id.PointerIndexPayload,
2984 ast.Node.Id.Switch,
2985 ast.Node.Id.SwitchCase,
2986 ast.Node.Id.SwitchElse,
2987 ast.Node.Id.FieldInitializer,
2988 ast.Node.Id.DocComment,
2989 ast.Node.Id.LineComment,
2990 ast.Node.Id.TestDecl => return false,
2991 ast.Node.Id.While => {
2992 const while_node = @fieldParentPtr(ast.Node.While, "base", n);
2993 if (while_node.@"else") |@"else"| {
2994 n = @"else".base;
2995 continue;
2996 }
2997
2998 return while_node.body.id != ast.Node.Id.Block;
2999 },
3000 ast.Node.Id.For => {
3001 const for_node = @fieldParentPtr(ast.Node.For, "base", n);
3002 if (for_node.@"else") |@"else"| {
3003 n = @"else".base;
3004 continue;
3005 }
3006
3007 return for_node.body.id != ast.Node.Id.Block;
3008 },
3009 ast.Node.Id.If => {
3010 const if_node = @fieldParentPtr(ast.Node.If, "base", n);
3011 if (if_node.@"else") |@"else"| {
3012 n = @"else".base;
3013 continue;
3014 }
3015
3016 return if_node.body.id != ast.Node.Id.Block;
3017 },
3018 ast.Node.Id.Else => {
3019 const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
3020 n = else_node.body;
3021 continue;
3022 },
3023 ast.Node.Id.Defer => {
3024 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
3025 return defer_node.expr.id != ast.Node.Id.Block;
3026 },
3027 ast.Node.Id.Comptime => {
3028 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
3029 return comptime_node.expr.id != ast.Node.Id.Block;
3030 },
3031 ast.Node.Id.Suspend => {
3032 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
3033 if (suspend_node.body) |body| {
3034 return body.id != ast.Node.Id.Block;
3035 }
3036
3037 return true;
3038 },
3039 else => return true,
3040 }
3041 }
3042 }
3043
3044 fn lookForSameLineComment(self: &Parser, arena: &mem.Allocator, node: &ast.Node) !void {
3045 const node_last_token = node.lastToken();
3046
3047 const line_comment_token = self.getNextToken();
3048 if (line_comment_token.id != Token.Id.DocComment and line_comment_token.id != Token.Id.LineComment) {
3049 self.putBackToken(line_comment_token);
3050 return;
3051 }
3052
3053 const offset_loc = self.tokenizer.getTokenLocation(node_last_token.end, line_comment_token);
3054 const different_line = offset_loc.line != 0;
3055 if (different_line) {
3056 self.putBackToken(line_comment_token);
3057 return;
3058 }
3059
3060 node.same_line_comment = try arena.construct(line_comment_token);
3061 }
3062
3063 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
3064 switch (token.id) {
3065 Token.Id.StringLiteral => {
3066 return &(try self.createLiteral(arena, ast.Node.StringLiteral, token)).base;
3067 },
3068 Token.Id.MultilineStringLiteralLine => {
3069 const node = try self.createNode(arena, ast.Node.MultilineStringLiteral,
3070 ast.Node.MultilineStringLiteral {
3071 .base = undefined,
3072 .tokens = ArrayList(Token).init(arena),
3073 }
3074 );
3075 try node.tokens.append(token);
3076 while (true) {
3077 const multiline_str = self.getNextToken();
3078 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
3079 self.putBackToken(multiline_str);
3080 break;
3081 }
3082
3083 try node.tokens.append(multiline_str);
3084 }
3085
3086 return &node.base;
3087 },
3088 // TODO: We shouldn't need a cast, but:
3089 // 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.
3090 else => return (?&ast.Node)(null),
3091 }
3092 }
3093
3094 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
3095 switch (token.id) {
3096 Token.Id.Keyword_suspend => {
3097 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
3098 ast.Node.Suspend {
3099 .base = undefined,
3100 .label = null,
3101 .suspend_token = *token,
3102 .payload = null,
3103 .body = null,
3104 }
3105 );
3106
3107 stack.append(State { .SuspendBody = node }) catch unreachable;
3108 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3109 return true;
3110 },
3111 Token.Id.Keyword_if => {
3112 const node = try self.createToCtxNode(arena, ctx, ast.Node.If,
3113 ast.Node.If {
3114 .base = undefined,
3115 .if_token = *token,
3116 .condition = undefined,
3117 .payload = null,
3118 .body = undefined,
3119 .@"else" = null,
3120 }
3121 );
3122
3123 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3124 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3125 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3126 try stack.append(State { .LookForSameLineComment = &node.condition });
3127 try stack.append(State { .ExpectToken = Token.Id.RParen });
3128 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3129 try stack.append(State { .ExpectToken = Token.Id.LParen });
3130 return true;
3131 },
3132 Token.Id.Keyword_while => {
3133 stack.append(State {
3134 .While = LoopCtx {
3135 .label = null,
3136 .inline_token = null,
3137 .loop_token = *token,
3138 .opt_ctx = *ctx,
3139 }
3140 }) catch unreachable;
3141 return true;
3142 },
3143 Token.Id.Keyword_for => {
3144 stack.append(State {
3145 .For = LoopCtx {
3146 .label = null,
3147 .inline_token = null,
3148 .loop_token = *token,
3149 .opt_ctx = *ctx,
3150 }
3151 }) catch unreachable;
3152 return true;
3153 },
3154 Token.Id.Keyword_switch => {
3155 const node = try arena.construct(ast.Node.Switch {
3156 .base = ast.Node {
3157 .id = ast.Node.Id.Switch,
3158 .same_line_comment = null,
3159 },
3160 .switch_token = *token,
3161 .expr = undefined,
3162 .cases = ArrayList(&ast.Node).init(arena),
3163 .rbrace = undefined,
3164 });
3165 ctx.store(&node.base);
3166
3167 stack.append(State {
3168 .SwitchCaseOrEnd = ListSave(&ast.Node) {
3169 .list = &node.cases,
3170 .ptr = &node.rbrace,
3171 },
3172 }) catch unreachable;
3173 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3174 try stack.append(State { .ExpectToken = Token.Id.RParen });
3175 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3176 try stack.append(State { .ExpectToken = Token.Id.LParen });
3177 return true;
3178 },
3179 Token.Id.Keyword_comptime => {
3180 const node = try self.createToCtxNode(arena, ctx, ast.Node.Comptime,
3181 ast.Node.Comptime {
3182 .base = undefined,
3183 .comptime_token = *token,
3184 .expr = undefined,
3185 .doc_comments = null,
3186 }
3187 );
3188 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3189 return true;
3190 },
3191 Token.Id.LBrace => {
3192 const block = try self.createToCtxNode(arena, ctx, ast.Node.Block,
3193 ast.Node.Block {
3194 .base = undefined,
3195 .label = null,
3196 .lbrace = *token,
3197 .statements = ArrayList(&ast.Node).init(arena),
3198 .rbrace = undefined,
3199 }
3200 );
3201 stack.append(State { .Block = block }) catch unreachable;
3202 return true;
3203 },
3204 else => {
3205 return false;
3206 }
3207 }
3208 }
3209
3210 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
3211 var token = self.getNextToken();
3212 switch (token.id) {
3213 Token.Id.Comma => return null,
3214 else => {
3215 if (end == token.id) {
3216 return token;
3217 }
3218
3219 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
3220 },
3221 }
3222 }
3223
3224 fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3225 // TODO: We have to cast all cases because of this:
3226 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3227 return switch (*id) {
3228 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = void{} },
3229 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = void{} },
3230 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = void{} },
3231 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = void{} },
3232 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = void{} },
3233 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = void{} },
3234 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = void{} },
3235 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = void{} },
3236 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = void{} },
3237 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = void{} },
3238 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = void{} },
3239 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = void{} },
3240 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = void{} },
3241 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = void{} },
3242 else => null,
3243 };
3244 }
3245
3246 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3247 return switch (id) {
3248 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3249 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3250 else => null,
3251 };
3252 }
3253
3254 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3255 return switch (id) {
3256 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3257 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3258 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3259 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3260 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3261 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3262 else => null,
3263 };
3264 }
3265
3266 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3267 return switch (id) {
3268 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3269 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3270 else => null,
3271 };
3272 }
3273
3274 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3275 return switch (id) {
3276 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3277 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3278 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3279 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3280 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3281 else => null,
3282 };
3283 }
3284
3285 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3286 return switch (id) {
3287 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3288 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3289 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3290 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3291 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3292 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3293 else => null,
3294 };
3295 }
3296
3297 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3298 return switch (id) {
3299 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3300 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3301 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3302 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3303 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3304 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3305 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3306 .align_expr = null,
3307 .bit_offset_start_token = null,
3308 .bit_offset_end_token = null,
3309 .const_token = null,
3310 .volatile_token = null,
3311 },
3312 },
3313 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3314 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3315 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3316 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3317 else => null,
3318 };
3319 }
3320
3321 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3322 const node = try arena.create(T);
3323 *node = *init_to;
3324 node.base = blk: {
3325 const id = ast.Node.typeToId(T);
3326 break :blk ast.Node {
3327 .id = id,
3328 .same_line_comment = null,
3329 };
3330 };
3331
3332 return node;
3333 }
3334
3335 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
3336 const node = try self.createNode(arena, T, init_to);
3337 try list.append(&node.base);
3338
3339 return node;
3340 }
3341
3342 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3343 const node = try self.createNode(arena, T, init_to);
3344 opt_ctx.store(&node.base);
3345
3346 return node;
3347 }
3348
3349 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
3350 return self.createNode(arena, T,
3351 T {
3352 .base = undefined,
3353 .token = *token,
3354 }
3355 );
3356 }
3357
3358 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3359 const node = try self.createLiteral(arena, T, token);
3360 opt_ctx.store(&node.base);
3361
3362 return node;
3363 }
3364
3365 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3366 const loc = self.tokenizer.getTokenLocation(0, token);
3367 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3368 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3369 {
3370 var i: usize = 0;
3371 while (i < loc.column) : (i += 1) {
3372 warn(" ");
3373 }
3374 }
3375 {
3376 const caret_count = token.end - token.start;
3377 var i: usize = 0;
3378 while (i < caret_count) : (i += 1) {
3379 warn("~");
3380 }
3381 }
3382 warn("\n");
3383 return error.ParseError;
3384 }
3385
3386 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
3387 const token = self.getNextToken();
3388 if (token.id != id) {
3389 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3390 }
3391 return token;
3392 }
3393
3394 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3395 if (self.isPeekToken(id)) {
3396 return self.getNextToken();
3397 }
3398 return null;
3399 }
3400
3401 fn putBackToken(self: &Parser, token: &const Token) void {
3402 self.put_back_tokens[self.put_back_count] = *token;
3403 self.put_back_count += 1;
3404 }
3405
3406 fn getNextToken(self: &Parser) Token {
3407 if (self.put_back_count != 0) {
3408 const put_back_index = self.put_back_count - 1;
3409 const put_back_token = self.put_back_tokens[put_back_index];
3410 self.put_back_count = put_back_index;
3411 return put_back_token;
3412 } else {
3413 return self.tokenizer.next();
3414 }
3415 }
3416
3417 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3418 const token = self.getNextToken();
3419 defer self.putBackToken(token);
3420 return id == token.id;
3421 }
3422
3423 const RenderAstFrame = struct {
3424 node: &ast.Node,
3425 indent: usize,
3426 };
3427
3428 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3429 var stack = self.initUtilityArrayList(RenderAstFrame);
3430 defer self.deinitUtilityArrayList(stack);
3431
3432 try stack.append(RenderAstFrame {
3433 .node = &root_node.base,
3434 .indent = 0,
3435 });
3436
3437 while (stack.popOrNull()) |frame| {
3438 {
3439 var i: usize = 0;
3440 while (i < frame.indent) : (i += 1) {
3441 try stream.print(" ");
3442 }
3443 }
3444 try stream.print("{}\n", @tagName(frame.node.id));
3445 var child_i: usize = 0;
3446 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3447 try stack.append(RenderAstFrame {
3448 .node = child,
3449 .indent = frame.indent + 2,
3450 });
3451 }
3452 }
3453 }
3454
3455 const RenderState = union(enum) {
3456 TopLevelDecl: &ast.Node,
3457 ParamDecl: &ast.Node,
3458 Text: []const u8,
3459 Expression: &ast.Node,
3460 VarDecl: &ast.Node.VarDecl,
3461 Statement: &ast.Node,
3462 PrintIndent,
3463 Indent: usize,
3464 PrintSameLineComment: ?&Token,
3465 PrintLineComment: &Token,
3466 };
3467
3468 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3469 var stack = self.initUtilityArrayList(RenderState);
3470 defer self.deinitUtilityArrayList(stack);
3471
3472 {
3473 try stack.append(RenderState { .Text = "\n"});
3474
3475 var i = root_node.decls.len;
3476 while (i != 0) {
3477 i -= 1;
3478 const decl = root_node.decls.items[i];
3479 try stack.append(RenderState {.TopLevelDecl = decl});
3480 if (i != 0) {
3481 try stack.append(RenderState {
3482 .Text = blk: {
3483 const prev_node = root_node.decls.at(i - 1);
3484 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
3485 if (loc.line >= 2) {
3486 break :blk "\n\n";
3487 }
3488 break :blk "\n";
3489 },
3490 });
3491 }
3492 }
3493 }
3494
3495 const indent_delta = 4;
3496 var indent: usize = 0;
3497 while (stack.popOrNull()) |state| {
3498 switch (state) {
3499 RenderState.TopLevelDecl => |decl| {
3500 try stack.append(RenderState { .PrintSameLineComment = decl.same_line_comment } );
3501 switch (decl.id) {
3502 ast.Node.Id.FnProto => {
3503 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3504 try self.renderComments(stream, fn_proto, indent);
3505
3506 if (fn_proto.body_node) |body_node| {
3507 stack.append(RenderState { .Expression = body_node}) catch unreachable;
3508 try stack.append(RenderState { .Text = " "});
3509 } else {
3510 stack.append(RenderState { .Text = ";" }) catch unreachable;
3511 }
3512
3513 try stack.append(RenderState { .Expression = decl });
3514 },
3515 ast.Node.Id.Use => {
3516 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
3517 if (use_decl.visib_token) |visib_token| {
3518 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3519 }
3520 try stream.print("use ");
3521 try stack.append(RenderState { .Text = ";" });
3522 try stack.append(RenderState { .Expression = use_decl.expr });
3523 },
3524 ast.Node.Id.VarDecl => {
3525 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
3526 try self.renderComments(stream, var_decl, indent);
3527 try stack.append(RenderState { .VarDecl = var_decl});
3528 },
3529 ast.Node.Id.TestDecl => {
3530 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3531 try self.renderComments(stream, test_decl, indent);
3532 try stream.print("test ");
3533 try stack.append(RenderState { .Expression = test_decl.body_node });
3534 try stack.append(RenderState { .Text = " " });
3535 try stack.append(RenderState { .Expression = test_decl.name });
3536 },
3537 ast.Node.Id.StructField => {
3538 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
3539 try self.renderComments(stream, field, indent);
3540 if (field.visib_token) |visib_token| {
3541 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3542 }
3543 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3544 try stack.append(RenderState { .Text = "," });
3545 try stack.append(RenderState { .Expression = field.type_expr});
3546 },
3547 ast.Node.Id.UnionTag => {
3548 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
3549 try self.renderComments(stream, tag, indent);
3550 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3551
3552 try stack.append(RenderState { .Text = "," });
3553
3554 if (tag.value_expr) |value_expr| {
3555 try stack.append(RenderState { .Expression = value_expr });
3556 try stack.append(RenderState { .Text = " = " });
3557 }
3558
3559 if (tag.type_expr) |type_expr| {
3560 try stream.print(": ");
3561 try stack.append(RenderState { .Expression = type_expr});
3562 }
3563 },
3564 ast.Node.Id.EnumTag => {
3565 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
3566 try self.renderComments(stream, tag, indent);
3567 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3568
3569 try stack.append(RenderState { .Text = "," });
3570 if (tag.value) |value| {
3571 try stream.print(" = ");
3572 try stack.append(RenderState { .Expression = value});
3573 }
3574 },
3575 ast.Node.Id.ErrorTag => {
3576 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
3577 try self.renderComments(stream, tag, indent);
3578 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3579 },
3580 ast.Node.Id.Comptime => {
3581 if (requireSemiColon(decl)) {
3582 try stack.append(RenderState { .Text = ";" });
3583 }
3584 try stack.append(RenderState { .Expression = decl });
3585 },
3586 ast.Node.Id.LineComment => {
3587 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
3588 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
3589 },
3590 else => unreachable,
3591 }
3592 },
3593
3594 RenderState.VarDecl => |var_decl| {
3595 try stack.append(RenderState { .Text = ";" });
3596 if (var_decl.init_node) |init_node| {
3597 try stack.append(RenderState { .Expression = init_node });
3598 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
3599 try stack.append(RenderState { .Text = text });
3600 }
3601 if (var_decl.align_node) |align_node| {
3602 try stack.append(RenderState { .Text = ")" });
3603 try stack.append(RenderState { .Expression = align_node });
3604 try stack.append(RenderState { .Text = " align(" });
3605 }
3606 if (var_decl.type_node) |type_node| {
3607 try stack.append(RenderState { .Expression = type_node });
3608 try stack.append(RenderState { .Text = ": " });
3609 }
3610 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3611 try stack.append(RenderState { .Text = " " });
3612 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3613
3614 if (var_decl.comptime_token) |comptime_token| {
3615 try stack.append(RenderState { .Text = " " });
3616 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3617 }
3618
3619 if (var_decl.extern_export_token) |extern_export_token| {
3620 if (var_decl.lib_name != null) {
3621 try stack.append(RenderState { .Text = " " });
3622 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3623 }
3624 try stack.append(RenderState { .Text = " " });
3625 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
3626 }
3627
3628 if (var_decl.visib_token) |visib_token| {
3629 try stack.append(RenderState { .Text = " " });
3630 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3631 }
3632 },
3633
3634 RenderState.ParamDecl => |base| {
3635 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
3636 if (param_decl.comptime_token) |comptime_token| {
3637 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
3638 }
3639 if (param_decl.noalias_token) |noalias_token| {
3640 try stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token));
3641 }
3642 if (param_decl.name_token) |name_token| {
3643 try stream.print("{}: ", self.tokenizer.getTokenSlice(name_token));
3644 }
3645 if (param_decl.var_args_token) |var_args_token| {
3646 try stream.print("{}", self.tokenizer.getTokenSlice(var_args_token));
3647 } else {
3648 try stack.append(RenderState { .Expression = param_decl.type_node});
3649 }
3650 },
3651 RenderState.Text => |bytes| {
3652 try stream.write(bytes);
3653 },
3654 RenderState.Expression => |base| switch (base.id) {
3655 ast.Node.Id.Identifier => {
3656 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
3657 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
3658 },
3659 ast.Node.Id.Block => {
3660 const block = @fieldParentPtr(ast.Node.Block, "base", base);
3661 if (block.label) |label| {
3662 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3663 }
3664
3665 if (block.statements.len == 0) {
3666 try stream.write("{}");
3667 } else {
3668 try stream.write("{");
3669 try stack.append(RenderState { .Text = "}"});
3670 try stack.append(RenderState.PrintIndent);
3671 try stack.append(RenderState { .Indent = indent});
3672 try stack.append(RenderState { .Text = "\n"});
3673 var i = block.statements.len;
3674 while (i != 0) {
3675 i -= 1;
3676 const statement_node = block.statements.items[i];
3677 try stack.append(RenderState { .Statement = statement_node});
3678 try stack.append(RenderState.PrintIndent);
3679 try stack.append(RenderState { .Indent = indent + indent_delta});
3680 try stack.append(RenderState {
3681 .Text = blk: {
3682 if (i != 0) {
3683 const prev_node = block.statements.items[i - 1];
3684 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
3685 if (loc.line >= 2) {
3686 break :blk "\n\n";
3687 }
3688 }
3689 break :blk "\n";
3690 },
3691 });
3692 }
3693 }
3694 },
3695 ast.Node.Id.Defer => {
3696 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
3697 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3698 try stack.append(RenderState { .Expression = defer_node.expr });
3699 },
3700 ast.Node.Id.Comptime => {
3701 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
3702 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3703 try stack.append(RenderState { .Expression = comptime_node.expr });
3704 },
3705 ast.Node.Id.AsyncAttribute => {
3706 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
3707 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3708
3709 if (async_attr.allocator_type) |allocator_type| {
3710 try stack.append(RenderState { .Text = ">" });
3711 try stack.append(RenderState { .Expression = allocator_type });
3712 try stack.append(RenderState { .Text = "<" });
3713 }
3714 },
3715 ast.Node.Id.Suspend => {
3716 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
3717 if (suspend_node.label) |label| {
3718 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3719 }
3720 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3721
3722 if (suspend_node.body) |body| {
3723 try stack.append(RenderState { .Expression = body });
3724 try stack.append(RenderState { .Text = " " });
3725 }
3726
3727 if (suspend_node.payload) |payload| {
3728 try stack.append(RenderState { .Expression = payload });
3729 try stack.append(RenderState { .Text = " " });
3730 }
3731 },
3732 ast.Node.Id.InfixOp => {
3733 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
3734 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3735
3736 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
3737 if (prefix_op_node.op.Catch) |payload| {
3738 try stack.append(RenderState { .Text = " " });
3739 try stack.append(RenderState { .Expression = payload });
3740 }
3741 try stack.append(RenderState { .Text = " catch " });
3742 } else {
3743 const text = switch (prefix_op_node.op) {
3744 ast.Node.InfixOp.Op.Add => " + ",
3745 ast.Node.InfixOp.Op.AddWrap => " +% ",
3746 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
3747 ast.Node.InfixOp.Op.ArrayMult => " ** ",
3748 ast.Node.InfixOp.Op.Assign => " = ",
3749 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
3750 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
3751 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
3752 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
3753 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
3754 ast.Node.InfixOp.Op.AssignDiv => " /= ",
3755 ast.Node.InfixOp.Op.AssignMinus => " -= ",
3756 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
3757 ast.Node.InfixOp.Op.AssignMod => " %= ",
3758 ast.Node.InfixOp.Op.AssignPlus => " += ",
3759 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
3760 ast.Node.InfixOp.Op.AssignTimes => " *= ",
3761 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
3762 ast.Node.InfixOp.Op.BangEqual => " != ",
3763 ast.Node.InfixOp.Op.BitAnd => " & ",
3764 ast.Node.InfixOp.Op.BitOr => " | ",
3765 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
3766 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
3767 ast.Node.InfixOp.Op.BitXor => " ^ ",
3768 ast.Node.InfixOp.Op.BoolAnd => " and ",
3769 ast.Node.InfixOp.Op.BoolOr => " or ",
3770 ast.Node.InfixOp.Op.Div => " / ",
3771 ast.Node.InfixOp.Op.EqualEqual => " == ",
3772 ast.Node.InfixOp.Op.ErrorUnion => "!",
3773 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
3774 ast.Node.InfixOp.Op.GreaterThan => " > ",
3775 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
3776 ast.Node.InfixOp.Op.LessThan => " < ",
3777 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
3778 ast.Node.InfixOp.Op.Mod => " % ",
3779 ast.Node.InfixOp.Op.Mult => " * ",
3780 ast.Node.InfixOp.Op.MultWrap => " *% ",
3781 ast.Node.InfixOp.Op.Period => ".",
3782 ast.Node.InfixOp.Op.Sub => " - ",
3783 ast.Node.InfixOp.Op.SubWrap => " -% ",
3784 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
3785 ast.Node.InfixOp.Op.Range => " ... ",
3786 ast.Node.InfixOp.Op.Catch => unreachable,
3787 };
3788
3789 try stack.append(RenderState { .Text = text });
3790 }
3791 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
3792 },
3793 ast.Node.Id.PrefixOp => {
3794 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
3795 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3796 switch (prefix_op_node.op) {
3797 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
3798 try stream.write("&");
3799 if (addr_of_info.volatile_token != null) {
3800 try stack.append(RenderState { .Text = "volatile "});
3801 }
3802 if (addr_of_info.const_token != null) {
3803 try stack.append(RenderState { .Text = "const "});
3804 }
3805 if (addr_of_info.align_expr) |align_expr| {
3806 try stream.print("align(");
3807 try stack.append(RenderState { .Text = ") "});
3808 try stack.append(RenderState { .Expression = align_expr});
3809 }
3810 },
3811 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
3812 try stream.write("[]");
3813 if (addr_of_info.volatile_token != null) {
3814 try stack.append(RenderState { .Text = "volatile "});
3815 }
3816 if (addr_of_info.const_token != null) {
3817 try stack.append(RenderState { .Text = "const "});
3818 }
3819 if (addr_of_info.align_expr) |align_expr| {
3820 try stream.print("align(");
3821 try stack.append(RenderState { .Text = ") "});
3822 try stack.append(RenderState { .Expression = align_expr});
3823 }
3824 },
3825 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
3826 try stack.append(RenderState { .Text = "]"});
3827 try stack.append(RenderState { .Expression = array_index});
3828 try stack.append(RenderState { .Text = "["});
3829 },
3830 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
3831 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
3832 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
3833 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
3834 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
3835 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
3836 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
3837 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
3838 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
3839 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
3840 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
3841 }
3842 },
3843 ast.Node.Id.SuffixOp => {
3844 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
3845
3846 switch (suffix_op.op) {
3847 ast.Node.SuffixOp.Op.Call => |call_info| {
3848 try stack.append(RenderState { .Text = ")"});
3849 var i = call_info.params.len;
3850 while (i != 0) {
3851 i -= 1;
3852 const param_node = call_info.params.at(i);
3853 try stack.append(RenderState { .Expression = param_node});
3854 if (i != 0) {
3855 try stack.append(RenderState { .Text = ", " });
3856 }
3857 }
3858 try stack.append(RenderState { .Text = "("});
3859 try stack.append(RenderState { .Expression = suffix_op.lhs });
3860
3861 if (call_info.async_attr) |async_attr| {
3862 try stack.append(RenderState { .Text = " "});
3863 try stack.append(RenderState { .Expression = &async_attr.base });
3864 }
3865 },
3866 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
3867 try stack.append(RenderState { .Text = "]"});
3868 try stack.append(RenderState { .Expression = index_expr});
3869 try stack.append(RenderState { .Text = "["});
3870 try stack.append(RenderState { .Expression = suffix_op.lhs });
3871 },
3872 ast.Node.SuffixOp.Op.Slice => |range| {
3873 try stack.append(RenderState { .Text = "]"});
3874 if (range.end) |end| {
3875 try stack.append(RenderState { .Expression = end});
3876 }
3877 try stack.append(RenderState { .Text = ".."});
3878 try stack.append(RenderState { .Expression = range.start});
3879 try stack.append(RenderState { .Text = "["});
3880 try stack.append(RenderState { .Expression = suffix_op.lhs });
3881 },
3882 ast.Node.SuffixOp.Op.StructInitializer => |field_inits| {
3883 if (field_inits.len == 0) {
3884 try stack.append(RenderState { .Text = "{}" });
3885 try stack.append(RenderState { .Expression = suffix_op.lhs });
3886 continue;
3887 }
3888 if (field_inits.len == 1) {
3889 const field_init = field_inits.at(0);
3890
3891 try stack.append(RenderState { .Text = " }" });
3892 try stack.append(RenderState { .Expression = field_init });
3893 try stack.append(RenderState { .Text = "{ " });
3894 try stack.append(RenderState { .Expression = suffix_op.lhs });
3895 continue;
3896 }
3897 try stack.append(RenderState { .Text = "}"});
3898 try stack.append(RenderState.PrintIndent);
3899 try stack.append(RenderState { .Indent = indent });
3900 try stack.append(RenderState { .Text = "\n" });
3901 var i = field_inits.len;
3902 while (i != 0) {
3903 i -= 1;
3904 const field_init = field_inits.at(i);
3905 if (field_init.id != ast.Node.Id.LineComment) {
3906 try stack.append(RenderState { .Text = "," });
3907 }
3908 try stack.append(RenderState { .Expression = field_init });
3909 try stack.append(RenderState.PrintIndent);
3910 if (i != 0) {
3911 try stack.append(RenderState { .Text = blk: {
3912 const prev_node = field_inits.at(i - 1);
3913 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, field_init.firstToken());
3914 if (loc.line >= 2) {
3915 break :blk "\n\n";
3916 }
3917 break :blk "\n";
3918 }});
3919 }
3920 }
3921 try stack.append(RenderState { .Indent = indent + indent_delta });
3922 try stack.append(RenderState { .Text = "{\n"});
3923 try stack.append(RenderState { .Expression = suffix_op.lhs });
3924 },
3925 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
3926 if (exprs.len == 0) {
3927 try stack.append(RenderState { .Text = "{}" });
3928 try stack.append(RenderState { .Expression = suffix_op.lhs });
3929 continue;
3930 }
3931 if (exprs.len == 1) {
3932 const expr = exprs.at(0);
3933
3934 try stack.append(RenderState { .Text = "}" });
3935 try stack.append(RenderState { .Expression = expr });
3936 try stack.append(RenderState { .Text = "{" });
3937 try stack.append(RenderState { .Expression = suffix_op.lhs });
3938 continue;
3939 }
3940
3941 try stack.append(RenderState { .Text = "}"});
3942 try stack.append(RenderState.PrintIndent);
3943 try stack.append(RenderState { .Indent = indent });
3944 var i = exprs.len;
3945 while (i != 0) {
3946 i -= 1;
3947 const expr = exprs.at(i);
3948 try stack.append(RenderState { .Text = ",\n" });
3949 try stack.append(RenderState { .Expression = expr });
3950 try stack.append(RenderState.PrintIndent);
3951 }
3952 try stack.append(RenderState { .Indent = indent + indent_delta });
3953 try stack.append(RenderState { .Text = "{\n"});
3954 try stack.append(RenderState { .Expression = suffix_op.lhs });
3955 },
3956 }
3957 },
3958 ast.Node.Id.ControlFlowExpression => {
3959 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
3960
3961 if (flow_expr.rhs) |rhs| {
3962 try stack.append(RenderState { .Expression = rhs });
3963 try stack.append(RenderState { .Text = " " });
3964 }
3965
3966 switch (flow_expr.kind) {
3967 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
3968 try stream.print("break");
3969 if (maybe_label) |label| {
3970 try stream.print(" :");
3971 try stack.append(RenderState { .Expression = label });
3972 }
3973 },
3974 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
3975 try stream.print("continue");
3976 if (maybe_label) |label| {
3977 try stream.print(" :");
3978 try stack.append(RenderState { .Expression = label });
3979 }
3980 },
3981 ast.Node.ControlFlowExpression.Kind.Return => {
3982 try stream.print("return");
3983 },
3984
3985 }
3986 },
3987 ast.Node.Id.Payload => {
3988 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
3989 try stack.append(RenderState { .Text = "|"});
3990 try stack.append(RenderState { .Expression = payload.error_symbol });
3991 try stack.append(RenderState { .Text = "|"});
3992 },
3993 ast.Node.Id.PointerPayload => {
3994 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
3995 try stack.append(RenderState { .Text = "|"});
3996 try stack.append(RenderState { .Expression = payload.value_symbol });
3997
3998 if (payload.ptr_token) |ptr_token| {
3999 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
4000 }
4001
4002 try stack.append(RenderState { .Text = "|"});
4003 },
4004 ast.Node.Id.PointerIndexPayload => {
4005 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
4006 try stack.append(RenderState { .Text = "|"});
4007
4008 if (payload.index_symbol) |index_symbol| {
4009 try stack.append(RenderState { .Expression = index_symbol });
4010 try stack.append(RenderState { .Text = ", "});
4011 }
4012
4013 try stack.append(RenderState { .Expression = payload.value_symbol });
4014
4015 if (payload.ptr_token) |ptr_token| {
4016 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
4017 }
4018
4019 try stack.append(RenderState { .Text = "|"});
4020 },
4021 ast.Node.Id.GroupedExpression => {
4022 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
4023 try stack.append(RenderState { .Text = ")"});
4024 try stack.append(RenderState { .Expression = grouped_expr.expr });
4025 try stack.append(RenderState { .Text = "("});
4026 },
4027 ast.Node.Id.FieldInitializer => {
4028 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
4029 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
4030 try stack.append(RenderState { .Expression = field_init.expr });
4031 },
4032 ast.Node.Id.IntegerLiteral => {
4033 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
4034 try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
4035 },
4036 ast.Node.Id.FloatLiteral => {
4037 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
4038 try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
4039 },
4040 ast.Node.Id.StringLiteral => {
4041 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
4042 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
4043 },
4044 ast.Node.Id.CharLiteral => {
4045 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4046 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
4047 },
4048 ast.Node.Id.BoolLiteral => {
4049 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4050 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
4051 },
4052 ast.Node.Id.NullLiteral => {
4053 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
4054 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
4055 },
4056 ast.Node.Id.ThisLiteral => {
4057 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
4058 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
4059 },
4060 ast.Node.Id.Unreachable => {
4061 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
4062 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
4063 },
4064 ast.Node.Id.ErrorType => {
4065 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
4066 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
4067 },
4068 ast.Node.Id.VarType => {
4069 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
4070 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
4071 },
4072 ast.Node.Id.ContainerDecl => {
4073 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
4074
4075 switch (container_decl.layout) {
4076 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
4077 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
4078 ast.Node.ContainerDecl.Layout.Auto => { },
4079 }
4080
4081 switch (container_decl.kind) {
4082 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
4083 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
4084 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
4085 }
4086
4087 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
4088 if (fields_and_decls.len == 0) {
4089 try stack.append(RenderState { .Text = "{}"});
4090 } else {
4091 try stack.append(RenderState { .Text = "}"});
4092 try stack.append(RenderState.PrintIndent);
4093 try stack.append(RenderState { .Indent = indent });
4094 try stack.append(RenderState { .Text = "\n"});
4095
4096 var i = fields_and_decls.len;
4097 while (i != 0) {
4098 i -= 1;
4099 const node = fields_and_decls[i];
4100 try stack.append(RenderState { .TopLevelDecl = node});
4101 try stack.append(RenderState.PrintIndent);
4102 try stack.append(RenderState {
4103 .Text = blk: {
4104 if (i != 0) {
4105 const prev_node = fields_and_decls[i - 1];
4106 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4107 if (loc.line >= 2) {
4108 break :blk "\n\n";
4109 }
4110 }
4111 break :blk "\n";
4112 },
4113 });
4114 }
4115 try stack.append(RenderState { .Indent = indent + indent_delta});
4116 try stack.append(RenderState { .Text = "{"});
4117 }
4118
4119 switch (container_decl.init_arg_expr) {
4120 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
4121 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
4122 if (enum_tag_type) |expr| {
4123 try stack.append(RenderState { .Text = ")) "});
4124 try stack.append(RenderState { .Expression = expr});
4125 try stack.append(RenderState { .Text = "(enum("});
4126 } else {
4127 try stack.append(RenderState { .Text = "(enum) "});
4128 }
4129 },
4130 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
4131 try stack.append(RenderState { .Text = ") "});
4132 try stack.append(RenderState { .Expression = type_expr});
4133 try stack.append(RenderState { .Text = "("});
4134 },
4135 }
4136 },
4137 ast.Node.Id.ErrorSetDecl => {
4138 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
4139
4140 const decls = err_set_decl.decls.toSliceConst();
4141 if (decls.len == 0) {
4142 try stream.write("error{}");
4143 continue;
4144 }
4145
4146 if (decls.len == 1) blk: {
4147 const node = decls[0];
4148
4149 // if there are any doc comments or same line comments
4150 // don't try to put it all on one line
4151 if (node.same_line_comment != null) break :blk;
4152 if (node.cast(ast.Node.ErrorTag)) |tag| {
4153 if (tag.doc_comments != null) break :blk;
4154 } else {
4155 break :blk;
4156 }
4157
4158
4159 try stream.write("error{");
4160 try stack.append(RenderState { .Text = "}" });
4161 try stack.append(RenderState { .TopLevelDecl = node });
4162 continue;
4163 }
4164
4165 try stream.write("error{");
4166
4167 try stack.append(RenderState { .Text = "}"});
4168 try stack.append(RenderState.PrintIndent);
4169 try stack.append(RenderState { .Indent = indent });
4170 try stack.append(RenderState { .Text = "\n"});
4171
4172 var i = decls.len;
4173 while (i != 0) {
4174 i -= 1;
4175 const node = decls[i];
4176 if (node.id != ast.Node.Id.LineComment) {
4177 try stack.append(RenderState { .Text = "," });
4178 }
4179 try stack.append(RenderState { .TopLevelDecl = node });
4180 try stack.append(RenderState.PrintIndent);
4181 try stack.append(RenderState {
4182 .Text = blk: {
4183 if (i != 0) {
4184 const prev_node = decls[i - 1];
4185 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4186 if (loc.line >= 2) {
4187 break :blk "\n\n";
4188 }
4189 }
4190 break :blk "\n";
4191 },
4192 });
4193 }
4194 try stack.append(RenderState { .Indent = indent + indent_delta});
4195 },
4196 ast.Node.Id.MultilineStringLiteral => {
4197 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
4198 try stream.print("\n");
4199
4200 var i : usize = 0;
4201 while (i < multiline_str_literal.tokens.len) : (i += 1) {
4202 const t = multiline_str_literal.tokens.at(i);
4203 try stream.writeByteNTimes(' ', indent + indent_delta);
4204 try stream.print("{}", self.tokenizer.getTokenSlice(t));
4205 }
4206 try stream.writeByteNTimes(' ', indent);
4207 },
4208 ast.Node.Id.UndefinedLiteral => {
4209 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
4210 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
4211 },
4212 ast.Node.Id.BuiltinCall => {
4213 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
4214 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
4215 try stack.append(RenderState { .Text = ")"});
4216 var i = builtin_call.params.len;
4217 while (i != 0) {
4218 i -= 1;
4219 const param_node = builtin_call.params.at(i);
4220 try stack.append(RenderState { .Expression = param_node});
4221 if (i != 0) {
4222 try stack.append(RenderState { .Text = ", " });
4223 }
4224 }
4225 },
4226 ast.Node.Id.FnProto => {
4227 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
4228
4229 switch (fn_proto.return_type) {
4230 ast.Node.FnProto.ReturnType.Explicit => |node| {
4231 try stack.append(RenderState { .Expression = node});
4232 },
4233 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
4234 try stack.append(RenderState { .Expression = node});
4235 try stack.append(RenderState { .Text = "!"});
4236 },
4237 }
4238
4239 if (fn_proto.align_expr) |align_expr| {
4240 try stack.append(RenderState { .Text = ") " });
4241 try stack.append(RenderState { .Expression = align_expr});
4242 try stack.append(RenderState { .Text = "align(" });
4243 }
4244
4245 try stack.append(RenderState { .Text = ") " });
4246 var i = fn_proto.params.len;
4247 while (i != 0) {
4248 i -= 1;
4249 const param_decl_node = fn_proto.params.items[i];
4250 try stack.append(RenderState { .ParamDecl = param_decl_node});
4251 if (i != 0) {
4252 try stack.append(RenderState { .Text = ", " });
4253 }
4254 }
4255
4256 try stack.append(RenderState { .Text = "(" });
4257 if (fn_proto.name_token) |name_token| {
4258 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
4259 try stack.append(RenderState { .Text = " " });
4260 }
4261
4262 try stack.append(RenderState { .Text = "fn" });
4263
4264 if (fn_proto.async_attr) |async_attr| {
4265 try stack.append(RenderState { .Text = " " });
4266 try stack.append(RenderState { .Expression = &async_attr.base });
4267 }
4268
4269 if (fn_proto.cc_token) |cc_token| {
4270 try stack.append(RenderState { .Text = " " });
4271 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
4272 }
4273
4274 if (fn_proto.lib_name) |lib_name| {
4275 try stack.append(RenderState { .Text = " " });
4276 try stack.append(RenderState { .Expression = lib_name });
4277 }
4278 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
4279 try stack.append(RenderState { .Text = " " });
4280 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
4281 }
4282
4283 if (fn_proto.visib_token) |visib_token| {
4284 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
4285 try stack.append(RenderState { .Text = " " });
4286 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
4287 }
4288 },
4289 ast.Node.Id.PromiseType => {
4290 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
4291 try stream.write(self.tokenizer.getTokenSlice(promise_type.promise_token));
4292 if (promise_type.result) |result| {
4293 try stream.write(self.tokenizer.getTokenSlice(result.arrow_token));
4294 try stack.append(RenderState { .Expression = result.return_type});
4295 }
4296 },
4297 ast.Node.Id.LineComment => {
4298 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
4299 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
4300 },
4301 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
4302 ast.Node.Id.Switch => {
4303 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
4304 const cases = switch_node.cases.toSliceConst();
4305
4306 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
4307
4308 if (cases.len == 0) {
4309 try stack.append(RenderState { .Text = ") {}"});
4310 try stack.append(RenderState { .Expression = switch_node.expr });
4311 continue;
4312 }
4313
4314 try stack.append(RenderState { .Text = "}"});
4315 try stack.append(RenderState.PrintIndent);
4316 try stack.append(RenderState { .Indent = indent });
4317 try stack.append(RenderState { .Text = "\n"});
4318
4319 var i = cases.len;
4320 while (i != 0) {
4321 i -= 1;
4322 const node = cases[i];
4323 try stack.append(RenderState { .Expression = node});
4324 try stack.append(RenderState.PrintIndent);
4325 try stack.append(RenderState {
4326 .Text = blk: {
4327 if (i != 0) {
4328 const prev_node = cases[i - 1];
4329 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4330 if (loc.line >= 2) {
4331 break :blk "\n\n";
4332 }
4333 }
4334 break :blk "\n";
4335 },
4336 });
4337 }
4338 try stack.append(RenderState { .Indent = indent + indent_delta});
4339 try stack.append(RenderState { .Text = ") {"});
4340 try stack.append(RenderState { .Expression = switch_node.expr });
4341 },
4342 ast.Node.Id.SwitchCase => {
4343 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
4344
4345 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment });
4346 try stack.append(RenderState { .Text = "," });
4347 try stack.append(RenderState { .Expression = switch_case.expr });
4348 if (switch_case.payload) |payload| {
4349 try stack.append(RenderState { .Text = " " });
4350 try stack.append(RenderState { .Expression = payload });
4351 }
4352 try stack.append(RenderState { .Text = " => "});
4353
4354 const items = switch_case.items.toSliceConst();
4355 var i = items.len;
4356 while (i != 0) {
4357 i -= 1;
4358 try stack.append(RenderState { .Expression = items[i] });
4359
4360 if (i != 0) {
4361 try stack.append(RenderState.PrintIndent);
4362 try stack.append(RenderState { .Text = ",\n" });
4363 }
4364 }
4365 },
4366 ast.Node.Id.SwitchElse => {
4367 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
4368 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
4369 },
4370 ast.Node.Id.Else => {
4371 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
4372 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
4373
4374 switch (else_node.body.id) {
4375 ast.Node.Id.Block, ast.Node.Id.If,
4376 ast.Node.Id.For, ast.Node.Id.While,
4377 ast.Node.Id.Switch => {
4378 try stream.print(" ");
4379 try stack.append(RenderState { .Expression = else_node.body });
4380 },
4381 else => {
4382 try stack.append(RenderState { .Indent = indent });
4383 try stack.append(RenderState { .Expression = else_node.body });
4384 try stack.append(RenderState.PrintIndent);
4385 try stack.append(RenderState { .Indent = indent + indent_delta });
4386 try stack.append(RenderState { .Text = "\n" });
4387 }
4388 }
4389
4390 if (else_node.payload) |payload| {
4391 try stack.append(RenderState { .Text = " " });
4392 try stack.append(RenderState { .Expression = payload });
4393 }
4394 },
4395 ast.Node.Id.While => {
4396 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
4397 if (while_node.label) |label| {
4398 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4399 }
4400
4401 if (while_node.inline_token) |inline_token| {
4402 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4403 }
4404
4405 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
4406
4407 if (while_node.@"else") |@"else"| {
4408 try stack.append(RenderState { .Expression = &@"else".base });
4409
4410 if (while_node.body.id == ast.Node.Id.Block) {
4411 try stack.append(RenderState { .Text = " " });
4412 } else {
4413 try stack.append(RenderState.PrintIndent);
4414 try stack.append(RenderState { .Text = "\n" });
4415 }
4416 }
4417
4418 if (while_node.body.id == ast.Node.Id.Block) {
4419 try stack.append(RenderState { .Expression = while_node.body });
4420 try stack.append(RenderState { .Text = " " });
4421 } else {
4422 try stack.append(RenderState { .Indent = indent });
4423 try stack.append(RenderState { .Expression = while_node.body });
4424 try stack.append(RenderState.PrintIndent);
4425 try stack.append(RenderState { .Indent = indent + indent_delta });
4426 try stack.append(RenderState { .Text = "\n" });
4427 }
4428
4429 if (while_node.continue_expr) |continue_expr| {
4430 try stack.append(RenderState { .Text = ")" });
4431 try stack.append(RenderState { .Expression = continue_expr });
4432 try stack.append(RenderState { .Text = ": (" });
4433 try stack.append(RenderState { .Text = " " });
4434 }
4435
4436 if (while_node.payload) |payload| {
4437 try stack.append(RenderState { .Expression = payload });
4438 try stack.append(RenderState { .Text = " " });
4439 }
4440
4441 try stack.append(RenderState { .Text = ")" });
4442 try stack.append(RenderState { .Expression = while_node.condition });
4443 try stack.append(RenderState { .Text = "(" });
4444 },
4445 ast.Node.Id.For => {
4446 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
4447 if (for_node.label) |label| {
4448 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4449 }
4450
4451 if (for_node.inline_token) |inline_token| {
4452 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4453 }
4454
4455 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
4456
4457 if (for_node.@"else") |@"else"| {
4458 try stack.append(RenderState { .Expression = &@"else".base });
4459
4460 if (for_node.body.id == ast.Node.Id.Block) {
4461 try stack.append(RenderState { .Text = " " });
4462 } else {
4463 try stack.append(RenderState.PrintIndent);
4464 try stack.append(RenderState { .Text = "\n" });
4465 }
4466 }
4467
4468 if (for_node.body.id == ast.Node.Id.Block) {
4469 try stack.append(RenderState { .Expression = for_node.body });
4470 try stack.append(RenderState { .Text = " " });
4471 } else {
4472 try stack.append(RenderState { .Indent = indent });
4473 try stack.append(RenderState { .Expression = for_node.body });
4474 try stack.append(RenderState.PrintIndent);
4475 try stack.append(RenderState { .Indent = indent + indent_delta });
4476 try stack.append(RenderState { .Text = "\n" });
4477 }
4478
4479 if (for_node.payload) |payload| {
4480 try stack.append(RenderState { .Expression = payload });
4481 try stack.append(RenderState { .Text = " " });
4482 }
4483
4484 try stack.append(RenderState { .Text = ")" });
4485 try stack.append(RenderState { .Expression = for_node.array_expr });
4486 try stack.append(RenderState { .Text = "(" });
4487 },
4488 ast.Node.Id.If => {
4489 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
4490 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
4491
4492 switch (if_node.body.id) {
4493 ast.Node.Id.Block, ast.Node.Id.If,
4494 ast.Node.Id.For, ast.Node.Id.While,
4495 ast.Node.Id.Switch => {
4496 if (if_node.@"else") |@"else"| {
4497 try stack.append(RenderState { .Expression = &@"else".base });
4498
4499 if (if_node.body.id == ast.Node.Id.Block) {
4500 try stack.append(RenderState { .Text = " " });
4501 } else {
4502 try stack.append(RenderState.PrintIndent);
4503 try stack.append(RenderState { .Text = "\n" });
4504 }
4505 }
4506 },
4507 else => {
4508 if (if_node.@"else") |@"else"| {
4509 try stack.append(RenderState { .Expression = @"else".body });
4510
4511 if (@"else".payload) |payload| {
4512 try stack.append(RenderState { .Text = " " });
4513 try stack.append(RenderState { .Expression = payload });
4514 }
4515
4516 try stack.append(RenderState { .Text = " " });
4517 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
4518 try stack.append(RenderState { .Text = " " });
4519 }
4520 }
4521 }
4522
4523 if (if_node.condition.same_line_comment) |comment| {
4524 try stack.append(RenderState { .Indent = indent });
4525 try stack.append(RenderState { .Expression = if_node.body });
4526 try stack.append(RenderState.PrintIndent);
4527 try stack.append(RenderState { .Indent = indent + indent_delta });
4528 try stack.append(RenderState { .Text = "\n" });
4529 try stack.append(RenderState { .PrintLineComment = comment });
4530 } else {
4531 try stack.append(RenderState { .Expression = if_node.body });
4532 }
4533
4534
4535 try stack.append(RenderState { .Text = " " });
4536
4537 if (if_node.payload) |payload| {
4538 try stack.append(RenderState { .Expression = payload });
4539 try stack.append(RenderState { .Text = " " });
4540 }
4541
4542 try stack.append(RenderState { .Text = ")" });
4543 try stack.append(RenderState { .Expression = if_node.condition });
4544 try stack.append(RenderState { .Text = "(" });
4545 },
4546 ast.Node.Id.Asm => {
4547 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
4548 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4549
4550 if (asm_node.volatile_token) |volatile_token| {
4551 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
4552 }
4553
4554 try stack.append(RenderState { .Indent = indent });
4555 try stack.append(RenderState { .Text = ")" });
4556 {
4557 const cloppers = asm_node.cloppers.toSliceConst();
4558 var i = cloppers.len;
4559 while (i != 0) {
4560 i -= 1;
4561 try stack.append(RenderState { .Expression = cloppers[i] });
4562
4563 if (i != 0) {
4564 try stack.append(RenderState { .Text = ", " });
4565 }
4566 }
4567 }
4568 try stack.append(RenderState { .Text = ": " });
4569 try stack.append(RenderState.PrintIndent);
4570 try stack.append(RenderState { .Indent = indent + indent_delta });
4571 try stack.append(RenderState { .Text = "\n" });
4572 {
4573 const inputs = asm_node.inputs.toSliceConst();
4574 var i = inputs.len;
4575 while (i != 0) {
4576 i -= 1;
4577 const node = inputs[i];
4578 try stack.append(RenderState { .Expression = &node.base});
4579
4580 if (i != 0) {
4581 try stack.append(RenderState.PrintIndent);
4582 try stack.append(RenderState {
4583 .Text = blk: {
4584 const prev_node = inputs[i - 1];
4585 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4586 if (loc.line >= 2) {
4587 break :blk "\n\n";
4588 }
4589 break :blk "\n";
4590 },
4591 });
4592 try stack.append(RenderState { .Text = "," });
4593 }
4594 }
4595 }
4596 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4597 try stack.append(RenderState { .Text = ": "});
4598 try stack.append(RenderState.PrintIndent);
4599 try stack.append(RenderState { .Indent = indent + indent_delta});
4600 try stack.append(RenderState { .Text = "\n" });
4601 {
4602 const outputs = asm_node.outputs.toSliceConst();
4603 var i = outputs.len;
4604 while (i != 0) {
4605 i -= 1;
4606 const node = outputs[i];
4607 try stack.append(RenderState { .Expression = &node.base});
4608
4609 if (i != 0) {
4610 try stack.append(RenderState.PrintIndent);
4611 try stack.append(RenderState {
4612 .Text = blk: {
4613 const prev_node = outputs[i - 1];
4614 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4615 if (loc.line >= 2) {
4616 break :blk "\n\n";
4617 }
4618 break :blk "\n";
4619 },
4620 });
4621 try stack.append(RenderState { .Text = "," });
4622 }
4623 }
4624 }
4625 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4626 try stack.append(RenderState { .Text = ": "});
4627 try stack.append(RenderState.PrintIndent);
4628 try stack.append(RenderState { .Indent = indent + indent_delta});
4629 try stack.append(RenderState { .Text = "\n" });
4630 try stack.append(RenderState { .Expression = asm_node.template });
4631 try stack.append(RenderState { .Text = "(" });
4632 },
4633 ast.Node.Id.AsmInput => {
4634 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
4635
4636 try stack.append(RenderState { .Text = ")"});
4637 try stack.append(RenderState { .Expression = asm_input.expr});
4638 try stack.append(RenderState { .Text = " ("});
4639 try stack.append(RenderState { .Expression = asm_input.constraint });
4640 try stack.append(RenderState { .Text = "] "});
4641 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
4642 try stack.append(RenderState { .Text = "["});
4643 },
4644 ast.Node.Id.AsmOutput => {
4645 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
4646
4647 try stack.append(RenderState { .Text = ")"});
4648 switch (asm_output.kind) {
4649 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
4650 try stack.append(RenderState { .Expression = &variable_name.base});
4651 },
4652 ast.Node.AsmOutput.Kind.Return => |return_type| {
4653 try stack.append(RenderState { .Expression = return_type});
4654 try stack.append(RenderState { .Text = "-> "});
4655 },
4656 }
4657 try stack.append(RenderState { .Text = " ("});
4658 try stack.append(RenderState { .Expression = asm_output.constraint });
4659 try stack.append(RenderState { .Text = "] "});
4660 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
4661 try stack.append(RenderState { .Text = "["});
4662 },
4663
4664 ast.Node.Id.StructField,
4665 ast.Node.Id.UnionTag,
4666 ast.Node.Id.EnumTag,
4667 ast.Node.Id.ErrorTag,
4668 ast.Node.Id.Root,
4669 ast.Node.Id.VarDecl,
4670 ast.Node.Id.Use,
4671 ast.Node.Id.TestDecl,
4672 ast.Node.Id.ParamDecl => unreachable,
4673 },
4674 RenderState.Statement => |base| {
4675 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment } );
4676 switch (base.id) {
4677 ast.Node.Id.VarDecl => {
4678 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
4679 try stack.append(RenderState { .VarDecl = var_decl});
4680 },
4681 else => {
4682 if (requireSemiColon(base)) {
4683 try stack.append(RenderState { .Text = ";" });
4684 }
4685 try stack.append(RenderState { .Expression = base });
4686 },
4687 }
4688 },
4689 RenderState.Indent => |new_indent| indent = new_indent,
4690 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
4691 RenderState.PrintSameLineComment => |maybe_comment| blk: {
4692 const comment_token = maybe_comment ?? break :blk;
4693 try stream.print(" {}", self.tokenizer.getTokenSlice(comment_token));
4694 },
4695 RenderState.PrintLineComment => |comment_token| {
4696 try stream.write(self.tokenizer.getTokenSlice(comment_token));
4697 },
4698 }
4699 }
4700 }
4701
4702 fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
4703 const comment = node.doc_comments ?? return;
4704 for (comment.lines.toSliceConst()) |line_token| {
4705 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4706 try stream.writeByteNTimes(' ', indent);
4707 }
4708 }
4709
4710 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
4711 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
4712 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
4713 const typed_slice = ([]T)(self.utility_bytes);
4714 return ArrayList(T) {
4715 .allocator = self.util_allocator,
4716 .items = typed_slice,
4717 .len = 0,
4718 };
4719 }
4720
4721 fn deinitUtilityArrayList(self: &Parser, list: var) void {
4722 self.utility_bytes = ([]align(utility_bytes_align) u8)(list.items);
4723 }
4724
4725};
4726
4727test "std.zig.parser" {
4728 _ = @import("parser_test.zig");
4729}
std/zig/parser_test.zig+81-59
...@@ -1,28 +1,71 @@...@@ -1,28 +1,71 @@
1test "zig fmt: same-line comment after a statement" {
2 try testCanonical(
3 \\test "" {
4 \\ a = b;
5 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
6 \\ a = b;
7 \\}
8 \\
9 );
10}
11
12test "zig fmt: same-line comment after var decl in struct" {
13 try testCanonical(
14 \\pub const vfs_cap_data = extern struct {
15 \\ const Data = struct {}; // when on disk.
16 \\};
17 \\
18 );
19}
20
21test "zig fmt: same-line comment after field decl" {
22 try testCanonical(
23 \\pub const dirent = extern struct {
24 \\ d_name: u8,
25 \\ d_name: u8, // comment 1
26 \\ d_name: u8,
27 \\ d_name: u8, // comment 2
28 \\ d_name: u8,
29 \\};
30 \\
31 );
32}
33
34test "zig fmt: same-line comment after switch prong" {
35 try testCanonical(
36 \\test "" {
37 \\ switch (err) {
38 \\ error.PathAlreadyExists => {}, // comment 2
39 \\ else => return err, // comment 1
40 \\ }
41 \\}
42 \\
43 );
44}
45
1test "zig fmt: same-line comment after non-block if expression" {46test "zig fmt: same-line comment after non-block if expression" {
2 try testCanonical(47 try testCanonical(
3 \\comptime {48 \\comptime {
4 \\ if (sr > n_uword_bits - 1) {49 \\ if (sr > n_uword_bits - 1) // d > r
5 \\ // d > r
6 \\ return 0;50 \\ return 0;
7 \\ }
8 \\}51 \\}
9 \\52 \\
10 );53 );
11}54}
1255
13test "zig fmt: switch with empty body" {56test "zig fmt: same-line comment on comptime expression" {
14 try testCanonical(57 try testCanonical(
15 \\test "" {58 \\test "" {
16 \\ foo() catch |err| switch (err) {};59 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
17 \\}60 \\}
18 \\61 \\
19 );62 );
20}63}
2164
22test "zig fmt: same-line comment on comptime expression" {65test "zig fmt: switch with empty body" {
23 try testCanonical(66 try testCanonical(
24 \\test "" {67 \\test "" {
25 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt68 \\ foo() catch |err| switch (err) {};
26 \\}69 \\}
27 \\70 \\
28 );71 );
...@@ -154,18 +197,6 @@ test "zig fmt: comments before switch prong" {...@@ -154,18 +197,6 @@ test "zig fmt: comments before switch prong" {
154 );197 );
155}198}
156199
157test "zig fmt: same-line comment after switch prong" {
158 try testCanonical(
159 \\test "" {
160 \\ switch (err) {
161 \\ error.PathAlreadyExists => {}, // comment 2
162 \\ else => return err, // comment 1
163 \\ }
164 \\}
165 \\
166 );
167}
168
169test "zig fmt: comments before var decl in struct" {200test "zig fmt: comments before var decl in struct" {
170 try testCanonical(201 try testCanonical(
171 \\pub const vfs_cap_data = extern struct {202 \\pub const vfs_cap_data = extern struct {
...@@ -191,28 +222,6 @@ test "zig fmt: comments before var decl in struct" {...@@ -191,28 +222,6 @@ test "zig fmt: comments before var decl in struct" {
191 );222 );
192}223}
193224
194test "zig fmt: same-line comment after var decl in struct" {
195 try testCanonical(
196 \\pub const vfs_cap_data = extern struct {
197 \\ const Data = struct {}; // when on disk.
198 \\};
199 \\
200 );
201}
202
203test "zig fmt: same-line comment after field decl" {
204 try testCanonical(
205 \\pub const dirent = extern struct {
206 \\ d_name: u8,
207 \\ d_name: u8, // comment 1
208 \\ d_name: u8,
209 \\ d_name: u8, // comment 2
210 \\ d_name: u8,
211 \\};
212 \\
213 );
214}
215
216test "zig fmt: array literal with 1 item on 1 line" {225test "zig fmt: array literal with 1 item on 1 line" {
217 try testCanonical(226 try testCanonical(
218 \\var s = []const u64{0} ** 25;227 \\var s = []const u64{0} ** 25;
...@@ -220,17 +229,6 @@ test "zig fmt: array literal with 1 item on 1 line" {...@@ -220,17 +229,6 @@ test "zig fmt: array literal with 1 item on 1 line" {
220 );229 );
221}230}
222231
223test "zig fmt: same-line comment after a statement" {
224 try testCanonical(
225 \\test "" {
226 \\ a = b;
227 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
228 \\ a = b;
229 \\}
230 \\
231 );
232}
233
234test "zig fmt: comments before global variables" {232test "zig fmt: comments before global variables" {
235 try testCanonical(233 try testCanonical(
236 \\/// Foo copies keys and values before they go into the map, and234 \\/// Foo copies keys and values before they go into the map, and
...@@ -1094,25 +1092,48 @@ test "zig fmt: error return" {...@@ -1094,25 +1092,48 @@ test "zig fmt: error return" {
1094const std = @import("std");1092const std = @import("std");
1095const mem = std.mem;1093const mem = std.mem;
1096const warn = std.debug.warn;1094const warn = std.debug.warn;
1097const Tokenizer = std.zig.Tokenizer;
1098const Parser = std.zig.Parser;
1099const io = std.io;1095const io = std.io;
11001096
1101var fixed_buffer_mem: [100 * 1024]u8 = undefined;1097var fixed_buffer_mem: [100 * 1024]u8 = undefined;
11021098
1103fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {1099fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1104 var tokenizer = Tokenizer.init(source);1100 var stderr_file = try io.getStdErr();
1105 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");1101 var stderr = &io.FileOutStream.init(&stderr_file).stream;
1106 defer parser.deinit();
11071102
1108 var tree = try parser.parse();1103 var tree = try std.zig.parse(allocator, source);
1109 defer tree.deinit();1104 defer tree.deinit();
11101105
1106 var error_it = tree.errors.iterator(0);
1107 while (error_it.next()) |parse_error| {
1108 const token = tree.tokens.at(parse_error.loc());
1109 const loc = tree.tokenLocation(0, parse_error.loc());
1110 try stderr.print("(memory buffer):{}:{}: error: ", loc.line + 1, loc.column + 1);
1111 try tree.renderError(parse_error, stderr);
1112 try stderr.print("\n{}\n", source[loc.line_start..loc.line_end]);
1113 {
1114 var i: usize = 0;
1115 while (i < loc.column) : (i += 1) {
1116 try stderr.write(" ");
1117 }
1118 }
1119 {
1120 const caret_count = token.end - token.start;
1121 var i: usize = 0;
1122 while (i < caret_count) : (i += 1) {
1123 try stderr.write("~");
1124 }
1125 }
1126 try stderr.write("\n");
1127 }
1128 if (tree.errors.len != 0) {
1129 return error.ParseError;
1130 }
1131
1111 var buffer = try std.Buffer.initSize(allocator, 0);1132 var buffer = try std.Buffer.initSize(allocator, 0);
1112 errdefer buffer.deinit();1133 errdefer buffer.deinit();
11131134
1114 var buffer_out_stream = io.BufferOutStream.init(&buffer);1135 var buffer_out_stream = io.BufferOutStream.init(&buffer);
1115 try parser.renderSource(&buffer_out_stream.stream, tree.root_node);1136 try std.zig.render(allocator, &buffer_out_stream.stream, &tree);
1116 return buffer.toOwnedSlice();1137 return buffer.toOwnedSlice();
1117}1138}
11181139
...@@ -1151,6 +1172,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {...@@ -1151,6 +1172,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
1151 }1172 }
1152 },1173 },
1153 error.ParseError => @panic("test failed"),1174 error.ParseError => @panic("test failed"),
1175 else => @panic("test failed"),
1154 }1176 }
1155 }1177 }
1156}1178}
std/zig/render.zig created+1270
...@@ -0,0 +1,1270 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Token = std.zig.Token;
6
7const RenderState = union(enum) {
8 TopLevelDecl: &ast.Node,
9 ParamDecl: &ast.Node,
10 Text: []const u8,
11 Expression: &ast.Node,
12 VarDecl: &ast.Node.VarDecl,
13 Statement: &ast.Node,
14 PrintIndent,
15 Indent: usize,
16 MaybeSemiColon: &ast.Node,
17 Token: ast.TokenIndex,
18 NonBreakToken: ast.TokenIndex,
19};
20
21const indent_delta = 4;
22
23pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {
24 var stack = std.ArrayList(RenderState).init(allocator);
25 defer stack.deinit();
26
27 {
28 try stack.append(RenderState { .Text = "\n"});
29
30 var i = tree.root_node.decls.len;
31 while (i != 0) {
32 i -= 1;
33 const decl = *tree.root_node.decls.at(i);
34 try stack.append(RenderState {.TopLevelDecl = decl});
35 if (i != 0) {
36 try stack.append(RenderState {
37 .Text = blk: {
38 const prev_node = *tree.root_node.decls.at(i - 1);
39 const prev_node_last_token = tree.tokens.at(prev_node.lastToken());
40 const loc = tree.tokenLocation(prev_node_last_token.end, decl.firstToken());
41 if (loc.line >= 2) {
42 break :blk "\n\n";
43 }
44 break :blk "\n";
45 },
46 });
47 }
48 }
49 }
50
51 var indent: usize = 0;
52 while (stack.popOrNull()) |state| {
53 switch (state) {
54 RenderState.TopLevelDecl => |decl| {
55 switch (decl.id) {
56 ast.Node.Id.FnProto => {
57 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
58 try renderComments(tree, stream, fn_proto, indent);
59
60 if (fn_proto.body_node) |body_node| {
61 stack.append(RenderState { .Expression = body_node}) catch unreachable;
62 try stack.append(RenderState { .Text = " "});
63 } else {
64 stack.append(RenderState { .Text = ";" }) catch unreachable;
65 }
66
67 try stack.append(RenderState { .Expression = decl });
68 },
69 ast.Node.Id.Use => {
70 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
71 if (use_decl.visib_token) |visib_token| {
72 try stream.print("{} ", tree.tokenSlice(visib_token));
73 }
74 try stream.print("use ");
75 try stack.append(RenderState { .Text = ";" });
76 try stack.append(RenderState { .Expression = use_decl.expr });
77 },
78 ast.Node.Id.VarDecl => {
79 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
80 try renderComments(tree, stream, var_decl, indent);
81 try stack.append(RenderState { .VarDecl = var_decl});
82 },
83 ast.Node.Id.TestDecl => {
84 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
85 try renderComments(tree, stream, test_decl, indent);
86 try stream.print("test ");
87 try stack.append(RenderState { .Expression = test_decl.body_node });
88 try stack.append(RenderState { .Text = " " });
89 try stack.append(RenderState { .Expression = test_decl.name });
90 },
91 ast.Node.Id.StructField => {
92 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
93 try renderComments(tree, stream, field, indent);
94 if (field.visib_token) |visib_token| {
95 try stream.print("{} ", tree.tokenSlice(visib_token));
96 }
97 try stream.print("{}: ", tree.tokenSlice(field.name_token));
98 try stack.append(RenderState { .Token = field.lastToken() + 1 });
99 try stack.append(RenderState { .Expression = field.type_expr});
100 },
101 ast.Node.Id.UnionTag => {
102 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
103 try renderComments(tree, stream, tag, indent);
104 try stream.print("{}", tree.tokenSlice(tag.name_token));
105
106 try stack.append(RenderState { .Text = "," });
107
108 if (tag.value_expr) |value_expr| {
109 try stack.append(RenderState { .Expression = value_expr });
110 try stack.append(RenderState { .Text = " = " });
111 }
112
113 if (tag.type_expr) |type_expr| {
114 try stream.print(": ");
115 try stack.append(RenderState { .Expression = type_expr});
116 }
117 },
118 ast.Node.Id.EnumTag => {
119 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
120 try renderComments(tree, stream, tag, indent);
121 try stream.print("{}", tree.tokenSlice(tag.name_token));
122
123 try stack.append(RenderState { .Text = "," });
124 if (tag.value) |value| {
125 try stream.print(" = ");
126 try stack.append(RenderState { .Expression = value});
127 }
128 },
129 ast.Node.Id.ErrorTag => {
130 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
131 try renderComments(tree, stream, tag, indent);
132 try stream.print("{}", tree.tokenSlice(tag.name_token));
133 },
134 ast.Node.Id.Comptime => {
135 try stack.append(RenderState { .MaybeSemiColon = decl });
136 try stack.append(RenderState { .Expression = decl });
137 },
138 ast.Node.Id.LineComment => {
139 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
140 try stream.write(tree.tokenSlice(line_comment_node.token));
141 },
142 else => unreachable,
143 }
144 },
145
146 RenderState.VarDecl => |var_decl| {
147 try stack.append(RenderState { .Token = var_decl.semicolon_token });
148 if (var_decl.init_node) |init_node| {
149 try stack.append(RenderState { .Expression = init_node });
150 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
151 try stack.append(RenderState { .Text = text });
152 }
153 if (var_decl.align_node) |align_node| {
154 try stack.append(RenderState { .Text = ")" });
155 try stack.append(RenderState { .Expression = align_node });
156 try stack.append(RenderState { .Text = " align(" });
157 }
158 if (var_decl.type_node) |type_node| {
159 try stack.append(RenderState { .Expression = type_node });
160 try stack.append(RenderState { .Text = ": " });
161 }
162 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
163 try stack.append(RenderState { .Text = " " });
164 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
165
166 if (var_decl.comptime_token) |comptime_token| {
167 try stack.append(RenderState { .Text = " " });
168 try stack.append(RenderState { .Text = tree.tokenSlice(comptime_token) });
169 }
170
171 if (var_decl.extern_export_token) |extern_export_token| {
172 if (var_decl.lib_name != null) {
173 try stack.append(RenderState { .Text = " " });
174 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
175 }
176 try stack.append(RenderState { .Text = " " });
177 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_token) });
178 }
179
180 if (var_decl.visib_token) |visib_token| {
181 try stack.append(RenderState { .Text = " " });
182 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token) });
183 }
184 },
185
186 RenderState.ParamDecl => |base| {
187 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
188 if (param_decl.comptime_token) |comptime_token| {
189 try stream.print("{} ", tree.tokenSlice(comptime_token));
190 }
191 if (param_decl.noalias_token) |noalias_token| {
192 try stream.print("{} ", tree.tokenSlice(noalias_token));
193 }
194 if (param_decl.name_token) |name_token| {
195 try stream.print("{}: ", tree.tokenSlice(name_token));
196 }
197 if (param_decl.var_args_token) |var_args_token| {
198 try stream.print("{}", tree.tokenSlice(var_args_token));
199 } else {
200 try stack.append(RenderState { .Expression = param_decl.type_node});
201 }
202 },
203 RenderState.Text => |bytes| {
204 try stream.write(bytes);
205 },
206 RenderState.Expression => |base| switch (base.id) {
207 ast.Node.Id.Identifier => {
208 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
209 try stream.print("{}", tree.tokenSlice(identifier.token));
210 },
211 ast.Node.Id.Block => {
212 const block = @fieldParentPtr(ast.Node.Block, "base", base);
213 if (block.label) |label| {
214 try stream.print("{}: ", tree.tokenSlice(label));
215 }
216
217 if (block.statements.len == 0) {
218 try stream.write("{}");
219 } else {
220 try stream.write("{");
221 try stack.append(RenderState { .Text = "}"});
222 try stack.append(RenderState.PrintIndent);
223 try stack.append(RenderState { .Indent = indent});
224 try stack.append(RenderState { .Text = "\n"});
225 var i = block.statements.len;
226 while (i != 0) {
227 i -= 1;
228 const statement_node = *block.statements.at(i);
229 try stack.append(RenderState { .Statement = statement_node});
230 try stack.append(RenderState.PrintIndent);
231 try stack.append(RenderState { .Indent = indent + indent_delta});
232 try stack.append(RenderState {
233 .Text = blk: {
234 if (i != 0) {
235 const prev_node = *block.statements.at(i - 1);
236 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
237 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());
238 if (loc.line >= 2) {
239 break :blk "\n\n";
240 }
241 }
242 break :blk "\n";
243 },
244 });
245 }
246 }
247 },
248 ast.Node.Id.Defer => {
249 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
250 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
251 try stack.append(RenderState { .Expression = defer_node.expr });
252 },
253 ast.Node.Id.Comptime => {
254 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
255 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
256 try stack.append(RenderState { .Expression = comptime_node.expr });
257 },
258 ast.Node.Id.AsyncAttribute => {
259 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
260 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
261
262 if (async_attr.allocator_type) |allocator_type| {
263 try stack.append(RenderState { .Text = ">" });
264 try stack.append(RenderState { .Expression = allocator_type });
265 try stack.append(RenderState { .Text = "<" });
266 }
267 },
268 ast.Node.Id.Suspend => {
269 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
270 if (suspend_node.label) |label| {
271 try stream.print("{}: ", tree.tokenSlice(label));
272 }
273 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
274
275 if (suspend_node.body) |body| {
276 try stack.append(RenderState { .Expression = body });
277 try stack.append(RenderState { .Text = " " });
278 }
279
280 if (suspend_node.payload) |payload| {
281 try stack.append(RenderState { .Expression = payload });
282 try stack.append(RenderState { .Text = " " });
283 }
284 },
285 ast.Node.Id.InfixOp => {
286 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
287 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
288
289 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
290 if (prefix_op_node.op.Catch) |payload| {
291 try stack.append(RenderState { .Text = " " });
292 try stack.append(RenderState { .Expression = payload });
293 }
294 try stack.append(RenderState { .Text = " catch " });
295 } else {
296 const text = switch (prefix_op_node.op) {
297 ast.Node.InfixOp.Op.Add => " + ",
298 ast.Node.InfixOp.Op.AddWrap => " +% ",
299 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
300 ast.Node.InfixOp.Op.ArrayMult => " ** ",
301 ast.Node.InfixOp.Op.Assign => " = ",
302 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
303 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
304 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
305 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
306 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
307 ast.Node.InfixOp.Op.AssignDiv => " /= ",
308 ast.Node.InfixOp.Op.AssignMinus => " -= ",
309 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
310 ast.Node.InfixOp.Op.AssignMod => " %= ",
311 ast.Node.InfixOp.Op.AssignPlus => " += ",
312 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
313 ast.Node.InfixOp.Op.AssignTimes => " *= ",
314 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
315 ast.Node.InfixOp.Op.BangEqual => " != ",
316 ast.Node.InfixOp.Op.BitAnd => " & ",
317 ast.Node.InfixOp.Op.BitOr => " | ",
318 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
319 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
320 ast.Node.InfixOp.Op.BitXor => " ^ ",
321 ast.Node.InfixOp.Op.BoolAnd => " and ",
322 ast.Node.InfixOp.Op.BoolOr => " or ",
323 ast.Node.InfixOp.Op.Div => " / ",
324 ast.Node.InfixOp.Op.EqualEqual => " == ",
325 ast.Node.InfixOp.Op.ErrorUnion => "!",
326 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
327 ast.Node.InfixOp.Op.GreaterThan => " > ",
328 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
329 ast.Node.InfixOp.Op.LessThan => " < ",
330 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
331 ast.Node.InfixOp.Op.Mod => " % ",
332 ast.Node.InfixOp.Op.Mult => " * ",
333 ast.Node.InfixOp.Op.MultWrap => " *% ",
334 ast.Node.InfixOp.Op.Period => ".",
335 ast.Node.InfixOp.Op.Sub => " - ",
336 ast.Node.InfixOp.Op.SubWrap => " -% ",
337 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
338 ast.Node.InfixOp.Op.Range => " ... ",
339 ast.Node.InfixOp.Op.Catch => unreachable,
340 };
341
342 try stack.append(RenderState { .Text = text });
343 }
344 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
345 },
346 ast.Node.Id.PrefixOp => {
347 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
348 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
349 switch (prefix_op_node.op) {
350 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
351 try stream.write("&");
352 if (addr_of_info.volatile_token != null) {
353 try stack.append(RenderState { .Text = "volatile "});
354 }
355 if (addr_of_info.const_token != null) {
356 try stack.append(RenderState { .Text = "const "});
357 }
358 if (addr_of_info.align_expr) |align_expr| {
359 try stream.print("align(");
360 try stack.append(RenderState { .Text = ") "});
361 try stack.append(RenderState { .Expression = align_expr});
362 }
363 },
364 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
365 try stream.write("[]");
366 if (addr_of_info.volatile_token != null) {
367 try stack.append(RenderState { .Text = "volatile "});
368 }
369 if (addr_of_info.const_token != null) {
370 try stack.append(RenderState { .Text = "const "});
371 }
372 if (addr_of_info.align_expr) |align_expr| {
373 try stream.print("align(");
374 try stack.append(RenderState { .Text = ") "});
375 try stack.append(RenderState { .Expression = align_expr});
376 }
377 },
378 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
379 try stack.append(RenderState { .Text = "]"});
380 try stack.append(RenderState { .Expression = array_index});
381 try stack.append(RenderState { .Text = "["});
382 },
383 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
384 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
385 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
386 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
387 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
388 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
389 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
390 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
391 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
392 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
393 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
394 }
395 },
396 ast.Node.Id.SuffixOp => {
397 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
398
399 switch (suffix_op.op) {
400 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
401 try stack.append(RenderState { .Text = ")"});
402 var i = call_info.params.len;
403 while (i != 0) {
404 i -= 1;
405 const param_node = *call_info.params.at(i);
406 try stack.append(RenderState { .Expression = param_node});
407 if (i != 0) {
408 try stack.append(RenderState { .Text = ", " });
409 }
410 }
411 try stack.append(RenderState { .Text = "("});
412 try stack.append(RenderState { .Expression = suffix_op.lhs });
413
414 if (call_info.async_attr) |async_attr| {
415 try stack.append(RenderState { .Text = " "});
416 try stack.append(RenderState { .Expression = &async_attr.base });
417 }
418 },
419 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
420 try stack.append(RenderState { .Text = "]"});
421 try stack.append(RenderState { .Expression = index_expr});
422 try stack.append(RenderState { .Text = "["});
423 try stack.append(RenderState { .Expression = suffix_op.lhs });
424 },
425 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
426 try stack.append(RenderState { .Text = "]"});
427 if (range.end) |end| {
428 try stack.append(RenderState { .Expression = end});
429 }
430 try stack.append(RenderState { .Text = ".."});
431 try stack.append(RenderState { .Expression = range.start});
432 try stack.append(RenderState { .Text = "["});
433 try stack.append(RenderState { .Expression = suffix_op.lhs });
434 },
435 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
436 if (field_inits.len == 0) {
437 try stack.append(RenderState { .Text = "{}" });
438 try stack.append(RenderState { .Expression = suffix_op.lhs });
439 continue;
440 }
441 if (field_inits.len == 1) {
442 const field_init = *field_inits.at(0);
443
444 try stack.append(RenderState { .Text = " }" });
445 try stack.append(RenderState { .Expression = field_init });
446 try stack.append(RenderState { .Text = "{ " });
447 try stack.append(RenderState { .Expression = suffix_op.lhs });
448 continue;
449 }
450 try stack.append(RenderState { .Text = "}"});
451 try stack.append(RenderState.PrintIndent);
452 try stack.append(RenderState { .Indent = indent });
453 try stack.append(RenderState { .Text = "\n" });
454 var i = field_inits.len;
455 while (i != 0) {
456 i -= 1;
457 const field_init = *field_inits.at(i);
458 if (field_init.id != ast.Node.Id.LineComment) {
459 try stack.append(RenderState { .Text = "," });
460 }
461 try stack.append(RenderState { .Expression = field_init });
462 try stack.append(RenderState.PrintIndent);
463 if (i != 0) {
464 try stack.append(RenderState { .Text = blk: {
465 const prev_node = *field_inits.at(i - 1);
466 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
467 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
468 if (loc.line >= 2) {
469 break :blk "\n\n";
470 }
471 break :blk "\n";
472 }});
473 }
474 }
475 try stack.append(RenderState { .Indent = indent + indent_delta });
476 try stack.append(RenderState { .Text = "{\n"});
477 try stack.append(RenderState { .Expression = suffix_op.lhs });
478 },
479 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
480 if (exprs.len == 0) {
481 try stack.append(RenderState { .Text = "{}" });
482 try stack.append(RenderState { .Expression = suffix_op.lhs });
483 continue;
484 }
485 if (exprs.len == 1) {
486 const expr = *exprs.at(0);
487
488 try stack.append(RenderState { .Text = "}" });
489 try stack.append(RenderState { .Expression = expr });
490 try stack.append(RenderState { .Text = "{" });
491 try stack.append(RenderState { .Expression = suffix_op.lhs });
492 continue;
493 }
494
495 try stack.append(RenderState { .Text = "}"});
496 try stack.append(RenderState.PrintIndent);
497 try stack.append(RenderState { .Indent = indent });
498 var i = exprs.len;
499 while (i != 0) {
500 i -= 1;
501 const expr = *exprs.at(i);
502 try stack.append(RenderState { .Text = ",\n" });
503 try stack.append(RenderState { .Expression = expr });
504 try stack.append(RenderState.PrintIndent);
505 }
506 try stack.append(RenderState { .Indent = indent + indent_delta });
507 try stack.append(RenderState { .Text = "{\n"});
508 try stack.append(RenderState { .Expression = suffix_op.lhs });
509 },
510 }
511 },
512 ast.Node.Id.ControlFlowExpression => {
513 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
514
515 if (flow_expr.rhs) |rhs| {
516 try stack.append(RenderState { .Expression = rhs });
517 try stack.append(RenderState { .Text = " " });
518 }
519
520 switch (flow_expr.kind) {
521 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
522 try stream.print("break");
523 if (maybe_label) |label| {
524 try stream.print(" :");
525 try stack.append(RenderState { .Expression = label });
526 }
527 },
528 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
529 try stream.print("continue");
530 if (maybe_label) |label| {
531 try stream.print(" :");
532 try stack.append(RenderState { .Expression = label });
533 }
534 },
535 ast.Node.ControlFlowExpression.Kind.Return => {
536 try stream.print("return");
537 },
538
539 }
540 },
541 ast.Node.Id.Payload => {
542 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
543 try stack.append(RenderState { .Text = "|"});
544 try stack.append(RenderState { .Expression = payload.error_symbol });
545 try stack.append(RenderState { .Text = "|"});
546 },
547 ast.Node.Id.PointerPayload => {
548 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
549 try stack.append(RenderState { .Text = "|"});
550 try stack.append(RenderState { .Expression = payload.value_symbol });
551
552 if (payload.ptr_token) |ptr_token| {
553 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
554 }
555
556 try stack.append(RenderState { .Text = "|"});
557 },
558 ast.Node.Id.PointerIndexPayload => {
559 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
560 try stack.append(RenderState { .Text = "|"});
561
562 if (payload.index_symbol) |index_symbol| {
563 try stack.append(RenderState { .Expression = index_symbol });
564 try stack.append(RenderState { .Text = ", "});
565 }
566
567 try stack.append(RenderState { .Expression = payload.value_symbol });
568
569 if (payload.ptr_token) |ptr_token| {
570 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
571 }
572
573 try stack.append(RenderState { .Text = "|"});
574 },
575 ast.Node.Id.GroupedExpression => {
576 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
577 try stack.append(RenderState { .Text = ")"});
578 try stack.append(RenderState { .Expression = grouped_expr.expr });
579 try stack.append(RenderState { .Text = "("});
580 },
581 ast.Node.Id.FieldInitializer => {
582 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
583 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
584 try stack.append(RenderState { .Expression = field_init.expr });
585 },
586 ast.Node.Id.IntegerLiteral => {
587 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
588 try stream.print("{}", tree.tokenSlice(integer_literal.token));
589 },
590 ast.Node.Id.FloatLiteral => {
591 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
592 try stream.print("{}", tree.tokenSlice(float_literal.token));
593 },
594 ast.Node.Id.StringLiteral => {
595 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
596 try stream.print("{}", tree.tokenSlice(string_literal.token));
597 },
598 ast.Node.Id.CharLiteral => {
599 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
600 try stream.print("{}", tree.tokenSlice(char_literal.token));
601 },
602 ast.Node.Id.BoolLiteral => {
603 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
604 try stream.print("{}", tree.tokenSlice(bool_literal.token));
605 },
606 ast.Node.Id.NullLiteral => {
607 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
608 try stream.print("{}", tree.tokenSlice(null_literal.token));
609 },
610 ast.Node.Id.ThisLiteral => {
611 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
612 try stream.print("{}", tree.tokenSlice(this_literal.token));
613 },
614 ast.Node.Id.Unreachable => {
615 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
616 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
617 },
618 ast.Node.Id.ErrorType => {
619 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
620 try stream.print("{}", tree.tokenSlice(error_type.token));
621 },
622 ast.Node.Id.VarType => {
623 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
624 try stream.print("{}", tree.tokenSlice(var_type.token));
625 },
626 ast.Node.Id.ContainerDecl => {
627 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
628
629 switch (container_decl.layout) {
630 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
631 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
632 ast.Node.ContainerDecl.Layout.Auto => { },
633 }
634
635 switch (container_decl.kind) {
636 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
637 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
638 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
639 }
640
641 if (container_decl.fields_and_decls.len == 0) {
642 try stack.append(RenderState { .Text = "{}"});
643 } else {
644 try stack.append(RenderState { .Text = "}"});
645 try stack.append(RenderState.PrintIndent);
646 try stack.append(RenderState { .Indent = indent });
647 try stack.append(RenderState { .Text = "\n"});
648
649 var i = container_decl.fields_and_decls.len;
650 while (i != 0) {
651 i -= 1;
652 const node = *container_decl.fields_and_decls.at(i);
653 try stack.append(RenderState { .TopLevelDecl = node});
654 try stack.append(RenderState.PrintIndent);
655 try stack.append(RenderState {
656 .Text = blk: {
657 if (i != 0) {
658 const prev_node = *container_decl.fields_and_decls.at(i - 1);
659 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
660 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
661 if (loc.line >= 2) {
662 break :blk "\n\n";
663 }
664 }
665 break :blk "\n";
666 },
667 });
668 }
669 try stack.append(RenderState { .Indent = indent + indent_delta});
670 try stack.append(RenderState { .Text = "{"});
671 }
672
673 switch (container_decl.init_arg_expr) {
674 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
675 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
676 if (enum_tag_type) |expr| {
677 try stack.append(RenderState { .Text = ")) "});
678 try stack.append(RenderState { .Expression = expr});
679 try stack.append(RenderState { .Text = "(enum("});
680 } else {
681 try stack.append(RenderState { .Text = "(enum) "});
682 }
683 },
684 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
685 try stack.append(RenderState { .Text = ") "});
686 try stack.append(RenderState { .Expression = type_expr});
687 try stack.append(RenderState { .Text = "("});
688 },
689 }
690 },
691 ast.Node.Id.ErrorSetDecl => {
692 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
693
694 if (err_set_decl.decls.len == 0) {
695 try stream.write("error{}");
696 continue;
697 }
698
699 if (err_set_decl.decls.len == 1) blk: {
700 const node = *err_set_decl.decls.at(0);
701
702 // if there are any doc comments or same line comments
703 // don't try to put it all on one line
704 if (node.cast(ast.Node.ErrorTag)) |tag| {
705 if (tag.doc_comments != null) break :blk;
706 } else {
707 break :blk;
708 }
709
710
711 try stream.write("error{");
712 try stack.append(RenderState { .Text = "}" });
713 try stack.append(RenderState { .TopLevelDecl = node });
714 continue;
715 }
716
717 try stream.write("error{");
718
719 try stack.append(RenderState { .Text = "}"});
720 try stack.append(RenderState.PrintIndent);
721 try stack.append(RenderState { .Indent = indent });
722 try stack.append(RenderState { .Text = "\n"});
723
724 var i = err_set_decl.decls.len;
725 while (i != 0) {
726 i -= 1;
727 const node = *err_set_decl.decls.at(i);
728 if (node.id != ast.Node.Id.LineComment) {
729 try stack.append(RenderState { .Text = "," });
730 }
731 try stack.append(RenderState { .TopLevelDecl = node });
732 try stack.append(RenderState.PrintIndent);
733 try stack.append(RenderState {
734 .Text = blk: {
735 if (i != 0) {
736 const prev_node = *err_set_decl.decls.at(i - 1);
737 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
738 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
739 if (loc.line >= 2) {
740 break :blk "\n\n";
741 }
742 }
743 break :blk "\n";
744 },
745 });
746 }
747 try stack.append(RenderState { .Indent = indent + indent_delta});
748 },
749 ast.Node.Id.MultilineStringLiteral => {
750 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
751 try stream.print("\n");
752
753 var i : usize = 0;
754 while (i < multiline_str_literal.lines.len) : (i += 1) {
755 const t = *multiline_str_literal.lines.at(i);
756 try stream.writeByteNTimes(' ', indent + indent_delta);
757 try stream.print("{}", tree.tokenSlice(t));
758 }
759 try stream.writeByteNTimes(' ', indent);
760 },
761 ast.Node.Id.UndefinedLiteral => {
762 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
763 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
764 },
765 ast.Node.Id.BuiltinCall => {
766 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
767 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
768 try stack.append(RenderState { .Text = ")"});
769 var i = builtin_call.params.len;
770 while (i != 0) {
771 i -= 1;
772 const param_node = *builtin_call.params.at(i);
773 try stack.append(RenderState { .Expression = param_node});
774 if (i != 0) {
775 try stack.append(RenderState { .Text = ", " });
776 }
777 }
778 },
779 ast.Node.Id.FnProto => {
780 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
781
782 switch (fn_proto.return_type) {
783 ast.Node.FnProto.ReturnType.Explicit => |node| {
784 try stack.append(RenderState { .Expression = node});
785 },
786 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
787 try stack.append(RenderState { .Expression = node});
788 try stack.append(RenderState { .Text = "!"});
789 },
790 }
791
792 if (fn_proto.align_expr) |align_expr| {
793 try stack.append(RenderState { .Text = ") " });
794 try stack.append(RenderState { .Expression = align_expr});
795 try stack.append(RenderState { .Text = "align(" });
796 }
797
798 try stack.append(RenderState { .Text = ") " });
799 var i = fn_proto.params.len;
800 while (i != 0) {
801 i -= 1;
802 const param_decl_node = *fn_proto.params.at(i);
803 try stack.append(RenderState { .ParamDecl = param_decl_node});
804 if (i != 0) {
805 try stack.append(RenderState { .Text = ", " });
806 }
807 }
808
809 try stack.append(RenderState { .Text = "(" });
810 if (fn_proto.name_token) |name_token| {
811 try stack.append(RenderState { .Text = tree.tokenSlice(name_token) });
812 try stack.append(RenderState { .Text = " " });
813 }
814
815 try stack.append(RenderState { .Text = "fn" });
816
817 if (fn_proto.async_attr) |async_attr| {
818 try stack.append(RenderState { .Text = " " });
819 try stack.append(RenderState { .Expression = &async_attr.base });
820 }
821
822 if (fn_proto.cc_token) |cc_token| {
823 try stack.append(RenderState { .Text = " " });
824 try stack.append(RenderState { .Text = tree.tokenSlice(cc_token) });
825 }
826
827 if (fn_proto.lib_name) |lib_name| {
828 try stack.append(RenderState { .Text = " " });
829 try stack.append(RenderState { .Expression = lib_name });
830 }
831 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
832 try stack.append(RenderState { .Text = " " });
833 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
834 }
835
836 if (fn_proto.visib_token) |visib_token_index| {
837 const visib_token = tree.tokens.at(visib_token_index);
838 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
839 try stack.append(RenderState { .Text = " " });
840 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token_index) });
841 }
842 },
843 ast.Node.Id.PromiseType => {
844 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
845 try stream.write(tree.tokenSlice(promise_type.promise_token));
846 if (promise_type.result) |result| {
847 try stream.write(tree.tokenSlice(result.arrow_token));
848 try stack.append(RenderState { .Expression = result.return_type});
849 }
850 },
851 ast.Node.Id.LineComment => {
852 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
853 try stream.write(tree.tokenSlice(line_comment_node.token));
854 },
855 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
856 ast.Node.Id.Switch => {
857 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
858
859 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
860
861 if (switch_node.cases.len == 0) {
862 try stack.append(RenderState { .Text = ") {}"});
863 try stack.append(RenderState { .Expression = switch_node.expr });
864 continue;
865 }
866
867 try stack.append(RenderState { .Text = "}"});
868 try stack.append(RenderState.PrintIndent);
869 try stack.append(RenderState { .Indent = indent });
870 try stack.append(RenderState { .Text = "\n"});
871
872 var i = switch_node.cases.len;
873 while (i != 0) {
874 i -= 1;
875 const node = *switch_node.cases.at(i);
876 try stack.append(RenderState { .Expression = node});
877 try stack.append(RenderState.PrintIndent);
878 try stack.append(RenderState {
879 .Text = blk: {
880 if (i != 0) {
881 const prev_node = *switch_node.cases.at(i - 1);
882 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
883 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
884 if (loc.line >= 2) {
885 break :blk "\n\n";
886 }
887 }
888 break :blk "\n";
889 },
890 });
891 }
892 try stack.append(RenderState { .Indent = indent + indent_delta});
893 try stack.append(RenderState { .Text = ") {"});
894 try stack.append(RenderState { .Expression = switch_node.expr });
895 },
896 ast.Node.Id.SwitchCase => {
897 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
898
899 try stack.append(RenderState { .Token = switch_case.lastToken() + 1 });
900 try stack.append(RenderState { .Expression = switch_case.expr });
901 if (switch_case.payload) |payload| {
902 try stack.append(RenderState { .Text = " " });
903 try stack.append(RenderState { .Expression = payload });
904 }
905 try stack.append(RenderState { .Text = " => "});
906
907 var i = switch_case.items.len;
908 while (i != 0) {
909 i -= 1;
910 try stack.append(RenderState { .Expression = *switch_case.items.at(i) });
911
912 if (i != 0) {
913 try stack.append(RenderState.PrintIndent);
914 try stack.append(RenderState { .Text = ",\n" });
915 }
916 }
917 },
918 ast.Node.Id.SwitchElse => {
919 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
920 try stream.print("{}", tree.tokenSlice(switch_else.token));
921 },
922 ast.Node.Id.Else => {
923 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
924 try stream.print("{}", tree.tokenSlice(else_node.else_token));
925
926 switch (else_node.body.id) {
927 ast.Node.Id.Block, ast.Node.Id.If,
928 ast.Node.Id.For, ast.Node.Id.While,
929 ast.Node.Id.Switch => {
930 try stream.print(" ");
931 try stack.append(RenderState { .Expression = else_node.body });
932 },
933 else => {
934 try stack.append(RenderState { .Indent = indent });
935 try stack.append(RenderState { .Expression = else_node.body });
936 try stack.append(RenderState.PrintIndent);
937 try stack.append(RenderState { .Indent = indent + indent_delta });
938 try stack.append(RenderState { .Text = "\n" });
939 }
940 }
941
942 if (else_node.payload) |payload| {
943 try stack.append(RenderState { .Text = " " });
944 try stack.append(RenderState { .Expression = payload });
945 }
946 },
947 ast.Node.Id.While => {
948 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
949 if (while_node.label) |label| {
950 try stream.print("{}: ", tree.tokenSlice(label));
951 }
952
953 if (while_node.inline_token) |inline_token| {
954 try stream.print("{} ", tree.tokenSlice(inline_token));
955 }
956
957 try stream.print("{} ", tree.tokenSlice(while_node.while_token));
958
959 if (while_node.@"else") |@"else"| {
960 try stack.append(RenderState { .Expression = &@"else".base });
961
962 if (while_node.body.id == ast.Node.Id.Block) {
963 try stack.append(RenderState { .Text = " " });
964 } else {
965 try stack.append(RenderState.PrintIndent);
966 try stack.append(RenderState { .Text = "\n" });
967 }
968 }
969
970 if (while_node.body.id == ast.Node.Id.Block) {
971 try stack.append(RenderState { .Expression = while_node.body });
972 try stack.append(RenderState { .Text = " " });
973 } else {
974 try stack.append(RenderState { .Indent = indent });
975 try stack.append(RenderState { .Expression = while_node.body });
976 try stack.append(RenderState.PrintIndent);
977 try stack.append(RenderState { .Indent = indent + indent_delta });
978 try stack.append(RenderState { .Text = "\n" });
979 }
980
981 if (while_node.continue_expr) |continue_expr| {
982 try stack.append(RenderState { .Text = ")" });
983 try stack.append(RenderState { .Expression = continue_expr });
984 try stack.append(RenderState { .Text = ": (" });
985 try stack.append(RenderState { .Text = " " });
986 }
987
988 if (while_node.payload) |payload| {
989 try stack.append(RenderState { .Expression = payload });
990 try stack.append(RenderState { .Text = " " });
991 }
992
993 try stack.append(RenderState { .Text = ")" });
994 try stack.append(RenderState { .Expression = while_node.condition });
995 try stack.append(RenderState { .Text = "(" });
996 },
997 ast.Node.Id.For => {
998 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
999 if (for_node.label) |label| {
1000 try stream.print("{}: ", tree.tokenSlice(label));
1001 }
1002
1003 if (for_node.inline_token) |inline_token| {
1004 try stream.print("{} ", tree.tokenSlice(inline_token));
1005 }
1006
1007 try stream.print("{} ", tree.tokenSlice(for_node.for_token));
1008
1009 if (for_node.@"else") |@"else"| {
1010 try stack.append(RenderState { .Expression = &@"else".base });
1011
1012 if (for_node.body.id == ast.Node.Id.Block) {
1013 try stack.append(RenderState { .Text = " " });
1014 } else {
1015 try stack.append(RenderState.PrintIndent);
1016 try stack.append(RenderState { .Text = "\n" });
1017 }
1018 }
1019
1020 if (for_node.body.id == ast.Node.Id.Block) {
1021 try stack.append(RenderState { .Expression = for_node.body });
1022 try stack.append(RenderState { .Text = " " });
1023 } else {
1024 try stack.append(RenderState { .Indent = indent });
1025 try stack.append(RenderState { .Expression = for_node.body });
1026 try stack.append(RenderState.PrintIndent);
1027 try stack.append(RenderState { .Indent = indent + indent_delta });
1028 try stack.append(RenderState { .Text = "\n" });
1029 }
1030
1031 if (for_node.payload) |payload| {
1032 try stack.append(RenderState { .Expression = payload });
1033 try stack.append(RenderState { .Text = " " });
1034 }
1035
1036 try stack.append(RenderState { .Text = ")" });
1037 try stack.append(RenderState { .Expression = for_node.array_expr });
1038 try stack.append(RenderState { .Text = "(" });
1039 },
1040 ast.Node.Id.If => {
1041 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1042 try stream.print("{} ", tree.tokenSlice(if_node.if_token));
1043
1044 switch (if_node.body.id) {
1045 ast.Node.Id.Block, ast.Node.Id.If,
1046 ast.Node.Id.For, ast.Node.Id.While,
1047 ast.Node.Id.Switch => {
1048 if (if_node.@"else") |@"else"| {
1049 try stack.append(RenderState { .Expression = &@"else".base });
1050
1051 if (if_node.body.id == ast.Node.Id.Block) {
1052 try stack.append(RenderState { .Text = " " });
1053 } else {
1054 try stack.append(RenderState.PrintIndent);
1055 try stack.append(RenderState { .Text = "\n" });
1056 }
1057 }
1058 },
1059 else => {
1060 if (if_node.@"else") |@"else"| {
1061 try stack.append(RenderState { .Expression = @"else".body });
1062
1063 if (@"else".payload) |payload| {
1064 try stack.append(RenderState { .Text = " " });
1065 try stack.append(RenderState { .Expression = payload });
1066 }
1067
1068 try stack.append(RenderState { .Text = " " });
1069 try stack.append(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
1070 try stack.append(RenderState { .Text = " " });
1071 }
1072 }
1073 }
1074
1075 try stack.append(RenderState { .Expression = if_node.body });
1076
1077 if (if_node.payload) |payload| {
1078 try stack.append(RenderState { .Text = " " });
1079 try stack.append(RenderState { .Expression = payload });
1080 }
1081
1082 try stack.append(RenderState { .NonBreakToken = if_node.condition.lastToken() + 1 });
1083 try stack.append(RenderState { .Expression = if_node.condition });
1084 try stack.append(RenderState { .Text = "(" });
1085 },
1086 ast.Node.Id.Asm => {
1087 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1088 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
1089
1090 if (asm_node.volatile_token) |volatile_token| {
1091 try stream.print("{} ", tree.tokenSlice(volatile_token));
1092 }
1093
1094 try stack.append(RenderState { .Indent = indent });
1095 try stack.append(RenderState { .Text = ")" });
1096 {
1097 var i = asm_node.clobbers.len;
1098 while (i != 0) {
1099 i -= 1;
1100 try stack.append(RenderState { .Expression = *asm_node.clobbers.at(i) });
1101
1102 if (i != 0) {
1103 try stack.append(RenderState { .Text = ", " });
1104 }
1105 }
1106 }
1107 try stack.append(RenderState { .Text = ": " });
1108 try stack.append(RenderState.PrintIndent);
1109 try stack.append(RenderState { .Indent = indent + indent_delta });
1110 try stack.append(RenderState { .Text = "\n" });
1111 {
1112 var i = asm_node.inputs.len;
1113 while (i != 0) {
1114 i -= 1;
1115 const node = *asm_node.inputs.at(i);
1116 try stack.append(RenderState { .Expression = &node.base});
1117
1118 if (i != 0) {
1119 try stack.append(RenderState.PrintIndent);
1120 try stack.append(RenderState {
1121 .Text = blk: {
1122 const prev_node = *asm_node.inputs.at(i - 1);
1123 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1124 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1125 if (loc.line >= 2) {
1126 break :blk "\n\n";
1127 }
1128 break :blk "\n";
1129 },
1130 });
1131 try stack.append(RenderState { .Text = "," });
1132 }
1133 }
1134 }
1135 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1136 try stack.append(RenderState { .Text = ": "});
1137 try stack.append(RenderState.PrintIndent);
1138 try stack.append(RenderState { .Indent = indent + indent_delta});
1139 try stack.append(RenderState { .Text = "\n" });
1140 {
1141 var i = asm_node.outputs.len;
1142 while (i != 0) {
1143 i -= 1;
1144 const node = *asm_node.outputs.at(i);
1145 try stack.append(RenderState { .Expression = &node.base});
1146
1147 if (i != 0) {
1148 try stack.append(RenderState.PrintIndent);
1149 try stack.append(RenderState {
1150 .Text = blk: {
1151 const prev_node = *asm_node.outputs.at(i - 1);
1152 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1153 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1154 if (loc.line >= 2) {
1155 break :blk "\n\n";
1156 }
1157 break :blk "\n";
1158 },
1159 });
1160 try stack.append(RenderState { .Text = "," });
1161 }
1162 }
1163 }
1164 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1165 try stack.append(RenderState { .Text = ": "});
1166 try stack.append(RenderState.PrintIndent);
1167 try stack.append(RenderState { .Indent = indent + indent_delta});
1168 try stack.append(RenderState { .Text = "\n" });
1169 try stack.append(RenderState { .Expression = asm_node.template });
1170 try stack.append(RenderState { .Text = "(" });
1171 },
1172 ast.Node.Id.AsmInput => {
1173 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1174
1175 try stack.append(RenderState { .Text = ")"});
1176 try stack.append(RenderState { .Expression = asm_input.expr});
1177 try stack.append(RenderState { .Text = " ("});
1178 try stack.append(RenderState { .Expression = asm_input.constraint });
1179 try stack.append(RenderState { .Text = "] "});
1180 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
1181 try stack.append(RenderState { .Text = "["});
1182 },
1183 ast.Node.Id.AsmOutput => {
1184 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1185
1186 try stack.append(RenderState { .Text = ")"});
1187 switch (asm_output.kind) {
1188 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1189 try stack.append(RenderState { .Expression = &variable_name.base});
1190 },
1191 ast.Node.AsmOutput.Kind.Return => |return_type| {
1192 try stack.append(RenderState { .Expression = return_type});
1193 try stack.append(RenderState { .Text = "-> "});
1194 },
1195 }
1196 try stack.append(RenderState { .Text = " ("});
1197 try stack.append(RenderState { .Expression = asm_output.constraint });
1198 try stack.append(RenderState { .Text = "] "});
1199 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
1200 try stack.append(RenderState { .Text = "["});
1201 },
1202
1203 ast.Node.Id.StructField,
1204 ast.Node.Id.UnionTag,
1205 ast.Node.Id.EnumTag,
1206 ast.Node.Id.ErrorTag,
1207 ast.Node.Id.Root,
1208 ast.Node.Id.VarDecl,
1209 ast.Node.Id.Use,
1210 ast.Node.Id.TestDecl,
1211 ast.Node.Id.ParamDecl => unreachable,
1212 },
1213 RenderState.Statement => |base| {
1214 switch (base.id) {
1215 ast.Node.Id.VarDecl => {
1216 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1217 try stack.append(RenderState { .VarDecl = var_decl});
1218 },
1219 else => {
1220 try stack.append(RenderState { .MaybeSemiColon = base });
1221 try stack.append(RenderState { .Expression = base });
1222 },
1223 }
1224 },
1225 RenderState.Indent => |new_indent| indent = new_indent,
1226 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
1227 RenderState.Token => |token_index| try renderToken(tree, stream, token_index, indent, true),
1228 RenderState.NonBreakToken => |token_index| try renderToken(tree, stream, token_index, indent, false),
1229 RenderState.MaybeSemiColon => |base| {
1230 if (base.requireSemiColon()) {
1231 const semicolon_index = base.lastToken() + 1;
1232 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1233 try renderToken(tree, stream, semicolon_index, indent, true);
1234 }
1235 },
1236 }
1237 }
1238}
1239
1240fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) !void {
1241 const token = tree.tokens.at(token_index);
1242 try stream.write(tree.tokenSlicePtr(token));
1243
1244 const next_token = tree.tokens.at(token_index + 1);
1245 if (next_token.id == Token.Id.LineComment) {
1246 const loc = tree.tokenLocationPtr(token.end, next_token);
1247 if (loc.line == 0) {
1248 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1249 if (!line_break) {
1250 try stream.write("\n");
1251 try stream.writeByteNTimes(' ', indent + indent_delta);
1252 return;
1253 }
1254 }
1255 }
1256
1257 if (!line_break) {
1258 try stream.writeByte(' ');
1259 }
1260}
1261
1262fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {
1263 const comment = node.doc_comments ?? return;
1264 var it = comment.lines.iterator(0);
1265 while (it.next()) |line_token_index| {
1266 try stream.print("{}\n", tree.tokenSlice(*line_token_index));
1267 try stream.writeByteNTimes(' ', indent);
1268 }
1269}
1270
std/zig/tokenizer.zig-35
...@@ -195,37 +195,6 @@ pub const Tokenizer = struct {...@@ -195,37 +195,6 @@ pub const Tokenizer = struct {
195 index: usize,195 index: usize,
196 pending_invalid_token: ?Token,196 pending_invalid_token: ?Token,
197197
198 pub const Location = struct {
199 line: usize,
200 column: usize,
201 line_start: usize,
202 line_end: usize,
203 };
204
205 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
206 var loc = Location {
207 .line = 0,
208 .column = 0,
209 .line_start = start_index,
210 .line_end = self.buffer.len,
211 };
212 for (self.buffer[start_index..]) |c, i| {
213 if (i + start_index == token.start) {
214 loc.line_end = i + start_index;
215 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
216 return loc;
217 }
218 if (c == '\n') {
219 loc.line += 1;
220 loc.column = 0;
221 loc.line_start = i + 1;
222 } else {
223 loc.column += 1;
224 }
225 }
226 return loc;
227 }
228
229 /// For debugging purposes198 /// For debugging purposes
230 pub fn dump(self: &Tokenizer, token: &const Token) void {199 pub fn dump(self: &Tokenizer, token: &const Token) void {
231 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);200 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);
...@@ -1047,10 +1016,6 @@ pub const Tokenizer = struct {...@@ -1047,10 +1016,6 @@ pub const Tokenizer = struct {
1047 return result;1016 return result;
1048 }1017 }
10491018
1050 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) []const u8 {
1051 return self.buffer[token.start..token.end];
1052 }
1053
1054 fn checkLiteralCharacter(self: &Tokenizer) void {1019 fn checkLiteralCharacter(self: &Tokenizer) void {
1055 if (self.pending_invalid_token != null) return;1020 if (self.pending_invalid_token != null) return;
1056 const invalid_length = self.getInvalidCharacterLength();1021 const invalid_length = self.getInvalidCharacterLength();