authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-07 22:07:50-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-07 22:07:50-04:00
log0cb65b266aa20015f068e0460c74eb75a0b7f65c
treec1446befab9e876bffd4720e6cf43dca57005f21
parent69ef6ae0f9c2a99119bb4a39ef2112b2250a98c5

separate std.zig.parse and std.zig.render


6 files changed, 4754 insertions(+), 4746 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
std/zig/ast.zig+74
...@@ -336,6 +336,80 @@ pub const Node = struct {...@@ -336,6 +336,80 @@ pub const Node = struct {
336 unreachable;336 unreachable;
337 }337 }
338338
339 pub fn requireSemiColon(base: &const Node) bool {
340 var n = base;
341 while (true) {
342 switch (n.id) {
343 Id.Root,
344 Id.StructField,
345 Id.UnionTag,
346 Id.EnumTag,
347 Id.ParamDecl,
348 Id.Block,
349 Id.Payload,
350 Id.PointerPayload,
351 Id.PointerIndexPayload,
352 Id.Switch,
353 Id.SwitchCase,
354 Id.SwitchElse,
355 Id.FieldInitializer,
356 Id.DocComment,
357 Id.LineComment,
358 Id.TestDecl => return false,
359 Id.While => {
360 const while_node = @fieldParentPtr(While, "base", n);
361 if (while_node.@"else") |@"else"| {
362 n = @"else".base;
363 continue;
364 }
365
366 return while_node.body.id != Id.Block;
367 },
368 Id.For => {
369 const for_node = @fieldParentPtr(For, "base", n);
370 if (for_node.@"else") |@"else"| {
371 n = @"else".base;
372 continue;
373 }
374
375 return for_node.body.id != Id.Block;
376 },
377 Id.If => {
378 const if_node = @fieldParentPtr(If, "base", n);
379 if (if_node.@"else") |@"else"| {
380 n = @"else".base;
381 continue;
382 }
383
384 return if_node.body.id != Id.Block;
385 },
386 Id.Else => {
387 const else_node = @fieldParentPtr(Else, "base", n);
388 n = else_node.body;
389 continue;
390 },
391 Id.Defer => {
392 const defer_node = @fieldParentPtr(Defer, "base", n);
393 return defer_node.expr.id != Id.Block;
394 },
395 Id.Comptime => {
396 const comptime_node = @fieldParentPtr(Comptime, "base", n);
397 return comptime_node.expr.id != Id.Block;
398 },
399 Id.Suspend => {
400 const suspend_node = @fieldParentPtr(Suspend, "base", n);
401 if (suspend_node.body) |body| {
402 return body.id != Id.Block;
403 }
404
405 return true;
406 },
407 else => return true,
408 }
409 }
410 }
411
412
339 pub const Root = struct {413 pub const Root = struct {
340 base: Node,414 base: Node,
341 doc_comments: ?&DocComment,415 doc_comments: ?&DocComment,
std/zig/index.zig+5-4
...@@ -1,12 +1,13 @@...@@ -1,12 +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 parse = @import("parser.zig").parse;4pub const parse = @import("parse.zig").parse;
5pub const render = @import("parser.zig").renderSource;5pub const render = @import("render.zig").render;
6pub const ast = @import("ast.zig");6pub const ast = @import("ast.zig");
77
8test "std.zig tests" {8test "std.zig tests" {
9 _ = @import("tokenizer.zig");
10 _ = @import("parser.zig");
11 _ = @import("ast.zig");9 _ = @import("ast.zig");
10 _ = @import("parse.zig");
11 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");
12}13}
std/zig/parse.zig created+3432
...@@ -0,0 +1,3432 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const SegmentedList = std.SegmentedList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Tokenizer = std.zig.Tokenizer;
7const Token = std.zig.Token;
8const TokenIndex = ast.TokenIndex;
9const Error = ast.Error;
10
11/// Returns an AST tree, allocated with the parser's allocator.
12/// Result should be freed with tree.deinit() when there are
13/// no more references to any AST nodes of the tree.
14pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
15 var tree_arena = std.heap.ArenaAllocator.init(allocator);
16 errdefer tree_arena.deinit();
17
18 var stack = SegmentedList(State, 32).init(allocator);
19 defer stack.deinit();
20
21 const arena = &tree_arena.allocator;
22 const root_node = try createNode(arena, ast.Node.Root,
23 ast.Node.Root {
24 .base = undefined,
25 .decls = ast.Node.Root.DeclList.init(arena),
26 .doc_comments = null,
27 // initialized when we get the eof token
28 .eof_token = undefined,
29 }
30 );
31
32 var tree = ast.Tree {
33 .source = source,
34 .root_node = root_node,
35 .arena_allocator = tree_arena,
36 .tokens = ast.Tree.TokenList.init(arena),
37 .errors = ast.Tree.ErrorList.init(arena),
38 };
39
40 var tokenizer = Tokenizer.init(tree.source);
41 while (true) {
42 const token_ptr = try tree.tokens.addOne();
43 *token_ptr = tokenizer.next();
44 if (token_ptr.id == Token.Id.Eof)
45 break;
46 }
47 var tok_it = tree.tokens.iterator(0);
48
49 try stack.push(State.TopLevel);
50
51 while (true) {
52 // This gives us 1 free push that can't fail
53 const state = ??stack.pop();
54
55 switch (state) {
56 State.TopLevel => {
57 while (try eatLineComment(arena, &tok_it)) |line_comment| {
58 try root_node.decls.push(&line_comment.base);
59 }
60
61 const comments = try eatDocComments(arena, &tok_it);
62
63 const token_index = tok_it.index;
64 const token_ptr = ??tok_it.next();
65 switch (token_ptr.id) {
66 Token.Id.Keyword_test => {
67 stack.push(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.push(State { .Block = block });
89 try stack.push(State {
90 .ExpectTokenSave = ExpectTokenSave {
91 .id = Token.Id.LBrace,
92 .ptr = &block.rbrace,
93 }
94 });
95 try stack.push(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.push(State.TopLevel) catch unreachable;
105 try stack.push(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.push(State.TopLevel) catch unreachable;
137 try stack.push(State { .Block = block });
138 try stack.push(State {
139 .ExpectTokenSave = ExpectTokenSave {
140 .id = Token.Id.LBrace,
141 .ptr = &block.rbrace,
142 }
143 });
144 continue;
145 },
146 else => {
147 _ = tok_it.prev();
148 stack.push(State.TopLevel) catch unreachable;
149 try stack.push(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_index = tok_it.index;
164 const token_ptr = ??tok_it.next();
165 switch (token_ptr.id) {
166 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
167 stack.push(State {
168 .TopLevelDecl = TopLevelDeclCtx {
169 .decls = ctx.decls,
170 .visib_token = ctx.visib_token,
171 .extern_export_inline_token = AnnotatedToken {
172 .index = token_index,
173 .ptr = token_ptr,
174 },
175 .lib_name = null,
176 .comments = ctx.comments,
177 },
178 }) catch unreachable;
179 continue;
180 },
181 Token.Id.Keyword_extern => {
182 stack.push(State {
183 .TopLevelLibname = TopLevelDeclCtx {
184 .decls = ctx.decls,
185 .visib_token = ctx.visib_token,
186 .extern_export_inline_token = AnnotatedToken {
187 .index = token_index,
188 .ptr = token_ptr,
189 },
190 .lib_name = null,
191 .comments = ctx.comments,
192 },
193 }) catch unreachable;
194 continue;
195 },
196 else => {
197 _ = tok_it.prev();
198 stack.push(State { .TopLevelDecl = ctx }) catch unreachable;
199 continue;
200 }
201 }
202 },
203 State.TopLevelLibname => |ctx| {
204 const lib_name = blk: {
205 const lib_name_token_index = tok_it.index;
206 const lib_name_token_ptr = ??tok_it.next();
207 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index)) ?? {
208 _ = tok_it.prev();
209 break :blk null;
210 };
211 };
212
213 stack.push(State {
214 .TopLevelDecl = TopLevelDeclCtx {
215 .decls = ctx.decls,
216 .visib_token = ctx.visib_token,
217 .extern_export_inline_token = ctx.extern_export_inline_token,
218 .lib_name = lib_name,
219 .comments = ctx.comments,
220 },
221 }) catch unreachable;
222 continue;
223 },
224 State.TopLevelDecl => |ctx| {
225 const token_index = tok_it.index;
226 const token_ptr = ??tok_it.next();
227 switch (token_ptr.id) {
228 Token.Id.Keyword_use => {
229 if (ctx.extern_export_inline_token) |annotated_token| {
230 *(try tree.errors.addOne()) = Error {
231 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
232 };
233 return tree;
234 }
235
236 const node = try arena.construct(ast.Node.Use {
237 .base = ast.Node {.id = ast.Node.Id.Use },
238 .visib_token = ctx.visib_token,
239 .expr = undefined,
240 .semicolon_token = undefined,
241 .doc_comments = ctx.comments,
242 });
243 try ctx.decls.push(&node.base);
244
245 stack.push(State {
246 .ExpectTokenSave = ExpectTokenSave {
247 .id = Token.Id.Semicolon,
248 .ptr = &node.semicolon_token,
249 }
250 }) catch unreachable;
251 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
252 continue;
253 },
254 Token.Id.Keyword_var, Token.Id.Keyword_const => {
255 if (ctx.extern_export_inline_token) |annotated_token| {
256 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
257 *(try tree.errors.addOne()) = Error {
258 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
259 };
260 return tree;
261 }
262 }
263
264 try stack.push(State {
265 .VarDecl = VarDeclCtx {
266 .comments = ctx.comments,
267 .visib_token = ctx.visib_token,
268 .lib_name = ctx.lib_name,
269 .comptime_token = null,
270 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
271 .mut_token = token_index,
272 .list = ctx.decls
273 }
274 });
275 continue;
276 },
277 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
278 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
279 const fn_proto = try arena.construct(ast.Node.FnProto {
280 .base = ast.Node {
281 .id = ast.Node.Id.FnProto,
282 },
283 .doc_comments = ctx.comments,
284 .visib_token = ctx.visib_token,
285 .name_token = null,
286 .fn_token = undefined,
287 .params = ast.Node.FnProto.ParamList.init(arena),
288 .return_type = undefined,
289 .var_args_token = null,
290 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
291 .cc_token = null,
292 .async_attr = null,
293 .body_node = null,
294 .lib_name = ctx.lib_name,
295 .align_expr = null,
296 });
297 try ctx.decls.push(&fn_proto.base);
298 stack.push(State { .FnDef = fn_proto }) catch unreachable;
299 try stack.push(State { .FnProto = fn_proto });
300
301 switch (token_ptr.id) {
302 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
303 fn_proto.cc_token = token_index;
304 try stack.push(State {
305 .ExpectTokenSave = ExpectTokenSave {
306 .id = Token.Id.Keyword_fn,
307 .ptr = &fn_proto.fn_token,
308 }
309 });
310 continue;
311 },
312 Token.Id.Keyword_async => {
313 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
314 ast.Node.AsyncAttribute {
315 .base = undefined,
316 .async_token = token_index,
317 .allocator_type = null,
318 .rangle_bracket = null,
319 }
320 );
321 fn_proto.async_attr = async_node;
322
323 try stack.push(State {
324 .ExpectTokenSave = ExpectTokenSave {
325 .id = Token.Id.Keyword_fn,
326 .ptr = &fn_proto.fn_token,
327 }
328 });
329 try stack.push(State { .AsyncAllocator = async_node });
330 continue;
331 },
332 Token.Id.Keyword_fn => {
333 fn_proto.fn_token = token_index;
334 continue;
335 },
336 else => unreachable,
337 }
338 },
339 else => {
340 *(try tree.errors.addOne()) = Error {
341 .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn { .token = token_index },
342 };
343 return tree;
344 },
345 }
346 },
347 State.TopLevelExternOrField => |ctx| {
348 if (eatToken(&tok_it, Token.Id.Identifier)) |identifier| {
349 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
350 const node = try arena.construct(ast.Node.StructField {
351 .base = ast.Node {
352 .id = ast.Node.Id.StructField,
353 },
354 .doc_comments = ctx.comments,
355 .visib_token = ctx.visib_token,
356 .name_token = identifier,
357 .type_expr = undefined,
358 });
359 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
360 *node_ptr = &node.base;
361
362 stack.push(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
363 try stack.push(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
364 try stack.push(State { .ExpectToken = Token.Id.Colon });
365 continue;
366 }
367
368 stack.push(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
369 try stack.push(State {
370 .TopLevelExtern = TopLevelDeclCtx {
371 .decls = &ctx.container_decl.fields_and_decls,
372 .visib_token = ctx.visib_token,
373 .extern_export_inline_token = null,
374 .lib_name = null,
375 .comments = ctx.comments,
376 }
377 });
378 continue;
379 },
380
381 State.FieldInitValue => |ctx| {
382 const eq_tok_index = tok_it.index;
383 const eq_tok_ptr = ??tok_it.next();
384 if (eq_tok_ptr.id != Token.Id.Equal) {
385 _ = tok_it.prev();
386 continue;
387 }
388 stack.push(State { .Expression = ctx }) catch unreachable;
389 continue;
390 },
391
392 State.ContainerKind => |ctx| {
393 const token_index = tok_it.index;
394 const token_ptr = ??tok_it.next();
395 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
396 ast.Node.ContainerDecl {
397 .base = undefined,
398 .ltoken = ctx.ltoken,
399 .layout = ctx.layout,
400 .kind = switch (token_ptr.id) {
401 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
402 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
403 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
404 else => {
405 *(try tree.errors.addOne()) = Error {
406 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
407 };
408 return tree;
409 },
410 },
411 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
412 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
413 .rbrace_token = undefined,
414 }
415 );
416
417 stack.push(State { .ContainerDecl = node }) catch unreachable;
418 try stack.push(State { .ExpectToken = Token.Id.LBrace });
419 try stack.push(State { .ContainerInitArgStart = node });
420 continue;
421 },
422
423 State.ContainerInitArgStart => |container_decl| {
424 if (eatToken(&tok_it, Token.Id.LParen) == null) {
425 continue;
426 }
427
428 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
429 try stack.push(State { .ContainerInitArg = container_decl });
430 continue;
431 },
432
433 State.ContainerInitArg => |container_decl| {
434 const init_arg_token_index = tok_it.index;
435 const init_arg_token_ptr = ??tok_it.next();
436 switch (init_arg_token_ptr.id) {
437 Token.Id.Keyword_enum => {
438 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
439 const lparen_tok_index = tok_it.index;
440 const lparen_tok_ptr = ??tok_it.next();
441 if (lparen_tok_ptr.id == Token.Id.LParen) {
442 try stack.push(State { .ExpectToken = Token.Id.RParen } );
443 try stack.push(State { .Expression = OptionalCtx {
444 .RequiredNull = &container_decl.init_arg_expr.Enum,
445 } });
446 } else {
447 _ = tok_it.prev();
448 }
449 },
450 else => {
451 _ = tok_it.prev();
452 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
453 stack.push(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
454 },
455 }
456 continue;
457 },
458
459 State.ContainerDecl => |container_decl| {
460 while (try eatLineComment(arena, &tok_it)) |line_comment| {
461 try container_decl.fields_and_decls.push(&line_comment.base);
462 }
463
464 const comments = try eatDocComments(arena, &tok_it);
465 const token_index = tok_it.index;
466 const token_ptr = ??tok_it.next();
467 switch (token_ptr.id) {
468 Token.Id.Identifier => {
469 switch (container_decl.kind) {
470 ast.Node.ContainerDecl.Kind.Struct => {
471 const node = try arena.construct(ast.Node.StructField {
472 .base = ast.Node {
473 .id = ast.Node.Id.StructField,
474 },
475 .doc_comments = comments,
476 .visib_token = null,
477 .name_token = token_index,
478 .type_expr = undefined,
479 });
480 const node_ptr = try container_decl.fields_and_decls.addOne();
481 *node_ptr = &node.base;
482
483 try stack.push(State { .FieldListCommaOrEnd = container_decl });
484 try stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
485 try stack.push(State { .ExpectToken = Token.Id.Colon });
486 continue;
487 },
488 ast.Node.ContainerDecl.Kind.Union => {
489 const node = try arena.construct(ast.Node.UnionTag {
490 .base = ast.Node {.id = ast.Node.Id.UnionTag },
491 .name_token = token_index,
492 .type_expr = null,
493 .value_expr = null,
494 .doc_comments = comments,
495 });
496 try container_decl.fields_and_decls.push(&node.base);
497
498 stack.push(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
499 try stack.push(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
500 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
501 try stack.push(State { .IfToken = Token.Id.Colon });
502 continue;
503 },
504 ast.Node.ContainerDecl.Kind.Enum => {
505 const node = try arena.construct(ast.Node.EnumTag {
506 .base = ast.Node { .id = ast.Node.Id.EnumTag },
507 .name_token = token_index,
508 .value = null,
509 .doc_comments = comments,
510 });
511 try container_decl.fields_and_decls.push(&node.base);
512
513 stack.push(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
514 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
515 try stack.push(State { .IfToken = Token.Id.Equal });
516 continue;
517 },
518 }
519 },
520 Token.Id.Keyword_pub => {
521 switch (container_decl.kind) {
522 ast.Node.ContainerDecl.Kind.Struct => {
523 try stack.push(State {
524 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
525 .visib_token = token_index,
526 .container_decl = container_decl,
527 .comments = comments,
528 }
529 });
530 continue;
531 },
532 else => {
533 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
534 try stack.push(State {
535 .TopLevelExtern = TopLevelDeclCtx {
536 .decls = &container_decl.fields_and_decls,
537 .visib_token = token_index,
538 .extern_export_inline_token = null,
539 .lib_name = null,
540 .comments = comments,
541 }
542 });
543 continue;
544 }
545 }
546 },
547 Token.Id.Keyword_export => {
548 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
549 try stack.push(State {
550 .TopLevelExtern = TopLevelDeclCtx {
551 .decls = &container_decl.fields_and_decls,
552 .visib_token = token_index,
553 .extern_export_inline_token = null,
554 .lib_name = null,
555 .comments = comments,
556 }
557 });
558 continue;
559 },
560 Token.Id.RBrace => {
561 if (comments != null) {
562 *(try tree.errors.addOne()) = Error {
563 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
564 };
565 return tree;
566 }
567 container_decl.rbrace_token = token_index;
568 continue;
569 },
570 else => {
571 _ = tok_it.prev();
572 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
573 try stack.push(State {
574 .TopLevelExtern = TopLevelDeclCtx {
575 .decls = &container_decl.fields_and_decls,
576 .visib_token = null,
577 .extern_export_inline_token = null,
578 .lib_name = null,
579 .comments = comments,
580 }
581 });
582 continue;
583 }
584 }
585 },
586
587
588 State.VarDecl => |ctx| {
589 const var_decl = try arena.construct(ast.Node.VarDecl {
590 .base = ast.Node {
591 .id = ast.Node.Id.VarDecl,
592 },
593 .doc_comments = ctx.comments,
594 .visib_token = ctx.visib_token,
595 .mut_token = ctx.mut_token,
596 .comptime_token = ctx.comptime_token,
597 .extern_export_token = ctx.extern_export_token,
598 .type_node = null,
599 .align_node = null,
600 .init_node = null,
601 .lib_name = ctx.lib_name,
602 // initialized later
603 .name_token = undefined,
604 .eq_token = undefined,
605 .semicolon_token = undefined,
606 });
607 try ctx.list.push(&var_decl.base);
608
609 try stack.push(State { .VarDeclAlign = var_decl });
610 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
611 try stack.push(State { .IfToken = Token.Id.Colon });
612 try stack.push(State {
613 .ExpectTokenSave = ExpectTokenSave {
614 .id = Token.Id.Identifier,
615 .ptr = &var_decl.name_token,
616 }
617 });
618 continue;
619 },
620 State.VarDeclAlign => |var_decl| {
621 try stack.push(State { .VarDeclEq = var_decl });
622
623 const next_token_index = tok_it.index;
624 const next_token_ptr = ??tok_it.next();
625 if (next_token_ptr.id == Token.Id.Keyword_align) {
626 try stack.push(State { .ExpectToken = Token.Id.RParen });
627 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
628 try stack.push(State { .ExpectToken = Token.Id.LParen });
629 continue;
630 }
631
632 _ = tok_it.prev();
633 continue;
634 },
635 State.VarDeclEq => |var_decl| {
636 const token_index = tok_it.index;
637 const token_ptr = ??tok_it.next();
638 switch (token_ptr.id) {
639 Token.Id.Equal => {
640 var_decl.eq_token = token_index;
641 stack.push(State {
642 .ExpectTokenSave = ExpectTokenSave {
643 .id = Token.Id.Semicolon,
644 .ptr = &var_decl.semicolon_token,
645 },
646 }) catch unreachable;
647 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
648 continue;
649 },
650 Token.Id.Semicolon => {
651 var_decl.semicolon_token = token_index;
652 continue;
653 },
654 else => {
655 *(try tree.errors.addOne()) = Error {
656 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
657 };
658 return tree;
659 }
660 }
661 },
662
663
664 State.FnDef => |fn_proto| {
665 const token_index = tok_it.index;
666 const token_ptr = ??tok_it.next();
667 switch(token_ptr.id) {
668 Token.Id.LBrace => {
669 const block = try arena.construct(ast.Node.Block {
670 .base = ast.Node { .id = ast.Node.Id.Block },
671 .label = null,
672 .lbrace = token_index,
673 .statements = ast.Node.Block.StatementList.init(arena),
674 .rbrace = undefined,
675 });
676 fn_proto.body_node = &block.base;
677 stack.push(State { .Block = block }) catch unreachable;
678 continue;
679 },
680 Token.Id.Semicolon => continue,
681 else => {
682 *(try tree.errors.addOne()) = Error {
683 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
684 };
685 return tree;
686 },
687 }
688 },
689 State.FnProto => |fn_proto| {
690 stack.push(State { .FnProtoAlign = fn_proto }) catch unreachable;
691 try stack.push(State { .ParamDecl = fn_proto });
692 try stack.push(State { .ExpectToken = Token.Id.LParen });
693
694 if (eatToken(&tok_it, Token.Id.Identifier)) |name_token| {
695 fn_proto.name_token = name_token;
696 }
697 continue;
698 },
699 State.FnProtoAlign => |fn_proto| {
700 stack.push(State { .FnProtoReturnType = fn_proto }) catch unreachable;
701
702 if (eatToken(&tok_it, Token.Id.Keyword_align)) |align_token| {
703 try stack.push(State { .ExpectToken = Token.Id.RParen });
704 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
705 try stack.push(State { .ExpectToken = Token.Id.LParen });
706 }
707 continue;
708 },
709 State.FnProtoReturnType => |fn_proto| {
710 const token_index = tok_it.index;
711 const token_ptr = ??tok_it.next();
712 switch (token_ptr.id) {
713 Token.Id.Bang => {
714 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
715 stack.push(State {
716 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
717 }) catch unreachable;
718 continue;
719 },
720 else => {
721 // TODO: this is a special case. Remove this when #760 is fixed
722 if (token_ptr.id == Token.Id.Keyword_error) {
723 if ((??tok_it.peek()).id == Token.Id.LBrace) {
724 const error_type_node = try arena.construct(ast.Node.ErrorType {
725 .base = ast.Node { .id = ast.Node.Id.ErrorType },
726 .token = token_index,
727 });
728 fn_proto.return_type = ast.Node.FnProto.ReturnType {
729 .Explicit = &error_type_node.base,
730 };
731 continue;
732 }
733 }
734
735 _ = tok_it.prev();
736 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
737 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
738 continue;
739 },
740 }
741 },
742
743
744 State.ParamDecl => |fn_proto| {
745 if (eatToken(&tok_it, Token.Id.RParen)) |_| {
746 continue;
747 }
748 const param_decl = try arena.construct(ast.Node.ParamDecl {
749 .base = ast.Node {.id = ast.Node.Id.ParamDecl },
750 .comptime_token = null,
751 .noalias_token = null,
752 .name_token = null,
753 .type_node = undefined,
754 .var_args_token = null,
755 });
756 try fn_proto.params.push(&param_decl.base);
757
758 stack.push(State {
759 .ParamDeclEnd = ParamDeclEndCtx {
760 .param_decl = param_decl,
761 .fn_proto = fn_proto,
762 }
763 }) catch unreachable;
764 try stack.push(State { .ParamDeclName = param_decl });
765 try stack.push(State { .ParamDeclAliasOrComptime = param_decl });
766 continue;
767 },
768 State.ParamDeclAliasOrComptime => |param_decl| {
769 if (eatToken(&tok_it, Token.Id.Keyword_comptime)) |comptime_token| {
770 param_decl.comptime_token = comptime_token;
771 } else if (eatToken(&tok_it, Token.Id.Keyword_noalias)) |noalias_token| {
772 param_decl.noalias_token = noalias_token;
773 }
774 continue;
775 },
776 State.ParamDeclName => |param_decl| {
777 // TODO: Here, we eat two tokens in one state. This means that we can't have
778 // comments between these two tokens.
779 if (eatToken(&tok_it, Token.Id.Identifier)) |ident_token| {
780 if (eatToken(&tok_it, Token.Id.Colon)) |_| {
781 param_decl.name_token = ident_token;
782 } else {
783 _ = tok_it.prev();
784 }
785 }
786 continue;
787 },
788 State.ParamDeclEnd => |ctx| {
789 if (eatToken(&tok_it, Token.Id.Ellipsis3)) |ellipsis3| {
790 ctx.param_decl.var_args_token = ellipsis3;
791 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
792 continue;
793 }
794
795 try stack.push(State { .ParamDeclComma = ctx.fn_proto });
796 try stack.push(State {
797 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
798 });
799 continue;
800 },
801 State.ParamDeclComma => |fn_proto| {
802 switch (expectCommaOrEnd(&tok_it, Token.Id.RParen)) {
803 ExpectCommaOrEndResult.end_token => |t| {
804 if (t == null) {
805 stack.push(State { .ParamDecl = fn_proto }) catch unreachable;
806 }
807 continue;
808 },
809 ExpectCommaOrEndResult.parse_error => |e| {
810 try tree.errors.push(e);
811 return tree;
812 },
813 }
814 },
815
816 State.MaybeLabeledExpression => |ctx| {
817 if (eatToken(&tok_it, Token.Id.Colon)) |_| {
818 stack.push(State {
819 .LabeledExpression = LabelCtx {
820 .label = ctx.label,
821 .opt_ctx = ctx.opt_ctx,
822 }
823 }) catch unreachable;
824 continue;
825 }
826
827 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
828 continue;
829 },
830 State.LabeledExpression => |ctx| {
831 const token_index = tok_it.index;
832 const token_ptr = ??tok_it.next();
833 switch (token_ptr.id) {
834 Token.Id.LBrace => {
835 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
836 ast.Node.Block {
837 .base = undefined,
838 .label = ctx.label,
839 .lbrace = token_index,
840 .statements = ast.Node.Block.StatementList.init(arena),
841 .rbrace = undefined,
842 }
843 );
844 stack.push(State { .Block = block }) catch unreachable;
845 continue;
846 },
847 Token.Id.Keyword_while => {
848 stack.push(State {
849 .While = LoopCtx {
850 .label = ctx.label,
851 .inline_token = null,
852 .loop_token = token_index,
853 .opt_ctx = ctx.opt_ctx.toRequired(),
854 }
855 }) catch unreachable;
856 continue;
857 },
858 Token.Id.Keyword_for => {
859 stack.push(State {
860 .For = LoopCtx {
861 .label = ctx.label,
862 .inline_token = null,
863 .loop_token = token_index,
864 .opt_ctx = ctx.opt_ctx.toRequired(),
865 }
866 }) catch unreachable;
867 continue;
868 },
869 Token.Id.Keyword_suspend => {
870 const node = try arena.construct(ast.Node.Suspend {
871 .base = ast.Node {
872 .id = ast.Node.Id.Suspend,
873 },
874 .label = ctx.label,
875 .suspend_token = token_index,
876 .payload = null,
877 .body = null,
878 });
879 ctx.opt_ctx.store(&node.base);
880 stack.push(State { .SuspendBody = node }) catch unreachable;
881 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
882 continue;
883 },
884 Token.Id.Keyword_inline => {
885 stack.push(State {
886 .Inline = InlineCtx {
887 .label = ctx.label,
888 .inline_token = token_index,
889 .opt_ctx = ctx.opt_ctx.toRequired(),
890 }
891 }) catch unreachable;
892 continue;
893 },
894 else => {
895 if (ctx.opt_ctx != OptionalCtx.Optional) {
896 *(try tree.errors.addOne()) = Error {
897 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
898 };
899 return tree;
900 }
901
902 _ = tok_it.prev();
903 continue;
904 },
905 }
906 },
907 State.Inline => |ctx| {
908 const token_index = tok_it.index;
909 const token_ptr = ??tok_it.next();
910 switch (token_ptr.id) {
911 Token.Id.Keyword_while => {
912 stack.push(State {
913 .While = LoopCtx {
914 .inline_token = ctx.inline_token,
915 .label = ctx.label,
916 .loop_token = token_index,
917 .opt_ctx = ctx.opt_ctx.toRequired(),
918 }
919 }) catch unreachable;
920 continue;
921 },
922 Token.Id.Keyword_for => {
923 stack.push(State {
924 .For = LoopCtx {
925 .inline_token = ctx.inline_token,
926 .label = ctx.label,
927 .loop_token = token_index,
928 .opt_ctx = ctx.opt_ctx.toRequired(),
929 }
930 }) catch unreachable;
931 continue;
932 },
933 else => {
934 if (ctx.opt_ctx != OptionalCtx.Optional) {
935 *(try tree.errors.addOne()) = Error {
936 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
937 };
938 return tree;
939 }
940
941 _ = tok_it.prev();
942 continue;
943 },
944 }
945 },
946 State.While => |ctx| {
947 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
948 ast.Node.While {
949 .base = undefined,
950 .label = ctx.label,
951 .inline_token = ctx.inline_token,
952 .while_token = ctx.loop_token,
953 .condition = undefined,
954 .payload = null,
955 .continue_expr = null,
956 .body = undefined,
957 .@"else" = null,
958 }
959 );
960 stack.push(State { .Else = &node.@"else" }) catch unreachable;
961 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
962 try stack.push(State { .WhileContinueExpr = &node.continue_expr });
963 try stack.push(State { .IfToken = Token.Id.Colon });
964 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
965 try stack.push(State { .ExpectToken = Token.Id.RParen });
966 try stack.push(State { .Expression = OptionalCtx { .Required = &node.condition } });
967 try stack.push(State { .ExpectToken = Token.Id.LParen });
968 continue;
969 },
970 State.WhileContinueExpr => |dest| {
971 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
972 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
973 try stack.push(State { .ExpectToken = Token.Id.LParen });
974 continue;
975 },
976 State.For => |ctx| {
977 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
978 ast.Node.For {
979 .base = undefined,
980 .label = ctx.label,
981 .inline_token = ctx.inline_token,
982 .for_token = ctx.loop_token,
983 .array_expr = undefined,
984 .payload = null,
985 .body = undefined,
986 .@"else" = null,
987 }
988 );
989 stack.push(State { .Else = &node.@"else" }) catch unreachable;
990 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
991 try stack.push(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
992 try stack.push(State { .ExpectToken = Token.Id.RParen });
993 try stack.push(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
994 try stack.push(State { .ExpectToken = Token.Id.LParen });
995 continue;
996 },
997 State.Else => |dest| {
998 if (eatToken(&tok_it, Token.Id.Keyword_else)) |else_token| {
999 const node = try createNode(arena, ast.Node.Else,
1000 ast.Node.Else {
1001 .base = undefined,
1002 .else_token = else_token,
1003 .payload = null,
1004 .body = undefined,
1005 }
1006 );
1007 *dest = node;
1008
1009 stack.push(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1010 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1011 continue;
1012 } else {
1013 continue;
1014 }
1015 },
1016
1017
1018 State.Block => |block| {
1019 const token_index = tok_it.index;
1020 const token_ptr = ??tok_it.next();
1021 switch (token_ptr.id) {
1022 Token.Id.RBrace => {
1023 block.rbrace = token_index;
1024 continue;
1025 },
1026 else => {
1027 _ = tok_it.prev();
1028 stack.push(State { .Block = block }) catch unreachable;
1029
1030 var any_comments = false;
1031 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1032 try block.statements.push(&line_comment.base);
1033 any_comments = true;
1034 }
1035 if (any_comments) continue;
1036
1037 try stack.push(State { .Statement = block });
1038 continue;
1039 },
1040 }
1041 },
1042 State.Statement => |block| {
1043 const token_index = tok_it.index;
1044 const token_ptr = ??tok_it.next();
1045 switch (token_ptr.id) {
1046 Token.Id.Keyword_comptime => {
1047 stack.push(State {
1048 .ComptimeStatement = ComptimeStatementCtx {
1049 .comptime_token = token_index,
1050 .block = block,
1051 }
1052 }) catch unreachable;
1053 continue;
1054 },
1055 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1056 stack.push(State {
1057 .VarDecl = VarDeclCtx {
1058 .comments = null,
1059 .visib_token = null,
1060 .comptime_token = null,
1061 .extern_export_token = null,
1062 .lib_name = null,
1063 .mut_token = token_index,
1064 .list = &block.statements,
1065 }
1066 }) catch unreachable;
1067 continue;
1068 },
1069 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1070 const node = try arena.construct(ast.Node.Defer {
1071 .base = ast.Node {
1072 .id = ast.Node.Id.Defer,
1073 },
1074 .defer_token = token_index,
1075 .kind = switch (token_ptr.id) {
1076 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1077 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1078 else => unreachable,
1079 },
1080 .expr = undefined,
1081 });
1082 const node_ptr = try block.statements.addOne();
1083 *node_ptr = &node.base;
1084
1085 stack.push(State { .Semicolon = node_ptr }) catch unreachable;
1086 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1087 continue;
1088 },
1089 Token.Id.LBrace => {
1090 const inner_block = try arena.construct(ast.Node.Block {
1091 .base = ast.Node { .id = ast.Node.Id.Block },
1092 .label = null,
1093 .lbrace = token_index,
1094 .statements = ast.Node.Block.StatementList.init(arena),
1095 .rbrace = undefined,
1096 });
1097 try block.statements.push(&inner_block.base);
1098
1099 stack.push(State { .Block = inner_block }) catch unreachable;
1100 continue;
1101 },
1102 else => {
1103 _ = tok_it.prev();
1104 const statement = try block.statements.addOne();
1105 try stack.push(State { .Semicolon = statement });
1106 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1107 continue;
1108 }
1109 }
1110 },
1111 State.ComptimeStatement => |ctx| {
1112 const token_index = tok_it.index;
1113 const token_ptr = ??tok_it.next();
1114 switch (token_ptr.id) {
1115 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1116 stack.push(State {
1117 .VarDecl = VarDeclCtx {
1118 .comments = null,
1119 .visib_token = null,
1120 .comptime_token = ctx.comptime_token,
1121 .extern_export_token = null,
1122 .lib_name = null,
1123 .mut_token = token_index,
1124 .list = &ctx.block.statements,
1125 }
1126 }) catch unreachable;
1127 continue;
1128 },
1129 else => {
1130 _ = tok_it.prev();
1131 _ = tok_it.prev();
1132 const statement = try ctx.block.statements.addOne();
1133 try stack.push(State { .Semicolon = statement });
1134 try stack.push(State { .Expression = OptionalCtx { .Required = statement } });
1135 continue;
1136 }
1137 }
1138 },
1139 State.Semicolon => |node_ptr| {
1140 const node = *node_ptr;
1141 if (node.requireSemiColon()) {
1142 stack.push(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1143 continue;
1144 }
1145 continue;
1146 },
1147
1148 State.AsmOutputItems => |items| {
1149 const lbracket_index = tok_it.index;
1150 const lbracket_ptr = ??tok_it.next();
1151 if (lbracket_ptr.id != Token.Id.LBracket) {
1152 _ = tok_it.prev();
1153 continue;
1154 }
1155
1156 const node = try createNode(arena, ast.Node.AsmOutput,
1157 ast.Node.AsmOutput {
1158 .base = undefined,
1159 .symbolic_name = undefined,
1160 .constraint = undefined,
1161 .kind = undefined,
1162 }
1163 );
1164 try items.push(node);
1165
1166 stack.push(State { .AsmOutputItems = items }) catch unreachable;
1167 try stack.push(State { .IfToken = Token.Id.Comma });
1168 try stack.push(State { .ExpectToken = Token.Id.RParen });
1169 try stack.push(State { .AsmOutputReturnOrType = node });
1170 try stack.push(State { .ExpectToken = Token.Id.LParen });
1171 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1172 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1173 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1174 continue;
1175 },
1176 State.AsmOutputReturnOrType => |node| {
1177 const token_index = tok_it.index;
1178 const token_ptr = ??tok_it.next();
1179 switch (token_ptr.id) {
1180 Token.Id.Identifier => {
1181 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1182 continue;
1183 },
1184 Token.Id.Arrow => {
1185 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1186 try stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1187 continue;
1188 },
1189 else => {
1190 *(try tree.errors.addOne()) = Error {
1191 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1192 .token = token_index,
1193 },
1194 };
1195 return tree;
1196 },
1197 }
1198 },
1199 State.AsmInputItems => |items| {
1200 const lbracket_index = tok_it.index;
1201 const lbracket_ptr = ??tok_it.next();
1202 if (lbracket_ptr.id != Token.Id.LBracket) {
1203 _ = tok_it.prev();
1204 continue;
1205 }
1206
1207 const node = try createNode(arena, ast.Node.AsmInput,
1208 ast.Node.AsmInput {
1209 .base = undefined,
1210 .symbolic_name = undefined,
1211 .constraint = undefined,
1212 .expr = undefined,
1213 }
1214 );
1215 try items.push(node);
1216
1217 stack.push(State { .AsmInputItems = items }) catch unreachable;
1218 try stack.push(State { .IfToken = Token.Id.Comma });
1219 try stack.push(State { .ExpectToken = Token.Id.RParen });
1220 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
1221 try stack.push(State { .ExpectToken = Token.Id.LParen });
1222 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1223 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1224 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1225 continue;
1226 },
1227 State.AsmClobberItems => |items| {
1228 stack.push(State { .AsmClobberItems = items }) catch unreachable;
1229 try stack.push(State { .IfToken = Token.Id.Comma });
1230 try stack.push(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1231 continue;
1232 },
1233
1234
1235 State.ExprListItemOrEnd => |list_state| {
1236 if (eatToken(&tok_it, list_state.end)) |token_index| {
1237 *list_state.ptr = token_index;
1238 continue;
1239 }
1240
1241 stack.push(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1242 try stack.push(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1243 continue;
1244 },
1245 State.ExprListCommaOrEnd => |list_state| {
1246 switch (expectCommaOrEnd(&tok_it, list_state.end)) {
1247 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1248 *list_state.ptr = end;
1249 continue;
1250 } else {
1251 stack.push(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1252 continue;
1253 },
1254 ExpectCommaOrEndResult.parse_error => |e| {
1255 try tree.errors.push(e);
1256 return tree;
1257 },
1258 }
1259 },
1260 State.FieldInitListItemOrEnd => |list_state| {
1261 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1262 try list_state.list.push(&line_comment.base);
1263 }
1264
1265 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1266 *list_state.ptr = rbrace;
1267 continue;
1268 }
1269
1270 const node = try arena.construct(ast.Node.FieldInitializer {
1271 .base = ast.Node {
1272 .id = ast.Node.Id.FieldInitializer,
1273 },
1274 .period_token = undefined,
1275 .name_token = undefined,
1276 .expr = undefined,
1277 });
1278 try list_state.list.push(&node.base);
1279
1280 stack.push(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1281 try stack.push(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1282 try stack.push(State { .ExpectToken = Token.Id.Equal });
1283 try stack.push(State {
1284 .ExpectTokenSave = ExpectTokenSave {
1285 .id = Token.Id.Identifier,
1286 .ptr = &node.name_token,
1287 }
1288 });
1289 try stack.push(State {
1290 .ExpectTokenSave = ExpectTokenSave {
1291 .id = Token.Id.Period,
1292 .ptr = &node.period_token,
1293 }
1294 });
1295 continue;
1296 },
1297 State.FieldInitListCommaOrEnd => |list_state| {
1298 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1299 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1300 *list_state.ptr = end;
1301 continue;
1302 } else {
1303 stack.push(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1304 continue;
1305 },
1306 ExpectCommaOrEndResult.parse_error => |e| {
1307 try tree.errors.push(e);
1308 return tree;
1309 },
1310 }
1311 },
1312 State.FieldListCommaOrEnd => |container_decl| {
1313 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1314 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1315 container_decl.rbrace_token = end;
1316 continue;
1317 } else {
1318 try stack.push(State { .ContainerDecl = container_decl });
1319 continue;
1320 },
1321 ExpectCommaOrEndResult.parse_error => |e| {
1322 try tree.errors.push(e);
1323 return tree;
1324 },
1325 }
1326 },
1327 State.ErrorTagListItemOrEnd => |list_state| {
1328 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1329 try list_state.list.push(&line_comment.base);
1330 }
1331
1332 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1333 *list_state.ptr = rbrace;
1334 continue;
1335 }
1336
1337 const node_ptr = try list_state.list.addOne();
1338
1339 try stack.push(State { .ErrorTagListCommaOrEnd = list_state });
1340 try stack.push(State { .ErrorTag = node_ptr });
1341 continue;
1342 },
1343 State.ErrorTagListCommaOrEnd => |list_state| {
1344 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1345 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1346 *list_state.ptr = end;
1347 continue;
1348 } else {
1349 stack.push(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1350 continue;
1351 },
1352 ExpectCommaOrEndResult.parse_error => |e| {
1353 try tree.errors.push(e);
1354 return tree;
1355 },
1356 }
1357 },
1358 State.SwitchCaseOrEnd => |list_state| {
1359 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1360 try list_state.list.push(&line_comment.base);
1361 }
1362
1363 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1364 *list_state.ptr = rbrace;
1365 continue;
1366 }
1367
1368 const comments = try eatDocComments(arena, &tok_it);
1369 const node = try arena.construct(ast.Node.SwitchCase {
1370 .base = ast.Node {
1371 .id = ast.Node.Id.SwitchCase,
1372 },
1373 .items = ast.Node.SwitchCase.ItemList.init(arena),
1374 .payload = null,
1375 .expr = undefined,
1376 });
1377 try list_state.list.push(&node.base);
1378 try stack.push(State { .SwitchCaseCommaOrEnd = list_state });
1379 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1380 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1381 try stack.push(State { .SwitchCaseFirstItem = &node.items });
1382
1383 continue;
1384 },
1385
1386 State.SwitchCaseCommaOrEnd => |list_state| {
1387 switch (expectCommaOrEnd(&tok_it, Token.Id.RParen)) {
1388 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1389 *list_state.ptr = end;
1390 continue;
1391 } else {
1392 try stack.push(State { .SwitchCaseOrEnd = list_state });
1393 continue;
1394 },
1395 ExpectCommaOrEndResult.parse_error => |e| {
1396 try tree.errors.push(e);
1397 return tree;
1398 },
1399 }
1400 },
1401
1402 State.SwitchCaseFirstItem => |case_items| {
1403 const token_index = tok_it.index;
1404 const token_ptr = ??tok_it.next();
1405 if (token_ptr.id == Token.Id.Keyword_else) {
1406 const else_node = try arena.construct(ast.Node.SwitchElse {
1407 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},
1408 .token = token_index,
1409 });
1410 try case_items.push(&else_node.base);
1411
1412 try stack.push(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1413 continue;
1414 } else {
1415 _ = tok_it.prev();
1416 try stack.push(State { .SwitchCaseItem = case_items });
1417 continue;
1418 }
1419 },
1420 State.SwitchCaseItem => |case_items| {
1421 stack.push(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1422 try stack.push(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1423 },
1424 State.SwitchCaseItemCommaOrEnd => |case_items| {
1425 switch (expectCommaOrEnd(&tok_it, Token.Id.EqualAngleBracketRight)) {
1426 ExpectCommaOrEndResult.end_token => |t| {
1427 if (t == null) {
1428 stack.push(State { .SwitchCaseItem = case_items }) catch unreachable;
1429 }
1430 continue;
1431 },
1432 ExpectCommaOrEndResult.parse_error => |e| {
1433 try tree.errors.push(e);
1434 return tree;
1435 },
1436 }
1437 continue;
1438 },
1439
1440
1441 State.SuspendBody => |suspend_node| {
1442 if (suspend_node.payload != null) {
1443 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1444 }
1445 continue;
1446 },
1447 State.AsyncAllocator => |async_node| {
1448 if (eatToken(&tok_it, Token.Id.AngleBracketLeft) == null) {
1449 continue;
1450 }
1451
1452 async_node.rangle_bracket = TokenIndex(0);
1453 try stack.push(State {
1454 .ExpectTokenSave = ExpectTokenSave {
1455 .id = Token.Id.AngleBracketRight,
1456 .ptr = &??async_node.rangle_bracket,
1457 }
1458 });
1459 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1460 continue;
1461 },
1462 State.AsyncEnd => |ctx| {
1463 const node = ctx.ctx.get() ?? continue;
1464
1465 switch (node.id) {
1466 ast.Node.Id.FnProto => {
1467 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1468 fn_proto.async_attr = ctx.attribute;
1469 continue;
1470 },
1471 ast.Node.Id.SuffixOp => {
1472 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1473 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1474 suffix_op.op.Call.async_attr = ctx.attribute;
1475 continue;
1476 }
1477
1478 *(try tree.errors.addOne()) = Error {
1479 .ExpectedCall = Error.ExpectedCall { .node = node },
1480 };
1481 return tree;
1482 },
1483 else => {
1484 *(try tree.errors.addOne()) = Error {
1485 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1486 };
1487 return tree;
1488 }
1489 }
1490 },
1491
1492
1493 State.ExternType => |ctx| {
1494 if (eatToken(&tok_it, Token.Id.Keyword_fn)) |fn_token| {
1495 const fn_proto = try arena.construct(ast.Node.FnProto {
1496 .base = ast.Node {
1497 .id = ast.Node.Id.FnProto,
1498 },
1499 .doc_comments = ctx.comments,
1500 .visib_token = null,
1501 .name_token = null,
1502 .fn_token = fn_token,
1503 .params = ast.Node.FnProto.ParamList.init(arena),
1504 .return_type = undefined,
1505 .var_args_token = null,
1506 .extern_export_inline_token = ctx.extern_token,
1507 .cc_token = null,
1508 .async_attr = null,
1509 .body_node = null,
1510 .lib_name = null,
1511 .align_expr = null,
1512 });
1513 ctx.opt_ctx.store(&fn_proto.base);
1514 stack.push(State { .FnProto = fn_proto }) catch unreachable;
1515 continue;
1516 }
1517
1518 stack.push(State {
1519 .ContainerKind = ContainerKindCtx {
1520 .opt_ctx = ctx.opt_ctx,
1521 .ltoken = ctx.extern_token,
1522 .layout = ast.Node.ContainerDecl.Layout.Extern,
1523 },
1524 }) catch unreachable;
1525 continue;
1526 },
1527 State.SliceOrArrayAccess => |node| {
1528 const token_index = tok_it.index;
1529 const token_ptr = ??tok_it.next();
1530 switch (token_ptr.id) {
1531 Token.Id.Ellipsis2 => {
1532 const start = node.op.ArrayAccess;
1533 node.op = ast.Node.SuffixOp.Op {
1534 .Slice = ast.Node.SuffixOp.Op.Slice {
1535 .start = start,
1536 .end = null,
1537 }
1538 };
1539
1540 stack.push(State {
1541 .ExpectTokenSave = ExpectTokenSave {
1542 .id = Token.Id.RBracket,
1543 .ptr = &node.rtoken,
1544 }
1545 }) catch unreachable;
1546 try stack.push(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1547 continue;
1548 },
1549 Token.Id.RBracket => {
1550 node.rtoken = token_index;
1551 continue;
1552 },
1553 else => {
1554 *(try tree.errors.addOne()) = Error {
1555 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1556 };
1557 return tree;
1558 }
1559 }
1560 },
1561 State.SliceOrArrayType => |node| {
1562 if (eatToken(&tok_it, Token.Id.RBracket)) |_| {
1563 node.op = ast.Node.PrefixOp.Op {
1564 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1565 .align_expr = null,
1566 .bit_offset_start_token = null,
1567 .bit_offset_end_token = null,
1568 .const_token = null,
1569 .volatile_token = null,
1570 }
1571 };
1572 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1573 try stack.push(State { .AddrOfModifiers = &node.op.SliceType });
1574 continue;
1575 }
1576
1577 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1578 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1579 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1580 try stack.push(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1581 continue;
1582 },
1583 State.AddrOfModifiers => |addr_of_info| {
1584 const token_index = tok_it.index;
1585 const token_ptr = ??tok_it.next();
1586 switch (token_ptr.id) {
1587 Token.Id.Keyword_align => {
1588 stack.push(state) catch unreachable;
1589 if (addr_of_info.align_expr != null) {
1590 *(try tree.errors.addOne()) = Error {
1591 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1592 };
1593 return tree;
1594 }
1595 try stack.push(State { .ExpectToken = Token.Id.RParen });
1596 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1597 try stack.push(State { .ExpectToken = Token.Id.LParen });
1598 continue;
1599 },
1600 Token.Id.Keyword_const => {
1601 stack.push(state) catch unreachable;
1602 if (addr_of_info.const_token != null) {
1603 *(try tree.errors.addOne()) = Error {
1604 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1605 };
1606 return tree;
1607 }
1608 addr_of_info.const_token = token_index;
1609 continue;
1610 },
1611 Token.Id.Keyword_volatile => {
1612 stack.push(state) catch unreachable;
1613 if (addr_of_info.volatile_token != null) {
1614 *(try tree.errors.addOne()) = Error {
1615 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1616 };
1617 return tree;
1618 }
1619 addr_of_info.volatile_token = token_index;
1620 continue;
1621 },
1622 else => {
1623 _ = tok_it.prev();
1624 continue;
1625 },
1626 }
1627 },
1628
1629
1630 State.Payload => |opt_ctx| {
1631 const token_index = tok_it.index;
1632 const token_ptr = ??tok_it.next();
1633 if (token_ptr.id != Token.Id.Pipe) {
1634 if (opt_ctx != OptionalCtx.Optional) {
1635 *(try tree.errors.addOne()) = Error {
1636 .ExpectedToken = Error.ExpectedToken {
1637 .token = token_index,
1638 .expected_id = Token.Id.Pipe,
1639 },
1640 };
1641 return tree;
1642 }
1643
1644 _ = tok_it.prev();
1645 continue;
1646 }
1647
1648 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1649 ast.Node.Payload {
1650 .base = undefined,
1651 .lpipe = token_index,
1652 .error_symbol = undefined,
1653 .rpipe = undefined
1654 }
1655 );
1656
1657 stack.push(State {
1658 .ExpectTokenSave = ExpectTokenSave {
1659 .id = Token.Id.Pipe,
1660 .ptr = &node.rpipe,
1661 }
1662 }) catch unreachable;
1663 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1664 continue;
1665 },
1666 State.PointerPayload => |opt_ctx| {
1667 const token_index = tok_it.index;
1668 const token_ptr = ??tok_it.next();
1669 if (token_ptr.id != Token.Id.Pipe) {
1670 if (opt_ctx != OptionalCtx.Optional) {
1671 *(try tree.errors.addOne()) = Error {
1672 .ExpectedToken = Error.ExpectedToken {
1673 .token = token_index,
1674 .expected_id = Token.Id.Pipe,
1675 },
1676 };
1677 return tree;
1678 }
1679
1680 _ = tok_it.prev();
1681 continue;
1682 }
1683
1684 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1685 ast.Node.PointerPayload {
1686 .base = undefined,
1687 .lpipe = token_index,
1688 .ptr_token = null,
1689 .value_symbol = undefined,
1690 .rpipe = undefined
1691 }
1692 );
1693
1694 try stack.push(State {
1695 .ExpectTokenSave = ExpectTokenSave {
1696 .id = Token.Id.Pipe,
1697 .ptr = &node.rpipe,
1698 }
1699 });
1700 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1701 try stack.push(State {
1702 .OptionalTokenSave = OptionalTokenSave {
1703 .id = Token.Id.Asterisk,
1704 .ptr = &node.ptr_token,
1705 }
1706 });
1707 continue;
1708 },
1709 State.PointerIndexPayload => |opt_ctx| {
1710 const token_index = tok_it.index;
1711 const token_ptr = ??tok_it.next();
1712 if (token_ptr.id != Token.Id.Pipe) {
1713 if (opt_ctx != OptionalCtx.Optional) {
1714 *(try tree.errors.addOne()) = Error {
1715 .ExpectedToken = Error.ExpectedToken {
1716 .token = token_index,
1717 .expected_id = Token.Id.Pipe,
1718 },
1719 };
1720 return tree;
1721 }
1722
1723 _ = tok_it.prev();
1724 continue;
1725 }
1726
1727 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1728 ast.Node.PointerIndexPayload {
1729 .base = undefined,
1730 .lpipe = token_index,
1731 .ptr_token = null,
1732 .value_symbol = undefined,
1733 .index_symbol = null,
1734 .rpipe = undefined
1735 }
1736 );
1737
1738 stack.push(State {
1739 .ExpectTokenSave = ExpectTokenSave {
1740 .id = Token.Id.Pipe,
1741 .ptr = &node.rpipe,
1742 }
1743 }) catch unreachable;
1744 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1745 try stack.push(State { .IfToken = Token.Id.Comma });
1746 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1747 try stack.push(State {
1748 .OptionalTokenSave = OptionalTokenSave {
1749 .id = Token.Id.Asterisk,
1750 .ptr = &node.ptr_token,
1751 }
1752 });
1753 continue;
1754 },
1755
1756
1757 State.Expression => |opt_ctx| {
1758 const token_index = tok_it.index;
1759 const token_ptr = ??tok_it.next();
1760 switch (token_ptr.id) {
1761 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1762 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1763 ast.Node.ControlFlowExpression {
1764 .base = undefined,
1765 .ltoken = token_index,
1766 .kind = undefined,
1767 .rhs = null,
1768 }
1769 );
1770
1771 stack.push(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1772
1773 switch (token_ptr.id) {
1774 Token.Id.Keyword_break => {
1775 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1776 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1777 try stack.push(State { .IfToken = Token.Id.Colon });
1778 },
1779 Token.Id.Keyword_continue => {
1780 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1781 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1782 try stack.push(State { .IfToken = Token.Id.Colon });
1783 },
1784 Token.Id.Keyword_return => {
1785 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1786 },
1787 else => unreachable,
1788 }
1789 continue;
1790 },
1791 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1792 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1793 ast.Node.PrefixOp {
1794 .base = undefined,
1795 .op_token = token_index,
1796 .op = switch (token_ptr.id) {
1797 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1798 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1799 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1800 else => unreachable,
1801 },
1802 .rhs = undefined,
1803 }
1804 );
1805
1806 stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1807 continue;
1808 },
1809 else => {
1810 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1811 _ = tok_it.prev();
1812 stack.push(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1813 }
1814 continue;
1815 }
1816 }
1817 },
1818 State.RangeExpressionBegin => |opt_ctx| {
1819 stack.push(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1820 try stack.push(State { .Expression = opt_ctx });
1821 continue;
1822 },
1823 State.RangeExpressionEnd => |opt_ctx| {
1824 const lhs = opt_ctx.get() ?? continue;
1825
1826 if (eatToken(&tok_it, Token.Id.Ellipsis3)) |ellipsis3| {
1827 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1828 ast.Node.InfixOp {
1829 .base = undefined,
1830 .lhs = lhs,
1831 .op_token = ellipsis3,
1832 .op = ast.Node.InfixOp.Op.Range,
1833 .rhs = undefined,
1834 }
1835 );
1836 stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1837 continue;
1838 }
1839 },
1840 State.AssignmentExpressionBegin => |opt_ctx| {
1841 stack.push(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1842 try stack.push(State { .Expression = opt_ctx });
1843 continue;
1844 },
1845
1846 State.AssignmentExpressionEnd => |opt_ctx| {
1847 const lhs = opt_ctx.get() ?? continue;
1848
1849 const token_index = tok_it.index;
1850 const token_ptr = ??tok_it.next();
1851 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1852 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1853 ast.Node.InfixOp {
1854 .base = undefined,
1855 .lhs = lhs,
1856 .op_token = token_index,
1857 .op = ass_id,
1858 .rhs = undefined,
1859 }
1860 );
1861 stack.push(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1862 try stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1863 continue;
1864 } else {
1865 _ = tok_it.prev();
1866 continue;
1867 }
1868 },
1869
1870 State.UnwrapExpressionBegin => |opt_ctx| {
1871 stack.push(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1872 try stack.push(State { .BoolOrExpressionBegin = opt_ctx });
1873 continue;
1874 },
1875
1876 State.UnwrapExpressionEnd => |opt_ctx| {
1877 const lhs = opt_ctx.get() ?? continue;
1878
1879 const token_index = tok_it.index;
1880 const token_ptr = ??tok_it.next();
1881 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1882 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1883 ast.Node.InfixOp {
1884 .base = undefined,
1885 .lhs = lhs,
1886 .op_token = token_index,
1887 .op = unwrap_id,
1888 .rhs = undefined,
1889 }
1890 );
1891
1892 stack.push(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1893 try stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1894
1895 if (node.op == ast.Node.InfixOp.Op.Catch) {
1896 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1897 }
1898 continue;
1899 } else {
1900 _ = tok_it.prev();
1901 continue;
1902 }
1903 },
1904
1905 State.BoolOrExpressionBegin => |opt_ctx| {
1906 stack.push(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1907 try stack.push(State { .BoolAndExpressionBegin = opt_ctx });
1908 continue;
1909 },
1910
1911 State.BoolOrExpressionEnd => |opt_ctx| {
1912 const lhs = opt_ctx.get() ?? continue;
1913
1914 if (eatToken(&tok_it, Token.Id.Keyword_or)) |or_token| {
1915 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1916 ast.Node.InfixOp {
1917 .base = undefined,
1918 .lhs = lhs,
1919 .op_token = or_token,
1920 .op = ast.Node.InfixOp.Op.BoolOr,
1921 .rhs = undefined,
1922 }
1923 );
1924 stack.push(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1925 try stack.push(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1926 continue;
1927 }
1928 },
1929
1930 State.BoolAndExpressionBegin => |opt_ctx| {
1931 stack.push(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1932 try stack.push(State { .ComparisonExpressionBegin = opt_ctx });
1933 continue;
1934 },
1935
1936 State.BoolAndExpressionEnd => |opt_ctx| {
1937 const lhs = opt_ctx.get() ?? continue;
1938
1939 if (eatToken(&tok_it, Token.Id.Keyword_and)) |and_token| {
1940 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1941 ast.Node.InfixOp {
1942 .base = undefined,
1943 .lhs = lhs,
1944 .op_token = and_token,
1945 .op = ast.Node.InfixOp.Op.BoolAnd,
1946 .rhs = undefined,
1947 }
1948 );
1949 stack.push(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1950 try stack.push(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1951 continue;
1952 }
1953 },
1954
1955 State.ComparisonExpressionBegin => |opt_ctx| {
1956 stack.push(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1957 try stack.push(State { .BinaryOrExpressionBegin = opt_ctx });
1958 continue;
1959 },
1960
1961 State.ComparisonExpressionEnd => |opt_ctx| {
1962 const lhs = opt_ctx.get() ?? continue;
1963
1964 const token_index = tok_it.index;
1965 const token_ptr = ??tok_it.next();
1966 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1967 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1968 ast.Node.InfixOp {
1969 .base = undefined,
1970 .lhs = lhs,
1971 .op_token = token_index,
1972 .op = comp_id,
1973 .rhs = undefined,
1974 }
1975 );
1976 stack.push(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1977 try stack.push(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1978 continue;
1979 } else {
1980 _ = tok_it.prev();
1981 continue;
1982 }
1983 },
1984
1985 State.BinaryOrExpressionBegin => |opt_ctx| {
1986 stack.push(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
1987 try stack.push(State { .BinaryXorExpressionBegin = opt_ctx });
1988 continue;
1989 },
1990
1991 State.BinaryOrExpressionEnd => |opt_ctx| {
1992 const lhs = opt_ctx.get() ?? continue;
1993
1994 if (eatToken(&tok_it, Token.Id.Pipe)) |pipe| {
1995 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1996 ast.Node.InfixOp {
1997 .base = undefined,
1998 .lhs = lhs,
1999 .op_token = pipe,
2000 .op = ast.Node.InfixOp.Op.BitOr,
2001 .rhs = undefined,
2002 }
2003 );
2004 stack.push(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2005 try stack.push(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2006 continue;
2007 }
2008 },
2009
2010 State.BinaryXorExpressionBegin => |opt_ctx| {
2011 stack.push(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2012 try stack.push(State { .BinaryAndExpressionBegin = opt_ctx });
2013 continue;
2014 },
2015
2016 State.BinaryXorExpressionEnd => |opt_ctx| {
2017 const lhs = opt_ctx.get() ?? continue;
2018
2019 if (eatToken(&tok_it, Token.Id.Caret)) |caret| {
2020 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2021 ast.Node.InfixOp {
2022 .base = undefined,
2023 .lhs = lhs,
2024 .op_token = caret,
2025 .op = ast.Node.InfixOp.Op.BitXor,
2026 .rhs = undefined,
2027 }
2028 );
2029 stack.push(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2030 try stack.push(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2031 continue;
2032 }
2033 },
2034
2035 State.BinaryAndExpressionBegin => |opt_ctx| {
2036 stack.push(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2037 try stack.push(State { .BitShiftExpressionBegin = opt_ctx });
2038 continue;
2039 },
2040
2041 State.BinaryAndExpressionEnd => |opt_ctx| {
2042 const lhs = opt_ctx.get() ?? continue;
2043
2044 if (eatToken(&tok_it, Token.Id.Ampersand)) |ampersand| {
2045 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2046 ast.Node.InfixOp {
2047 .base = undefined,
2048 .lhs = lhs,
2049 .op_token = ampersand,
2050 .op = ast.Node.InfixOp.Op.BitAnd,
2051 .rhs = undefined,
2052 }
2053 );
2054 stack.push(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2055 try stack.push(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2056 continue;
2057 }
2058 },
2059
2060 State.BitShiftExpressionBegin => |opt_ctx| {
2061 stack.push(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2062 try stack.push(State { .AdditionExpressionBegin = opt_ctx });
2063 continue;
2064 },
2065
2066 State.BitShiftExpressionEnd => |opt_ctx| {
2067 const lhs = opt_ctx.get() ?? continue;
2068
2069 const token_index = tok_it.index;
2070 const token_ptr = ??tok_it.next();
2071 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2072 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2073 ast.Node.InfixOp {
2074 .base = undefined,
2075 .lhs = lhs,
2076 .op_token = token_index,
2077 .op = bitshift_id,
2078 .rhs = undefined,
2079 }
2080 );
2081 stack.push(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2082 try stack.push(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2083 continue;
2084 } else {
2085 _ = tok_it.prev();
2086 continue;
2087 }
2088 },
2089
2090 State.AdditionExpressionBegin => |opt_ctx| {
2091 stack.push(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2092 try stack.push(State { .MultiplyExpressionBegin = opt_ctx });
2093 continue;
2094 },
2095
2096 State.AdditionExpressionEnd => |opt_ctx| {
2097 const lhs = opt_ctx.get() ?? continue;
2098
2099 const token_index = tok_it.index;
2100 const token_ptr = ??tok_it.next();
2101 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2102 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2103 ast.Node.InfixOp {
2104 .base = undefined,
2105 .lhs = lhs,
2106 .op_token = token_index,
2107 .op = add_id,
2108 .rhs = undefined,
2109 }
2110 );
2111 stack.push(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2112 try stack.push(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2113 continue;
2114 } else {
2115 _ = tok_it.prev();
2116 continue;
2117 }
2118 },
2119
2120 State.MultiplyExpressionBegin => |opt_ctx| {
2121 stack.push(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2122 try stack.push(State { .CurlySuffixExpressionBegin = opt_ctx });
2123 continue;
2124 },
2125
2126 State.MultiplyExpressionEnd => |opt_ctx| {
2127 const lhs = opt_ctx.get() ?? continue;
2128
2129 const token_index = tok_it.index;
2130 const token_ptr = ??tok_it.next();
2131 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2132 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2133 ast.Node.InfixOp {
2134 .base = undefined,
2135 .lhs = lhs,
2136 .op_token = token_index,
2137 .op = mult_id,
2138 .rhs = undefined,
2139 }
2140 );
2141 stack.push(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2142 try stack.push(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2143 continue;
2144 } else {
2145 _ = tok_it.prev();
2146 continue;
2147 }
2148 },
2149
2150 State.CurlySuffixExpressionBegin => |opt_ctx| {
2151 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2152 try stack.push(State { .IfToken = Token.Id.LBrace });
2153 try stack.push(State { .TypeExprBegin = opt_ctx });
2154 continue;
2155 },
2156
2157 State.CurlySuffixExpressionEnd => |opt_ctx| {
2158 const lhs = opt_ctx.get() ?? continue;
2159
2160 if ((??tok_it.peek()).id == Token.Id.Period) {
2161 const node = try arena.construct(ast.Node.SuffixOp {
2162 .base = ast.Node { .id = ast.Node.Id.SuffixOp },
2163 .lhs = lhs,
2164 .op = ast.Node.SuffixOp.Op {
2165 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2166 },
2167 .rtoken = undefined,
2168 });
2169 opt_ctx.store(&node.base);
2170
2171 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2172 try stack.push(State { .IfToken = Token.Id.LBrace });
2173 try stack.push(State {
2174 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {
2175 .list = &node.op.StructInitializer,
2176 .ptr = &node.rtoken,
2177 }
2178 });
2179 continue;
2180 }
2181
2182 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2183 ast.Node.SuffixOp {
2184 .base = undefined,
2185 .lhs = lhs,
2186 .op = ast.Node.SuffixOp.Op {
2187 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2188 },
2189 .rtoken = undefined,
2190 }
2191 );
2192 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2193 try stack.push(State { .IfToken = Token.Id.LBrace });
2194 try stack.push(State {
2195 .ExprListItemOrEnd = ExprListCtx {
2196 .list = &node.op.ArrayInitializer,
2197 .end = Token.Id.RBrace,
2198 .ptr = &node.rtoken,
2199 }
2200 });
2201 continue;
2202 },
2203
2204 State.TypeExprBegin => |opt_ctx| {
2205 stack.push(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2206 try stack.push(State { .PrefixOpExpression = opt_ctx });
2207 continue;
2208 },
2209
2210 State.TypeExprEnd => |opt_ctx| {
2211 const lhs = opt_ctx.get() ?? continue;
2212
2213 if (eatToken(&tok_it, Token.Id.Bang)) |bang| {
2214 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2215 ast.Node.InfixOp {
2216 .base = undefined,
2217 .lhs = lhs,
2218 .op_token = bang,
2219 .op = ast.Node.InfixOp.Op.ErrorUnion,
2220 .rhs = undefined,
2221 }
2222 );
2223 stack.push(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2224 try stack.push(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2225 continue;
2226 }
2227 },
2228
2229 State.PrefixOpExpression => |opt_ctx| {
2230 const token_index = tok_it.index;
2231 const token_ptr = ??tok_it.next();
2232 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2233 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2234 ast.Node.PrefixOp {
2235 .base = undefined,
2236 .op_token = token_index,
2237 .op = prefix_id,
2238 .rhs = undefined,
2239 }
2240 );
2241
2242 // Treat '**' token as two derefs
2243 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2244 const child = try createNode(arena, ast.Node.PrefixOp,
2245 ast.Node.PrefixOp {
2246 .base = undefined,
2247 .op_token = token_index,
2248 .op = prefix_id,
2249 .rhs = undefined,
2250 }
2251 );
2252 node.rhs = &child.base;
2253 node = child;
2254 }
2255
2256 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2257 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2258 try stack.push(State { .AddrOfModifiers = &node.op.AddrOf });
2259 }
2260 continue;
2261 } else {
2262 _ = tok_it.prev();
2263 stack.push(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2264 continue;
2265 }
2266 },
2267
2268 State.SuffixOpExpressionBegin => |opt_ctx| {
2269 if (eatToken(&tok_it, Token.Id.Keyword_async)) |async_token| {
2270 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
2271 ast.Node.AsyncAttribute {
2272 .base = undefined,
2273 .async_token = async_token,
2274 .allocator_type = null,
2275 .rangle_bracket = null,
2276 }
2277 );
2278 stack.push(State {
2279 .AsyncEnd = AsyncEndCtx {
2280 .ctx = opt_ctx,
2281 .attribute = async_node,
2282 }
2283 }) catch unreachable;
2284 try stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2285 try stack.push(State { .PrimaryExpression = opt_ctx.toRequired() });
2286 try stack.push(State { .AsyncAllocator = async_node });
2287 continue;
2288 }
2289
2290 stack.push(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2291 try stack.push(State { .PrimaryExpression = opt_ctx });
2292 continue;
2293 },
2294
2295 State.SuffixOpExpressionEnd => |opt_ctx| {
2296 const lhs = opt_ctx.get() ?? continue;
2297
2298 const token_index = tok_it.index;
2299 const token_ptr = ??tok_it.next();
2300 switch (token_ptr.id) {
2301 Token.Id.LParen => {
2302 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2303 ast.Node.SuffixOp {
2304 .base = undefined,
2305 .lhs = lhs,
2306 .op = ast.Node.SuffixOp.Op {
2307 .Call = ast.Node.SuffixOp.Op.Call {
2308 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2309 .async_attr = null,
2310 }
2311 },
2312 .rtoken = undefined,
2313 }
2314 );
2315 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2316 try stack.push(State {
2317 .ExprListItemOrEnd = ExprListCtx {
2318 .list = &node.op.Call.params,
2319 .end = Token.Id.RParen,
2320 .ptr = &node.rtoken,
2321 }
2322 });
2323 continue;
2324 },
2325 Token.Id.LBracket => {
2326 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2327 ast.Node.SuffixOp {
2328 .base = undefined,
2329 .lhs = lhs,
2330 .op = ast.Node.SuffixOp.Op {
2331 .ArrayAccess = undefined,
2332 },
2333 .rtoken = undefined
2334 }
2335 );
2336 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2337 try stack.push(State { .SliceOrArrayAccess = node });
2338 try stack.push(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2339 continue;
2340 },
2341 Token.Id.Period => {
2342 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2343 ast.Node.InfixOp {
2344 .base = undefined,
2345 .lhs = lhs,
2346 .op_token = token_index,
2347 .op = ast.Node.InfixOp.Op.Period,
2348 .rhs = undefined,
2349 }
2350 );
2351 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2352 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2353 continue;
2354 },
2355 else => {
2356 _ = tok_it.prev();
2357 continue;
2358 },
2359 }
2360 },
2361
2362 State.PrimaryExpression => |opt_ctx| {
2363 const token_index = tok_it.index;
2364 const token_ptr = ??tok_it.next();
2365 switch (token_ptr.id) {
2366 Token.Id.IntegerLiteral => {
2367 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token_index);
2368 continue;
2369 },
2370 Token.Id.FloatLiteral => {
2371 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token_index);
2372 continue;
2373 },
2374 Token.Id.CharLiteral => {
2375 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token_index);
2376 continue;
2377 },
2378 Token.Id.Keyword_undefined => {
2379 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token_index);
2380 continue;
2381 },
2382 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2383 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token_index);
2384 continue;
2385 },
2386 Token.Id.Keyword_null => {
2387 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token_index);
2388 continue;
2389 },
2390 Token.Id.Keyword_this => {
2391 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token_index);
2392 continue;
2393 },
2394 Token.Id.Keyword_var => {
2395 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token_index);
2396 continue;
2397 },
2398 Token.Id.Keyword_unreachable => {
2399 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token_index);
2400 continue;
2401 },
2402 Token.Id.Keyword_promise => {
2403 const node = try arena.construct(ast.Node.PromiseType {
2404 .base = ast.Node {
2405 .id = ast.Node.Id.PromiseType,
2406 },
2407 .promise_token = token_index,
2408 .result = null,
2409 });
2410 opt_ctx.store(&node.base);
2411 const next_token_index = tok_it.index;
2412 const next_token_ptr = ??tok_it.next();
2413 if (next_token_ptr.id != Token.Id.Arrow) {
2414 _ = tok_it.prev();
2415 continue;
2416 }
2417 node.result = ast.Node.PromiseType.Result {
2418 .arrow_token = next_token_index,
2419 .return_type = undefined,
2420 };
2421 const return_type_ptr = &((??node.result).return_type);
2422 try stack.push(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2423 continue;
2424 },
2425 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2426 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index)) ?? unreachable);
2427 continue;
2428 },
2429 Token.Id.LParen => {
2430 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2431 ast.Node.GroupedExpression {
2432 .base = undefined,
2433 .lparen = token_index,
2434 .expr = undefined,
2435 .rparen = undefined,
2436 }
2437 );
2438 stack.push(State {
2439 .ExpectTokenSave = ExpectTokenSave {
2440 .id = Token.Id.RParen,
2441 .ptr = &node.rparen,
2442 }
2443 }) catch unreachable;
2444 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
2445 continue;
2446 },
2447 Token.Id.Builtin => {
2448 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2449 ast.Node.BuiltinCall {
2450 .base = undefined,
2451 .builtin_token = token_index,
2452 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2453 .rparen_token = undefined,
2454 }
2455 );
2456 stack.push(State {
2457 .ExprListItemOrEnd = ExprListCtx {
2458 .list = &node.params,
2459 .end = Token.Id.RParen,
2460 .ptr = &node.rparen_token,
2461 }
2462 }) catch unreachable;
2463 try stack.push(State { .ExpectToken = Token.Id.LParen, });
2464 continue;
2465 },
2466 Token.Id.LBracket => {
2467 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2468 ast.Node.PrefixOp {
2469 .base = undefined,
2470 .op_token = token_index,
2471 .op = undefined,
2472 .rhs = undefined,
2473 }
2474 );
2475 stack.push(State { .SliceOrArrayType = node }) catch unreachable;
2476 continue;
2477 },
2478 Token.Id.Keyword_error => {
2479 stack.push(State {
2480 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2481 .error_token = token_index,
2482 .opt_ctx = opt_ctx
2483 }
2484 }) catch unreachable;
2485 continue;
2486 },
2487 Token.Id.Keyword_packed => {
2488 stack.push(State {
2489 .ContainerKind = ContainerKindCtx {
2490 .opt_ctx = opt_ctx,
2491 .ltoken = token_index,
2492 .layout = ast.Node.ContainerDecl.Layout.Packed,
2493 },
2494 }) catch unreachable;
2495 continue;
2496 },
2497 Token.Id.Keyword_extern => {
2498 stack.push(State {
2499 .ExternType = ExternTypeCtx {
2500 .opt_ctx = opt_ctx,
2501 .extern_token = token_index,
2502 .comments = null,
2503 },
2504 }) catch unreachable;
2505 continue;
2506 },
2507 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2508 _ = tok_it.prev();
2509 stack.push(State {
2510 .ContainerKind = ContainerKindCtx {
2511 .opt_ctx = opt_ctx,
2512 .ltoken = token_index,
2513 .layout = ast.Node.ContainerDecl.Layout.Auto,
2514 },
2515 }) catch unreachable;
2516 continue;
2517 },
2518 Token.Id.Identifier => {
2519 stack.push(State {
2520 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2521 .label = token_index,
2522 .opt_ctx = opt_ctx
2523 }
2524 }) catch unreachable;
2525 continue;
2526 },
2527 Token.Id.Keyword_fn => {
2528 const fn_proto = try arena.construct(ast.Node.FnProto {
2529 .base = ast.Node {
2530 .id = ast.Node.Id.FnProto,
2531 },
2532 .doc_comments = null,
2533 .visib_token = null,
2534 .name_token = null,
2535 .fn_token = token_index,
2536 .params = ast.Node.FnProto.ParamList.init(arena),
2537 .return_type = undefined,
2538 .var_args_token = null,
2539 .extern_export_inline_token = null,
2540 .cc_token = null,
2541 .async_attr = null,
2542 .body_node = null,
2543 .lib_name = null,
2544 .align_expr = null,
2545 });
2546 opt_ctx.store(&fn_proto.base);
2547 stack.push(State { .FnProto = fn_proto }) catch unreachable;
2548 continue;
2549 },
2550 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2551 const fn_proto = try arena.construct(ast.Node.FnProto {
2552 .base = ast.Node {
2553 .id = ast.Node.Id.FnProto,
2554 },
2555 .doc_comments = null,
2556 .visib_token = null,
2557 .name_token = null,
2558 .fn_token = undefined,
2559 .params = ast.Node.FnProto.ParamList.init(arena),
2560 .return_type = undefined,
2561 .var_args_token = null,
2562 .extern_export_inline_token = null,
2563 .cc_token = token_index,
2564 .async_attr = null,
2565 .body_node = null,
2566 .lib_name = null,
2567 .align_expr = null,
2568 });
2569 opt_ctx.store(&fn_proto.base);
2570 stack.push(State { .FnProto = fn_proto }) catch unreachable;
2571 try stack.push(State {
2572 .ExpectTokenSave = ExpectTokenSave {
2573 .id = Token.Id.Keyword_fn,
2574 .ptr = &fn_proto.fn_token
2575 }
2576 });
2577 continue;
2578 },
2579 Token.Id.Keyword_asm => {
2580 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2581 ast.Node.Asm {
2582 .base = undefined,
2583 .asm_token = token_index,
2584 .volatile_token = null,
2585 .template = undefined,
2586 .outputs = ast.Node.Asm.OutputList.init(arena),
2587 .inputs = ast.Node.Asm.InputList.init(arena),
2588 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2589 .rparen = undefined,
2590 }
2591 );
2592 stack.push(State {
2593 .ExpectTokenSave = ExpectTokenSave {
2594 .id = Token.Id.RParen,
2595 .ptr = &node.rparen,
2596 }
2597 }) catch unreachable;
2598 try stack.push(State { .AsmClobberItems = &node.clobbers });
2599 try stack.push(State { .IfToken = Token.Id.Colon });
2600 try stack.push(State { .AsmInputItems = &node.inputs });
2601 try stack.push(State { .IfToken = Token.Id.Colon });
2602 try stack.push(State { .AsmOutputItems = &node.outputs });
2603 try stack.push(State { .IfToken = Token.Id.Colon });
2604 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2605 try stack.push(State { .ExpectToken = Token.Id.LParen });
2606 try stack.push(State {
2607 .OptionalTokenSave = OptionalTokenSave {
2608 .id = Token.Id.Keyword_volatile,
2609 .ptr = &node.volatile_token,
2610 }
2611 });
2612 },
2613 Token.Id.Keyword_inline => {
2614 stack.push(State {
2615 .Inline = InlineCtx {
2616 .label = null,
2617 .inline_token = token_index,
2618 .opt_ctx = opt_ctx,
2619 }
2620 }) catch unreachable;
2621 continue;
2622 },
2623 else => {
2624 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
2625 _ = tok_it.prev();
2626 if (opt_ctx != OptionalCtx.Optional) {
2627 *(try tree.errors.addOne()) = Error {
2628 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2629 };
2630 return tree;
2631 }
2632 }
2633 continue;
2634 }
2635 }
2636 },
2637
2638
2639 State.ErrorTypeOrSetDecl => |ctx| {
2640 if (eatToken(&tok_it, Token.Id.LBrace) == null) {
2641 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2642 continue;
2643 }
2644
2645 const node = try arena.construct(ast.Node.ErrorSetDecl {
2646 .base = ast.Node {
2647 .id = ast.Node.Id.ErrorSetDecl,
2648 },
2649 .error_token = ctx.error_token,
2650 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2651 .rbrace_token = undefined,
2652 });
2653 ctx.opt_ctx.store(&node.base);
2654
2655 stack.push(State {
2656 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {
2657 .list = &node.decls,
2658 .ptr = &node.rbrace_token,
2659 }
2660 }) catch unreachable;
2661 continue;
2662 },
2663 State.StringLiteral => |opt_ctx| {
2664 const token_index = tok_it.index;
2665 const token_ptr = ??tok_it.next();
2666 opt_ctx.store(
2667 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index)) ?? {
2668 _ = tok_it.prev();
2669 if (opt_ctx != OptionalCtx.Optional) {
2670 *(try tree.errors.addOne()) = Error {
2671 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2672 };
2673 return tree;
2674 }
2675
2676 continue;
2677 }
2678 );
2679 },
2680
2681 State.Identifier => |opt_ctx| {
2682 if (eatToken(&tok_it, Token.Id.Identifier)) |ident_token| {
2683 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2684 continue;
2685 }
2686
2687 if (opt_ctx != OptionalCtx.Optional) {
2688 const token_index = tok_it.index;
2689 const token_ptr = ??tok_it.next();
2690 *(try tree.errors.addOne()) = Error {
2691 .ExpectedToken = Error.ExpectedToken {
2692 .token = token_index,
2693 .expected_id = Token.Id.Identifier,
2694 },
2695 };
2696 return tree;
2697 }
2698 },
2699
2700 State.ErrorTag => |node_ptr| {
2701 const comments = try eatDocComments(arena, &tok_it);
2702 const ident_token_index = tok_it.index;
2703 const ident_token_ptr = ??tok_it.next();
2704 if (ident_token_ptr.id != Token.Id.Identifier) {
2705 *(try tree.errors.addOne()) = Error {
2706 .ExpectedToken = Error.ExpectedToken {
2707 .token = ident_token_index,
2708 .expected_id = Token.Id.Identifier,
2709 },
2710 };
2711 return tree;
2712 }
2713
2714 const node = try arena.construct(ast.Node.ErrorTag {
2715 .base = ast.Node {
2716 .id = ast.Node.Id.ErrorTag,
2717 },
2718 .doc_comments = comments,
2719 .name_token = ident_token_index,
2720 });
2721 *node_ptr = &node.base;
2722 continue;
2723 },
2724
2725 State.ExpectToken => |token_id| {
2726 const token_index = tok_it.index;
2727 const token_ptr = ??tok_it.next();
2728 if (token_ptr.id != token_id) {
2729 *(try tree.errors.addOne()) = Error {
2730 .ExpectedToken = Error.ExpectedToken {
2731 .token = token_index,
2732 .expected_id = token_id,
2733 },
2734 };
2735 return tree;
2736 }
2737 continue;
2738 },
2739 State.ExpectTokenSave => |expect_token_save| {
2740 const token_index = tok_it.index;
2741 const token_ptr = ??tok_it.next();
2742 if (token_ptr.id != expect_token_save.id) {
2743 *(try tree.errors.addOne()) = Error {
2744 .ExpectedToken = Error.ExpectedToken {
2745 .token = token_index,
2746 .expected_id = expect_token_save.id,
2747 },
2748 };
2749 return tree;
2750 }
2751 *expect_token_save.ptr = token_index;
2752 continue;
2753 },
2754 State.IfToken => |token_id| {
2755 if (eatToken(&tok_it, token_id)) |_| {
2756 continue;
2757 }
2758
2759 _ = stack.pop();
2760 continue;
2761 },
2762 State.IfTokenSave => |if_token_save| {
2763 if (eatToken(&tok_it, if_token_save.id)) |token_index| {
2764 *if_token_save.ptr = token_index;
2765 continue;
2766 }
2767
2768 _ = stack.pop();
2769 continue;
2770 },
2771 State.OptionalTokenSave => |optional_token_save| {
2772 if (eatToken(&tok_it, optional_token_save.id)) |token_index| {
2773 *optional_token_save.ptr = token_index;
2774 continue;
2775 }
2776
2777 continue;
2778 },
2779 }
2780 }
2781}
2782
2783const AnnotatedToken = struct {
2784 ptr: &Token,
2785 index: TokenIndex,
2786};
2787
2788const TopLevelDeclCtx = struct {
2789 decls: &ast.Node.Root.DeclList,
2790 visib_token: ?TokenIndex,
2791 extern_export_inline_token: ?AnnotatedToken,
2792 lib_name: ?&ast.Node,
2793 comments: ?&ast.Node.DocComment,
2794};
2795
2796const VarDeclCtx = struct {
2797 mut_token: TokenIndex,
2798 visib_token: ?TokenIndex,
2799 comptime_token: ?TokenIndex,
2800 extern_export_token: ?TokenIndex,
2801 lib_name: ?&ast.Node,
2802 list: &ast.Node.Root.DeclList,
2803 comments: ?&ast.Node.DocComment,
2804};
2805
2806const TopLevelExternOrFieldCtx = struct {
2807 visib_token: TokenIndex,
2808 container_decl: &ast.Node.ContainerDecl,
2809 comments: ?&ast.Node.DocComment,
2810};
2811
2812const ExternTypeCtx = struct {
2813 opt_ctx: OptionalCtx,
2814 extern_token: TokenIndex,
2815 comments: ?&ast.Node.DocComment,
2816};
2817
2818const ContainerKindCtx = struct {
2819 opt_ctx: OptionalCtx,
2820 ltoken: TokenIndex,
2821 layout: ast.Node.ContainerDecl.Layout,
2822};
2823
2824const ExpectTokenSave = struct {
2825 id: @TagType(Token.Id),
2826 ptr: &TokenIndex,
2827};
2828
2829const OptionalTokenSave = struct {
2830 id: @TagType(Token.Id),
2831 ptr: &?TokenIndex,
2832};
2833
2834const ExprListCtx = struct {
2835 list: &ast.Node.SuffixOp.Op.InitList,
2836 end: Token.Id,
2837 ptr: &TokenIndex,
2838};
2839
2840fn ListSave(comptime List: type) type {
2841 return struct {
2842 list: &List,
2843 ptr: &TokenIndex,
2844 };
2845}
2846
2847const MaybeLabeledExpressionCtx = struct {
2848 label: TokenIndex,
2849 opt_ctx: OptionalCtx,
2850};
2851
2852const LabelCtx = struct {
2853 label: ?TokenIndex,
2854 opt_ctx: OptionalCtx,
2855};
2856
2857const InlineCtx = struct {
2858 label: ?TokenIndex,
2859 inline_token: ?TokenIndex,
2860 opt_ctx: OptionalCtx,
2861};
2862
2863const LoopCtx = struct {
2864 label: ?TokenIndex,
2865 inline_token: ?TokenIndex,
2866 loop_token: TokenIndex,
2867 opt_ctx: OptionalCtx,
2868};
2869
2870const AsyncEndCtx = struct {
2871 ctx: OptionalCtx,
2872 attribute: &ast.Node.AsyncAttribute,
2873};
2874
2875const ErrorTypeOrSetDeclCtx = struct {
2876 opt_ctx: OptionalCtx,
2877 error_token: TokenIndex,
2878};
2879
2880const ParamDeclEndCtx = struct {
2881 fn_proto: &ast.Node.FnProto,
2882 param_decl: &ast.Node.ParamDecl,
2883};
2884
2885const ComptimeStatementCtx = struct {
2886 comptime_token: TokenIndex,
2887 block: &ast.Node.Block,
2888};
2889
2890const OptionalCtx = union(enum) {
2891 Optional: &?&ast.Node,
2892 RequiredNull: &?&ast.Node,
2893 Required: &&ast.Node,
2894
2895 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2896 switch (*self) {
2897 OptionalCtx.Optional => |ptr| *ptr = value,
2898 OptionalCtx.RequiredNull => |ptr| *ptr = value,
2899 OptionalCtx.Required => |ptr| *ptr = value,
2900 }
2901 }
2902
2903 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2904 switch (*self) {
2905 OptionalCtx.Optional => |ptr| return *ptr,
2906 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
2907 OptionalCtx.Required => |ptr| return *ptr,
2908 }
2909 }
2910
2911 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2912 switch (*self) {
2913 OptionalCtx.Optional => |ptr| {
2914 return OptionalCtx { .RequiredNull = ptr };
2915 },
2916 OptionalCtx.RequiredNull => |ptr| return *self,
2917 OptionalCtx.Required => |ptr| return *self,
2918 }
2919 }
2920};
2921
2922const AddCommentsCtx = struct {
2923 node_ptr: &&ast.Node,
2924 comments: ?&ast.Node.DocComment,
2925};
2926
2927const State = union(enum) {
2928 TopLevel,
2929 TopLevelExtern: TopLevelDeclCtx,
2930 TopLevelLibname: TopLevelDeclCtx,
2931 TopLevelDecl: TopLevelDeclCtx,
2932 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2933
2934 ContainerKind: ContainerKindCtx,
2935 ContainerInitArgStart: &ast.Node.ContainerDecl,
2936 ContainerInitArg: &ast.Node.ContainerDecl,
2937 ContainerDecl: &ast.Node.ContainerDecl,
2938
2939 VarDecl: VarDeclCtx,
2940 VarDeclAlign: &ast.Node.VarDecl,
2941 VarDeclEq: &ast.Node.VarDecl,
2942
2943 FnDef: &ast.Node.FnProto,
2944 FnProto: &ast.Node.FnProto,
2945 FnProtoAlign: &ast.Node.FnProto,
2946 FnProtoReturnType: &ast.Node.FnProto,
2947
2948 ParamDecl: &ast.Node.FnProto,
2949 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
2950 ParamDeclName: &ast.Node.ParamDecl,
2951 ParamDeclEnd: ParamDeclEndCtx,
2952 ParamDeclComma: &ast.Node.FnProto,
2953
2954 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2955 LabeledExpression: LabelCtx,
2956 Inline: InlineCtx,
2957 While: LoopCtx,
2958 WhileContinueExpr: &?&ast.Node,
2959 For: LoopCtx,
2960 Else: &?&ast.Node.Else,
2961
2962 Block: &ast.Node.Block,
2963 Statement: &ast.Node.Block,
2964 ComptimeStatement: ComptimeStatementCtx,
2965 Semicolon: &&ast.Node,
2966
2967 AsmOutputItems: &ast.Node.Asm.OutputList,
2968 AsmOutputReturnOrType: &ast.Node.AsmOutput,
2969 AsmInputItems: &ast.Node.Asm.InputList,
2970 AsmClobberItems: &ast.Node.Asm.ClobberList,
2971
2972 ExprListItemOrEnd: ExprListCtx,
2973 ExprListCommaOrEnd: ExprListCtx,
2974 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2975 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2976 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
2977 FieldInitValue: OptionalCtx,
2978 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2979 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2980 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
2981 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
2982 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
2983 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
2984 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
2985
2986 SuspendBody: &ast.Node.Suspend,
2987 AsyncAllocator: &ast.Node.AsyncAttribute,
2988 AsyncEnd: AsyncEndCtx,
2989
2990 ExternType: ExternTypeCtx,
2991 SliceOrArrayAccess: &ast.Node.SuffixOp,
2992 SliceOrArrayType: &ast.Node.PrefixOp,
2993 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
2994
2995 Payload: OptionalCtx,
2996 PointerPayload: OptionalCtx,
2997 PointerIndexPayload: OptionalCtx,
2998
2999 Expression: OptionalCtx,
3000 RangeExpressionBegin: OptionalCtx,
3001 RangeExpressionEnd: OptionalCtx,
3002 AssignmentExpressionBegin: OptionalCtx,
3003 AssignmentExpressionEnd: OptionalCtx,
3004 UnwrapExpressionBegin: OptionalCtx,
3005 UnwrapExpressionEnd: OptionalCtx,
3006 BoolOrExpressionBegin: OptionalCtx,
3007 BoolOrExpressionEnd: OptionalCtx,
3008 BoolAndExpressionBegin: OptionalCtx,
3009 BoolAndExpressionEnd: OptionalCtx,
3010 ComparisonExpressionBegin: OptionalCtx,
3011 ComparisonExpressionEnd: OptionalCtx,
3012 BinaryOrExpressionBegin: OptionalCtx,
3013 BinaryOrExpressionEnd: OptionalCtx,
3014 BinaryXorExpressionBegin: OptionalCtx,
3015 BinaryXorExpressionEnd: OptionalCtx,
3016 BinaryAndExpressionBegin: OptionalCtx,
3017 BinaryAndExpressionEnd: OptionalCtx,
3018 BitShiftExpressionBegin: OptionalCtx,
3019 BitShiftExpressionEnd: OptionalCtx,
3020 AdditionExpressionBegin: OptionalCtx,
3021 AdditionExpressionEnd: OptionalCtx,
3022 MultiplyExpressionBegin: OptionalCtx,
3023 MultiplyExpressionEnd: OptionalCtx,
3024 CurlySuffixExpressionBegin: OptionalCtx,
3025 CurlySuffixExpressionEnd: OptionalCtx,
3026 TypeExprBegin: OptionalCtx,
3027 TypeExprEnd: OptionalCtx,
3028 PrefixOpExpression: OptionalCtx,
3029 SuffixOpExpressionBegin: OptionalCtx,
3030 SuffixOpExpressionEnd: OptionalCtx,
3031 PrimaryExpression: OptionalCtx,
3032
3033 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3034 StringLiteral: OptionalCtx,
3035 Identifier: OptionalCtx,
3036 ErrorTag: &&ast.Node,
3037
3038
3039 IfToken: @TagType(Token.Id),
3040 IfTokenSave: ExpectTokenSave,
3041 ExpectToken: @TagType(Token.Id),
3042 ExpectTokenSave: ExpectTokenSave,
3043 OptionalTokenSave: OptionalTokenSave,
3044};
3045
3046fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator) !?&ast.Node.DocComment {
3047 var result: ?&ast.Node.DocComment = null;
3048 while (true) {
3049 if (eatToken(tok_it, Token.Id.DocComment)) |line_comment| {
3050 const node = blk: {
3051 if (result) |comment_node| {
3052 break :blk comment_node;
3053 } else {
3054 const comment_node = try arena.construct(ast.Node.DocComment {
3055 .base = ast.Node {
3056 .id = ast.Node.Id.DocComment,
3057 },
3058 .lines = ast.Node.DocComment.LineList.init(arena),
3059 });
3060 result = comment_node;
3061 break :blk comment_node;
3062 }
3063 };
3064 try node.lines.push(line_comment);
3065 continue;
3066 }
3067 break;
3068 }
3069 return result;
3070}
3071
3072fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator) !?&ast.Node.LineComment {
3073 const token = eatToken(tok_it, Token.Id.LineComment) ?? return null;
3074 return try arena.construct(ast.Node.LineComment {
3075 .base = ast.Node {
3076 .id = ast.Node.Id.LineComment,
3077 },
3078 .token = token,
3079 });
3080}
3081
3082fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3083 token_ptr: &const Token, token_index: TokenIndex) !?&ast.Node
3084{
3085 switch (token_ptr.id) {
3086 Token.Id.StringLiteral => {
3087 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3088 },
3089 Token.Id.MultilineStringLiteralLine => {
3090 const node = try arena.construct(ast.Node.MultilineStringLiteral {
3091 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },
3092 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3093 });
3094 try node.lines.push(token_index);
3095 while (true) {
3096 const multiline_str_index = tok_it.index;
3097 const multiline_str_ptr = ??tok_it.next();
3098 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3099 _ = tok_it.prev();
3100 break;
3101 }
3102
3103 try node.lines.push(multiline_str_index);
3104 }
3105
3106 return &node.base;
3107 },
3108 // TODO: We shouldn't need a cast, but:
3109 // 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.
3110 else => return (?&ast.Node)(null),
3111 }
3112}
3113
3114fn parseBlockExpr(stack: &SegmentedList(State, 32), arena: &mem.Allocator, ctx: &const OptionalCtx,
3115 token_ptr: &const Token, token_index: TokenIndex) !bool {
3116 switch (token_ptr.id) {
3117 Token.Id.Keyword_suspend => {
3118 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,
3119 ast.Node.Suspend {
3120 .base = undefined,
3121 .label = null,
3122 .suspend_token = token_index,
3123 .payload = null,
3124 .body = null,
3125 }
3126 );
3127
3128 stack.push(State { .SuspendBody = node }) catch unreachable;
3129 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3130 return true;
3131 },
3132 Token.Id.Keyword_if => {
3133 const node = try createToCtxNode(arena, ctx, ast.Node.If,
3134 ast.Node.If {
3135 .base = undefined,
3136 .if_token = token_index,
3137 .condition = undefined,
3138 .payload = null,
3139 .body = undefined,
3140 .@"else" = null,
3141 }
3142 );
3143
3144 stack.push(State { .Else = &node.@"else" }) catch unreachable;
3145 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
3146 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3147 try stack.push(State { .ExpectToken = Token.Id.RParen });
3148 try stack.push(State { .Expression = OptionalCtx { .Required = &node.condition } });
3149 try stack.push(State { .ExpectToken = Token.Id.LParen });
3150 return true;
3151 },
3152 Token.Id.Keyword_while => {
3153 stack.push(State {
3154 .While = LoopCtx {
3155 .label = null,
3156 .inline_token = null,
3157 .loop_token = token_index,
3158 .opt_ctx = *ctx,
3159 }
3160 }) catch unreachable;
3161 return true;
3162 },
3163 Token.Id.Keyword_for => {
3164 stack.push(State {
3165 .For = LoopCtx {
3166 .label = null,
3167 .inline_token = null,
3168 .loop_token = token_index,
3169 .opt_ctx = *ctx,
3170 }
3171 }) catch unreachable;
3172 return true;
3173 },
3174 Token.Id.Keyword_switch => {
3175 const node = try arena.construct(ast.Node.Switch {
3176 .base = ast.Node {
3177 .id = ast.Node.Id.Switch,
3178 },
3179 .switch_token = token_index,
3180 .expr = undefined,
3181 .cases = ast.Node.Switch.CaseList.init(arena),
3182 .rbrace = undefined,
3183 });
3184 ctx.store(&node.base);
3185
3186 stack.push(State {
3187 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {
3188 .list = &node.cases,
3189 .ptr = &node.rbrace,
3190 },
3191 }) catch unreachable;
3192 try stack.push(State { .ExpectToken = Token.Id.LBrace });
3193 try stack.push(State { .ExpectToken = Token.Id.RParen });
3194 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
3195 try stack.push(State { .ExpectToken = Token.Id.LParen });
3196 return true;
3197 },
3198 Token.Id.Keyword_comptime => {
3199 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,
3200 ast.Node.Comptime {
3201 .base = undefined,
3202 .comptime_token = token_index,
3203 .expr = undefined,
3204 .doc_comments = null,
3205 }
3206 );
3207 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
3208 return true;
3209 },
3210 Token.Id.LBrace => {
3211 const block = try arena.construct(ast.Node.Block {
3212 .base = ast.Node {.id = ast.Node.Id.Block },
3213 .label = null,
3214 .lbrace = token_index,
3215 .statements = ast.Node.Block.StatementList.init(arena),
3216 .rbrace = undefined,
3217 });
3218 ctx.store(&block.base);
3219 stack.push(State { .Block = block }) catch unreachable;
3220 return true;
3221 },
3222 else => {
3223 return false;
3224 }
3225 }
3226}
3227
3228const ExpectCommaOrEndResult = union(enum) {
3229 end_token: ?TokenIndex,
3230 parse_error: Error,
3231};
3232
3233fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3234 const token_index = tok_it.index;
3235 const token_ptr = ??tok_it.next();
3236 switch (token_ptr.id) {
3237 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},
3238 else => {
3239 if (end == token_ptr.id) {
3240 return ExpectCommaOrEndResult { .end_token = token_index };
3241 }
3242
3243 return ExpectCommaOrEndResult {
3244 .parse_error = Error {
3245 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {
3246 .token = token_index,
3247 .end_id = end,
3248 },
3249 },
3250 };
3251 },
3252 }
3253}
3254
3255fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3256 // TODO: We have to cast all cases because of this:
3257 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3258 return switch (*id) {
3259 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },
3260 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },
3261 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },
3262 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },
3263 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },
3264 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },
3265 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },
3266 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },
3267 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },
3268 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },
3269 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },
3270 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },
3271 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },
3272 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },
3273 else => null,
3274 };
3275}
3276
3277fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3278 return switch (id) {
3279 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3280 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3281 else => null,
3282 };
3283}
3284
3285fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3286 return switch (id) {
3287 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3288 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3289 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3290 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3291 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3292 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3293 else => null,
3294 };
3295}
3296
3297fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3298 return switch (id) {
3299 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3300 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3301 else => null,
3302 };
3303}
3304
3305fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3306 return switch (id) {
3307 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3308 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3309 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3310 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3311 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3312 else => null,
3313 };
3314}
3315
3316fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3317 return switch (id) {
3318 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3319 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3320 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3321 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3322 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3323 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3324 else => null,
3325 };
3326}
3327
3328fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3329 return switch (id) {
3330 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3331 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3332 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3333 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3334 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3335 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3336 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3337 .align_expr = null,
3338 .bit_offset_start_token = null,
3339 .bit_offset_end_token = null,
3340 .const_token = null,
3341 .volatile_token = null,
3342 },
3343 },
3344 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3345 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3346 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3347 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3348 else => null,
3349 };
3350}
3351
3352fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3353 const node = try arena.create(T);
3354 *node = *init_to;
3355 node.base = blk: {
3356 const id = ast.Node.typeToId(T);
3357 break :blk ast.Node {
3358 .id = id,
3359 };
3360 };
3361
3362 return node;
3363}
3364
3365fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3366 const node = try createNode(arena, T, init_to);
3367 opt_ctx.store(&node.base);
3368
3369 return node;
3370}
3371
3372fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3373 return createNode(arena, T,
3374 T {
3375 .base = undefined,
3376 .token = token_index,
3377 }
3378 );
3379}
3380
3381fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
3382 const node = try createLiteral(arena, T, token_index);
3383 opt_ctx.store(&node.base);
3384
3385 return node;
3386}
3387
3388fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, id: @TagType(Token.Id)) ?TokenIndex {
3389 const token_index = tok_it.index;
3390 const token_ptr = ??tok_it.next();
3391 if (token_ptr.id == id)
3392 return token_index;
3393
3394 _ = tok_it.prev();
3395 return null;
3396}
3397
3398const RenderAstFrame = struct {
3399 node: &ast.Node,
3400 indent: usize,
3401};
3402
3403pub fn renderAst(allocator: &mem.Allocator, tree: &const ast.Tree, stream: var) !void {
3404 var stack = SegmentedList(State, 32).init(allocator);
3405 defer stack.deinit();
3406
3407 try stack.push(RenderAstFrame {
3408 .node = &root_node.base,
3409 .indent = 0,
3410 });
3411
3412 while (stack.popOrNull()) |frame| {
3413 {
3414 var i: usize = 0;
3415 while (i < frame.indent) : (i += 1) {
3416 try stream.print(" ");
3417 }
3418 }
3419 try stream.print("{}\n", @tagName(frame.node.id));
3420 var child_i: usize = 0;
3421 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3422 try stack.push(RenderAstFrame {
3423 .node = child,
3424 .indent = frame.indent + 2,
3425 });
3426 }
3427 }
3428}
3429
3430test "std.zig.parser" {
3431 _ = @import("parser_test.zig");
3432}
std/zig/parser.zig deleted-4741
...@@ -1,4741 +0,0 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const SegmentedList = std.SegmentedList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Tokenizer = std.zig.Tokenizer;
7const Token = std.zig.Token;
8const TokenIndex = ast.TokenIndex;
9const Error = ast.Error;
10const builtin = @import("builtin");
11const io = std.io;
12
13/// Returns an AST tree, allocated with the parser's allocator.
14/// Result should be freed with tree.deinit() when there are
15/// no more references to any AST nodes of the tree.
16pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
17 var tree_arena = std.heap.ArenaAllocator.init(allocator);
18 errdefer tree_arena.deinit();
19
20 var stack = SegmentedList(State, 32).init(allocator);
21 defer stack.deinit();
22
23 const arena = &tree_arena.allocator;
24 const root_node = try createNode(arena, ast.Node.Root,
25 ast.Node.Root {
26 .base = undefined,
27 .decls = ast.Node.Root.DeclList.init(arena),
28 .doc_comments = null,
29 // initialized when we get the eof token
30 .eof_token = undefined,
31 }
32 );
33
34 var tree = ast.Tree {
35 .source = source,
36 .root_node = root_node,
37 .arena_allocator = tree_arena,
38 .tokens = ast.Tree.TokenList.init(arena),
39 .errors = ast.Tree.ErrorList.init(arena),
40 };
41
42 var tokenizer = Tokenizer.init(tree.source);
43 while (true) {
44 const token_ptr = try tree.tokens.addOne();
45 *token_ptr = tokenizer.next();
46 if (token_ptr.id == Token.Id.Eof)
47 break;
48 }
49 var tok_it = tree.tokens.iterator(0);
50
51 try stack.push(State.TopLevel);
52
53 while (true) {
54 // This gives us 1 free push that can't fail
55 const state = ??stack.pop();
56
57 switch (state) {
58 State.TopLevel => {
59 while (try eatLineComment(arena, &tok_it)) |line_comment| {
60 try root_node.decls.push(&line_comment.base);
61 }
62
63 const comments = try eatDocComments(arena, &tok_it);
64
65 const token_index = tok_it.index;
66 const token_ptr = ??tok_it.next();
67 switch (token_ptr.id) {
68 Token.Id.Keyword_test => {
69 stack.push(State.TopLevel) catch unreachable;
70
71 const block = try arena.construct(ast.Node.Block {
72 .base = ast.Node {
73 .id = ast.Node.Id.Block,
74 },
75 .label = null,
76 .lbrace = undefined,
77 .statements = ast.Node.Block.StatementList.init(arena),
78 .rbrace = undefined,
79 });
80 const test_node = try arena.construct(ast.Node.TestDecl {
81 .base = ast.Node {
82 .id = ast.Node.Id.TestDecl,
83 },
84 .doc_comments = comments,
85 .test_token = token_index,
86 .name = undefined,
87 .body_node = &block.base,
88 });
89 try root_node.decls.push(&test_node.base);
90 try stack.push(State { .Block = block });
91 try stack.push(State {
92 .ExpectTokenSave = ExpectTokenSave {
93 .id = Token.Id.LBrace,
94 .ptr = &block.rbrace,
95 }
96 });
97 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
98 continue;
99 },
100 Token.Id.Eof => {
101 root_node.eof_token = token_index;
102 root_node.doc_comments = comments;
103 return tree;
104 },
105 Token.Id.Keyword_pub => {
106 stack.push(State.TopLevel) catch unreachable;
107 try stack.push(State {
108 .TopLevelExtern = TopLevelDeclCtx {
109 .decls = &root_node.decls,
110 .visib_token = token_index,
111 .extern_export_inline_token = null,
112 .lib_name = null,
113 .comments = comments,
114 }
115 });
116 continue;
117 },
118 Token.Id.Keyword_comptime => {
119 const block = try createNode(arena, ast.Node.Block,
120 ast.Node.Block {
121 .base = undefined,
122 .label = null,
123 .lbrace = undefined,
124 .statements = ast.Node.Block.StatementList.init(arena),
125 .rbrace = undefined,
126 }
127 );
128 const node = try arena.construct(ast.Node.Comptime {
129 .base = ast.Node {
130 .id = ast.Node.Id.Comptime,
131 },
132 .comptime_token = token_index,
133 .expr = &block.base,
134 .doc_comments = comments,
135 });
136 try root_node.decls.push(&node.base);
137
138 stack.push(State.TopLevel) catch unreachable;
139 try stack.push(State { .Block = block });
140 try stack.push(State {
141 .ExpectTokenSave = ExpectTokenSave {
142 .id = Token.Id.LBrace,
143 .ptr = &block.rbrace,
144 }
145 });
146 continue;
147 },
148 else => {
149 _ = tok_it.prev();
150 stack.push(State.TopLevel) catch unreachable;
151 try stack.push(State {
152 .TopLevelExtern = TopLevelDeclCtx {
153 .decls = &root_node.decls,
154 .visib_token = null,
155 .extern_export_inline_token = null,
156 .lib_name = null,
157 .comments = comments,
158 }
159 });
160 continue;
161 },
162 }
163 },
164 State.TopLevelExtern => |ctx| {
165 const token_index = tok_it.index;
166 const token_ptr = ??tok_it.next();
167 switch (token_ptr.id) {
168 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
169 stack.push(State {
170 .TopLevelDecl = TopLevelDeclCtx {
171 .decls = ctx.decls,
172 .visib_token = ctx.visib_token,
173 .extern_export_inline_token = AnnotatedToken {
174 .index = token_index,
175 .ptr = token_ptr,
176 },
177 .lib_name = null,
178 .comments = ctx.comments,
179 },
180 }) catch unreachable;
181 continue;
182 },
183 Token.Id.Keyword_extern => {
184 stack.push(State {
185 .TopLevelLibname = TopLevelDeclCtx {
186 .decls = ctx.decls,
187 .visib_token = ctx.visib_token,
188 .extern_export_inline_token = AnnotatedToken {
189 .index = token_index,
190 .ptr = token_ptr,
191 },
192 .lib_name = null,
193 .comments = ctx.comments,
194 },
195 }) catch unreachable;
196 continue;
197 },
198 else => {
199 _ = tok_it.prev();
200 stack.push(State { .TopLevelDecl = ctx }) catch unreachable;
201 continue;
202 }
203 }
204 },
205 State.TopLevelLibname => |ctx| {
206 const lib_name = blk: {
207 const lib_name_token_index = tok_it.index;
208 const lib_name_token_ptr = ??tok_it.next();
209 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index)) ?? {
210 _ = tok_it.prev();
211 break :blk null;
212 };
213 };
214
215 stack.push(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_index = tok_it.index;
228 const token_ptr = ??tok_it.next();
229 switch (token_ptr.id) {
230 Token.Id.Keyword_use => {
231 if (ctx.extern_export_inline_token) |annotated_token| {
232 *(try tree.errors.addOne()) = Error {
233 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
234 };
235 return tree;
236 }
237
238 const node = try arena.construct(ast.Node.Use {
239 .base = ast.Node {.id = ast.Node.Id.Use },
240 .visib_token = ctx.visib_token,
241 .expr = undefined,
242 .semicolon_token = undefined,
243 .doc_comments = ctx.comments,
244 });
245 try ctx.decls.push(&node.base);
246
247 stack.push(State {
248 .ExpectTokenSave = ExpectTokenSave {
249 .id = Token.Id.Semicolon,
250 .ptr = &node.semicolon_token,
251 }
252 }) catch unreachable;
253 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
254 continue;
255 },
256 Token.Id.Keyword_var, Token.Id.Keyword_const => {
257 if (ctx.extern_export_inline_token) |annotated_token| {
258 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
259 *(try tree.errors.addOne()) = Error {
260 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
261 };
262 return tree;
263 }
264 }
265
266 try stack.push(State {
267 .VarDecl = VarDeclCtx {
268 .comments = ctx.comments,
269 .visib_token = ctx.visib_token,
270 .lib_name = ctx.lib_name,
271 .comptime_token = null,
272 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
273 .mut_token = token_index,
274 .list = ctx.decls
275 }
276 });
277 continue;
278 },
279 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
280 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
281 const fn_proto = try arena.construct(ast.Node.FnProto {
282 .base = ast.Node {
283 .id = ast.Node.Id.FnProto,
284 },
285 .doc_comments = ctx.comments,
286 .visib_token = ctx.visib_token,
287 .name_token = null,
288 .fn_token = undefined,
289 .params = ast.Node.FnProto.ParamList.init(arena),
290 .return_type = undefined,
291 .var_args_token = null,
292 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
293 .cc_token = null,
294 .async_attr = null,
295 .body_node = null,
296 .lib_name = ctx.lib_name,
297 .align_expr = null,
298 });
299 try ctx.decls.push(&fn_proto.base);
300 stack.push(State { .FnDef = fn_proto }) catch unreachable;
301 try stack.push(State { .FnProto = fn_proto });
302
303 switch (token_ptr.id) {
304 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
305 fn_proto.cc_token = token_index;
306 try stack.push(State {
307 .ExpectTokenSave = ExpectTokenSave {
308 .id = Token.Id.Keyword_fn,
309 .ptr = &fn_proto.fn_token,
310 }
311 });
312 continue;
313 },
314 Token.Id.Keyword_async => {
315 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
316 ast.Node.AsyncAttribute {
317 .base = undefined,
318 .async_token = token_index,
319 .allocator_type = null,
320 .rangle_bracket = null,
321 }
322 );
323 fn_proto.async_attr = async_node;
324
325 try stack.push(State {
326 .ExpectTokenSave = ExpectTokenSave {
327 .id = Token.Id.Keyword_fn,
328 .ptr = &fn_proto.fn_token,
329 }
330 });
331 try stack.push(State { .AsyncAllocator = async_node });
332 continue;
333 },
334 Token.Id.Keyword_fn => {
335 fn_proto.fn_token = token_index;
336 continue;
337 },
338 else => unreachable,
339 }
340 },
341 else => {
342 *(try tree.errors.addOne()) = Error {
343 .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn { .token = token_index },
344 };
345 return tree;
346 },
347 }
348 },
349 State.TopLevelExternOrField => |ctx| {
350 if (eatToken(&tok_it, Token.Id.Identifier)) |identifier| {
351 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
352 const node = try arena.construct(ast.Node.StructField {
353 .base = ast.Node {
354 .id = ast.Node.Id.StructField,
355 },
356 .doc_comments = ctx.comments,
357 .visib_token = ctx.visib_token,
358 .name_token = identifier,
359 .type_expr = undefined,
360 });
361 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
362 *node_ptr = &node.base;
363
364 stack.push(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
365 try stack.push(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
366 try stack.push(State { .ExpectToken = Token.Id.Colon });
367 continue;
368 }
369
370 stack.push(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
371 try stack.push(State {
372 .TopLevelExtern = TopLevelDeclCtx {
373 .decls = &ctx.container_decl.fields_and_decls,
374 .visib_token = ctx.visib_token,
375 .extern_export_inline_token = null,
376 .lib_name = null,
377 .comments = ctx.comments,
378 }
379 });
380 continue;
381 },
382
383 State.FieldInitValue => |ctx| {
384 const eq_tok_index = tok_it.index;
385 const eq_tok_ptr = ??tok_it.next();
386 if (eq_tok_ptr.id != Token.Id.Equal) {
387 _ = tok_it.prev();
388 continue;
389 }
390 stack.push(State { .Expression = ctx }) catch unreachable;
391 continue;
392 },
393
394 State.ContainerKind => |ctx| {
395 const token_index = tok_it.index;
396 const token_ptr = ??tok_it.next();
397 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
398 ast.Node.ContainerDecl {
399 .base = undefined,
400 .ltoken = ctx.ltoken,
401 .layout = ctx.layout,
402 .kind = switch (token_ptr.id) {
403 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
404 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
405 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
406 else => {
407 *(try tree.errors.addOne()) = Error {
408 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
409 };
410 return tree;
411 },
412 },
413 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
414 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
415 .rbrace_token = undefined,
416 }
417 );
418
419 stack.push(State { .ContainerDecl = node }) catch unreachable;
420 try stack.push(State { .ExpectToken = Token.Id.LBrace });
421 try stack.push(State { .ContainerInitArgStart = node });
422 continue;
423 },
424
425 State.ContainerInitArgStart => |container_decl| {
426 if (eatToken(&tok_it, Token.Id.LParen) == null) {
427 continue;
428 }
429
430 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
431 try stack.push(State { .ContainerInitArg = container_decl });
432 continue;
433 },
434
435 State.ContainerInitArg => |container_decl| {
436 const init_arg_token_index = tok_it.index;
437 const init_arg_token_ptr = ??tok_it.next();
438 switch (init_arg_token_ptr.id) {
439 Token.Id.Keyword_enum => {
440 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
441 const lparen_tok_index = tok_it.index;
442 const lparen_tok_ptr = ??tok_it.next();
443 if (lparen_tok_ptr.id == Token.Id.LParen) {
444 try stack.push(State { .ExpectToken = Token.Id.RParen } );
445 try stack.push(State { .Expression = OptionalCtx {
446 .RequiredNull = &container_decl.init_arg_expr.Enum,
447 } });
448 } else {
449 _ = tok_it.prev();
450 }
451 },
452 else => {
453 _ = tok_it.prev();
454 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
455 stack.push(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
456 },
457 }
458 continue;
459 },
460
461 State.ContainerDecl => |container_decl| {
462 while (try eatLineComment(arena, &tok_it)) |line_comment| {
463 try container_decl.fields_and_decls.push(&line_comment.base);
464 }
465
466 const comments = try eatDocComments(arena, &tok_it);
467 const token_index = tok_it.index;
468 const token_ptr = ??tok_it.next();
469 switch (token_ptr.id) {
470 Token.Id.Identifier => {
471 switch (container_decl.kind) {
472 ast.Node.ContainerDecl.Kind.Struct => {
473 const node = try arena.construct(ast.Node.StructField {
474 .base = ast.Node {
475 .id = ast.Node.Id.StructField,
476 },
477 .doc_comments = comments,
478 .visib_token = null,
479 .name_token = token_index,
480 .type_expr = undefined,
481 });
482 const node_ptr = try container_decl.fields_and_decls.addOne();
483 *node_ptr = &node.base;
484
485 try stack.push(State { .FieldListCommaOrEnd = container_decl });
486 try stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
487 try stack.push(State { .ExpectToken = Token.Id.Colon });
488 continue;
489 },
490 ast.Node.ContainerDecl.Kind.Union => {
491 const node = try arena.construct(ast.Node.UnionTag {
492 .base = ast.Node {.id = ast.Node.Id.UnionTag },
493 .name_token = token_index,
494 .type_expr = null,
495 .value_expr = null,
496 .doc_comments = comments,
497 });
498 try container_decl.fields_and_decls.push(&node.base);
499
500 stack.push(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
501 try stack.push(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
502 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
503 try stack.push(State { .IfToken = Token.Id.Colon });
504 continue;
505 },
506 ast.Node.ContainerDecl.Kind.Enum => {
507 const node = try arena.construct(ast.Node.EnumTag {
508 .base = ast.Node { .id = ast.Node.Id.EnumTag },
509 .name_token = token_index,
510 .value = null,
511 .doc_comments = comments,
512 });
513 try container_decl.fields_and_decls.push(&node.base);
514
515 stack.push(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
516 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
517 try stack.push(State { .IfToken = Token.Id.Equal });
518 continue;
519 },
520 }
521 },
522 Token.Id.Keyword_pub => {
523 switch (container_decl.kind) {
524 ast.Node.ContainerDecl.Kind.Struct => {
525 try stack.push(State {
526 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
527 .visib_token = token_index,
528 .container_decl = container_decl,
529 .comments = comments,
530 }
531 });
532 continue;
533 },
534 else => {
535 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
536 try stack.push(State {
537 .TopLevelExtern = TopLevelDeclCtx {
538 .decls = &container_decl.fields_and_decls,
539 .visib_token = token_index,
540 .extern_export_inline_token = null,
541 .lib_name = null,
542 .comments = comments,
543 }
544 });
545 continue;
546 }
547 }
548 },
549 Token.Id.Keyword_export => {
550 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
551 try stack.push(State {
552 .TopLevelExtern = TopLevelDeclCtx {
553 .decls = &container_decl.fields_and_decls,
554 .visib_token = token_index,
555 .extern_export_inline_token = null,
556 .lib_name = null,
557 .comments = comments,
558 }
559 });
560 continue;
561 },
562 Token.Id.RBrace => {
563 if (comments != null) {
564 *(try tree.errors.addOne()) = Error {
565 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
566 };
567 return tree;
568 }
569 container_decl.rbrace_token = token_index;
570 continue;
571 },
572 else => {
573 _ = tok_it.prev();
574 stack.push(State{ .ContainerDecl = container_decl }) catch unreachable;
575 try stack.push(State {
576 .TopLevelExtern = TopLevelDeclCtx {
577 .decls = &container_decl.fields_and_decls,
578 .visib_token = null,
579 .extern_export_inline_token = null,
580 .lib_name = null,
581 .comments = comments,
582 }
583 });
584 continue;
585 }
586 }
587 },
588
589
590 State.VarDecl => |ctx| {
591 const var_decl = try arena.construct(ast.Node.VarDecl {
592 .base = ast.Node {
593 .id = ast.Node.Id.VarDecl,
594 },
595 .doc_comments = ctx.comments,
596 .visib_token = ctx.visib_token,
597 .mut_token = ctx.mut_token,
598 .comptime_token = ctx.comptime_token,
599 .extern_export_token = ctx.extern_export_token,
600 .type_node = null,
601 .align_node = null,
602 .init_node = null,
603 .lib_name = ctx.lib_name,
604 // initialized later
605 .name_token = undefined,
606 .eq_token = undefined,
607 .semicolon_token = undefined,
608 });
609 try ctx.list.push(&var_decl.base);
610
611 try stack.push(State { .VarDeclAlign = var_decl });
612 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
613 try stack.push(State { .IfToken = Token.Id.Colon });
614 try stack.push(State {
615 .ExpectTokenSave = ExpectTokenSave {
616 .id = Token.Id.Identifier,
617 .ptr = &var_decl.name_token,
618 }
619 });
620 continue;
621 },
622 State.VarDeclAlign => |var_decl| {
623 try stack.push(State { .VarDeclEq = var_decl });
624
625 const next_token_index = tok_it.index;
626 const next_token_ptr = ??tok_it.next();
627 if (next_token_ptr.id == Token.Id.Keyword_align) {
628 try stack.push(State { .ExpectToken = Token.Id.RParen });
629 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
630 try stack.push(State { .ExpectToken = Token.Id.LParen });
631 continue;
632 }
633
634 _ = tok_it.prev();
635 continue;
636 },
637 State.VarDeclEq => |var_decl| {
638 const token_index = tok_it.index;
639 const token_ptr = ??tok_it.next();
640 switch (token_ptr.id) {
641 Token.Id.Equal => {
642 var_decl.eq_token = token_index;
643 stack.push(State {
644 .ExpectTokenSave = ExpectTokenSave {
645 .id = Token.Id.Semicolon,
646 .ptr = &var_decl.semicolon_token,
647 },
648 }) catch unreachable;
649 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
650 continue;
651 },
652 Token.Id.Semicolon => {
653 var_decl.semicolon_token = token_index;
654 continue;
655 },
656 else => {
657 *(try tree.errors.addOne()) = Error {
658 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
659 };
660 return tree;
661 }
662 }
663 },
664
665
666 State.FnDef => |fn_proto| {
667 const token_index = tok_it.index;
668 const token_ptr = ??tok_it.next();
669 switch(token_ptr.id) {
670 Token.Id.LBrace => {
671 const block = try arena.construct(ast.Node.Block {
672 .base = ast.Node { .id = ast.Node.Id.Block },
673 .label = null,
674 .lbrace = token_index,
675 .statements = ast.Node.Block.StatementList.init(arena),
676 .rbrace = undefined,
677 });
678 fn_proto.body_node = &block.base;
679 stack.push(State { .Block = block }) catch unreachable;
680 continue;
681 },
682 Token.Id.Semicolon => continue,
683 else => {
684 *(try tree.errors.addOne()) = Error {
685 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
686 };
687 return tree;
688 },
689 }
690 },
691 State.FnProto => |fn_proto| {
692 stack.push(State { .FnProtoAlign = fn_proto }) catch unreachable;
693 try stack.push(State { .ParamDecl = fn_proto });
694 try stack.push(State { .ExpectToken = Token.Id.LParen });
695
696 if (eatToken(&tok_it, Token.Id.Identifier)) |name_token| {
697 fn_proto.name_token = name_token;
698 }
699 continue;
700 },
701 State.FnProtoAlign => |fn_proto| {
702 stack.push(State { .FnProtoReturnType = fn_proto }) catch unreachable;
703
704 if (eatToken(&tok_it, Token.Id.Keyword_align)) |align_token| {
705 try stack.push(State { .ExpectToken = Token.Id.RParen });
706 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
707 try stack.push(State { .ExpectToken = Token.Id.LParen });
708 }
709 continue;
710 },
711 State.FnProtoReturnType => |fn_proto| {
712 const token_index = tok_it.index;
713 const token_ptr = ??tok_it.next();
714 switch (token_ptr.id) {
715 Token.Id.Bang => {
716 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
717 stack.push(State {
718 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
719 }) catch unreachable;
720 continue;
721 },
722 else => {
723 // TODO: this is a special case. Remove this when #760 is fixed
724 if (token_ptr.id == Token.Id.Keyword_error) {
725 if ((??tok_it.peek()).id == Token.Id.LBrace) {
726 const error_type_node = try arena.construct(ast.Node.ErrorType {
727 .base = ast.Node { .id = ast.Node.Id.ErrorType },
728 .token = token_index,
729 });
730 fn_proto.return_type = ast.Node.FnProto.ReturnType {
731 .Explicit = &error_type_node.base,
732 };
733 continue;
734 }
735 }
736
737 _ = tok_it.prev();
738 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
739 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
740 continue;
741 },
742 }
743 },
744
745
746 State.ParamDecl => |fn_proto| {
747 if (eatToken(&tok_it, Token.Id.RParen)) |_| {
748 continue;
749 }
750 const param_decl = try arena.construct(ast.Node.ParamDecl {
751 .base = ast.Node {.id = ast.Node.Id.ParamDecl },
752 .comptime_token = null,
753 .noalias_token = null,
754 .name_token = null,
755 .type_node = undefined,
756 .var_args_token = null,
757 });
758 try fn_proto.params.push(&param_decl.base);
759
760 stack.push(State {
761 .ParamDeclEnd = ParamDeclEndCtx {
762 .param_decl = param_decl,
763 .fn_proto = fn_proto,
764 }
765 }) catch unreachable;
766 try stack.push(State { .ParamDeclName = param_decl });
767 try stack.push(State { .ParamDeclAliasOrComptime = param_decl });
768 continue;
769 },
770 State.ParamDeclAliasOrComptime => |param_decl| {
771 if (eatToken(&tok_it, Token.Id.Keyword_comptime)) |comptime_token| {
772 param_decl.comptime_token = comptime_token;
773 } else if (eatToken(&tok_it, Token.Id.Keyword_noalias)) |noalias_token| {
774 param_decl.noalias_token = noalias_token;
775 }
776 continue;
777 },
778 State.ParamDeclName => |param_decl| {
779 // TODO: Here, we eat two tokens in one state. This means that we can't have
780 // comments between these two tokens.
781 if (eatToken(&tok_it, Token.Id.Identifier)) |ident_token| {
782 if (eatToken(&tok_it, Token.Id.Colon)) |_| {
783 param_decl.name_token = ident_token;
784 } else {
785 _ = tok_it.prev();
786 }
787 }
788 continue;
789 },
790 State.ParamDeclEnd => |ctx| {
791 if (eatToken(&tok_it, Token.Id.Ellipsis3)) |ellipsis3| {
792 ctx.param_decl.var_args_token = ellipsis3;
793 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
794 continue;
795 }
796
797 try stack.push(State { .ParamDeclComma = ctx.fn_proto });
798 try stack.push(State {
799 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
800 });
801 continue;
802 },
803 State.ParamDeclComma => |fn_proto| {
804 switch (expectCommaOrEnd(&tok_it, Token.Id.RParen)) {
805 ExpectCommaOrEndResult.end_token => |t| {
806 if (t == null) {
807 stack.push(State { .ParamDecl = fn_proto }) catch unreachable;
808 }
809 continue;
810 },
811 ExpectCommaOrEndResult.parse_error => |e| {
812 try tree.errors.push(e);
813 return tree;
814 },
815 }
816 },
817
818 State.MaybeLabeledExpression => |ctx| {
819 if (eatToken(&tok_it, Token.Id.Colon)) |_| {
820 stack.push(State {
821 .LabeledExpression = LabelCtx {
822 .label = ctx.label,
823 .opt_ctx = ctx.opt_ctx,
824 }
825 }) catch unreachable;
826 continue;
827 }
828
829 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
830 continue;
831 },
832 State.LabeledExpression => |ctx| {
833 const token_index = tok_it.index;
834 const token_ptr = ??tok_it.next();
835 switch (token_ptr.id) {
836 Token.Id.LBrace => {
837 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
838 ast.Node.Block {
839 .base = undefined,
840 .label = ctx.label,
841 .lbrace = token_index,
842 .statements = ast.Node.Block.StatementList.init(arena),
843 .rbrace = undefined,
844 }
845 );
846 stack.push(State { .Block = block }) catch unreachable;
847 continue;
848 },
849 Token.Id.Keyword_while => {
850 stack.push(State {
851 .While = LoopCtx {
852 .label = ctx.label,
853 .inline_token = null,
854 .loop_token = token_index,
855 .opt_ctx = ctx.opt_ctx.toRequired(),
856 }
857 }) catch unreachable;
858 continue;
859 },
860 Token.Id.Keyword_for => {
861 stack.push(State {
862 .For = 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_suspend => {
872 const node = try arena.construct(ast.Node.Suspend {
873 .base = ast.Node {
874 .id = ast.Node.Id.Suspend,
875 },
876 .label = ctx.label,
877 .suspend_token = token_index,
878 .payload = null,
879 .body = null,
880 });
881 ctx.opt_ctx.store(&node.base);
882 stack.push(State { .SuspendBody = node }) catch unreachable;
883 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
884 continue;
885 },
886 Token.Id.Keyword_inline => {
887 stack.push(State {
888 .Inline = InlineCtx {
889 .label = ctx.label,
890 .inline_token = token_index,
891 .opt_ctx = ctx.opt_ctx.toRequired(),
892 }
893 }) catch unreachable;
894 continue;
895 },
896 else => {
897 if (ctx.opt_ctx != OptionalCtx.Optional) {
898 *(try tree.errors.addOne()) = Error {
899 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
900 };
901 return tree;
902 }
903
904 _ = tok_it.prev();
905 continue;
906 },
907 }
908 },
909 State.Inline => |ctx| {
910 const token_index = tok_it.index;
911 const token_ptr = ??tok_it.next();
912 switch (token_ptr.id) {
913 Token.Id.Keyword_while => {
914 stack.push(State {
915 .While = LoopCtx {
916 .inline_token = ctx.inline_token,
917 .label = ctx.label,
918 .loop_token = token_index,
919 .opt_ctx = ctx.opt_ctx.toRequired(),
920 }
921 }) catch unreachable;
922 continue;
923 },
924 Token.Id.Keyword_for => {
925 stack.push(State {
926 .For = LoopCtx {
927 .inline_token = ctx.inline_token,
928 .label = ctx.label,
929 .loop_token = token_index,
930 .opt_ctx = ctx.opt_ctx.toRequired(),
931 }
932 }) catch unreachable;
933 continue;
934 },
935 else => {
936 if (ctx.opt_ctx != OptionalCtx.Optional) {
937 *(try tree.errors.addOne()) = Error {
938 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
939 };
940 return tree;
941 }
942
943 _ = tok_it.prev();
944 continue;
945 },
946 }
947 },
948 State.While => |ctx| {
949 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
950 ast.Node.While {
951 .base = undefined,
952 .label = ctx.label,
953 .inline_token = ctx.inline_token,
954 .while_token = ctx.loop_token,
955 .condition = undefined,
956 .payload = null,
957 .continue_expr = null,
958 .body = undefined,
959 .@"else" = null,
960 }
961 );
962 stack.push(State { .Else = &node.@"else" }) catch unreachable;
963 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
964 try stack.push(State { .WhileContinueExpr = &node.continue_expr });
965 try stack.push(State { .IfToken = Token.Id.Colon });
966 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
967 try stack.push(State { .ExpectToken = Token.Id.RParen });
968 try stack.push(State { .Expression = OptionalCtx { .Required = &node.condition } });
969 try stack.push(State { .ExpectToken = Token.Id.LParen });
970 continue;
971 },
972 State.WhileContinueExpr => |dest| {
973 stack.push(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
974 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
975 try stack.push(State { .ExpectToken = Token.Id.LParen });
976 continue;
977 },
978 State.For => |ctx| {
979 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
980 ast.Node.For {
981 .base = undefined,
982 .label = ctx.label,
983 .inline_token = ctx.inline_token,
984 .for_token = ctx.loop_token,
985 .array_expr = undefined,
986 .payload = null,
987 .body = undefined,
988 .@"else" = null,
989 }
990 );
991 stack.push(State { .Else = &node.@"else" }) catch unreachable;
992 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
993 try stack.push(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
994 try stack.push(State { .ExpectToken = Token.Id.RParen });
995 try stack.push(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
996 try stack.push(State { .ExpectToken = Token.Id.LParen });
997 continue;
998 },
999 State.Else => |dest| {
1000 if (eatToken(&tok_it, Token.Id.Keyword_else)) |else_token| {
1001 const node = try createNode(arena, ast.Node.Else,
1002 ast.Node.Else {
1003 .base = undefined,
1004 .else_token = else_token,
1005 .payload = null,
1006 .body = undefined,
1007 }
1008 );
1009 *dest = node;
1010
1011 stack.push(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1012 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1013 continue;
1014 } else {
1015 continue;
1016 }
1017 },
1018
1019
1020 State.Block => |block| {
1021 const token_index = tok_it.index;
1022 const token_ptr = ??tok_it.next();
1023 switch (token_ptr.id) {
1024 Token.Id.RBrace => {
1025 block.rbrace = token_index;
1026 continue;
1027 },
1028 else => {
1029 _ = tok_it.prev();
1030 stack.push(State { .Block = block }) catch unreachable;
1031
1032 var any_comments = false;
1033 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1034 try block.statements.push(&line_comment.base);
1035 any_comments = true;
1036 }
1037 if (any_comments) continue;
1038
1039 try stack.push(State { .Statement = block });
1040 continue;
1041 },
1042 }
1043 },
1044 State.Statement => |block| {
1045 const token_index = tok_it.index;
1046 const token_ptr = ??tok_it.next();
1047 switch (token_ptr.id) {
1048 Token.Id.Keyword_comptime => {
1049 stack.push(State {
1050 .ComptimeStatement = ComptimeStatementCtx {
1051 .comptime_token = token_index,
1052 .block = block,
1053 }
1054 }) catch unreachable;
1055 continue;
1056 },
1057 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1058 stack.push(State {
1059 .VarDecl = VarDeclCtx {
1060 .comments = null,
1061 .visib_token = null,
1062 .comptime_token = null,
1063 .extern_export_token = null,
1064 .lib_name = null,
1065 .mut_token = token_index,
1066 .list = &block.statements,
1067 }
1068 }) catch unreachable;
1069 continue;
1070 },
1071 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1072 const node = try arena.construct(ast.Node.Defer {
1073 .base = ast.Node {
1074 .id = ast.Node.Id.Defer,
1075 },
1076 .defer_token = token_index,
1077 .kind = switch (token_ptr.id) {
1078 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1079 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1080 else => unreachable,
1081 },
1082 .expr = undefined,
1083 });
1084 const node_ptr = try block.statements.addOne();
1085 *node_ptr = &node.base;
1086
1087 stack.push(State { .Semicolon = node_ptr }) catch unreachable;
1088 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1089 continue;
1090 },
1091 Token.Id.LBrace => {
1092 const inner_block = try arena.construct(ast.Node.Block {
1093 .base = ast.Node { .id = ast.Node.Id.Block },
1094 .label = null,
1095 .lbrace = token_index,
1096 .statements = ast.Node.Block.StatementList.init(arena),
1097 .rbrace = undefined,
1098 });
1099 try block.statements.push(&inner_block.base);
1100
1101 stack.push(State { .Block = inner_block }) catch unreachable;
1102 continue;
1103 },
1104 else => {
1105 _ = tok_it.prev();
1106 const statement = try block.statements.addOne();
1107 try stack.push(State { .Semicolon = statement });
1108 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1109 continue;
1110 }
1111 }
1112 },
1113 State.ComptimeStatement => |ctx| {
1114 const token_index = tok_it.index;
1115 const token_ptr = ??tok_it.next();
1116 switch (token_ptr.id) {
1117 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1118 stack.push(State {
1119 .VarDecl = VarDeclCtx {
1120 .comments = null,
1121 .visib_token = null,
1122 .comptime_token = ctx.comptime_token,
1123 .extern_export_token = null,
1124 .lib_name = null,
1125 .mut_token = token_index,
1126 .list = &ctx.block.statements,
1127 }
1128 }) catch unreachable;
1129 continue;
1130 },
1131 else => {
1132 _ = tok_it.prev();
1133 _ = tok_it.prev();
1134 const statement = try ctx.block.statements.addOne();
1135 try stack.push(State { .Semicolon = statement });
1136 try stack.push(State { .Expression = OptionalCtx { .Required = statement } });
1137 continue;
1138 }
1139 }
1140 },
1141 State.Semicolon => |node_ptr| {
1142 const node = *node_ptr;
1143 if (requireSemiColon(node)) {
1144 stack.push(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1145 continue;
1146 }
1147 continue;
1148 },
1149
1150 State.AsmOutputItems => |items| {
1151 const lbracket_index = tok_it.index;
1152 const lbracket_ptr = ??tok_it.next();
1153 if (lbracket_ptr.id != Token.Id.LBracket) {
1154 _ = tok_it.prev();
1155 continue;
1156 }
1157
1158 const node = try createNode(arena, ast.Node.AsmOutput,
1159 ast.Node.AsmOutput {
1160 .base = undefined,
1161 .symbolic_name = undefined,
1162 .constraint = undefined,
1163 .kind = undefined,
1164 }
1165 );
1166 try items.push(node);
1167
1168 stack.push(State { .AsmOutputItems = items }) catch unreachable;
1169 try stack.push(State { .IfToken = Token.Id.Comma });
1170 try stack.push(State { .ExpectToken = Token.Id.RParen });
1171 try stack.push(State { .AsmOutputReturnOrType = node });
1172 try stack.push(State { .ExpectToken = Token.Id.LParen });
1173 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1174 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1175 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1176 continue;
1177 },
1178 State.AsmOutputReturnOrType => |node| {
1179 const token_index = tok_it.index;
1180 const token_ptr = ??tok_it.next();
1181 switch (token_ptr.id) {
1182 Token.Id.Identifier => {
1183 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1184 continue;
1185 },
1186 Token.Id.Arrow => {
1187 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1188 try stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1189 continue;
1190 },
1191 else => {
1192 *(try tree.errors.addOne()) = Error {
1193 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1194 .token = token_index,
1195 },
1196 };
1197 return tree;
1198 },
1199 }
1200 },
1201 State.AsmInputItems => |items| {
1202 const lbracket_index = tok_it.index;
1203 const lbracket_ptr = ??tok_it.next();
1204 if (lbracket_ptr.id != Token.Id.LBracket) {
1205 _ = tok_it.prev();
1206 continue;
1207 }
1208
1209 const node = try createNode(arena, ast.Node.AsmInput,
1210 ast.Node.AsmInput {
1211 .base = undefined,
1212 .symbolic_name = undefined,
1213 .constraint = undefined,
1214 .expr = undefined,
1215 }
1216 );
1217 try items.push(node);
1218
1219 stack.push(State { .AsmInputItems = items }) catch unreachable;
1220 try stack.push(State { .IfToken = Token.Id.Comma });
1221 try stack.push(State { .ExpectToken = Token.Id.RParen });
1222 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
1223 try stack.push(State { .ExpectToken = Token.Id.LParen });
1224 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1225 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1226 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1227 continue;
1228 },
1229 State.AsmClobberItems => |items| {
1230 stack.push(State { .AsmClobberItems = items }) catch unreachable;
1231 try stack.push(State { .IfToken = Token.Id.Comma });
1232 try stack.push(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1233 continue;
1234 },
1235
1236
1237 State.ExprListItemOrEnd => |list_state| {
1238 if (eatToken(&tok_it, list_state.end)) |token_index| {
1239 *list_state.ptr = token_index;
1240 continue;
1241 }
1242
1243 stack.push(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1244 try stack.push(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1245 continue;
1246 },
1247 State.ExprListCommaOrEnd => |list_state| {
1248 switch (expectCommaOrEnd(&tok_it, list_state.end)) {
1249 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1250 *list_state.ptr = end;
1251 continue;
1252 } else {
1253 stack.push(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1254 continue;
1255 },
1256 ExpectCommaOrEndResult.parse_error => |e| {
1257 try tree.errors.push(e);
1258 return tree;
1259 },
1260 }
1261 },
1262 State.FieldInitListItemOrEnd => |list_state| {
1263 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1264 try list_state.list.push(&line_comment.base);
1265 }
1266
1267 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1268 *list_state.ptr = rbrace;
1269 continue;
1270 }
1271
1272 const node = try arena.construct(ast.Node.FieldInitializer {
1273 .base = ast.Node {
1274 .id = ast.Node.Id.FieldInitializer,
1275 },
1276 .period_token = undefined,
1277 .name_token = undefined,
1278 .expr = undefined,
1279 });
1280 try list_state.list.push(&node.base);
1281
1282 stack.push(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1283 try stack.push(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1284 try stack.push(State { .ExpectToken = Token.Id.Equal });
1285 try stack.push(State {
1286 .ExpectTokenSave = ExpectTokenSave {
1287 .id = Token.Id.Identifier,
1288 .ptr = &node.name_token,
1289 }
1290 });
1291 try stack.push(State {
1292 .ExpectTokenSave = ExpectTokenSave {
1293 .id = Token.Id.Period,
1294 .ptr = &node.period_token,
1295 }
1296 });
1297 continue;
1298 },
1299 State.FieldInitListCommaOrEnd => |list_state| {
1300 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1301 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1302 *list_state.ptr = end;
1303 continue;
1304 } else {
1305 stack.push(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1306 continue;
1307 },
1308 ExpectCommaOrEndResult.parse_error => |e| {
1309 try tree.errors.push(e);
1310 return tree;
1311 },
1312 }
1313 },
1314 State.FieldListCommaOrEnd => |container_decl| {
1315 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1316 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1317 container_decl.rbrace_token = end;
1318 continue;
1319 } else {
1320 try stack.push(State { .ContainerDecl = container_decl });
1321 continue;
1322 },
1323 ExpectCommaOrEndResult.parse_error => |e| {
1324 try tree.errors.push(e);
1325 return tree;
1326 },
1327 }
1328 },
1329 State.ErrorTagListItemOrEnd => |list_state| {
1330 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1331 try list_state.list.push(&line_comment.base);
1332 }
1333
1334 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1335 *list_state.ptr = rbrace;
1336 continue;
1337 }
1338
1339 const node_ptr = try list_state.list.addOne();
1340
1341 try stack.push(State { .ErrorTagListCommaOrEnd = list_state });
1342 try stack.push(State { .ErrorTag = node_ptr });
1343 continue;
1344 },
1345 State.ErrorTagListCommaOrEnd => |list_state| {
1346 switch (expectCommaOrEnd(&tok_it, Token.Id.RBrace)) {
1347 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1348 *list_state.ptr = end;
1349 continue;
1350 } else {
1351 stack.push(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1352 continue;
1353 },
1354 ExpectCommaOrEndResult.parse_error => |e| {
1355 try tree.errors.push(e);
1356 return tree;
1357 },
1358 }
1359 },
1360 State.SwitchCaseOrEnd => |list_state| {
1361 while (try eatLineComment(arena, &tok_it)) |line_comment| {
1362 try list_state.list.push(&line_comment.base);
1363 }
1364
1365 if (eatToken(&tok_it, Token.Id.RBrace)) |rbrace| {
1366 *list_state.ptr = rbrace;
1367 continue;
1368 }
1369
1370 const comments = try eatDocComments(arena, &tok_it);
1371 const node = try arena.construct(ast.Node.SwitchCase {
1372 .base = ast.Node {
1373 .id = ast.Node.Id.SwitchCase,
1374 },
1375 .items = ast.Node.SwitchCase.ItemList.init(arena),
1376 .payload = null,
1377 .expr = undefined,
1378 });
1379 try list_state.list.push(&node.base);
1380 try stack.push(State { .SwitchCaseCommaOrEnd = list_state });
1381 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1382 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1383 try stack.push(State { .SwitchCaseFirstItem = &node.items });
1384
1385 continue;
1386 },
1387
1388 State.SwitchCaseCommaOrEnd => |list_state| {
1389 switch (expectCommaOrEnd(&tok_it, Token.Id.RParen)) {
1390 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1391 *list_state.ptr = end;
1392 continue;
1393 } else {
1394 try stack.push(State { .SwitchCaseOrEnd = list_state });
1395 continue;
1396 },
1397 ExpectCommaOrEndResult.parse_error => |e| {
1398 try tree.errors.push(e);
1399 return tree;
1400 },
1401 }
1402 },
1403
1404 State.SwitchCaseFirstItem => |case_items| {
1405 const token_index = tok_it.index;
1406 const token_ptr = ??tok_it.next();
1407 if (token_ptr.id == Token.Id.Keyword_else) {
1408 const else_node = try arena.construct(ast.Node.SwitchElse {
1409 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},
1410 .token = token_index,
1411 });
1412 try case_items.push(&else_node.base);
1413
1414 try stack.push(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1415 continue;
1416 } else {
1417 _ = tok_it.prev();
1418 try stack.push(State { .SwitchCaseItem = case_items });
1419 continue;
1420 }
1421 },
1422 State.SwitchCaseItem => |case_items| {
1423 stack.push(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1424 try stack.push(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1425 },
1426 State.SwitchCaseItemCommaOrEnd => |case_items| {
1427 switch (expectCommaOrEnd(&tok_it, Token.Id.EqualAngleBracketRight)) {
1428 ExpectCommaOrEndResult.end_token => |t| {
1429 if (t == null) {
1430 stack.push(State { .SwitchCaseItem = case_items }) catch unreachable;
1431 }
1432 continue;
1433 },
1434 ExpectCommaOrEndResult.parse_error => |e| {
1435 try tree.errors.push(e);
1436 return tree;
1437 },
1438 }
1439 continue;
1440 },
1441
1442
1443 State.SuspendBody => |suspend_node| {
1444 if (suspend_node.payload != null) {
1445 try stack.push(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1446 }
1447 continue;
1448 },
1449 State.AsyncAllocator => |async_node| {
1450 if (eatToken(&tok_it, Token.Id.AngleBracketLeft) == null) {
1451 continue;
1452 }
1453
1454 async_node.rangle_bracket = TokenIndex(0);
1455 try stack.push(State {
1456 .ExpectTokenSave = ExpectTokenSave {
1457 .id = Token.Id.AngleBracketRight,
1458 .ptr = &??async_node.rangle_bracket,
1459 }
1460 });
1461 try stack.push(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1462 continue;
1463 },
1464 State.AsyncEnd => |ctx| {
1465 const node = ctx.ctx.get() ?? continue;
1466
1467 switch (node.id) {
1468 ast.Node.Id.FnProto => {
1469 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1470 fn_proto.async_attr = ctx.attribute;
1471 continue;
1472 },
1473 ast.Node.Id.SuffixOp => {
1474 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1475 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1476 suffix_op.op.Call.async_attr = ctx.attribute;
1477 continue;
1478 }
1479
1480 *(try tree.errors.addOne()) = Error {
1481 .ExpectedCall = Error.ExpectedCall { .node = node },
1482 };
1483 return tree;
1484 },
1485 else => {
1486 *(try tree.errors.addOne()) = Error {
1487 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1488 };
1489 return tree;
1490 }
1491 }
1492 },
1493
1494
1495 State.ExternType => |ctx| {
1496 if (eatToken(&tok_it, Token.Id.Keyword_fn)) |fn_token| {
1497 const fn_proto = try arena.construct(ast.Node.FnProto {
1498 .base = ast.Node {
1499 .id = ast.Node.Id.FnProto,
1500 },
1501 .doc_comments = ctx.comments,
1502 .visib_token = null,
1503 .name_token = null,
1504 .fn_token = fn_token,
1505 .params = ast.Node.FnProto.ParamList.init(arena),
1506 .return_type = undefined,
1507 .var_args_token = null,
1508 .extern_export_inline_token = ctx.extern_token,
1509 .cc_token = null,
1510 .async_attr = null,
1511 .body_node = null,
1512 .lib_name = null,
1513 .align_expr = null,
1514 });
1515 ctx.opt_ctx.store(&fn_proto.base);
1516 stack.push(State { .FnProto = fn_proto }) catch unreachable;
1517 continue;
1518 }
1519
1520 stack.push(State {
1521 .ContainerKind = ContainerKindCtx {
1522 .opt_ctx = ctx.opt_ctx,
1523 .ltoken = ctx.extern_token,
1524 .layout = ast.Node.ContainerDecl.Layout.Extern,
1525 },
1526 }) catch unreachable;
1527 continue;
1528 },
1529 State.SliceOrArrayAccess => |node| {
1530 const token_index = tok_it.index;
1531 const token_ptr = ??tok_it.next();
1532 switch (token_ptr.id) {
1533 Token.Id.Ellipsis2 => {
1534 const start = node.op.ArrayAccess;
1535 node.op = ast.Node.SuffixOp.Op {
1536 .Slice = ast.Node.SuffixOp.Op.Slice {
1537 .start = start,
1538 .end = null,
1539 }
1540 };
1541
1542 stack.push(State {
1543 .ExpectTokenSave = ExpectTokenSave {
1544 .id = Token.Id.RBracket,
1545 .ptr = &node.rtoken,
1546 }
1547 }) catch unreachable;
1548 try stack.push(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1549 continue;
1550 },
1551 Token.Id.RBracket => {
1552 node.rtoken = token_index;
1553 continue;
1554 },
1555 else => {
1556 *(try tree.errors.addOne()) = Error {
1557 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1558 };
1559 return tree;
1560 }
1561 }
1562 },
1563 State.SliceOrArrayType => |node| {
1564 if (eatToken(&tok_it, Token.Id.RBracket)) |_| {
1565 node.op = ast.Node.PrefixOp.Op {
1566 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1567 .align_expr = null,
1568 .bit_offset_start_token = null,
1569 .bit_offset_end_token = null,
1570 .const_token = null,
1571 .volatile_token = null,
1572 }
1573 };
1574 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1575 try stack.push(State { .AddrOfModifiers = &node.op.SliceType });
1576 continue;
1577 }
1578
1579 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1580 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1581 try stack.push(State { .ExpectToken = Token.Id.RBracket });
1582 try stack.push(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1583 continue;
1584 },
1585 State.AddrOfModifiers => |addr_of_info| {
1586 const token_index = tok_it.index;
1587 const token_ptr = ??tok_it.next();
1588 switch (token_ptr.id) {
1589 Token.Id.Keyword_align => {
1590 stack.push(state) catch unreachable;
1591 if (addr_of_info.align_expr != null) {
1592 *(try tree.errors.addOne()) = Error {
1593 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1594 };
1595 return tree;
1596 }
1597 try stack.push(State { .ExpectToken = Token.Id.RParen });
1598 try stack.push(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1599 try stack.push(State { .ExpectToken = Token.Id.LParen });
1600 continue;
1601 },
1602 Token.Id.Keyword_const => {
1603 stack.push(state) catch unreachable;
1604 if (addr_of_info.const_token != null) {
1605 *(try tree.errors.addOne()) = Error {
1606 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1607 };
1608 return tree;
1609 }
1610 addr_of_info.const_token = token_index;
1611 continue;
1612 },
1613 Token.Id.Keyword_volatile => {
1614 stack.push(state) catch unreachable;
1615 if (addr_of_info.volatile_token != null) {
1616 *(try tree.errors.addOne()) = Error {
1617 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1618 };
1619 return tree;
1620 }
1621 addr_of_info.volatile_token = token_index;
1622 continue;
1623 },
1624 else => {
1625 _ = tok_it.prev();
1626 continue;
1627 },
1628 }
1629 },
1630
1631
1632 State.Payload => |opt_ctx| {
1633 const token_index = tok_it.index;
1634 const token_ptr = ??tok_it.next();
1635 if (token_ptr.id != Token.Id.Pipe) {
1636 if (opt_ctx != OptionalCtx.Optional) {
1637 *(try tree.errors.addOne()) = Error {
1638 .ExpectedToken = Error.ExpectedToken {
1639 .token = token_index,
1640 .expected_id = Token.Id.Pipe,
1641 },
1642 };
1643 return tree;
1644 }
1645
1646 _ = tok_it.prev();
1647 continue;
1648 }
1649
1650 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1651 ast.Node.Payload {
1652 .base = undefined,
1653 .lpipe = token_index,
1654 .error_symbol = undefined,
1655 .rpipe = undefined
1656 }
1657 );
1658
1659 stack.push(State {
1660 .ExpectTokenSave = ExpectTokenSave {
1661 .id = Token.Id.Pipe,
1662 .ptr = &node.rpipe,
1663 }
1664 }) catch unreachable;
1665 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1666 continue;
1667 },
1668 State.PointerPayload => |opt_ctx| {
1669 const token_index = tok_it.index;
1670 const token_ptr = ??tok_it.next();
1671 if (token_ptr.id != Token.Id.Pipe) {
1672 if (opt_ctx != OptionalCtx.Optional) {
1673 *(try tree.errors.addOne()) = Error {
1674 .ExpectedToken = Error.ExpectedToken {
1675 .token = token_index,
1676 .expected_id = Token.Id.Pipe,
1677 },
1678 };
1679 return tree;
1680 }
1681
1682 _ = tok_it.prev();
1683 continue;
1684 }
1685
1686 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1687 ast.Node.PointerPayload {
1688 .base = undefined,
1689 .lpipe = token_index,
1690 .ptr_token = null,
1691 .value_symbol = undefined,
1692 .rpipe = undefined
1693 }
1694 );
1695
1696 try stack.push(State {
1697 .ExpectTokenSave = ExpectTokenSave {
1698 .id = Token.Id.Pipe,
1699 .ptr = &node.rpipe,
1700 }
1701 });
1702 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1703 try stack.push(State {
1704 .OptionalTokenSave = OptionalTokenSave {
1705 .id = Token.Id.Asterisk,
1706 .ptr = &node.ptr_token,
1707 }
1708 });
1709 continue;
1710 },
1711 State.PointerIndexPayload => |opt_ctx| {
1712 const token_index = tok_it.index;
1713 const token_ptr = ??tok_it.next();
1714 if (token_ptr.id != Token.Id.Pipe) {
1715 if (opt_ctx != OptionalCtx.Optional) {
1716 *(try tree.errors.addOne()) = Error {
1717 .ExpectedToken = Error.ExpectedToken {
1718 .token = token_index,
1719 .expected_id = Token.Id.Pipe,
1720 },
1721 };
1722 return tree;
1723 }
1724
1725 _ = tok_it.prev();
1726 continue;
1727 }
1728
1729 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1730 ast.Node.PointerIndexPayload {
1731 .base = undefined,
1732 .lpipe = token_index,
1733 .ptr_token = null,
1734 .value_symbol = undefined,
1735 .index_symbol = null,
1736 .rpipe = undefined
1737 }
1738 );
1739
1740 stack.push(State {
1741 .ExpectTokenSave = ExpectTokenSave {
1742 .id = Token.Id.Pipe,
1743 .ptr = &node.rpipe,
1744 }
1745 }) catch unreachable;
1746 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1747 try stack.push(State { .IfToken = Token.Id.Comma });
1748 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1749 try stack.push(State {
1750 .OptionalTokenSave = OptionalTokenSave {
1751 .id = Token.Id.Asterisk,
1752 .ptr = &node.ptr_token,
1753 }
1754 });
1755 continue;
1756 },
1757
1758
1759 State.Expression => |opt_ctx| {
1760 const token_index = tok_it.index;
1761 const token_ptr = ??tok_it.next();
1762 switch (token_ptr.id) {
1763 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1764 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1765 ast.Node.ControlFlowExpression {
1766 .base = undefined,
1767 .ltoken = token_index,
1768 .kind = undefined,
1769 .rhs = null,
1770 }
1771 );
1772
1773 stack.push(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1774
1775 switch (token_ptr.id) {
1776 Token.Id.Keyword_break => {
1777 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1778 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1779 try stack.push(State { .IfToken = Token.Id.Colon });
1780 },
1781 Token.Id.Keyword_continue => {
1782 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1783 try stack.push(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1784 try stack.push(State { .IfToken = Token.Id.Colon });
1785 },
1786 Token.Id.Keyword_return => {
1787 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1788 },
1789 else => unreachable,
1790 }
1791 continue;
1792 },
1793 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1794 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1795 ast.Node.PrefixOp {
1796 .base = undefined,
1797 .op_token = token_index,
1798 .op = switch (token_ptr.id) {
1799 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1800 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1801 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1802 else => unreachable,
1803 },
1804 .rhs = undefined,
1805 }
1806 );
1807
1808 stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1809 continue;
1810 },
1811 else => {
1812 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1813 _ = tok_it.prev();
1814 stack.push(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1815 }
1816 continue;
1817 }
1818 }
1819 },
1820 State.RangeExpressionBegin => |opt_ctx| {
1821 stack.push(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1822 try stack.push(State { .Expression = opt_ctx });
1823 continue;
1824 },
1825 State.RangeExpressionEnd => |opt_ctx| {
1826 const lhs = opt_ctx.get() ?? continue;
1827
1828 if (eatToken(&tok_it, Token.Id.Ellipsis3)) |ellipsis3| {
1829 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1830 ast.Node.InfixOp {
1831 .base = undefined,
1832 .lhs = lhs,
1833 .op_token = ellipsis3,
1834 .op = ast.Node.InfixOp.Op.Range,
1835 .rhs = undefined,
1836 }
1837 );
1838 stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1839 continue;
1840 }
1841 },
1842 State.AssignmentExpressionBegin => |opt_ctx| {
1843 stack.push(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1844 try stack.push(State { .Expression = opt_ctx });
1845 continue;
1846 },
1847
1848 State.AssignmentExpressionEnd => |opt_ctx| {
1849 const lhs = opt_ctx.get() ?? continue;
1850
1851 const token_index = tok_it.index;
1852 const token_ptr = ??tok_it.next();
1853 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1854 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1855 ast.Node.InfixOp {
1856 .base = undefined,
1857 .lhs = lhs,
1858 .op_token = token_index,
1859 .op = ass_id,
1860 .rhs = undefined,
1861 }
1862 );
1863 stack.push(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1864 try stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1865 continue;
1866 } else {
1867 _ = tok_it.prev();
1868 continue;
1869 }
1870 },
1871
1872 State.UnwrapExpressionBegin => |opt_ctx| {
1873 stack.push(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1874 try stack.push(State { .BoolOrExpressionBegin = opt_ctx });
1875 continue;
1876 },
1877
1878 State.UnwrapExpressionEnd => |opt_ctx| {
1879 const lhs = opt_ctx.get() ?? continue;
1880
1881 const token_index = tok_it.index;
1882 const token_ptr = ??tok_it.next();
1883 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1884 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1885 ast.Node.InfixOp {
1886 .base = undefined,
1887 .lhs = lhs,
1888 .op_token = token_index,
1889 .op = unwrap_id,
1890 .rhs = undefined,
1891 }
1892 );
1893
1894 stack.push(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1895 try stack.push(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1896
1897 if (node.op == ast.Node.InfixOp.Op.Catch) {
1898 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1899 }
1900 continue;
1901 } else {
1902 _ = tok_it.prev();
1903 continue;
1904 }
1905 },
1906
1907 State.BoolOrExpressionBegin => |opt_ctx| {
1908 stack.push(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1909 try stack.push(State { .BoolAndExpressionBegin = opt_ctx });
1910 continue;
1911 },
1912
1913 State.BoolOrExpressionEnd => |opt_ctx| {
1914 const lhs = opt_ctx.get() ?? continue;
1915
1916 if (eatToken(&tok_it, Token.Id.Keyword_or)) |or_token| {
1917 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1918 ast.Node.InfixOp {
1919 .base = undefined,
1920 .lhs = lhs,
1921 .op_token = or_token,
1922 .op = ast.Node.InfixOp.Op.BoolOr,
1923 .rhs = undefined,
1924 }
1925 );
1926 stack.push(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1927 try stack.push(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1928 continue;
1929 }
1930 },
1931
1932 State.BoolAndExpressionBegin => |opt_ctx| {
1933 stack.push(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1934 try stack.push(State { .ComparisonExpressionBegin = opt_ctx });
1935 continue;
1936 },
1937
1938 State.BoolAndExpressionEnd => |opt_ctx| {
1939 const lhs = opt_ctx.get() ?? continue;
1940
1941 if (eatToken(&tok_it, Token.Id.Keyword_and)) |and_token| {
1942 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1943 ast.Node.InfixOp {
1944 .base = undefined,
1945 .lhs = lhs,
1946 .op_token = and_token,
1947 .op = ast.Node.InfixOp.Op.BoolAnd,
1948 .rhs = undefined,
1949 }
1950 );
1951 stack.push(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1952 try stack.push(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1953 continue;
1954 }
1955 },
1956
1957 State.ComparisonExpressionBegin => |opt_ctx| {
1958 stack.push(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1959 try stack.push(State { .BinaryOrExpressionBegin = opt_ctx });
1960 continue;
1961 },
1962
1963 State.ComparisonExpressionEnd => |opt_ctx| {
1964 const lhs = opt_ctx.get() ?? continue;
1965
1966 const token_index = tok_it.index;
1967 const token_ptr = ??tok_it.next();
1968 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1969 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1970 ast.Node.InfixOp {
1971 .base = undefined,
1972 .lhs = lhs,
1973 .op_token = token_index,
1974 .op = comp_id,
1975 .rhs = undefined,
1976 }
1977 );
1978 stack.push(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1979 try stack.push(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1980 continue;
1981 } else {
1982 _ = tok_it.prev();
1983 continue;
1984 }
1985 },
1986
1987 State.BinaryOrExpressionBegin => |opt_ctx| {
1988 stack.push(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
1989 try stack.push(State { .BinaryXorExpressionBegin = opt_ctx });
1990 continue;
1991 },
1992
1993 State.BinaryOrExpressionEnd => |opt_ctx| {
1994 const lhs = opt_ctx.get() ?? continue;
1995
1996 if (eatToken(&tok_it, Token.Id.Pipe)) |pipe| {
1997 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1998 ast.Node.InfixOp {
1999 .base = undefined,
2000 .lhs = lhs,
2001 .op_token = pipe,
2002 .op = ast.Node.InfixOp.Op.BitOr,
2003 .rhs = undefined,
2004 }
2005 );
2006 stack.push(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2007 try stack.push(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2008 continue;
2009 }
2010 },
2011
2012 State.BinaryXorExpressionBegin => |opt_ctx| {
2013 stack.push(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2014 try stack.push(State { .BinaryAndExpressionBegin = opt_ctx });
2015 continue;
2016 },
2017
2018 State.BinaryXorExpressionEnd => |opt_ctx| {
2019 const lhs = opt_ctx.get() ?? continue;
2020
2021 if (eatToken(&tok_it, Token.Id.Caret)) |caret| {
2022 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2023 ast.Node.InfixOp {
2024 .base = undefined,
2025 .lhs = lhs,
2026 .op_token = caret,
2027 .op = ast.Node.InfixOp.Op.BitXor,
2028 .rhs = undefined,
2029 }
2030 );
2031 stack.push(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2032 try stack.push(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2033 continue;
2034 }
2035 },
2036
2037 State.BinaryAndExpressionBegin => |opt_ctx| {
2038 stack.push(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2039 try stack.push(State { .BitShiftExpressionBegin = opt_ctx });
2040 continue;
2041 },
2042
2043 State.BinaryAndExpressionEnd => |opt_ctx| {
2044 const lhs = opt_ctx.get() ?? continue;
2045
2046 if (eatToken(&tok_it, Token.Id.Ampersand)) |ampersand| {
2047 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2048 ast.Node.InfixOp {
2049 .base = undefined,
2050 .lhs = lhs,
2051 .op_token = ampersand,
2052 .op = ast.Node.InfixOp.Op.BitAnd,
2053 .rhs = undefined,
2054 }
2055 );
2056 stack.push(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2057 try stack.push(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2058 continue;
2059 }
2060 },
2061
2062 State.BitShiftExpressionBegin => |opt_ctx| {
2063 stack.push(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2064 try stack.push(State { .AdditionExpressionBegin = opt_ctx });
2065 continue;
2066 },
2067
2068 State.BitShiftExpressionEnd => |opt_ctx| {
2069 const lhs = opt_ctx.get() ?? continue;
2070
2071 const token_index = tok_it.index;
2072 const token_ptr = ??tok_it.next();
2073 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2074 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2075 ast.Node.InfixOp {
2076 .base = undefined,
2077 .lhs = lhs,
2078 .op_token = token_index,
2079 .op = bitshift_id,
2080 .rhs = undefined,
2081 }
2082 );
2083 stack.push(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2084 try stack.push(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2085 continue;
2086 } else {
2087 _ = tok_it.prev();
2088 continue;
2089 }
2090 },
2091
2092 State.AdditionExpressionBegin => |opt_ctx| {
2093 stack.push(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2094 try stack.push(State { .MultiplyExpressionBegin = opt_ctx });
2095 continue;
2096 },
2097
2098 State.AdditionExpressionEnd => |opt_ctx| {
2099 const lhs = opt_ctx.get() ?? continue;
2100
2101 const token_index = tok_it.index;
2102 const token_ptr = ??tok_it.next();
2103 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2104 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2105 ast.Node.InfixOp {
2106 .base = undefined,
2107 .lhs = lhs,
2108 .op_token = token_index,
2109 .op = add_id,
2110 .rhs = undefined,
2111 }
2112 );
2113 stack.push(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2114 try stack.push(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2115 continue;
2116 } else {
2117 _ = tok_it.prev();
2118 continue;
2119 }
2120 },
2121
2122 State.MultiplyExpressionBegin => |opt_ctx| {
2123 stack.push(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2124 try stack.push(State { .CurlySuffixExpressionBegin = opt_ctx });
2125 continue;
2126 },
2127
2128 State.MultiplyExpressionEnd => |opt_ctx| {
2129 const lhs = opt_ctx.get() ?? continue;
2130
2131 const token_index = tok_it.index;
2132 const token_ptr = ??tok_it.next();
2133 if (tokenIdToMultiply(token_ptr.id)) |mult_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 = mult_id,
2140 .rhs = undefined,
2141 }
2142 );
2143 stack.push(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2144 try stack.push(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2145 continue;
2146 } else {
2147 _ = tok_it.prev();
2148 continue;
2149 }
2150 },
2151
2152 State.CurlySuffixExpressionBegin => |opt_ctx| {
2153 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2154 try stack.push(State { .IfToken = Token.Id.LBrace });
2155 try stack.push(State { .TypeExprBegin = opt_ctx });
2156 continue;
2157 },
2158
2159 State.CurlySuffixExpressionEnd => |opt_ctx| {
2160 const lhs = opt_ctx.get() ?? continue;
2161
2162 if ((??tok_it.peek()).id == Token.Id.Period) {
2163 const node = try arena.construct(ast.Node.SuffixOp {
2164 .base = ast.Node { .id = ast.Node.Id.SuffixOp },
2165 .lhs = lhs,
2166 .op = ast.Node.SuffixOp.Op {
2167 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2168 },
2169 .rtoken = undefined,
2170 });
2171 opt_ctx.store(&node.base);
2172
2173 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2174 try stack.push(State { .IfToken = Token.Id.LBrace });
2175 try stack.push(State {
2176 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {
2177 .list = &node.op.StructInitializer,
2178 .ptr = &node.rtoken,
2179 }
2180 });
2181 continue;
2182 }
2183
2184 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2185 ast.Node.SuffixOp {
2186 .base = undefined,
2187 .lhs = lhs,
2188 .op = ast.Node.SuffixOp.Op {
2189 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2190 },
2191 .rtoken = undefined,
2192 }
2193 );
2194 stack.push(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2195 try stack.push(State { .IfToken = Token.Id.LBrace });
2196 try stack.push(State {
2197 .ExprListItemOrEnd = ExprListCtx {
2198 .list = &node.op.ArrayInitializer,
2199 .end = Token.Id.RBrace,
2200 .ptr = &node.rtoken,
2201 }
2202 });
2203 continue;
2204 },
2205
2206 State.TypeExprBegin => |opt_ctx| {
2207 stack.push(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2208 try stack.push(State { .PrefixOpExpression = opt_ctx });
2209 continue;
2210 },
2211
2212 State.TypeExprEnd => |opt_ctx| {
2213 const lhs = opt_ctx.get() ?? continue;
2214
2215 if (eatToken(&tok_it, Token.Id.Bang)) |bang| {
2216 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2217 ast.Node.InfixOp {
2218 .base = undefined,
2219 .lhs = lhs,
2220 .op_token = bang,
2221 .op = ast.Node.InfixOp.Op.ErrorUnion,
2222 .rhs = undefined,
2223 }
2224 );
2225 stack.push(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2226 try stack.push(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2227 continue;
2228 }
2229 },
2230
2231 State.PrefixOpExpression => |opt_ctx| {
2232 const token_index = tok_it.index;
2233 const token_ptr = ??tok_it.next();
2234 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2235 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2236 ast.Node.PrefixOp {
2237 .base = undefined,
2238 .op_token = token_index,
2239 .op = prefix_id,
2240 .rhs = undefined,
2241 }
2242 );
2243
2244 // Treat '**' token as two derefs
2245 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2246 const child = try createNode(arena, ast.Node.PrefixOp,
2247 ast.Node.PrefixOp {
2248 .base = undefined,
2249 .op_token = token_index,
2250 .op = prefix_id,
2251 .rhs = undefined,
2252 }
2253 );
2254 node.rhs = &child.base;
2255 node = child;
2256 }
2257
2258 stack.push(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2259 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2260 try stack.push(State { .AddrOfModifiers = &node.op.AddrOf });
2261 }
2262 continue;
2263 } else {
2264 _ = tok_it.prev();
2265 stack.push(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2266 continue;
2267 }
2268 },
2269
2270 State.SuffixOpExpressionBegin => |opt_ctx| {
2271 if (eatToken(&tok_it, Token.Id.Keyword_async)) |async_token| {
2272 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
2273 ast.Node.AsyncAttribute {
2274 .base = undefined,
2275 .async_token = async_token,
2276 .allocator_type = null,
2277 .rangle_bracket = null,
2278 }
2279 );
2280 stack.push(State {
2281 .AsyncEnd = AsyncEndCtx {
2282 .ctx = opt_ctx,
2283 .attribute = async_node,
2284 }
2285 }) catch unreachable;
2286 try stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2287 try stack.push(State { .PrimaryExpression = opt_ctx.toRequired() });
2288 try stack.push(State { .AsyncAllocator = async_node });
2289 continue;
2290 }
2291
2292 stack.push(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2293 try stack.push(State { .PrimaryExpression = opt_ctx });
2294 continue;
2295 },
2296
2297 State.SuffixOpExpressionEnd => |opt_ctx| {
2298 const lhs = opt_ctx.get() ?? continue;
2299
2300 const token_index = tok_it.index;
2301 const token_ptr = ??tok_it.next();
2302 switch (token_ptr.id) {
2303 Token.Id.LParen => {
2304 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2305 ast.Node.SuffixOp {
2306 .base = undefined,
2307 .lhs = lhs,
2308 .op = ast.Node.SuffixOp.Op {
2309 .Call = ast.Node.SuffixOp.Op.Call {
2310 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2311 .async_attr = null,
2312 }
2313 },
2314 .rtoken = undefined,
2315 }
2316 );
2317 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2318 try stack.push(State {
2319 .ExprListItemOrEnd = ExprListCtx {
2320 .list = &node.op.Call.params,
2321 .end = Token.Id.RParen,
2322 .ptr = &node.rtoken,
2323 }
2324 });
2325 continue;
2326 },
2327 Token.Id.LBracket => {
2328 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2329 ast.Node.SuffixOp {
2330 .base = undefined,
2331 .lhs = lhs,
2332 .op = ast.Node.SuffixOp.Op {
2333 .ArrayAccess = undefined,
2334 },
2335 .rtoken = undefined
2336 }
2337 );
2338 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2339 try stack.push(State { .SliceOrArrayAccess = node });
2340 try stack.push(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2341 continue;
2342 },
2343 Token.Id.Period => {
2344 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2345 ast.Node.InfixOp {
2346 .base = undefined,
2347 .lhs = lhs,
2348 .op_token = token_index,
2349 .op = ast.Node.InfixOp.Op.Period,
2350 .rhs = undefined,
2351 }
2352 );
2353 stack.push(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2354 try stack.push(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2355 continue;
2356 },
2357 else => {
2358 _ = tok_it.prev();
2359 continue;
2360 },
2361 }
2362 },
2363
2364 State.PrimaryExpression => |opt_ctx| {
2365 const token_index = tok_it.index;
2366 const token_ptr = ??tok_it.next();
2367 switch (token_ptr.id) {
2368 Token.Id.IntegerLiteral => {
2369 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token_index);
2370 continue;
2371 },
2372 Token.Id.FloatLiteral => {
2373 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token_index);
2374 continue;
2375 },
2376 Token.Id.CharLiteral => {
2377 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token_index);
2378 continue;
2379 },
2380 Token.Id.Keyword_undefined => {
2381 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token_index);
2382 continue;
2383 },
2384 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2385 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token_index);
2386 continue;
2387 },
2388 Token.Id.Keyword_null => {
2389 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token_index);
2390 continue;
2391 },
2392 Token.Id.Keyword_this => {
2393 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token_index);
2394 continue;
2395 },
2396 Token.Id.Keyword_var => {
2397 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token_index);
2398 continue;
2399 },
2400 Token.Id.Keyword_unreachable => {
2401 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token_index);
2402 continue;
2403 },
2404 Token.Id.Keyword_promise => {
2405 const node = try arena.construct(ast.Node.PromiseType {
2406 .base = ast.Node {
2407 .id = ast.Node.Id.PromiseType,
2408 },
2409 .promise_token = token_index,
2410 .result = null,
2411 });
2412 opt_ctx.store(&node.base);
2413 const next_token_index = tok_it.index;
2414 const next_token_ptr = ??tok_it.next();
2415 if (next_token_ptr.id != Token.Id.Arrow) {
2416 _ = tok_it.prev();
2417 continue;
2418 }
2419 node.result = ast.Node.PromiseType.Result {
2420 .arrow_token = next_token_index,
2421 .return_type = undefined,
2422 };
2423 const return_type_ptr = &((??node.result).return_type);
2424 try stack.push(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2425 continue;
2426 },
2427 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2428 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index)) ?? unreachable);
2429 continue;
2430 },
2431 Token.Id.LParen => {
2432 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2433 ast.Node.GroupedExpression {
2434 .base = undefined,
2435 .lparen = token_index,
2436 .expr = undefined,
2437 .rparen = undefined,
2438 }
2439 );
2440 stack.push(State {
2441 .ExpectTokenSave = ExpectTokenSave {
2442 .id = Token.Id.RParen,
2443 .ptr = &node.rparen,
2444 }
2445 }) catch unreachable;
2446 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
2447 continue;
2448 },
2449 Token.Id.Builtin => {
2450 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2451 ast.Node.BuiltinCall {
2452 .base = undefined,
2453 .builtin_token = token_index,
2454 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2455 .rparen_token = undefined,
2456 }
2457 );
2458 stack.push(State {
2459 .ExprListItemOrEnd = ExprListCtx {
2460 .list = &node.params,
2461 .end = Token.Id.RParen,
2462 .ptr = &node.rparen_token,
2463 }
2464 }) catch unreachable;
2465 try stack.push(State { .ExpectToken = Token.Id.LParen, });
2466 continue;
2467 },
2468 Token.Id.LBracket => {
2469 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2470 ast.Node.PrefixOp {
2471 .base = undefined,
2472 .op_token = token_index,
2473 .op = undefined,
2474 .rhs = undefined,
2475 }
2476 );
2477 stack.push(State { .SliceOrArrayType = node }) catch unreachable;
2478 continue;
2479 },
2480 Token.Id.Keyword_error => {
2481 stack.push(State {
2482 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2483 .error_token = token_index,
2484 .opt_ctx = opt_ctx
2485 }
2486 }) catch unreachable;
2487 continue;
2488 },
2489 Token.Id.Keyword_packed => {
2490 stack.push(State {
2491 .ContainerKind = ContainerKindCtx {
2492 .opt_ctx = opt_ctx,
2493 .ltoken = token_index,
2494 .layout = ast.Node.ContainerDecl.Layout.Packed,
2495 },
2496 }) catch unreachable;
2497 continue;
2498 },
2499 Token.Id.Keyword_extern => {
2500 stack.push(State {
2501 .ExternType = ExternTypeCtx {
2502 .opt_ctx = opt_ctx,
2503 .extern_token = token_index,
2504 .comments = null,
2505 },
2506 }) catch unreachable;
2507 continue;
2508 },
2509 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2510 _ = tok_it.prev();
2511 stack.push(State {
2512 .ContainerKind = ContainerKindCtx {
2513 .opt_ctx = opt_ctx,
2514 .ltoken = token_index,
2515 .layout = ast.Node.ContainerDecl.Layout.Auto,
2516 },
2517 }) catch unreachable;
2518 continue;
2519 },
2520 Token.Id.Identifier => {
2521 stack.push(State {
2522 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2523 .label = token_index,
2524 .opt_ctx = opt_ctx
2525 }
2526 }) catch unreachable;
2527 continue;
2528 },
2529 Token.Id.Keyword_fn => {
2530 const fn_proto = try arena.construct(ast.Node.FnProto {
2531 .base = ast.Node {
2532 .id = ast.Node.Id.FnProto,
2533 },
2534 .doc_comments = null,
2535 .visib_token = null,
2536 .name_token = null,
2537 .fn_token = token_index,
2538 .params = ast.Node.FnProto.ParamList.init(arena),
2539 .return_type = undefined,
2540 .var_args_token = null,
2541 .extern_export_inline_token = null,
2542 .cc_token = null,
2543 .async_attr = null,
2544 .body_node = null,
2545 .lib_name = null,
2546 .align_expr = null,
2547 });
2548 opt_ctx.store(&fn_proto.base);
2549 stack.push(State { .FnProto = fn_proto }) catch unreachable;
2550 continue;
2551 },
2552 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2553 const fn_proto = try arena.construct(ast.Node.FnProto {
2554 .base = ast.Node {
2555 .id = ast.Node.Id.FnProto,
2556 },
2557 .doc_comments = null,
2558 .visib_token = null,
2559 .name_token = null,
2560 .fn_token = undefined,
2561 .params = ast.Node.FnProto.ParamList.init(arena),
2562 .return_type = undefined,
2563 .var_args_token = null,
2564 .extern_export_inline_token = null,
2565 .cc_token = token_index,
2566 .async_attr = null,
2567 .body_node = null,
2568 .lib_name = null,
2569 .align_expr = null,
2570 });
2571 opt_ctx.store(&fn_proto.base);
2572 stack.push(State { .FnProto = fn_proto }) catch unreachable;
2573 try stack.push(State {
2574 .ExpectTokenSave = ExpectTokenSave {
2575 .id = Token.Id.Keyword_fn,
2576 .ptr = &fn_proto.fn_token
2577 }
2578 });
2579 continue;
2580 },
2581 Token.Id.Keyword_asm => {
2582 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2583 ast.Node.Asm {
2584 .base = undefined,
2585 .asm_token = token_index,
2586 .volatile_token = null,
2587 .template = undefined,
2588 .outputs = ast.Node.Asm.OutputList.init(arena),
2589 .inputs = ast.Node.Asm.InputList.init(arena),
2590 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2591 .rparen = undefined,
2592 }
2593 );
2594 stack.push(State {
2595 .ExpectTokenSave = ExpectTokenSave {
2596 .id = Token.Id.RParen,
2597 .ptr = &node.rparen,
2598 }
2599 }) catch unreachable;
2600 try stack.push(State { .AsmClobberItems = &node.clobbers });
2601 try stack.push(State { .IfToken = Token.Id.Colon });
2602 try stack.push(State { .AsmInputItems = &node.inputs });
2603 try stack.push(State { .IfToken = Token.Id.Colon });
2604 try stack.push(State { .AsmOutputItems = &node.outputs });
2605 try stack.push(State { .IfToken = Token.Id.Colon });
2606 try stack.push(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2607 try stack.push(State { .ExpectToken = Token.Id.LParen });
2608 try stack.push(State {
2609 .OptionalTokenSave = OptionalTokenSave {
2610 .id = Token.Id.Keyword_volatile,
2611 .ptr = &node.volatile_token,
2612 }
2613 });
2614 },
2615 Token.Id.Keyword_inline => {
2616 stack.push(State {
2617 .Inline = InlineCtx {
2618 .label = null,
2619 .inline_token = token_index,
2620 .opt_ctx = opt_ctx,
2621 }
2622 }) catch unreachable;
2623 continue;
2624 },
2625 else => {
2626 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
2627 _ = tok_it.prev();
2628 if (opt_ctx != OptionalCtx.Optional) {
2629 *(try tree.errors.addOne()) = Error {
2630 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2631 };
2632 return tree;
2633 }
2634 }
2635 continue;
2636 }
2637 }
2638 },
2639
2640
2641 State.ErrorTypeOrSetDecl => |ctx| {
2642 if (eatToken(&tok_it, Token.Id.LBrace) == null) {
2643 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2644 continue;
2645 }
2646
2647 const node = try arena.construct(ast.Node.ErrorSetDecl {
2648 .base = ast.Node {
2649 .id = ast.Node.Id.ErrorSetDecl,
2650 },
2651 .error_token = ctx.error_token,
2652 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2653 .rbrace_token = undefined,
2654 });
2655 ctx.opt_ctx.store(&node.base);
2656
2657 stack.push(State {
2658 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {
2659 .list = &node.decls,
2660 .ptr = &node.rbrace_token,
2661 }
2662 }) catch unreachable;
2663 continue;
2664 },
2665 State.StringLiteral => |opt_ctx| {
2666 const token_index = tok_it.index;
2667 const token_ptr = ??tok_it.next();
2668 opt_ctx.store(
2669 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index)) ?? {
2670 _ = tok_it.prev();
2671 if (opt_ctx != OptionalCtx.Optional) {
2672 *(try tree.errors.addOne()) = Error {
2673 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2674 };
2675 return tree;
2676 }
2677
2678 continue;
2679 }
2680 );
2681 },
2682
2683 State.Identifier => |opt_ctx| {
2684 if (eatToken(&tok_it, Token.Id.Identifier)) |ident_token| {
2685 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2686 continue;
2687 }
2688
2689 if (opt_ctx != OptionalCtx.Optional) {
2690 const token_index = tok_it.index;
2691 const token_ptr = ??tok_it.next();
2692 *(try tree.errors.addOne()) = Error {
2693 .ExpectedToken = Error.ExpectedToken {
2694 .token = token_index,
2695 .expected_id = Token.Id.Identifier,
2696 },
2697 };
2698 return tree;
2699 }
2700 },
2701
2702 State.ErrorTag => |node_ptr| {
2703 const comments = try eatDocComments(arena, &tok_it);
2704 const ident_token_index = tok_it.index;
2705 const ident_token_ptr = ??tok_it.next();
2706 if (ident_token_ptr.id != Token.Id.Identifier) {
2707 *(try tree.errors.addOne()) = Error {
2708 .ExpectedToken = Error.ExpectedToken {
2709 .token = ident_token_index,
2710 .expected_id = Token.Id.Identifier,
2711 },
2712 };
2713 return tree;
2714 }
2715
2716 const node = try arena.construct(ast.Node.ErrorTag {
2717 .base = ast.Node {
2718 .id = ast.Node.Id.ErrorTag,
2719 },
2720 .doc_comments = comments,
2721 .name_token = ident_token_index,
2722 });
2723 *node_ptr = &node.base;
2724 continue;
2725 },
2726
2727 State.ExpectToken => |token_id| {
2728 const token_index = tok_it.index;
2729 const token_ptr = ??tok_it.next();
2730 if (token_ptr.id != token_id) {
2731 *(try tree.errors.addOne()) = Error {
2732 .ExpectedToken = Error.ExpectedToken {
2733 .token = token_index,
2734 .expected_id = token_id,
2735 },
2736 };
2737 return tree;
2738 }
2739 continue;
2740 },
2741 State.ExpectTokenSave => |expect_token_save| {
2742 const token_index = tok_it.index;
2743 const token_ptr = ??tok_it.next();
2744 if (token_ptr.id != expect_token_save.id) {
2745 *(try tree.errors.addOne()) = Error {
2746 .ExpectedToken = Error.ExpectedToken {
2747 .token = token_index,
2748 .expected_id = expect_token_save.id,
2749 },
2750 };
2751 return tree;
2752 }
2753 *expect_token_save.ptr = token_index;
2754 continue;
2755 },
2756 State.IfToken => |token_id| {
2757 if (eatToken(&tok_it, token_id)) |_| {
2758 continue;
2759 }
2760
2761 _ = stack.pop();
2762 continue;
2763 },
2764 State.IfTokenSave => |if_token_save| {
2765 if (eatToken(&tok_it, if_token_save.id)) |token_index| {
2766 *if_token_save.ptr = token_index;
2767 continue;
2768 }
2769
2770 _ = stack.pop();
2771 continue;
2772 },
2773 State.OptionalTokenSave => |optional_token_save| {
2774 if (eatToken(&tok_it, optional_token_save.id)) |token_index| {
2775 *optional_token_save.ptr = token_index;
2776 continue;
2777 }
2778
2779 continue;
2780 },
2781 }
2782 }
2783}
2784
2785const AnnotatedToken = struct {
2786 ptr: &Token,
2787 index: TokenIndex,
2788};
2789
2790const TopLevelDeclCtx = struct {
2791 decls: &ast.Node.Root.DeclList,
2792 visib_token: ?TokenIndex,
2793 extern_export_inline_token: ?AnnotatedToken,
2794 lib_name: ?&ast.Node,
2795 comments: ?&ast.Node.DocComment,
2796};
2797
2798const VarDeclCtx = struct {
2799 mut_token: TokenIndex,
2800 visib_token: ?TokenIndex,
2801 comptime_token: ?TokenIndex,
2802 extern_export_token: ?TokenIndex,
2803 lib_name: ?&ast.Node,
2804 list: &ast.Node.Root.DeclList,
2805 comments: ?&ast.Node.DocComment,
2806};
2807
2808const TopLevelExternOrFieldCtx = struct {
2809 visib_token: TokenIndex,
2810 container_decl: &ast.Node.ContainerDecl,
2811 comments: ?&ast.Node.DocComment,
2812};
2813
2814const ExternTypeCtx = struct {
2815 opt_ctx: OptionalCtx,
2816 extern_token: TokenIndex,
2817 comments: ?&ast.Node.DocComment,
2818};
2819
2820const ContainerKindCtx = struct {
2821 opt_ctx: OptionalCtx,
2822 ltoken: TokenIndex,
2823 layout: ast.Node.ContainerDecl.Layout,
2824};
2825
2826const ExpectTokenSave = struct {
2827 id: @TagType(Token.Id),
2828 ptr: &TokenIndex,
2829};
2830
2831const OptionalTokenSave = struct {
2832 id: @TagType(Token.Id),
2833 ptr: &?TokenIndex,
2834};
2835
2836const ExprListCtx = struct {
2837 list: &ast.Node.SuffixOp.Op.InitList,
2838 end: Token.Id,
2839 ptr: &TokenIndex,
2840};
2841
2842fn ListSave(comptime List: type) type {
2843 return struct {
2844 list: &List,
2845 ptr: &TokenIndex,
2846 };
2847}
2848
2849const MaybeLabeledExpressionCtx = struct {
2850 label: TokenIndex,
2851 opt_ctx: OptionalCtx,
2852};
2853
2854const LabelCtx = struct {
2855 label: ?TokenIndex,
2856 opt_ctx: OptionalCtx,
2857};
2858
2859const InlineCtx = struct {
2860 label: ?TokenIndex,
2861 inline_token: ?TokenIndex,
2862 opt_ctx: OptionalCtx,
2863};
2864
2865const LoopCtx = struct {
2866 label: ?TokenIndex,
2867 inline_token: ?TokenIndex,
2868 loop_token: TokenIndex,
2869 opt_ctx: OptionalCtx,
2870};
2871
2872const AsyncEndCtx = struct {
2873 ctx: OptionalCtx,
2874 attribute: &ast.Node.AsyncAttribute,
2875};
2876
2877const ErrorTypeOrSetDeclCtx = struct {
2878 opt_ctx: OptionalCtx,
2879 error_token: TokenIndex,
2880};
2881
2882const ParamDeclEndCtx = struct {
2883 fn_proto: &ast.Node.FnProto,
2884 param_decl: &ast.Node.ParamDecl,
2885};
2886
2887const ComptimeStatementCtx = struct {
2888 comptime_token: TokenIndex,
2889 block: &ast.Node.Block,
2890};
2891
2892const OptionalCtx = union(enum) {
2893 Optional: &?&ast.Node,
2894 RequiredNull: &?&ast.Node,
2895 Required: &&ast.Node,
2896
2897 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2898 switch (*self) {
2899 OptionalCtx.Optional => |ptr| *ptr = value,
2900 OptionalCtx.RequiredNull => |ptr| *ptr = value,
2901 OptionalCtx.Required => |ptr| *ptr = value,
2902 }
2903 }
2904
2905 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2906 switch (*self) {
2907 OptionalCtx.Optional => |ptr| return *ptr,
2908 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
2909 OptionalCtx.Required => |ptr| return *ptr,
2910 }
2911 }
2912
2913 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2914 switch (*self) {
2915 OptionalCtx.Optional => |ptr| {
2916 return OptionalCtx { .RequiredNull = ptr };
2917 },
2918 OptionalCtx.RequiredNull => |ptr| return *self,
2919 OptionalCtx.Required => |ptr| return *self,
2920 }
2921 }
2922};
2923
2924const AddCommentsCtx = struct {
2925 node_ptr: &&ast.Node,
2926 comments: ?&ast.Node.DocComment,
2927};
2928
2929const State = union(enum) {
2930 TopLevel,
2931 TopLevelExtern: TopLevelDeclCtx,
2932 TopLevelLibname: TopLevelDeclCtx,
2933 TopLevelDecl: TopLevelDeclCtx,
2934 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2935
2936 ContainerKind: ContainerKindCtx,
2937 ContainerInitArgStart: &ast.Node.ContainerDecl,
2938 ContainerInitArg: &ast.Node.ContainerDecl,
2939 ContainerDecl: &ast.Node.ContainerDecl,
2940
2941 VarDecl: VarDeclCtx,
2942 VarDeclAlign: &ast.Node.VarDecl,
2943 VarDeclEq: &ast.Node.VarDecl,
2944
2945 FnDef: &ast.Node.FnProto,
2946 FnProto: &ast.Node.FnProto,
2947 FnProtoAlign: &ast.Node.FnProto,
2948 FnProtoReturnType: &ast.Node.FnProto,
2949
2950 ParamDecl: &ast.Node.FnProto,
2951 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
2952 ParamDeclName: &ast.Node.ParamDecl,
2953 ParamDeclEnd: ParamDeclEndCtx,
2954 ParamDeclComma: &ast.Node.FnProto,
2955
2956 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2957 LabeledExpression: LabelCtx,
2958 Inline: InlineCtx,
2959 While: LoopCtx,
2960 WhileContinueExpr: &?&ast.Node,
2961 For: LoopCtx,
2962 Else: &?&ast.Node.Else,
2963
2964 Block: &ast.Node.Block,
2965 Statement: &ast.Node.Block,
2966 ComptimeStatement: ComptimeStatementCtx,
2967 Semicolon: &&ast.Node,
2968
2969 AsmOutputItems: &ast.Node.Asm.OutputList,
2970 AsmOutputReturnOrType: &ast.Node.AsmOutput,
2971 AsmInputItems: &ast.Node.Asm.InputList,
2972 AsmClobberItems: &ast.Node.Asm.ClobberList,
2973
2974 ExprListItemOrEnd: ExprListCtx,
2975 ExprListCommaOrEnd: ExprListCtx,
2976 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2977 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2978 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
2979 FieldInitValue: OptionalCtx,
2980 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2981 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2982 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
2983 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
2984 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
2985 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
2986 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
2987
2988 SuspendBody: &ast.Node.Suspend,
2989 AsyncAllocator: &ast.Node.AsyncAttribute,
2990 AsyncEnd: AsyncEndCtx,
2991
2992 ExternType: ExternTypeCtx,
2993 SliceOrArrayAccess: &ast.Node.SuffixOp,
2994 SliceOrArrayType: &ast.Node.PrefixOp,
2995 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
2996
2997 Payload: OptionalCtx,
2998 PointerPayload: OptionalCtx,
2999 PointerIndexPayload: OptionalCtx,
3000
3001 Expression: OptionalCtx,
3002 RangeExpressionBegin: OptionalCtx,
3003 RangeExpressionEnd: OptionalCtx,
3004 AssignmentExpressionBegin: OptionalCtx,
3005 AssignmentExpressionEnd: OptionalCtx,
3006 UnwrapExpressionBegin: OptionalCtx,
3007 UnwrapExpressionEnd: OptionalCtx,
3008 BoolOrExpressionBegin: OptionalCtx,
3009 BoolOrExpressionEnd: OptionalCtx,
3010 BoolAndExpressionBegin: OptionalCtx,
3011 BoolAndExpressionEnd: OptionalCtx,
3012 ComparisonExpressionBegin: OptionalCtx,
3013 ComparisonExpressionEnd: OptionalCtx,
3014 BinaryOrExpressionBegin: OptionalCtx,
3015 BinaryOrExpressionEnd: OptionalCtx,
3016 BinaryXorExpressionBegin: OptionalCtx,
3017 BinaryXorExpressionEnd: OptionalCtx,
3018 BinaryAndExpressionBegin: OptionalCtx,
3019 BinaryAndExpressionEnd: OptionalCtx,
3020 BitShiftExpressionBegin: OptionalCtx,
3021 BitShiftExpressionEnd: OptionalCtx,
3022 AdditionExpressionBegin: OptionalCtx,
3023 AdditionExpressionEnd: OptionalCtx,
3024 MultiplyExpressionBegin: OptionalCtx,
3025 MultiplyExpressionEnd: OptionalCtx,
3026 CurlySuffixExpressionBegin: OptionalCtx,
3027 CurlySuffixExpressionEnd: OptionalCtx,
3028 TypeExprBegin: OptionalCtx,
3029 TypeExprEnd: OptionalCtx,
3030 PrefixOpExpression: OptionalCtx,
3031 SuffixOpExpressionBegin: OptionalCtx,
3032 SuffixOpExpressionEnd: OptionalCtx,
3033 PrimaryExpression: OptionalCtx,
3034
3035 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3036 StringLiteral: OptionalCtx,
3037 Identifier: OptionalCtx,
3038 ErrorTag: &&ast.Node,
3039
3040
3041 IfToken: @TagType(Token.Id),
3042 IfTokenSave: ExpectTokenSave,
3043 ExpectToken: @TagType(Token.Id),
3044 ExpectTokenSave: ExpectTokenSave,
3045 OptionalTokenSave: OptionalTokenSave,
3046};
3047
3048fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator) !?&ast.Node.DocComment {
3049 var result: ?&ast.Node.DocComment = null;
3050 while (true) {
3051 if (eatToken(tok_it, Token.Id.DocComment)) |line_comment| {
3052 const node = blk: {
3053 if (result) |comment_node| {
3054 break :blk comment_node;
3055 } else {
3056 const comment_node = try arena.construct(ast.Node.DocComment {
3057 .base = ast.Node {
3058 .id = ast.Node.Id.DocComment,
3059 },
3060 .lines = ast.Node.DocComment.LineList.init(arena),
3061 });
3062 result = comment_node;
3063 break :blk comment_node;
3064 }
3065 };
3066 try node.lines.push(line_comment);
3067 continue;
3068 }
3069 break;
3070 }
3071 return result;
3072}
3073
3074fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator) !?&ast.Node.LineComment {
3075 const token = eatToken(tok_it, Token.Id.LineComment) ?? return null;
3076 return try arena.construct(ast.Node.LineComment {
3077 .base = ast.Node {
3078 .id = ast.Node.Id.LineComment,
3079 },
3080 .token = token,
3081 });
3082}
3083
3084fn requireSemiColon(node: &const ast.Node) bool {
3085 var n = node;
3086 while (true) {
3087 switch (n.id) {
3088 ast.Node.Id.Root,
3089 ast.Node.Id.StructField,
3090 ast.Node.Id.UnionTag,
3091 ast.Node.Id.EnumTag,
3092 ast.Node.Id.ParamDecl,
3093 ast.Node.Id.Block,
3094 ast.Node.Id.Payload,
3095 ast.Node.Id.PointerPayload,
3096 ast.Node.Id.PointerIndexPayload,
3097 ast.Node.Id.Switch,
3098 ast.Node.Id.SwitchCase,
3099 ast.Node.Id.SwitchElse,
3100 ast.Node.Id.FieldInitializer,
3101 ast.Node.Id.DocComment,
3102 ast.Node.Id.LineComment,
3103 ast.Node.Id.TestDecl => return false,
3104 ast.Node.Id.While => {
3105 const while_node = @fieldParentPtr(ast.Node.While, "base", n);
3106 if (while_node.@"else") |@"else"| {
3107 n = @"else".base;
3108 continue;
3109 }
3110
3111 return while_node.body.id != ast.Node.Id.Block;
3112 },
3113 ast.Node.Id.For => {
3114 const for_node = @fieldParentPtr(ast.Node.For, "base", n);
3115 if (for_node.@"else") |@"else"| {
3116 n = @"else".base;
3117 continue;
3118 }
3119
3120 return for_node.body.id != ast.Node.Id.Block;
3121 },
3122 ast.Node.Id.If => {
3123 const if_node = @fieldParentPtr(ast.Node.If, "base", n);
3124 if (if_node.@"else") |@"else"| {
3125 n = @"else".base;
3126 continue;
3127 }
3128
3129 return if_node.body.id != ast.Node.Id.Block;
3130 },
3131 ast.Node.Id.Else => {
3132 const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
3133 n = else_node.body;
3134 continue;
3135 },
3136 ast.Node.Id.Defer => {
3137 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
3138 return defer_node.expr.id != ast.Node.Id.Block;
3139 },
3140 ast.Node.Id.Comptime => {
3141 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
3142 return comptime_node.expr.id != ast.Node.Id.Block;
3143 },
3144 ast.Node.Id.Suspend => {
3145 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
3146 if (suspend_node.body) |body| {
3147 return body.id != ast.Node.Id.Block;
3148 }
3149
3150 return true;
3151 },
3152 else => return true,
3153 }
3154 }
3155}
3156
3157fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3158 token_ptr: &const Token, token_index: TokenIndex) !?&ast.Node
3159{
3160 switch (token_ptr.id) {
3161 Token.Id.StringLiteral => {
3162 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3163 },
3164 Token.Id.MultilineStringLiteralLine => {
3165 const node = try arena.construct(ast.Node.MultilineStringLiteral {
3166 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },
3167 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3168 });
3169 try node.lines.push(token_index);
3170 while (true) {
3171 const multiline_str_index = tok_it.index;
3172 const multiline_str_ptr = ??tok_it.next();
3173 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3174 _ = tok_it.prev();
3175 break;
3176 }
3177
3178 try node.lines.push(multiline_str_index);
3179 }
3180
3181 return &node.base;
3182 },
3183 // TODO: We shouldn't need a cast, but:
3184 // 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.
3185 else => return (?&ast.Node)(null),
3186 }
3187}
3188
3189fn parseBlockExpr(stack: &SegmentedList(State, 32), arena: &mem.Allocator, ctx: &const OptionalCtx,
3190 token_ptr: &const Token, token_index: TokenIndex) !bool {
3191 switch (token_ptr.id) {
3192 Token.Id.Keyword_suspend => {
3193 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,
3194 ast.Node.Suspend {
3195 .base = undefined,
3196 .label = null,
3197 .suspend_token = token_index,
3198 .payload = null,
3199 .body = null,
3200 }
3201 );
3202
3203 stack.push(State { .SuspendBody = node }) catch unreachable;
3204 try stack.push(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3205 return true;
3206 },
3207 Token.Id.Keyword_if => {
3208 const node = try createToCtxNode(arena, ctx, ast.Node.If,
3209 ast.Node.If {
3210 .base = undefined,
3211 .if_token = token_index,
3212 .condition = undefined,
3213 .payload = null,
3214 .body = undefined,
3215 .@"else" = null,
3216 }
3217 );
3218
3219 stack.push(State { .Else = &node.@"else" }) catch unreachable;
3220 try stack.push(State { .Expression = OptionalCtx { .Required = &node.body } });
3221 try stack.push(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3222 try stack.push(State { .ExpectToken = Token.Id.RParen });
3223 try stack.push(State { .Expression = OptionalCtx { .Required = &node.condition } });
3224 try stack.push(State { .ExpectToken = Token.Id.LParen });
3225 return true;
3226 },
3227 Token.Id.Keyword_while => {
3228 stack.push(State {
3229 .While = LoopCtx {
3230 .label = null,
3231 .inline_token = null,
3232 .loop_token = token_index,
3233 .opt_ctx = *ctx,
3234 }
3235 }) catch unreachable;
3236 return true;
3237 },
3238 Token.Id.Keyword_for => {
3239 stack.push(State {
3240 .For = LoopCtx {
3241 .label = null,
3242 .inline_token = null,
3243 .loop_token = token_index,
3244 .opt_ctx = *ctx,
3245 }
3246 }) catch unreachable;
3247 return true;
3248 },
3249 Token.Id.Keyword_switch => {
3250 const node = try arena.construct(ast.Node.Switch {
3251 .base = ast.Node {
3252 .id = ast.Node.Id.Switch,
3253 },
3254 .switch_token = token_index,
3255 .expr = undefined,
3256 .cases = ast.Node.Switch.CaseList.init(arena),
3257 .rbrace = undefined,
3258 });
3259 ctx.store(&node.base);
3260
3261 stack.push(State {
3262 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {
3263 .list = &node.cases,
3264 .ptr = &node.rbrace,
3265 },
3266 }) catch unreachable;
3267 try stack.push(State { .ExpectToken = Token.Id.LBrace });
3268 try stack.push(State { .ExpectToken = Token.Id.RParen });
3269 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
3270 try stack.push(State { .ExpectToken = Token.Id.LParen });
3271 return true;
3272 },
3273 Token.Id.Keyword_comptime => {
3274 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,
3275 ast.Node.Comptime {
3276 .base = undefined,
3277 .comptime_token = token_index,
3278 .expr = undefined,
3279 .doc_comments = null,
3280 }
3281 );
3282 try stack.push(State { .Expression = OptionalCtx { .Required = &node.expr } });
3283 return true;
3284 },
3285 Token.Id.LBrace => {
3286 const block = try arena.construct(ast.Node.Block {
3287 .base = ast.Node {.id = ast.Node.Id.Block },
3288 .label = null,
3289 .lbrace = token_index,
3290 .statements = ast.Node.Block.StatementList.init(arena),
3291 .rbrace = undefined,
3292 });
3293 ctx.store(&block.base);
3294 stack.push(State { .Block = block }) catch unreachable;
3295 return true;
3296 },
3297 else => {
3298 return false;
3299 }
3300 }
3301}
3302
3303const ExpectCommaOrEndResult = union(enum) {
3304 end_token: ?TokenIndex,
3305 parse_error: Error,
3306};
3307
3308fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3309 const token_index = tok_it.index;
3310 const token_ptr = ??tok_it.next();
3311 switch (token_ptr.id) {
3312 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},
3313 else => {
3314 if (end == token_ptr.id) {
3315 return ExpectCommaOrEndResult { .end_token = token_index };
3316 }
3317
3318 return ExpectCommaOrEndResult {
3319 .parse_error = Error {
3320 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {
3321 .token = token_index,
3322 .end_id = end,
3323 },
3324 },
3325 };
3326 },
3327 }
3328}
3329
3330fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3331 // TODO: We have to cast all cases because of this:
3332 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3333 return switch (*id) {
3334 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },
3335 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },
3336 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },
3337 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },
3338 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },
3339 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },
3340 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },
3341 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },
3342 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },
3343 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },
3344 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },
3345 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },
3346 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },
3347 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },
3348 else => null,
3349 };
3350}
3351
3352fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3353 return switch (id) {
3354 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3355 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3356 else => null,
3357 };
3358}
3359
3360fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3361 return switch (id) {
3362 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3363 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3364 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3365 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3366 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3367 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3368 else => null,
3369 };
3370}
3371
3372fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3373 return switch (id) {
3374 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3375 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3376 else => null,
3377 };
3378}
3379
3380fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3381 return switch (id) {
3382 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3383 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3384 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3385 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3386 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3387 else => null,
3388 };
3389}
3390
3391fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3392 return switch (id) {
3393 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3394 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3395 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3396 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3397 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3398 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3399 else => null,
3400 };
3401}
3402
3403fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3404 return switch (id) {
3405 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3406 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3407 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3408 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3409 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3410 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3411 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3412 .align_expr = null,
3413 .bit_offset_start_token = null,
3414 .bit_offset_end_token = null,
3415 .const_token = null,
3416 .volatile_token = null,
3417 },
3418 },
3419 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3420 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3421 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3422 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3423 else => null,
3424 };
3425}
3426
3427fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3428 const node = try arena.create(T);
3429 *node = *init_to;
3430 node.base = blk: {
3431 const id = ast.Node.typeToId(T);
3432 break :blk ast.Node {
3433 .id = id,
3434 };
3435 };
3436
3437 return node;
3438}
3439
3440fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3441 const node = try createNode(arena, T, init_to);
3442 opt_ctx.store(&node.base);
3443
3444 return node;
3445}
3446
3447fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3448 return createNode(arena, T,
3449 T {
3450 .base = undefined,
3451 .token = token_index,
3452 }
3453 );
3454}
3455
3456fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
3457 const node = try createLiteral(arena, T, token_index);
3458 opt_ctx.store(&node.base);
3459
3460 return node;
3461}
3462
3463fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, id: @TagType(Token.Id)) ?TokenIndex {
3464 const token_index = tok_it.index;
3465 const token_ptr = ??tok_it.next();
3466 if (token_ptr.id == id)
3467 return token_index;
3468
3469 _ = tok_it.prev();
3470 return null;
3471}
3472
3473const RenderAstFrame = struct {
3474 node: &ast.Node,
3475 indent: usize,
3476};
3477
3478pub fn renderAst(allocator: &mem.Allocator, tree: &const ast.Tree, stream: var) !void {
3479 var stack = SegmentedList(State, 32).init(allocator);
3480 defer stack.deinit();
3481
3482 try stack.push(RenderAstFrame {
3483 .node = &root_node.base,
3484 .indent = 0,
3485 });
3486
3487 while (stack.popOrNull()) |frame| {
3488 {
3489 var i: usize = 0;
3490 while (i < frame.indent) : (i += 1) {
3491 try stream.print(" ");
3492 }
3493 }
3494 try stream.print("{}\n", @tagName(frame.node.id));
3495 var child_i: usize = 0;
3496 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3497 try stack.push(RenderAstFrame {
3498 .node = child,
3499 .indent = frame.indent + 2,
3500 });
3501 }
3502 }
3503}
3504
3505const RenderState = union(enum) {
3506 TopLevelDecl: &ast.Node,
3507 ParamDecl: &ast.Node,
3508 Text: []const u8,
3509 Expression: &ast.Node,
3510 VarDecl: &ast.Node.VarDecl,
3511 Statement: &ast.Node,
3512 PrintIndent,
3513 Indent: usize,
3514};
3515
3516pub fn renderSource(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {
3517 var stack = SegmentedList(RenderState, 32).init(allocator);
3518 defer stack.deinit();
3519
3520 {
3521 try stack.push(RenderState { .Text = "\n"});
3522
3523 var i = tree.root_node.decls.len;
3524 while (i != 0) {
3525 i -= 1;
3526 const decl = *tree.root_node.decls.at(i);
3527 try stack.push(RenderState {.TopLevelDecl = decl});
3528 if (i != 0) {
3529 try stack.push(RenderState {
3530 .Text = blk: {
3531 const prev_node = *tree.root_node.decls.at(i - 1);
3532 const prev_node_last_token = tree.tokens.at(prev_node.lastToken());
3533 const loc = tree.tokenLocation(prev_node_last_token.end, decl.firstToken());
3534 if (loc.line >= 2) {
3535 break :blk "\n\n";
3536 }
3537 break :blk "\n";
3538 },
3539 });
3540 }
3541 }
3542 }
3543
3544 const indent_delta = 4;
3545 var indent: usize = 0;
3546 while (stack.pop()) |state| {
3547 switch (state) {
3548 RenderState.TopLevelDecl => |decl| {
3549 switch (decl.id) {
3550 ast.Node.Id.FnProto => {
3551 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3552 try renderComments(tree, stream, fn_proto, indent);
3553
3554 if (fn_proto.body_node) |body_node| {
3555 stack.push(RenderState { .Expression = body_node}) catch unreachable;
3556 try stack.push(RenderState { .Text = " "});
3557 } else {
3558 stack.push(RenderState { .Text = ";" }) catch unreachable;
3559 }
3560
3561 try stack.push(RenderState { .Expression = decl });
3562 },
3563 ast.Node.Id.Use => {
3564 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
3565 if (use_decl.visib_token) |visib_token| {
3566 try stream.print("{} ", tree.tokenSlice(visib_token));
3567 }
3568 try stream.print("use ");
3569 try stack.push(RenderState { .Text = ";" });
3570 try stack.push(RenderState { .Expression = use_decl.expr });
3571 },
3572 ast.Node.Id.VarDecl => {
3573 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
3574 try renderComments(tree, stream, var_decl, indent);
3575 try stack.push(RenderState { .VarDecl = var_decl});
3576 },
3577 ast.Node.Id.TestDecl => {
3578 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3579 try renderComments(tree, stream, test_decl, indent);
3580 try stream.print("test ");
3581 try stack.push(RenderState { .Expression = test_decl.body_node });
3582 try stack.push(RenderState { .Text = " " });
3583 try stack.push(RenderState { .Expression = test_decl.name });
3584 },
3585 ast.Node.Id.StructField => {
3586 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
3587 try renderComments(tree, stream, field, indent);
3588 if (field.visib_token) |visib_token| {
3589 try stream.print("{} ", tree.tokenSlice(visib_token));
3590 }
3591 try stream.print("{}: ", tree.tokenSlice(field.name_token));
3592 try stack.push(RenderState { .Text = "," });
3593 try stack.push(RenderState { .Expression = field.type_expr});
3594 },
3595 ast.Node.Id.UnionTag => {
3596 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
3597 try renderComments(tree, stream, tag, indent);
3598 try stream.print("{}", tree.tokenSlice(tag.name_token));
3599
3600 try stack.push(RenderState { .Text = "," });
3601
3602 if (tag.value_expr) |value_expr| {
3603 try stack.push(RenderState { .Expression = value_expr });
3604 try stack.push(RenderState { .Text = " = " });
3605 }
3606
3607 if (tag.type_expr) |type_expr| {
3608 try stream.print(": ");
3609 try stack.push(RenderState { .Expression = type_expr});
3610 }
3611 },
3612 ast.Node.Id.EnumTag => {
3613 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
3614 try renderComments(tree, stream, tag, indent);
3615 try stream.print("{}", tree.tokenSlice(tag.name_token));
3616
3617 try stack.push(RenderState { .Text = "," });
3618 if (tag.value) |value| {
3619 try stream.print(" = ");
3620 try stack.push(RenderState { .Expression = value});
3621 }
3622 },
3623 ast.Node.Id.ErrorTag => {
3624 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
3625 try renderComments(tree, stream, tag, indent);
3626 try stream.print("{}", tree.tokenSlice(tag.name_token));
3627 },
3628 ast.Node.Id.Comptime => {
3629 if (requireSemiColon(decl)) {
3630 try stack.push(RenderState { .Text = ";" });
3631 }
3632 try stack.push(RenderState { .Expression = decl });
3633 },
3634 ast.Node.Id.LineComment => {
3635 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
3636 try stream.write(tree.tokenSlice(line_comment_node.token));
3637 },
3638 else => unreachable,
3639 }
3640 },
3641
3642 RenderState.VarDecl => |var_decl| {
3643 try stack.push(RenderState { .Text = ";" });
3644 if (var_decl.init_node) |init_node| {
3645 try stack.push(RenderState { .Expression = init_node });
3646 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
3647 try stack.push(RenderState { .Text = text });
3648 }
3649 if (var_decl.align_node) |align_node| {
3650 try stack.push(RenderState { .Text = ")" });
3651 try stack.push(RenderState { .Expression = align_node });
3652 try stack.push(RenderState { .Text = " align(" });
3653 }
3654 if (var_decl.type_node) |type_node| {
3655 try stack.push(RenderState { .Expression = type_node });
3656 try stack.push(RenderState { .Text = ": " });
3657 }
3658 try stack.push(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
3659 try stack.push(RenderState { .Text = " " });
3660 try stack.push(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
3661
3662 if (var_decl.comptime_token) |comptime_token| {
3663 try stack.push(RenderState { .Text = " " });
3664 try stack.push(RenderState { .Text = tree.tokenSlice(comptime_token) });
3665 }
3666
3667 if (var_decl.extern_export_token) |extern_export_token| {
3668 if (var_decl.lib_name != null) {
3669 try stack.push(RenderState { .Text = " " });
3670 try stack.push(RenderState { .Expression = ??var_decl.lib_name });
3671 }
3672 try stack.push(RenderState { .Text = " " });
3673 try stack.push(RenderState { .Text = tree.tokenSlice(extern_export_token) });
3674 }
3675
3676 if (var_decl.visib_token) |visib_token| {
3677 try stack.push(RenderState { .Text = " " });
3678 try stack.push(RenderState { .Text = tree.tokenSlice(visib_token) });
3679 }
3680 },
3681
3682 RenderState.ParamDecl => |base| {
3683 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
3684 if (param_decl.comptime_token) |comptime_token| {
3685 try stream.print("{} ", tree.tokenSlice(comptime_token));
3686 }
3687 if (param_decl.noalias_token) |noalias_token| {
3688 try stream.print("{} ", tree.tokenSlice(noalias_token));
3689 }
3690 if (param_decl.name_token) |name_token| {
3691 try stream.print("{}: ", tree.tokenSlice(name_token));
3692 }
3693 if (param_decl.var_args_token) |var_args_token| {
3694 try stream.print("{}", tree.tokenSlice(var_args_token));
3695 } else {
3696 try stack.push(RenderState { .Expression = param_decl.type_node});
3697 }
3698 },
3699 RenderState.Text => |bytes| {
3700 try stream.write(bytes);
3701 },
3702 RenderState.Expression => |base| switch (base.id) {
3703 ast.Node.Id.Identifier => {
3704 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
3705 try stream.print("{}", tree.tokenSlice(identifier.token));
3706 },
3707 ast.Node.Id.Block => {
3708 const block = @fieldParentPtr(ast.Node.Block, "base", base);
3709 if (block.label) |label| {
3710 try stream.print("{}: ", tree.tokenSlice(label));
3711 }
3712
3713 if (block.statements.len == 0) {
3714 try stream.write("{}");
3715 } else {
3716 try stream.write("{");
3717 try stack.push(RenderState { .Text = "}"});
3718 try stack.push(RenderState.PrintIndent);
3719 try stack.push(RenderState { .Indent = indent});
3720 try stack.push(RenderState { .Text = "\n"});
3721 var i = block.statements.len;
3722 while (i != 0) {
3723 i -= 1;
3724 const statement_node = *block.statements.at(i);
3725 try stack.push(RenderState { .Statement = statement_node});
3726 try stack.push(RenderState.PrintIndent);
3727 try stack.push(RenderState { .Indent = indent + indent_delta});
3728 try stack.push(RenderState {
3729 .Text = blk: {
3730 if (i != 0) {
3731 const prev_node = *block.statements.at(i - 1);
3732 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
3733 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());
3734 if (loc.line >= 2) {
3735 break :blk "\n\n";
3736 }
3737 }
3738 break :blk "\n";
3739 },
3740 });
3741 }
3742 }
3743 },
3744 ast.Node.Id.Defer => {
3745 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
3746 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
3747 try stack.push(RenderState { .Expression = defer_node.expr });
3748 },
3749 ast.Node.Id.Comptime => {
3750 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
3751 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
3752 try stack.push(RenderState { .Expression = comptime_node.expr });
3753 },
3754 ast.Node.Id.AsyncAttribute => {
3755 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
3756 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
3757
3758 if (async_attr.allocator_type) |allocator_type| {
3759 try stack.push(RenderState { .Text = ">" });
3760 try stack.push(RenderState { .Expression = allocator_type });
3761 try stack.push(RenderState { .Text = "<" });
3762 }
3763 },
3764 ast.Node.Id.Suspend => {
3765 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
3766 if (suspend_node.label) |label| {
3767 try stream.print("{}: ", tree.tokenSlice(label));
3768 }
3769 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
3770
3771 if (suspend_node.body) |body| {
3772 try stack.push(RenderState { .Expression = body });
3773 try stack.push(RenderState { .Text = " " });
3774 }
3775
3776 if (suspend_node.payload) |payload| {
3777 try stack.push(RenderState { .Expression = payload });
3778 try stack.push(RenderState { .Text = " " });
3779 }
3780 },
3781 ast.Node.Id.InfixOp => {
3782 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
3783 try stack.push(RenderState { .Expression = prefix_op_node.rhs });
3784
3785 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
3786 if (prefix_op_node.op.Catch) |payload| {
3787 try stack.push(RenderState { .Text = " " });
3788 try stack.push(RenderState { .Expression = payload });
3789 }
3790 try stack.push(RenderState { .Text = " catch " });
3791 } else {
3792 const text = switch (prefix_op_node.op) {
3793 ast.Node.InfixOp.Op.Add => " + ",
3794 ast.Node.InfixOp.Op.AddWrap => " +% ",
3795 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
3796 ast.Node.InfixOp.Op.ArrayMult => " ** ",
3797 ast.Node.InfixOp.Op.Assign => " = ",
3798 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
3799 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
3800 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
3801 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
3802 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
3803 ast.Node.InfixOp.Op.AssignDiv => " /= ",
3804 ast.Node.InfixOp.Op.AssignMinus => " -= ",
3805 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
3806 ast.Node.InfixOp.Op.AssignMod => " %= ",
3807 ast.Node.InfixOp.Op.AssignPlus => " += ",
3808 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
3809 ast.Node.InfixOp.Op.AssignTimes => " *= ",
3810 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
3811 ast.Node.InfixOp.Op.BangEqual => " != ",
3812 ast.Node.InfixOp.Op.BitAnd => " & ",
3813 ast.Node.InfixOp.Op.BitOr => " | ",
3814 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
3815 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
3816 ast.Node.InfixOp.Op.BitXor => " ^ ",
3817 ast.Node.InfixOp.Op.BoolAnd => " and ",
3818 ast.Node.InfixOp.Op.BoolOr => " or ",
3819 ast.Node.InfixOp.Op.Div => " / ",
3820 ast.Node.InfixOp.Op.EqualEqual => " == ",
3821 ast.Node.InfixOp.Op.ErrorUnion => "!",
3822 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
3823 ast.Node.InfixOp.Op.GreaterThan => " > ",
3824 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
3825 ast.Node.InfixOp.Op.LessThan => " < ",
3826 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
3827 ast.Node.InfixOp.Op.Mod => " % ",
3828 ast.Node.InfixOp.Op.Mult => " * ",
3829 ast.Node.InfixOp.Op.MultWrap => " *% ",
3830 ast.Node.InfixOp.Op.Period => ".",
3831 ast.Node.InfixOp.Op.Sub => " - ",
3832 ast.Node.InfixOp.Op.SubWrap => " -% ",
3833 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
3834 ast.Node.InfixOp.Op.Range => " ... ",
3835 ast.Node.InfixOp.Op.Catch => unreachable,
3836 };
3837
3838 try stack.push(RenderState { .Text = text });
3839 }
3840 try stack.push(RenderState { .Expression = prefix_op_node.lhs });
3841 },
3842 ast.Node.Id.PrefixOp => {
3843 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
3844 try stack.push(RenderState { .Expression = prefix_op_node.rhs });
3845 switch (prefix_op_node.op) {
3846 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
3847 try stream.write("&");
3848 if (addr_of_info.volatile_token != null) {
3849 try stack.push(RenderState { .Text = "volatile "});
3850 }
3851 if (addr_of_info.const_token != null) {
3852 try stack.push(RenderState { .Text = "const "});
3853 }
3854 if (addr_of_info.align_expr) |align_expr| {
3855 try stream.print("align(");
3856 try stack.push(RenderState { .Text = ") "});
3857 try stack.push(RenderState { .Expression = align_expr});
3858 }
3859 },
3860 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
3861 try stream.write("[]");
3862 if (addr_of_info.volatile_token != null) {
3863 try stack.push(RenderState { .Text = "volatile "});
3864 }
3865 if (addr_of_info.const_token != null) {
3866 try stack.push(RenderState { .Text = "const "});
3867 }
3868 if (addr_of_info.align_expr) |align_expr| {
3869 try stream.print("align(");
3870 try stack.push(RenderState { .Text = ") "});
3871 try stack.push(RenderState { .Expression = align_expr});
3872 }
3873 },
3874 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
3875 try stack.push(RenderState { .Text = "]"});
3876 try stack.push(RenderState { .Expression = array_index});
3877 try stack.push(RenderState { .Text = "["});
3878 },
3879 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
3880 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
3881 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
3882 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
3883 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
3884 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
3885 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
3886 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
3887 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
3888 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
3889 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
3890 }
3891 },
3892 ast.Node.Id.SuffixOp => {
3893 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
3894
3895 switch (suffix_op.op) {
3896 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
3897 try stack.push(RenderState { .Text = ")"});
3898 var i = call_info.params.len;
3899 while (i != 0) {
3900 i -= 1;
3901 const param_node = *call_info.params.at(i);
3902 try stack.push(RenderState { .Expression = param_node});
3903 if (i != 0) {
3904 try stack.push(RenderState { .Text = ", " });
3905 }
3906 }
3907 try stack.push(RenderState { .Text = "("});
3908 try stack.push(RenderState { .Expression = suffix_op.lhs });
3909
3910 if (call_info.async_attr) |async_attr| {
3911 try stack.push(RenderState { .Text = " "});
3912 try stack.push(RenderState { .Expression = &async_attr.base });
3913 }
3914 },
3915 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
3916 try stack.push(RenderState { .Text = "]"});
3917 try stack.push(RenderState { .Expression = index_expr});
3918 try stack.push(RenderState { .Text = "["});
3919 try stack.push(RenderState { .Expression = suffix_op.lhs });
3920 },
3921 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
3922 try stack.push(RenderState { .Text = "]"});
3923 if (range.end) |end| {
3924 try stack.push(RenderState { .Expression = end});
3925 }
3926 try stack.push(RenderState { .Text = ".."});
3927 try stack.push(RenderState { .Expression = range.start});
3928 try stack.push(RenderState { .Text = "["});
3929 try stack.push(RenderState { .Expression = suffix_op.lhs });
3930 },
3931 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
3932 if (field_inits.len == 0) {
3933 try stack.push(RenderState { .Text = "{}" });
3934 try stack.push(RenderState { .Expression = suffix_op.lhs });
3935 continue;
3936 }
3937 if (field_inits.len == 1) {
3938 const field_init = *field_inits.at(0);
3939
3940 try stack.push(RenderState { .Text = " }" });
3941 try stack.push(RenderState { .Expression = field_init });
3942 try stack.push(RenderState { .Text = "{ " });
3943 try stack.push(RenderState { .Expression = suffix_op.lhs });
3944 continue;
3945 }
3946 try stack.push(RenderState { .Text = "}"});
3947 try stack.push(RenderState.PrintIndent);
3948 try stack.push(RenderState { .Indent = indent });
3949 try stack.push(RenderState { .Text = "\n" });
3950 var i = field_inits.len;
3951 while (i != 0) {
3952 i -= 1;
3953 const field_init = *field_inits.at(i);
3954 if (field_init.id != ast.Node.Id.LineComment) {
3955 try stack.push(RenderState { .Text = "," });
3956 }
3957 try stack.push(RenderState { .Expression = field_init });
3958 try stack.push(RenderState.PrintIndent);
3959 if (i != 0) {
3960 try stack.push(RenderState { .Text = blk: {
3961 const prev_node = *field_inits.at(i - 1);
3962 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
3963 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
3964 if (loc.line >= 2) {
3965 break :blk "\n\n";
3966 }
3967 break :blk "\n";
3968 }});
3969 }
3970 }
3971 try stack.push(RenderState { .Indent = indent + indent_delta });
3972 try stack.push(RenderState { .Text = "{\n"});
3973 try stack.push(RenderState { .Expression = suffix_op.lhs });
3974 },
3975 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
3976 if (exprs.len == 0) {
3977 try stack.push(RenderState { .Text = "{}" });
3978 try stack.push(RenderState { .Expression = suffix_op.lhs });
3979 continue;
3980 }
3981 if (exprs.len == 1) {
3982 const expr = *exprs.at(0);
3983
3984 try stack.push(RenderState { .Text = "}" });
3985 try stack.push(RenderState { .Expression = expr });
3986 try stack.push(RenderState { .Text = "{" });
3987 try stack.push(RenderState { .Expression = suffix_op.lhs });
3988 continue;
3989 }
3990
3991 try stack.push(RenderState { .Text = "}"});
3992 try stack.push(RenderState.PrintIndent);
3993 try stack.push(RenderState { .Indent = indent });
3994 var i = exprs.len;
3995 while (i != 0) {
3996 i -= 1;
3997 const expr = *exprs.at(i);
3998 try stack.push(RenderState { .Text = ",\n" });
3999 try stack.push(RenderState { .Expression = expr });
4000 try stack.push(RenderState.PrintIndent);
4001 }
4002 try stack.push(RenderState { .Indent = indent + indent_delta });
4003 try stack.push(RenderState { .Text = "{\n"});
4004 try stack.push(RenderState { .Expression = suffix_op.lhs });
4005 },
4006 }
4007 },
4008 ast.Node.Id.ControlFlowExpression => {
4009 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
4010
4011 if (flow_expr.rhs) |rhs| {
4012 try stack.push(RenderState { .Expression = rhs });
4013 try stack.push(RenderState { .Text = " " });
4014 }
4015
4016 switch (flow_expr.kind) {
4017 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
4018 try stream.print("break");
4019 if (maybe_label) |label| {
4020 try stream.print(" :");
4021 try stack.push(RenderState { .Expression = label });
4022 }
4023 },
4024 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
4025 try stream.print("continue");
4026 if (maybe_label) |label| {
4027 try stream.print(" :");
4028 try stack.push(RenderState { .Expression = label });
4029 }
4030 },
4031 ast.Node.ControlFlowExpression.Kind.Return => {
4032 try stream.print("return");
4033 },
4034
4035 }
4036 },
4037 ast.Node.Id.Payload => {
4038 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
4039 try stack.push(RenderState { .Text = "|"});
4040 try stack.push(RenderState { .Expression = payload.error_symbol });
4041 try stack.push(RenderState { .Text = "|"});
4042 },
4043 ast.Node.Id.PointerPayload => {
4044 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
4045 try stack.push(RenderState { .Text = "|"});
4046 try stack.push(RenderState { .Expression = payload.value_symbol });
4047
4048 if (payload.ptr_token) |ptr_token| {
4049 try stack.push(RenderState { .Text = tree.tokenSlice(ptr_token) });
4050 }
4051
4052 try stack.push(RenderState { .Text = "|"});
4053 },
4054 ast.Node.Id.PointerIndexPayload => {
4055 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
4056 try stack.push(RenderState { .Text = "|"});
4057
4058 if (payload.index_symbol) |index_symbol| {
4059 try stack.push(RenderState { .Expression = index_symbol });
4060 try stack.push(RenderState { .Text = ", "});
4061 }
4062
4063 try stack.push(RenderState { .Expression = payload.value_symbol });
4064
4065 if (payload.ptr_token) |ptr_token| {
4066 try stack.push(RenderState { .Text = tree.tokenSlice(ptr_token) });
4067 }
4068
4069 try stack.push(RenderState { .Text = "|"});
4070 },
4071 ast.Node.Id.GroupedExpression => {
4072 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
4073 try stack.push(RenderState { .Text = ")"});
4074 try stack.push(RenderState { .Expression = grouped_expr.expr });
4075 try stack.push(RenderState { .Text = "("});
4076 },
4077 ast.Node.Id.FieldInitializer => {
4078 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
4079 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
4080 try stack.push(RenderState { .Expression = field_init.expr });
4081 },
4082 ast.Node.Id.IntegerLiteral => {
4083 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
4084 try stream.print("{}", tree.tokenSlice(integer_literal.token));
4085 },
4086 ast.Node.Id.FloatLiteral => {
4087 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
4088 try stream.print("{}", tree.tokenSlice(float_literal.token));
4089 },
4090 ast.Node.Id.StringLiteral => {
4091 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
4092 try stream.print("{}", tree.tokenSlice(string_literal.token));
4093 },
4094 ast.Node.Id.CharLiteral => {
4095 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4096 try stream.print("{}", tree.tokenSlice(char_literal.token));
4097 },
4098 ast.Node.Id.BoolLiteral => {
4099 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4100 try stream.print("{}", tree.tokenSlice(bool_literal.token));
4101 },
4102 ast.Node.Id.NullLiteral => {
4103 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
4104 try stream.print("{}", tree.tokenSlice(null_literal.token));
4105 },
4106 ast.Node.Id.ThisLiteral => {
4107 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
4108 try stream.print("{}", tree.tokenSlice(this_literal.token));
4109 },
4110 ast.Node.Id.Unreachable => {
4111 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
4112 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
4113 },
4114 ast.Node.Id.ErrorType => {
4115 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
4116 try stream.print("{}", tree.tokenSlice(error_type.token));
4117 },
4118 ast.Node.Id.VarType => {
4119 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
4120 try stream.print("{}", tree.tokenSlice(var_type.token));
4121 },
4122 ast.Node.Id.ContainerDecl => {
4123 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
4124
4125 switch (container_decl.layout) {
4126 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
4127 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
4128 ast.Node.ContainerDecl.Layout.Auto => { },
4129 }
4130
4131 switch (container_decl.kind) {
4132 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
4133 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
4134 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
4135 }
4136
4137 if (container_decl.fields_and_decls.len == 0) {
4138 try stack.push(RenderState { .Text = "{}"});
4139 } else {
4140 try stack.push(RenderState { .Text = "}"});
4141 try stack.push(RenderState.PrintIndent);
4142 try stack.push(RenderState { .Indent = indent });
4143 try stack.push(RenderState { .Text = "\n"});
4144
4145 var i = container_decl.fields_and_decls.len;
4146 while (i != 0) {
4147 i -= 1;
4148 const node = *container_decl.fields_and_decls.at(i);
4149 try stack.push(RenderState { .TopLevelDecl = node});
4150 try stack.push(RenderState.PrintIndent);
4151 try stack.push(RenderState {
4152 .Text = blk: {
4153 if (i != 0) {
4154 const prev_node = *container_decl.fields_and_decls.at(i - 1);
4155 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
4156 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
4157 if (loc.line >= 2) {
4158 break :blk "\n\n";
4159 }
4160 }
4161 break :blk "\n";
4162 },
4163 });
4164 }
4165 try stack.push(RenderState { .Indent = indent + indent_delta});
4166 try stack.push(RenderState { .Text = "{"});
4167 }
4168
4169 switch (container_decl.init_arg_expr) {
4170 ast.Node.ContainerDecl.InitArg.None => try stack.push(RenderState { .Text = " "}),
4171 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
4172 if (enum_tag_type) |expr| {
4173 try stack.push(RenderState { .Text = ")) "});
4174 try stack.push(RenderState { .Expression = expr});
4175 try stack.push(RenderState { .Text = "(enum("});
4176 } else {
4177 try stack.push(RenderState { .Text = "(enum) "});
4178 }
4179 },
4180 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
4181 try stack.push(RenderState { .Text = ") "});
4182 try stack.push(RenderState { .Expression = type_expr});
4183 try stack.push(RenderState { .Text = "("});
4184 },
4185 }
4186 },
4187 ast.Node.Id.ErrorSetDecl => {
4188 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
4189
4190 if (err_set_decl.decls.len == 0) {
4191 try stream.write("error{}");
4192 continue;
4193 }
4194
4195 if (err_set_decl.decls.len == 1) blk: {
4196 const node = *err_set_decl.decls.at(0);
4197
4198 // if there are any doc comments or same line comments
4199 // don't try to put it all on one line
4200 if (node.cast(ast.Node.ErrorTag)) |tag| {
4201 if (tag.doc_comments != null) break :blk;
4202 } else {
4203 break :blk;
4204 }
4205
4206
4207 try stream.write("error{");
4208 try stack.push(RenderState { .Text = "}" });
4209 try stack.push(RenderState { .TopLevelDecl = node });
4210 continue;
4211 }
4212
4213 try stream.write("error{");
4214
4215 try stack.push(RenderState { .Text = "}"});
4216 try stack.push(RenderState.PrintIndent);
4217 try stack.push(RenderState { .Indent = indent });
4218 try stack.push(RenderState { .Text = "\n"});
4219
4220 var i = err_set_decl.decls.len;
4221 while (i != 0) {
4222 i -= 1;
4223 const node = *err_set_decl.decls.at(i);
4224 if (node.id != ast.Node.Id.LineComment) {
4225 try stack.push(RenderState { .Text = "," });
4226 }
4227 try stack.push(RenderState { .TopLevelDecl = node });
4228 try stack.push(RenderState.PrintIndent);
4229 try stack.push(RenderState {
4230 .Text = blk: {
4231 if (i != 0) {
4232 const prev_node = *err_set_decl.decls.at(i - 1);
4233 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
4234 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
4235 if (loc.line >= 2) {
4236 break :blk "\n\n";
4237 }
4238 }
4239 break :blk "\n";
4240 },
4241 });
4242 }
4243 try stack.push(RenderState { .Indent = indent + indent_delta});
4244 },
4245 ast.Node.Id.MultilineStringLiteral => {
4246 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
4247 try stream.print("\n");
4248
4249 var i : usize = 0;
4250 while (i < multiline_str_literal.lines.len) : (i += 1) {
4251 const t = *multiline_str_literal.lines.at(i);
4252 try stream.writeByteNTimes(' ', indent + indent_delta);
4253 try stream.print("{}", tree.tokenSlice(t));
4254 }
4255 try stream.writeByteNTimes(' ', indent);
4256 },
4257 ast.Node.Id.UndefinedLiteral => {
4258 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
4259 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
4260 },
4261 ast.Node.Id.BuiltinCall => {
4262 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
4263 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
4264 try stack.push(RenderState { .Text = ")"});
4265 var i = builtin_call.params.len;
4266 while (i != 0) {
4267 i -= 1;
4268 const param_node = *builtin_call.params.at(i);
4269 try stack.push(RenderState { .Expression = param_node});
4270 if (i != 0) {
4271 try stack.push(RenderState { .Text = ", " });
4272 }
4273 }
4274 },
4275 ast.Node.Id.FnProto => {
4276 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
4277
4278 switch (fn_proto.return_type) {
4279 ast.Node.FnProto.ReturnType.Explicit => |node| {
4280 try stack.push(RenderState { .Expression = node});
4281 },
4282 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
4283 try stack.push(RenderState { .Expression = node});
4284 try stack.push(RenderState { .Text = "!"});
4285 },
4286 }
4287
4288 if (fn_proto.align_expr) |align_expr| {
4289 try stack.push(RenderState { .Text = ") " });
4290 try stack.push(RenderState { .Expression = align_expr});
4291 try stack.push(RenderState { .Text = "align(" });
4292 }
4293
4294 try stack.push(RenderState { .Text = ") " });
4295 var i = fn_proto.params.len;
4296 while (i != 0) {
4297 i -= 1;
4298 const param_decl_node = *fn_proto.params.at(i);
4299 try stack.push(RenderState { .ParamDecl = param_decl_node});
4300 if (i != 0) {
4301 try stack.push(RenderState { .Text = ", " });
4302 }
4303 }
4304
4305 try stack.push(RenderState { .Text = "(" });
4306 if (fn_proto.name_token) |name_token| {
4307 try stack.push(RenderState { .Text = tree.tokenSlice(name_token) });
4308 try stack.push(RenderState { .Text = " " });
4309 }
4310
4311 try stack.push(RenderState { .Text = "fn" });
4312
4313 if (fn_proto.async_attr) |async_attr| {
4314 try stack.push(RenderState { .Text = " " });
4315 try stack.push(RenderState { .Expression = &async_attr.base });
4316 }
4317
4318 if (fn_proto.cc_token) |cc_token| {
4319 try stack.push(RenderState { .Text = " " });
4320 try stack.push(RenderState { .Text = tree.tokenSlice(cc_token) });
4321 }
4322
4323 if (fn_proto.lib_name) |lib_name| {
4324 try stack.push(RenderState { .Text = " " });
4325 try stack.push(RenderState { .Expression = lib_name });
4326 }
4327 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
4328 try stack.push(RenderState { .Text = " " });
4329 try stack.push(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
4330 }
4331
4332 if (fn_proto.visib_token) |visib_token_index| {
4333 const visib_token = tree.tokens.at(visib_token_index);
4334 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
4335 try stack.push(RenderState { .Text = " " });
4336 try stack.push(RenderState { .Text = tree.tokenSlice(visib_token_index) });
4337 }
4338 },
4339 ast.Node.Id.PromiseType => {
4340 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
4341 try stream.write(tree.tokenSlice(promise_type.promise_token));
4342 if (promise_type.result) |result| {
4343 try stream.write(tree.tokenSlice(result.arrow_token));
4344 try stack.push(RenderState { .Expression = result.return_type});
4345 }
4346 },
4347 ast.Node.Id.LineComment => {
4348 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
4349 try stream.write(tree.tokenSlice(line_comment_node.token));
4350 },
4351 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
4352 ast.Node.Id.Switch => {
4353 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
4354
4355 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
4356
4357 if (switch_node.cases.len == 0) {
4358 try stack.push(RenderState { .Text = ") {}"});
4359 try stack.push(RenderState { .Expression = switch_node.expr });
4360 continue;
4361 }
4362
4363 try stack.push(RenderState { .Text = "}"});
4364 try stack.push(RenderState.PrintIndent);
4365 try stack.push(RenderState { .Indent = indent });
4366 try stack.push(RenderState { .Text = "\n"});
4367
4368 var i = switch_node.cases.len;
4369 while (i != 0) {
4370 i -= 1;
4371 const node = *switch_node.cases.at(i);
4372 try stack.push(RenderState { .Expression = node});
4373 try stack.push(RenderState.PrintIndent);
4374 try stack.push(RenderState {
4375 .Text = blk: {
4376 if (i != 0) {
4377 const prev_node = *switch_node.cases.at(i - 1);
4378 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
4379 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
4380 if (loc.line >= 2) {
4381 break :blk "\n\n";
4382 }
4383 }
4384 break :blk "\n";
4385 },
4386 });
4387 }
4388 try stack.push(RenderState { .Indent = indent + indent_delta});
4389 try stack.push(RenderState { .Text = ") {"});
4390 try stack.push(RenderState { .Expression = switch_node.expr });
4391 },
4392 ast.Node.Id.SwitchCase => {
4393 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
4394
4395 try stack.push(RenderState { .Text = "," });
4396 try stack.push(RenderState { .Expression = switch_case.expr });
4397 if (switch_case.payload) |payload| {
4398 try stack.push(RenderState { .Text = " " });
4399 try stack.push(RenderState { .Expression = payload });
4400 }
4401 try stack.push(RenderState { .Text = " => "});
4402
4403 var i = switch_case.items.len;
4404 while (i != 0) {
4405 i -= 1;
4406 try stack.push(RenderState { .Expression = *switch_case.items.at(i) });
4407
4408 if (i != 0) {
4409 try stack.push(RenderState.PrintIndent);
4410 try stack.push(RenderState { .Text = ",\n" });
4411 }
4412 }
4413 },
4414 ast.Node.Id.SwitchElse => {
4415 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
4416 try stream.print("{}", tree.tokenSlice(switch_else.token));
4417 },
4418 ast.Node.Id.Else => {
4419 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
4420 try stream.print("{}", tree.tokenSlice(else_node.else_token));
4421
4422 switch (else_node.body.id) {
4423 ast.Node.Id.Block, ast.Node.Id.If,
4424 ast.Node.Id.For, ast.Node.Id.While,
4425 ast.Node.Id.Switch => {
4426 try stream.print(" ");
4427 try stack.push(RenderState { .Expression = else_node.body });
4428 },
4429 else => {
4430 try stack.push(RenderState { .Indent = indent });
4431 try stack.push(RenderState { .Expression = else_node.body });
4432 try stack.push(RenderState.PrintIndent);
4433 try stack.push(RenderState { .Indent = indent + indent_delta });
4434 try stack.push(RenderState { .Text = "\n" });
4435 }
4436 }
4437
4438 if (else_node.payload) |payload| {
4439 try stack.push(RenderState { .Text = " " });
4440 try stack.push(RenderState { .Expression = payload });
4441 }
4442 },
4443 ast.Node.Id.While => {
4444 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
4445 if (while_node.label) |label| {
4446 try stream.print("{}: ", tree.tokenSlice(label));
4447 }
4448
4449 if (while_node.inline_token) |inline_token| {
4450 try stream.print("{} ", tree.tokenSlice(inline_token));
4451 }
4452
4453 try stream.print("{} ", tree.tokenSlice(while_node.while_token));
4454
4455 if (while_node.@"else") |@"else"| {
4456 try stack.push(RenderState { .Expression = &@"else".base });
4457
4458 if (while_node.body.id == ast.Node.Id.Block) {
4459 try stack.push(RenderState { .Text = " " });
4460 } else {
4461 try stack.push(RenderState.PrintIndent);
4462 try stack.push(RenderState { .Text = "\n" });
4463 }
4464 }
4465
4466 if (while_node.body.id == ast.Node.Id.Block) {
4467 try stack.push(RenderState { .Expression = while_node.body });
4468 try stack.push(RenderState { .Text = " " });
4469 } else {
4470 try stack.push(RenderState { .Indent = indent });
4471 try stack.push(RenderState { .Expression = while_node.body });
4472 try stack.push(RenderState.PrintIndent);
4473 try stack.push(RenderState { .Indent = indent + indent_delta });
4474 try stack.push(RenderState { .Text = "\n" });
4475 }
4476
4477 if (while_node.continue_expr) |continue_expr| {
4478 try stack.push(RenderState { .Text = ")" });
4479 try stack.push(RenderState { .Expression = continue_expr });
4480 try stack.push(RenderState { .Text = ": (" });
4481 try stack.push(RenderState { .Text = " " });
4482 }
4483
4484 if (while_node.payload) |payload| {
4485 try stack.push(RenderState { .Expression = payload });
4486 try stack.push(RenderState { .Text = " " });
4487 }
4488
4489 try stack.push(RenderState { .Text = ")" });
4490 try stack.push(RenderState { .Expression = while_node.condition });
4491 try stack.push(RenderState { .Text = "(" });
4492 },
4493 ast.Node.Id.For => {
4494 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
4495 if (for_node.label) |label| {
4496 try stream.print("{}: ", tree.tokenSlice(label));
4497 }
4498
4499 if (for_node.inline_token) |inline_token| {
4500 try stream.print("{} ", tree.tokenSlice(inline_token));
4501 }
4502
4503 try stream.print("{} ", tree.tokenSlice(for_node.for_token));
4504
4505 if (for_node.@"else") |@"else"| {
4506 try stack.push(RenderState { .Expression = &@"else".base });
4507
4508 if (for_node.body.id == ast.Node.Id.Block) {
4509 try stack.push(RenderState { .Text = " " });
4510 } else {
4511 try stack.push(RenderState.PrintIndent);
4512 try stack.push(RenderState { .Text = "\n" });
4513 }
4514 }
4515
4516 if (for_node.body.id == ast.Node.Id.Block) {
4517 try stack.push(RenderState { .Expression = for_node.body });
4518 try stack.push(RenderState { .Text = " " });
4519 } else {
4520 try stack.push(RenderState { .Indent = indent });
4521 try stack.push(RenderState { .Expression = for_node.body });
4522 try stack.push(RenderState.PrintIndent);
4523 try stack.push(RenderState { .Indent = indent + indent_delta });
4524 try stack.push(RenderState { .Text = "\n" });
4525 }
4526
4527 if (for_node.payload) |payload| {
4528 try stack.push(RenderState { .Expression = payload });
4529 try stack.push(RenderState { .Text = " " });
4530 }
4531
4532 try stack.push(RenderState { .Text = ")" });
4533 try stack.push(RenderState { .Expression = for_node.array_expr });
4534 try stack.push(RenderState { .Text = "(" });
4535 },
4536 ast.Node.Id.If => {
4537 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
4538 try stream.print("{} ", tree.tokenSlice(if_node.if_token));
4539
4540 switch (if_node.body.id) {
4541 ast.Node.Id.Block, ast.Node.Id.If,
4542 ast.Node.Id.For, ast.Node.Id.While,
4543 ast.Node.Id.Switch => {
4544 if (if_node.@"else") |@"else"| {
4545 try stack.push(RenderState { .Expression = &@"else".base });
4546
4547 if (if_node.body.id == ast.Node.Id.Block) {
4548 try stack.push(RenderState { .Text = " " });
4549 } else {
4550 try stack.push(RenderState.PrintIndent);
4551 try stack.push(RenderState { .Text = "\n" });
4552 }
4553 }
4554 },
4555 else => {
4556 if (if_node.@"else") |@"else"| {
4557 try stack.push(RenderState { .Expression = @"else".body });
4558
4559 if (@"else".payload) |payload| {
4560 try stack.push(RenderState { .Text = " " });
4561 try stack.push(RenderState { .Expression = payload });
4562 }
4563
4564 try stack.push(RenderState { .Text = " " });
4565 try stack.push(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
4566 try stack.push(RenderState { .Text = " " });
4567 }
4568 }
4569 }
4570
4571 try stack.push(RenderState { .Expression = if_node.body });
4572 try stack.push(RenderState { .Text = " " });
4573
4574 if (if_node.payload) |payload| {
4575 try stack.push(RenderState { .Expression = payload });
4576 try stack.push(RenderState { .Text = " " });
4577 }
4578
4579 try stack.push(RenderState { .Text = ")" });
4580 try stack.push(RenderState { .Expression = if_node.condition });
4581 try stack.push(RenderState { .Text = "(" });
4582 },
4583 ast.Node.Id.Asm => {
4584 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
4585 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
4586
4587 if (asm_node.volatile_token) |volatile_token| {
4588 try stream.print("{} ", tree.tokenSlice(volatile_token));
4589 }
4590
4591 try stack.push(RenderState { .Indent = indent });
4592 try stack.push(RenderState { .Text = ")" });
4593 {
4594 var i = asm_node.clobbers.len;
4595 while (i != 0) {
4596 i -= 1;
4597 try stack.push(RenderState { .Expression = *asm_node.clobbers.at(i) });
4598
4599 if (i != 0) {
4600 try stack.push(RenderState { .Text = ", " });
4601 }
4602 }
4603 }
4604 try stack.push(RenderState { .Text = ": " });
4605 try stack.push(RenderState.PrintIndent);
4606 try stack.push(RenderState { .Indent = indent + indent_delta });
4607 try stack.push(RenderState { .Text = "\n" });
4608 {
4609 var i = asm_node.inputs.len;
4610 while (i != 0) {
4611 i -= 1;
4612 const node = *asm_node.inputs.at(i);
4613 try stack.push(RenderState { .Expression = &node.base});
4614
4615 if (i != 0) {
4616 try stack.push(RenderState.PrintIndent);
4617 try stack.push(RenderState {
4618 .Text = blk: {
4619 const prev_node = *asm_node.inputs.at(i - 1);
4620 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
4621 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
4622 if (loc.line >= 2) {
4623 break :blk "\n\n";
4624 }
4625 break :blk "\n";
4626 },
4627 });
4628 try stack.push(RenderState { .Text = "," });
4629 }
4630 }
4631 }
4632 try stack.push(RenderState { .Indent = indent + indent_delta + 2});
4633 try stack.push(RenderState { .Text = ": "});
4634 try stack.push(RenderState.PrintIndent);
4635 try stack.push(RenderState { .Indent = indent + indent_delta});
4636 try stack.push(RenderState { .Text = "\n" });
4637 {
4638 var i = asm_node.outputs.len;
4639 while (i != 0) {
4640 i -= 1;
4641 const node = *asm_node.outputs.at(i);
4642 try stack.push(RenderState { .Expression = &node.base});
4643
4644 if (i != 0) {
4645 try stack.push(RenderState.PrintIndent);
4646 try stack.push(RenderState {
4647 .Text = blk: {
4648 const prev_node = *asm_node.outputs.at(i - 1);
4649 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
4650 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
4651 if (loc.line >= 2) {
4652 break :blk "\n\n";
4653 }
4654 break :blk "\n";
4655 },
4656 });
4657 try stack.push(RenderState { .Text = "," });
4658 }
4659 }
4660 }
4661 try stack.push(RenderState { .Indent = indent + indent_delta + 2});
4662 try stack.push(RenderState { .Text = ": "});
4663 try stack.push(RenderState.PrintIndent);
4664 try stack.push(RenderState { .Indent = indent + indent_delta});
4665 try stack.push(RenderState { .Text = "\n" });
4666 try stack.push(RenderState { .Expression = asm_node.template });
4667 try stack.push(RenderState { .Text = "(" });
4668 },
4669 ast.Node.Id.AsmInput => {
4670 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
4671
4672 try stack.push(RenderState { .Text = ")"});
4673 try stack.push(RenderState { .Expression = asm_input.expr});
4674 try stack.push(RenderState { .Text = " ("});
4675 try stack.push(RenderState { .Expression = asm_input.constraint });
4676 try stack.push(RenderState { .Text = "] "});
4677 try stack.push(RenderState { .Expression = asm_input.symbolic_name });
4678 try stack.push(RenderState { .Text = "["});
4679 },
4680 ast.Node.Id.AsmOutput => {
4681 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
4682
4683 try stack.push(RenderState { .Text = ")"});
4684 switch (asm_output.kind) {
4685 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
4686 try stack.push(RenderState { .Expression = &variable_name.base});
4687 },
4688 ast.Node.AsmOutput.Kind.Return => |return_type| {
4689 try stack.push(RenderState { .Expression = return_type});
4690 try stack.push(RenderState { .Text = "-> "});
4691 },
4692 }
4693 try stack.push(RenderState { .Text = " ("});
4694 try stack.push(RenderState { .Expression = asm_output.constraint });
4695 try stack.push(RenderState { .Text = "] "});
4696 try stack.push(RenderState { .Expression = asm_output.symbolic_name });
4697 try stack.push(RenderState { .Text = "["});
4698 },
4699
4700 ast.Node.Id.StructField,
4701 ast.Node.Id.UnionTag,
4702 ast.Node.Id.EnumTag,
4703 ast.Node.Id.ErrorTag,
4704 ast.Node.Id.Root,
4705 ast.Node.Id.VarDecl,
4706 ast.Node.Id.Use,
4707 ast.Node.Id.TestDecl,
4708 ast.Node.Id.ParamDecl => unreachable,
4709 },
4710 RenderState.Statement => |base| {
4711 switch (base.id) {
4712 ast.Node.Id.VarDecl => {
4713 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
4714 try stack.push(RenderState { .VarDecl = var_decl});
4715 },
4716 else => {
4717 if (requireSemiColon(base)) {
4718 try stack.push(RenderState { .Text = ";" });
4719 }
4720 try stack.push(RenderState { .Expression = base });
4721 },
4722 }
4723 },
4724 RenderState.Indent => |new_indent| indent = new_indent,
4725 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
4726 }
4727 }
4728}
4729
4730fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {
4731 const comment = node.doc_comments ?? return;
4732 var it = comment.lines.iterator(0);
4733 while (it.next()) |line_token_index| {
4734 try stream.print("{}\n", tree.tokenSlice(*line_token_index));
4735 try stream.writeByteNTimes(' ', indent);
4736 }
4737}
4738
4739test "std.zig.parser" {
4740 _ = @import("parser_test.zig");
4741}
std/zig/render.zig created+1241
...@@ -0,0 +1,1241 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const SegmentedList = std.SegmentedList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Token = std.zig.Token;
7
8const RenderState = union(enum) {
9 TopLevelDecl: &ast.Node,
10 ParamDecl: &ast.Node,
11 Text: []const u8,
12 Expression: &ast.Node,
13 VarDecl: &ast.Node.VarDecl,
14 Statement: &ast.Node,
15 PrintIndent,
16 Indent: usize,
17};
18
19pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {
20 var stack = SegmentedList(RenderState, 32).init(allocator);
21 defer stack.deinit();
22
23 {
24 try stack.push(RenderState { .Text = "\n"});
25
26 var i = tree.root_node.decls.len;
27 while (i != 0) {
28 i -= 1;
29 const decl = *tree.root_node.decls.at(i);
30 try stack.push(RenderState {.TopLevelDecl = decl});
31 if (i != 0) {
32 try stack.push(RenderState {
33 .Text = blk: {
34 const prev_node = *tree.root_node.decls.at(i - 1);
35 const prev_node_last_token = tree.tokens.at(prev_node.lastToken());
36 const loc = tree.tokenLocation(prev_node_last_token.end, decl.firstToken());
37 if (loc.line >= 2) {
38 break :blk "\n\n";
39 }
40 break :blk "\n";
41 },
42 });
43 }
44 }
45 }
46
47 const indent_delta = 4;
48 var indent: usize = 0;
49 while (stack.pop()) |state| {
50 switch (state) {
51 RenderState.TopLevelDecl => |decl| {
52 switch (decl.id) {
53 ast.Node.Id.FnProto => {
54 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
55 try renderComments(tree, stream, fn_proto, indent);
56
57 if (fn_proto.body_node) |body_node| {
58 stack.push(RenderState { .Expression = body_node}) catch unreachable;
59 try stack.push(RenderState { .Text = " "});
60 } else {
61 stack.push(RenderState { .Text = ";" }) catch unreachable;
62 }
63
64 try stack.push(RenderState { .Expression = decl });
65 },
66 ast.Node.Id.Use => {
67 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
68 if (use_decl.visib_token) |visib_token| {
69 try stream.print("{} ", tree.tokenSlice(visib_token));
70 }
71 try stream.print("use ");
72 try stack.push(RenderState { .Text = ";" });
73 try stack.push(RenderState { .Expression = use_decl.expr });
74 },
75 ast.Node.Id.VarDecl => {
76 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
77 try renderComments(tree, stream, var_decl, indent);
78 try stack.push(RenderState { .VarDecl = var_decl});
79 },
80 ast.Node.Id.TestDecl => {
81 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
82 try renderComments(tree, stream, test_decl, indent);
83 try stream.print("test ");
84 try stack.push(RenderState { .Expression = test_decl.body_node });
85 try stack.push(RenderState { .Text = " " });
86 try stack.push(RenderState { .Expression = test_decl.name });
87 },
88 ast.Node.Id.StructField => {
89 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
90 try renderComments(tree, stream, field, indent);
91 if (field.visib_token) |visib_token| {
92 try stream.print("{} ", tree.tokenSlice(visib_token));
93 }
94 try stream.print("{}: ", tree.tokenSlice(field.name_token));
95 try stack.push(RenderState { .Text = "," });
96 try stack.push(RenderState { .Expression = field.type_expr});
97 },
98 ast.Node.Id.UnionTag => {
99 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
100 try renderComments(tree, stream, tag, indent);
101 try stream.print("{}", tree.tokenSlice(tag.name_token));
102
103 try stack.push(RenderState { .Text = "," });
104
105 if (tag.value_expr) |value_expr| {
106 try stack.push(RenderState { .Expression = value_expr });
107 try stack.push(RenderState { .Text = " = " });
108 }
109
110 if (tag.type_expr) |type_expr| {
111 try stream.print(": ");
112 try stack.push(RenderState { .Expression = type_expr});
113 }
114 },
115 ast.Node.Id.EnumTag => {
116 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
117 try renderComments(tree, stream, tag, indent);
118 try stream.print("{}", tree.tokenSlice(tag.name_token));
119
120 try stack.push(RenderState { .Text = "," });
121 if (tag.value) |value| {
122 try stream.print(" = ");
123 try stack.push(RenderState { .Expression = value});
124 }
125 },
126 ast.Node.Id.ErrorTag => {
127 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
128 try renderComments(tree, stream, tag, indent);
129 try stream.print("{}", tree.tokenSlice(tag.name_token));
130 },
131 ast.Node.Id.Comptime => {
132 if (decl.requireSemiColon()) {
133 try stack.push(RenderState { .Text = ";" });
134 }
135 try stack.push(RenderState { .Expression = decl });
136 },
137 ast.Node.Id.LineComment => {
138 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
139 try stream.write(tree.tokenSlice(line_comment_node.token));
140 },
141 else => unreachable,
142 }
143 },
144
145 RenderState.VarDecl => |var_decl| {
146 try stack.push(RenderState { .Text = ";" });
147 if (var_decl.init_node) |init_node| {
148 try stack.push(RenderState { .Expression = init_node });
149 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
150 try stack.push(RenderState { .Text = text });
151 }
152 if (var_decl.align_node) |align_node| {
153 try stack.push(RenderState { .Text = ")" });
154 try stack.push(RenderState { .Expression = align_node });
155 try stack.push(RenderState { .Text = " align(" });
156 }
157 if (var_decl.type_node) |type_node| {
158 try stack.push(RenderState { .Expression = type_node });
159 try stack.push(RenderState { .Text = ": " });
160 }
161 try stack.push(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
162 try stack.push(RenderState { .Text = " " });
163 try stack.push(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
164
165 if (var_decl.comptime_token) |comptime_token| {
166 try stack.push(RenderState { .Text = " " });
167 try stack.push(RenderState { .Text = tree.tokenSlice(comptime_token) });
168 }
169
170 if (var_decl.extern_export_token) |extern_export_token| {
171 if (var_decl.lib_name != null) {
172 try stack.push(RenderState { .Text = " " });
173 try stack.push(RenderState { .Expression = ??var_decl.lib_name });
174 }
175 try stack.push(RenderState { .Text = " " });
176 try stack.push(RenderState { .Text = tree.tokenSlice(extern_export_token) });
177 }
178
179 if (var_decl.visib_token) |visib_token| {
180 try stack.push(RenderState { .Text = " " });
181 try stack.push(RenderState { .Text = tree.tokenSlice(visib_token) });
182 }
183 },
184
185 RenderState.ParamDecl => |base| {
186 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
187 if (param_decl.comptime_token) |comptime_token| {
188 try stream.print("{} ", tree.tokenSlice(comptime_token));
189 }
190 if (param_decl.noalias_token) |noalias_token| {
191 try stream.print("{} ", tree.tokenSlice(noalias_token));
192 }
193 if (param_decl.name_token) |name_token| {
194 try stream.print("{}: ", tree.tokenSlice(name_token));
195 }
196 if (param_decl.var_args_token) |var_args_token| {
197 try stream.print("{}", tree.tokenSlice(var_args_token));
198 } else {
199 try stack.push(RenderState { .Expression = param_decl.type_node});
200 }
201 },
202 RenderState.Text => |bytes| {
203 try stream.write(bytes);
204 },
205 RenderState.Expression => |base| switch (base.id) {
206 ast.Node.Id.Identifier => {
207 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
208 try stream.print("{}", tree.tokenSlice(identifier.token));
209 },
210 ast.Node.Id.Block => {
211 const block = @fieldParentPtr(ast.Node.Block, "base", base);
212 if (block.label) |label| {
213 try stream.print("{}: ", tree.tokenSlice(label));
214 }
215
216 if (block.statements.len == 0) {
217 try stream.write("{}");
218 } else {
219 try stream.write("{");
220 try stack.push(RenderState { .Text = "}"});
221 try stack.push(RenderState.PrintIndent);
222 try stack.push(RenderState { .Indent = indent});
223 try stack.push(RenderState { .Text = "\n"});
224 var i = block.statements.len;
225 while (i != 0) {
226 i -= 1;
227 const statement_node = *block.statements.at(i);
228 try stack.push(RenderState { .Statement = statement_node});
229 try stack.push(RenderState.PrintIndent);
230 try stack.push(RenderState { .Indent = indent + indent_delta});
231 try stack.push(RenderState {
232 .Text = blk: {
233 if (i != 0) {
234 const prev_node = *block.statements.at(i - 1);
235 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
236 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());
237 if (loc.line >= 2) {
238 break :blk "\n\n";
239 }
240 }
241 break :blk "\n";
242 },
243 });
244 }
245 }
246 },
247 ast.Node.Id.Defer => {
248 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
249 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
250 try stack.push(RenderState { .Expression = defer_node.expr });
251 },
252 ast.Node.Id.Comptime => {
253 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
254 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
255 try stack.push(RenderState { .Expression = comptime_node.expr });
256 },
257 ast.Node.Id.AsyncAttribute => {
258 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
259 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
260
261 if (async_attr.allocator_type) |allocator_type| {
262 try stack.push(RenderState { .Text = ">" });
263 try stack.push(RenderState { .Expression = allocator_type });
264 try stack.push(RenderState { .Text = "<" });
265 }
266 },
267 ast.Node.Id.Suspend => {
268 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
269 if (suspend_node.label) |label| {
270 try stream.print("{}: ", tree.tokenSlice(label));
271 }
272 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
273
274 if (suspend_node.body) |body| {
275 try stack.push(RenderState { .Expression = body });
276 try stack.push(RenderState { .Text = " " });
277 }
278
279 if (suspend_node.payload) |payload| {
280 try stack.push(RenderState { .Expression = payload });
281 try stack.push(RenderState { .Text = " " });
282 }
283 },
284 ast.Node.Id.InfixOp => {
285 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
286 try stack.push(RenderState { .Expression = prefix_op_node.rhs });
287
288 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
289 if (prefix_op_node.op.Catch) |payload| {
290 try stack.push(RenderState { .Text = " " });
291 try stack.push(RenderState { .Expression = payload });
292 }
293 try stack.push(RenderState { .Text = " catch " });
294 } else {
295 const text = switch (prefix_op_node.op) {
296 ast.Node.InfixOp.Op.Add => " + ",
297 ast.Node.InfixOp.Op.AddWrap => " +% ",
298 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
299 ast.Node.InfixOp.Op.ArrayMult => " ** ",
300 ast.Node.InfixOp.Op.Assign => " = ",
301 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
302 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
303 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
304 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
305 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
306 ast.Node.InfixOp.Op.AssignDiv => " /= ",
307 ast.Node.InfixOp.Op.AssignMinus => " -= ",
308 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
309 ast.Node.InfixOp.Op.AssignMod => " %= ",
310 ast.Node.InfixOp.Op.AssignPlus => " += ",
311 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
312 ast.Node.InfixOp.Op.AssignTimes => " *= ",
313 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
314 ast.Node.InfixOp.Op.BangEqual => " != ",
315 ast.Node.InfixOp.Op.BitAnd => " & ",
316 ast.Node.InfixOp.Op.BitOr => " | ",
317 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
318 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
319 ast.Node.InfixOp.Op.BitXor => " ^ ",
320 ast.Node.InfixOp.Op.BoolAnd => " and ",
321 ast.Node.InfixOp.Op.BoolOr => " or ",
322 ast.Node.InfixOp.Op.Div => " / ",
323 ast.Node.InfixOp.Op.EqualEqual => " == ",
324 ast.Node.InfixOp.Op.ErrorUnion => "!",
325 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
326 ast.Node.InfixOp.Op.GreaterThan => " > ",
327 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
328 ast.Node.InfixOp.Op.LessThan => " < ",
329 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
330 ast.Node.InfixOp.Op.Mod => " % ",
331 ast.Node.InfixOp.Op.Mult => " * ",
332 ast.Node.InfixOp.Op.MultWrap => " *% ",
333 ast.Node.InfixOp.Op.Period => ".",
334 ast.Node.InfixOp.Op.Sub => " - ",
335 ast.Node.InfixOp.Op.SubWrap => " -% ",
336 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
337 ast.Node.InfixOp.Op.Range => " ... ",
338 ast.Node.InfixOp.Op.Catch => unreachable,
339 };
340
341 try stack.push(RenderState { .Text = text });
342 }
343 try stack.push(RenderState { .Expression = prefix_op_node.lhs });
344 },
345 ast.Node.Id.PrefixOp => {
346 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
347 try stack.push(RenderState { .Expression = prefix_op_node.rhs });
348 switch (prefix_op_node.op) {
349 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
350 try stream.write("&");
351 if (addr_of_info.volatile_token != null) {
352 try stack.push(RenderState { .Text = "volatile "});
353 }
354 if (addr_of_info.const_token != null) {
355 try stack.push(RenderState { .Text = "const "});
356 }
357 if (addr_of_info.align_expr) |align_expr| {
358 try stream.print("align(");
359 try stack.push(RenderState { .Text = ") "});
360 try stack.push(RenderState { .Expression = align_expr});
361 }
362 },
363 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
364 try stream.write("[]");
365 if (addr_of_info.volatile_token != null) {
366 try stack.push(RenderState { .Text = "volatile "});
367 }
368 if (addr_of_info.const_token != null) {
369 try stack.push(RenderState { .Text = "const "});
370 }
371 if (addr_of_info.align_expr) |align_expr| {
372 try stream.print("align(");
373 try stack.push(RenderState { .Text = ") "});
374 try stack.push(RenderState { .Expression = align_expr});
375 }
376 },
377 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
378 try stack.push(RenderState { .Text = "]"});
379 try stack.push(RenderState { .Expression = array_index});
380 try stack.push(RenderState { .Text = "["});
381 },
382 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
383 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
384 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
385 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
386 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
387 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
388 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
389 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
390 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
391 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
392 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
393 }
394 },
395 ast.Node.Id.SuffixOp => {
396 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
397
398 switch (suffix_op.op) {
399 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
400 try stack.push(RenderState { .Text = ")"});
401 var i = call_info.params.len;
402 while (i != 0) {
403 i -= 1;
404 const param_node = *call_info.params.at(i);
405 try stack.push(RenderState { .Expression = param_node});
406 if (i != 0) {
407 try stack.push(RenderState { .Text = ", " });
408 }
409 }
410 try stack.push(RenderState { .Text = "("});
411 try stack.push(RenderState { .Expression = suffix_op.lhs });
412
413 if (call_info.async_attr) |async_attr| {
414 try stack.push(RenderState { .Text = " "});
415 try stack.push(RenderState { .Expression = &async_attr.base });
416 }
417 },
418 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
419 try stack.push(RenderState { .Text = "]"});
420 try stack.push(RenderState { .Expression = index_expr});
421 try stack.push(RenderState { .Text = "["});
422 try stack.push(RenderState { .Expression = suffix_op.lhs });
423 },
424 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
425 try stack.push(RenderState { .Text = "]"});
426 if (range.end) |end| {
427 try stack.push(RenderState { .Expression = end});
428 }
429 try stack.push(RenderState { .Text = ".."});
430 try stack.push(RenderState { .Expression = range.start});
431 try stack.push(RenderState { .Text = "["});
432 try stack.push(RenderState { .Expression = suffix_op.lhs });
433 },
434 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
435 if (field_inits.len == 0) {
436 try stack.push(RenderState { .Text = "{}" });
437 try stack.push(RenderState { .Expression = suffix_op.lhs });
438 continue;
439 }
440 if (field_inits.len == 1) {
441 const field_init = *field_inits.at(0);
442
443 try stack.push(RenderState { .Text = " }" });
444 try stack.push(RenderState { .Expression = field_init });
445 try stack.push(RenderState { .Text = "{ " });
446 try stack.push(RenderState { .Expression = suffix_op.lhs });
447 continue;
448 }
449 try stack.push(RenderState { .Text = "}"});
450 try stack.push(RenderState.PrintIndent);
451 try stack.push(RenderState { .Indent = indent });
452 try stack.push(RenderState { .Text = "\n" });
453 var i = field_inits.len;
454 while (i != 0) {
455 i -= 1;
456 const field_init = *field_inits.at(i);
457 if (field_init.id != ast.Node.Id.LineComment) {
458 try stack.push(RenderState { .Text = "," });
459 }
460 try stack.push(RenderState { .Expression = field_init });
461 try stack.push(RenderState.PrintIndent);
462 if (i != 0) {
463 try stack.push(RenderState { .Text = blk: {
464 const prev_node = *field_inits.at(i - 1);
465 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
466 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
467 if (loc.line >= 2) {
468 break :blk "\n\n";
469 }
470 break :blk "\n";
471 }});
472 }
473 }
474 try stack.push(RenderState { .Indent = indent + indent_delta });
475 try stack.push(RenderState { .Text = "{\n"});
476 try stack.push(RenderState { .Expression = suffix_op.lhs });
477 },
478 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
479 if (exprs.len == 0) {
480 try stack.push(RenderState { .Text = "{}" });
481 try stack.push(RenderState { .Expression = suffix_op.lhs });
482 continue;
483 }
484 if (exprs.len == 1) {
485 const expr = *exprs.at(0);
486
487 try stack.push(RenderState { .Text = "}" });
488 try stack.push(RenderState { .Expression = expr });
489 try stack.push(RenderState { .Text = "{" });
490 try stack.push(RenderState { .Expression = suffix_op.lhs });
491 continue;
492 }
493
494 try stack.push(RenderState { .Text = "}"});
495 try stack.push(RenderState.PrintIndent);
496 try stack.push(RenderState { .Indent = indent });
497 var i = exprs.len;
498 while (i != 0) {
499 i -= 1;
500 const expr = *exprs.at(i);
501 try stack.push(RenderState { .Text = ",\n" });
502 try stack.push(RenderState { .Expression = expr });
503 try stack.push(RenderState.PrintIndent);
504 }
505 try stack.push(RenderState { .Indent = indent + indent_delta });
506 try stack.push(RenderState { .Text = "{\n"});
507 try stack.push(RenderState { .Expression = suffix_op.lhs });
508 },
509 }
510 },
511 ast.Node.Id.ControlFlowExpression => {
512 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
513
514 if (flow_expr.rhs) |rhs| {
515 try stack.push(RenderState { .Expression = rhs });
516 try stack.push(RenderState { .Text = " " });
517 }
518
519 switch (flow_expr.kind) {
520 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
521 try stream.print("break");
522 if (maybe_label) |label| {
523 try stream.print(" :");
524 try stack.push(RenderState { .Expression = label });
525 }
526 },
527 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
528 try stream.print("continue");
529 if (maybe_label) |label| {
530 try stream.print(" :");
531 try stack.push(RenderState { .Expression = label });
532 }
533 },
534 ast.Node.ControlFlowExpression.Kind.Return => {
535 try stream.print("return");
536 },
537
538 }
539 },
540 ast.Node.Id.Payload => {
541 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
542 try stack.push(RenderState { .Text = "|"});
543 try stack.push(RenderState { .Expression = payload.error_symbol });
544 try stack.push(RenderState { .Text = "|"});
545 },
546 ast.Node.Id.PointerPayload => {
547 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
548 try stack.push(RenderState { .Text = "|"});
549 try stack.push(RenderState { .Expression = payload.value_symbol });
550
551 if (payload.ptr_token) |ptr_token| {
552 try stack.push(RenderState { .Text = tree.tokenSlice(ptr_token) });
553 }
554
555 try stack.push(RenderState { .Text = "|"});
556 },
557 ast.Node.Id.PointerIndexPayload => {
558 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
559 try stack.push(RenderState { .Text = "|"});
560
561 if (payload.index_symbol) |index_symbol| {
562 try stack.push(RenderState { .Expression = index_symbol });
563 try stack.push(RenderState { .Text = ", "});
564 }
565
566 try stack.push(RenderState { .Expression = payload.value_symbol });
567
568 if (payload.ptr_token) |ptr_token| {
569 try stack.push(RenderState { .Text = tree.tokenSlice(ptr_token) });
570 }
571
572 try stack.push(RenderState { .Text = "|"});
573 },
574 ast.Node.Id.GroupedExpression => {
575 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
576 try stack.push(RenderState { .Text = ")"});
577 try stack.push(RenderState { .Expression = grouped_expr.expr });
578 try stack.push(RenderState { .Text = "("});
579 },
580 ast.Node.Id.FieldInitializer => {
581 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
582 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
583 try stack.push(RenderState { .Expression = field_init.expr });
584 },
585 ast.Node.Id.IntegerLiteral => {
586 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
587 try stream.print("{}", tree.tokenSlice(integer_literal.token));
588 },
589 ast.Node.Id.FloatLiteral => {
590 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
591 try stream.print("{}", tree.tokenSlice(float_literal.token));
592 },
593 ast.Node.Id.StringLiteral => {
594 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
595 try stream.print("{}", tree.tokenSlice(string_literal.token));
596 },
597 ast.Node.Id.CharLiteral => {
598 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
599 try stream.print("{}", tree.tokenSlice(char_literal.token));
600 },
601 ast.Node.Id.BoolLiteral => {
602 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
603 try stream.print("{}", tree.tokenSlice(bool_literal.token));
604 },
605 ast.Node.Id.NullLiteral => {
606 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
607 try stream.print("{}", tree.tokenSlice(null_literal.token));
608 },
609 ast.Node.Id.ThisLiteral => {
610 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
611 try stream.print("{}", tree.tokenSlice(this_literal.token));
612 },
613 ast.Node.Id.Unreachable => {
614 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
615 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
616 },
617 ast.Node.Id.ErrorType => {
618 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
619 try stream.print("{}", tree.tokenSlice(error_type.token));
620 },
621 ast.Node.Id.VarType => {
622 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
623 try stream.print("{}", tree.tokenSlice(var_type.token));
624 },
625 ast.Node.Id.ContainerDecl => {
626 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
627
628 switch (container_decl.layout) {
629 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
630 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
631 ast.Node.ContainerDecl.Layout.Auto => { },
632 }
633
634 switch (container_decl.kind) {
635 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
636 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
637 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
638 }
639
640 if (container_decl.fields_and_decls.len == 0) {
641 try stack.push(RenderState { .Text = "{}"});
642 } else {
643 try stack.push(RenderState { .Text = "}"});
644 try stack.push(RenderState.PrintIndent);
645 try stack.push(RenderState { .Indent = indent });
646 try stack.push(RenderState { .Text = "\n"});
647
648 var i = container_decl.fields_and_decls.len;
649 while (i != 0) {
650 i -= 1;
651 const node = *container_decl.fields_and_decls.at(i);
652 try stack.push(RenderState { .TopLevelDecl = node});
653 try stack.push(RenderState.PrintIndent);
654 try stack.push(RenderState {
655 .Text = blk: {
656 if (i != 0) {
657 const prev_node = *container_decl.fields_and_decls.at(i - 1);
658 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
659 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
660 if (loc.line >= 2) {
661 break :blk "\n\n";
662 }
663 }
664 break :blk "\n";
665 },
666 });
667 }
668 try stack.push(RenderState { .Indent = indent + indent_delta});
669 try stack.push(RenderState { .Text = "{"});
670 }
671
672 switch (container_decl.init_arg_expr) {
673 ast.Node.ContainerDecl.InitArg.None => try stack.push(RenderState { .Text = " "}),
674 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
675 if (enum_tag_type) |expr| {
676 try stack.push(RenderState { .Text = ")) "});
677 try stack.push(RenderState { .Expression = expr});
678 try stack.push(RenderState { .Text = "(enum("});
679 } else {
680 try stack.push(RenderState { .Text = "(enum) "});
681 }
682 },
683 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
684 try stack.push(RenderState { .Text = ") "});
685 try stack.push(RenderState { .Expression = type_expr});
686 try stack.push(RenderState { .Text = "("});
687 },
688 }
689 },
690 ast.Node.Id.ErrorSetDecl => {
691 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
692
693 if (err_set_decl.decls.len == 0) {
694 try stream.write("error{}");
695 continue;
696 }
697
698 if (err_set_decl.decls.len == 1) blk: {
699 const node = *err_set_decl.decls.at(0);
700
701 // if there are any doc comments or same line comments
702 // don't try to put it all on one line
703 if (node.cast(ast.Node.ErrorTag)) |tag| {
704 if (tag.doc_comments != null) break :blk;
705 } else {
706 break :blk;
707 }
708
709
710 try stream.write("error{");
711 try stack.push(RenderState { .Text = "}" });
712 try stack.push(RenderState { .TopLevelDecl = node });
713 continue;
714 }
715
716 try stream.write("error{");
717
718 try stack.push(RenderState { .Text = "}"});
719 try stack.push(RenderState.PrintIndent);
720 try stack.push(RenderState { .Indent = indent });
721 try stack.push(RenderState { .Text = "\n"});
722
723 var i = err_set_decl.decls.len;
724 while (i != 0) {
725 i -= 1;
726 const node = *err_set_decl.decls.at(i);
727 if (node.id != ast.Node.Id.LineComment) {
728 try stack.push(RenderState { .Text = "," });
729 }
730 try stack.push(RenderState { .TopLevelDecl = node });
731 try stack.push(RenderState.PrintIndent);
732 try stack.push(RenderState {
733 .Text = blk: {
734 if (i != 0) {
735 const prev_node = *err_set_decl.decls.at(i - 1);
736 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
737 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
738 if (loc.line >= 2) {
739 break :blk "\n\n";
740 }
741 }
742 break :blk "\n";
743 },
744 });
745 }
746 try stack.push(RenderState { .Indent = indent + indent_delta});
747 },
748 ast.Node.Id.MultilineStringLiteral => {
749 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
750 try stream.print("\n");
751
752 var i : usize = 0;
753 while (i < multiline_str_literal.lines.len) : (i += 1) {
754 const t = *multiline_str_literal.lines.at(i);
755 try stream.writeByteNTimes(' ', indent + indent_delta);
756 try stream.print("{}", tree.tokenSlice(t));
757 }
758 try stream.writeByteNTimes(' ', indent);
759 },
760 ast.Node.Id.UndefinedLiteral => {
761 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
762 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
763 },
764 ast.Node.Id.BuiltinCall => {
765 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
766 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
767 try stack.push(RenderState { .Text = ")"});
768 var i = builtin_call.params.len;
769 while (i != 0) {
770 i -= 1;
771 const param_node = *builtin_call.params.at(i);
772 try stack.push(RenderState { .Expression = param_node});
773 if (i != 0) {
774 try stack.push(RenderState { .Text = ", " });
775 }
776 }
777 },
778 ast.Node.Id.FnProto => {
779 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
780
781 switch (fn_proto.return_type) {
782 ast.Node.FnProto.ReturnType.Explicit => |node| {
783 try stack.push(RenderState { .Expression = node});
784 },
785 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
786 try stack.push(RenderState { .Expression = node});
787 try stack.push(RenderState { .Text = "!"});
788 },
789 }
790
791 if (fn_proto.align_expr) |align_expr| {
792 try stack.push(RenderState { .Text = ") " });
793 try stack.push(RenderState { .Expression = align_expr});
794 try stack.push(RenderState { .Text = "align(" });
795 }
796
797 try stack.push(RenderState { .Text = ") " });
798 var i = fn_proto.params.len;
799 while (i != 0) {
800 i -= 1;
801 const param_decl_node = *fn_proto.params.at(i);
802 try stack.push(RenderState { .ParamDecl = param_decl_node});
803 if (i != 0) {
804 try stack.push(RenderState { .Text = ", " });
805 }
806 }
807
808 try stack.push(RenderState { .Text = "(" });
809 if (fn_proto.name_token) |name_token| {
810 try stack.push(RenderState { .Text = tree.tokenSlice(name_token) });
811 try stack.push(RenderState { .Text = " " });
812 }
813
814 try stack.push(RenderState { .Text = "fn" });
815
816 if (fn_proto.async_attr) |async_attr| {
817 try stack.push(RenderState { .Text = " " });
818 try stack.push(RenderState { .Expression = &async_attr.base });
819 }
820
821 if (fn_proto.cc_token) |cc_token| {
822 try stack.push(RenderState { .Text = " " });
823 try stack.push(RenderState { .Text = tree.tokenSlice(cc_token) });
824 }
825
826 if (fn_proto.lib_name) |lib_name| {
827 try stack.push(RenderState { .Text = " " });
828 try stack.push(RenderState { .Expression = lib_name });
829 }
830 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
831 try stack.push(RenderState { .Text = " " });
832 try stack.push(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
833 }
834
835 if (fn_proto.visib_token) |visib_token_index| {
836 const visib_token = tree.tokens.at(visib_token_index);
837 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
838 try stack.push(RenderState { .Text = " " });
839 try stack.push(RenderState { .Text = tree.tokenSlice(visib_token_index) });
840 }
841 },
842 ast.Node.Id.PromiseType => {
843 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
844 try stream.write(tree.tokenSlice(promise_type.promise_token));
845 if (promise_type.result) |result| {
846 try stream.write(tree.tokenSlice(result.arrow_token));
847 try stack.push(RenderState { .Expression = result.return_type});
848 }
849 },
850 ast.Node.Id.LineComment => {
851 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
852 try stream.write(tree.tokenSlice(line_comment_node.token));
853 },
854 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
855 ast.Node.Id.Switch => {
856 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
857
858 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
859
860 if (switch_node.cases.len == 0) {
861 try stack.push(RenderState { .Text = ") {}"});
862 try stack.push(RenderState { .Expression = switch_node.expr });
863 continue;
864 }
865
866 try stack.push(RenderState { .Text = "}"});
867 try stack.push(RenderState.PrintIndent);
868 try stack.push(RenderState { .Indent = indent });
869 try stack.push(RenderState { .Text = "\n"});
870
871 var i = switch_node.cases.len;
872 while (i != 0) {
873 i -= 1;
874 const node = *switch_node.cases.at(i);
875 try stack.push(RenderState { .Expression = node});
876 try stack.push(RenderState.PrintIndent);
877 try stack.push(RenderState {
878 .Text = blk: {
879 if (i != 0) {
880 const prev_node = *switch_node.cases.at(i - 1);
881 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
882 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
883 if (loc.line >= 2) {
884 break :blk "\n\n";
885 }
886 }
887 break :blk "\n";
888 },
889 });
890 }
891 try stack.push(RenderState { .Indent = indent + indent_delta});
892 try stack.push(RenderState { .Text = ") {"});
893 try stack.push(RenderState { .Expression = switch_node.expr });
894 },
895 ast.Node.Id.SwitchCase => {
896 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
897
898 try stack.push(RenderState { .Text = "," });
899 try stack.push(RenderState { .Expression = switch_case.expr });
900 if (switch_case.payload) |payload| {
901 try stack.push(RenderState { .Text = " " });
902 try stack.push(RenderState { .Expression = payload });
903 }
904 try stack.push(RenderState { .Text = " => "});
905
906 var i = switch_case.items.len;
907 while (i != 0) {
908 i -= 1;
909 try stack.push(RenderState { .Expression = *switch_case.items.at(i) });
910
911 if (i != 0) {
912 try stack.push(RenderState.PrintIndent);
913 try stack.push(RenderState { .Text = ",\n" });
914 }
915 }
916 },
917 ast.Node.Id.SwitchElse => {
918 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
919 try stream.print("{}", tree.tokenSlice(switch_else.token));
920 },
921 ast.Node.Id.Else => {
922 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
923 try stream.print("{}", tree.tokenSlice(else_node.else_token));
924
925 switch (else_node.body.id) {
926 ast.Node.Id.Block, ast.Node.Id.If,
927 ast.Node.Id.For, ast.Node.Id.While,
928 ast.Node.Id.Switch => {
929 try stream.print(" ");
930 try stack.push(RenderState { .Expression = else_node.body });
931 },
932 else => {
933 try stack.push(RenderState { .Indent = indent });
934 try stack.push(RenderState { .Expression = else_node.body });
935 try stack.push(RenderState.PrintIndent);
936 try stack.push(RenderState { .Indent = indent + indent_delta });
937 try stack.push(RenderState { .Text = "\n" });
938 }
939 }
940
941 if (else_node.payload) |payload| {
942 try stack.push(RenderState { .Text = " " });
943 try stack.push(RenderState { .Expression = payload });
944 }
945 },
946 ast.Node.Id.While => {
947 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
948 if (while_node.label) |label| {
949 try stream.print("{}: ", tree.tokenSlice(label));
950 }
951
952 if (while_node.inline_token) |inline_token| {
953 try stream.print("{} ", tree.tokenSlice(inline_token));
954 }
955
956 try stream.print("{} ", tree.tokenSlice(while_node.while_token));
957
958 if (while_node.@"else") |@"else"| {
959 try stack.push(RenderState { .Expression = &@"else".base });
960
961 if (while_node.body.id == ast.Node.Id.Block) {
962 try stack.push(RenderState { .Text = " " });
963 } else {
964 try stack.push(RenderState.PrintIndent);
965 try stack.push(RenderState { .Text = "\n" });
966 }
967 }
968
969 if (while_node.body.id == ast.Node.Id.Block) {
970 try stack.push(RenderState { .Expression = while_node.body });
971 try stack.push(RenderState { .Text = " " });
972 } else {
973 try stack.push(RenderState { .Indent = indent });
974 try stack.push(RenderState { .Expression = while_node.body });
975 try stack.push(RenderState.PrintIndent);
976 try stack.push(RenderState { .Indent = indent + indent_delta });
977 try stack.push(RenderState { .Text = "\n" });
978 }
979
980 if (while_node.continue_expr) |continue_expr| {
981 try stack.push(RenderState { .Text = ")" });
982 try stack.push(RenderState { .Expression = continue_expr });
983 try stack.push(RenderState { .Text = ": (" });
984 try stack.push(RenderState { .Text = " " });
985 }
986
987 if (while_node.payload) |payload| {
988 try stack.push(RenderState { .Expression = payload });
989 try stack.push(RenderState { .Text = " " });
990 }
991
992 try stack.push(RenderState { .Text = ")" });
993 try stack.push(RenderState { .Expression = while_node.condition });
994 try stack.push(RenderState { .Text = "(" });
995 },
996 ast.Node.Id.For => {
997 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
998 if (for_node.label) |label| {
999 try stream.print("{}: ", tree.tokenSlice(label));
1000 }
1001
1002 if (for_node.inline_token) |inline_token| {
1003 try stream.print("{} ", tree.tokenSlice(inline_token));
1004 }
1005
1006 try stream.print("{} ", tree.tokenSlice(for_node.for_token));
1007
1008 if (for_node.@"else") |@"else"| {
1009 try stack.push(RenderState { .Expression = &@"else".base });
1010
1011 if (for_node.body.id == ast.Node.Id.Block) {
1012 try stack.push(RenderState { .Text = " " });
1013 } else {
1014 try stack.push(RenderState.PrintIndent);
1015 try stack.push(RenderState { .Text = "\n" });
1016 }
1017 }
1018
1019 if (for_node.body.id == ast.Node.Id.Block) {
1020 try stack.push(RenderState { .Expression = for_node.body });
1021 try stack.push(RenderState { .Text = " " });
1022 } else {
1023 try stack.push(RenderState { .Indent = indent });
1024 try stack.push(RenderState { .Expression = for_node.body });
1025 try stack.push(RenderState.PrintIndent);
1026 try stack.push(RenderState { .Indent = indent + indent_delta });
1027 try stack.push(RenderState { .Text = "\n" });
1028 }
1029
1030 if (for_node.payload) |payload| {
1031 try stack.push(RenderState { .Expression = payload });
1032 try stack.push(RenderState { .Text = " " });
1033 }
1034
1035 try stack.push(RenderState { .Text = ")" });
1036 try stack.push(RenderState { .Expression = for_node.array_expr });
1037 try stack.push(RenderState { .Text = "(" });
1038 },
1039 ast.Node.Id.If => {
1040 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1041 try stream.print("{} ", tree.tokenSlice(if_node.if_token));
1042
1043 switch (if_node.body.id) {
1044 ast.Node.Id.Block, ast.Node.Id.If,
1045 ast.Node.Id.For, ast.Node.Id.While,
1046 ast.Node.Id.Switch => {
1047 if (if_node.@"else") |@"else"| {
1048 try stack.push(RenderState { .Expression = &@"else".base });
1049
1050 if (if_node.body.id == ast.Node.Id.Block) {
1051 try stack.push(RenderState { .Text = " " });
1052 } else {
1053 try stack.push(RenderState.PrintIndent);
1054 try stack.push(RenderState { .Text = "\n" });
1055 }
1056 }
1057 },
1058 else => {
1059 if (if_node.@"else") |@"else"| {
1060 try stack.push(RenderState { .Expression = @"else".body });
1061
1062 if (@"else".payload) |payload| {
1063 try stack.push(RenderState { .Text = " " });
1064 try stack.push(RenderState { .Expression = payload });
1065 }
1066
1067 try stack.push(RenderState { .Text = " " });
1068 try stack.push(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
1069 try stack.push(RenderState { .Text = " " });
1070 }
1071 }
1072 }
1073
1074 try stack.push(RenderState { .Expression = if_node.body });
1075 try stack.push(RenderState { .Text = " " });
1076
1077 if (if_node.payload) |payload| {
1078 try stack.push(RenderState { .Expression = payload });
1079 try stack.push(RenderState { .Text = " " });
1080 }
1081
1082 try stack.push(RenderState { .Text = ")" });
1083 try stack.push(RenderState { .Expression = if_node.condition });
1084 try stack.push(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.push(RenderState { .Indent = indent });
1095 try stack.push(RenderState { .Text = ")" });
1096 {
1097 var i = asm_node.clobbers.len;
1098 while (i != 0) {
1099 i -= 1;
1100 try stack.push(RenderState { .Expression = *asm_node.clobbers.at(i) });
1101
1102 if (i != 0) {
1103 try stack.push(RenderState { .Text = ", " });
1104 }
1105 }
1106 }
1107 try stack.push(RenderState { .Text = ": " });
1108 try stack.push(RenderState.PrintIndent);
1109 try stack.push(RenderState { .Indent = indent + indent_delta });
1110 try stack.push(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.push(RenderState { .Expression = &node.base});
1117
1118 if (i != 0) {
1119 try stack.push(RenderState.PrintIndent);
1120 try stack.push(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.push(RenderState { .Text = "," });
1132 }
1133 }
1134 }
1135 try stack.push(RenderState { .Indent = indent + indent_delta + 2});
1136 try stack.push(RenderState { .Text = ": "});
1137 try stack.push(RenderState.PrintIndent);
1138 try stack.push(RenderState { .Indent = indent + indent_delta});
1139 try stack.push(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.push(RenderState { .Expression = &node.base});
1146
1147 if (i != 0) {
1148 try stack.push(RenderState.PrintIndent);
1149 try stack.push(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.push(RenderState { .Text = "," });
1161 }
1162 }
1163 }
1164 try stack.push(RenderState { .Indent = indent + indent_delta + 2});
1165 try stack.push(RenderState { .Text = ": "});
1166 try stack.push(RenderState.PrintIndent);
1167 try stack.push(RenderState { .Indent = indent + indent_delta});
1168 try stack.push(RenderState { .Text = "\n" });
1169 try stack.push(RenderState { .Expression = asm_node.template });
1170 try stack.push(RenderState { .Text = "(" });
1171 },
1172 ast.Node.Id.AsmInput => {
1173 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1174
1175 try stack.push(RenderState { .Text = ")"});
1176 try stack.push(RenderState { .Expression = asm_input.expr});
1177 try stack.push(RenderState { .Text = " ("});
1178 try stack.push(RenderState { .Expression = asm_input.constraint });
1179 try stack.push(RenderState { .Text = "] "});
1180 try stack.push(RenderState { .Expression = asm_input.symbolic_name });
1181 try stack.push(RenderState { .Text = "["});
1182 },
1183 ast.Node.Id.AsmOutput => {
1184 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1185
1186 try stack.push(RenderState { .Text = ")"});
1187 switch (asm_output.kind) {
1188 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1189 try stack.push(RenderState { .Expression = &variable_name.base});
1190 },
1191 ast.Node.AsmOutput.Kind.Return => |return_type| {
1192 try stack.push(RenderState { .Expression = return_type});
1193 try stack.push(RenderState { .Text = "-> "});
1194 },
1195 }
1196 try stack.push(RenderState { .Text = " ("});
1197 try stack.push(RenderState { .Expression = asm_output.constraint });
1198 try stack.push(RenderState { .Text = "] "});
1199 try stack.push(RenderState { .Expression = asm_output.symbolic_name });
1200 try stack.push(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.push(RenderState { .VarDecl = var_decl});
1218 },
1219 else => {
1220 if (base.requireSemiColon()) {
1221 try stack.push(RenderState { .Text = ";" });
1222 }
1223 try stack.push(RenderState { .Expression = base });
1224 },
1225 }
1226 },
1227 RenderState.Indent => |new_indent| indent = new_indent,
1228 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
1229 }
1230 }
1231}
1232
1233fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {
1234 const comment = node.doc_comments ?? return;
1235 var it = comment.lines.iterator(0);
1236 while (it.next()) |line_token_index| {
1237 try stream.print("{}\n", tree.tokenSlice(*line_token_index));
1238 try stream.writeByteNTimes(' ', indent);
1239 }
1240}
1241