authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-13 13:38:03-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-13 13:38:03-04:00
log86a352c45bb654951529660b2e6cbbfa72773170
treee7a4f5760918ec54bf247e9c23dc7e29d1d7c459
parent4787127cf6418f7a819c9d6f07a9046d76e0de65
parent05ecb49bac30041459ae08764edd2aced23d10eb

Merge branch 'master' into pointer-reform


26 files changed, 5793 insertions(+), 5185 deletions(-)

CMakeLists.txt+2-1
......@@ -576,7 +576,8 @@ set(ZIG_STD_FILES
576576 "unicode.zig"
577577 "zig/ast.zig"
578578 "zig/index.zig"
579 "zig/parser.zig"
579 "zig/parse.zig"
580 "zig/render.zig"
580581 "zig/tokenizer.zig"
581582)
582583
README.md+2-2
......@@ -1,9 +1,9 @@
1![ZIG](http://ziglang.org/zig-logo.svg)
1![ZIG](https://ziglang.org/zig-logo.svg)
22
33A programming language designed for robustness, optimality, and
44clarity.
55
6[ziglang.org](http://ziglang.org)
6[ziglang.org](https://ziglang.org)
77
88## Feature Highlights
99
doc/langref.html.in+44-3
......@@ -4485,17 +4485,58 @@ mem.set(u8, dest, c);</code></pre>
44854485 If no overflow or underflow occurs, returns <code>false</code>.
44864486 </p>
44874487 {#header_close#}
4488 {#header_open|@newStackCall#}
4489 <pre><code class="zig">@newStackCall(new_stack: []u8, function: var, args: ...) -&gt; var</code></pre>
4490 <p>
4491 This calls a function, in the same way that invoking an expression with parentheses does. However,
4492 instead of using the same stack as the caller, the function uses the stack provided in the <code>new_stack</code>
4493 parameter.
4494 </p>
4495 {#code_begin|test#}
4496const std = @import("std");
4497const assert = std.debug.assert;
4498
4499var new_stack_bytes: [1024]u8 = undefined;
4500
4501test "calling a function with a new stack" {
4502 const arg = 1234;
4503
4504 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
4505 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
4506 _ = targetFunction(arg);
4507
4508 assert(arg == 1234);
4509 assert(a < b);
4510}
4511
4512fn targetFunction(x: i32) usize {
4513 assert(x == 1234);
4514
4515 var local_variable: i32 = 42;
4516 const ptr = &local_variable;
4517 *ptr += 1;
4518
4519 assert(local_variable == 43);
4520 return @ptrToInt(ptr);
4521}
4522 {#code_end#}
4523 {#header_close#}
44884524 {#header_open|@noInlineCall#}
44894525 <pre><code class="zig">@noInlineCall(function: var, args: ...) -&gt; var</code></pre>
44904526 <p>
44914527 This calls a function, in the same way that invoking an expression with parentheses does:
44924528 </p>
4493 <pre><code class="zig">const assert = @import("std").debug.assert;
4529 {#code_begin|test#}
4530const assert = @import("std").debug.assert;
4531
44944532test "noinline function call" {
44954533 assert(@noInlineCall(add, 3, 9) == 12);
44964534}
44974535
4498fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
4536fn add(a: i32, b: i32) i32 {
4537 return a + b;
4538}
4539 {#code_end#}
44994540 <p>
45004541 Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call
45014542 will not be inlined. If the call must be inlined, a compile error is emitted.
......@@ -6453,7 +6494,7 @@ hljs.registerLanguage("zig", function(t) {
64536494 a = t.IR + "\\s*\\(",
64546495 c = {
64556496 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
6456 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
6497 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo newStackCall",
64576498 literal: "true false null undefined"
64586499 },
64596500 n = [e, t.CLCM, t.CBCM, s, r];
src-self-hosted/main.zig+30-20
......@@ -637,14 +637,12 @@ const usage_fmt =
637637 \\
638638 \\Options:
639639 \\ --help Print this help and exit
640 \\ --keep-backups Retain backup entries for every file
641640 \\
642641 \\
643642 ;
644643
645644const args_fmt_spec = []Flag {
646645 Flag.Bool("--help"),
647 Flag.Bool("--keep-backups"),
648646};
649647
650648fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
......@@ -671,34 +669,46 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
671669 };
672670 defer allocator.free(source_code);
673671
674 var tokenizer = std.zig.Tokenizer.init(source_code);
675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
676 defer parser.deinit();
677
678 var tree = parser.parse() catch |err| {
672 var tree = std.zig.parse(allocator, source_code) catch |err| {
679673 try stderr.print("error parsing file '{}': {}\n", file_path, err);
680674 continue;
681675 };
682676 defer tree.deinit();
683677
684 var original_file_backup = try Buffer.init(allocator, file_path);
685 defer original_file_backup.deinit();
686 try original_file_backup.append(".backup");
687678
688 try os.rename(allocator, file_path, original_file_backup.toSliceConst());
679 var error_it = tree.errors.iterator(0);
680 while (error_it.next()) |parse_error| {
681 const token = tree.tokens.at(parse_error.loc());
682 const loc = tree.tokenLocation(0, parse_error.loc());
683 try stderr.print("{}:{}:{}: error: ", file_path, loc.line + 1, loc.column + 1);
684 try tree.renderError(parse_error, stderr);
685 try stderr.print("\n{}\n", source_code[loc.line_start..loc.line_end]);
686 {
687 var i: usize = 0;
688 while (i < loc.column) : (i += 1) {
689 try stderr.write(" ");
690 }
691 }
692 {
693 const caret_count = token.end - token.start;
694 var i: usize = 0;
695 while (i < caret_count) : (i += 1) {
696 try stderr.write("~");
697 }
698 }
699 try stderr.write("\n");
700 }
701 if (tree.errors.len != 0) {
702 continue;
703 }
689704
690705 try stderr.print("{}\n", file_path);
691706
692 // TODO: BufferedAtomicFile has some access problems.
693 var out_file = try os.File.openWrite(allocator, file_path);
694 defer out_file.close();
707 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
708 defer baf.destroy();
695709
696 var out_file_stream = io.FileOutStream.init(&out_file);
697 try parser.renderSource(out_file_stream.stream, tree.root_node);
698
699 if (!flags.present("keep-backups")) {
700 try os.deleteFile(allocator, original_file_backup.toSliceConst());
701 }
710 try std.zig.render(allocator, baf.stream(), &tree);
711 try baf.finish();
702712 }
703713}
704714
src-self-hosted/module.zig+2-21
......@@ -8,9 +8,7 @@ const c = @import("c.zig");
88const builtin = @import("builtin");
99const Target = @import("target.zig").Target;
1010const warn = std.debug.warn;
11const Tokenizer = std.zig.Tokenizer;
1211const Token = std.zig.Token;
13const Parser = std.zig.Parser;
1412const ArrayList = std.ArrayList;
1513
1614pub const Module = struct {
......@@ -246,34 +244,17 @@ pub const Module = struct {
246244
247245 warn("{}", source_code);
248246
249 warn("====tokenization:====\n");
250 {
251 var tokenizer = Tokenizer.init(source_code);
252 while (true) {
253 const token = tokenizer.next();
254 tokenizer.dump(token);
255 if (token.id == Token.Id.Eof) {
256 break;
257 }
258 }
259 }
260
261247 warn("====parse:====\n");
262248
263 var tokenizer = Tokenizer.init(source_code);
264 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
265 defer parser.deinit();
266
267 var tree = try parser.parse();
249 var tree = try std.zig.parse(self.allocator, source_code);
268250 defer tree.deinit();
269251
270252 var stderr_file = try std.io.getStdErr();
271253 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
272254 const out_stream = &stderr_file_out_stream.stream;
273 try parser.renderAst(out_stream, tree.root_node);
274255
275256 warn("====fmt:====\n");
276 try parser.renderSource(out_stream, tree.root_node);
257 try std.zig.render(self.allocator, out_stream, &tree);
277258
278259 warn("====ir:====\n");
279260 warn("TODO\n\n");
src/all_types.hpp+7
......@@ -1345,6 +1345,7 @@ enum BuiltinFnId {
13451345 BuiltinFnIdOffsetOf,
13461346 BuiltinFnIdInlineCall,
13471347 BuiltinFnIdNoInlineCall,
1348 BuiltinFnIdNewStackCall,
13481349 BuiltinFnIdTypeId,
13491350 BuiltinFnIdShlExact,
13501351 BuiltinFnIdShrExact,
......@@ -1661,8 +1662,13 @@ struct CodeGen {
16611662 LLVMValueRef coro_alloc_helper_fn_val;
16621663 LLVMValueRef merge_err_ret_traces_fn_val;
16631664 LLVMValueRef add_error_return_trace_addr_fn_val;
1665 LLVMValueRef stacksave_fn_val;
1666 LLVMValueRef stackrestore_fn_val;
1667 LLVMValueRef write_register_fn_val;
16641668 bool error_during_imports;
16651669
1670 LLVMValueRef sp_md_node;
1671
16661672 const char **clang_argv;
16671673 size_t clang_argv_len;
16681674 ZigList<const char *> lib_dirs;
......@@ -2285,6 +2291,7 @@ struct IrInstructionCall {
22852291 bool is_async;
22862292
22872293 IrInstruction *async_allocator;
2294 IrInstruction *new_stack;
22882295};
22892296
22902297struct IrInstructionConst {
src/bigint.cpp+1-1
......@@ -1425,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
14251425 uint64_t digit = op1_digits[op_digit_index];
14261426 size_t dest_digit_index = op_digit_index - digit_shift_count;
14271427 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
1428 carry = digit << leftover_shift_count;
1428 carry = digit << (64 - leftover_shift_count);
14291429
14301430 if (dest_digit_index == 0) { break; }
14311431 op_digit_index -= 1;
src/codegen.cpp+97-2
......@@ -938,6 +938,53 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
938938 return g->memcpy_fn_val;
939939}
940940
941static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
942 if (g->stacksave_fn_val)
943 return g->stacksave_fn_val;
944
945 // declare i8* @llvm.stacksave()
946
947 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
948 g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
949 assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
950
951 return g->stacksave_fn_val;
952}
953
954static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
955 if (g->stackrestore_fn_val)
956 return g->stackrestore_fn_val;
957
958 // declare void @llvm.stackrestore(i8* %ptr)
959
960 LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
961 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), &param_type, 1, false);
962 g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
963 assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
964
965 return g->stackrestore_fn_val;
966}
967
968static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
969 if (g->write_register_fn_val)
970 return g->write_register_fn_val;
971
972 // declare void @llvm.write_register.i64(metadata, i64 @value)
973 // !0 = !{!"sp\00"}
974
975 LLVMTypeRef param_types[] = {
976 LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
977 LLVMIntType(g->pointer_size_bytes * 8),
978 };
979
980 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
981 Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
982 g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
983 assert(LLVMGetIntrinsicID(g->write_register_fn_val));
984
985 return g->write_register_fn_val;
986}
987
941988static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
942989 if (g->coro_destroy_fn_val)
943990 return g->coro_destroy_fn_val;
......@@ -2901,6 +2948,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
29012948 return 1 + get_async_allocator_arg_index(g, fn_type_id);
29022949}
29032950
2951
2952static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
2953 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
2954 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
2955
2956 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
2957 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
2958
2959 LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
2960 LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
2961 LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
2962 LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
2963 return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
2964}
2965
2966static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
2967 LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
2968
2969 if (g->sp_md_node == nullptr) {
2970 Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
2971 LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
2972 g->sp_md_node = LLVMMDNode(&str_node, 1);
2973 }
2974
2975 LLVMValueRef params[] = {
2976 g->sp_md_node,
2977 aligned_end_addr,
2978 };
2979
2980 LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
2981}
2982
29042983static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
29052984 LLVMValueRef fn_val;
29062985 TypeTableEntry *fn_type;
......@@ -2967,8 +3046,23 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
29673046 }
29683047
29693048 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
2970 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
2971 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3049 LLVMValueRef result;
3050
3051 if (instruction->new_stack == nullptr) {
3052 result = ZigLLVMBuildCall(g->builder, fn_val,
3053 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3054 } else {
3055 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
3056 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
3057
3058 LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
3059 LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
3060 gen_set_stack_pointer(g, new_stack_addr);
3061 result = ZigLLVMBuildCall(g->builder, fn_val,
3062 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3063 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
3064 }
3065
29723066
29733067 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
29743068 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
......@@ -6171,6 +6265,7 @@ static void define_builtin_fns(CodeGen *g) {
61716265 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
61726266 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
61736267 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
6268 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
61746269 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
61756270 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
61766271 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
src/ir.cpp+69-12
......@@ -1102,7 +1102,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
11021102
11031103static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
11041104 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1105 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
1105 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1106 IrInstruction *new_stack)
11061107{
11071108 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
11081109 call_instruction->fn_entry = fn_entry;
......@@ -1113,6 +1114,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
11131114 call_instruction->arg_count = arg_count;
11141115 call_instruction->is_async = is_async;
11151116 call_instruction->async_allocator = async_allocator;
1117 call_instruction->new_stack = new_stack;
11161118
11171119 if (fn_ref)
11181120 ir_ref_instruction(fn_ref, irb->current_basic_block);
......@@ -1120,16 +1122,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
11201122 ir_ref_instruction(args[i], irb->current_basic_block);
11211123 if (async_allocator)
11221124 ir_ref_instruction(async_allocator, irb->current_basic_block);
1125 if (new_stack != nullptr)
1126 ir_ref_instruction(new_stack, irb->current_basic_block);
11231127
11241128 return &call_instruction->base;
11251129}
11261130
11271131static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
11281132 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1129 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
1133 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1134 IrInstruction *new_stack)
11301135{
11311136 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1132 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
1137 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, new_stack);
11331138 ir_link_new_instruction(new_instruction, old_instruction);
11341139 return new_instruction;
11351140}
......@@ -4303,7 +4308,37 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
43034308 }
43044309 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
43054310
4306 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
4311 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
4312 return ir_lval_wrap(irb, scope, call, lval);
4313 }
4314 case BuiltinFnIdNewStackCall:
4315 {
4316 if (node->data.fn_call_expr.params.length == 0) {
4317 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
4318 return irb->codegen->invalid_instruction;
4319 }
4320
4321 AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
4322 IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
4323 if (new_stack == irb->codegen->invalid_instruction)
4324 return new_stack;
4325
4326 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
4327 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
4328 if (fn_ref == irb->codegen->invalid_instruction)
4329 return fn_ref;
4330
4331 size_t arg_count = node->data.fn_call_expr.params.length - 2;
4332
4333 IrInstruction **args = allocate<IrInstruction*>(arg_count);
4334 for (size_t i = 0; i < arg_count; i += 1) {
4335 AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
4336 args[i] = ir_gen_node(irb, arg_node, scope);
4337 if (args[i] == irb->codegen->invalid_instruction)
4338 return args[i];
4339 }
4340
4341 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
43074342 return ir_lval_wrap(irb, scope, call, lval);
43084343 }
43094344 case BuiltinFnIdTypeId:
......@@ -4513,7 +4548,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
45134548 }
45144549 }
45154550
4516 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
4551 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
45174552 return ir_lval_wrap(irb, scope, fn_call, lval);
45184553}
45194554
......@@ -6831,7 +6866,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
68316866 IrInstruction **args = allocate<IrInstruction *>(arg_count);
68326867 args[0] = implicit_allocator_ptr; // self
68336868 args[1] = mem_slice; // old_mem
6834 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
6869 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
68356870
68366871 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
68376872 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
......@@ -8692,6 +8727,10 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
86928727 *dest = *src;
86938728 if (!same_global_refs) {
86948729 dest->global_refs = global_refs;
8730 if (dest->type->id == TypeTableEntryIdStruct) {
8731 dest->data.x_struct.fields = allocate_nonzero<ConstExprValue>(dest->type->data.structure.src_field_count);
8732 memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count);
8733 }
86958734 }
86968735}
86978736
......@@ -11676,7 +11715,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1167611715 if (var->mem_slot_index != SIZE_MAX) {
1167711716 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
1167811717 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
11679 *mem_slot = casted_init_value->value;
11718 copy_const_val(mem_slot, &casted_init_value->value,
11719 !is_comptime_var || var->gen_is_const);
1168011720
1168111721 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
1168211722 ir_build_const_from(ira, &decl_var_instruction->base);
......@@ -11993,7 +12033,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
1199312033 TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
1199412034
1199512035 IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
11996 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);
12036 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
1199712037 result->value.type = async_return_type;
1199812038 return result;
1199912039}
......@@ -12363,6 +12403,19 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1236312403 return ir_finish_anal(ira, return_type);
1236412404 }
1236512405
12406 IrInstruction *casted_new_stack = nullptr;
12407 if (call_instruction->new_stack != nullptr) {
12408 TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
12409 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
12410 IrInstruction *new_stack = call_instruction->new_stack->other;
12411 if (type_is_invalid(new_stack->value.type))
12412 return ira->codegen->builtin_types.entry_invalid;
12413
12414 casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
12415 if (type_is_invalid(casted_new_stack->value.type))
12416 return ira->codegen->builtin_types.entry_invalid;
12417 }
12418
1236612419 if (fn_type->data.fn.is_generic) {
1236712420 if (!fn_entry) {
1236812421 ir_add_error(ira, call_instruction->fn_ref,
......@@ -12589,7 +12642,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1258912642 assert(async_allocator_inst == nullptr);
1259012643 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
1259112644 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
12592 call_instruction->is_async, nullptr);
12645 call_instruction->is_async, nullptr, casted_new_stack);
1259312646
1259412647 ir_add_alloca(ira, new_call_instruction, return_type);
1259512648
......@@ -12680,7 +12733,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1268012733
1268112734
1268212735 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
12683 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
12736 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
1268412737
1268512738 ir_add_alloca(ira, new_call_instruction, return_type);
1268612739 return ir_finish_anal(ira, return_type);
......@@ -14715,7 +14768,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
1471514768 }
1471614769
1471714770 if (value->value.type->id != TypeTableEntryIdUnion) {
14718 ir_add_error(ira, source_instr,
14771 ir_add_error(ira, value,
1471914772 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
1472014773 return ira->codegen->invalid_instruction;
1472114774 }
......@@ -18036,7 +18089,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1803618089 if (type_is_invalid(end_value->value.type))
1803718090 return ira->codegen->builtin_types.entry_invalid;
1803818091
18039 assert(start_value->value.type->id == TypeTableEntryIdEnum);
18092 if (start_value->value.type->id != TypeTableEntryIdEnum) {
18093 ir_add_error(ira, range->start, buf_sprintf("not an enum type"));
18094 return ira->codegen->builtin_types.entry_invalid;
18095 }
18096
1804018097 BigInt start_index;
1804118098 bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
1804218099
src/target.cpp+62
......@@ -896,3 +896,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
896896
897897 return false;
898898}
899
900const char *arch_stack_pointer_register_name(const ArchType *arch) {
901 switch (arch->arch) {
902 case ZigLLVM_UnknownArch:
903 zig_unreachable();
904 case ZigLLVM_x86:
905 return "sp";
906 case ZigLLVM_x86_64:
907 return "rsp";
908
909 case ZigLLVM_aarch64:
910 case ZigLLVM_arm:
911 case ZigLLVM_thumb:
912 case ZigLLVM_aarch64_be:
913 case ZigLLVM_amdgcn:
914 case ZigLLVM_amdil:
915 case ZigLLVM_amdil64:
916 case ZigLLVM_armeb:
917 case ZigLLVM_arc:
918 case ZigLLVM_avr:
919 case ZigLLVM_bpfeb:
920 case ZigLLVM_bpfel:
921 case ZigLLVM_hexagon:
922 case ZigLLVM_lanai:
923 case ZigLLVM_hsail:
924 case ZigLLVM_hsail64:
925 case ZigLLVM_kalimba:
926 case ZigLLVM_le32:
927 case ZigLLVM_le64:
928 case ZigLLVM_mips:
929 case ZigLLVM_mips64:
930 case ZigLLVM_mips64el:
931 case ZigLLVM_mipsel:
932 case ZigLLVM_msp430:
933 case ZigLLVM_nios2:
934 case ZigLLVM_nvptx:
935 case ZigLLVM_nvptx64:
936 case ZigLLVM_ppc64le:
937 case ZigLLVM_r600:
938 case ZigLLVM_renderscript32:
939 case ZigLLVM_renderscript64:
940 case ZigLLVM_riscv32:
941 case ZigLLVM_riscv64:
942 case ZigLLVM_shave:
943 case ZigLLVM_sparc:
944 case ZigLLVM_sparcel:
945 case ZigLLVM_sparcv9:
946 case ZigLLVM_spir:
947 case ZigLLVM_spir64:
948 case ZigLLVM_systemz:
949 case ZigLLVM_tce:
950 case ZigLLVM_tcele:
951 case ZigLLVM_thumbeb:
952 case ZigLLVM_wasm32:
953 case ZigLLVM_wasm64:
954 case ZigLLVM_xcore:
955 case ZigLLVM_ppc:
956 case ZigLLVM_ppc64:
957 zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
958 }
959 zig_unreachable();
960}
src/target.hpp+2
......@@ -77,6 +77,8 @@ size_t target_arch_count(void);
7777const ArchType *get_target_arch(size_t index);
7878void get_arch_name(char *out_str, const ArchType *arch);
7979
80const char *arch_stack_pointer_register_name(const ArchType *arch);
81
8082size_t target_vendor_count(void);
8183ZigLLVM_VendorType get_target_vendor(size_t index);
8284
std/buffer.zig+4-20
......@@ -94,26 +94,10 @@ pub const Buffer = struct {
9494 mem.copy(u8, self.list.toSlice()[old_len..], m);
9595 }
9696
97 // TODO: remove, use OutStream for this
98 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void {
99 return fmt.format(self, append, format, args);
100 }
101
102 // TODO: remove, use OutStream for this
10397 pub fn appendByte(self: &Buffer, byte: u8) !void {
104 return self.appendByteNTimes(byte, 1);
105 }
106
107 // TODO: remove, use OutStream for this
108 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void {
109 var prev_size: usize = self.len();
110 const new_size = prev_size + count;
111 try self.resize(new_size);
112
113 var i: usize = prev_size;
114 while (i < new_size) : (i += 1) {
115 self.list.items[i] = byte;
116 }
98 const old_len = self.len();
99 try self.resize(old_len + 1);
100 self.list.toSlice()[old_len] = byte;
117101 }
118102
119103 pub fn eql(self: &const Buffer, m: []const u8) bool {
......@@ -149,7 +133,7 @@ test "simple Buffer" {
149133 var buf = try Buffer.init(debug.global_allocator, "");
150134 assert(buf.len() == 0);
151135 try buf.append("hello");
152 try buf.appendByte(' ');
136 try buf.append(" ");
153137 try buf.append("world");
154138 assert(buf.eql("hello world"));
155139 assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
std/io_test.zig+17-1
......@@ -1,6 +1,5 @@
11const std = @import("index.zig");
22const io = std.io;
3const allocator = std.debug.global_allocator;
43const DefaultPrng = std.rand.DefaultPrng;
54const assert = std.debug.assert;
65const mem = std.mem;
......@@ -8,6 +7,9 @@ const os = std.os;
87const builtin = @import("builtin");
98
109test "write a file, read it, then delete it" {
10 var raw_bytes: [200 * 1024]u8 = undefined;
11 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;
12
1113 var data: [1024]u8 = undefined;
1214 var prng = DefaultPrng.init(1234);
1315 prng.random.bytes(data[0..]);
......@@ -44,3 +46,17 @@ test "write a file, read it, then delete it" {
4446 }
4547 try os.deleteFile(allocator, tmp_file_name);
4648}
49
50test "BufferOutStream" {
51 var bytes: [100]u8 = undefined;
52 var allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
53
54 var buffer = try std.Buffer.initSize(allocator, 0);
55 var buf_stream = &std.io.BufferOutStream.init(&buffer).stream;
56
57 const x: i32 = 42;
58 const y: i32 = 1234;
59 try buf_stream.print("x: {}\ny: {}\n", x, y);
60
61 assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
62}
std/os/child_process.zig+5-3
......@@ -661,6 +661,8 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
661661 var buf = try Buffer.initSize(allocator, 0);
662662 defer buf.deinit();
663663
664 var buf_stream = &io.BufferOutStream.init(&buf).stream;
665
664666 for (argv) |arg, arg_i| {
665667 if (arg_i != 0) try buf.appendByte(' ');
666668 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
......@@ -673,18 +675,18 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
673675 switch (byte) {
674676 '\\' => backslash_count += 1,
675677 '"' => {
676 try buf.appendByteNTimes('\\', backslash_count * 2 + 1);
678 try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
677679 try buf.appendByte('"');
678680 backslash_count = 0;
679681 },
680682 else => {
681 try buf.appendByteNTimes('\\', backslash_count);
683 try buf_stream.writeByteNTimes('\\', backslash_count);
682684 try buf.appendByte(byte);
683685 backslash_count = 0;
684686 },
685687 }
686688 }
687 try buf.appendByteNTimes('\\', backslash_count * 2);
689 try buf_stream.writeByteNTimes('\\', backslash_count * 2);
688690 try buf.appendByte('"');
689691 }
690692
std/segmented_list.zig+11
......@@ -91,6 +91,8 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
9191 allocator: &Allocator,
9292 len: usize,
9393
94 pub const prealloc_count = prealloc_item_count;
95
9496 /// Deinitialize with `deinit`
9597 pub fn init(allocator: &Allocator) Self {
9698 return Self{
......@@ -283,6 +285,15 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
283285
284286 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
285287 }
288
289 pub fn peek(it: &Iterator) ?&T {
290 if (it.index >= it.list.len)
291 return null;
292 if (it.index < prealloc_item_count)
293 return &it.list.prealloc_segment[it.index];
294
295 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
296 }
286297 };
287298
288299 pub fn iterator(self: &Self, start_index: usize) Iterator {
std/zig/ast.zig+601-266
......@@ -1,12 +1,232 @@
11const std = @import("../index.zig");
22const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const Token = std.zig.Token;
3const SegmentedList = std.SegmentedList;
54const mem = std.mem;
5const Token = std.zig.Token;
6
7pub const TokenIndex = usize;
8
9pub const Tree = struct {
10 source: []const u8,
11 tokens: TokenList,
12 root_node: &Node.Root,
13 arena_allocator: std.heap.ArenaAllocator,
14 errors: ErrorList,
15
16 pub const TokenList = SegmentedList(Token, 64);
17 pub const ErrorList = SegmentedList(Error, 0);
18
19 pub fn deinit(self: &Tree) void {
20 self.arena_allocator.deinit();
21 }
22
23 pub fn renderError(self: &Tree, parse_error: &Error, stream: var) !void {
24 return parse_error.render(&self.tokens, stream);
25 }
26
27 pub fn tokenSlice(self: &Tree, token_index: TokenIndex) []const u8 {
28 return self.tokenSlicePtr(self.tokens.at(token_index));
29 }
30
31 pub fn tokenSlicePtr(self: &Tree, token: &const Token) []const u8 {
32 return self.source[token.start..token.end];
33 }
34
35 pub const Location = struct {
36 line: usize,
37 column: usize,
38 line_start: usize,
39 line_end: usize,
40 };
41
42 pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {
43 var loc = Location {
44 .line = 0,
45 .column = 0,
46 .line_start = start_index,
47 .line_end = self.source.len,
48 };
49 const token_start = token.start;
50 for (self.source[start_index..]) |c, i| {
51 if (i + start_index == token_start) {
52 loc.line_end = i + start_index;
53 while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') : (loc.line_end += 1) {}
54 return loc;
55 }
56 if (c == '\n') {
57 loc.line += 1;
58 loc.column = 0;
59 loc.line_start = i + 1;
60 } else {
61 loc.column += 1;
62 }
63 }
64 return loc;
65 }
66
67 pub fn tokenLocation(self: &Tree, start_index: usize, token_index: TokenIndex) Location {
68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
69 }
70
71 pub fn dump(self: &Tree) void {
72 self.root_node.base.dump(0);
73 }
74
75};
76
77pub const Error = union(enum) {
78 InvalidToken: InvalidToken,
79 ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
80 ExpectedAggregateKw: ExpectedAggregateKw,
81 UnattachedDocComment: UnattachedDocComment,
82 ExpectedEqOrSemi: ExpectedEqOrSemi,
83 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
84 ExpectedLabelable: ExpectedLabelable,
85 ExpectedInlinable: ExpectedInlinable,
86 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
87 ExpectedCall: ExpectedCall,
88 ExpectedCallOrFnProto: ExpectedCallOrFnProto,
89 ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
90 ExtraAlignQualifier: ExtraAlignQualifier,
91 ExtraConstQualifier: ExtraConstQualifier,
92 ExtraVolatileQualifier: ExtraVolatileQualifier,
93 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
94 ExpectedToken: ExpectedToken,
95 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
96
97 pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
98 switch (*self) {
99 // TODO https://github.com/zig-lang/zig/issues/683
100 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
101 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
102 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
103 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
104 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
105 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
106 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
107 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
108 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
109 @TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
110 @TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
111 @TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
112 @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
113 @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
114 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
115 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
116 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
117 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
118 }
119 }
120
121 pub fn loc(self: &Error) TokenIndex {
122 switch (*self) {
123 // TODO https://github.com/zig-lang/zig/issues/683
124 @TagType(Error).InvalidToken => |x| return x.token,
125 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
126 @TagType(Error).ExpectedAggregateKw => |x| return x.token,
127 @TagType(Error).UnattachedDocComment => |x| return x.token,
128 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
129 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
130 @TagType(Error).ExpectedLabelable => |x| return x.token,
131 @TagType(Error).ExpectedInlinable => |x| return x.token,
132 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
133 @TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
134 @TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
135 @TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
136 @TagType(Error).ExtraAlignQualifier => |x| return x.token,
137 @TagType(Error).ExtraConstQualifier => |x| return x.token,
138 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
139 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
140 @TagType(Error).ExpectedToken => |x| return x.token,
141 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
142 }
143 }
144
145 pub const InvalidToken = SingleTokenError("Invalid token {}");
146 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
147 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++
148 @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++
149 @tagName(Token.Id.Keyword_enum) ++ ", found {}");
150 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
151 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
152 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
153 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
154 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++
155 @tagName(Token.Id.Identifier) ++ ", found {}");
156 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
157 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
158
159 pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
160 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
161 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
162 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
163
164 pub const ExpectedCall = struct {
165 node: &Node,
166
167 pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
168 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}",
169 @tagName(self.node.id));
170 }
171 };
172
173 pub const ExpectedCallOrFnProto = struct {
174 node: &Node,
175
176 pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
177 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
178 @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
179 }
180 };
181
182 pub const ExpectedToken = struct {
183 token: TokenIndex,
184 expected_id: @TagType(Token.Id),
185
186 pub fn render(self: &ExpectedToken, tokens: &Tree.TokenList, stream: var) !void {
187 const token_name = @tagName(tokens.at(self.token).id);
188 return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
189 }
190 };
191
192 pub const ExpectedCommaOrEnd = struct {
193 token: TokenIndex,
194 end_id: @TagType(Token.Id),
195
196 pub fn render(self: &ExpectedCommaOrEnd, tokens: &Tree.TokenList, stream: var) !void {
197 const token_name = @tagName(tokens.at(self.token).id);
198 return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name);
199 }
200 };
201
202 fn SingleTokenError(comptime msg: []const u8) type {
203 return struct {
204 const ThisError = this;
205
206 token: TokenIndex,
207
208 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
209 const token_name = @tagName(tokens.at(self.token).id);
210 return stream.print(msg, token_name);
211 }
212 };
213 }
214
215 fn SimpleError(comptime msg: []const u8) type {
216 return struct {
217 const ThisError = this;
218
219 token: TokenIndex,
220
221 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
222 return stream.write(msg);
223 }
224 };
225 }
226};
6227
7228pub const Node = struct {
8229 id: Id,
9 same_line_comment: ?&Token,
10230
11231 pub const Id = enum {
12232 // Top level
......@@ -95,7 +315,7 @@ pub const Node = struct {
95315 unreachable;
96316 }
97317
98 pub fn firstToken(base: &Node) Token {
318 pub fn firstToken(base: &Node) TokenIndex {
99319 comptime var i = 0;
100320 inline while (i < @memberCount(Id)) : (i += 1) {
101321 if (base.id == @field(Id, @memberName(Id, i))) {
......@@ -106,7 +326,7 @@ pub const Node = struct {
106326 unreachable;
107327 }
108328
109 pub fn lastToken(base: &Node) Token {
329 pub fn lastToken(base: &Node) TokenIndex {
110330 comptime var i = 0;
111331 inline while (i < @memberCount(Id)) : (i += 1) {
112332 if (base.id == @field(Id, @memberName(Id, i))) {
......@@ -127,42 +347,132 @@ pub const Node = struct {
127347 unreachable;
128348 }
129349
350 pub fn requireSemiColon(base: &const Node) bool {
351 var n = base;
352 while (true) {
353 switch (n.id) {
354 Id.Root,
355 Id.StructField,
356 Id.UnionTag,
357 Id.EnumTag,
358 Id.ParamDecl,
359 Id.Block,
360 Id.Payload,
361 Id.PointerPayload,
362 Id.PointerIndexPayload,
363 Id.Switch,
364 Id.SwitchCase,
365 Id.SwitchElse,
366 Id.FieldInitializer,
367 Id.DocComment,
368 Id.LineComment,
369 Id.TestDecl => return false,
370 Id.While => {
371 const while_node = @fieldParentPtr(While, "base", n);
372 if (while_node.@"else") |@"else"| {
373 n = @"else".base;
374 continue;
375 }
376
377 return while_node.body.id != Id.Block;
378 },
379 Id.For => {
380 const for_node = @fieldParentPtr(For, "base", n);
381 if (for_node.@"else") |@"else"| {
382 n = @"else".base;
383 continue;
384 }
385
386 return for_node.body.id != Id.Block;
387 },
388 Id.If => {
389 const if_node = @fieldParentPtr(If, "base", n);
390 if (if_node.@"else") |@"else"| {
391 n = @"else".base;
392 continue;
393 }
394
395 return if_node.body.id != Id.Block;
396 },
397 Id.Else => {
398 const else_node = @fieldParentPtr(Else, "base", n);
399 n = else_node.body;
400 continue;
401 },
402 Id.Defer => {
403 const defer_node = @fieldParentPtr(Defer, "base", n);
404 return defer_node.expr.id != Id.Block;
405 },
406 Id.Comptime => {
407 const comptime_node = @fieldParentPtr(Comptime, "base", n);
408 return comptime_node.expr.id != Id.Block;
409 },
410 Id.Suspend => {
411 const suspend_node = @fieldParentPtr(Suspend, "base", n);
412 if (suspend_node.body) |body| {
413 return body.id != Id.Block;
414 }
415
416 return true;
417 },
418 else => return true,
419 }
420 }
421 }
422
423 pub fn dump(self: &Node, indent: usize) void {
424 {
425 var i: usize = 0;
426 while (i < indent) : (i += 1) {
427 std.debug.warn(" ");
428 }
429 }
430 std.debug.warn("{}\n", @tagName(self.id));
431
432 var child_i: usize = 0;
433 while (self.iterate(child_i)) |child| : (child_i += 1) {
434 child.dump(indent + 2);
435 }
436 }
437
130438 pub const Root = struct {
131439 base: Node,
132440 doc_comments: ?&DocComment,
133 decls: ArrayList(&Node),
134 eof_token: Token,
441 decls: DeclList,
442 eof_token: TokenIndex,
443
444 pub const DeclList = SegmentedList(&Node, 4);
135445
136446 pub fn iterate(self: &Root, index: usize) ?&Node {
137447 if (index < self.decls.len) {
138 return self.decls.items[self.decls.len - index - 1];
448 return *self.decls.at(index);
139449 }
140450 return null;
141451 }
142452
143 pub fn firstToken(self: &Root) Token {
144 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
453 pub fn firstToken(self: &Root) TokenIndex {
454 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(0)).firstToken();
145455 }
146456
147 pub fn lastToken(self: &Root) Token {
148 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
457 pub fn lastToken(self: &Root) TokenIndex {
458 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(self.decls.len - 1)).lastToken();
149459 }
150460 };
151461
152462 pub const VarDecl = struct {
153463 base: Node,
154464 doc_comments: ?&DocComment,
155 visib_token: ?Token,
156 name_token: Token,
157 eq_token: Token,
158 mut_token: Token,
159 comptime_token: ?Token,
160 extern_export_token: ?Token,
465 visib_token: ?TokenIndex,
466 name_token: TokenIndex,
467 eq_token: TokenIndex,
468 mut_token: TokenIndex,
469 comptime_token: ?TokenIndex,
470 extern_export_token: ?TokenIndex,
161471 lib_name: ?&Node,
162472 type_node: ?&Node,
163473 align_node: ?&Node,
164474 init_node: ?&Node,
165 semicolon_token: Token,
475 semicolon_token: TokenIndex,
166476
167477 pub fn iterate(self: &VarDecl, index: usize) ?&Node {
168478 var i = index;
......@@ -185,7 +495,7 @@ pub const Node = struct {
185495 return null;
186496 }
187497
188 pub fn firstToken(self: &VarDecl) Token {
498 pub fn firstToken(self: &VarDecl) TokenIndex {
189499 if (self.visib_token) |visib_token| return visib_token;
190500 if (self.comptime_token) |comptime_token| return comptime_token;
191501 if (self.extern_export_token) |extern_export_token| return extern_export_token;
......@@ -193,7 +503,7 @@ pub const Node = struct {
193503 return self.mut_token;
194504 }
195505
196 pub fn lastToken(self: &VarDecl) Token {
506 pub fn lastToken(self: &VarDecl) TokenIndex {
197507 return self.semicolon_token;
198508 }
199509 };
......@@ -201,9 +511,9 @@ pub const Node = struct {
201511 pub const Use = struct {
202512 base: Node,
203513 doc_comments: ?&DocComment,
204 visib_token: ?Token,
514 visib_token: ?TokenIndex,
205515 expr: &Node,
206 semicolon_token: Token,
516 semicolon_token: TokenIndex,
207517
208518 pub fn iterate(self: &Use, index: usize) ?&Node {
209519 var i = index;
......@@ -214,48 +524,52 @@ pub const Node = struct {
214524 return null;
215525 }
216526
217 pub fn firstToken(self: &Use) Token {
527 pub fn firstToken(self: &Use) TokenIndex {
218528 if (self.visib_token) |visib_token| return visib_token;
219529 return self.expr.firstToken();
220530 }
221531
222 pub fn lastToken(self: &Use) Token {
532 pub fn lastToken(self: &Use) TokenIndex {
223533 return self.semicolon_token;
224534 }
225535 };
226536
227537 pub const ErrorSetDecl = struct {
228538 base: Node,
229 error_token: Token,
230 decls: ArrayList(&Node),
231 rbrace_token: Token,
539 error_token: TokenIndex,
540 decls: DeclList,
541 rbrace_token: TokenIndex,
542
543 pub const DeclList = SegmentedList(&Node, 2);
232544
233545 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
234546 var i = index;
235547
236 if (i < self.decls.len) return self.decls.at(i);
548 if (i < self.decls.len) return *self.decls.at(i);
237549 i -= self.decls.len;
238550
239551 return null;
240552 }
241553
242 pub fn firstToken(self: &ErrorSetDecl) Token {
554 pub fn firstToken(self: &ErrorSetDecl) TokenIndex {
243555 return self.error_token;
244556 }
245557
246 pub fn lastToken(self: &ErrorSetDecl) Token {
558 pub fn lastToken(self: &ErrorSetDecl) TokenIndex {
247559 return self.rbrace_token;
248560 }
249561 };
250562
251563 pub const ContainerDecl = struct {
252564 base: Node,
253 ltoken: Token,
565 ltoken: TokenIndex,
254566 layout: Layout,
255567 kind: Kind,
256568 init_arg_expr: InitArg,
257 fields_and_decls: ArrayList(&Node),
258 rbrace_token: Token,
569 fields_and_decls: DeclList,
570 rbrace_token: TokenIndex,
571
572 pub const DeclList = Root.DeclList;
259573
260574 const Layout = enum {
261575 Auto,
......@@ -287,17 +601,17 @@ pub const Node = struct {
287601 InitArg.Enum => { }
288602 }
289603
290 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
604 if (i < self.fields_and_decls.len) return *self.fields_and_decls.at(i);
291605 i -= self.fields_and_decls.len;
292606
293607 return null;
294608 }
295609
296 pub fn firstToken(self: &ContainerDecl) Token {
610 pub fn firstToken(self: &ContainerDecl) TokenIndex {
297611 return self.ltoken;
298612 }
299613
300 pub fn lastToken(self: &ContainerDecl) Token {
614 pub fn lastToken(self: &ContainerDecl) TokenIndex {
301615 return self.rbrace_token;
302616 }
303617 };
......@@ -305,8 +619,8 @@ pub const Node = struct {
305619 pub const StructField = struct {
306620 base: Node,
307621 doc_comments: ?&DocComment,
308 visib_token: ?Token,
309 name_token: Token,
622 visib_token: ?TokenIndex,
623 name_token: TokenIndex,
310624 type_expr: &Node,
311625
312626 pub fn iterate(self: &StructField, index: usize) ?&Node {
......@@ -318,12 +632,12 @@ pub const Node = struct {
318632 return null;
319633 }
320634
321 pub fn firstToken(self: &StructField) Token {
635 pub fn firstToken(self: &StructField) TokenIndex {
322636 if (self.visib_token) |visib_token| return visib_token;
323637 return self.name_token;
324638 }
325639
326 pub fn lastToken(self: &StructField) Token {
640 pub fn lastToken(self: &StructField) TokenIndex {
327641 return self.type_expr.lastToken();
328642 }
329643 };
......@@ -331,7 +645,7 @@ pub const Node = struct {
331645 pub const UnionTag = struct {
332646 base: Node,
333647 doc_comments: ?&DocComment,
334 name_token: Token,
648 name_token: TokenIndex,
335649 type_expr: ?&Node,
336650 value_expr: ?&Node,
337651
......@@ -351,11 +665,11 @@ pub const Node = struct {
351665 return null;
352666 }
353667
354 pub fn firstToken(self: &UnionTag) Token {
668 pub fn firstToken(self: &UnionTag) TokenIndex {
355669 return self.name_token;
356670 }
357671
358 pub fn lastToken(self: &UnionTag) Token {
672 pub fn lastToken(self: &UnionTag) TokenIndex {
359673 if (self.value_expr) |value_expr| {
360674 return value_expr.lastToken();
361675 }
......@@ -370,7 +684,7 @@ pub const Node = struct {
370684 pub const EnumTag = struct {
371685 base: Node,
372686 doc_comments: ?&DocComment,
373 name_token: Token,
687 name_token: TokenIndex,
374688 value: ?&Node,
375689
376690 pub fn iterate(self: &EnumTag, index: usize) ?&Node {
......@@ -384,11 +698,11 @@ pub const Node = struct {
384698 return null;
385699 }
386700
387 pub fn firstToken(self: &EnumTag) Token {
701 pub fn firstToken(self: &EnumTag) TokenIndex {
388702 return self.name_token;
389703 }
390704
391 pub fn lastToken(self: &EnumTag) Token {
705 pub fn lastToken(self: &EnumTag) TokenIndex {
392706 if (self.value) |value| {
393707 return value.lastToken();
394708 }
......@@ -400,7 +714,7 @@ pub const Node = struct {
400714 pub const ErrorTag = struct {
401715 base: Node,
402716 doc_comments: ?&DocComment,
403 name_token: Token,
717 name_token: TokenIndex,
404718
405719 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {
406720 var i = index;
......@@ -413,37 +727,37 @@ pub const Node = struct {
413727 return null;
414728 }
415729
416 pub fn firstToken(self: &ErrorTag) Token {
730 pub fn firstToken(self: &ErrorTag) TokenIndex {
417731 return self.name_token;
418732 }
419733
420 pub fn lastToken(self: &ErrorTag) Token {
734 pub fn lastToken(self: &ErrorTag) TokenIndex {
421735 return self.name_token;
422736 }
423737 };
424738
425739 pub const Identifier = struct {
426740 base: Node,
427 token: Token,
741 token: TokenIndex,
428742
429743 pub fn iterate(self: &Identifier, index: usize) ?&Node {
430744 return null;
431745 }
432746
433 pub fn firstToken(self: &Identifier) Token {
747 pub fn firstToken(self: &Identifier) TokenIndex {
434748 return self.token;
435749 }
436750
437 pub fn lastToken(self: &Identifier) Token {
751 pub fn lastToken(self: &Identifier) TokenIndex {
438752 return self.token;
439753 }
440754 };
441755
442756 pub const AsyncAttribute = struct {
443757 base: Node,
444 async_token: Token,
758 async_token: TokenIndex,
445759 allocator_type: ?&Node,
446 rangle_bracket: ?Token,
760 rangle_bracket: ?TokenIndex,
447761
448762 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {
449763 var i = index;
......@@ -456,11 +770,11 @@ pub const Node = struct {
456770 return null;
457771 }
458772
459 pub fn firstToken(self: &AsyncAttribute) Token {
773 pub fn firstToken(self: &AsyncAttribute) TokenIndex {
460774 return self.async_token;
461775 }
462776
463 pub fn lastToken(self: &AsyncAttribute) Token {
777 pub fn lastToken(self: &AsyncAttribute) TokenIndex {
464778 if (self.rangle_bracket) |rangle_bracket| {
465779 return rangle_bracket;
466780 }
......@@ -472,19 +786,21 @@ pub const Node = struct {
472786 pub const FnProto = struct {
473787 base: Node,
474788 doc_comments: ?&DocComment,
475 visib_token: ?Token,
476 fn_token: Token,
477 name_token: ?Token,
478 params: ArrayList(&Node),
789 visib_token: ?TokenIndex,
790 fn_token: TokenIndex,
791 name_token: ?TokenIndex,
792 params: ParamList,
479793 return_type: ReturnType,
480 var_args_token: ?Token,
481 extern_export_inline_token: ?Token,
482 cc_token: ?Token,
794 var_args_token: ?TokenIndex,
795 extern_export_inline_token: ?TokenIndex,
796 cc_token: ?TokenIndex,
483797 async_attr: ?&AsyncAttribute,
484798 body_node: ?&Node,
485799 lib_name: ?&Node, // populated if this is an extern declaration
486800 align_expr: ?&Node, // populated if align(A) is present
487801
802 pub const ParamList = SegmentedList(&Node, 2);
803
488804 pub const ReturnType = union(enum) {
489805 Explicit: &Node,
490806 InferErrorSet: &Node,
......@@ -493,8 +809,16 @@ pub const Node = struct {
493809 pub fn iterate(self: &FnProto, index: usize) ?&Node {
494810 var i = index;
495811
496 if (self.body_node) |body_node| {
497 if (i < 1) return body_node;
812 if (self.lib_name) |lib_name| {
813 if (i < 1) return lib_name;
814 i -= 1;
815 }
816
817 if (i < self.params.len) return *self.params.at(self.params.len - i - 1);
818 i -= self.params.len;
819
820 if (self.align_expr) |align_expr| {
821 if (i < 1) return align_expr;
498822 i -= 1;
499823 }
500824
......@@ -510,23 +834,16 @@ pub const Node = struct {
510834 },
511835 }
512836
513 if (self.align_expr) |align_expr| {
514 if (i < 1) return align_expr;
837 if (self.body_node) |body_node| {
838 if (i < 1) return body_node;
515839 i -= 1;
516840 }
517841
518 if (i < self.params.len) return self.params.items[self.params.len - i - 1];
519 i -= self.params.len;
520
521 if (self.lib_name) |lib_name| {
522 if (i < 1) return lib_name;
523 i -= 1;
524 }
525842
526843 return null;
527844 }
528845
529 pub fn firstToken(self: &FnProto) Token {
846 pub fn firstToken(self: &FnProto) TokenIndex {
530847 if (self.visib_token) |visib_token| return visib_token;
531848 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
532849 assert(self.lib_name == null);
......@@ -534,7 +851,7 @@ pub const Node = struct {
534851 return self.fn_token;
535852 }
536853
537 pub fn lastToken(self: &FnProto) Token {
854 pub fn lastToken(self: &FnProto) TokenIndex {
538855 if (self.body_node) |body_node| return body_node.lastToken();
539856 switch (self.return_type) {
540857 // TODO allow this and next prong to share bodies since the types are the same
......@@ -546,11 +863,11 @@ pub const Node = struct {
546863
547864 pub const PromiseType = struct {
548865 base: Node,
549 promise_token: Token,
866 promise_token: TokenIndex,
550867 result: ?Result,
551868
552869 pub const Result = struct {
553 arrow_token: Token,
870 arrow_token: TokenIndex,
554871 return_type: &Node,
555872 };
556873
......@@ -565,11 +882,11 @@ pub const Node = struct {
565882 return null;
566883 }
567884
568 pub fn firstToken(self: &PromiseType) Token {
885 pub fn firstToken(self: &PromiseType) TokenIndex {
569886 return self.promise_token;
570887 }
571888
572 pub fn lastToken(self: &PromiseType) Token {
889 pub fn lastToken(self: &PromiseType) TokenIndex {
573890 if (self.result) |result| return result.return_type.lastToken();
574891 return self.promise_token;
575892 }
......@@ -577,11 +894,11 @@ pub const Node = struct {
577894
578895 pub const ParamDecl = struct {
579896 base: Node,
580 comptime_token: ?Token,
581 noalias_token: ?Token,
582 name_token: ?Token,
897 comptime_token: ?TokenIndex,
898 noalias_token: ?TokenIndex,
899 name_token: ?TokenIndex,
583900 type_node: &Node,
584 var_args_token: ?Token,
901 var_args_token: ?TokenIndex,
585902
586903 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {
587904 var i = index;
......@@ -592,14 +909,14 @@ pub const Node = struct {
592909 return null;
593910 }
594911
595 pub fn firstToken(self: &ParamDecl) Token {
912 pub fn firstToken(self: &ParamDecl) TokenIndex {
596913 if (self.comptime_token) |comptime_token| return comptime_token;
597914 if (self.noalias_token) |noalias_token| return noalias_token;
598915 if (self.name_token) |name_token| return name_token;
599916 return self.type_node.firstToken();
600917 }
601918
602 pub fn lastToken(self: &ParamDecl) Token {
919 pub fn lastToken(self: &ParamDecl) TokenIndex {
603920 if (self.var_args_token) |var_args_token| return var_args_token;
604921 return self.type_node.lastToken();
605922 }
......@@ -607,21 +924,23 @@ pub const Node = struct {
607924
608925 pub const Block = struct {
609926 base: Node,
610 label: ?Token,
611 lbrace: Token,
612 statements: ArrayList(&Node),
613 rbrace: Token,
927 label: ?TokenIndex,
928 lbrace: TokenIndex,
929 statements: StatementList,
930 rbrace: TokenIndex,
931
932 pub const StatementList = Root.DeclList;
614933
615934 pub fn iterate(self: &Block, index: usize) ?&Node {
616935 var i = index;
617936
618 if (i < self.statements.len) return self.statements.items[i];
937 if (i < self.statements.len) return *self.statements.at(i);
619938 i -= self.statements.len;
620939
621940 return null;
622941 }
623942
624 pub fn firstToken(self: &Block) Token {
943 pub fn firstToken(self: &Block) TokenIndex {
625944 if (self.label) |label| {
626945 return label;
627946 }
......@@ -629,14 +948,14 @@ pub const Node = struct {
629948 return self.lbrace;
630949 }
631950
632 pub fn lastToken(self: &Block) Token {
951 pub fn lastToken(self: &Block) TokenIndex {
633952 return self.rbrace;
634953 }
635954 };
636955
637956 pub const Defer = struct {
638957 base: Node,
639 defer_token: Token,
958 defer_token: TokenIndex,
640959 kind: Kind,
641960 expr: &Node,
642961
......@@ -654,11 +973,11 @@ pub const Node = struct {
654973 return null;
655974 }
656975
657 pub fn firstToken(self: &Defer) Token {
976 pub fn firstToken(self: &Defer) TokenIndex {
658977 return self.defer_token;
659978 }
660979
661 pub fn lastToken(self: &Defer) Token {
980 pub fn lastToken(self: &Defer) TokenIndex {
662981 return self.expr.lastToken();
663982 }
664983 };
......@@ -666,7 +985,7 @@ pub const Node = struct {
666985 pub const Comptime = struct {
667986 base: Node,
668987 doc_comments: ?&DocComment,
669 comptime_token: Token,
988 comptime_token: TokenIndex,
670989 expr: &Node,
671990
672991 pub fn iterate(self: &Comptime, index: usize) ?&Node {
......@@ -678,20 +997,20 @@ pub const Node = struct {
678997 return null;
679998 }
680999
681 pub fn firstToken(self: &Comptime) Token {
1000 pub fn firstToken(self: &Comptime) TokenIndex {
6821001 return self.comptime_token;
6831002 }
6841003
685 pub fn lastToken(self: &Comptime) Token {
1004 pub fn lastToken(self: &Comptime) TokenIndex {
6861005 return self.expr.lastToken();
6871006 }
6881007 };
6891008
6901009 pub const Payload = struct {
6911010 base: Node,
692 lpipe: Token,
1011 lpipe: TokenIndex,
6931012 error_symbol: &Node,
694 rpipe: Token,
1013 rpipe: TokenIndex,
6951014
6961015 pub fn iterate(self: &Payload, index: usize) ?&Node {
6971016 var i = index;
......@@ -702,21 +1021,21 @@ pub const Node = struct {
7021021 return null;
7031022 }
7041023
705 pub fn firstToken(self: &Payload) Token {
1024 pub fn firstToken(self: &Payload) TokenIndex {
7061025 return self.lpipe;
7071026 }
7081027
709 pub fn lastToken(self: &Payload) Token {
1028 pub fn lastToken(self: &Payload) TokenIndex {
7101029 return self.rpipe;
7111030 }
7121031 };
7131032
7141033 pub const PointerPayload = struct {
7151034 base: Node,
716 lpipe: Token,
717 ptr_token: ?Token,
1035 lpipe: TokenIndex,
1036 ptr_token: ?TokenIndex,
7181037 value_symbol: &Node,
719 rpipe: Token,
1038 rpipe: TokenIndex,
7201039
7211040 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {
7221041 var i = index;
......@@ -727,22 +1046,22 @@ pub const Node = struct {
7271046 return null;
7281047 }
7291048
730 pub fn firstToken(self: &PointerPayload) Token {
1049 pub fn firstToken(self: &PointerPayload) TokenIndex {
7311050 return self.lpipe;
7321051 }
7331052
734 pub fn lastToken(self: &PointerPayload) Token {
1053 pub fn lastToken(self: &PointerPayload) TokenIndex {
7351054 return self.rpipe;
7361055 }
7371056 };
7381057
7391058 pub const PointerIndexPayload = struct {
7401059 base: Node,
741 lpipe: Token,
742 ptr_token: ?Token,
1060 lpipe: TokenIndex,
1061 ptr_token: ?TokenIndex,
7431062 value_symbol: &Node,
7441063 index_symbol: ?&Node,
745 rpipe: Token,
1064 rpipe: TokenIndex,
7461065
7471066 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {
7481067 var i = index;
......@@ -758,18 +1077,18 @@ pub const Node = struct {
7581077 return null;
7591078 }
7601079
761 pub fn firstToken(self: &PointerIndexPayload) Token {
1080 pub fn firstToken(self: &PointerIndexPayload) TokenIndex {
7621081 return self.lpipe;
7631082 }
7641083
765 pub fn lastToken(self: &PointerIndexPayload) Token {
1084 pub fn lastToken(self: &PointerIndexPayload) TokenIndex {
7661085 return self.rpipe;
7671086 }
7681087 };
7691088
7701089 pub const Else = struct {
7711090 base: Node,
772 else_token: Token,
1091 else_token: TokenIndex,
7731092 payload: ?&Node,
7741093 body: &Node,
7751094
......@@ -787,22 +1106,24 @@ pub const Node = struct {
7871106 return null;
7881107 }
7891108
790 pub fn firstToken(self: &Else) Token {
1109 pub fn firstToken(self: &Else) TokenIndex {
7911110 return self.else_token;
7921111 }
7931112
794 pub fn lastToken(self: &Else) Token {
1113 pub fn lastToken(self: &Else) TokenIndex {
7951114 return self.body.lastToken();
7961115 }
7971116 };
7981117
7991118 pub const Switch = struct {
8001119 base: Node,
801 switch_token: Token,
1120 switch_token: TokenIndex,
8021121 expr: &Node,
8031122 /// these can be SwitchCase nodes or LineComment nodes
804 cases: ArrayList(&Node),
805 rbrace: Token,
1123 cases: CaseList,
1124 rbrace: TokenIndex,
1125
1126 pub const CaseList = SegmentedList(&Node, 2);
8061127
8071128 pub fn iterate(self: &Switch, index: usize) ?&Node {
8081129 var i = index;
......@@ -810,31 +1131,33 @@ pub const Node = struct {
8101131 if (i < 1) return self.expr;
8111132 i -= 1;
8121133
813 if (i < self.cases.len) return self.cases.at(i);
1134 if (i < self.cases.len) return *self.cases.at(i);
8141135 i -= self.cases.len;
8151136
8161137 return null;
8171138 }
8181139
819 pub fn firstToken(self: &Switch) Token {
1140 pub fn firstToken(self: &Switch) TokenIndex {
8201141 return self.switch_token;
8211142 }
8221143
823 pub fn lastToken(self: &Switch) Token {
1144 pub fn lastToken(self: &Switch) TokenIndex {
8241145 return self.rbrace;
8251146 }
8261147 };
8271148
8281149 pub const SwitchCase = struct {
8291150 base: Node,
830 items: ArrayList(&Node),
1151 items: ItemList,
8311152 payload: ?&Node,
8321153 expr: &Node,
8331154
1155 pub const ItemList = SegmentedList(&Node, 1);
1156
8341157 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
8351158 var i = index;
8361159
837 if (i < self.items.len) return self.items.at(i);
1160 if (i < self.items.len) return *self.items.at(i);
8381161 i -= self.items.len;
8391162
8401163 if (self.payload) |payload| {
......@@ -848,37 +1171,37 @@ pub const Node = struct {
8481171 return null;
8491172 }
8501173
851 pub fn firstToken(self: &SwitchCase) Token {
852 return self.items.at(0).firstToken();
1174 pub fn firstToken(self: &SwitchCase) TokenIndex {
1175 return (*self.items.at(0)).firstToken();
8531176 }
8541177
855 pub fn lastToken(self: &SwitchCase) Token {
1178 pub fn lastToken(self: &SwitchCase) TokenIndex {
8561179 return self.expr.lastToken();
8571180 }
8581181 };
8591182
8601183 pub const SwitchElse = struct {
8611184 base: Node,
862 token: Token,
1185 token: TokenIndex,
8631186
8641187 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {
8651188 return null;
8661189 }
8671190
868 pub fn firstToken(self: &SwitchElse) Token {
1191 pub fn firstToken(self: &SwitchElse) TokenIndex {
8691192 return self.token;
8701193 }
8711194
872 pub fn lastToken(self: &SwitchElse) Token {
1195 pub fn lastToken(self: &SwitchElse) TokenIndex {
8731196 return self.token;
8741197 }
8751198 };
8761199
8771200 pub const While = struct {
8781201 base: Node,
879 label: ?Token,
880 inline_token: ?Token,
881 while_token: Token,
1202 label: ?TokenIndex,
1203 inline_token: ?TokenIndex,
1204 while_token: TokenIndex,
8821205 condition: &Node,
8831206 payload: ?&Node,
8841207 continue_expr: ?&Node,
......@@ -912,7 +1235,7 @@ pub const Node = struct {
9121235 return null;
9131236 }
9141237
915 pub fn firstToken(self: &While) Token {
1238 pub fn firstToken(self: &While) TokenIndex {
9161239 if (self.label) |label| {
9171240 return label;
9181241 }
......@@ -924,7 +1247,7 @@ pub const Node = struct {
9241247 return self.while_token;
9251248 }
9261249
927 pub fn lastToken(self: &While) Token {
1250 pub fn lastToken(self: &While) TokenIndex {
9281251 if (self.@"else") |@"else"| {
9291252 return @"else".body.lastToken();
9301253 }
......@@ -935,9 +1258,9 @@ pub const Node = struct {
9351258
9361259 pub const For = struct {
9371260 base: Node,
938 label: ?Token,
939 inline_token: ?Token,
940 for_token: Token,
1261 label: ?TokenIndex,
1262 inline_token: ?TokenIndex,
1263 for_token: TokenIndex,
9411264 array_expr: &Node,
9421265 payload: ?&Node,
9431266 body: &Node,
......@@ -965,7 +1288,7 @@ pub const Node = struct {
9651288 return null;
9661289 }
9671290
968 pub fn firstToken(self: &For) Token {
1291 pub fn firstToken(self: &For) TokenIndex {
9691292 if (self.label) |label| {
9701293 return label;
9711294 }
......@@ -977,7 +1300,7 @@ pub const Node = struct {
9771300 return self.for_token;
9781301 }
9791302
980 pub fn lastToken(self: &For) Token {
1303 pub fn lastToken(self: &For) TokenIndex {
9811304 if (self.@"else") |@"else"| {
9821305 return @"else".body.lastToken();
9831306 }
......@@ -988,7 +1311,7 @@ pub const Node = struct {
9881311
9891312 pub const If = struct {
9901313 base: Node,
991 if_token: Token,
1314 if_token: TokenIndex,
9921315 condition: &Node,
9931316 payload: ?&Node,
9941317 body: &Node,
......@@ -1016,11 +1339,11 @@ pub const Node = struct {
10161339 return null;
10171340 }
10181341
1019 pub fn firstToken(self: &If) Token {
1342 pub fn firstToken(self: &If) TokenIndex {
10201343 return self.if_token;
10211344 }
10221345
1023 pub fn lastToken(self: &If) Token {
1346 pub fn lastToken(self: &If) TokenIndex {
10241347 if (self.@"else") |@"else"| {
10251348 return @"else".body.lastToken();
10261349 }
......@@ -1031,7 +1354,7 @@ pub const Node = struct {
10311354
10321355 pub const InfixOp = struct {
10331356 base: Node,
1034 op_token: Token,
1357 op_token: TokenIndex,
10351358 lhs: &Node,
10361359 op: Op,
10371360 rhs: &Node,
......@@ -1146,18 +1469,18 @@ pub const Node = struct {
11461469 return null;
11471470 }
11481471
1149 pub fn firstToken(self: &InfixOp) Token {
1472 pub fn firstToken(self: &InfixOp) TokenIndex {
11501473 return self.lhs.firstToken();
11511474 }
11521475
1153 pub fn lastToken(self: &InfixOp) Token {
1476 pub fn lastToken(self: &InfixOp) TokenIndex {
11541477 return self.rhs.lastToken();
11551478 }
11561479 };
11571480
11581481 pub const PrefixOp = struct {
11591482 base: Node,
1160 op_token: Token,
1483 op_token: TokenIndex,
11611484 op: Op,
11621485 rhs: &Node,
11631486
......@@ -1168,7 +1491,6 @@ pub const Node = struct {
11681491 BitNot,
11691492 BoolNot,
11701493 Cancel,
1171 Deref,
11721494 MaybeType,
11731495 Negation,
11741496 NegationWrap,
......@@ -1180,10 +1502,10 @@ pub const Node = struct {
11801502
11811503 const AddrOfInfo = struct {
11821504 align_expr: ?&Node,
1183 bit_offset_start_token: ?Token,
1184 bit_offset_end_token: ?Token,
1185 const_token: ?Token,
1186 volatile_token: ?Token,
1505 bit_offset_start_token: ?TokenIndex,
1506 bit_offset_end_token: ?TokenIndex,
1507 const_token: ?TokenIndex,
1508 volatile_token: ?TokenIndex,
11871509 };
11881510
11891511 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
......@@ -1210,7 +1532,6 @@ pub const Node = struct {
12101532 Op.BitNot,
12111533 Op.BoolNot,
12121534 Op.Cancel,
1213 Op.Deref,
12141535 Op.MaybeType,
12151536 Op.Negation,
12161537 Op.NegationWrap,
......@@ -1225,19 +1546,19 @@ pub const Node = struct {
12251546 return null;
12261547 }
12271548
1228 pub fn firstToken(self: &PrefixOp) Token {
1549 pub fn firstToken(self: &PrefixOp) TokenIndex {
12291550 return self.op_token;
12301551 }
12311552
1232 pub fn lastToken(self: &PrefixOp) Token {
1553 pub fn lastToken(self: &PrefixOp) TokenIndex {
12331554 return self.rhs.lastToken();
12341555 }
12351556 };
12361557
12371558 pub const FieldInitializer = struct {
12381559 base: Node,
1239 period_token: Token,
1240 name_token: Token,
1560 period_token: TokenIndex,
1561 name_token: TokenIndex,
12411562 expr: &Node,
12421563
12431564 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {
......@@ -1249,11 +1570,11 @@ pub const Node = struct {
12491570 return null;
12501571 }
12511572
1252 pub fn firstToken(self: &FieldInitializer) Token {
1573 pub fn firstToken(self: &FieldInitializer) TokenIndex {
12531574 return self.period_token;
12541575 }
12551576
1256 pub fn lastToken(self: &FieldInitializer) Token {
1577 pub fn lastToken(self: &FieldInitializer) TokenIndex {
12571578 return self.expr.lastToken();
12581579 }
12591580 };
......@@ -1262,24 +1583,29 @@ pub const Node = struct {
12621583 base: Node,
12631584 lhs: &Node,
12641585 op: Op,
1265 rtoken: Token,
1586 rtoken: TokenIndex,
12661587
1267 const Op = union(enum) {
1268 Call: CallInfo,
1588 pub const Op = union(enum) {
1589 Call: Call,
12691590 ArrayAccess: &Node,
1270 Slice: SliceRange,
1271 ArrayInitializer: ArrayList(&Node),
1272 StructInitializer: ArrayList(&Node),
1273 };
1591 Slice: Slice,
1592 ArrayInitializer: InitList,
1593 StructInitializer: InitList,
1594 Deref,
12741595
1275 const CallInfo = struct {
1276 params: ArrayList(&Node),
1277 async_attr: ?&AsyncAttribute,
1278 };
1596 pub const InitList = SegmentedList(&Node, 2);
12791597
1280 const SliceRange = struct {
1281 start: &Node,
1282 end: ?&Node,
1598 pub const Call = struct {
1599 params: ParamList,
1600 async_attr: ?&AsyncAttribute,
1601
1602 pub const ParamList = SegmentedList(&Node, 2);
1603 };
1604
1605 pub const Slice = struct {
1606 start: &Node,
1607 end: ?&Node,
1608 };
12831609 };
12841610
12851611 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {
......@@ -1289,15 +1615,15 @@ pub const Node = struct {
12891615 i -= 1;
12901616
12911617 switch (self.op) {
1292 Op.Call => |call_info| {
1293 if (i < call_info.params.len) return call_info.params.at(i);
1618 @TagType(Op).Call => |*call_info| {
1619 if (i < call_info.params.len) return *call_info.params.at(i);
12941620 i -= call_info.params.len;
12951621 },
12961622 Op.ArrayAccess => |index_expr| {
12971623 if (i < 1) return index_expr;
12981624 i -= 1;
12991625 },
1300 Op.Slice => |range| {
1626 @TagType(Op).Slice => |range| {
13011627 if (i < 1) return range.start;
13021628 i -= 1;
13031629
......@@ -1306,12 +1632,12 @@ pub const Node = struct {
13061632 i -= 1;
13071633 }
13081634 },
1309 Op.ArrayInitializer => |exprs| {
1310 if (i < exprs.len) return exprs.at(i);
1635 Op.ArrayInitializer => |*exprs| {
1636 if (i < exprs.len) return *exprs.at(i);
13111637 i -= exprs.len;
13121638 },
1313 Op.StructInitializer => |fields| {
1314 if (i < fields.len) return fields.at(i);
1639 Op.StructInitializer => |*fields| {
1640 if (i < fields.len) return *fields.at(i);
13151641 i -= fields.len;
13161642 },
13171643 }
......@@ -1319,20 +1645,20 @@ pub const Node = struct {
13191645 return null;
13201646 }
13211647
1322 pub fn firstToken(self: &SuffixOp) Token {
1648 pub fn firstToken(self: &SuffixOp) TokenIndex {
13231649 return self.lhs.firstToken();
13241650 }
13251651
1326 pub fn lastToken(self: &SuffixOp) Token {
1652 pub fn lastToken(self: &SuffixOp) TokenIndex {
13271653 return self.rtoken;
13281654 }
13291655 };
13301656
13311657 pub const GroupedExpression = struct {
13321658 base: Node,
1333 lparen: Token,
1659 lparen: TokenIndex,
13341660 expr: &Node,
1335 rparen: Token,
1661 rparen: TokenIndex,
13361662
13371663 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {
13381664 var i = index;
......@@ -1343,18 +1669,18 @@ pub const Node = struct {
13431669 return null;
13441670 }
13451671
1346 pub fn firstToken(self: &GroupedExpression) Token {
1672 pub fn firstToken(self: &GroupedExpression) TokenIndex {
13471673 return self.lparen;
13481674 }
13491675
1350 pub fn lastToken(self: &GroupedExpression) Token {
1676 pub fn lastToken(self: &GroupedExpression) TokenIndex {
13511677 return self.rparen;
13521678 }
13531679 };
13541680
13551681 pub const ControlFlowExpression = struct {
13561682 base: Node,
1357 ltoken: Token,
1683 ltoken: TokenIndex,
13581684 kind: Kind,
13591685 rhs: ?&Node,
13601686
......@@ -1391,11 +1717,11 @@ pub const Node = struct {
13911717 return null;
13921718 }
13931719
1394 pub fn firstToken(self: &ControlFlowExpression) Token {
1720 pub fn firstToken(self: &ControlFlowExpression) TokenIndex {
13951721 return self.ltoken;
13961722 }
13971723
1398 pub fn lastToken(self: &ControlFlowExpression) Token {
1724 pub fn lastToken(self: &ControlFlowExpression) TokenIndex {
13991725 if (self.rhs) |rhs| {
14001726 return rhs.lastToken();
14011727 }
......@@ -1420,8 +1746,8 @@ pub const Node = struct {
14201746
14211747 pub const Suspend = struct {
14221748 base: Node,
1423 label: ?Token,
1424 suspend_token: Token,
1749 label: ?TokenIndex,
1750 suspend_token: TokenIndex,
14251751 payload: ?&Node,
14261752 body: ?&Node,
14271753
......@@ -1441,12 +1767,12 @@ pub const Node = struct {
14411767 return null;
14421768 }
14431769
1444 pub fn firstToken(self: &Suspend) Token {
1770 pub fn firstToken(self: &Suspend) TokenIndex {
14451771 if (self.label) |label| return label;
14461772 return self.suspend_token;
14471773 }
14481774
1449 pub fn lastToken(self: &Suspend) Token {
1775 pub fn lastToken(self: &Suspend) TokenIndex {
14501776 if (self.body) |body| {
14511777 return body.lastToken();
14521778 }
......@@ -1461,177 +1787,181 @@ pub const Node = struct {
14611787
14621788 pub const IntegerLiteral = struct {
14631789 base: Node,
1464 token: Token,
1790 token: TokenIndex,
14651791
14661792 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {
14671793 return null;
14681794 }
14691795
1470 pub fn firstToken(self: &IntegerLiteral) Token {
1796 pub fn firstToken(self: &IntegerLiteral) TokenIndex {
14711797 return self.token;
14721798 }
14731799
1474 pub fn lastToken(self: &IntegerLiteral) Token {
1800 pub fn lastToken(self: &IntegerLiteral) TokenIndex {
14751801 return self.token;
14761802 }
14771803 };
14781804
14791805 pub const FloatLiteral = struct {
14801806 base: Node,
1481 token: Token,
1807 token: TokenIndex,
14821808
14831809 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {
14841810 return null;
14851811 }
14861812
1487 pub fn firstToken(self: &FloatLiteral) Token {
1813 pub fn firstToken(self: &FloatLiteral) TokenIndex {
14881814 return self.token;
14891815 }
14901816
1491 pub fn lastToken(self: &FloatLiteral) Token {
1817 pub fn lastToken(self: &FloatLiteral) TokenIndex {
14921818 return self.token;
14931819 }
14941820 };
14951821
14961822 pub const BuiltinCall = struct {
14971823 base: Node,
1498 builtin_token: Token,
1499 params: ArrayList(&Node),
1500 rparen_token: Token,
1824 builtin_token: TokenIndex,
1825 params: ParamList,
1826 rparen_token: TokenIndex,
1827
1828 pub const ParamList = SegmentedList(&Node, 2);
15011829
15021830 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
15031831 var i = index;
15041832
1505 if (i < self.params.len) return self.params.at(i);
1833 if (i < self.params.len) return *self.params.at(i);
15061834 i -= self.params.len;
15071835
15081836 return null;
15091837 }
15101838
1511 pub fn firstToken(self: &BuiltinCall) Token {
1839 pub fn firstToken(self: &BuiltinCall) TokenIndex {
15121840 return self.builtin_token;
15131841 }
15141842
1515 pub fn lastToken(self: &BuiltinCall) Token {
1843 pub fn lastToken(self: &BuiltinCall) TokenIndex {
15161844 return self.rparen_token;
15171845 }
15181846 };
15191847
15201848 pub const StringLiteral = struct {
15211849 base: Node,
1522 token: Token,
1850 token: TokenIndex,
15231851
15241852 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {
15251853 return null;
15261854 }
15271855
1528 pub fn firstToken(self: &StringLiteral) Token {
1856 pub fn firstToken(self: &StringLiteral) TokenIndex {
15291857 return self.token;
15301858 }
15311859
1532 pub fn lastToken(self: &StringLiteral) Token {
1860 pub fn lastToken(self: &StringLiteral) TokenIndex {
15331861 return self.token;
15341862 }
15351863 };
15361864
15371865 pub const MultilineStringLiteral = struct {
15381866 base: Node,
1539 tokens: ArrayList(Token),
1867 lines: LineList,
1868
1869 pub const LineList = SegmentedList(TokenIndex, 4);
15401870
15411871 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {
15421872 return null;
15431873 }
15441874
1545 pub fn firstToken(self: &MultilineStringLiteral) Token {
1546 return self.tokens.at(0);
1875 pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {
1876 return *self.lines.at(0);
15471877 }
15481878
1549 pub fn lastToken(self: &MultilineStringLiteral) Token {
1550 return self.tokens.at(self.tokens.len - 1);
1879 pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {
1880 return *self.lines.at(self.lines.len - 1);
15511881 }
15521882 };
15531883
15541884 pub const CharLiteral = struct {
15551885 base: Node,
1556 token: Token,
1886 token: TokenIndex,
15571887
15581888 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {
15591889 return null;
15601890 }
15611891
1562 pub fn firstToken(self: &CharLiteral) Token {
1892 pub fn firstToken(self: &CharLiteral) TokenIndex {
15631893 return self.token;
15641894 }
15651895
1566 pub fn lastToken(self: &CharLiteral) Token {
1896 pub fn lastToken(self: &CharLiteral) TokenIndex {
15671897 return self.token;
15681898 }
15691899 };
15701900
15711901 pub const BoolLiteral = struct {
15721902 base: Node,
1573 token: Token,
1903 token: TokenIndex,
15741904
15751905 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {
15761906 return null;
15771907 }
15781908
1579 pub fn firstToken(self: &BoolLiteral) Token {
1909 pub fn firstToken(self: &BoolLiteral) TokenIndex {
15801910 return self.token;
15811911 }
15821912
1583 pub fn lastToken(self: &BoolLiteral) Token {
1913 pub fn lastToken(self: &BoolLiteral) TokenIndex {
15841914 return self.token;
15851915 }
15861916 };
15871917
15881918 pub const NullLiteral = struct {
15891919 base: Node,
1590 token: Token,
1920 token: TokenIndex,
15911921
15921922 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {
15931923 return null;
15941924 }
15951925
1596 pub fn firstToken(self: &NullLiteral) Token {
1926 pub fn firstToken(self: &NullLiteral) TokenIndex {
15971927 return self.token;
15981928 }
15991929
1600 pub fn lastToken(self: &NullLiteral) Token {
1930 pub fn lastToken(self: &NullLiteral) TokenIndex {
16011931 return self.token;
16021932 }
16031933 };
16041934
16051935 pub const UndefinedLiteral = struct {
16061936 base: Node,
1607 token: Token,
1937 token: TokenIndex,
16081938
16091939 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {
16101940 return null;
16111941 }
16121942
1613 pub fn firstToken(self: &UndefinedLiteral) Token {
1943 pub fn firstToken(self: &UndefinedLiteral) TokenIndex {
16141944 return self.token;
16151945 }
16161946
1617 pub fn lastToken(self: &UndefinedLiteral) Token {
1947 pub fn lastToken(self: &UndefinedLiteral) TokenIndex {
16181948 return self.token;
16191949 }
16201950 };
16211951
16221952 pub const ThisLiteral = struct {
16231953 base: Node,
1624 token: Token,
1954 token: TokenIndex,
16251955
16261956 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {
16271957 return null;
16281958 }
16291959
1630 pub fn firstToken(self: &ThisLiteral) Token {
1960 pub fn firstToken(self: &ThisLiteral) TokenIndex {
16311961 return self.token;
16321962 }
16331963
1634 pub fn lastToken(self: &ThisLiteral) Token {
1964 pub fn lastToken(self: &ThisLiteral) TokenIndex {
16351965 return self.token;
16361966 }
16371967 };
......@@ -1670,11 +2000,11 @@ pub const Node = struct {
16702000 return null;
16712001 }
16722002
1673 pub fn firstToken(self: &AsmOutput) Token {
2003 pub fn firstToken(self: &AsmOutput) TokenIndex {
16742004 return self.symbolic_name.firstToken();
16752005 }
16762006
1677 pub fn lastToken(self: &AsmOutput) Token {
2007 pub fn lastToken(self: &AsmOutput) TokenIndex {
16782008 return switch (self.kind) {
16792009 Kind.Variable => |variable_name| variable_name.lastToken(),
16802010 Kind.Return => |return_type| return_type.lastToken(),
......@@ -1703,139 +2033,144 @@ pub const Node = struct {
17032033 return null;
17042034 }
17052035
1706 pub fn firstToken(self: &AsmInput) Token {
2036 pub fn firstToken(self: &AsmInput) TokenIndex {
17072037 return self.symbolic_name.firstToken();
17082038 }
17092039
1710 pub fn lastToken(self: &AsmInput) Token {
2040 pub fn lastToken(self: &AsmInput) TokenIndex {
17112041 return self.expr.lastToken();
17122042 }
17132043 };
17142044
17152045 pub const Asm = struct {
17162046 base: Node,
1717 asm_token: Token,
1718 volatile_token: ?Token,
2047 asm_token: TokenIndex,
2048 volatile_token: ?TokenIndex,
17192049 template: &Node,
1720 //tokens: ArrayList(AsmToken),
1721 outputs: ArrayList(&AsmOutput),
1722 inputs: ArrayList(&AsmInput),
1723 cloppers: ArrayList(&Node),
1724 rparen: Token,
2050 outputs: OutputList,
2051 inputs: InputList,
2052 clobbers: ClobberList,
2053 rparen: TokenIndex,
2054
2055 const OutputList = SegmentedList(&AsmOutput, 2);
2056 const InputList = SegmentedList(&AsmInput, 2);
2057 const ClobberList = SegmentedList(&Node, 2);
17252058
17262059 pub fn iterate(self: &Asm, index: usize) ?&Node {
17272060 var i = index;
17282061
1729 if (i < self.outputs.len) return &self.outputs.at(index).base;
2062 if (i < self.outputs.len) return &(*self.outputs.at(index)).base;
17302063 i -= self.outputs.len;
17312064
1732 if (i < self.inputs.len) return &self.inputs.at(index).base;
2065 if (i < self.inputs.len) return &(*self.inputs.at(index)).base;
17332066 i -= self.inputs.len;
17342067
1735 if (i < self.cloppers.len) return self.cloppers.at(index);
1736 i -= self.cloppers.len;
2068 if (i < self.clobbers.len) return *self.clobbers.at(index);
2069 i -= self.clobbers.len;
17372070
17382071 return null;
17392072 }
17402073
1741 pub fn firstToken(self: &Asm) Token {
2074 pub fn firstToken(self: &Asm) TokenIndex {
17422075 return self.asm_token;
17432076 }
17442077
1745 pub fn lastToken(self: &Asm) Token {
2078 pub fn lastToken(self: &Asm) TokenIndex {
17462079 return self.rparen;
17472080 }
17482081 };
17492082
17502083 pub const Unreachable = struct {
17512084 base: Node,
1752 token: Token,
2085 token: TokenIndex,
17532086
17542087 pub fn iterate(self: &Unreachable, index: usize) ?&Node {
17552088 return null;
17562089 }
17572090
1758 pub fn firstToken(self: &Unreachable) Token {
2091 pub fn firstToken(self: &Unreachable) TokenIndex {
17592092 return self.token;
17602093 }
17612094
1762 pub fn lastToken(self: &Unreachable) Token {
2095 pub fn lastToken(self: &Unreachable) TokenIndex {
17632096 return self.token;
17642097 }
17652098 };
17662099
17672100 pub const ErrorType = struct {
17682101 base: Node,
1769 token: Token,
2102 token: TokenIndex,
17702103
17712104 pub fn iterate(self: &ErrorType, index: usize) ?&Node {
17722105 return null;
17732106 }
17742107
1775 pub fn firstToken(self: &ErrorType) Token {
2108 pub fn firstToken(self: &ErrorType) TokenIndex {
17762109 return self.token;
17772110 }
17782111
1779 pub fn lastToken(self: &ErrorType) Token {
2112 pub fn lastToken(self: &ErrorType) TokenIndex {
17802113 return self.token;
17812114 }
17822115 };
17832116
17842117 pub const VarType = struct {
17852118 base: Node,
1786 token: Token,
2119 token: TokenIndex,
17872120
17882121 pub fn iterate(self: &VarType, index: usize) ?&Node {
17892122 return null;
17902123 }
17912124
1792 pub fn firstToken(self: &VarType) Token {
2125 pub fn firstToken(self: &VarType) TokenIndex {
17932126 return self.token;
17942127 }
17952128
1796 pub fn lastToken(self: &VarType) Token {
2129 pub fn lastToken(self: &VarType) TokenIndex {
17972130 return self.token;
17982131 }
17992132 };
18002133
18012134 pub const LineComment = struct {
18022135 base: Node,
1803 token: Token,
2136 token: TokenIndex,
18042137
18052138 pub fn iterate(self: &LineComment, index: usize) ?&Node {
18062139 return null;
18072140 }
18082141
1809 pub fn firstToken(self: &LineComment) Token {
2142 pub fn firstToken(self: &LineComment) TokenIndex {
18102143 return self.token;
18112144 }
18122145
1813 pub fn lastToken(self: &LineComment) Token {
2146 pub fn lastToken(self: &LineComment) TokenIndex {
18142147 return self.token;
18152148 }
18162149 };
18172150
18182151 pub const DocComment = struct {
18192152 base: Node,
1820 lines: ArrayList(Token),
2153 lines: LineList,
2154
2155 pub const LineList = SegmentedList(TokenIndex, 4);
18212156
18222157 pub fn iterate(self: &DocComment, index: usize) ?&Node {
18232158 return null;
18242159 }
18252160
1826 pub fn firstToken(self: &DocComment) Token {
1827 return self.lines.at(0);
2161 pub fn firstToken(self: &DocComment) TokenIndex {
2162 return *self.lines.at(0);
18282163 }
18292164
1830 pub fn lastToken(self: &DocComment) Token {
1831 return self.lines.at(self.lines.len - 1);
2165 pub fn lastToken(self: &DocComment) TokenIndex {
2166 return *self.lines.at(self.lines.len - 1);
18322167 }
18332168 };
18342169
18352170 pub const TestDecl = struct {
18362171 base: Node,
18372172 doc_comments: ?&DocComment,
1838 test_token: Token,
2173 test_token: TokenIndex,
18392174 name: &Node,
18402175 body_node: &Node,
18412176
......@@ -1848,11 +2183,11 @@ pub const Node = struct {
18482183 return null;
18492184 }
18502185
1851 pub fn firstToken(self: &TestDecl) Token {
2186 pub fn firstToken(self: &TestDecl) TokenIndex {
18522187 return self.test_token;
18532188 }
18542189
1855 pub fn lastToken(self: &TestDecl) Token {
2190 pub fn lastToken(self: &TestDecl) TokenIndex {
18562191 return self.body_node.lastToken();
18572192 }
18582193 };
std/zig/index.zig+5-3
......@@ -1,11 +1,13 @@
11const tokenizer = @import("tokenizer.zig");
22pub const Token = tokenizer.Token;
33pub const Tokenizer = tokenizer.Tokenizer;
4pub const Parser = @import("parser.zig").Parser;
4pub const parse = @import("parse.zig").parse;
5pub const render = @import("render.zig").render;
56pub const ast = @import("ast.zig");
67
78test "std.zig tests" {
8 _ = @import("tokenizer.zig");
9 _ = @import("parser.zig");
109 _ = @import("ast.zig");
10 _ = @import("parse.zig");
11 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");
1113}
std/zig/parse.zig created+3470
......@@ -0,0 +1,3470 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Tokenizer = std.zig.Tokenizer;
6const Token = std.zig.Token;
7const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;
9
10/// Result should be freed with tree.deinit() when there are
11/// no more references to any of the tokens or nodes.
12pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
13 var tree_arena = std.heap.ArenaAllocator.init(allocator);
14 errdefer tree_arena.deinit();
15
16 var stack = std.ArrayList(State).init(allocator);
17 defer stack.deinit();
18
19 const arena = &tree_arena.allocator;
20 const root_node = try createNode(arena, ast.Node.Root,
21 ast.Node.Root {
22 .base = undefined,
23 .decls = ast.Node.Root.DeclList.init(arena),
24 .doc_comments = null,
25 // initialized when we get the eof token
26 .eof_token = undefined,
27 }
28 );
29
30 var tree = ast.Tree {
31 .source = source,
32 .root_node = root_node,
33 .arena_allocator = tree_arena,
34 .tokens = ast.Tree.TokenList.init(arena),
35 .errors = ast.Tree.ErrorList.init(arena),
36 };
37
38 var tokenizer = Tokenizer.init(tree.source);
39 while (true) {
40 const token_ptr = try tree.tokens.addOne();
41 *token_ptr = tokenizer.next();
42 if (token_ptr.id == Token.Id.Eof)
43 break;
44 }
45 var tok_it = tree.tokens.iterator(0);
46
47 try stack.append(State.TopLevel);
48
49 while (true) {
50 // This gives us 1 free push that can't fail
51 const state = stack.pop();
52
53 switch (state) {
54 State.TopLevel => {
55 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
56 try root_node.decls.push(&line_comment.base);
57 }
58
59 const comments = try eatDocComments(arena, &tok_it, &tree);
60
61 const token = nextToken(&tok_it, &tree);
62 const token_index = token.index;
63 const token_ptr = token.ptr;
64 switch (token_ptr.id) {
65 Token.Id.Keyword_test => {
66 stack.append(State.TopLevel) catch unreachable;
67
68 const block = try arena.construct(ast.Node.Block {
69 .base = ast.Node {
70 .id = ast.Node.Id.Block,
71 },
72 .label = null,
73 .lbrace = undefined,
74 .statements = ast.Node.Block.StatementList.init(arena),
75 .rbrace = undefined,
76 });
77 const test_node = try arena.construct(ast.Node.TestDecl {
78 .base = ast.Node {
79 .id = ast.Node.Id.TestDecl,
80 },
81 .doc_comments = comments,
82 .test_token = token_index,
83 .name = undefined,
84 .body_node = &block.base,
85 });
86 try root_node.decls.push(&test_node.base);
87 try stack.append(State { .Block = block });
88 try stack.append(State {
89 .ExpectTokenSave = ExpectTokenSave {
90 .id = Token.Id.LBrace,
91 .ptr = &block.rbrace,
92 }
93 });
94 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
95 continue;
96 },
97 Token.Id.Eof => {
98 root_node.eof_token = token_index;
99 root_node.doc_comments = comments;
100 return tree;
101 },
102 Token.Id.Keyword_pub => {
103 stack.append(State.TopLevel) catch unreachable;
104 try stack.append(State {
105 .TopLevelExtern = TopLevelDeclCtx {
106 .decls = &root_node.decls,
107 .visib_token = token_index,
108 .extern_export_inline_token = null,
109 .lib_name = null,
110 .comments = comments,
111 }
112 });
113 continue;
114 },
115 Token.Id.Keyword_comptime => {
116 const block = try createNode(arena, ast.Node.Block,
117 ast.Node.Block {
118 .base = undefined,
119 .label = null,
120 .lbrace = undefined,
121 .statements = ast.Node.Block.StatementList.init(arena),
122 .rbrace = undefined,
123 }
124 );
125 const node = try arena.construct(ast.Node.Comptime {
126 .base = ast.Node {
127 .id = ast.Node.Id.Comptime,
128 },
129 .comptime_token = token_index,
130 .expr = &block.base,
131 .doc_comments = comments,
132 });
133 try root_node.decls.push(&node.base);
134
135 stack.append(State.TopLevel) catch unreachable;
136 try stack.append(State { .Block = block });
137 try stack.append(State {
138 .ExpectTokenSave = ExpectTokenSave {
139 .id = Token.Id.LBrace,
140 .ptr = &block.rbrace,
141 }
142 });
143 continue;
144 },
145 else => {
146 putBackToken(&tok_it, &tree);
147 stack.append(State.TopLevel) catch unreachable;
148 try stack.append(State {
149 .TopLevelExtern = TopLevelDeclCtx {
150 .decls = &root_node.decls,
151 .visib_token = null,
152 .extern_export_inline_token = null,
153 .lib_name = null,
154 .comments = comments,
155 }
156 });
157 continue;
158 },
159 }
160 },
161 State.TopLevelExtern => |ctx| {
162 const token = nextToken(&tok_it, &tree);
163 const token_index = token.index;
164 const token_ptr = token.ptr;
165 switch (token_ptr.id) {
166 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
167 stack.append(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.append(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 putBackToken(&tok_it, &tree);
198 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
199 continue;
200 }
201 }
202 },
203 State.TopLevelLibname => |ctx| {
204 const lib_name = blk: {
205 const lib_name_token = nextToken(&tok_it, &tree);
206 const lib_name_token_index = lib_name_token.index;
207 const lib_name_token_ptr = lib_name_token.ptr;
208 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
209 putBackToken(&tok_it, &tree);
210 break :blk null;
211 };
212 };
213
214 stack.append(State {
215 .TopLevelDecl = TopLevelDeclCtx {
216 .decls = ctx.decls,
217 .visib_token = ctx.visib_token,
218 .extern_export_inline_token = ctx.extern_export_inline_token,
219 .lib_name = lib_name,
220 .comments = ctx.comments,
221 },
222 }) catch unreachable;
223 continue;
224 },
225 State.TopLevelDecl => |ctx| {
226 const token = nextToken(&tok_it, &tree);
227 const token_index = token.index;
228 const token_ptr = token.ptr;
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.append(State {
248 .ExpectTokenSave = ExpectTokenSave {
249 .id = Token.Id.Semicolon,
250 .ptr = &node.semicolon_token,
251 }
252 }) catch unreachable;
253 try stack.append(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.append(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.append(State { .FnDef = fn_proto }) catch unreachable;
301 try stack.append(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.append(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.append(State {
326 .ExpectTokenSave = ExpectTokenSave {
327 .id = Token.Id.Keyword_fn,
328 .ptr = &fn_proto.fn_token,
329 }
330 });
331 try stack.append(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, &tree, 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.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
365 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
366 try stack.append(State { .ExpectToken = Token.Id.Colon });
367 continue;
368 }
369
370 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
371 try stack.append(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 = nextToken(&tok_it, &tree);
385 const eq_tok_index = eq_tok.index;
386 const eq_tok_ptr = eq_tok.ptr;
387 if (eq_tok_ptr.id != Token.Id.Equal) {
388 putBackToken(&tok_it, &tree);
389 continue;
390 }
391 stack.append(State { .Expression = ctx }) catch unreachable;
392 continue;
393 },
394
395 State.ContainerKind => |ctx| {
396 const token = nextToken(&tok_it, &tree);
397 const token_index = token.index;
398 const token_ptr = token.ptr;
399 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
400 ast.Node.ContainerDecl {
401 .base = undefined,
402 .ltoken = ctx.ltoken,
403 .layout = ctx.layout,
404 .kind = switch (token_ptr.id) {
405 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
406 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
407 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
408 else => {
409 *(try tree.errors.addOne()) = Error {
410 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
411 };
412 return tree;
413 },
414 },
415 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
416 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
417 .rbrace_token = undefined,
418 }
419 );
420
421 stack.append(State { .ContainerDecl = node }) catch unreachable;
422 try stack.append(State { .ExpectToken = Token.Id.LBrace });
423 try stack.append(State { .ContainerInitArgStart = node });
424 continue;
425 },
426
427 State.ContainerInitArgStart => |container_decl| {
428 if (eatToken(&tok_it, &tree, Token.Id.LParen) == null) {
429 continue;
430 }
431
432 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
433 try stack.append(State { .ContainerInitArg = container_decl });
434 continue;
435 },
436
437 State.ContainerInitArg => |container_decl| {
438 const init_arg_token = nextToken(&tok_it, &tree);
439 const init_arg_token_index = init_arg_token.index;
440 const init_arg_token_ptr = init_arg_token.ptr;
441 switch (init_arg_token_ptr.id) {
442 Token.Id.Keyword_enum => {
443 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
444 const lparen_tok = nextToken(&tok_it, &tree);
445 const lparen_tok_index = lparen_tok.index;
446 const lparen_tok_ptr = lparen_tok.ptr;
447 if (lparen_tok_ptr.id == Token.Id.LParen) {
448 try stack.append(State { .ExpectToken = Token.Id.RParen } );
449 try stack.append(State { .Expression = OptionalCtx {
450 .RequiredNull = &container_decl.init_arg_expr.Enum,
451 } });
452 } else {
453 putBackToken(&tok_it, &tree);
454 }
455 },
456 else => {
457 putBackToken(&tok_it, &tree);
458 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
459 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
460 },
461 }
462 continue;
463 },
464
465 State.ContainerDecl => |container_decl| {
466 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
467 try container_decl.fields_and_decls.push(&line_comment.base);
468 }
469
470 const comments = try eatDocComments(arena, &tok_it, &tree);
471 const token = nextToken(&tok_it, &tree);
472 const token_index = token.index;
473 const token_ptr = token.ptr;
474 switch (token_ptr.id) {
475 Token.Id.Identifier => {
476 switch (container_decl.kind) {
477 ast.Node.ContainerDecl.Kind.Struct => {
478 const node = try arena.construct(ast.Node.StructField {
479 .base = ast.Node {
480 .id = ast.Node.Id.StructField,
481 },
482 .doc_comments = comments,
483 .visib_token = null,
484 .name_token = token_index,
485 .type_expr = undefined,
486 });
487 const node_ptr = try container_decl.fields_and_decls.addOne();
488 *node_ptr = &node.base;
489
490 try stack.append(State { .FieldListCommaOrEnd = container_decl });
491 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
492 try stack.append(State { .ExpectToken = Token.Id.Colon });
493 continue;
494 },
495 ast.Node.ContainerDecl.Kind.Union => {
496 const node = try arena.construct(ast.Node.UnionTag {
497 .base = ast.Node {.id = ast.Node.Id.UnionTag },
498 .name_token = token_index,
499 .type_expr = null,
500 .value_expr = null,
501 .doc_comments = comments,
502 });
503 try container_decl.fields_and_decls.push(&node.base);
504
505 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
506 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
507 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
508 try stack.append(State { .IfToken = Token.Id.Colon });
509 continue;
510 },
511 ast.Node.ContainerDecl.Kind.Enum => {
512 const node = try arena.construct(ast.Node.EnumTag {
513 .base = ast.Node { .id = ast.Node.Id.EnumTag },
514 .name_token = token_index,
515 .value = null,
516 .doc_comments = comments,
517 });
518 try container_decl.fields_and_decls.push(&node.base);
519
520 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
521 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
522 try stack.append(State { .IfToken = Token.Id.Equal });
523 continue;
524 },
525 }
526 },
527 Token.Id.Keyword_pub => {
528 switch (container_decl.kind) {
529 ast.Node.ContainerDecl.Kind.Struct => {
530 try stack.append(State {
531 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
532 .visib_token = token_index,
533 .container_decl = container_decl,
534 .comments = comments,
535 }
536 });
537 continue;
538 },
539 else => {
540 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
541 try stack.append(State {
542 .TopLevelExtern = TopLevelDeclCtx {
543 .decls = &container_decl.fields_and_decls,
544 .visib_token = token_index,
545 .extern_export_inline_token = null,
546 .lib_name = null,
547 .comments = comments,
548 }
549 });
550 continue;
551 }
552 }
553 },
554 Token.Id.Keyword_export => {
555 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
556 try stack.append(State {
557 .TopLevelExtern = TopLevelDeclCtx {
558 .decls = &container_decl.fields_and_decls,
559 .visib_token = token_index,
560 .extern_export_inline_token = null,
561 .lib_name = null,
562 .comments = comments,
563 }
564 });
565 continue;
566 },
567 Token.Id.RBrace => {
568 if (comments != null) {
569 *(try tree.errors.addOne()) = Error {
570 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
571 };
572 return tree;
573 }
574 container_decl.rbrace_token = token_index;
575 continue;
576 },
577 else => {
578 putBackToken(&tok_it, &tree);
579 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
580 try stack.append(State {
581 .TopLevelExtern = TopLevelDeclCtx {
582 .decls = &container_decl.fields_and_decls,
583 .visib_token = null,
584 .extern_export_inline_token = null,
585 .lib_name = null,
586 .comments = comments,
587 }
588 });
589 continue;
590 }
591 }
592 },
593
594
595 State.VarDecl => |ctx| {
596 const var_decl = try arena.construct(ast.Node.VarDecl {
597 .base = ast.Node {
598 .id = ast.Node.Id.VarDecl,
599 },
600 .doc_comments = ctx.comments,
601 .visib_token = ctx.visib_token,
602 .mut_token = ctx.mut_token,
603 .comptime_token = ctx.comptime_token,
604 .extern_export_token = ctx.extern_export_token,
605 .type_node = null,
606 .align_node = null,
607 .init_node = null,
608 .lib_name = ctx.lib_name,
609 // initialized later
610 .name_token = undefined,
611 .eq_token = undefined,
612 .semicolon_token = undefined,
613 });
614 try ctx.list.push(&var_decl.base);
615
616 try stack.append(State { .VarDeclAlign = var_decl });
617 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
618 try stack.append(State { .IfToken = Token.Id.Colon });
619 try stack.append(State {
620 .ExpectTokenSave = ExpectTokenSave {
621 .id = Token.Id.Identifier,
622 .ptr = &var_decl.name_token,
623 }
624 });
625 continue;
626 },
627 State.VarDeclAlign => |var_decl| {
628 try stack.append(State { .VarDeclEq = var_decl });
629
630 const next_token = nextToken(&tok_it, &tree);
631 const next_token_index = next_token.index;
632 const next_token_ptr = next_token.ptr;
633 if (next_token_ptr.id == Token.Id.Keyword_align) {
634 try stack.append(State { .ExpectToken = Token.Id.RParen });
635 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
636 try stack.append(State { .ExpectToken = Token.Id.LParen });
637 continue;
638 }
639
640 putBackToken(&tok_it, &tree);
641 continue;
642 },
643 State.VarDeclEq => |var_decl| {
644 const token = nextToken(&tok_it, &tree);
645 const token_index = token.index;
646 const token_ptr = token.ptr;
647 switch (token_ptr.id) {
648 Token.Id.Equal => {
649 var_decl.eq_token = token_index;
650 stack.append(State {
651 .ExpectTokenSave = ExpectTokenSave {
652 .id = Token.Id.Semicolon,
653 .ptr = &var_decl.semicolon_token,
654 },
655 }) catch unreachable;
656 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
657 continue;
658 },
659 Token.Id.Semicolon => {
660 var_decl.semicolon_token = token_index;
661 continue;
662 },
663 else => {
664 *(try tree.errors.addOne()) = Error {
665 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
666 };
667 return tree;
668 }
669 }
670 },
671
672
673 State.FnDef => |fn_proto| {
674 const token = nextToken(&tok_it, &tree);
675 const token_index = token.index;
676 const token_ptr = token.ptr;
677 switch(token_ptr.id) {
678 Token.Id.LBrace => {
679 const block = try arena.construct(ast.Node.Block {
680 .base = ast.Node { .id = ast.Node.Id.Block },
681 .label = null,
682 .lbrace = token_index,
683 .statements = ast.Node.Block.StatementList.init(arena),
684 .rbrace = undefined,
685 });
686 fn_proto.body_node = &block.base;
687 stack.append(State { .Block = block }) catch unreachable;
688 continue;
689 },
690 Token.Id.Semicolon => continue,
691 else => {
692 *(try tree.errors.addOne()) = Error {
693 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
694 };
695 return tree;
696 },
697 }
698 },
699 State.FnProto => |fn_proto| {
700 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
701 try stack.append(State { .ParamDecl = fn_proto });
702 try stack.append(State { .ExpectToken = Token.Id.LParen });
703
704 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {
705 fn_proto.name_token = name_token;
706 }
707 continue;
708 },
709 State.FnProtoAlign => |fn_proto| {
710 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
711
712 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {
713 try stack.append(State { .ExpectToken = Token.Id.RParen });
714 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
715 try stack.append(State { .ExpectToken = Token.Id.LParen });
716 }
717 continue;
718 },
719 State.FnProtoReturnType => |fn_proto| {
720 const token = nextToken(&tok_it, &tree);
721 const token_index = token.index;
722 const token_ptr = token.ptr;
723 switch (token_ptr.id) {
724 Token.Id.Bang => {
725 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
726 stack.append(State {
727 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
728 }) catch unreachable;
729 continue;
730 },
731 else => {
732 // TODO: this is a special case. Remove this when #760 is fixed
733 if (token_ptr.id == Token.Id.Keyword_error) {
734 if ((??tok_it.peek()).id == Token.Id.LBrace) {
735 const error_type_node = try arena.construct(ast.Node.ErrorType {
736 .base = ast.Node { .id = ast.Node.Id.ErrorType },
737 .token = token_index,
738 });
739 fn_proto.return_type = ast.Node.FnProto.ReturnType {
740 .Explicit = &error_type_node.base,
741 };
742 continue;
743 }
744 }
745
746 putBackToken(&tok_it, &tree);
747 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
748 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
749 continue;
750 },
751 }
752 },
753
754
755 State.ParamDecl => |fn_proto| {
756 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
757 continue;
758 }
759 const param_decl = try arena.construct(ast.Node.ParamDecl {
760 .base = ast.Node {.id = ast.Node.Id.ParamDecl },
761 .comptime_token = null,
762 .noalias_token = null,
763 .name_token = null,
764 .type_node = undefined,
765 .var_args_token = null,
766 });
767 try fn_proto.params.push(&param_decl.base);
768
769 stack.append(State {
770 .ParamDeclEnd = ParamDeclEndCtx {
771 .param_decl = param_decl,
772 .fn_proto = fn_proto,
773 }
774 }) catch unreachable;
775 try stack.append(State { .ParamDeclName = param_decl });
776 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
777 continue;
778 },
779 State.ParamDeclAliasOrComptime => |param_decl| {
780 if (eatToken(&tok_it, &tree, Token.Id.Keyword_comptime)) |comptime_token| {
781 param_decl.comptime_token = comptime_token;
782 } else if (eatToken(&tok_it, &tree, Token.Id.Keyword_noalias)) |noalias_token| {
783 param_decl.noalias_token = noalias_token;
784 }
785 continue;
786 },
787 State.ParamDeclName => |param_decl| {
788 // TODO: Here, we eat two tokens in one state. This means that we can't have
789 // comments between these two tokens.
790 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
791 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
792 param_decl.name_token = ident_token;
793 } else {
794 putBackToken(&tok_it, &tree);
795 }
796 }
797 continue;
798 },
799 State.ParamDeclEnd => |ctx| {
800 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
801 ctx.param_decl.var_args_token = ellipsis3;
802 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
803 continue;
804 }
805
806 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
807 try stack.append(State {
808 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
809 });
810 continue;
811 },
812 State.ParamDeclComma => |fn_proto| {
813 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
814 ExpectCommaOrEndResult.end_token => |t| {
815 if (t == null) {
816 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
817 }
818 continue;
819 },
820 ExpectCommaOrEndResult.parse_error => |e| {
821 try tree.errors.push(e);
822 return tree;
823 },
824 }
825 },
826
827 State.MaybeLabeledExpression => |ctx| {
828 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
829 stack.append(State {
830 .LabeledExpression = LabelCtx {
831 .label = ctx.label,
832 .opt_ctx = ctx.opt_ctx,
833 }
834 }) catch unreachable;
835 continue;
836 }
837
838 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
839 continue;
840 },
841 State.LabeledExpression => |ctx| {
842 const token = nextToken(&tok_it, &tree);
843 const token_index = token.index;
844 const token_ptr = token.ptr;
845 switch (token_ptr.id) {
846 Token.Id.LBrace => {
847 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
848 ast.Node.Block {
849 .base = undefined,
850 .label = ctx.label,
851 .lbrace = token_index,
852 .statements = ast.Node.Block.StatementList.init(arena),
853 .rbrace = undefined,
854 }
855 );
856 stack.append(State { .Block = block }) catch unreachable;
857 continue;
858 },
859 Token.Id.Keyword_while => {
860 stack.append(State {
861 .While = LoopCtx {
862 .label = ctx.label,
863 .inline_token = null,
864 .loop_token = token_index,
865 .opt_ctx = ctx.opt_ctx.toRequired(),
866 }
867 }) catch unreachable;
868 continue;
869 },
870 Token.Id.Keyword_for => {
871 stack.append(State {
872 .For = LoopCtx {
873 .label = ctx.label,
874 .inline_token = null,
875 .loop_token = token_index,
876 .opt_ctx = ctx.opt_ctx.toRequired(),
877 }
878 }) catch unreachable;
879 continue;
880 },
881 Token.Id.Keyword_suspend => {
882 const node = try arena.construct(ast.Node.Suspend {
883 .base = ast.Node {
884 .id = ast.Node.Id.Suspend,
885 },
886 .label = ctx.label,
887 .suspend_token = token_index,
888 .payload = null,
889 .body = null,
890 });
891 ctx.opt_ctx.store(&node.base);
892 stack.append(State { .SuspendBody = node }) catch unreachable;
893 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
894 continue;
895 },
896 Token.Id.Keyword_inline => {
897 stack.append(State {
898 .Inline = InlineCtx {
899 .label = ctx.label,
900 .inline_token = token_index,
901 .opt_ctx = ctx.opt_ctx.toRequired(),
902 }
903 }) catch unreachable;
904 continue;
905 },
906 else => {
907 if (ctx.opt_ctx != OptionalCtx.Optional) {
908 *(try tree.errors.addOne()) = Error {
909 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
910 };
911 return tree;
912 }
913
914 putBackToken(&tok_it, &tree);
915 continue;
916 },
917 }
918 },
919 State.Inline => |ctx| {
920 const token = nextToken(&tok_it, &tree);
921 const token_index = token.index;
922 const token_ptr = token.ptr;
923 switch (token_ptr.id) {
924 Token.Id.Keyword_while => {
925 stack.append(State {
926 .While = 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 Token.Id.Keyword_for => {
936 stack.append(State {
937 .For = LoopCtx {
938 .inline_token = ctx.inline_token,
939 .label = ctx.label,
940 .loop_token = token_index,
941 .opt_ctx = ctx.opt_ctx.toRequired(),
942 }
943 }) catch unreachable;
944 continue;
945 },
946 else => {
947 if (ctx.opt_ctx != OptionalCtx.Optional) {
948 *(try tree.errors.addOne()) = Error {
949 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
950 };
951 return tree;
952 }
953
954 putBackToken(&tok_it, &tree);
955 continue;
956 },
957 }
958 },
959 State.While => |ctx| {
960 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
961 ast.Node.While {
962 .base = undefined,
963 .label = ctx.label,
964 .inline_token = ctx.inline_token,
965 .while_token = ctx.loop_token,
966 .condition = undefined,
967 .payload = null,
968 .continue_expr = null,
969 .body = undefined,
970 .@"else" = null,
971 }
972 );
973 stack.append(State { .Else = &node.@"else" }) catch unreachable;
974 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
975 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
976 try stack.append(State { .IfToken = Token.Id.Colon });
977 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
978 try stack.append(State { .ExpectToken = Token.Id.RParen });
979 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
980 try stack.append(State { .ExpectToken = Token.Id.LParen });
981 continue;
982 },
983 State.WhileContinueExpr => |dest| {
984 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
985 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
986 try stack.append(State { .ExpectToken = Token.Id.LParen });
987 continue;
988 },
989 State.For => |ctx| {
990 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
991 ast.Node.For {
992 .base = undefined,
993 .label = ctx.label,
994 .inline_token = ctx.inline_token,
995 .for_token = ctx.loop_token,
996 .array_expr = undefined,
997 .payload = null,
998 .body = undefined,
999 .@"else" = null,
1000 }
1001 );
1002 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1003 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1004 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1005 try stack.append(State { .ExpectToken = Token.Id.RParen });
1006 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1007 try stack.append(State { .ExpectToken = Token.Id.LParen });
1008 continue;
1009 },
1010 State.Else => |dest| {
1011 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
1012 const node = try createNode(arena, ast.Node.Else,
1013 ast.Node.Else {
1014 .base = undefined,
1015 .else_token = else_token,
1016 .payload = null,
1017 .body = undefined,
1018 }
1019 );
1020 *dest = node;
1021
1022 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1023 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1024 continue;
1025 } else {
1026 continue;
1027 }
1028 },
1029
1030
1031 State.Block => |block| {
1032 const token = nextToken(&tok_it, &tree);
1033 const token_index = token.index;
1034 const token_ptr = token.ptr;
1035 switch (token_ptr.id) {
1036 Token.Id.RBrace => {
1037 block.rbrace = token_index;
1038 continue;
1039 },
1040 else => {
1041 putBackToken(&tok_it, &tree);
1042 stack.append(State { .Block = block }) catch unreachable;
1043
1044 var any_comments = false;
1045 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1046 try block.statements.push(&line_comment.base);
1047 any_comments = true;
1048 }
1049 if (any_comments) continue;
1050
1051 try stack.append(State { .Statement = block });
1052 continue;
1053 },
1054 }
1055 },
1056 State.Statement => |block| {
1057 const token = nextToken(&tok_it, &tree);
1058 const token_index = token.index;
1059 const token_ptr = token.ptr;
1060 switch (token_ptr.id) {
1061 Token.Id.Keyword_comptime => {
1062 stack.append(State {
1063 .ComptimeStatement = ComptimeStatementCtx {
1064 .comptime_token = token_index,
1065 .block = block,
1066 }
1067 }) catch unreachable;
1068 continue;
1069 },
1070 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1071 stack.append(State {
1072 .VarDecl = VarDeclCtx {
1073 .comments = null,
1074 .visib_token = null,
1075 .comptime_token = null,
1076 .extern_export_token = null,
1077 .lib_name = null,
1078 .mut_token = token_index,
1079 .list = &block.statements,
1080 }
1081 }) catch unreachable;
1082 continue;
1083 },
1084 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1085 const node = try arena.construct(ast.Node.Defer {
1086 .base = ast.Node {
1087 .id = ast.Node.Id.Defer,
1088 },
1089 .defer_token = token_index,
1090 .kind = switch (token_ptr.id) {
1091 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1092 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1093 else => unreachable,
1094 },
1095 .expr = undefined,
1096 });
1097 const node_ptr = try block.statements.addOne();
1098 *node_ptr = &node.base;
1099
1100 stack.append(State { .Semicolon = node_ptr }) catch unreachable;
1101 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1102 continue;
1103 },
1104 Token.Id.LBrace => {
1105 const inner_block = try arena.construct(ast.Node.Block {
1106 .base = ast.Node { .id = ast.Node.Id.Block },
1107 .label = null,
1108 .lbrace = token_index,
1109 .statements = ast.Node.Block.StatementList.init(arena),
1110 .rbrace = undefined,
1111 });
1112 try block.statements.push(&inner_block.base);
1113
1114 stack.append(State { .Block = inner_block }) catch unreachable;
1115 continue;
1116 },
1117 else => {
1118 putBackToken(&tok_it, &tree);
1119 const statement = try block.statements.addOne();
1120 try stack.append(State { .Semicolon = statement });
1121 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1122 continue;
1123 }
1124 }
1125 },
1126 State.ComptimeStatement => |ctx| {
1127 const token = nextToken(&tok_it, &tree);
1128 const token_index = token.index;
1129 const token_ptr = token.ptr;
1130 switch (token_ptr.id) {
1131 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1132 stack.append(State {
1133 .VarDecl = VarDeclCtx {
1134 .comments = null,
1135 .visib_token = null,
1136 .comptime_token = ctx.comptime_token,
1137 .extern_export_token = null,
1138 .lib_name = null,
1139 .mut_token = token_index,
1140 .list = &ctx.block.statements,
1141 }
1142 }) catch unreachable;
1143 continue;
1144 },
1145 else => {
1146 putBackToken(&tok_it, &tree);
1147 putBackToken(&tok_it, &tree);
1148 const statement = try ctx.block.statements.addOne();
1149 try stack.append(State { .Semicolon = statement });
1150 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1151 continue;
1152 }
1153 }
1154 },
1155 State.Semicolon => |node_ptr| {
1156 const node = *node_ptr;
1157 if (node.requireSemiColon()) {
1158 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1159 continue;
1160 }
1161 continue;
1162 },
1163
1164 State.AsmOutputItems => |items| {
1165 const lbracket = nextToken(&tok_it, &tree);
1166 const lbracket_index = lbracket.index;
1167 const lbracket_ptr = lbracket.ptr;
1168 if (lbracket_ptr.id != Token.Id.LBracket) {
1169 putBackToken(&tok_it, &tree);
1170 continue;
1171 }
1172
1173 const node = try createNode(arena, ast.Node.AsmOutput,
1174 ast.Node.AsmOutput {
1175 .base = undefined,
1176 .symbolic_name = undefined,
1177 .constraint = undefined,
1178 .kind = undefined,
1179 }
1180 );
1181 try items.push(node);
1182
1183 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1184 try stack.append(State { .IfToken = Token.Id.Comma });
1185 try stack.append(State { .ExpectToken = Token.Id.RParen });
1186 try stack.append(State { .AsmOutputReturnOrType = node });
1187 try stack.append(State { .ExpectToken = Token.Id.LParen });
1188 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1189 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1190 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1191 continue;
1192 },
1193 State.AsmOutputReturnOrType => |node| {
1194 const token = nextToken(&tok_it, &tree);
1195 const token_index = token.index;
1196 const token_ptr = token.ptr;
1197 switch (token_ptr.id) {
1198 Token.Id.Identifier => {
1199 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1200 continue;
1201 },
1202 Token.Id.Arrow => {
1203 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1204 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1205 continue;
1206 },
1207 else => {
1208 *(try tree.errors.addOne()) = Error {
1209 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1210 .token = token_index,
1211 },
1212 };
1213 return tree;
1214 },
1215 }
1216 },
1217 State.AsmInputItems => |items| {
1218 const lbracket = nextToken(&tok_it, &tree);
1219 const lbracket_index = lbracket.index;
1220 const lbracket_ptr = lbracket.ptr;
1221 if (lbracket_ptr.id != Token.Id.LBracket) {
1222 putBackToken(&tok_it, &tree);
1223 continue;
1224 }
1225
1226 const node = try createNode(arena, ast.Node.AsmInput,
1227 ast.Node.AsmInput {
1228 .base = undefined,
1229 .symbolic_name = undefined,
1230 .constraint = undefined,
1231 .expr = undefined,
1232 }
1233 );
1234 try items.push(node);
1235
1236 stack.append(State { .AsmInputItems = items }) catch unreachable;
1237 try stack.append(State { .IfToken = Token.Id.Comma });
1238 try stack.append(State { .ExpectToken = Token.Id.RParen });
1239 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1240 try stack.append(State { .ExpectToken = Token.Id.LParen });
1241 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1242 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1243 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1244 continue;
1245 },
1246 State.AsmClobberItems => |items| {
1247 stack.append(State { .AsmClobberItems = items }) catch unreachable;
1248 try stack.append(State { .IfToken = Token.Id.Comma });
1249 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1250 continue;
1251 },
1252
1253
1254 State.ExprListItemOrEnd => |list_state| {
1255 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {
1256 *list_state.ptr = token_index;
1257 continue;
1258 }
1259
1260 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1261 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1262 continue;
1263 },
1264 State.ExprListCommaOrEnd => |list_state| {
1265 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {
1266 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1267 *list_state.ptr = end;
1268 continue;
1269 } else {
1270 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1271 continue;
1272 },
1273 ExpectCommaOrEndResult.parse_error => |e| {
1274 try tree.errors.push(e);
1275 return tree;
1276 },
1277 }
1278 },
1279 State.FieldInitListItemOrEnd => |list_state| {
1280 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1281 try list_state.list.push(&line_comment.base);
1282 }
1283
1284 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1285 *list_state.ptr = rbrace;
1286 continue;
1287 }
1288
1289 const node = try arena.construct(ast.Node.FieldInitializer {
1290 .base = ast.Node {
1291 .id = ast.Node.Id.FieldInitializer,
1292 },
1293 .period_token = undefined,
1294 .name_token = undefined,
1295 .expr = undefined,
1296 });
1297 try list_state.list.push(&node.base);
1298
1299 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1300 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1301 try stack.append(State { .ExpectToken = Token.Id.Equal });
1302 try stack.append(State {
1303 .ExpectTokenSave = ExpectTokenSave {
1304 .id = Token.Id.Identifier,
1305 .ptr = &node.name_token,
1306 }
1307 });
1308 try stack.append(State {
1309 .ExpectTokenSave = ExpectTokenSave {
1310 .id = Token.Id.Period,
1311 .ptr = &node.period_token,
1312 }
1313 });
1314 continue;
1315 },
1316 State.FieldInitListCommaOrEnd => |list_state| {
1317 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1318 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1319 *list_state.ptr = end;
1320 continue;
1321 } else {
1322 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1323 continue;
1324 },
1325 ExpectCommaOrEndResult.parse_error => |e| {
1326 try tree.errors.push(e);
1327 return tree;
1328 },
1329 }
1330 },
1331 State.FieldListCommaOrEnd => |container_decl| {
1332 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1333 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1334 container_decl.rbrace_token = end;
1335 continue;
1336 } else {
1337 try stack.append(State { .ContainerDecl = container_decl });
1338 continue;
1339 },
1340 ExpectCommaOrEndResult.parse_error => |e| {
1341 try tree.errors.push(e);
1342 return tree;
1343 },
1344 }
1345 },
1346 State.ErrorTagListItemOrEnd => |list_state| {
1347 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1348 try list_state.list.push(&line_comment.base);
1349 }
1350
1351 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1352 *list_state.ptr = rbrace;
1353 continue;
1354 }
1355
1356 const node_ptr = try list_state.list.addOne();
1357
1358 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1359 try stack.append(State { .ErrorTag = node_ptr });
1360 continue;
1361 },
1362 State.ErrorTagListCommaOrEnd => |list_state| {
1363 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1364 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1365 *list_state.ptr = end;
1366 continue;
1367 } else {
1368 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1369 continue;
1370 },
1371 ExpectCommaOrEndResult.parse_error => |e| {
1372 try tree.errors.push(e);
1373 return tree;
1374 },
1375 }
1376 },
1377 State.SwitchCaseOrEnd => |list_state| {
1378 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1379 try list_state.list.push(&line_comment.base);
1380 }
1381
1382 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1383 *list_state.ptr = rbrace;
1384 continue;
1385 }
1386
1387 const comments = try eatDocComments(arena, &tok_it, &tree);
1388 const node = try arena.construct(ast.Node.SwitchCase {
1389 .base = ast.Node {
1390 .id = ast.Node.Id.SwitchCase,
1391 },
1392 .items = ast.Node.SwitchCase.ItemList.init(arena),
1393 .payload = null,
1394 .expr = undefined,
1395 });
1396 try list_state.list.push(&node.base);
1397 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1398 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1399 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1400 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1401
1402 continue;
1403 },
1404
1405 State.SwitchCaseCommaOrEnd => |list_state| {
1406 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
1407 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1408 *list_state.ptr = end;
1409 continue;
1410 } else {
1411 try stack.append(State { .SwitchCaseOrEnd = list_state });
1412 continue;
1413 },
1414 ExpectCommaOrEndResult.parse_error => |e| {
1415 try tree.errors.push(e);
1416 return tree;
1417 },
1418 }
1419 },
1420
1421 State.SwitchCaseFirstItem => |case_items| {
1422 const token = nextToken(&tok_it, &tree);
1423 const token_index = token.index;
1424 const token_ptr = token.ptr;
1425 if (token_ptr.id == Token.Id.Keyword_else) {
1426 const else_node = try arena.construct(ast.Node.SwitchElse {
1427 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},
1428 .token = token_index,
1429 });
1430 try case_items.push(&else_node.base);
1431
1432 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1433 continue;
1434 } else {
1435 putBackToken(&tok_it, &tree);
1436 try stack.append(State { .SwitchCaseItem = case_items });
1437 continue;
1438 }
1439 },
1440 State.SwitchCaseItem => |case_items| {
1441 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1442 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1443 },
1444 State.SwitchCaseItemCommaOrEnd => |case_items| {
1445 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1446 ExpectCommaOrEndResult.end_token => |t| {
1447 if (t == null) {
1448 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1449 }
1450 continue;
1451 },
1452 ExpectCommaOrEndResult.parse_error => |e| {
1453 try tree.errors.push(e);
1454 return tree;
1455 },
1456 }
1457 continue;
1458 },
1459
1460
1461 State.SuspendBody => |suspend_node| {
1462 if (suspend_node.payload != null) {
1463 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1464 }
1465 continue;
1466 },
1467 State.AsyncAllocator => |async_node| {
1468 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
1469 continue;
1470 }
1471
1472 async_node.rangle_bracket = TokenIndex(0);
1473 try stack.append(State {
1474 .ExpectTokenSave = ExpectTokenSave {
1475 .id = Token.Id.AngleBracketRight,
1476 .ptr = &??async_node.rangle_bracket,
1477 }
1478 });
1479 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1480 continue;
1481 },
1482 State.AsyncEnd => |ctx| {
1483 const node = ctx.ctx.get() ?? continue;
1484
1485 switch (node.id) {
1486 ast.Node.Id.FnProto => {
1487 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1488 fn_proto.async_attr = ctx.attribute;
1489 continue;
1490 },
1491 ast.Node.Id.SuffixOp => {
1492 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1493 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1494 suffix_op.op.Call.async_attr = ctx.attribute;
1495 continue;
1496 }
1497
1498 *(try tree.errors.addOne()) = Error {
1499 .ExpectedCall = Error.ExpectedCall { .node = node },
1500 };
1501 return tree;
1502 },
1503 else => {
1504 *(try tree.errors.addOne()) = Error {
1505 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1506 };
1507 return tree;
1508 }
1509 }
1510 },
1511
1512
1513 State.ExternType => |ctx| {
1514 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1515 const fn_proto = try arena.construct(ast.Node.FnProto {
1516 .base = ast.Node {
1517 .id = ast.Node.Id.FnProto,
1518 },
1519 .doc_comments = ctx.comments,
1520 .visib_token = null,
1521 .name_token = null,
1522 .fn_token = fn_token,
1523 .params = ast.Node.FnProto.ParamList.init(arena),
1524 .return_type = undefined,
1525 .var_args_token = null,
1526 .extern_export_inline_token = ctx.extern_token,
1527 .cc_token = null,
1528 .async_attr = null,
1529 .body_node = null,
1530 .lib_name = null,
1531 .align_expr = null,
1532 });
1533 ctx.opt_ctx.store(&fn_proto.base);
1534 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1535 continue;
1536 }
1537
1538 stack.append(State {
1539 .ContainerKind = ContainerKindCtx {
1540 .opt_ctx = ctx.opt_ctx,
1541 .ltoken = ctx.extern_token,
1542 .layout = ast.Node.ContainerDecl.Layout.Extern,
1543 },
1544 }) catch unreachable;
1545 continue;
1546 },
1547 State.SliceOrArrayAccess => |node| {
1548 const token = nextToken(&tok_it, &tree);
1549 const token_index = token.index;
1550 const token_ptr = token.ptr;
1551 switch (token_ptr.id) {
1552 Token.Id.Ellipsis2 => {
1553 const start = node.op.ArrayAccess;
1554 node.op = ast.Node.SuffixOp.Op {
1555 .Slice = ast.Node.SuffixOp.Op.Slice {
1556 .start = start,
1557 .end = null,
1558 }
1559 };
1560
1561 stack.append(State {
1562 .ExpectTokenSave = ExpectTokenSave {
1563 .id = Token.Id.RBracket,
1564 .ptr = &node.rtoken,
1565 }
1566 }) catch unreachable;
1567 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1568 continue;
1569 },
1570 Token.Id.RBracket => {
1571 node.rtoken = token_index;
1572 continue;
1573 },
1574 else => {
1575 *(try tree.errors.addOne()) = Error {
1576 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1577 };
1578 return tree;
1579 }
1580 }
1581 },
1582 State.SliceOrArrayType => |node| {
1583 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {
1584 node.op = ast.Node.PrefixOp.Op {
1585 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1586 .align_expr = null,
1587 .bit_offset_start_token = null,
1588 .bit_offset_end_token = null,
1589 .const_token = null,
1590 .volatile_token = null,
1591 }
1592 };
1593 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1594 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1595 continue;
1596 }
1597
1598 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1599 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1600 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1601 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1602 continue;
1603 },
1604 State.AddrOfModifiers => |addr_of_info| {
1605 const token = nextToken(&tok_it, &tree);
1606 const token_index = token.index;
1607 const token_ptr = token.ptr;
1608 switch (token_ptr.id) {
1609 Token.Id.Keyword_align => {
1610 stack.append(state) catch unreachable;
1611 if (addr_of_info.align_expr != null) {
1612 *(try tree.errors.addOne()) = Error {
1613 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1614 };
1615 return tree;
1616 }
1617 try stack.append(State { .ExpectToken = Token.Id.RParen });
1618 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1619 try stack.append(State { .ExpectToken = Token.Id.LParen });
1620 continue;
1621 },
1622 Token.Id.Keyword_const => {
1623 stack.append(state) catch unreachable;
1624 if (addr_of_info.const_token != null) {
1625 *(try tree.errors.addOne()) = Error {
1626 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1627 };
1628 return tree;
1629 }
1630 addr_of_info.const_token = token_index;
1631 continue;
1632 },
1633 Token.Id.Keyword_volatile => {
1634 stack.append(state) catch unreachable;
1635 if (addr_of_info.volatile_token != null) {
1636 *(try tree.errors.addOne()) = Error {
1637 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1638 };
1639 return tree;
1640 }
1641 addr_of_info.volatile_token = token_index;
1642 continue;
1643 },
1644 else => {
1645 putBackToken(&tok_it, &tree);
1646 continue;
1647 },
1648 }
1649 },
1650
1651
1652 State.Payload => |opt_ctx| {
1653 const token = nextToken(&tok_it, &tree);
1654 const token_index = token.index;
1655 const token_ptr = token.ptr;
1656 if (token_ptr.id != Token.Id.Pipe) {
1657 if (opt_ctx != OptionalCtx.Optional) {
1658 *(try tree.errors.addOne()) = Error {
1659 .ExpectedToken = Error.ExpectedToken {
1660 .token = token_index,
1661 .expected_id = Token.Id.Pipe,
1662 },
1663 };
1664 return tree;
1665 }
1666
1667 putBackToken(&tok_it, &tree);
1668 continue;
1669 }
1670
1671 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1672 ast.Node.Payload {
1673 .base = undefined,
1674 .lpipe = token_index,
1675 .error_symbol = undefined,
1676 .rpipe = undefined
1677 }
1678 );
1679
1680 stack.append(State {
1681 .ExpectTokenSave = ExpectTokenSave {
1682 .id = Token.Id.Pipe,
1683 .ptr = &node.rpipe,
1684 }
1685 }) catch unreachable;
1686 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1687 continue;
1688 },
1689 State.PointerPayload => |opt_ctx| {
1690 const token = nextToken(&tok_it, &tree);
1691 const token_index = token.index;
1692 const token_ptr = token.ptr;
1693 if (token_ptr.id != Token.Id.Pipe) {
1694 if (opt_ctx != OptionalCtx.Optional) {
1695 *(try tree.errors.addOne()) = Error {
1696 .ExpectedToken = Error.ExpectedToken {
1697 .token = token_index,
1698 .expected_id = Token.Id.Pipe,
1699 },
1700 };
1701 return tree;
1702 }
1703
1704 putBackToken(&tok_it, &tree);
1705 continue;
1706 }
1707
1708 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1709 ast.Node.PointerPayload {
1710 .base = undefined,
1711 .lpipe = token_index,
1712 .ptr_token = null,
1713 .value_symbol = undefined,
1714 .rpipe = undefined
1715 }
1716 );
1717
1718 try stack.append(State {
1719 .ExpectTokenSave = ExpectTokenSave {
1720 .id = Token.Id.Pipe,
1721 .ptr = &node.rpipe,
1722 }
1723 });
1724 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1725 try stack.append(State {
1726 .OptionalTokenSave = OptionalTokenSave {
1727 .id = Token.Id.Asterisk,
1728 .ptr = &node.ptr_token,
1729 }
1730 });
1731 continue;
1732 },
1733 State.PointerIndexPayload => |opt_ctx| {
1734 const token = nextToken(&tok_it, &tree);
1735 const token_index = token.index;
1736 const token_ptr = token.ptr;
1737 if (token_ptr.id != Token.Id.Pipe) {
1738 if (opt_ctx != OptionalCtx.Optional) {
1739 *(try tree.errors.addOne()) = Error {
1740 .ExpectedToken = Error.ExpectedToken {
1741 .token = token_index,
1742 .expected_id = Token.Id.Pipe,
1743 },
1744 };
1745 return tree;
1746 }
1747
1748 putBackToken(&tok_it, &tree);
1749 continue;
1750 }
1751
1752 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1753 ast.Node.PointerIndexPayload {
1754 .base = undefined,
1755 .lpipe = token_index,
1756 .ptr_token = null,
1757 .value_symbol = undefined,
1758 .index_symbol = null,
1759 .rpipe = undefined
1760 }
1761 );
1762
1763 stack.append(State {
1764 .ExpectTokenSave = ExpectTokenSave {
1765 .id = Token.Id.Pipe,
1766 .ptr = &node.rpipe,
1767 }
1768 }) catch unreachable;
1769 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1770 try stack.append(State { .IfToken = Token.Id.Comma });
1771 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1772 try stack.append(State {
1773 .OptionalTokenSave = OptionalTokenSave {
1774 .id = Token.Id.Asterisk,
1775 .ptr = &node.ptr_token,
1776 }
1777 });
1778 continue;
1779 },
1780
1781
1782 State.Expression => |opt_ctx| {
1783 const token = nextToken(&tok_it, &tree);
1784 const token_index = token.index;
1785 const token_ptr = token.ptr;
1786 switch (token_ptr.id) {
1787 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1788 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1789 ast.Node.ControlFlowExpression {
1790 .base = undefined,
1791 .ltoken = token_index,
1792 .kind = undefined,
1793 .rhs = null,
1794 }
1795 );
1796
1797 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1798
1799 switch (token_ptr.id) {
1800 Token.Id.Keyword_break => {
1801 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1802 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1803 try stack.append(State { .IfToken = Token.Id.Colon });
1804 },
1805 Token.Id.Keyword_continue => {
1806 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1807 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1808 try stack.append(State { .IfToken = Token.Id.Colon });
1809 },
1810 Token.Id.Keyword_return => {
1811 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1812 },
1813 else => unreachable,
1814 }
1815 continue;
1816 },
1817 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1818 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1819 ast.Node.PrefixOp {
1820 .base = undefined,
1821 .op_token = token_index,
1822 .op = switch (token_ptr.id) {
1823 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1824 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1825 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1826 else => unreachable,
1827 },
1828 .rhs = undefined,
1829 }
1830 );
1831
1832 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1833 continue;
1834 },
1835 else => {
1836 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1837 putBackToken(&tok_it, &tree);
1838 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1839 }
1840 continue;
1841 }
1842 }
1843 },
1844 State.RangeExpressionBegin => |opt_ctx| {
1845 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1846 try stack.append(State { .Expression = opt_ctx });
1847 continue;
1848 },
1849 State.RangeExpressionEnd => |opt_ctx| {
1850 const lhs = opt_ctx.get() ?? continue;
1851
1852 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1853 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1854 ast.Node.InfixOp {
1855 .base = undefined,
1856 .lhs = lhs,
1857 .op_token = ellipsis3,
1858 .op = ast.Node.InfixOp.Op.Range,
1859 .rhs = undefined,
1860 }
1861 );
1862 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1863 continue;
1864 }
1865 },
1866 State.AssignmentExpressionBegin => |opt_ctx| {
1867 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1868 try stack.append(State { .Expression = opt_ctx });
1869 continue;
1870 },
1871
1872 State.AssignmentExpressionEnd => |opt_ctx| {
1873 const lhs = opt_ctx.get() ?? continue;
1874
1875 const token = nextToken(&tok_it, &tree);
1876 const token_index = token.index;
1877 const token_ptr = token.ptr;
1878 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1879 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1880 ast.Node.InfixOp {
1881 .base = undefined,
1882 .lhs = lhs,
1883 .op_token = token_index,
1884 .op = ass_id,
1885 .rhs = undefined,
1886 }
1887 );
1888 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1889 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1890 continue;
1891 } else {
1892 putBackToken(&tok_it, &tree);
1893 continue;
1894 }
1895 },
1896
1897 State.UnwrapExpressionBegin => |opt_ctx| {
1898 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1899 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1900 continue;
1901 },
1902
1903 State.UnwrapExpressionEnd => |opt_ctx| {
1904 const lhs = opt_ctx.get() ?? continue;
1905
1906 const token = nextToken(&tok_it, &tree);
1907 const token_index = token.index;
1908 const token_ptr = token.ptr;
1909 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1910 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1911 ast.Node.InfixOp {
1912 .base = undefined,
1913 .lhs = lhs,
1914 .op_token = token_index,
1915 .op = unwrap_id,
1916 .rhs = undefined,
1917 }
1918 );
1919
1920 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1921 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1922
1923 if (node.op == ast.Node.InfixOp.Op.Catch) {
1924 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1925 }
1926 continue;
1927 } else {
1928 putBackToken(&tok_it, &tree);
1929 continue;
1930 }
1931 },
1932
1933 State.BoolOrExpressionBegin => |opt_ctx| {
1934 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1935 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1936 continue;
1937 },
1938
1939 State.BoolOrExpressionEnd => |opt_ctx| {
1940 const lhs = opt_ctx.get() ?? continue;
1941
1942 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1943 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1944 ast.Node.InfixOp {
1945 .base = undefined,
1946 .lhs = lhs,
1947 .op_token = or_token,
1948 .op = ast.Node.InfixOp.Op.BoolOr,
1949 .rhs = undefined,
1950 }
1951 );
1952 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1953 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1954 continue;
1955 }
1956 },
1957
1958 State.BoolAndExpressionBegin => |opt_ctx| {
1959 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1960 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1961 continue;
1962 },
1963
1964 State.BoolAndExpressionEnd => |opt_ctx| {
1965 const lhs = opt_ctx.get() ?? continue;
1966
1967 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1968 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1969 ast.Node.InfixOp {
1970 .base = undefined,
1971 .lhs = lhs,
1972 .op_token = and_token,
1973 .op = ast.Node.InfixOp.Op.BoolAnd,
1974 .rhs = undefined,
1975 }
1976 );
1977 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1978 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1979 continue;
1980 }
1981 },
1982
1983 State.ComparisonExpressionBegin => |opt_ctx| {
1984 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1985 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
1986 continue;
1987 },
1988
1989 State.ComparisonExpressionEnd => |opt_ctx| {
1990 const lhs = opt_ctx.get() ?? continue;
1991
1992 const token = nextToken(&tok_it, &tree);
1993 const token_index = token.index;
1994 const token_ptr = token.ptr;
1995 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1996 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1997 ast.Node.InfixOp {
1998 .base = undefined,
1999 .lhs = lhs,
2000 .op_token = token_index,
2001 .op = comp_id,
2002 .rhs = undefined,
2003 }
2004 );
2005 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2006 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2007 continue;
2008 } else {
2009 putBackToken(&tok_it, &tree);
2010 continue;
2011 }
2012 },
2013
2014 State.BinaryOrExpressionBegin => |opt_ctx| {
2015 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2016 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2017 continue;
2018 },
2019
2020 State.BinaryOrExpressionEnd => |opt_ctx| {
2021 const lhs = opt_ctx.get() ?? continue;
2022
2023 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
2024 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2025 ast.Node.InfixOp {
2026 .base = undefined,
2027 .lhs = lhs,
2028 .op_token = pipe,
2029 .op = ast.Node.InfixOp.Op.BitOr,
2030 .rhs = undefined,
2031 }
2032 );
2033 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2034 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2035 continue;
2036 }
2037 },
2038
2039 State.BinaryXorExpressionBegin => |opt_ctx| {
2040 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2041 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2042 continue;
2043 },
2044
2045 State.BinaryXorExpressionEnd => |opt_ctx| {
2046 const lhs = opt_ctx.get() ?? continue;
2047
2048 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2049 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2050 ast.Node.InfixOp {
2051 .base = undefined,
2052 .lhs = lhs,
2053 .op_token = caret,
2054 .op = ast.Node.InfixOp.Op.BitXor,
2055 .rhs = undefined,
2056 }
2057 );
2058 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2059 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2060 continue;
2061 }
2062 },
2063
2064 State.BinaryAndExpressionBegin => |opt_ctx| {
2065 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2066 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2067 continue;
2068 },
2069
2070 State.BinaryAndExpressionEnd => |opt_ctx| {
2071 const lhs = opt_ctx.get() ?? continue;
2072
2073 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2074 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2075 ast.Node.InfixOp {
2076 .base = undefined,
2077 .lhs = lhs,
2078 .op_token = ampersand,
2079 .op = ast.Node.InfixOp.Op.BitAnd,
2080 .rhs = undefined,
2081 }
2082 );
2083 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2084 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2085 continue;
2086 }
2087 },
2088
2089 State.BitShiftExpressionBegin => |opt_ctx| {
2090 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2091 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2092 continue;
2093 },
2094
2095 State.BitShiftExpressionEnd => |opt_ctx| {
2096 const lhs = opt_ctx.get() ?? continue;
2097
2098 const token = nextToken(&tok_it, &tree);
2099 const token_index = token.index;
2100 const token_ptr = token.ptr;
2101 if (tokenIdToBitShift(token_ptr.id)) |bitshift_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 = bitshift_id,
2108 .rhs = undefined,
2109 }
2110 );
2111 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2112 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2113 continue;
2114 } else {
2115 putBackToken(&tok_it, &tree);
2116 continue;
2117 }
2118 },
2119
2120 State.AdditionExpressionBegin => |opt_ctx| {
2121 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2122 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2123 continue;
2124 },
2125
2126 State.AdditionExpressionEnd => |opt_ctx| {
2127 const lhs = opt_ctx.get() ?? continue;
2128
2129 const token = nextToken(&tok_it, &tree);
2130 const token_index = token.index;
2131 const token_ptr = token.ptr;
2132 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2133 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2134 ast.Node.InfixOp {
2135 .base = undefined,
2136 .lhs = lhs,
2137 .op_token = token_index,
2138 .op = add_id,
2139 .rhs = undefined,
2140 }
2141 );
2142 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2143 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2144 continue;
2145 } else {
2146 putBackToken(&tok_it, &tree);
2147 continue;
2148 }
2149 },
2150
2151 State.MultiplyExpressionBegin => |opt_ctx| {
2152 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2153 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2154 continue;
2155 },
2156
2157 State.MultiplyExpressionEnd => |opt_ctx| {
2158 const lhs = opt_ctx.get() ?? continue;
2159
2160 const token = nextToken(&tok_it, &tree);
2161 const token_index = token.index;
2162 const token_ptr = token.ptr;
2163 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2164 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2165 ast.Node.InfixOp {
2166 .base = undefined,
2167 .lhs = lhs,
2168 .op_token = token_index,
2169 .op = mult_id,
2170 .rhs = undefined,
2171 }
2172 );
2173 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2174 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2175 continue;
2176 } else {
2177 putBackToken(&tok_it, &tree);
2178 continue;
2179 }
2180 },
2181
2182 State.CurlySuffixExpressionBegin => |opt_ctx| {
2183 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2184 try stack.append(State { .IfToken = Token.Id.LBrace });
2185 try stack.append(State { .TypeExprBegin = opt_ctx });
2186 continue;
2187 },
2188
2189 State.CurlySuffixExpressionEnd => |opt_ctx| {
2190 const lhs = opt_ctx.get() ?? continue;
2191
2192 if ((??tok_it.peek()).id == Token.Id.Period) {
2193 const node = try arena.construct(ast.Node.SuffixOp {
2194 .base = ast.Node { .id = ast.Node.Id.SuffixOp },
2195 .lhs = lhs,
2196 .op = ast.Node.SuffixOp.Op {
2197 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2198 },
2199 .rtoken = undefined,
2200 });
2201 opt_ctx.store(&node.base);
2202
2203 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2204 try stack.append(State { .IfToken = Token.Id.LBrace });
2205 try stack.append(State {
2206 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {
2207 .list = &node.op.StructInitializer,
2208 .ptr = &node.rtoken,
2209 }
2210 });
2211 continue;
2212 }
2213
2214 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2215 ast.Node.SuffixOp {
2216 .base = undefined,
2217 .lhs = lhs,
2218 .op = ast.Node.SuffixOp.Op {
2219 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2220 },
2221 .rtoken = undefined,
2222 }
2223 );
2224 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2225 try stack.append(State { .IfToken = Token.Id.LBrace });
2226 try stack.append(State {
2227 .ExprListItemOrEnd = ExprListCtx {
2228 .list = &node.op.ArrayInitializer,
2229 .end = Token.Id.RBrace,
2230 .ptr = &node.rtoken,
2231 }
2232 });
2233 continue;
2234 },
2235
2236 State.TypeExprBegin => |opt_ctx| {
2237 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2238 try stack.append(State { .PrefixOpExpression = opt_ctx });
2239 continue;
2240 },
2241
2242 State.TypeExprEnd => |opt_ctx| {
2243 const lhs = opt_ctx.get() ?? continue;
2244
2245 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2246 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2247 ast.Node.InfixOp {
2248 .base = undefined,
2249 .lhs = lhs,
2250 .op_token = bang,
2251 .op = ast.Node.InfixOp.Op.ErrorUnion,
2252 .rhs = undefined,
2253 }
2254 );
2255 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2256 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2257 continue;
2258 }
2259 },
2260
2261 State.PrefixOpExpression => |opt_ctx| {
2262 const token = nextToken(&tok_it, &tree);
2263 const token_index = token.index;
2264 const token_ptr = token.ptr;
2265 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2266 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2267 ast.Node.PrefixOp {
2268 .base = undefined,
2269 .op_token = token_index,
2270 .op = prefix_id,
2271 .rhs = undefined,
2272 }
2273 );
2274
2275 // Treat '**' token as two derefs
2276 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2277 const child = try createNode(arena, ast.Node.PrefixOp,
2278 ast.Node.PrefixOp {
2279 .base = undefined,
2280 .op_token = token_index,
2281 .op = prefix_id,
2282 .rhs = undefined,
2283 }
2284 );
2285 node.rhs = &child.base;
2286 node = child;
2287 }
2288
2289 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2290 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2291 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2292 }
2293 continue;
2294 } else {
2295 putBackToken(&tok_it, &tree);
2296 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2297 continue;
2298 }
2299 },
2300
2301 State.SuffixOpExpressionBegin => |opt_ctx| {
2302 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2303 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
2304 ast.Node.AsyncAttribute {
2305 .base = undefined,
2306 .async_token = async_token,
2307 .allocator_type = null,
2308 .rangle_bracket = null,
2309 }
2310 );
2311 stack.append(State {
2312 .AsyncEnd = AsyncEndCtx {
2313 .ctx = opt_ctx,
2314 .attribute = async_node,
2315 }
2316 }) catch unreachable;
2317 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2318 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2319 try stack.append(State { .AsyncAllocator = async_node });
2320 continue;
2321 }
2322
2323 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2324 try stack.append(State { .PrimaryExpression = opt_ctx });
2325 continue;
2326 },
2327
2328 State.SuffixOpExpressionEnd => |opt_ctx| {
2329 const lhs = opt_ctx.get() ?? continue;
2330
2331 const token = nextToken(&tok_it, &tree);
2332 const token_index = token.index;
2333 const token_ptr = token.ptr;
2334 switch (token_ptr.id) {
2335 Token.Id.LParen => {
2336 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2337 ast.Node.SuffixOp {
2338 .base = undefined,
2339 .lhs = lhs,
2340 .op = ast.Node.SuffixOp.Op {
2341 .Call = ast.Node.SuffixOp.Op.Call {
2342 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2343 .async_attr = null,
2344 }
2345 },
2346 .rtoken = undefined,
2347 }
2348 );
2349 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2350 try stack.append(State {
2351 .ExprListItemOrEnd = ExprListCtx {
2352 .list = &node.op.Call.params,
2353 .end = Token.Id.RParen,
2354 .ptr = &node.rtoken,
2355 }
2356 });
2357 continue;
2358 },
2359 Token.Id.LBracket => {
2360 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2361 ast.Node.SuffixOp {
2362 .base = undefined,
2363 .lhs = lhs,
2364 .op = ast.Node.SuffixOp.Op {
2365 .ArrayAccess = undefined,
2366 },
2367 .rtoken = undefined
2368 }
2369 );
2370 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2371 try stack.append(State { .SliceOrArrayAccess = node });
2372 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2373 continue;
2374 },
2375 Token.Id.Period => {
2376 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2377 ast.Node.InfixOp {
2378 .base = undefined,
2379 .lhs = lhs,
2380 .op_token = token_index,
2381 .op = ast.Node.InfixOp.Op.Period,
2382 .rhs = undefined,
2383 }
2384 );
2385 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2386 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2387 continue;
2388 },
2389 else => {
2390 putBackToken(&tok_it, &tree);
2391 continue;
2392 },
2393 }
2394 },
2395
2396 State.PrimaryExpression => |opt_ctx| {
2397 const token = nextToken(&tok_it, &tree);
2398 switch (token.ptr.id) {
2399 Token.Id.IntegerLiteral => {
2400 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token.index);
2401 continue;
2402 },
2403 Token.Id.FloatLiteral => {
2404 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index);
2405 continue;
2406 },
2407 Token.Id.CharLiteral => {
2408 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token.index);
2409 continue;
2410 },
2411 Token.Id.Keyword_undefined => {
2412 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2413 continue;
2414 },
2415 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2416 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
2417 continue;
2418 },
2419 Token.Id.Keyword_null => {
2420 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token.index);
2421 continue;
2422 },
2423 Token.Id.Keyword_this => {
2424 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token.index);
2425 continue;
2426 },
2427 Token.Id.Keyword_var => {
2428 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token.index);
2429 continue;
2430 },
2431 Token.Id.Keyword_unreachable => {
2432 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token.index);
2433 continue;
2434 },
2435 Token.Id.Keyword_promise => {
2436 const node = try arena.construct(ast.Node.PromiseType {
2437 .base = ast.Node {
2438 .id = ast.Node.Id.PromiseType,
2439 },
2440 .promise_token = token.index,
2441 .result = null,
2442 });
2443 opt_ctx.store(&node.base);
2444 const next_token = nextToken(&tok_it, &tree);
2445 const next_token_index = next_token.index;
2446 const next_token_ptr = next_token.ptr;
2447 if (next_token_ptr.id != Token.Id.Arrow) {
2448 putBackToken(&tok_it, &tree);
2449 continue;
2450 }
2451 node.result = ast.Node.PromiseType.Result {
2452 .arrow_token = next_token_index,
2453 .return_type = undefined,
2454 };
2455 const return_type_ptr = &((??node.result).return_type);
2456 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2457 continue;
2458 },
2459 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2460 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
2461 continue;
2462 },
2463 Token.Id.LParen => {
2464 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2465 ast.Node.GroupedExpression {
2466 .base = undefined,
2467 .lparen = token.index,
2468 .expr = undefined,
2469 .rparen = undefined,
2470 }
2471 );
2472 stack.append(State {
2473 .ExpectTokenSave = ExpectTokenSave {
2474 .id = Token.Id.RParen,
2475 .ptr = &node.rparen,
2476 }
2477 }) catch unreachable;
2478 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2479 continue;
2480 },
2481 Token.Id.Builtin => {
2482 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2483 ast.Node.BuiltinCall {
2484 .base = undefined,
2485 .builtin_token = token.index,
2486 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2487 .rparen_token = undefined,
2488 }
2489 );
2490 stack.append(State {
2491 .ExprListItemOrEnd = ExprListCtx {
2492 .list = &node.params,
2493 .end = Token.Id.RParen,
2494 .ptr = &node.rparen_token,
2495 }
2496 }) catch unreachable;
2497 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2498 continue;
2499 },
2500 Token.Id.LBracket => {
2501 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2502 ast.Node.PrefixOp {
2503 .base = undefined,
2504 .op_token = token.index,
2505 .op = undefined,
2506 .rhs = undefined,
2507 }
2508 );
2509 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2510 continue;
2511 },
2512 Token.Id.Keyword_error => {
2513 stack.append(State {
2514 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2515 .error_token = token.index,
2516 .opt_ctx = opt_ctx
2517 }
2518 }) catch unreachable;
2519 continue;
2520 },
2521 Token.Id.Keyword_packed => {
2522 stack.append(State {
2523 .ContainerKind = ContainerKindCtx {
2524 .opt_ctx = opt_ctx,
2525 .ltoken = token.index,
2526 .layout = ast.Node.ContainerDecl.Layout.Packed,
2527 },
2528 }) catch unreachable;
2529 continue;
2530 },
2531 Token.Id.Keyword_extern => {
2532 stack.append(State {
2533 .ExternType = ExternTypeCtx {
2534 .opt_ctx = opt_ctx,
2535 .extern_token = token.index,
2536 .comments = null,
2537 },
2538 }) catch unreachable;
2539 continue;
2540 },
2541 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2542 putBackToken(&tok_it, &tree);
2543 stack.append(State {
2544 .ContainerKind = ContainerKindCtx {
2545 .opt_ctx = opt_ctx,
2546 .ltoken = token.index,
2547 .layout = ast.Node.ContainerDecl.Layout.Auto,
2548 },
2549 }) catch unreachable;
2550 continue;
2551 },
2552 Token.Id.Identifier => {
2553 stack.append(State {
2554 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2555 .label = token.index,
2556 .opt_ctx = opt_ctx
2557 }
2558 }) catch unreachable;
2559 continue;
2560 },
2561 Token.Id.Keyword_fn => {
2562 const fn_proto = try arena.construct(ast.Node.FnProto {
2563 .base = ast.Node {
2564 .id = ast.Node.Id.FnProto,
2565 },
2566 .doc_comments = null,
2567 .visib_token = null,
2568 .name_token = null,
2569 .fn_token = token.index,
2570 .params = ast.Node.FnProto.ParamList.init(arena),
2571 .return_type = undefined,
2572 .var_args_token = null,
2573 .extern_export_inline_token = null,
2574 .cc_token = null,
2575 .async_attr = null,
2576 .body_node = null,
2577 .lib_name = null,
2578 .align_expr = null,
2579 });
2580 opt_ctx.store(&fn_proto.base);
2581 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2582 continue;
2583 },
2584 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2585 const fn_proto = try arena.construct(ast.Node.FnProto {
2586 .base = ast.Node {
2587 .id = ast.Node.Id.FnProto,
2588 },
2589 .doc_comments = null,
2590 .visib_token = null,
2591 .name_token = null,
2592 .fn_token = undefined,
2593 .params = ast.Node.FnProto.ParamList.init(arena),
2594 .return_type = undefined,
2595 .var_args_token = null,
2596 .extern_export_inline_token = null,
2597 .cc_token = token.index,
2598 .async_attr = null,
2599 .body_node = null,
2600 .lib_name = null,
2601 .align_expr = null,
2602 });
2603 opt_ctx.store(&fn_proto.base);
2604 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2605 try stack.append(State {
2606 .ExpectTokenSave = ExpectTokenSave {
2607 .id = Token.Id.Keyword_fn,
2608 .ptr = &fn_proto.fn_token
2609 }
2610 });
2611 continue;
2612 },
2613 Token.Id.Keyword_asm => {
2614 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2615 ast.Node.Asm {
2616 .base = undefined,
2617 .asm_token = token.index,
2618 .volatile_token = null,
2619 .template = undefined,
2620 .outputs = ast.Node.Asm.OutputList.init(arena),
2621 .inputs = ast.Node.Asm.InputList.init(arena),
2622 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2623 .rparen = undefined,
2624 }
2625 );
2626 stack.append(State {
2627 .ExpectTokenSave = ExpectTokenSave {
2628 .id = Token.Id.RParen,
2629 .ptr = &node.rparen,
2630 }
2631 }) catch unreachable;
2632 try stack.append(State { .AsmClobberItems = &node.clobbers });
2633 try stack.append(State { .IfToken = Token.Id.Colon });
2634 try stack.append(State { .AsmInputItems = &node.inputs });
2635 try stack.append(State { .IfToken = Token.Id.Colon });
2636 try stack.append(State { .AsmOutputItems = &node.outputs });
2637 try stack.append(State { .IfToken = Token.Id.Colon });
2638 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2639 try stack.append(State { .ExpectToken = Token.Id.LParen });
2640 try stack.append(State {
2641 .OptionalTokenSave = OptionalTokenSave {
2642 .id = Token.Id.Keyword_volatile,
2643 .ptr = &node.volatile_token,
2644 }
2645 });
2646 },
2647 Token.Id.Keyword_inline => {
2648 stack.append(State {
2649 .Inline = InlineCtx {
2650 .label = null,
2651 .inline_token = token.index,
2652 .opt_ctx = opt_ctx,
2653 }
2654 }) catch unreachable;
2655 continue;
2656 },
2657 else => {
2658 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2659 putBackToken(&tok_it, &tree);
2660 if (opt_ctx != OptionalCtx.Optional) {
2661 *(try tree.errors.addOne()) = Error {
2662 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token.index },
2663 };
2664 return tree;
2665 }
2666 }
2667 continue;
2668 }
2669 }
2670 },
2671
2672
2673 State.ErrorTypeOrSetDecl => |ctx| {
2674 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
2675 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2676 continue;
2677 }
2678
2679 const node = try arena.construct(ast.Node.ErrorSetDecl {
2680 .base = ast.Node {
2681 .id = ast.Node.Id.ErrorSetDecl,
2682 },
2683 .error_token = ctx.error_token,
2684 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2685 .rbrace_token = undefined,
2686 });
2687 ctx.opt_ctx.store(&node.base);
2688
2689 stack.append(State {
2690 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {
2691 .list = &node.decls,
2692 .ptr = &node.rbrace_token,
2693 }
2694 }) catch unreachable;
2695 continue;
2696 },
2697 State.StringLiteral => |opt_ctx| {
2698 const token = nextToken(&tok_it, &tree);
2699 const token_index = token.index;
2700 const token_ptr = token.ptr;
2701 opt_ctx.store(
2702 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2703 putBackToken(&tok_it, &tree);
2704 if (opt_ctx != OptionalCtx.Optional) {
2705 *(try tree.errors.addOne()) = Error {
2706 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2707 };
2708 return tree;
2709 }
2710
2711 continue;
2712 }
2713 );
2714 },
2715
2716 State.Identifier => |opt_ctx| {
2717 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
2718 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2719 continue;
2720 }
2721
2722 if (opt_ctx != OptionalCtx.Optional) {
2723 const token = nextToken(&tok_it, &tree);
2724 const token_index = token.index;
2725 const token_ptr = token.ptr;
2726 *(try tree.errors.addOne()) = Error {
2727 .ExpectedToken = Error.ExpectedToken {
2728 .token = token_index,
2729 .expected_id = Token.Id.Identifier,
2730 },
2731 };
2732 return tree;
2733 }
2734 },
2735
2736 State.ErrorTag => |node_ptr| {
2737 const comments = try eatDocComments(arena, &tok_it, &tree);
2738 const ident_token = nextToken(&tok_it, &tree);
2739 const ident_token_index = ident_token.index;
2740 const ident_token_ptr = ident_token.ptr;
2741 if (ident_token_ptr.id != Token.Id.Identifier) {
2742 *(try tree.errors.addOne()) = Error {
2743 .ExpectedToken = Error.ExpectedToken {
2744 .token = ident_token_index,
2745 .expected_id = Token.Id.Identifier,
2746 },
2747 };
2748 return tree;
2749 }
2750
2751 const node = try arena.construct(ast.Node.ErrorTag {
2752 .base = ast.Node {
2753 .id = ast.Node.Id.ErrorTag,
2754 },
2755 .doc_comments = comments,
2756 .name_token = ident_token_index,
2757 });
2758 *node_ptr = &node.base;
2759 continue;
2760 },
2761
2762 State.ExpectToken => |token_id| {
2763 const token = nextToken(&tok_it, &tree);
2764 const token_index = token.index;
2765 const token_ptr = token.ptr;
2766 if (token_ptr.id != token_id) {
2767 *(try tree.errors.addOne()) = Error {
2768 .ExpectedToken = Error.ExpectedToken {
2769 .token = token_index,
2770 .expected_id = token_id,
2771 },
2772 };
2773 return tree;
2774 }
2775 continue;
2776 },
2777 State.ExpectTokenSave => |expect_token_save| {
2778 const token = nextToken(&tok_it, &tree);
2779 const token_index = token.index;
2780 const token_ptr = token.ptr;
2781 if (token_ptr.id != expect_token_save.id) {
2782 *(try tree.errors.addOne()) = Error {
2783 .ExpectedToken = Error.ExpectedToken {
2784 .token = token_index,
2785 .expected_id = expect_token_save.id,
2786 },
2787 };
2788 return tree;
2789 }
2790 *expect_token_save.ptr = token_index;
2791 continue;
2792 },
2793 State.IfToken => |token_id| {
2794 if (eatToken(&tok_it, &tree, token_id)) |_| {
2795 continue;
2796 }
2797
2798 _ = stack.pop();
2799 continue;
2800 },
2801 State.IfTokenSave => |if_token_save| {
2802 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {
2803 *if_token_save.ptr = token_index;
2804 continue;
2805 }
2806
2807 _ = stack.pop();
2808 continue;
2809 },
2810 State.OptionalTokenSave => |optional_token_save| {
2811 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {
2812 *optional_token_save.ptr = token_index;
2813 continue;
2814 }
2815
2816 continue;
2817 },
2818 }
2819 }
2820}
2821
2822const AnnotatedToken = struct {
2823 ptr: &Token,
2824 index: TokenIndex,
2825};
2826
2827const TopLevelDeclCtx = struct {
2828 decls: &ast.Node.Root.DeclList,
2829 visib_token: ?TokenIndex,
2830 extern_export_inline_token: ?AnnotatedToken,
2831 lib_name: ?&ast.Node,
2832 comments: ?&ast.Node.DocComment,
2833};
2834
2835const VarDeclCtx = struct {
2836 mut_token: TokenIndex,
2837 visib_token: ?TokenIndex,
2838 comptime_token: ?TokenIndex,
2839 extern_export_token: ?TokenIndex,
2840 lib_name: ?&ast.Node,
2841 list: &ast.Node.Root.DeclList,
2842 comments: ?&ast.Node.DocComment,
2843};
2844
2845const TopLevelExternOrFieldCtx = struct {
2846 visib_token: TokenIndex,
2847 container_decl: &ast.Node.ContainerDecl,
2848 comments: ?&ast.Node.DocComment,
2849};
2850
2851const ExternTypeCtx = struct {
2852 opt_ctx: OptionalCtx,
2853 extern_token: TokenIndex,
2854 comments: ?&ast.Node.DocComment,
2855};
2856
2857const ContainerKindCtx = struct {
2858 opt_ctx: OptionalCtx,
2859 ltoken: TokenIndex,
2860 layout: ast.Node.ContainerDecl.Layout,
2861};
2862
2863const ExpectTokenSave = struct {
2864 id: @TagType(Token.Id),
2865 ptr: &TokenIndex,
2866};
2867
2868const OptionalTokenSave = struct {
2869 id: @TagType(Token.Id),
2870 ptr: &?TokenIndex,
2871};
2872
2873const ExprListCtx = struct {
2874 list: &ast.Node.SuffixOp.Op.InitList,
2875 end: Token.Id,
2876 ptr: &TokenIndex,
2877};
2878
2879fn ListSave(comptime List: type) type {
2880 return struct {
2881 list: &List,
2882 ptr: &TokenIndex,
2883 };
2884}
2885
2886const MaybeLabeledExpressionCtx = struct {
2887 label: TokenIndex,
2888 opt_ctx: OptionalCtx,
2889};
2890
2891const LabelCtx = struct {
2892 label: ?TokenIndex,
2893 opt_ctx: OptionalCtx,
2894};
2895
2896const InlineCtx = struct {
2897 label: ?TokenIndex,
2898 inline_token: ?TokenIndex,
2899 opt_ctx: OptionalCtx,
2900};
2901
2902const LoopCtx = struct {
2903 label: ?TokenIndex,
2904 inline_token: ?TokenIndex,
2905 loop_token: TokenIndex,
2906 opt_ctx: OptionalCtx,
2907};
2908
2909const AsyncEndCtx = struct {
2910 ctx: OptionalCtx,
2911 attribute: &ast.Node.AsyncAttribute,
2912};
2913
2914const ErrorTypeOrSetDeclCtx = struct {
2915 opt_ctx: OptionalCtx,
2916 error_token: TokenIndex,
2917};
2918
2919const ParamDeclEndCtx = struct {
2920 fn_proto: &ast.Node.FnProto,
2921 param_decl: &ast.Node.ParamDecl,
2922};
2923
2924const ComptimeStatementCtx = struct {
2925 comptime_token: TokenIndex,
2926 block: &ast.Node.Block,
2927};
2928
2929const OptionalCtx = union(enum) {
2930 Optional: &?&ast.Node,
2931 RequiredNull: &?&ast.Node,
2932 Required: &&ast.Node,
2933
2934 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2935 switch (*self) {
2936 OptionalCtx.Optional => |ptr| *ptr = value,
2937 OptionalCtx.RequiredNull => |ptr| *ptr = value,
2938 OptionalCtx.Required => |ptr| *ptr = value,
2939 }
2940 }
2941
2942 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2943 switch (*self) {
2944 OptionalCtx.Optional => |ptr| return *ptr,
2945 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
2946 OptionalCtx.Required => |ptr| return *ptr,
2947 }
2948 }
2949
2950 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2951 switch (*self) {
2952 OptionalCtx.Optional => |ptr| {
2953 return OptionalCtx { .RequiredNull = ptr };
2954 },
2955 OptionalCtx.RequiredNull => |ptr| return *self,
2956 OptionalCtx.Required => |ptr| return *self,
2957 }
2958 }
2959};
2960
2961const AddCommentsCtx = struct {
2962 node_ptr: &&ast.Node,
2963 comments: ?&ast.Node.DocComment,
2964};
2965
2966const State = union(enum) {
2967 TopLevel,
2968 TopLevelExtern: TopLevelDeclCtx,
2969 TopLevelLibname: TopLevelDeclCtx,
2970 TopLevelDecl: TopLevelDeclCtx,
2971 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2972
2973 ContainerKind: ContainerKindCtx,
2974 ContainerInitArgStart: &ast.Node.ContainerDecl,
2975 ContainerInitArg: &ast.Node.ContainerDecl,
2976 ContainerDecl: &ast.Node.ContainerDecl,
2977
2978 VarDecl: VarDeclCtx,
2979 VarDeclAlign: &ast.Node.VarDecl,
2980 VarDeclEq: &ast.Node.VarDecl,
2981
2982 FnDef: &ast.Node.FnProto,
2983 FnProto: &ast.Node.FnProto,
2984 FnProtoAlign: &ast.Node.FnProto,
2985 FnProtoReturnType: &ast.Node.FnProto,
2986
2987 ParamDecl: &ast.Node.FnProto,
2988 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
2989 ParamDeclName: &ast.Node.ParamDecl,
2990 ParamDeclEnd: ParamDeclEndCtx,
2991 ParamDeclComma: &ast.Node.FnProto,
2992
2993 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2994 LabeledExpression: LabelCtx,
2995 Inline: InlineCtx,
2996 While: LoopCtx,
2997 WhileContinueExpr: &?&ast.Node,
2998 For: LoopCtx,
2999 Else: &?&ast.Node.Else,
3000
3001 Block: &ast.Node.Block,
3002 Statement: &ast.Node.Block,
3003 ComptimeStatement: ComptimeStatementCtx,
3004 Semicolon: &&ast.Node,
3005
3006 AsmOutputItems: &ast.Node.Asm.OutputList,
3007 AsmOutputReturnOrType: &ast.Node.AsmOutput,
3008 AsmInputItems: &ast.Node.Asm.InputList,
3009 AsmClobberItems: &ast.Node.Asm.ClobberList,
3010
3011 ExprListItemOrEnd: ExprListCtx,
3012 ExprListCommaOrEnd: ExprListCtx,
3013 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3014 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3015 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
3016 FieldInitValue: OptionalCtx,
3017 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3018 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3019 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
3020 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
3021 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
3022 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
3023 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
3024
3025 SuspendBody: &ast.Node.Suspend,
3026 AsyncAllocator: &ast.Node.AsyncAttribute,
3027 AsyncEnd: AsyncEndCtx,
3028
3029 ExternType: ExternTypeCtx,
3030 SliceOrArrayAccess: &ast.Node.SuffixOp,
3031 SliceOrArrayType: &ast.Node.PrefixOp,
3032 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
3033
3034 Payload: OptionalCtx,
3035 PointerPayload: OptionalCtx,
3036 PointerIndexPayload: OptionalCtx,
3037
3038 Expression: OptionalCtx,
3039 RangeExpressionBegin: OptionalCtx,
3040 RangeExpressionEnd: OptionalCtx,
3041 AssignmentExpressionBegin: OptionalCtx,
3042 AssignmentExpressionEnd: OptionalCtx,
3043 UnwrapExpressionBegin: OptionalCtx,
3044 UnwrapExpressionEnd: OptionalCtx,
3045 BoolOrExpressionBegin: OptionalCtx,
3046 BoolOrExpressionEnd: OptionalCtx,
3047 BoolAndExpressionBegin: OptionalCtx,
3048 BoolAndExpressionEnd: OptionalCtx,
3049 ComparisonExpressionBegin: OptionalCtx,
3050 ComparisonExpressionEnd: OptionalCtx,
3051 BinaryOrExpressionBegin: OptionalCtx,
3052 BinaryOrExpressionEnd: OptionalCtx,
3053 BinaryXorExpressionBegin: OptionalCtx,
3054 BinaryXorExpressionEnd: OptionalCtx,
3055 BinaryAndExpressionBegin: OptionalCtx,
3056 BinaryAndExpressionEnd: OptionalCtx,
3057 BitShiftExpressionBegin: OptionalCtx,
3058 BitShiftExpressionEnd: OptionalCtx,
3059 AdditionExpressionBegin: OptionalCtx,
3060 AdditionExpressionEnd: OptionalCtx,
3061 MultiplyExpressionBegin: OptionalCtx,
3062 MultiplyExpressionEnd: OptionalCtx,
3063 CurlySuffixExpressionBegin: OptionalCtx,
3064 CurlySuffixExpressionEnd: OptionalCtx,
3065 TypeExprBegin: OptionalCtx,
3066 TypeExprEnd: OptionalCtx,
3067 PrefixOpExpression: OptionalCtx,
3068 SuffixOpExpressionBegin: OptionalCtx,
3069 SuffixOpExpressionEnd: OptionalCtx,
3070 PrimaryExpression: OptionalCtx,
3071
3072 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3073 StringLiteral: OptionalCtx,
3074 Identifier: OptionalCtx,
3075 ErrorTag: &&ast.Node,
3076
3077
3078 IfToken: @TagType(Token.Id),
3079 IfTokenSave: ExpectTokenSave,
3080 ExpectToken: @TagType(Token.Id),
3081 ExpectTokenSave: ExpectTokenSave,
3082 OptionalTokenSave: OptionalTokenSave,
3083};
3084
3085fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment {
3086 var result: ?&ast.Node.DocComment = null;
3087 while (true) {
3088 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3089 const node = blk: {
3090 if (result) |comment_node| {
3091 break :blk comment_node;
3092 } else {
3093 const comment_node = try arena.construct(ast.Node.DocComment {
3094 .base = ast.Node {
3095 .id = ast.Node.Id.DocComment,
3096 },
3097 .lines = ast.Node.DocComment.LineList.init(arena),
3098 });
3099 result = comment_node;
3100 break :blk comment_node;
3101 }
3102 };
3103 try node.lines.push(line_comment);
3104 continue;
3105 }
3106 break;
3107 }
3108 return result;
3109}
3110
3111fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.LineComment {
3112 const token = eatToken(tok_it, tree, Token.Id.LineComment) ?? return null;
3113 return try arena.construct(ast.Node.LineComment {
3114 .base = ast.Node {
3115 .id = ast.Node.Id.LineComment,
3116 },
3117 .token = token,
3118 });
3119}
3120
3121fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3122 token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node
3123{
3124 switch (token_ptr.id) {
3125 Token.Id.StringLiteral => {
3126 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3127 },
3128 Token.Id.MultilineStringLiteralLine => {
3129 const node = try arena.construct(ast.Node.MultilineStringLiteral {
3130 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },
3131 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3132 });
3133 try node.lines.push(token_index);
3134 while (true) {
3135 const multiline_str = nextToken(tok_it, tree);
3136 const multiline_str_index = multiline_str.index;
3137 const multiline_str_ptr = multiline_str.ptr;
3138 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3139 putBackToken(tok_it, tree);
3140 break;
3141 }
3142
3143 try node.lines.push(multiline_str_index);
3144 }
3145
3146 return &node.base;
3147 },
3148 // TODO: We shouldn't need a cast, but:
3149 // 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.
3150 else => return (?&ast.Node)(null),
3151 }
3152}
3153
3154fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx,
3155 token_ptr: &const Token, token_index: TokenIndex) !bool {
3156 switch (token_ptr.id) {
3157 Token.Id.Keyword_suspend => {
3158 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,
3159 ast.Node.Suspend {
3160 .base = undefined,
3161 .label = null,
3162 .suspend_token = token_index,
3163 .payload = null,
3164 .body = null,
3165 }
3166 );
3167
3168 stack.append(State { .SuspendBody = node }) catch unreachable;
3169 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3170 return true;
3171 },
3172 Token.Id.Keyword_if => {
3173 const node = try createToCtxNode(arena, ctx, ast.Node.If,
3174 ast.Node.If {
3175 .base = undefined,
3176 .if_token = token_index,
3177 .condition = undefined,
3178 .payload = null,
3179 .body = undefined,
3180 .@"else" = null,
3181 }
3182 );
3183
3184 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3185 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3186 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3187 try stack.append(State { .ExpectToken = Token.Id.RParen });
3188 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3189 try stack.append(State { .ExpectToken = Token.Id.LParen });
3190 return true;
3191 },
3192 Token.Id.Keyword_while => {
3193 stack.append(State {
3194 .While = LoopCtx {
3195 .label = null,
3196 .inline_token = null,
3197 .loop_token = token_index,
3198 .opt_ctx = *ctx,
3199 }
3200 }) catch unreachable;
3201 return true;
3202 },
3203 Token.Id.Keyword_for => {
3204 stack.append(State {
3205 .For = LoopCtx {
3206 .label = null,
3207 .inline_token = null,
3208 .loop_token = token_index,
3209 .opt_ctx = *ctx,
3210 }
3211 }) catch unreachable;
3212 return true;
3213 },
3214 Token.Id.Keyword_switch => {
3215 const node = try arena.construct(ast.Node.Switch {
3216 .base = ast.Node {
3217 .id = ast.Node.Id.Switch,
3218 },
3219 .switch_token = token_index,
3220 .expr = undefined,
3221 .cases = ast.Node.Switch.CaseList.init(arena),
3222 .rbrace = undefined,
3223 });
3224 ctx.store(&node.base);
3225
3226 stack.append(State {
3227 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {
3228 .list = &node.cases,
3229 .ptr = &node.rbrace,
3230 },
3231 }) catch unreachable;
3232 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3233 try stack.append(State { .ExpectToken = Token.Id.RParen });
3234 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3235 try stack.append(State { .ExpectToken = Token.Id.LParen });
3236 return true;
3237 },
3238 Token.Id.Keyword_comptime => {
3239 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,
3240 ast.Node.Comptime {
3241 .base = undefined,
3242 .comptime_token = token_index,
3243 .expr = undefined,
3244 .doc_comments = null,
3245 }
3246 );
3247 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3248 return true;
3249 },
3250 Token.Id.LBrace => {
3251 const block = try arena.construct(ast.Node.Block {
3252 .base = ast.Node {.id = ast.Node.Id.Block },
3253 .label = null,
3254 .lbrace = token_index,
3255 .statements = ast.Node.Block.StatementList.init(arena),
3256 .rbrace = undefined,
3257 });
3258 ctx.store(&block.base);
3259 stack.append(State { .Block = block }) catch unreachable;
3260 return true;
3261 },
3262 else => {
3263 return false;
3264 }
3265 }
3266}
3267
3268const ExpectCommaOrEndResult = union(enum) {
3269 end_token: ?TokenIndex,
3270 parse_error: Error,
3271};
3272
3273fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3274 const token = nextToken(tok_it, tree);
3275 const token_index = token.index;
3276 const token_ptr = token.ptr;
3277 switch (token_ptr.id) {
3278 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},
3279 else => {
3280 if (end == token_ptr.id) {
3281 return ExpectCommaOrEndResult { .end_token = token_index };
3282 }
3283
3284 return ExpectCommaOrEndResult {
3285 .parse_error = Error {
3286 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {
3287 .token = token_index,
3288 .end_id = end,
3289 },
3290 },
3291 };
3292 },
3293 }
3294}
3295
3296fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3297 // TODO: We have to cast all cases because of this:
3298 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3299 return switch (*id) {
3300 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },
3301 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },
3302 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },
3303 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },
3304 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },
3305 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },
3306 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },
3307 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },
3308 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },
3309 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },
3310 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },
3311 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },
3312 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },
3313 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },
3314 else => null,
3315 };
3316}
3317
3318fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3319 return switch (id) {
3320 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3321 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3322 else => null,
3323 };
3324}
3325
3326fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3327 return switch (id) {
3328 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3329 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3330 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3331 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3332 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3333 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3334 else => null,
3335 };
3336}
3337
3338fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3339 return switch (id) {
3340 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3341 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3342 else => null,
3343 };
3344}
3345
3346fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3347 return switch (id) {
3348 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3349 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3350 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3351 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3352 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3353 else => null,
3354 };
3355}
3356
3357fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3358 return switch (id) {
3359 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3360 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3361 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3362 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3363 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3364 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3365 else => null,
3366 };
3367}
3368
3369fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3370 return switch (id) {
3371 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3372 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3373 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3374 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3375 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3376 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3377 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3378 .align_expr = null,
3379 .bit_offset_start_token = null,
3380 .bit_offset_end_token = null,
3381 .const_token = null,
3382 .volatile_token = null,
3383 },
3384 },
3385 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3386 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3387 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3388 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3389 else => null,
3390 };
3391}
3392
3393fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3394 const node = try arena.create(T);
3395 *node = *init_to;
3396 node.base = blk: {
3397 const id = ast.Node.typeToId(T);
3398 break :blk ast.Node {
3399 .id = id,
3400 };
3401 };
3402
3403 return node;
3404}
3405
3406fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3407 const node = try createNode(arena, T, init_to);
3408 opt_ctx.store(&node.base);
3409
3410 return node;
3411}
3412
3413fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3414 return createNode(arena, T,
3415 T {
3416 .base = undefined,
3417 .token = token_index,
3418 }
3419 );
3420}
3421
3422fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
3423 const node = try createLiteral(arena, T, token_index);
3424 opt_ctx.store(&node.base);
3425
3426 return node;
3427}
3428
3429fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3430 const token = nextToken(tok_it, tree);
3431
3432 if (token.ptr.id == id)
3433 return token.index;
3434
3435 putBackToken(tok_it, tree);
3436 return null;
3437}
3438
3439fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedToken {
3440 const result = AnnotatedToken {
3441 .index = tok_it.index,
3442 .ptr = ??tok_it.next(),
3443 };
3444 // possibly skip a following same line token
3445 const token = tok_it.next() ?? return result;
3446 if (token.id != Token.Id.LineComment) {
3447 putBackToken(tok_it, tree);
3448 return result;
3449 }
3450 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3451 if (loc.line != 0) {
3452 putBackToken(tok_it, tree);
3453 }
3454 return result;
3455}
3456
3457fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3458 const prev_tok = ??tok_it.prev();
3459 if (prev_tok.id == Token.Id.LineComment) {
3460 const minus2_tok = tok_it.prev() ?? return;
3461 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);
3462 if (loc.line != 0) {
3463 _ = tok_it.next();
3464 }
3465 }
3466}
3467
3468test "std.zig.parser" {
3469 _ = @import("parser_test.zig");
3470}
std/zig/parser.zig deleted-4734
......@@ -1,4734 +0,0 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Tokenizer = std.zig.Tokenizer;
7const Token = std.zig.Token;
8const builtin = @import("builtin");
9const io = std.io;
10
11// TODO when we make parse errors into error types instead of printing directly,
12// get rid of this
13const warn = std.debug.warn;
14
15pub const Parser = struct {
16 util_allocator: &mem.Allocator,
17 tokenizer: &Tokenizer,
18 put_back_tokens: [2]Token,
19 put_back_count: usize,
20 source_file_name: []const u8,
21
22 pub const Tree = struct {
23 root_node: &ast.Node.Root,
24 arena_allocator: std.heap.ArenaAllocator,
25
26 pub fn deinit(self: &Tree) void {
27 self.arena_allocator.deinit();
28 }
29 };
30
31 // This memory contents are used only during a function call. It's used to repurpose memory;
32 // we reuse the same bytes for the stack data structure used by parsing, tree rendering, and
33 // source rendering.
34 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );
35 utility_bytes: []align(utility_bytes_align) u8,
36
37 /// allocator must outlive the returned Parser and all the parse trees you create with it.
38 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser {
39 return Parser {
40 .util_allocator = allocator,
41 .tokenizer = tokenizer,
42 .put_back_tokens = undefined,
43 .put_back_count = 0,
44 .source_file_name = source_file_name,
45 .utility_bytes = []align(utility_bytes_align) u8{},
46 };
47 }
48
49 pub fn deinit(self: &Parser) void {
50 self.util_allocator.free(self.utility_bytes);
51 }
52
53 const TopLevelDeclCtx = struct {
54 decls: &ArrayList(&ast.Node),
55 visib_token: ?Token,
56 extern_export_inline_token: ?Token,
57 lib_name: ?&ast.Node,
58 comments: ?&ast.Node.DocComment,
59 };
60
61 const VarDeclCtx = struct {
62 mut_token: Token,
63 visib_token: ?Token,
64 comptime_token: ?Token,
65 extern_export_token: ?Token,
66 lib_name: ?&ast.Node,
67 list: &ArrayList(&ast.Node),
68 comments: ?&ast.Node.DocComment,
69 };
70
71 const TopLevelExternOrFieldCtx = struct {
72 visib_token: Token,
73 container_decl: &ast.Node.ContainerDecl,
74 comments: ?&ast.Node.DocComment,
75 };
76
77 const ExternTypeCtx = struct {
78 opt_ctx: OptionalCtx,
79 extern_token: Token,
80 comments: ?&ast.Node.DocComment,
81 };
82
83 const ContainerKindCtx = struct {
84 opt_ctx: OptionalCtx,
85 ltoken: Token,
86 layout: ast.Node.ContainerDecl.Layout,
87 };
88
89 const ExpectTokenSave = struct {
90 id: Token.Id,
91 ptr: &Token,
92 };
93
94 const OptionalTokenSave = struct {
95 id: Token.Id,
96 ptr: &?Token,
97 };
98
99 const ExprListCtx = struct {
100 list: &ArrayList(&ast.Node),
101 end: Token.Id,
102 ptr: &Token,
103 };
104
105 fn ListSave(comptime T: type) type {
106 return struct {
107 list: &ArrayList(T),
108 ptr: &Token,
109 };
110 }
111
112 const MaybeLabeledExpressionCtx = struct {
113 label: Token,
114 opt_ctx: OptionalCtx,
115 };
116
117 const LabelCtx = struct {
118 label: ?Token,
119 opt_ctx: OptionalCtx,
120 };
121
122 const InlineCtx = struct {
123 label: ?Token,
124 inline_token: ?Token,
125 opt_ctx: OptionalCtx,
126 };
127
128 const LoopCtx = struct {
129 label: ?Token,
130 inline_token: ?Token,
131 loop_token: Token,
132 opt_ctx: OptionalCtx,
133 };
134
135 const AsyncEndCtx = struct {
136 ctx: OptionalCtx,
137 attribute: &ast.Node.AsyncAttribute,
138 };
139
140 const ErrorTypeOrSetDeclCtx = struct {
141 opt_ctx: OptionalCtx,
142 error_token: Token,
143 };
144
145 const ParamDeclEndCtx = struct {
146 fn_proto: &ast.Node.FnProto,
147 param_decl: &ast.Node.ParamDecl,
148 };
149
150 const ComptimeStatementCtx = struct {
151 comptime_token: Token,
152 block: &ast.Node.Block,
153 };
154
155 const OptionalCtx = union(enum) {
156 Optional: &?&ast.Node,
157 RequiredNull: &?&ast.Node,
158 Required: &&ast.Node,
159
160 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
161 switch (*self) {
162 OptionalCtx.Optional => |ptr| *ptr = value,
163 OptionalCtx.RequiredNull => |ptr| *ptr = value,
164 OptionalCtx.Required => |ptr| *ptr = value,
165 }
166 }
167
168 pub fn get(self: &const OptionalCtx) ?&ast.Node {
169 switch (*self) {
170 OptionalCtx.Optional => |ptr| return *ptr,
171 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
172 OptionalCtx.Required => |ptr| return *ptr,
173 }
174 }
175
176 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
177 switch (*self) {
178 OptionalCtx.Optional => |ptr| {
179 return OptionalCtx { .RequiredNull = ptr };
180 },
181 OptionalCtx.RequiredNull => |ptr| return *self,
182 OptionalCtx.Required => |ptr| return *self,
183 }
184 }
185 };
186
187 const AddCommentsCtx = struct {
188 node_ptr: &&ast.Node,
189 comments: ?&ast.Node.DocComment,
190 };
191
192 const State = union(enum) {
193 TopLevel,
194 TopLevelExtern: TopLevelDeclCtx,
195 TopLevelLibname: TopLevelDeclCtx,
196 TopLevelDecl: TopLevelDeclCtx,
197 TopLevelExternOrField: TopLevelExternOrFieldCtx,
198
199 ContainerKind: ContainerKindCtx,
200 ContainerInitArgStart: &ast.Node.ContainerDecl,
201 ContainerInitArg: &ast.Node.ContainerDecl,
202 ContainerDecl: &ast.Node.ContainerDecl,
203
204 VarDecl: VarDeclCtx,
205 VarDeclAlign: &ast.Node.VarDecl,
206 VarDeclEq: &ast.Node.VarDecl,
207
208 FnDef: &ast.Node.FnProto,
209 FnProto: &ast.Node.FnProto,
210 FnProtoAlign: &ast.Node.FnProto,
211 FnProtoReturnType: &ast.Node.FnProto,
212
213 ParamDecl: &ast.Node.FnProto,
214 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
215 ParamDeclName: &ast.Node.ParamDecl,
216 ParamDeclEnd: ParamDeclEndCtx,
217 ParamDeclComma: &ast.Node.FnProto,
218
219 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
220 LabeledExpression: LabelCtx,
221 Inline: InlineCtx,
222 While: LoopCtx,
223 WhileContinueExpr: &?&ast.Node,
224 For: LoopCtx,
225 Else: &?&ast.Node.Else,
226
227 Block: &ast.Node.Block,
228 Statement: &ast.Node.Block,
229 ComptimeStatement: ComptimeStatementCtx,
230 Semicolon: &&ast.Node,
231 LookForSameLineComment: &&ast.Node,
232 LookForSameLineCommentDirect: &ast.Node,
233
234 AsmOutputItems: &ArrayList(&ast.Node.AsmOutput),
235 AsmOutputReturnOrType: &ast.Node.AsmOutput,
236 AsmInputItems: &ArrayList(&ast.Node.AsmInput),
237 AsmClopperItems: &ArrayList(&ast.Node),
238
239 ExprListItemOrEnd: ExprListCtx,
240 ExprListCommaOrEnd: ExprListCtx,
241 FieldInitListItemOrEnd: ListSave(&ast.Node),
242 FieldInitListCommaOrEnd: ListSave(&ast.Node),
243 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
244 FieldInitValue: OptionalCtx,
245 ErrorTagListItemOrEnd: ListSave(&ast.Node),
246 ErrorTagListCommaOrEnd: ListSave(&ast.Node),
247 SwitchCaseOrEnd: ListSave(&ast.Node),
248 SwitchCaseCommaOrEnd: ListSave(&ast.Node),
249 SwitchCaseFirstItem: &ArrayList(&ast.Node),
250 SwitchCaseItem: &ArrayList(&ast.Node),
251 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
252
253 SuspendBody: &ast.Node.Suspend,
254 AsyncAllocator: &ast.Node.AsyncAttribute,
255 AsyncEnd: AsyncEndCtx,
256
257 ExternType: ExternTypeCtx,
258 SliceOrArrayAccess: &ast.Node.SuffixOp,
259 SliceOrArrayType: &ast.Node.PrefixOp,
260 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
261
262 Payload: OptionalCtx,
263 PointerPayload: OptionalCtx,
264 PointerIndexPayload: OptionalCtx,
265
266 Expression: OptionalCtx,
267 RangeExpressionBegin: OptionalCtx,
268 RangeExpressionEnd: OptionalCtx,
269 AssignmentExpressionBegin: OptionalCtx,
270 AssignmentExpressionEnd: OptionalCtx,
271 UnwrapExpressionBegin: OptionalCtx,
272 UnwrapExpressionEnd: OptionalCtx,
273 BoolOrExpressionBegin: OptionalCtx,
274 BoolOrExpressionEnd: OptionalCtx,
275 BoolAndExpressionBegin: OptionalCtx,
276 BoolAndExpressionEnd: OptionalCtx,
277 ComparisonExpressionBegin: OptionalCtx,
278 ComparisonExpressionEnd: OptionalCtx,
279 BinaryOrExpressionBegin: OptionalCtx,
280 BinaryOrExpressionEnd: OptionalCtx,
281 BinaryXorExpressionBegin: OptionalCtx,
282 BinaryXorExpressionEnd: OptionalCtx,
283 BinaryAndExpressionBegin: OptionalCtx,
284 BinaryAndExpressionEnd: OptionalCtx,
285 BitShiftExpressionBegin: OptionalCtx,
286 BitShiftExpressionEnd: OptionalCtx,
287 AdditionExpressionBegin: OptionalCtx,
288 AdditionExpressionEnd: OptionalCtx,
289 MultiplyExpressionBegin: OptionalCtx,
290 MultiplyExpressionEnd: OptionalCtx,
291 CurlySuffixExpressionBegin: OptionalCtx,
292 CurlySuffixExpressionEnd: OptionalCtx,
293 TypeExprBegin: OptionalCtx,
294 TypeExprEnd: OptionalCtx,
295 PrefixOpExpression: OptionalCtx,
296 SuffixOpExpressionBegin: OptionalCtx,
297 SuffixOpExpressionEnd: OptionalCtx,
298 PrimaryExpression: OptionalCtx,
299
300 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
301 StringLiteral: OptionalCtx,
302 Identifier: OptionalCtx,
303 ErrorTag: &&ast.Node,
304
305
306 IfToken: @TagType(Token.Id),
307 IfTokenSave: ExpectTokenSave,
308 ExpectToken: @TagType(Token.Id),
309 ExpectTokenSave: ExpectTokenSave,
310 OptionalTokenSave: OptionalTokenSave,
311 };
312
313 /// Returns an AST tree, allocated with the parser's allocator.
314 /// Result should be freed with tree.deinit() when there are
315 /// no more references to any AST nodes of the tree.
316 pub fn parse(self: &Parser) !Tree {
317 var stack = self.initUtilityArrayList(State);
318 defer self.deinitUtilityArrayList(stack);
319
320 var arena_allocator = std.heap.ArenaAllocator.init(self.util_allocator);
321 errdefer arena_allocator.deinit();
322
323 const arena = &arena_allocator.allocator;
324 const root_node = try self.createNode(arena, ast.Node.Root,
325 ast.Node.Root {
326 .base = undefined,
327 .decls = ArrayList(&ast.Node).init(arena),
328 .doc_comments = null,
329 // initialized when we get the eof token
330 .eof_token = undefined,
331 }
332 );
333
334 try stack.append(State.TopLevel);
335
336 while (true) {
337 //{
338 // const token = self.getNextToken();
339 // warn("{} ", @tagName(token.id));
340 // self.putBackToken(token);
341 // var i: usize = stack.len;
342 // while (i != 0) {
343 // i -= 1;
344 // warn("{} ", @tagName(stack.items[i]));
345 // }
346 // warn("\n");
347 //}
348
349 // This gives us 1 free append that can't fail
350 const state = stack.pop();
351
352 switch (state) {
353 State.TopLevel => {
354 while (try self.eatLineComment(arena)) |line_comment| {
355 try root_node.decls.append(&line_comment.base);
356 }
357
358 const comments = try self.eatDocComments(arena);
359 const token = self.getNextToken();
360 switch (token.id) {
361 Token.Id.Keyword_test => {
362 stack.append(State.TopLevel) catch unreachable;
363
364 const block = try arena.construct(ast.Node.Block {
365 .base = ast.Node {
366 .id = ast.Node.Id.Block,
367 .same_line_comment = null,
368 },
369 .label = null,
370 .lbrace = undefined,
371 .statements = ArrayList(&ast.Node).init(arena),
372 .rbrace = undefined,
373 });
374 const test_node = try arena.construct(ast.Node.TestDecl {
375 .base = ast.Node {
376 .id = ast.Node.Id.TestDecl,
377 .same_line_comment = null,
378 },
379 .doc_comments = comments,
380 .test_token = token,
381 .name = undefined,
382 .body_node = &block.base,
383 });
384 try root_node.decls.append(&test_node.base);
385 try stack.append(State { .Block = block });
386 try stack.append(State {
387 .ExpectTokenSave = ExpectTokenSave {
388 .id = Token.Id.LBrace,
389 .ptr = &block.rbrace,
390 }
391 });
392 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
393 continue;
394 },
395 Token.Id.Eof => {
396 root_node.eof_token = token;
397 root_node.doc_comments = comments;
398 return Tree {
399 .root_node = root_node,
400 .arena_allocator = arena_allocator,
401 };
402 },
403 Token.Id.Keyword_pub => {
404 stack.append(State.TopLevel) catch unreachable;
405 try stack.append(State {
406 .TopLevelExtern = TopLevelDeclCtx {
407 .decls = &root_node.decls,
408 .visib_token = token,
409 .extern_export_inline_token = null,
410 .lib_name = null,
411 .comments = comments,
412 }
413 });
414 continue;
415 },
416 Token.Id.Keyword_comptime => {
417 const block = try self.createNode(arena, ast.Node.Block,
418 ast.Node.Block {
419 .base = undefined,
420 .label = null,
421 .lbrace = undefined,
422 .statements = ArrayList(&ast.Node).init(arena),
423 .rbrace = undefined,
424 }
425 );
426 const node = try self.createAttachNode(arena, &root_node.decls, ast.Node.Comptime,
427 ast.Node.Comptime {
428 .base = undefined,
429 .comptime_token = token,
430 .expr = &block.base,
431 .doc_comments = comments,
432 }
433 );
434 stack.append(State.TopLevel) catch unreachable;
435 try stack.append(State { .Block = block });
436 try stack.append(State {
437 .ExpectTokenSave = ExpectTokenSave {
438 .id = Token.Id.LBrace,
439 .ptr = &block.rbrace,
440 }
441 });
442 continue;
443 },
444 else => {
445 self.putBackToken(token);
446 stack.append(State.TopLevel) catch unreachable;
447 try stack.append(State {
448 .TopLevelExtern = TopLevelDeclCtx {
449 .decls = &root_node.decls,
450 .visib_token = null,
451 .extern_export_inline_token = null,
452 .lib_name = null,
453 .comments = comments,
454 }
455 });
456 continue;
457 },
458 }
459 },
460 State.TopLevelExtern => |ctx| {
461 const token = self.getNextToken();
462 switch (token.id) {
463 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
464 stack.append(State {
465 .TopLevelDecl = TopLevelDeclCtx {
466 .decls = ctx.decls,
467 .visib_token = ctx.visib_token,
468 .extern_export_inline_token = token,
469 .lib_name = null,
470 .comments = ctx.comments,
471 },
472 }) catch unreachable;
473 continue;
474 },
475 Token.Id.Keyword_extern => {
476 stack.append(State {
477 .TopLevelLibname = TopLevelDeclCtx {
478 .decls = ctx.decls,
479 .visib_token = ctx.visib_token,
480 .extern_export_inline_token = token,
481 .lib_name = null,
482 .comments = ctx.comments,
483 },
484 }) catch unreachable;
485 continue;
486 },
487 else => {
488 self.putBackToken(token);
489 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
490 continue;
491 }
492 }
493 },
494 State.TopLevelLibname => |ctx| {
495 const lib_name = blk: {
496 const lib_name_token = self.getNextToken();
497 break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? {
498 self.putBackToken(lib_name_token);
499 break :blk null;
500 };
501 };
502
503 stack.append(State {
504 .TopLevelDecl = TopLevelDeclCtx {
505 .decls = ctx.decls,
506 .visib_token = ctx.visib_token,
507 .extern_export_inline_token = ctx.extern_export_inline_token,
508 .lib_name = lib_name,
509 .comments = ctx.comments,
510 },
511 }) catch unreachable;
512 continue;
513 },
514 State.TopLevelDecl => |ctx| {
515 const token = self.getNextToken();
516 switch (token.id) {
517 Token.Id.Keyword_use => {
518 if (ctx.extern_export_inline_token != null) {
519 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
520 }
521
522 const node = try self.createAttachNode(arena, ctx.decls, ast.Node.Use,
523 ast.Node.Use {
524 .base = undefined,
525 .visib_token = ctx.visib_token,
526 .expr = undefined,
527 .semicolon_token = undefined,
528 .doc_comments = ctx.comments,
529 }
530 );
531 stack.append(State {
532 .ExpectTokenSave = ExpectTokenSave {
533 .id = Token.Id.Semicolon,
534 .ptr = &node.semicolon_token,
535 }
536 }) catch unreachable;
537 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
538 continue;
539 },
540 Token.Id.Keyword_var, Token.Id.Keyword_const => {
541 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
542 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
543 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
544 }
545 }
546
547 try stack.append(State {
548 .VarDecl = VarDeclCtx {
549 .comments = ctx.comments,
550 .visib_token = ctx.visib_token,
551 .lib_name = ctx.lib_name,
552 .comptime_token = null,
553 .extern_export_token = ctx.extern_export_inline_token,
554 .mut_token = token,
555 .list = ctx.decls
556 }
557 });
558 continue;
559 },
560 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
561 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
562 const fn_proto = try arena.construct(ast.Node.FnProto {
563 .base = ast.Node {
564 .id = ast.Node.Id.FnProto,
565 .same_line_comment = null,
566 },
567 .doc_comments = ctx.comments,
568 .visib_token = ctx.visib_token,
569 .name_token = null,
570 .fn_token = undefined,
571 .params = ArrayList(&ast.Node).init(arena),
572 .return_type = undefined,
573 .var_args_token = null,
574 .extern_export_inline_token = ctx.extern_export_inline_token,
575 .cc_token = null,
576 .async_attr = null,
577 .body_node = null,
578 .lib_name = ctx.lib_name,
579 .align_expr = null,
580 });
581 try ctx.decls.append(&fn_proto.base);
582 stack.append(State { .FnDef = fn_proto }) catch unreachable;
583 try stack.append(State { .FnProto = fn_proto });
584
585 switch (token.id) {
586 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
587 fn_proto.cc_token = token;
588 try stack.append(State {
589 .ExpectTokenSave = ExpectTokenSave {
590 .id = Token.Id.Keyword_fn,
591 .ptr = &fn_proto.fn_token,
592 }
593 });
594 continue;
595 },
596 Token.Id.Keyword_async => {
597 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
598 ast.Node.AsyncAttribute {
599 .base = undefined,
600 .async_token = token,
601 .allocator_type = null,
602 .rangle_bracket = null,
603 }
604 );
605 fn_proto.async_attr = async_node;
606
607 try stack.append(State {
608 .ExpectTokenSave = ExpectTokenSave {
609 .id = Token.Id.Keyword_fn,
610 .ptr = &fn_proto.fn_token,
611 }
612 });
613 try stack.append(State { .AsyncAllocator = async_node });
614 continue;
615 },
616 Token.Id.Keyword_fn => {
617 fn_proto.fn_token = token;
618 continue;
619 },
620 else => unreachable,
621 }
622 },
623 else => {
624 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
625 },
626 }
627 },
628 State.TopLevelExternOrField => |ctx| {
629 if (self.eatToken(Token.Id.Identifier)) |identifier| {
630 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
631 const node = try arena.construct(ast.Node.StructField {
632 .base = ast.Node {
633 .id = ast.Node.Id.StructField,
634 .same_line_comment = null,
635 },
636 .doc_comments = ctx.comments,
637 .visib_token = ctx.visib_token,
638 .name_token = identifier,
639 .type_expr = undefined,
640 });
641 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
642 *node_ptr = &node.base;
643
644 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
645 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
646 try stack.append(State { .ExpectToken = Token.Id.Colon });
647 continue;
648 }
649
650 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
651 try stack.append(State {
652 .TopLevelExtern = TopLevelDeclCtx {
653 .decls = &ctx.container_decl.fields_and_decls,
654 .visib_token = ctx.visib_token,
655 .extern_export_inline_token = null,
656 .lib_name = null,
657 .comments = ctx.comments,
658 }
659 });
660 continue;
661 },
662
663 State.FieldInitValue => |ctx| {
664 const eq_tok = self.getNextToken();
665 if (eq_tok.id != Token.Id.Equal) {
666 self.putBackToken(eq_tok);
667 continue;
668 }
669 stack.append(State { .Expression = ctx }) catch unreachable;
670 continue;
671 },
672
673 State.ContainerKind => |ctx| {
674 const token = self.getNextToken();
675 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
676 ast.Node.ContainerDecl {
677 .base = undefined,
678 .ltoken = ctx.ltoken,
679 .layout = ctx.layout,
680 .kind = switch (token.id) {
681 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
682 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
683 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
684 else => {
685 return self.parseError(token, "expected {}, {} or {}, found {}",
686 @tagName(Token.Id.Keyword_struct),
687 @tagName(Token.Id.Keyword_union),
688 @tagName(Token.Id.Keyword_enum),
689 @tagName(token.id));
690 },
691 },
692 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
693 .fields_and_decls = ArrayList(&ast.Node).init(arena),
694 .rbrace_token = undefined,
695 }
696 );
697
698 stack.append(State { .ContainerDecl = node }) catch unreachable;
699 try stack.append(State { .ExpectToken = Token.Id.LBrace });
700 try stack.append(State { .ContainerInitArgStart = node });
701 continue;
702 },
703
704 State.ContainerInitArgStart => |container_decl| {
705 if (self.eatToken(Token.Id.LParen) == null) {
706 continue;
707 }
708
709 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
710 try stack.append(State { .ContainerInitArg = container_decl });
711 continue;
712 },
713
714 State.ContainerInitArg => |container_decl| {
715 const init_arg_token = self.getNextToken();
716 switch (init_arg_token.id) {
717 Token.Id.Keyword_enum => {
718 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
719 const lparen_tok = self.getNextToken();
720 if (lparen_tok.id == Token.Id.LParen) {
721 try stack.append(State { .ExpectToken = Token.Id.RParen } );
722 try stack.append(State { .Expression = OptionalCtx {
723 .RequiredNull = &container_decl.init_arg_expr.Enum,
724 } });
725 } else {
726 self.putBackToken(lparen_tok);
727 }
728 },
729 else => {
730 self.putBackToken(init_arg_token);
731 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
732 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
733 },
734 }
735 continue;
736 },
737
738 State.ContainerDecl => |container_decl| {
739 while (try self.eatLineComment(arena)) |line_comment| {
740 try container_decl.fields_and_decls.append(&line_comment.base);
741 }
742
743 const comments = try self.eatDocComments(arena);
744 const token = self.getNextToken();
745 switch (token.id) {
746 Token.Id.Identifier => {
747 switch (container_decl.kind) {
748 ast.Node.ContainerDecl.Kind.Struct => {
749 const node = try arena.construct(ast.Node.StructField {
750 .base = ast.Node {
751 .id = ast.Node.Id.StructField,
752 .same_line_comment = null,
753 },
754 .doc_comments = comments,
755 .visib_token = null,
756 .name_token = token,
757 .type_expr = undefined,
758 });
759 const node_ptr = try container_decl.fields_and_decls.addOne();
760 *node_ptr = &node.base;
761
762 try stack.append(State { .FieldListCommaOrEnd = container_decl });
763 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
764 try stack.append(State { .ExpectToken = Token.Id.Colon });
765 continue;
766 },
767 ast.Node.ContainerDecl.Kind.Union => {
768 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.UnionTag,
769 ast.Node.UnionTag {
770 .base = undefined,
771 .name_token = token,
772 .type_expr = null,
773 .value_expr = null,
774 .doc_comments = comments,
775 }
776 );
777
778 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
779 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
780 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
781 try stack.append(State { .IfToken = Token.Id.Colon });
782 continue;
783 },
784 ast.Node.ContainerDecl.Kind.Enum => {
785 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.EnumTag,
786 ast.Node.EnumTag {
787 .base = undefined,
788 .name_token = token,
789 .value = null,
790 .doc_comments = comments,
791 }
792 );
793
794 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
795 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
796 try stack.append(State { .IfToken = Token.Id.Equal });
797 continue;
798 },
799 }
800 },
801 Token.Id.Keyword_pub => {
802 switch (container_decl.kind) {
803 ast.Node.ContainerDecl.Kind.Struct => {
804 try stack.append(State {
805 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
806 .visib_token = token,
807 .container_decl = container_decl,
808 .comments = comments,
809 }
810 });
811 continue;
812 },
813 else => {
814 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
815 try stack.append(State {
816 .TopLevelExtern = TopLevelDeclCtx {
817 .decls = &container_decl.fields_and_decls,
818 .visib_token = token,
819 .extern_export_inline_token = null,
820 .lib_name = null,
821 .comments = comments,
822 }
823 });
824 continue;
825 }
826 }
827 },
828 Token.Id.Keyword_export => {
829 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
830 try stack.append(State {
831 .TopLevelExtern = TopLevelDeclCtx {
832 .decls = &container_decl.fields_and_decls,
833 .visib_token = token,
834 .extern_export_inline_token = null,
835 .lib_name = null,
836 .comments = comments,
837 }
838 });
839 continue;
840 },
841 Token.Id.RBrace => {
842 if (comments != null) {
843 return self.parseError(token, "doc comments must be attached to a node");
844 }
845 container_decl.rbrace_token = token;
846 continue;
847 },
848 else => {
849 self.putBackToken(token);
850 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
851 try stack.append(State {
852 .TopLevelExtern = TopLevelDeclCtx {
853 .decls = &container_decl.fields_and_decls,
854 .visib_token = null,
855 .extern_export_inline_token = null,
856 .lib_name = null,
857 .comments = comments,
858 }
859 });
860 continue;
861 }
862 }
863 },
864
865
866 State.VarDecl => |ctx| {
867 const var_decl = try arena.construct(ast.Node.VarDecl {
868 .base = ast.Node {
869 .id = ast.Node.Id.VarDecl,
870 .same_line_comment = null,
871 },
872 .doc_comments = ctx.comments,
873 .visib_token = ctx.visib_token,
874 .mut_token = ctx.mut_token,
875 .comptime_token = ctx.comptime_token,
876 .extern_export_token = ctx.extern_export_token,
877 .type_node = null,
878 .align_node = null,
879 .init_node = null,
880 .lib_name = ctx.lib_name,
881 // initialized later
882 .name_token = undefined,
883 .eq_token = undefined,
884 .semicolon_token = undefined,
885 });
886 try ctx.list.append(&var_decl.base);
887
888 try stack.append(State { .LookForSameLineCommentDirect = &var_decl.base });
889 try stack.append(State { .VarDeclAlign = var_decl });
890 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
891 try stack.append(State { .IfToken = Token.Id.Colon });
892 try stack.append(State {
893 .ExpectTokenSave = ExpectTokenSave {
894 .id = Token.Id.Identifier,
895 .ptr = &var_decl.name_token,
896 }
897 });
898 continue;
899 },
900 State.VarDeclAlign => |var_decl| {
901 try stack.append(State { .VarDeclEq = var_decl });
902
903 const next_token = self.getNextToken();
904 if (next_token.id == Token.Id.Keyword_align) {
905 try stack.append(State { .ExpectToken = Token.Id.RParen });
906 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
907 try stack.append(State { .ExpectToken = Token.Id.LParen });
908 continue;
909 }
910
911 self.putBackToken(next_token);
912 continue;
913 },
914 State.VarDeclEq => |var_decl| {
915 const token = self.getNextToken();
916 switch (token.id) {
917 Token.Id.Equal => {
918 var_decl.eq_token = token;
919 stack.append(State {
920 .ExpectTokenSave = ExpectTokenSave {
921 .id = Token.Id.Semicolon,
922 .ptr = &var_decl.semicolon_token,
923 },
924 }) catch unreachable;
925 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
926 continue;
927 },
928 Token.Id.Semicolon => {
929 var_decl.semicolon_token = token;
930 continue;
931 },
932 else => {
933 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
934 }
935 }
936 },
937
938
939 State.FnDef => |fn_proto| {
940 const token = self.getNextToken();
941 switch(token.id) {
942 Token.Id.LBrace => {
943 const block = try self.createNode(arena, ast.Node.Block,
944 ast.Node.Block {
945 .base = undefined,
946 .label = null,
947 .lbrace = token,
948 .statements = ArrayList(&ast.Node).init(arena),
949 .rbrace = undefined,
950 }
951 );
952 fn_proto.body_node = &block.base;
953 stack.append(State { .Block = block }) catch unreachable;
954 continue;
955 },
956 Token.Id.Semicolon => continue,
957 else => {
958 return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
959 },
960 }
961 },
962 State.FnProto => |fn_proto| {
963 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
964 try stack.append(State { .ParamDecl = fn_proto });
965 try stack.append(State { .ExpectToken = Token.Id.LParen });
966
967 if (self.eatToken(Token.Id.Identifier)) |name_token| {
968 fn_proto.name_token = name_token;
969 }
970 continue;
971 },
972 State.FnProtoAlign => |fn_proto| {
973 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
974
975 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
976 try stack.append(State { .ExpectToken = Token.Id.RParen });
977 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
978 try stack.append(State { .ExpectToken = Token.Id.LParen });
979 }
980 continue;
981 },
982 State.FnProtoReturnType => |fn_proto| {
983 const token = self.getNextToken();
984 switch (token.id) {
985 Token.Id.Bang => {
986 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
987 stack.append(State {
988 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
989 }) catch unreachable;
990 continue;
991 },
992 else => {
993 // TODO: this is a special case. Remove this when #760 is fixed
994 if (token.id == Token.Id.Keyword_error) {
995 if (self.isPeekToken(Token.Id.LBrace)) {
996 fn_proto.return_type = ast.Node.FnProto.ReturnType {
997 .Explicit = &(try self.createLiteral(arena, ast.Node.ErrorType, token)).base
998 };
999 continue;
1000 }
1001 }
1002
1003 self.putBackToken(token);
1004 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
1005 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
1006 continue;
1007 },
1008 }
1009 },
1010
1011
1012 State.ParamDecl => |fn_proto| {
1013 if (self.eatToken(Token.Id.RParen)) |_| {
1014 continue;
1015 }
1016 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.Node.ParamDecl,
1017 ast.Node.ParamDecl {
1018 .base = undefined,
1019 .comptime_token = null,
1020 .noalias_token = null,
1021 .name_token = null,
1022 .type_node = undefined,
1023 .var_args_token = null,
1024 },
1025 );
1026
1027 stack.append(State {
1028 .ParamDeclEnd = ParamDeclEndCtx {
1029 .param_decl = param_decl,
1030 .fn_proto = fn_proto,
1031 }
1032 }) catch unreachable;
1033 try stack.append(State { .ParamDeclName = param_decl });
1034 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
1035 continue;
1036 },
1037 State.ParamDeclAliasOrComptime => |param_decl| {
1038 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
1039 param_decl.comptime_token = comptime_token;
1040 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
1041 param_decl.noalias_token = noalias_token;
1042 }
1043 continue;
1044 },
1045 State.ParamDeclName => |param_decl| {
1046 // TODO: Here, we eat two tokens in one state. This means that we can't have
1047 // comments between these two tokens.
1048 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
1049 if (self.eatToken(Token.Id.Colon)) |_| {
1050 param_decl.name_token = ident_token;
1051 } else {
1052 self.putBackToken(ident_token);
1053 }
1054 }
1055 continue;
1056 },
1057 State.ParamDeclEnd => |ctx| {
1058 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1059 ctx.param_decl.var_args_token = ellipsis3;
1060 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1061 continue;
1062 }
1063
1064 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
1065 try stack.append(State {
1066 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
1067 });
1068 continue;
1069 },
1070 State.ParamDeclComma => |fn_proto| {
1071 if ((try self.expectCommaOrEnd(Token.Id.RParen)) == null) {
1072 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
1073 }
1074 continue;
1075 },
1076
1077 State.MaybeLabeledExpression => |ctx| {
1078 if (self.eatToken(Token.Id.Colon)) |_| {
1079 stack.append(State {
1080 .LabeledExpression = LabelCtx {
1081 .label = ctx.label,
1082 .opt_ctx = ctx.opt_ctx,
1083 }
1084 }) catch unreachable;
1085 continue;
1086 }
1087
1088 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
1089 continue;
1090 },
1091 State.LabeledExpression => |ctx| {
1092 const token = self.getNextToken();
1093 switch (token.id) {
1094 Token.Id.LBrace => {
1095 const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
1096 ast.Node.Block {
1097 .base = undefined,
1098 .label = ctx.label,
1099 .lbrace = token,
1100 .statements = ArrayList(&ast.Node).init(arena),
1101 .rbrace = undefined,
1102 }
1103 );
1104 stack.append(State { .Block = block }) catch unreachable;
1105 continue;
1106 },
1107 Token.Id.Keyword_while => {
1108 stack.append(State {
1109 .While = LoopCtx {
1110 .label = ctx.label,
1111 .inline_token = null,
1112 .loop_token = token,
1113 .opt_ctx = ctx.opt_ctx.toRequired(),
1114 }
1115 }) catch unreachable;
1116 continue;
1117 },
1118 Token.Id.Keyword_for => {
1119 stack.append(State {
1120 .For = LoopCtx {
1121 .label = ctx.label,
1122 .inline_token = null,
1123 .loop_token = token,
1124 .opt_ctx = ctx.opt_ctx.toRequired(),
1125 }
1126 }) catch unreachable;
1127 continue;
1128 },
1129 Token.Id.Keyword_suspend => {
1130 const node = try arena.construct(ast.Node.Suspend {
1131 .base = ast.Node {
1132 .id = ast.Node.Id.Suspend,
1133 .same_line_comment = null,
1134 },
1135 .label = ctx.label,
1136 .suspend_token = token,
1137 .payload = null,
1138 .body = null,
1139 });
1140 ctx.opt_ctx.store(&node.base);
1141 stack.append(State { .SuspendBody = node }) catch unreachable;
1142 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1143 continue;
1144 },
1145 Token.Id.Keyword_inline => {
1146 stack.append(State {
1147 .Inline = InlineCtx {
1148 .label = ctx.label,
1149 .inline_token = token,
1150 .opt_ctx = ctx.opt_ctx.toRequired(),
1151 }
1152 }) catch unreachable;
1153 continue;
1154 },
1155 else => {
1156 if (ctx.opt_ctx != OptionalCtx.Optional) {
1157 return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
1158 }
1159
1160 self.putBackToken(token);
1161 continue;
1162 },
1163 }
1164 },
1165 State.Inline => |ctx| {
1166 const token = self.getNextToken();
1167 switch (token.id) {
1168 Token.Id.Keyword_while => {
1169 stack.append(State {
1170 .While = LoopCtx {
1171 .inline_token = ctx.inline_token,
1172 .label = ctx.label,
1173 .loop_token = token,
1174 .opt_ctx = ctx.opt_ctx.toRequired(),
1175 }
1176 }) catch unreachable;
1177 continue;
1178 },
1179 Token.Id.Keyword_for => {
1180 stack.append(State {
1181 .For = LoopCtx {
1182 .inline_token = ctx.inline_token,
1183 .label = ctx.label,
1184 .loop_token = token,
1185 .opt_ctx = ctx.opt_ctx.toRequired(),
1186 }
1187 }) catch unreachable;
1188 continue;
1189 },
1190 else => {
1191 if (ctx.opt_ctx != OptionalCtx.Optional) {
1192 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1193 }
1194
1195 self.putBackToken(token);
1196 continue;
1197 },
1198 }
1199 },
1200 State.While => |ctx| {
1201 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
1202 ast.Node.While {
1203 .base = undefined,
1204 .label = ctx.label,
1205 .inline_token = ctx.inline_token,
1206 .while_token = ctx.loop_token,
1207 .condition = undefined,
1208 .payload = null,
1209 .continue_expr = null,
1210 .body = undefined,
1211 .@"else" = null,
1212 }
1213 );
1214 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1215 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1216 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
1217 try stack.append(State { .IfToken = Token.Id.Colon });
1218 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1219 try stack.append(State { .ExpectToken = Token.Id.RParen });
1220 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
1221 try stack.append(State { .ExpectToken = Token.Id.LParen });
1222 continue;
1223 },
1224 State.WhileContinueExpr => |dest| {
1225 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1226 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
1227 try stack.append(State { .ExpectToken = Token.Id.LParen });
1228 continue;
1229 },
1230 State.For => |ctx| {
1231 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
1232 ast.Node.For {
1233 .base = undefined,
1234 .label = ctx.label,
1235 .inline_token = ctx.inline_token,
1236 .for_token = ctx.loop_token,
1237 .array_expr = undefined,
1238 .payload = null,
1239 .body = undefined,
1240 .@"else" = null,
1241 }
1242 );
1243 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1244 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1245 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1246 try stack.append(State { .ExpectToken = Token.Id.RParen });
1247 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1248 try stack.append(State { .ExpectToken = Token.Id.LParen });
1249 continue;
1250 },
1251 State.Else => |dest| {
1252 if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
1253 const node = try self.createNode(arena, ast.Node.Else,
1254 ast.Node.Else {
1255 .base = undefined,
1256 .else_token = else_token,
1257 .payload = null,
1258 .body = undefined,
1259 }
1260 );
1261 *dest = node;
1262
1263 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1264 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1265 continue;
1266 } else {
1267 continue;
1268 }
1269 },
1270
1271
1272 State.Block => |block| {
1273 const token = self.getNextToken();
1274 switch (token.id) {
1275 Token.Id.RBrace => {
1276 block.rbrace = token;
1277 continue;
1278 },
1279 else => {
1280 self.putBackToken(token);
1281 stack.append(State { .Block = block }) catch unreachable;
1282
1283 var any_comments = false;
1284 while (try self.eatLineComment(arena)) |line_comment| {
1285 try block.statements.append(&line_comment.base);
1286 any_comments = true;
1287 }
1288 if (any_comments) continue;
1289
1290 try stack.append(State { .Statement = block });
1291 continue;
1292 },
1293 }
1294 },
1295 State.Statement => |block| {
1296 const token = self.getNextToken();
1297 switch (token.id) {
1298 Token.Id.Keyword_comptime => {
1299 stack.append(State {
1300 .ComptimeStatement = ComptimeStatementCtx {
1301 .comptime_token = token,
1302 .block = block,
1303 }
1304 }) catch unreachable;
1305 continue;
1306 },
1307 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1308 stack.append(State {
1309 .VarDecl = VarDeclCtx {
1310 .comments = null,
1311 .visib_token = null,
1312 .comptime_token = null,
1313 .extern_export_token = null,
1314 .lib_name = null,
1315 .mut_token = token,
1316 .list = &block.statements,
1317 }
1318 }) catch unreachable;
1319 continue;
1320 },
1321 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1322 const node = try arena.construct(ast.Node.Defer {
1323 .base = ast.Node {
1324 .id = ast.Node.Id.Defer,
1325 .same_line_comment = null,
1326 },
1327 .defer_token = token,
1328 .kind = switch (token.id) {
1329 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1330 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1331 else => unreachable,
1332 },
1333 .expr = undefined,
1334 });
1335 const node_ptr = try block.statements.addOne();
1336 *node_ptr = &node.base;
1337
1338 stack.append(State { .Semicolon = node_ptr }) catch unreachable;
1339 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1340 continue;
1341 },
1342 Token.Id.LBrace => {
1343 const inner_block = try self.createAttachNode(arena, &block.statements, ast.Node.Block,
1344 ast.Node.Block {
1345 .base = undefined,
1346 .label = null,
1347 .lbrace = token,
1348 .statements = ArrayList(&ast.Node).init(arena),
1349 .rbrace = undefined,
1350 }
1351 );
1352 stack.append(State { .Block = inner_block }) catch unreachable;
1353 continue;
1354 },
1355 else => {
1356 self.putBackToken(token);
1357 const statement = try block.statements.addOne();
1358 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1359 try stack.append(State { .Semicolon = statement });
1360 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1361 continue;
1362 }
1363 }
1364 },
1365 State.ComptimeStatement => |ctx| {
1366 const token = self.getNextToken();
1367 switch (token.id) {
1368 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1369 stack.append(State {
1370 .VarDecl = VarDeclCtx {
1371 .comments = null,
1372 .visib_token = null,
1373 .comptime_token = ctx.comptime_token,
1374 .extern_export_token = null,
1375 .lib_name = null,
1376 .mut_token = token,
1377 .list = &ctx.block.statements,
1378 }
1379 }) catch unreachable;
1380 continue;
1381 },
1382 else => {
1383 self.putBackToken(token);
1384 self.putBackToken(ctx.comptime_token);
1385 const statement = try ctx.block.statements.addOne();
1386 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1387 try stack.append(State { .Semicolon = statement });
1388 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1389 continue;
1390 }
1391 }
1392 },
1393 State.Semicolon => |node_ptr| {
1394 const node = *node_ptr;
1395 if (requireSemiColon(node)) {
1396 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1397 continue;
1398 }
1399 continue;
1400 },
1401
1402 State.LookForSameLineComment => |node_ptr| {
1403 try self.lookForSameLineComment(arena, *node_ptr);
1404 continue;
1405 },
1406
1407 State.LookForSameLineCommentDirect => |node| {
1408 try self.lookForSameLineComment(arena, node);
1409 continue;
1410 },
1411
1412
1413 State.AsmOutputItems => |items| {
1414 const lbracket = self.getNextToken();
1415 if (lbracket.id != Token.Id.LBracket) {
1416 self.putBackToken(lbracket);
1417 continue;
1418 }
1419
1420 const node = try self.createNode(arena, ast.Node.AsmOutput,
1421 ast.Node.AsmOutput {
1422 .base = undefined,
1423 .symbolic_name = undefined,
1424 .constraint = undefined,
1425 .kind = undefined,
1426 }
1427 );
1428 try items.append(node);
1429
1430 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1431 try stack.append(State { .IfToken = Token.Id.Comma });
1432 try stack.append(State { .ExpectToken = Token.Id.RParen });
1433 try stack.append(State { .AsmOutputReturnOrType = node });
1434 try stack.append(State { .ExpectToken = Token.Id.LParen });
1435 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1436 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1437 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1438 continue;
1439 },
1440 State.AsmOutputReturnOrType => |node| {
1441 const token = self.getNextToken();
1442 switch (token.id) {
1443 Token.Id.Identifier => {
1444 node.kind = ast.Node.AsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.Node.Identifier, token) };
1445 continue;
1446 },
1447 Token.Id.Arrow => {
1448 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1449 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1450 continue;
1451 },
1452 else => {
1453 return self.parseError(token, "expected '->' or {}, found {}",
1454 @tagName(Token.Id.Identifier),
1455 @tagName(token.id));
1456 },
1457 }
1458 },
1459 State.AsmInputItems => |items| {
1460 const lbracket = self.getNextToken();
1461 if (lbracket.id != Token.Id.LBracket) {
1462 self.putBackToken(lbracket);
1463 continue;
1464 }
1465
1466 const node = try self.createNode(arena, ast.Node.AsmInput,
1467 ast.Node.AsmInput {
1468 .base = undefined,
1469 .symbolic_name = undefined,
1470 .constraint = undefined,
1471 .expr = undefined,
1472 }
1473 );
1474 try items.append(node);
1475
1476 stack.append(State { .AsmInputItems = items }) catch unreachable;
1477 try stack.append(State { .IfToken = Token.Id.Comma });
1478 try stack.append(State { .ExpectToken = Token.Id.RParen });
1479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1480 try stack.append(State { .ExpectToken = Token.Id.LParen });
1481 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1482 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1483 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1484 continue;
1485 },
1486 State.AsmClopperItems => |items| {
1487 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1488 try stack.append(State { .IfToken = Token.Id.Comma });
1489 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1490 continue;
1491 },
1492
1493
1494 State.ExprListItemOrEnd => |list_state| {
1495 if (self.eatToken(list_state.end)) |token| {
1496 *list_state.ptr = token;
1497 continue;
1498 }
1499
1500 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1501 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1502 continue;
1503 },
1504 State.ExprListCommaOrEnd => |list_state| {
1505 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1506 *list_state.ptr = end;
1507 continue;
1508 } else {
1509 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1510 continue;
1511 }
1512 },
1513 State.FieldInitListItemOrEnd => |list_state| {
1514 while (try self.eatLineComment(arena)) |line_comment| {
1515 try list_state.list.append(&line_comment.base);
1516 }
1517
1518 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1519 *list_state.ptr = rbrace;
1520 continue;
1521 }
1522
1523 const node = try arena.construct(ast.Node.FieldInitializer {
1524 .base = ast.Node {
1525 .id = ast.Node.Id.FieldInitializer,
1526 .same_line_comment = null,
1527 },
1528 .period_token = undefined,
1529 .name_token = undefined,
1530 .expr = undefined,
1531 });
1532 try list_state.list.append(&node.base);
1533
1534 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1535 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1536 try stack.append(State { .ExpectToken = Token.Id.Equal });
1537 try stack.append(State {
1538 .ExpectTokenSave = ExpectTokenSave {
1539 .id = Token.Id.Identifier,
1540 .ptr = &node.name_token,
1541 }
1542 });
1543 try stack.append(State {
1544 .ExpectTokenSave = ExpectTokenSave {
1545 .id = Token.Id.Period,
1546 .ptr = &node.period_token,
1547 }
1548 });
1549 continue;
1550 },
1551 State.FieldInitListCommaOrEnd => |list_state| {
1552 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1553 *list_state.ptr = end;
1554 continue;
1555 } else {
1556 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1557 continue;
1558 }
1559 },
1560 State.FieldListCommaOrEnd => |container_decl| {
1561 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1562 container_decl.rbrace_token = end;
1563 continue;
1564 }
1565
1566 try self.lookForSameLineComment(arena, container_decl.fields_and_decls.toSlice()[container_decl.fields_and_decls.len - 1]);
1567 try stack.append(State { .ContainerDecl = container_decl });
1568 continue;
1569 },
1570 State.ErrorTagListItemOrEnd => |list_state| {
1571 while (try self.eatLineComment(arena)) |line_comment| {
1572 try list_state.list.append(&line_comment.base);
1573 }
1574
1575 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1576 *list_state.ptr = rbrace;
1577 continue;
1578 }
1579
1580 const node_ptr = try list_state.list.addOne();
1581
1582 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1583 try stack.append(State { .ErrorTag = node_ptr });
1584 continue;
1585 },
1586 State.ErrorTagListCommaOrEnd => |list_state| {
1587 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1588 *list_state.ptr = end;
1589 continue;
1590 } else {
1591 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1592 continue;
1593 }
1594 },
1595 State.SwitchCaseOrEnd => |list_state| {
1596 while (try self.eatLineComment(arena)) |line_comment| {
1597 try list_state.list.append(&line_comment.base);
1598 }
1599
1600 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1601 *list_state.ptr = rbrace;
1602 continue;
1603 }
1604
1605 const comments = try self.eatDocComments(arena);
1606 const node = try arena.construct(ast.Node.SwitchCase {
1607 .base = ast.Node {
1608 .id = ast.Node.Id.SwitchCase,
1609 .same_line_comment = null,
1610 },
1611 .items = ArrayList(&ast.Node).init(arena),
1612 .payload = null,
1613 .expr = undefined,
1614 });
1615 try list_state.list.append(&node.base);
1616 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1617 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1618 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1619 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1620
1621 continue;
1622 },
1623
1624 State.SwitchCaseCommaOrEnd => |list_state| {
1625 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1626 *list_state.ptr = end;
1627 continue;
1628 }
1629
1630 const node = list_state.list.toSlice()[list_state.list.len - 1];
1631 try self.lookForSameLineComment(arena, node);
1632 try stack.append(State { .SwitchCaseOrEnd = list_state });
1633 continue;
1634 },
1635
1636 State.SwitchCaseFirstItem => |case_items| {
1637 const token = self.getNextToken();
1638 if (token.id == Token.Id.Keyword_else) {
1639 const else_node = try self.createAttachNode(arena, case_items, ast.Node.SwitchElse,
1640 ast.Node.SwitchElse {
1641 .base = undefined,
1642 .token = token,
1643 }
1644 );
1645 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1646 continue;
1647 } else {
1648 self.putBackToken(token);
1649 try stack.append(State { .SwitchCaseItem = case_items });
1650 continue;
1651 }
1652 },
1653 State.SwitchCaseItem => |case_items| {
1654 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1655 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1656 },
1657 State.SwitchCaseItemCommaOrEnd => |case_items| {
1658 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1659 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1660 }
1661 continue;
1662 },
1663
1664
1665 State.SuspendBody => |suspend_node| {
1666 if (suspend_node.payload != null) {
1667 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1668 }
1669 continue;
1670 },
1671 State.AsyncAllocator => |async_node| {
1672 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
1673 continue;
1674 }
1675
1676 async_node.rangle_bracket = Token(undefined);
1677 try stack.append(State {
1678 .ExpectTokenSave = ExpectTokenSave {
1679 .id = Token.Id.AngleBracketRight,
1680 .ptr = &??async_node.rangle_bracket,
1681 }
1682 });
1683 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1684 continue;
1685 },
1686 State.AsyncEnd => |ctx| {
1687 const node = ctx.ctx.get() ?? continue;
1688
1689 switch (node.id) {
1690 ast.Node.Id.FnProto => {
1691 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1692 fn_proto.async_attr = ctx.attribute;
1693 continue;
1694 },
1695 ast.Node.Id.SuffixOp => {
1696 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1697 if (suffix_op.op == ast.Node.SuffixOp.Op.Call) {
1698 suffix_op.op.Call.async_attr = ctx.attribute;
1699 continue;
1700 }
1701
1702 return self.parseError(node.firstToken(), "expected {}, found {}.",
1703 @tagName(ast.Node.SuffixOp.Op.Call),
1704 @tagName(suffix_op.op));
1705 },
1706 else => {
1707 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1708 @tagName(ast.Node.SuffixOp.Op.Call),
1709 @tagName(ast.Node.Id.FnProto),
1710 @tagName(node.id));
1711 }
1712 }
1713 },
1714
1715
1716 State.ExternType => |ctx| {
1717 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1718 const fn_proto = try arena.construct(ast.Node.FnProto {
1719 .base = ast.Node {
1720 .id = ast.Node.Id.FnProto,
1721 .same_line_comment = null,
1722 },
1723 .doc_comments = ctx.comments,
1724 .visib_token = null,
1725 .name_token = null,
1726 .fn_token = fn_token,
1727 .params = ArrayList(&ast.Node).init(arena),
1728 .return_type = undefined,
1729 .var_args_token = null,
1730 .extern_export_inline_token = ctx.extern_token,
1731 .cc_token = null,
1732 .async_attr = null,
1733 .body_node = null,
1734 .lib_name = null,
1735 .align_expr = null,
1736 });
1737 ctx.opt_ctx.store(&fn_proto.base);
1738 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1739 continue;
1740 }
1741
1742 stack.append(State {
1743 .ContainerKind = ContainerKindCtx {
1744 .opt_ctx = ctx.opt_ctx,
1745 .ltoken = ctx.extern_token,
1746 .layout = ast.Node.ContainerDecl.Layout.Extern,
1747 },
1748 }) catch unreachable;
1749 continue;
1750 },
1751 State.SliceOrArrayAccess => |node| {
1752 var token = self.getNextToken();
1753 switch (token.id) {
1754 Token.Id.Ellipsis2 => {
1755 const start = node.op.ArrayAccess;
1756 node.op = ast.Node.SuffixOp.Op {
1757 .Slice = ast.Node.SuffixOp.SliceRange {
1758 .start = start,
1759 .end = null,
1760 }
1761 };
1762
1763 stack.append(State {
1764 .ExpectTokenSave = ExpectTokenSave {
1765 .id = Token.Id.RBracket,
1766 .ptr = &node.rtoken,
1767 }
1768 }) catch unreachable;
1769 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1770 continue;
1771 },
1772 Token.Id.RBracket => {
1773 node.rtoken = token;
1774 continue;
1775 },
1776 else => {
1777 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1778 }
1779 }
1780 },
1781 State.SliceOrArrayType => |node| {
1782 if (self.eatToken(Token.Id.RBracket)) |_| {
1783 node.op = ast.Node.PrefixOp.Op {
1784 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1785 .align_expr = null,
1786 .bit_offset_start_token = null,
1787 .bit_offset_end_token = null,
1788 .const_token = null,
1789 .volatile_token = null,
1790 }
1791 };
1792 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1793 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1794 continue;
1795 }
1796
1797 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1798 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1799 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1800 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1801 continue;
1802 },
1803 State.AddrOfModifiers => |addr_of_info| {
1804 var token = self.getNextToken();
1805 switch (token.id) {
1806 Token.Id.Keyword_align => {
1807 stack.append(state) catch unreachable;
1808 if (addr_of_info.align_expr != null) {
1809 return self.parseError(token, "multiple align qualifiers");
1810 }
1811 try stack.append(State { .ExpectToken = Token.Id.RParen });
1812 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1813 try stack.append(State { .ExpectToken = Token.Id.LParen });
1814 continue;
1815 },
1816 Token.Id.Keyword_const => {
1817 stack.append(state) catch unreachable;
1818 if (addr_of_info.const_token != null) {
1819 return self.parseError(token, "duplicate qualifier: const");
1820 }
1821 addr_of_info.const_token = token;
1822 continue;
1823 },
1824 Token.Id.Keyword_volatile => {
1825 stack.append(state) catch unreachable;
1826 if (addr_of_info.volatile_token != null) {
1827 return self.parseError(token, "duplicate qualifier: volatile");
1828 }
1829 addr_of_info.volatile_token = token;
1830 continue;
1831 },
1832 else => {
1833 self.putBackToken(token);
1834 continue;
1835 },
1836 }
1837 },
1838
1839
1840 State.Payload => |opt_ctx| {
1841 const token = self.getNextToken();
1842 if (token.id != Token.Id.Pipe) {
1843 if (opt_ctx != OptionalCtx.Optional) {
1844 return self.parseError(token, "expected {}, found {}.",
1845 @tagName(Token.Id.Pipe),
1846 @tagName(token.id));
1847 }
1848
1849 self.putBackToken(token);
1850 continue;
1851 }
1852
1853 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1854 ast.Node.Payload {
1855 .base = undefined,
1856 .lpipe = token,
1857 .error_symbol = undefined,
1858 .rpipe = undefined
1859 }
1860 );
1861
1862 stack.append(State {
1863 .ExpectTokenSave = ExpectTokenSave {
1864 .id = Token.Id.Pipe,
1865 .ptr = &node.rpipe,
1866 }
1867 }) catch unreachable;
1868 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1869 continue;
1870 },
1871 State.PointerPayload => |opt_ctx| {
1872 const token = self.getNextToken();
1873 if (token.id != Token.Id.Pipe) {
1874 if (opt_ctx != OptionalCtx.Optional) {
1875 return self.parseError(token, "expected {}, found {}.",
1876 @tagName(Token.Id.Pipe),
1877 @tagName(token.id));
1878 }
1879
1880 self.putBackToken(token);
1881 continue;
1882 }
1883
1884 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1885 ast.Node.PointerPayload {
1886 .base = undefined,
1887 .lpipe = token,
1888 .ptr_token = null,
1889 .value_symbol = undefined,
1890 .rpipe = undefined
1891 }
1892 );
1893
1894 stack.append(State {.LookForSameLineCommentDirect = &node.base }) catch unreachable;
1895 try stack.append(State {
1896 .ExpectTokenSave = ExpectTokenSave {
1897 .id = Token.Id.Pipe,
1898 .ptr = &node.rpipe,
1899 }
1900 });
1901 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1902 try stack.append(State {
1903 .OptionalTokenSave = OptionalTokenSave {
1904 .id = Token.Id.Asterisk,
1905 .ptr = &node.ptr_token,
1906 }
1907 });
1908 continue;
1909 },
1910 State.PointerIndexPayload => |opt_ctx| {
1911 const token = self.getNextToken();
1912 if (token.id != Token.Id.Pipe) {
1913 if (opt_ctx != OptionalCtx.Optional) {
1914 return self.parseError(token, "expected {}, found {}.",
1915 @tagName(Token.Id.Pipe),
1916 @tagName(token.id));
1917 }
1918
1919 self.putBackToken(token);
1920 continue;
1921 }
1922
1923 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1924 ast.Node.PointerIndexPayload {
1925 .base = undefined,
1926 .lpipe = token,
1927 .ptr_token = null,
1928 .value_symbol = undefined,
1929 .index_symbol = null,
1930 .rpipe = undefined
1931 }
1932 );
1933
1934 stack.append(State {
1935 .ExpectTokenSave = ExpectTokenSave {
1936 .id = Token.Id.Pipe,
1937 .ptr = &node.rpipe,
1938 }
1939 }) catch unreachable;
1940 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1941 try stack.append(State { .IfToken = Token.Id.Comma });
1942 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1943 try stack.append(State {
1944 .OptionalTokenSave = OptionalTokenSave {
1945 .id = Token.Id.Asterisk,
1946 .ptr = &node.ptr_token,
1947 }
1948 });
1949 continue;
1950 },
1951
1952
1953 State.Expression => |opt_ctx| {
1954 const token = self.getNextToken();
1955 switch (token.id) {
1956 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1957 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1958 ast.Node.ControlFlowExpression {
1959 .base = undefined,
1960 .ltoken = token,
1961 .kind = undefined,
1962 .rhs = null,
1963 }
1964 );
1965
1966 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1967
1968 switch (token.id) {
1969 Token.Id.Keyword_break => {
1970 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1971 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1972 try stack.append(State { .IfToken = Token.Id.Colon });
1973 },
1974 Token.Id.Keyword_continue => {
1975 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1976 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1977 try stack.append(State { .IfToken = Token.Id.Colon });
1978 },
1979 Token.Id.Keyword_return => {
1980 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1981 },
1982 else => unreachable,
1983 }
1984 continue;
1985 },
1986 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1987 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1988 ast.Node.PrefixOp {
1989 .base = undefined,
1990 .op_token = token,
1991 .op = switch (token.id) {
1992 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1993 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1994 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1995 else => unreachable,
1996 },
1997 .rhs = undefined,
1998 }
1999 );
2000
2001 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2002 continue;
2003 },
2004 else => {
2005 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2006 self.putBackToken(token);
2007 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
2008 }
2009 continue;
2010 }
2011 }
2012 },
2013 State.RangeExpressionBegin => |opt_ctx| {
2014 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
2015 try stack.append(State { .Expression = opt_ctx });
2016 continue;
2017 },
2018 State.RangeExpressionEnd => |opt_ctx| {
2019 const lhs = opt_ctx.get() ?? continue;
2020
2021 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
2022 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2023 ast.Node.InfixOp {
2024 .base = undefined,
2025 .lhs = lhs,
2026 .op_token = ellipsis3,
2027 .op = ast.Node.InfixOp.Op.Range,
2028 .rhs = undefined,
2029 }
2030 );
2031 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2032 continue;
2033 }
2034 },
2035 State.AssignmentExpressionBegin => |opt_ctx| {
2036 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
2037 try stack.append(State { .Expression = opt_ctx });
2038 continue;
2039 },
2040
2041 State.AssignmentExpressionEnd => |opt_ctx| {
2042 const lhs = opt_ctx.get() ?? continue;
2043
2044 const token = self.getNextToken();
2045 if (tokenIdToAssignment(token.id)) |ass_id| {
2046 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2047 ast.Node.InfixOp {
2048 .base = undefined,
2049 .lhs = lhs,
2050 .op_token = token,
2051 .op = ass_id,
2052 .rhs = undefined,
2053 }
2054 );
2055 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2056 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
2057 continue;
2058 } else {
2059 self.putBackToken(token);
2060 continue;
2061 }
2062 },
2063
2064 State.UnwrapExpressionBegin => |opt_ctx| {
2065 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
2066 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
2067 continue;
2068 },
2069
2070 State.UnwrapExpressionEnd => |opt_ctx| {
2071 const lhs = opt_ctx.get() ?? continue;
2072
2073 const token = self.getNextToken();
2074 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
2075 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2076 ast.Node.InfixOp {
2077 .base = undefined,
2078 .lhs = lhs,
2079 .op_token = token,
2080 .op = unwrap_id,
2081 .rhs = undefined,
2082 }
2083 );
2084
2085 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2086 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
2087
2088 if (node.op == ast.Node.InfixOp.Op.Catch) {
2089 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
2090 }
2091 continue;
2092 } else {
2093 self.putBackToken(token);
2094 continue;
2095 }
2096 },
2097
2098 State.BoolOrExpressionBegin => |opt_ctx| {
2099 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
2100 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
2101 continue;
2102 },
2103
2104 State.BoolOrExpressionEnd => |opt_ctx| {
2105 const lhs = opt_ctx.get() ?? continue;
2106
2107 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
2108 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2109 ast.Node.InfixOp {
2110 .base = undefined,
2111 .lhs = lhs,
2112 .op_token = or_token,
2113 .op = ast.Node.InfixOp.Op.BoolOr,
2114 .rhs = undefined,
2115 }
2116 );
2117 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2118 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2119 continue;
2120 }
2121 },
2122
2123 State.BoolAndExpressionBegin => |opt_ctx| {
2124 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
2125 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
2126 continue;
2127 },
2128
2129 State.BoolAndExpressionEnd => |opt_ctx| {
2130 const lhs = opt_ctx.get() ?? continue;
2131
2132 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
2133 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2134 ast.Node.InfixOp {
2135 .base = undefined,
2136 .lhs = lhs,
2137 .op_token = and_token,
2138 .op = ast.Node.InfixOp.Op.BoolAnd,
2139 .rhs = undefined,
2140 }
2141 );
2142 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2143 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2144 continue;
2145 }
2146 },
2147
2148 State.ComparisonExpressionBegin => |opt_ctx| {
2149 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2150 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
2151 continue;
2152 },
2153
2154 State.ComparisonExpressionEnd => |opt_ctx| {
2155 const lhs = opt_ctx.get() ?? continue;
2156
2157 const token = self.getNextToken();
2158 if (tokenIdToComparison(token.id)) |comp_id| {
2159 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2160 ast.Node.InfixOp {
2161 .base = undefined,
2162 .lhs = lhs,
2163 .op_token = token,
2164 .op = comp_id,
2165 .rhs = undefined,
2166 }
2167 );
2168 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2169 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2170 continue;
2171 } else {
2172 self.putBackToken(token);
2173 continue;
2174 }
2175 },
2176
2177 State.BinaryOrExpressionBegin => |opt_ctx| {
2178 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2179 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2180 continue;
2181 },
2182
2183 State.BinaryOrExpressionEnd => |opt_ctx| {
2184 const lhs = opt_ctx.get() ?? continue;
2185
2186 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2187 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2188 ast.Node.InfixOp {
2189 .base = undefined,
2190 .lhs = lhs,
2191 .op_token = pipe,
2192 .op = ast.Node.InfixOp.Op.BitOr,
2193 .rhs = undefined,
2194 }
2195 );
2196 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2197 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2198 continue;
2199 }
2200 },
2201
2202 State.BinaryXorExpressionBegin => |opt_ctx| {
2203 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2204 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2205 continue;
2206 },
2207
2208 State.BinaryXorExpressionEnd => |opt_ctx| {
2209 const lhs = opt_ctx.get() ?? continue;
2210
2211 if (self.eatToken(Token.Id.Caret)) |caret| {
2212 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2213 ast.Node.InfixOp {
2214 .base = undefined,
2215 .lhs = lhs,
2216 .op_token = caret,
2217 .op = ast.Node.InfixOp.Op.BitXor,
2218 .rhs = undefined,
2219 }
2220 );
2221 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2222 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2223 continue;
2224 }
2225 },
2226
2227 State.BinaryAndExpressionBegin => |opt_ctx| {
2228 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2229 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2230 continue;
2231 },
2232
2233 State.BinaryAndExpressionEnd => |opt_ctx| {
2234 const lhs = opt_ctx.get() ?? continue;
2235
2236 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2237 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2238 ast.Node.InfixOp {
2239 .base = undefined,
2240 .lhs = lhs,
2241 .op_token = ampersand,
2242 .op = ast.Node.InfixOp.Op.BitAnd,
2243 .rhs = undefined,
2244 }
2245 );
2246 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2247 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2248 continue;
2249 }
2250 },
2251
2252 State.BitShiftExpressionBegin => |opt_ctx| {
2253 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2254 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2255 continue;
2256 },
2257
2258 State.BitShiftExpressionEnd => |opt_ctx| {
2259 const lhs = opt_ctx.get() ?? continue;
2260
2261 const token = self.getNextToken();
2262 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2263 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2264 ast.Node.InfixOp {
2265 .base = undefined,
2266 .lhs = lhs,
2267 .op_token = token,
2268 .op = bitshift_id,
2269 .rhs = undefined,
2270 }
2271 );
2272 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2273 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2274 continue;
2275 } else {
2276 self.putBackToken(token);
2277 continue;
2278 }
2279 },
2280
2281 State.AdditionExpressionBegin => |opt_ctx| {
2282 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2283 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2284 continue;
2285 },
2286
2287 State.AdditionExpressionEnd => |opt_ctx| {
2288 const lhs = opt_ctx.get() ?? continue;
2289
2290 const token = self.getNextToken();
2291 if (tokenIdToAddition(token.id)) |add_id| {
2292 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2293 ast.Node.InfixOp {
2294 .base = undefined,
2295 .lhs = lhs,
2296 .op_token = token,
2297 .op = add_id,
2298 .rhs = undefined,
2299 }
2300 );
2301 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2302 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2303 continue;
2304 } else {
2305 self.putBackToken(token);
2306 continue;
2307 }
2308 },
2309
2310 State.MultiplyExpressionBegin => |opt_ctx| {
2311 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2312 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2313 continue;
2314 },
2315
2316 State.MultiplyExpressionEnd => |opt_ctx| {
2317 const lhs = opt_ctx.get() ?? continue;
2318
2319 const token = self.getNextToken();
2320 if (tokenIdToMultiply(token.id)) |mult_id| {
2321 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2322 ast.Node.InfixOp {
2323 .base = undefined,
2324 .lhs = lhs,
2325 .op_token = token,
2326 .op = mult_id,
2327 .rhs = undefined,
2328 }
2329 );
2330 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2331 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2332 continue;
2333 } else {
2334 self.putBackToken(token);
2335 continue;
2336 }
2337 },
2338
2339 State.CurlySuffixExpressionBegin => |opt_ctx| {
2340 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2341 try stack.append(State { .IfToken = Token.Id.LBrace });
2342 try stack.append(State { .TypeExprBegin = opt_ctx });
2343 continue;
2344 },
2345
2346 State.CurlySuffixExpressionEnd => |opt_ctx| {
2347 const lhs = opt_ctx.get() ?? continue;
2348
2349 if (self.isPeekToken(Token.Id.Period)) {
2350 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2351 ast.Node.SuffixOp {
2352 .base = undefined,
2353 .lhs = lhs,
2354 .op = ast.Node.SuffixOp.Op {
2355 .StructInitializer = ArrayList(&ast.Node).init(arena),
2356 },
2357 .rtoken = undefined,
2358 }
2359 );
2360 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2361 try stack.append(State { .IfToken = Token.Id.LBrace });
2362 try stack.append(State {
2363 .FieldInitListItemOrEnd = ListSave(&ast.Node) {
2364 .list = &node.op.StructInitializer,
2365 .ptr = &node.rtoken,
2366 }
2367 });
2368 continue;
2369 }
2370
2371 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2372 ast.Node.SuffixOp {
2373 .base = undefined,
2374 .lhs = lhs,
2375 .op = ast.Node.SuffixOp.Op {
2376 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2377 },
2378 .rtoken = undefined,
2379 }
2380 );
2381 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2382 try stack.append(State { .IfToken = Token.Id.LBrace });
2383 try stack.append(State {
2384 .ExprListItemOrEnd = ExprListCtx {
2385 .list = &node.op.ArrayInitializer,
2386 .end = Token.Id.RBrace,
2387 .ptr = &node.rtoken,
2388 }
2389 });
2390 continue;
2391 },
2392
2393 State.TypeExprBegin => |opt_ctx| {
2394 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2395 try stack.append(State { .PrefixOpExpression = opt_ctx });
2396 continue;
2397 },
2398
2399 State.TypeExprEnd => |opt_ctx| {
2400 const lhs = opt_ctx.get() ?? continue;
2401
2402 if (self.eatToken(Token.Id.Bang)) |bang| {
2403 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2404 ast.Node.InfixOp {
2405 .base = undefined,
2406 .lhs = lhs,
2407 .op_token = bang,
2408 .op = ast.Node.InfixOp.Op.ErrorUnion,
2409 .rhs = undefined,
2410 }
2411 );
2412 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2413 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2414 continue;
2415 }
2416 },
2417
2418 State.PrefixOpExpression => |opt_ctx| {
2419 const token = self.getNextToken();
2420 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2421 var node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2422 ast.Node.PrefixOp {
2423 .base = undefined,
2424 .op_token = token,
2425 .op = prefix_id,
2426 .rhs = undefined,
2427 }
2428 );
2429
2430 // Treat '**' token as two derefs
2431 if (token.id == Token.Id.AsteriskAsterisk) {
2432 const child = try self.createNode(arena, ast.Node.PrefixOp,
2433 ast.Node.PrefixOp {
2434 .base = undefined,
2435 .op_token = token,
2436 .op = prefix_id,
2437 .rhs = undefined,
2438 }
2439 );
2440 node.rhs = &child.base;
2441 node = child;
2442 }
2443
2444 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2445 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2446 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2447 }
2448 continue;
2449 } else {
2450 self.putBackToken(token);
2451 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2452 continue;
2453 }
2454 },
2455
2456 State.SuffixOpExpressionBegin => |opt_ctx| {
2457 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2458 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
2459 ast.Node.AsyncAttribute {
2460 .base = undefined,
2461 .async_token = async_token,
2462 .allocator_type = null,
2463 .rangle_bracket = null,
2464 }
2465 );
2466 stack.append(State {
2467 .AsyncEnd = AsyncEndCtx {
2468 .ctx = opt_ctx,
2469 .attribute = async_node,
2470 }
2471 }) catch unreachable;
2472 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2473 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2474 try stack.append(State { .AsyncAllocator = async_node });
2475 continue;
2476 }
2477
2478 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2479 try stack.append(State { .PrimaryExpression = opt_ctx });
2480 continue;
2481 },
2482
2483 State.SuffixOpExpressionEnd => |opt_ctx| {
2484 const lhs = opt_ctx.get() ?? continue;
2485
2486 const token = self.getNextToken();
2487 switch (token.id) {
2488 Token.Id.LParen => {
2489 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2490 ast.Node.SuffixOp {
2491 .base = undefined,
2492 .lhs = lhs,
2493 .op = ast.Node.SuffixOp.Op {
2494 .Call = ast.Node.SuffixOp.CallInfo {
2495 .params = ArrayList(&ast.Node).init(arena),
2496 .async_attr = null,
2497 }
2498 },
2499 .rtoken = undefined,
2500 }
2501 );
2502 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2503 try stack.append(State {
2504 .ExprListItemOrEnd = ExprListCtx {
2505 .list = &node.op.Call.params,
2506 .end = Token.Id.RParen,
2507 .ptr = &node.rtoken,
2508 }
2509 });
2510 continue;
2511 },
2512 Token.Id.LBracket => {
2513 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2514 ast.Node.SuffixOp {
2515 .base = undefined,
2516 .lhs = lhs,
2517 .op = ast.Node.SuffixOp.Op {
2518 .ArrayAccess = undefined,
2519 },
2520 .rtoken = undefined
2521 }
2522 );
2523 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2524 try stack.append(State { .SliceOrArrayAccess = node });
2525 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2526 continue;
2527 },
2528 Token.Id.Period => {
2529 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2530 ast.Node.InfixOp {
2531 .base = undefined,
2532 .lhs = lhs,
2533 .op_token = token,
2534 .op = ast.Node.InfixOp.Op.Period,
2535 .rhs = undefined,
2536 }
2537 );
2538 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2539 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2540 continue;
2541 },
2542 else => {
2543 self.putBackToken(token);
2544 continue;
2545 },
2546 }
2547 },
2548
2549 State.PrimaryExpression => |opt_ctx| {
2550 const token = self.getNextToken();
2551 switch (token.id) {
2552 Token.Id.IntegerLiteral => {
2553 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token);
2554 continue;
2555 },
2556 Token.Id.FloatLiteral => {
2557 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token);
2558 continue;
2559 },
2560 Token.Id.CharLiteral => {
2561 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token);
2562 continue;
2563 },
2564 Token.Id.Keyword_undefined => {
2565 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token);
2566 continue;
2567 },
2568 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2569 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token);
2570 continue;
2571 },
2572 Token.Id.Keyword_null => {
2573 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token);
2574 continue;
2575 },
2576 Token.Id.Keyword_this => {
2577 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token);
2578 continue;
2579 },
2580 Token.Id.Keyword_var => {
2581 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token);
2582 continue;
2583 },
2584 Token.Id.Keyword_unreachable => {
2585 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
2586 continue;
2587 },
2588 Token.Id.Keyword_promise => {
2589 const node = try arena.construct(ast.Node.PromiseType {
2590 .base = ast.Node {
2591 .id = ast.Node.Id.PromiseType,
2592 .same_line_comment = null,
2593 },
2594 .promise_token = token,
2595 .result = null,
2596 });
2597 opt_ctx.store(&node.base);
2598 const next_token = self.getNextToken();
2599 if (next_token.id != Token.Id.Arrow) {
2600 self.putBackToken(next_token);
2601 continue;
2602 }
2603 node.result = ast.Node.PromiseType.Result {
2604 .arrow_token = next_token,
2605 .return_type = undefined,
2606 };
2607 const return_type_ptr = &((??node.result).return_type);
2608 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2609 continue;
2610 },
2611 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2612 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2613 continue;
2614 },
2615 Token.Id.LParen => {
2616 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2617 ast.Node.GroupedExpression {
2618 .base = undefined,
2619 .lparen = token,
2620 .expr = undefined,
2621 .rparen = undefined,
2622 }
2623 );
2624 stack.append(State {
2625 .ExpectTokenSave = ExpectTokenSave {
2626 .id = Token.Id.RParen,
2627 .ptr = &node.rparen,
2628 }
2629 }) catch unreachable;
2630 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2631 continue;
2632 },
2633 Token.Id.Builtin => {
2634 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2635 ast.Node.BuiltinCall {
2636 .base = undefined,
2637 .builtin_token = token,
2638 .params = ArrayList(&ast.Node).init(arena),
2639 .rparen_token = undefined,
2640 }
2641 );
2642 stack.append(State {
2643 .ExprListItemOrEnd = ExprListCtx {
2644 .list = &node.params,
2645 .end = Token.Id.RParen,
2646 .ptr = &node.rparen_token,
2647 }
2648 }) catch unreachable;
2649 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2650 continue;
2651 },
2652 Token.Id.LBracket => {
2653 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2654 ast.Node.PrefixOp {
2655 .base = undefined,
2656 .op_token = token,
2657 .op = undefined,
2658 .rhs = undefined,
2659 }
2660 );
2661 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2662 continue;
2663 },
2664 Token.Id.Keyword_error => {
2665 stack.append(State {
2666 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2667 .error_token = token,
2668 .opt_ctx = opt_ctx
2669 }
2670 }) catch unreachable;
2671 continue;
2672 },
2673 Token.Id.Keyword_packed => {
2674 stack.append(State {
2675 .ContainerKind = ContainerKindCtx {
2676 .opt_ctx = opt_ctx,
2677 .ltoken = token,
2678 .layout = ast.Node.ContainerDecl.Layout.Packed,
2679 },
2680 }) catch unreachable;
2681 continue;
2682 },
2683 Token.Id.Keyword_extern => {
2684 stack.append(State {
2685 .ExternType = ExternTypeCtx {
2686 .opt_ctx = opt_ctx,
2687 .extern_token = token,
2688 .comments = null,
2689 },
2690 }) catch unreachable;
2691 continue;
2692 },
2693 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2694 self.putBackToken(token);
2695 stack.append(State {
2696 .ContainerKind = ContainerKindCtx {
2697 .opt_ctx = opt_ctx,
2698 .ltoken = token,
2699 .layout = ast.Node.ContainerDecl.Layout.Auto,
2700 },
2701 }) catch unreachable;
2702 continue;
2703 },
2704 Token.Id.Identifier => {
2705 stack.append(State {
2706 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2707 .label = token,
2708 .opt_ctx = opt_ctx
2709 }
2710 }) catch unreachable;
2711 continue;
2712 },
2713 Token.Id.Keyword_fn => {
2714 const fn_proto = try arena.construct(ast.Node.FnProto {
2715 .base = ast.Node {
2716 .id = ast.Node.Id.FnProto,
2717 .same_line_comment = null,
2718 },
2719 .doc_comments = null,
2720 .visib_token = null,
2721 .name_token = null,
2722 .fn_token = token,
2723 .params = ArrayList(&ast.Node).init(arena),
2724 .return_type = undefined,
2725 .var_args_token = null,
2726 .extern_export_inline_token = null,
2727 .cc_token = null,
2728 .async_attr = null,
2729 .body_node = null,
2730 .lib_name = null,
2731 .align_expr = null,
2732 });
2733 opt_ctx.store(&fn_proto.base);
2734 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2735 continue;
2736 },
2737 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2738 const fn_proto = try arena.construct(ast.Node.FnProto {
2739 .base = ast.Node {
2740 .id = ast.Node.Id.FnProto,
2741 .same_line_comment = null,
2742 },
2743 .doc_comments = null,
2744 .visib_token = null,
2745 .name_token = null,
2746 .fn_token = undefined,
2747 .params = ArrayList(&ast.Node).init(arena),
2748 .return_type = undefined,
2749 .var_args_token = null,
2750 .extern_export_inline_token = null,
2751 .cc_token = token,
2752 .async_attr = null,
2753 .body_node = null,
2754 .lib_name = null,
2755 .align_expr = null,
2756 });
2757 opt_ctx.store(&fn_proto.base);
2758 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2759 try stack.append(State {
2760 .ExpectTokenSave = ExpectTokenSave {
2761 .id = Token.Id.Keyword_fn,
2762 .ptr = &fn_proto.fn_token
2763 }
2764 });
2765 continue;
2766 },
2767 Token.Id.Keyword_asm => {
2768 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2769 ast.Node.Asm {
2770 .base = undefined,
2771 .asm_token = token,
2772 .volatile_token = null,
2773 .template = undefined,
2774 //.tokens = ArrayList(ast.Node.Asm.AsmToken).init(arena),
2775 .outputs = ArrayList(&ast.Node.AsmOutput).init(arena),
2776 .inputs = ArrayList(&ast.Node.AsmInput).init(arena),
2777 .cloppers = ArrayList(&ast.Node).init(arena),
2778 .rparen = undefined,
2779 }
2780 );
2781 stack.append(State {
2782 .ExpectTokenSave = ExpectTokenSave {
2783 .id = Token.Id.RParen,
2784 .ptr = &node.rparen,
2785 }
2786 }) catch unreachable;
2787 try stack.append(State { .AsmClopperItems = &node.cloppers });
2788 try stack.append(State { .IfToken = Token.Id.Colon });
2789 try stack.append(State { .AsmInputItems = &node.inputs });
2790 try stack.append(State { .IfToken = Token.Id.Colon });
2791 try stack.append(State { .AsmOutputItems = &node.outputs });
2792 try stack.append(State { .IfToken = Token.Id.Colon });
2793 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2794 try stack.append(State { .ExpectToken = Token.Id.LParen });
2795 try stack.append(State {
2796 .OptionalTokenSave = OptionalTokenSave {
2797 .id = Token.Id.Keyword_volatile,
2798 .ptr = &node.volatile_token,
2799 }
2800 });
2801 },
2802 Token.Id.Keyword_inline => {
2803 stack.append(State {
2804 .Inline = InlineCtx {
2805 .label = null,
2806 .inline_token = token,
2807 .opt_ctx = opt_ctx,
2808 }
2809 }) catch unreachable;
2810 continue;
2811 },
2812 else => {
2813 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2814 self.putBackToken(token);
2815 if (opt_ctx != OptionalCtx.Optional) {
2816 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2817 }
2818 }
2819 continue;
2820 }
2821 }
2822 },
2823
2824
2825 State.ErrorTypeOrSetDecl => |ctx| {
2826 if (self.eatToken(Token.Id.LBrace) == null) {
2827 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2828 continue;
2829 }
2830
2831 const node = try arena.construct(ast.Node.ErrorSetDecl {
2832 .base = ast.Node {
2833 .id = ast.Node.Id.ErrorSetDecl,
2834 .same_line_comment = null,
2835 },
2836 .error_token = ctx.error_token,
2837 .decls = ArrayList(&ast.Node).init(arena),
2838 .rbrace_token = undefined,
2839 });
2840 ctx.opt_ctx.store(&node.base);
2841
2842 stack.append(State {
2843 .ErrorTagListItemOrEnd = ListSave(&ast.Node) {
2844 .list = &node.decls,
2845 .ptr = &node.rbrace_token,
2846 }
2847 }) catch unreachable;
2848 continue;
2849 },
2850 State.StringLiteral => |opt_ctx| {
2851 const token = self.getNextToken();
2852 opt_ctx.store(
2853 (try self.parseStringLiteral(arena, token)) ?? {
2854 self.putBackToken(token);
2855 if (opt_ctx != OptionalCtx.Optional) {
2856 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2857 }
2858
2859 continue;
2860 }
2861 );
2862 },
2863
2864 State.Identifier => |opt_ctx| {
2865 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2866 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2867 continue;
2868 }
2869
2870 if (opt_ctx != OptionalCtx.Optional) {
2871 const token = self.getNextToken();
2872 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2873 }
2874 },
2875
2876 State.ErrorTag => |node_ptr| {
2877 const comments = try self.eatDocComments(arena);
2878 const ident_token = self.getNextToken();
2879 if (ident_token.id != Token.Id.Identifier) {
2880 return self.parseError(ident_token, "expected {}, found {}",
2881 @tagName(Token.Id.Identifier), @tagName(ident_token.id));
2882 }
2883
2884 const node = try arena.construct(ast.Node.ErrorTag {
2885 .base = ast.Node {
2886 .id = ast.Node.Id.ErrorTag,
2887 .same_line_comment = null,
2888 },
2889 .doc_comments = comments,
2890 .name_token = ident_token,
2891 });
2892 *node_ptr = &node.base;
2893 continue;
2894 },
2895
2896 State.ExpectToken => |token_id| {
2897 _ = try self.expectToken(token_id);
2898 continue;
2899 },
2900 State.ExpectTokenSave => |expect_token_save| {
2901 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2902 continue;
2903 },
2904 State.IfToken => |token_id| {
2905 if (self.eatToken(token_id)) |_| {
2906 continue;
2907 }
2908
2909 _ = stack.pop();
2910 continue;
2911 },
2912 State.IfTokenSave => |if_token_save| {
2913 if (self.eatToken(if_token_save.id)) |token| {
2914 *if_token_save.ptr = token;
2915 continue;
2916 }
2917
2918 _ = stack.pop();
2919 continue;
2920 },
2921 State.OptionalTokenSave => |optional_token_save| {
2922 if (self.eatToken(optional_token_save.id)) |token| {
2923 *optional_token_save.ptr = token;
2924 continue;
2925 }
2926
2927 continue;
2928 },
2929 }
2930 }
2931 }
2932
2933 fn eatDocComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.DocComment {
2934 var result: ?&ast.Node.DocComment = null;
2935 while (true) {
2936 if (self.eatToken(Token.Id.DocComment)) |line_comment| {
2937 const node = blk: {
2938 if (result) |comment_node| {
2939 break :blk comment_node;
2940 } else {
2941 const comment_node = try arena.construct(ast.Node.DocComment {
2942 .base = ast.Node {
2943 .id = ast.Node.Id.DocComment,
2944 .same_line_comment = null,
2945 },
2946 .lines = ArrayList(Token).init(arena),
2947 });
2948 result = comment_node;
2949 break :blk comment_node;
2950 }
2951 };
2952 try node.lines.append(line_comment);
2953 continue;
2954 }
2955 break;
2956 }
2957 return result;
2958 }
2959
2960 fn eatLineComment(self: &Parser, arena: &mem.Allocator) !?&ast.Node.LineComment {
2961 const token = self.eatToken(Token.Id.LineComment) ?? return null;
2962 return try arena.construct(ast.Node.LineComment {
2963 .base = ast.Node {
2964 .id = ast.Node.Id.LineComment,
2965 .same_line_comment = null,
2966 },
2967 .token = token,
2968 });
2969 }
2970
2971 fn requireSemiColon(node: &const ast.Node) bool {
2972 var n = node;
2973 while (true) {
2974 switch (n.id) {
2975 ast.Node.Id.Root,
2976 ast.Node.Id.StructField,
2977 ast.Node.Id.UnionTag,
2978 ast.Node.Id.EnumTag,
2979 ast.Node.Id.ParamDecl,
2980 ast.Node.Id.Block,
2981 ast.Node.Id.Payload,
2982 ast.Node.Id.PointerPayload,
2983 ast.Node.Id.PointerIndexPayload,
2984 ast.Node.Id.Switch,
2985 ast.Node.Id.SwitchCase,
2986 ast.Node.Id.SwitchElse,
2987 ast.Node.Id.FieldInitializer,
2988 ast.Node.Id.DocComment,
2989 ast.Node.Id.LineComment,
2990 ast.Node.Id.TestDecl => return false,
2991 ast.Node.Id.While => {
2992 const while_node = @fieldParentPtr(ast.Node.While, "base", n);
2993 if (while_node.@"else") |@"else"| {
2994 n = @"else".base;
2995 continue;
2996 }
2997
2998 return while_node.body.id != ast.Node.Id.Block;
2999 },
3000 ast.Node.Id.For => {
3001 const for_node = @fieldParentPtr(ast.Node.For, "base", n);
3002 if (for_node.@"else") |@"else"| {
3003 n = @"else".base;
3004 continue;
3005 }
3006
3007 return for_node.body.id != ast.Node.Id.Block;
3008 },
3009 ast.Node.Id.If => {
3010 const if_node = @fieldParentPtr(ast.Node.If, "base", n);
3011 if (if_node.@"else") |@"else"| {
3012 n = @"else".base;
3013 continue;
3014 }
3015
3016 return if_node.body.id != ast.Node.Id.Block;
3017 },
3018 ast.Node.Id.Else => {
3019 const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
3020 n = else_node.body;
3021 continue;
3022 },
3023 ast.Node.Id.Defer => {
3024 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
3025 return defer_node.expr.id != ast.Node.Id.Block;
3026 },
3027 ast.Node.Id.Comptime => {
3028 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
3029 return comptime_node.expr.id != ast.Node.Id.Block;
3030 },
3031 ast.Node.Id.Suspend => {
3032 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
3033 if (suspend_node.body) |body| {
3034 return body.id != ast.Node.Id.Block;
3035 }
3036
3037 return true;
3038 },
3039 else => return true,
3040 }
3041 }
3042 }
3043
3044 fn lookForSameLineComment(self: &Parser, arena: &mem.Allocator, node: &ast.Node) !void {
3045 const node_last_token = node.lastToken();
3046
3047 const line_comment_token = self.getNextToken();
3048 if (line_comment_token.id != Token.Id.DocComment and line_comment_token.id != Token.Id.LineComment) {
3049 self.putBackToken(line_comment_token);
3050 return;
3051 }
3052
3053 const offset_loc = self.tokenizer.getTokenLocation(node_last_token.end, line_comment_token);
3054 const different_line = offset_loc.line != 0;
3055 if (different_line) {
3056 self.putBackToken(line_comment_token);
3057 return;
3058 }
3059
3060 node.same_line_comment = try arena.construct(line_comment_token);
3061 }
3062
3063 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
3064 switch (token.id) {
3065 Token.Id.StringLiteral => {
3066 return &(try self.createLiteral(arena, ast.Node.StringLiteral, token)).base;
3067 },
3068 Token.Id.MultilineStringLiteralLine => {
3069 const node = try self.createNode(arena, ast.Node.MultilineStringLiteral,
3070 ast.Node.MultilineStringLiteral {
3071 .base = undefined,
3072 .tokens = ArrayList(Token).init(arena),
3073 }
3074 );
3075 try node.tokens.append(token);
3076 while (true) {
3077 const multiline_str = self.getNextToken();
3078 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
3079 self.putBackToken(multiline_str);
3080 break;
3081 }
3082
3083 try node.tokens.append(multiline_str);
3084 }
3085
3086 return &node.base;
3087 },
3088 // TODO: We shouldn't need a cast, but:
3089 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
3090 else => return (?&ast.Node)(null),
3091 }
3092 }
3093
3094 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
3095 switch (token.id) {
3096 Token.Id.Keyword_suspend => {
3097 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
3098 ast.Node.Suspend {
3099 .base = undefined,
3100 .label = null,
3101 .suspend_token = *token,
3102 .payload = null,
3103 .body = null,
3104 }
3105 );
3106
3107 stack.append(State { .SuspendBody = node }) catch unreachable;
3108 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3109 return true;
3110 },
3111 Token.Id.Keyword_if => {
3112 const node = try self.createToCtxNode(arena, ctx, ast.Node.If,
3113 ast.Node.If {
3114 .base = undefined,
3115 .if_token = *token,
3116 .condition = undefined,
3117 .payload = null,
3118 .body = undefined,
3119 .@"else" = null,
3120 }
3121 );
3122
3123 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3124 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3125 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3126 try stack.append(State { .LookForSameLineComment = &node.condition });
3127 try stack.append(State { .ExpectToken = Token.Id.RParen });
3128 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3129 try stack.append(State { .ExpectToken = Token.Id.LParen });
3130 return true;
3131 },
3132 Token.Id.Keyword_while => {
3133 stack.append(State {
3134 .While = LoopCtx {
3135 .label = null,
3136 .inline_token = null,
3137 .loop_token = *token,
3138 .opt_ctx = *ctx,
3139 }
3140 }) catch unreachable;
3141 return true;
3142 },
3143 Token.Id.Keyword_for => {
3144 stack.append(State {
3145 .For = LoopCtx {
3146 .label = null,
3147 .inline_token = null,
3148 .loop_token = *token,
3149 .opt_ctx = *ctx,
3150 }
3151 }) catch unreachable;
3152 return true;
3153 },
3154 Token.Id.Keyword_switch => {
3155 const node = try arena.construct(ast.Node.Switch {
3156 .base = ast.Node {
3157 .id = ast.Node.Id.Switch,
3158 .same_line_comment = null,
3159 },
3160 .switch_token = *token,
3161 .expr = undefined,
3162 .cases = ArrayList(&ast.Node).init(arena),
3163 .rbrace = undefined,
3164 });
3165 ctx.store(&node.base);
3166
3167 stack.append(State {
3168 .SwitchCaseOrEnd = ListSave(&ast.Node) {
3169 .list = &node.cases,
3170 .ptr = &node.rbrace,
3171 },
3172 }) catch unreachable;
3173 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3174 try stack.append(State { .ExpectToken = Token.Id.RParen });
3175 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3176 try stack.append(State { .ExpectToken = Token.Id.LParen });
3177 return true;
3178 },
3179 Token.Id.Keyword_comptime => {
3180 const node = try self.createToCtxNode(arena, ctx, ast.Node.Comptime,
3181 ast.Node.Comptime {
3182 .base = undefined,
3183 .comptime_token = *token,
3184 .expr = undefined,
3185 .doc_comments = null,
3186 }
3187 );
3188 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3189 return true;
3190 },
3191 Token.Id.LBrace => {
3192 const block = try self.createToCtxNode(arena, ctx, ast.Node.Block,
3193 ast.Node.Block {
3194 .base = undefined,
3195 .label = null,
3196 .lbrace = *token,
3197 .statements = ArrayList(&ast.Node).init(arena),
3198 .rbrace = undefined,
3199 }
3200 );
3201 stack.append(State { .Block = block }) catch unreachable;
3202 return true;
3203 },
3204 else => {
3205 return false;
3206 }
3207 }
3208 }
3209
3210 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
3211 var token = self.getNextToken();
3212 switch (token.id) {
3213 Token.Id.Comma => return null,
3214 else => {
3215 if (end == token.id) {
3216 return token;
3217 }
3218
3219 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
3220 },
3221 }
3222 }
3223
3224 fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3225 // TODO: We have to cast all cases because of this:
3226 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3227 return switch (*id) {
3228 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = void{} },
3229 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = void{} },
3230 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = void{} },
3231 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = void{} },
3232 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = void{} },
3233 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = void{} },
3234 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = void{} },
3235 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = void{} },
3236 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = void{} },
3237 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = void{} },
3238 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = void{} },
3239 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = void{} },
3240 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = void{} },
3241 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = void{} },
3242 else => null,
3243 };
3244 }
3245
3246 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3247 return switch (id) {
3248 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3249 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3250 else => null,
3251 };
3252 }
3253
3254 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3255 return switch (id) {
3256 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3257 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3258 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3259 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3260 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3261 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3262 else => null,
3263 };
3264 }
3265
3266 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3267 return switch (id) {
3268 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3269 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3270 else => null,
3271 };
3272 }
3273
3274 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3275 return switch (id) {
3276 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3277 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3278 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3279 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3280 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3281 else => null,
3282 };
3283 }
3284
3285 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3286 return switch (id) {
3287 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3288 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3289 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3290 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3291 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3292 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3293 else => null,
3294 };
3295 }
3296
3297 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3298 return switch (id) {
3299 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3300 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3301 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3302 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3303 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3304 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3305 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3306 .align_expr = null,
3307 .bit_offset_start_token = null,
3308 .bit_offset_end_token = null,
3309 .const_token = null,
3310 .volatile_token = null,
3311 },
3312 },
3313 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3314 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3315 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3316 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3317 else => null,
3318 };
3319 }
3320
3321 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3322 const node = try arena.create(T);
3323 *node = *init_to;
3324 node.base = blk: {
3325 const id = ast.Node.typeToId(T);
3326 break :blk ast.Node {
3327 .id = id,
3328 .same_line_comment = null,
3329 };
3330 };
3331
3332 return node;
3333 }
3334
3335 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
3336 const node = try self.createNode(arena, T, init_to);
3337 try list.append(&node.base);
3338
3339 return node;
3340 }
3341
3342 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3343 const node = try self.createNode(arena, T, init_to);
3344 opt_ctx.store(&node.base);
3345
3346 return node;
3347 }
3348
3349 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
3350 return self.createNode(arena, T,
3351 T {
3352 .base = undefined,
3353 .token = *token,
3354 }
3355 );
3356 }
3357
3358 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3359 const node = try self.createLiteral(arena, T, token);
3360 opt_ctx.store(&node.base);
3361
3362 return node;
3363 }
3364
3365 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3366 const loc = self.tokenizer.getTokenLocation(0, token);
3367 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3368 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3369 {
3370 var i: usize = 0;
3371 while (i < loc.column) : (i += 1) {
3372 warn(" ");
3373 }
3374 }
3375 {
3376 const caret_count = token.end - token.start;
3377 var i: usize = 0;
3378 while (i < caret_count) : (i += 1) {
3379 warn("~");
3380 }
3381 }
3382 warn("\n");
3383 return error.ParseError;
3384 }
3385
3386 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
3387 const token = self.getNextToken();
3388 if (token.id != id) {
3389 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3390 }
3391 return token;
3392 }
3393
3394 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3395 if (self.isPeekToken(id)) {
3396 return self.getNextToken();
3397 }
3398 return null;
3399 }
3400
3401 fn putBackToken(self: &Parser, token: &const Token) void {
3402 self.put_back_tokens[self.put_back_count] = *token;
3403 self.put_back_count += 1;
3404 }
3405
3406 fn getNextToken(self: &Parser) Token {
3407 if (self.put_back_count != 0) {
3408 const put_back_index = self.put_back_count - 1;
3409 const put_back_token = self.put_back_tokens[put_back_index];
3410 self.put_back_count = put_back_index;
3411 return put_back_token;
3412 } else {
3413 return self.tokenizer.next();
3414 }
3415 }
3416
3417 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3418 const token = self.getNextToken();
3419 defer self.putBackToken(token);
3420 return id == token.id;
3421 }
3422
3423 const RenderAstFrame = struct {
3424 node: &ast.Node,
3425 indent: usize,
3426 };
3427
3428 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3429 var stack = self.initUtilityArrayList(RenderAstFrame);
3430 defer self.deinitUtilityArrayList(stack);
3431
3432 try stack.append(RenderAstFrame {
3433 .node = &root_node.base,
3434 .indent = 0,
3435 });
3436
3437 while (stack.popOrNull()) |frame| {
3438 {
3439 var i: usize = 0;
3440 while (i < frame.indent) : (i += 1) {
3441 try stream.print(" ");
3442 }
3443 }
3444 try stream.print("{}\n", @tagName(frame.node.id));
3445 var child_i: usize = 0;
3446 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3447 try stack.append(RenderAstFrame {
3448 .node = child,
3449 .indent = frame.indent + 2,
3450 });
3451 }
3452 }
3453 }
3454
3455 const RenderState = union(enum) {
3456 TopLevelDecl: &ast.Node,
3457 ParamDecl: &ast.Node,
3458 Text: []const u8,
3459 Expression: &ast.Node,
3460 VarDecl: &ast.Node.VarDecl,
3461 Statement: &ast.Node,
3462 PrintIndent,
3463 Indent: usize,
3464 PrintSameLineComment: ?&Token,
3465 PrintLineComment: &Token,
3466 };
3467
3468 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3469 var stack = self.initUtilityArrayList(RenderState);
3470 defer self.deinitUtilityArrayList(stack);
3471
3472 {
3473 try stack.append(RenderState { .Text = "\n"});
3474
3475 var i = root_node.decls.len;
3476 while (i != 0) {
3477 i -= 1;
3478 const decl = root_node.decls.items[i];
3479 try stack.append(RenderState {.TopLevelDecl = decl});
3480 if (i != 0) {
3481 try stack.append(RenderState {
3482 .Text = blk: {
3483 const prev_node = root_node.decls.at(i - 1);
3484 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
3485 if (loc.line >= 2) {
3486 break :blk "\n\n";
3487 }
3488 break :blk "\n";
3489 },
3490 });
3491 }
3492 }
3493 }
3494
3495 const indent_delta = 4;
3496 var indent: usize = 0;
3497 while (stack.popOrNull()) |state| {
3498 switch (state) {
3499 RenderState.TopLevelDecl => |decl| {
3500 try stack.append(RenderState { .PrintSameLineComment = decl.same_line_comment } );
3501 switch (decl.id) {
3502 ast.Node.Id.FnProto => {
3503 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3504 try self.renderComments(stream, fn_proto, indent);
3505
3506 if (fn_proto.body_node) |body_node| {
3507 stack.append(RenderState { .Expression = body_node}) catch unreachable;
3508 try stack.append(RenderState { .Text = " "});
3509 } else {
3510 stack.append(RenderState { .Text = ";" }) catch unreachable;
3511 }
3512
3513 try stack.append(RenderState { .Expression = decl });
3514 },
3515 ast.Node.Id.Use => {
3516 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
3517 if (use_decl.visib_token) |visib_token| {
3518 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3519 }
3520 try stream.print("use ");
3521 try stack.append(RenderState { .Text = ";" });
3522 try stack.append(RenderState { .Expression = use_decl.expr });
3523 },
3524 ast.Node.Id.VarDecl => {
3525 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
3526 try self.renderComments(stream, var_decl, indent);
3527 try stack.append(RenderState { .VarDecl = var_decl});
3528 },
3529 ast.Node.Id.TestDecl => {
3530 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3531 try self.renderComments(stream, test_decl, indent);
3532 try stream.print("test ");
3533 try stack.append(RenderState { .Expression = test_decl.body_node });
3534 try stack.append(RenderState { .Text = " " });
3535 try stack.append(RenderState { .Expression = test_decl.name });
3536 },
3537 ast.Node.Id.StructField => {
3538 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
3539 try self.renderComments(stream, field, indent);
3540 if (field.visib_token) |visib_token| {
3541 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3542 }
3543 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3544 try stack.append(RenderState { .Text = "," });
3545 try stack.append(RenderState { .Expression = field.type_expr});
3546 },
3547 ast.Node.Id.UnionTag => {
3548 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
3549 try self.renderComments(stream, tag, indent);
3550 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3551
3552 try stack.append(RenderState { .Text = "," });
3553
3554 if (tag.value_expr) |value_expr| {
3555 try stack.append(RenderState { .Expression = value_expr });
3556 try stack.append(RenderState { .Text = " = " });
3557 }
3558
3559 if (tag.type_expr) |type_expr| {
3560 try stream.print(": ");
3561 try stack.append(RenderState { .Expression = type_expr});
3562 }
3563 },
3564 ast.Node.Id.EnumTag => {
3565 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
3566 try self.renderComments(stream, tag, indent);
3567 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3568
3569 try stack.append(RenderState { .Text = "," });
3570 if (tag.value) |value| {
3571 try stream.print(" = ");
3572 try stack.append(RenderState { .Expression = value});
3573 }
3574 },
3575 ast.Node.Id.ErrorTag => {
3576 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
3577 try self.renderComments(stream, tag, indent);
3578 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3579 },
3580 ast.Node.Id.Comptime => {
3581 if (requireSemiColon(decl)) {
3582 try stack.append(RenderState { .Text = ";" });
3583 }
3584 try stack.append(RenderState { .Expression = decl });
3585 },
3586 ast.Node.Id.LineComment => {
3587 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
3588 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
3589 },
3590 else => unreachable,
3591 }
3592 },
3593
3594 RenderState.VarDecl => |var_decl| {
3595 try stack.append(RenderState { .Text = ";" });
3596 if (var_decl.init_node) |init_node| {
3597 try stack.append(RenderState { .Expression = init_node });
3598 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
3599 try stack.append(RenderState { .Text = text });
3600 }
3601 if (var_decl.align_node) |align_node| {
3602 try stack.append(RenderState { .Text = ")" });
3603 try stack.append(RenderState { .Expression = align_node });
3604 try stack.append(RenderState { .Text = " align(" });
3605 }
3606 if (var_decl.type_node) |type_node| {
3607 try stack.append(RenderState { .Expression = type_node });
3608 try stack.append(RenderState { .Text = ": " });
3609 }
3610 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3611 try stack.append(RenderState { .Text = " " });
3612 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3613
3614 if (var_decl.comptime_token) |comptime_token| {
3615 try stack.append(RenderState { .Text = " " });
3616 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3617 }
3618
3619 if (var_decl.extern_export_token) |extern_export_token| {
3620 if (var_decl.lib_name != null) {
3621 try stack.append(RenderState { .Text = " " });
3622 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3623 }
3624 try stack.append(RenderState { .Text = " " });
3625 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
3626 }
3627
3628 if (var_decl.visib_token) |visib_token| {
3629 try stack.append(RenderState { .Text = " " });
3630 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3631 }
3632 },
3633
3634 RenderState.ParamDecl => |base| {
3635 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
3636 if (param_decl.comptime_token) |comptime_token| {
3637 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
3638 }
3639 if (param_decl.noalias_token) |noalias_token| {
3640 try stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token));
3641 }
3642 if (param_decl.name_token) |name_token| {
3643 try stream.print("{}: ", self.tokenizer.getTokenSlice(name_token));
3644 }
3645 if (param_decl.var_args_token) |var_args_token| {
3646 try stream.print("{}", self.tokenizer.getTokenSlice(var_args_token));
3647 } else {
3648 try stack.append(RenderState { .Expression = param_decl.type_node});
3649 }
3650 },
3651 RenderState.Text => |bytes| {
3652 try stream.write(bytes);
3653 },
3654 RenderState.Expression => |base| switch (base.id) {
3655 ast.Node.Id.Identifier => {
3656 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
3657 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
3658 },
3659 ast.Node.Id.Block => {
3660 const block = @fieldParentPtr(ast.Node.Block, "base", base);
3661 if (block.label) |label| {
3662 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3663 }
3664
3665 if (block.statements.len == 0) {
3666 try stream.write("{}");
3667 } else {
3668 try stream.write("{");
3669 try stack.append(RenderState { .Text = "}"});
3670 try stack.append(RenderState.PrintIndent);
3671 try stack.append(RenderState { .Indent = indent});
3672 try stack.append(RenderState { .Text = "\n"});
3673 var i = block.statements.len;
3674 while (i != 0) {
3675 i -= 1;
3676 const statement_node = block.statements.items[i];
3677 try stack.append(RenderState { .Statement = statement_node});
3678 try stack.append(RenderState.PrintIndent);
3679 try stack.append(RenderState { .Indent = indent + indent_delta});
3680 try stack.append(RenderState {
3681 .Text = blk: {
3682 if (i != 0) {
3683 const prev_node = block.statements.items[i - 1];
3684 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
3685 if (loc.line >= 2) {
3686 break :blk "\n\n";
3687 }
3688 }
3689 break :blk "\n";
3690 },
3691 });
3692 }
3693 }
3694 },
3695 ast.Node.Id.Defer => {
3696 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
3697 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3698 try stack.append(RenderState { .Expression = defer_node.expr });
3699 },
3700 ast.Node.Id.Comptime => {
3701 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
3702 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3703 try stack.append(RenderState { .Expression = comptime_node.expr });
3704 },
3705 ast.Node.Id.AsyncAttribute => {
3706 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
3707 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3708
3709 if (async_attr.allocator_type) |allocator_type| {
3710 try stack.append(RenderState { .Text = ">" });
3711 try stack.append(RenderState { .Expression = allocator_type });
3712 try stack.append(RenderState { .Text = "<" });
3713 }
3714 },
3715 ast.Node.Id.Suspend => {
3716 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
3717 if (suspend_node.label) |label| {
3718 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3719 }
3720 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3721
3722 if (suspend_node.body) |body| {
3723 try stack.append(RenderState { .Expression = body });
3724 try stack.append(RenderState { .Text = " " });
3725 }
3726
3727 if (suspend_node.payload) |payload| {
3728 try stack.append(RenderState { .Expression = payload });
3729 try stack.append(RenderState { .Text = " " });
3730 }
3731 },
3732 ast.Node.Id.InfixOp => {
3733 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
3734 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3735
3736 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
3737 if (prefix_op_node.op.Catch) |payload| {
3738 try stack.append(RenderState { .Text = " " });
3739 try stack.append(RenderState { .Expression = payload });
3740 }
3741 try stack.append(RenderState { .Text = " catch " });
3742 } else {
3743 const text = switch (prefix_op_node.op) {
3744 ast.Node.InfixOp.Op.Add => " + ",
3745 ast.Node.InfixOp.Op.AddWrap => " +% ",
3746 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
3747 ast.Node.InfixOp.Op.ArrayMult => " ** ",
3748 ast.Node.InfixOp.Op.Assign => " = ",
3749 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
3750 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
3751 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
3752 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
3753 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
3754 ast.Node.InfixOp.Op.AssignDiv => " /= ",
3755 ast.Node.InfixOp.Op.AssignMinus => " -= ",
3756 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
3757 ast.Node.InfixOp.Op.AssignMod => " %= ",
3758 ast.Node.InfixOp.Op.AssignPlus => " += ",
3759 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
3760 ast.Node.InfixOp.Op.AssignTimes => " *= ",
3761 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
3762 ast.Node.InfixOp.Op.BangEqual => " != ",
3763 ast.Node.InfixOp.Op.BitAnd => " & ",
3764 ast.Node.InfixOp.Op.BitOr => " | ",
3765 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
3766 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
3767 ast.Node.InfixOp.Op.BitXor => " ^ ",
3768 ast.Node.InfixOp.Op.BoolAnd => " and ",
3769 ast.Node.InfixOp.Op.BoolOr => " or ",
3770 ast.Node.InfixOp.Op.Div => " / ",
3771 ast.Node.InfixOp.Op.EqualEqual => " == ",
3772 ast.Node.InfixOp.Op.ErrorUnion => "!",
3773 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
3774 ast.Node.InfixOp.Op.GreaterThan => " > ",
3775 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
3776 ast.Node.InfixOp.Op.LessThan => " < ",
3777 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
3778 ast.Node.InfixOp.Op.Mod => " % ",
3779 ast.Node.InfixOp.Op.Mult => " * ",
3780 ast.Node.InfixOp.Op.MultWrap => " *% ",
3781 ast.Node.InfixOp.Op.Period => ".",
3782 ast.Node.InfixOp.Op.Sub => " - ",
3783 ast.Node.InfixOp.Op.SubWrap => " -% ",
3784 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
3785 ast.Node.InfixOp.Op.Range => " ... ",
3786 ast.Node.InfixOp.Op.Catch => unreachable,
3787 };
3788
3789 try stack.append(RenderState { .Text = text });
3790 }
3791 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
3792 },
3793 ast.Node.Id.PrefixOp => {
3794 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
3795 if (prefix_op_node.op != ast.Node.PrefixOp.Op.Deref) {
3796 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3797 }
3798 switch (prefix_op_node.op) {
3799 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
3800 try stream.write("&");
3801 if (addr_of_info.volatile_token != null) {
3802 try stack.append(RenderState { .Text = "volatile "});
3803 }
3804 if (addr_of_info.const_token != null) {
3805 try stack.append(RenderState { .Text = "const "});
3806 }
3807 if (addr_of_info.align_expr) |align_expr| {
3808 try stream.print("align(");
3809 try stack.append(RenderState { .Text = ") "});
3810 try stack.append(RenderState { .Expression = align_expr});
3811 }
3812 },
3813 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
3814 try stream.write("[]");
3815 if (addr_of_info.volatile_token != null) {
3816 try stack.append(RenderState { .Text = "volatile "});
3817 }
3818 if (addr_of_info.const_token != null) {
3819 try stack.append(RenderState { .Text = "const "});
3820 }
3821 if (addr_of_info.align_expr) |align_expr| {
3822 try stream.print("align(");
3823 try stack.append(RenderState { .Text = ") "});
3824 try stack.append(RenderState { .Expression = align_expr});
3825 }
3826 },
3827 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
3828 try stack.append(RenderState { .Text = "]"});
3829 try stack.append(RenderState { .Expression = array_index});
3830 try stack.append(RenderState { .Text = "["});
3831 },
3832 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
3833 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
3834 ast.Node.PrefixOp.Op.Deref => {
3835 try stack.append(RenderState { .Text = ".*" });
3836 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3837 },
3838 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
3839 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
3840 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
3841 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
3842 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
3843 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
3844 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
3845 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
3846 }
3847 },
3848 ast.Node.Id.SuffixOp => {
3849 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
3850
3851 switch (suffix_op.op) {
3852 ast.Node.SuffixOp.Op.Call => |call_info| {
3853 try stack.append(RenderState { .Text = ")"});
3854 var i = call_info.params.len;
3855 while (i != 0) {
3856 i -= 1;
3857 const param_node = call_info.params.at(i);
3858 try stack.append(RenderState { .Expression = param_node});
3859 if (i != 0) {
3860 try stack.append(RenderState { .Text = ", " });
3861 }
3862 }
3863 try stack.append(RenderState { .Text = "("});
3864 try stack.append(RenderState { .Expression = suffix_op.lhs });
3865
3866 if (call_info.async_attr) |async_attr| {
3867 try stack.append(RenderState { .Text = " "});
3868 try stack.append(RenderState { .Expression = &async_attr.base });
3869 }
3870 },
3871 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
3872 try stack.append(RenderState { .Text = "]"});
3873 try stack.append(RenderState { .Expression = index_expr});
3874 try stack.append(RenderState { .Text = "["});
3875 try stack.append(RenderState { .Expression = suffix_op.lhs });
3876 },
3877 ast.Node.SuffixOp.Op.Slice => |range| {
3878 try stack.append(RenderState { .Text = "]"});
3879 if (range.end) |end| {
3880 try stack.append(RenderState { .Expression = end});
3881 }
3882 try stack.append(RenderState { .Text = ".."});
3883 try stack.append(RenderState { .Expression = range.start});
3884 try stack.append(RenderState { .Text = "["});
3885 try stack.append(RenderState { .Expression = suffix_op.lhs });
3886 },
3887 ast.Node.SuffixOp.Op.StructInitializer => |field_inits| {
3888 if (field_inits.len == 0) {
3889 try stack.append(RenderState { .Text = "{}" });
3890 try stack.append(RenderState { .Expression = suffix_op.lhs });
3891 continue;
3892 }
3893 if (field_inits.len == 1) {
3894 const field_init = field_inits.at(0);
3895
3896 try stack.append(RenderState { .Text = " }" });
3897 try stack.append(RenderState { .Expression = field_init });
3898 try stack.append(RenderState { .Text = "{ " });
3899 try stack.append(RenderState { .Expression = suffix_op.lhs });
3900 continue;
3901 }
3902 try stack.append(RenderState { .Text = "}"});
3903 try stack.append(RenderState.PrintIndent);
3904 try stack.append(RenderState { .Indent = indent });
3905 try stack.append(RenderState { .Text = "\n" });
3906 var i = field_inits.len;
3907 while (i != 0) {
3908 i -= 1;
3909 const field_init = field_inits.at(i);
3910 if (field_init.id != ast.Node.Id.LineComment) {
3911 try stack.append(RenderState { .Text = "," });
3912 }
3913 try stack.append(RenderState { .Expression = field_init });
3914 try stack.append(RenderState.PrintIndent);
3915 if (i != 0) {
3916 try stack.append(RenderState { .Text = blk: {
3917 const prev_node = field_inits.at(i - 1);
3918 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, field_init.firstToken());
3919 if (loc.line >= 2) {
3920 break :blk "\n\n";
3921 }
3922 break :blk "\n";
3923 }});
3924 }
3925 }
3926 try stack.append(RenderState { .Indent = indent + indent_delta });
3927 try stack.append(RenderState { .Text = "{\n"});
3928 try stack.append(RenderState { .Expression = suffix_op.lhs });
3929 },
3930 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
3931 if (exprs.len == 0) {
3932 try stack.append(RenderState { .Text = "{}" });
3933 try stack.append(RenderState { .Expression = suffix_op.lhs });
3934 continue;
3935 }
3936 if (exprs.len == 1) {
3937 const expr = exprs.at(0);
3938
3939 try stack.append(RenderState { .Text = "}" });
3940 try stack.append(RenderState { .Expression = expr });
3941 try stack.append(RenderState { .Text = "{" });
3942 try stack.append(RenderState { .Expression = suffix_op.lhs });
3943 continue;
3944 }
3945
3946 try stack.append(RenderState { .Text = "}"});
3947 try stack.append(RenderState.PrintIndent);
3948 try stack.append(RenderState { .Indent = indent });
3949 var i = exprs.len;
3950 while (i != 0) {
3951 i -= 1;
3952 const expr = exprs.at(i);
3953 try stack.append(RenderState { .Text = ",\n" });
3954 try stack.append(RenderState { .Expression = expr });
3955 try stack.append(RenderState.PrintIndent);
3956 }
3957 try stack.append(RenderState { .Indent = indent + indent_delta });
3958 try stack.append(RenderState { .Text = "{\n"});
3959 try stack.append(RenderState { .Expression = suffix_op.lhs });
3960 },
3961 }
3962 },
3963 ast.Node.Id.ControlFlowExpression => {
3964 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
3965
3966 if (flow_expr.rhs) |rhs| {
3967 try stack.append(RenderState { .Expression = rhs });
3968 try stack.append(RenderState { .Text = " " });
3969 }
3970
3971 switch (flow_expr.kind) {
3972 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
3973 try stream.print("break");
3974 if (maybe_label) |label| {
3975 try stream.print(" :");
3976 try stack.append(RenderState { .Expression = label });
3977 }
3978 },
3979 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
3980 try stream.print("continue");
3981 if (maybe_label) |label| {
3982 try stream.print(" :");
3983 try stack.append(RenderState { .Expression = label });
3984 }
3985 },
3986 ast.Node.ControlFlowExpression.Kind.Return => {
3987 try stream.print("return");
3988 },
3989
3990 }
3991 },
3992 ast.Node.Id.Payload => {
3993 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
3994 try stack.append(RenderState { .Text = "|"});
3995 try stack.append(RenderState { .Expression = payload.error_symbol });
3996 try stack.append(RenderState { .Text = "|"});
3997 },
3998 ast.Node.Id.PointerPayload => {
3999 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
4000 try stack.append(RenderState { .Text = "|"});
4001 try stack.append(RenderState { .Expression = payload.value_symbol });
4002
4003 if (payload.ptr_token) |ptr_token| {
4004 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
4005 }
4006
4007 try stack.append(RenderState { .Text = "|"});
4008 },
4009 ast.Node.Id.PointerIndexPayload => {
4010 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
4011 try stack.append(RenderState { .Text = "|"});
4012
4013 if (payload.index_symbol) |index_symbol| {
4014 try stack.append(RenderState { .Expression = index_symbol });
4015 try stack.append(RenderState { .Text = ", "});
4016 }
4017
4018 try stack.append(RenderState { .Expression = payload.value_symbol });
4019
4020 if (payload.ptr_token) |ptr_token| {
4021 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
4022 }
4023
4024 try stack.append(RenderState { .Text = "|"});
4025 },
4026 ast.Node.Id.GroupedExpression => {
4027 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
4028 try stack.append(RenderState { .Text = ")"});
4029 try stack.append(RenderState { .Expression = grouped_expr.expr });
4030 try stack.append(RenderState { .Text = "("});
4031 },
4032 ast.Node.Id.FieldInitializer => {
4033 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
4034 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
4035 try stack.append(RenderState { .Expression = field_init.expr });
4036 },
4037 ast.Node.Id.IntegerLiteral => {
4038 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
4039 try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
4040 },
4041 ast.Node.Id.FloatLiteral => {
4042 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
4043 try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
4044 },
4045 ast.Node.Id.StringLiteral => {
4046 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
4047 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
4048 },
4049 ast.Node.Id.CharLiteral => {
4050 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4051 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
4052 },
4053 ast.Node.Id.BoolLiteral => {
4054 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4055 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
4056 },
4057 ast.Node.Id.NullLiteral => {
4058 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
4059 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
4060 },
4061 ast.Node.Id.ThisLiteral => {
4062 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
4063 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
4064 },
4065 ast.Node.Id.Unreachable => {
4066 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
4067 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
4068 },
4069 ast.Node.Id.ErrorType => {
4070 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
4071 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
4072 },
4073 ast.Node.Id.VarType => {
4074 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
4075 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
4076 },
4077 ast.Node.Id.ContainerDecl => {
4078 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
4079
4080 switch (container_decl.layout) {
4081 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
4082 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
4083 ast.Node.ContainerDecl.Layout.Auto => { },
4084 }
4085
4086 switch (container_decl.kind) {
4087 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
4088 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
4089 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
4090 }
4091
4092 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
4093 if (fields_and_decls.len == 0) {
4094 try stack.append(RenderState { .Text = "{}"});
4095 } else {
4096 try stack.append(RenderState { .Text = "}"});
4097 try stack.append(RenderState.PrintIndent);
4098 try stack.append(RenderState { .Indent = indent });
4099 try stack.append(RenderState { .Text = "\n"});
4100
4101 var i = fields_and_decls.len;
4102 while (i != 0) {
4103 i -= 1;
4104 const node = fields_and_decls[i];
4105 try stack.append(RenderState { .TopLevelDecl = node});
4106 try stack.append(RenderState.PrintIndent);
4107 try stack.append(RenderState {
4108 .Text = blk: {
4109 if (i != 0) {
4110 const prev_node = fields_and_decls[i - 1];
4111 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4112 if (loc.line >= 2) {
4113 break :blk "\n\n";
4114 }
4115 }
4116 break :blk "\n";
4117 },
4118 });
4119 }
4120 try stack.append(RenderState { .Indent = indent + indent_delta});
4121 try stack.append(RenderState { .Text = "{"});
4122 }
4123
4124 switch (container_decl.init_arg_expr) {
4125 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
4126 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
4127 if (enum_tag_type) |expr| {
4128 try stack.append(RenderState { .Text = ")) "});
4129 try stack.append(RenderState { .Expression = expr});
4130 try stack.append(RenderState { .Text = "(enum("});
4131 } else {
4132 try stack.append(RenderState { .Text = "(enum) "});
4133 }
4134 },
4135 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
4136 try stack.append(RenderState { .Text = ") "});
4137 try stack.append(RenderState { .Expression = type_expr});
4138 try stack.append(RenderState { .Text = "("});
4139 },
4140 }
4141 },
4142 ast.Node.Id.ErrorSetDecl => {
4143 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
4144
4145 const decls = err_set_decl.decls.toSliceConst();
4146 if (decls.len == 0) {
4147 try stream.write("error{}");
4148 continue;
4149 }
4150
4151 if (decls.len == 1) blk: {
4152 const node = decls[0];
4153
4154 // if there are any doc comments or same line comments
4155 // don't try to put it all on one line
4156 if (node.same_line_comment != null) break :blk;
4157 if (node.cast(ast.Node.ErrorTag)) |tag| {
4158 if (tag.doc_comments != null) break :blk;
4159 } else {
4160 break :blk;
4161 }
4162
4163
4164 try stream.write("error{");
4165 try stack.append(RenderState { .Text = "}" });
4166 try stack.append(RenderState { .TopLevelDecl = node });
4167 continue;
4168 }
4169
4170 try stream.write("error{");
4171
4172 try stack.append(RenderState { .Text = "}"});
4173 try stack.append(RenderState.PrintIndent);
4174 try stack.append(RenderState { .Indent = indent });
4175 try stack.append(RenderState { .Text = "\n"});
4176
4177 var i = decls.len;
4178 while (i != 0) {
4179 i -= 1;
4180 const node = decls[i];
4181 if (node.id != ast.Node.Id.LineComment) {
4182 try stack.append(RenderState { .Text = "," });
4183 }
4184 try stack.append(RenderState { .TopLevelDecl = node });
4185 try stack.append(RenderState.PrintIndent);
4186 try stack.append(RenderState {
4187 .Text = blk: {
4188 if (i != 0) {
4189 const prev_node = decls[i - 1];
4190 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4191 if (loc.line >= 2) {
4192 break :blk "\n\n";
4193 }
4194 }
4195 break :blk "\n";
4196 },
4197 });
4198 }
4199 try stack.append(RenderState { .Indent = indent + indent_delta});
4200 },
4201 ast.Node.Id.MultilineStringLiteral => {
4202 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
4203 try stream.print("\n");
4204
4205 var i : usize = 0;
4206 while (i < multiline_str_literal.tokens.len) : (i += 1) {
4207 const t = multiline_str_literal.tokens.at(i);
4208 try stream.writeByteNTimes(' ', indent + indent_delta);
4209 try stream.print("{}", self.tokenizer.getTokenSlice(t));
4210 }
4211 try stream.writeByteNTimes(' ', indent);
4212 },
4213 ast.Node.Id.UndefinedLiteral => {
4214 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
4215 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
4216 },
4217 ast.Node.Id.BuiltinCall => {
4218 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
4219 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
4220 try stack.append(RenderState { .Text = ")"});
4221 var i = builtin_call.params.len;
4222 while (i != 0) {
4223 i -= 1;
4224 const param_node = builtin_call.params.at(i);
4225 try stack.append(RenderState { .Expression = param_node});
4226 if (i != 0) {
4227 try stack.append(RenderState { .Text = ", " });
4228 }
4229 }
4230 },
4231 ast.Node.Id.FnProto => {
4232 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
4233
4234 switch (fn_proto.return_type) {
4235 ast.Node.FnProto.ReturnType.Explicit => |node| {
4236 try stack.append(RenderState { .Expression = node});
4237 },
4238 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
4239 try stack.append(RenderState { .Expression = node});
4240 try stack.append(RenderState { .Text = "!"});
4241 },
4242 }
4243
4244 if (fn_proto.align_expr) |align_expr| {
4245 try stack.append(RenderState { .Text = ") " });
4246 try stack.append(RenderState { .Expression = align_expr});
4247 try stack.append(RenderState { .Text = "align(" });
4248 }
4249
4250 try stack.append(RenderState { .Text = ") " });
4251 var i = fn_proto.params.len;
4252 while (i != 0) {
4253 i -= 1;
4254 const param_decl_node = fn_proto.params.items[i];
4255 try stack.append(RenderState { .ParamDecl = param_decl_node});
4256 if (i != 0) {
4257 try stack.append(RenderState { .Text = ", " });
4258 }
4259 }
4260
4261 try stack.append(RenderState { .Text = "(" });
4262 if (fn_proto.name_token) |name_token| {
4263 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
4264 try stack.append(RenderState { .Text = " " });
4265 }
4266
4267 try stack.append(RenderState { .Text = "fn" });
4268
4269 if (fn_proto.async_attr) |async_attr| {
4270 try stack.append(RenderState { .Text = " " });
4271 try stack.append(RenderState { .Expression = &async_attr.base });
4272 }
4273
4274 if (fn_proto.cc_token) |cc_token| {
4275 try stack.append(RenderState { .Text = " " });
4276 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
4277 }
4278
4279 if (fn_proto.lib_name) |lib_name| {
4280 try stack.append(RenderState { .Text = " " });
4281 try stack.append(RenderState { .Expression = lib_name });
4282 }
4283 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
4284 try stack.append(RenderState { .Text = " " });
4285 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
4286 }
4287
4288 if (fn_proto.visib_token) |visib_token| {
4289 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
4290 try stack.append(RenderState { .Text = " " });
4291 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
4292 }
4293 },
4294 ast.Node.Id.PromiseType => {
4295 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
4296 try stream.write(self.tokenizer.getTokenSlice(promise_type.promise_token));
4297 if (promise_type.result) |result| {
4298 try stream.write(self.tokenizer.getTokenSlice(result.arrow_token));
4299 try stack.append(RenderState { .Expression = result.return_type});
4300 }
4301 },
4302 ast.Node.Id.LineComment => {
4303 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
4304 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
4305 },
4306 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
4307 ast.Node.Id.Switch => {
4308 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
4309 const cases = switch_node.cases.toSliceConst();
4310
4311 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
4312
4313 if (cases.len == 0) {
4314 try stack.append(RenderState { .Text = ") {}"});
4315 try stack.append(RenderState { .Expression = switch_node.expr });
4316 continue;
4317 }
4318
4319 try stack.append(RenderState { .Text = "}"});
4320 try stack.append(RenderState.PrintIndent);
4321 try stack.append(RenderState { .Indent = indent });
4322 try stack.append(RenderState { .Text = "\n"});
4323
4324 var i = cases.len;
4325 while (i != 0) {
4326 i -= 1;
4327 const node = cases[i];
4328 try stack.append(RenderState { .Expression = node});
4329 try stack.append(RenderState.PrintIndent);
4330 try stack.append(RenderState {
4331 .Text = blk: {
4332 if (i != 0) {
4333 const prev_node = cases[i - 1];
4334 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4335 if (loc.line >= 2) {
4336 break :blk "\n\n";
4337 }
4338 }
4339 break :blk "\n";
4340 },
4341 });
4342 }
4343 try stack.append(RenderState { .Indent = indent + indent_delta});
4344 try stack.append(RenderState { .Text = ") {"});
4345 try stack.append(RenderState { .Expression = switch_node.expr });
4346 },
4347 ast.Node.Id.SwitchCase => {
4348 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
4349
4350 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment });
4351 try stack.append(RenderState { .Text = "," });
4352 try stack.append(RenderState { .Expression = switch_case.expr });
4353 if (switch_case.payload) |payload| {
4354 try stack.append(RenderState { .Text = " " });
4355 try stack.append(RenderState { .Expression = payload });
4356 }
4357 try stack.append(RenderState { .Text = " => "});
4358
4359 const items = switch_case.items.toSliceConst();
4360 var i = items.len;
4361 while (i != 0) {
4362 i -= 1;
4363 try stack.append(RenderState { .Expression = items[i] });
4364
4365 if (i != 0) {
4366 try stack.append(RenderState.PrintIndent);
4367 try stack.append(RenderState { .Text = ",\n" });
4368 }
4369 }
4370 },
4371 ast.Node.Id.SwitchElse => {
4372 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
4373 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
4374 },
4375 ast.Node.Id.Else => {
4376 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
4377 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
4378
4379 switch (else_node.body.id) {
4380 ast.Node.Id.Block, ast.Node.Id.If,
4381 ast.Node.Id.For, ast.Node.Id.While,
4382 ast.Node.Id.Switch => {
4383 try stream.print(" ");
4384 try stack.append(RenderState { .Expression = else_node.body });
4385 },
4386 else => {
4387 try stack.append(RenderState { .Indent = indent });
4388 try stack.append(RenderState { .Expression = else_node.body });
4389 try stack.append(RenderState.PrintIndent);
4390 try stack.append(RenderState { .Indent = indent + indent_delta });
4391 try stack.append(RenderState { .Text = "\n" });
4392 }
4393 }
4394
4395 if (else_node.payload) |payload| {
4396 try stack.append(RenderState { .Text = " " });
4397 try stack.append(RenderState { .Expression = payload });
4398 }
4399 },
4400 ast.Node.Id.While => {
4401 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
4402 if (while_node.label) |label| {
4403 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4404 }
4405
4406 if (while_node.inline_token) |inline_token| {
4407 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4408 }
4409
4410 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
4411
4412 if (while_node.@"else") |@"else"| {
4413 try stack.append(RenderState { .Expression = &@"else".base });
4414
4415 if (while_node.body.id == ast.Node.Id.Block) {
4416 try stack.append(RenderState { .Text = " " });
4417 } else {
4418 try stack.append(RenderState.PrintIndent);
4419 try stack.append(RenderState { .Text = "\n" });
4420 }
4421 }
4422
4423 if (while_node.body.id == ast.Node.Id.Block) {
4424 try stack.append(RenderState { .Expression = while_node.body });
4425 try stack.append(RenderState { .Text = " " });
4426 } else {
4427 try stack.append(RenderState { .Indent = indent });
4428 try stack.append(RenderState { .Expression = while_node.body });
4429 try stack.append(RenderState.PrintIndent);
4430 try stack.append(RenderState { .Indent = indent + indent_delta });
4431 try stack.append(RenderState { .Text = "\n" });
4432 }
4433
4434 if (while_node.continue_expr) |continue_expr| {
4435 try stack.append(RenderState { .Text = ")" });
4436 try stack.append(RenderState { .Expression = continue_expr });
4437 try stack.append(RenderState { .Text = ": (" });
4438 try stack.append(RenderState { .Text = " " });
4439 }
4440
4441 if (while_node.payload) |payload| {
4442 try stack.append(RenderState { .Expression = payload });
4443 try stack.append(RenderState { .Text = " " });
4444 }
4445
4446 try stack.append(RenderState { .Text = ")" });
4447 try stack.append(RenderState { .Expression = while_node.condition });
4448 try stack.append(RenderState { .Text = "(" });
4449 },
4450 ast.Node.Id.For => {
4451 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
4452 if (for_node.label) |label| {
4453 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4454 }
4455
4456 if (for_node.inline_token) |inline_token| {
4457 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4458 }
4459
4460 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
4461
4462 if (for_node.@"else") |@"else"| {
4463 try stack.append(RenderState { .Expression = &@"else".base });
4464
4465 if (for_node.body.id == ast.Node.Id.Block) {
4466 try stack.append(RenderState { .Text = " " });
4467 } else {
4468 try stack.append(RenderState.PrintIndent);
4469 try stack.append(RenderState { .Text = "\n" });
4470 }
4471 }
4472
4473 if (for_node.body.id == ast.Node.Id.Block) {
4474 try stack.append(RenderState { .Expression = for_node.body });
4475 try stack.append(RenderState { .Text = " " });
4476 } else {
4477 try stack.append(RenderState { .Indent = indent });
4478 try stack.append(RenderState { .Expression = for_node.body });
4479 try stack.append(RenderState.PrintIndent);
4480 try stack.append(RenderState { .Indent = indent + indent_delta });
4481 try stack.append(RenderState { .Text = "\n" });
4482 }
4483
4484 if (for_node.payload) |payload| {
4485 try stack.append(RenderState { .Expression = payload });
4486 try stack.append(RenderState { .Text = " " });
4487 }
4488
4489 try stack.append(RenderState { .Text = ")" });
4490 try stack.append(RenderState { .Expression = for_node.array_expr });
4491 try stack.append(RenderState { .Text = "(" });
4492 },
4493 ast.Node.Id.If => {
4494 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
4495 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
4496
4497 switch (if_node.body.id) {
4498 ast.Node.Id.Block, ast.Node.Id.If,
4499 ast.Node.Id.For, ast.Node.Id.While,
4500 ast.Node.Id.Switch => {
4501 if (if_node.@"else") |@"else"| {
4502 try stack.append(RenderState { .Expression = &@"else".base });
4503
4504 if (if_node.body.id == ast.Node.Id.Block) {
4505 try stack.append(RenderState { .Text = " " });
4506 } else {
4507 try stack.append(RenderState.PrintIndent);
4508 try stack.append(RenderState { .Text = "\n" });
4509 }
4510 }
4511 },
4512 else => {
4513 if (if_node.@"else") |@"else"| {
4514 try stack.append(RenderState { .Expression = @"else".body });
4515
4516 if (@"else".payload) |payload| {
4517 try stack.append(RenderState { .Text = " " });
4518 try stack.append(RenderState { .Expression = payload });
4519 }
4520
4521 try stack.append(RenderState { .Text = " " });
4522 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
4523 try stack.append(RenderState { .Text = " " });
4524 }
4525 }
4526 }
4527
4528 if (if_node.condition.same_line_comment) |comment| {
4529 try stack.append(RenderState { .Indent = indent });
4530 try stack.append(RenderState { .Expression = if_node.body });
4531 try stack.append(RenderState.PrintIndent);
4532 try stack.append(RenderState { .Indent = indent + indent_delta });
4533 try stack.append(RenderState { .Text = "\n" });
4534 try stack.append(RenderState { .PrintLineComment = comment });
4535 } else {
4536 try stack.append(RenderState { .Expression = if_node.body });
4537 }
4538
4539
4540 try stack.append(RenderState { .Text = " " });
4541
4542 if (if_node.payload) |payload| {
4543 try stack.append(RenderState { .Expression = payload });
4544 try stack.append(RenderState { .Text = " " });
4545 }
4546
4547 try stack.append(RenderState { .Text = ")" });
4548 try stack.append(RenderState { .Expression = if_node.condition });
4549 try stack.append(RenderState { .Text = "(" });
4550 },
4551 ast.Node.Id.Asm => {
4552 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
4553 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4554
4555 if (asm_node.volatile_token) |volatile_token| {
4556 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
4557 }
4558
4559 try stack.append(RenderState { .Indent = indent });
4560 try stack.append(RenderState { .Text = ")" });
4561 {
4562 const cloppers = asm_node.cloppers.toSliceConst();
4563 var i = cloppers.len;
4564 while (i != 0) {
4565 i -= 1;
4566 try stack.append(RenderState { .Expression = cloppers[i] });
4567
4568 if (i != 0) {
4569 try stack.append(RenderState { .Text = ", " });
4570 }
4571 }
4572 }
4573 try stack.append(RenderState { .Text = ": " });
4574 try stack.append(RenderState.PrintIndent);
4575 try stack.append(RenderState { .Indent = indent + indent_delta });
4576 try stack.append(RenderState { .Text = "\n" });
4577 {
4578 const inputs = asm_node.inputs.toSliceConst();
4579 var i = inputs.len;
4580 while (i != 0) {
4581 i -= 1;
4582 const node = inputs[i];
4583 try stack.append(RenderState { .Expression = &node.base});
4584
4585 if (i != 0) {
4586 try stack.append(RenderState.PrintIndent);
4587 try stack.append(RenderState {
4588 .Text = blk: {
4589 const prev_node = inputs[i - 1];
4590 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4591 if (loc.line >= 2) {
4592 break :blk "\n\n";
4593 }
4594 break :blk "\n";
4595 },
4596 });
4597 try stack.append(RenderState { .Text = "," });
4598 }
4599 }
4600 }
4601 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4602 try stack.append(RenderState { .Text = ": "});
4603 try stack.append(RenderState.PrintIndent);
4604 try stack.append(RenderState { .Indent = indent + indent_delta});
4605 try stack.append(RenderState { .Text = "\n" });
4606 {
4607 const outputs = asm_node.outputs.toSliceConst();
4608 var i = outputs.len;
4609 while (i != 0) {
4610 i -= 1;
4611 const node = outputs[i];
4612 try stack.append(RenderState { .Expression = &node.base});
4613
4614 if (i != 0) {
4615 try stack.append(RenderState.PrintIndent);
4616 try stack.append(RenderState {
4617 .Text = blk: {
4618 const prev_node = outputs[i - 1];
4619 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4620 if (loc.line >= 2) {
4621 break :blk "\n\n";
4622 }
4623 break :blk "\n";
4624 },
4625 });
4626 try stack.append(RenderState { .Text = "," });
4627 }
4628 }
4629 }
4630 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4631 try stack.append(RenderState { .Text = ": "});
4632 try stack.append(RenderState.PrintIndent);
4633 try stack.append(RenderState { .Indent = indent + indent_delta});
4634 try stack.append(RenderState { .Text = "\n" });
4635 try stack.append(RenderState { .Expression = asm_node.template });
4636 try stack.append(RenderState { .Text = "(" });
4637 },
4638 ast.Node.Id.AsmInput => {
4639 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
4640
4641 try stack.append(RenderState { .Text = ")"});
4642 try stack.append(RenderState { .Expression = asm_input.expr});
4643 try stack.append(RenderState { .Text = " ("});
4644 try stack.append(RenderState { .Expression = asm_input.constraint });
4645 try stack.append(RenderState { .Text = "] "});
4646 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
4647 try stack.append(RenderState { .Text = "["});
4648 },
4649 ast.Node.Id.AsmOutput => {
4650 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
4651
4652 try stack.append(RenderState { .Text = ")"});
4653 switch (asm_output.kind) {
4654 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
4655 try stack.append(RenderState { .Expression = &variable_name.base});
4656 },
4657 ast.Node.AsmOutput.Kind.Return => |return_type| {
4658 try stack.append(RenderState { .Expression = return_type});
4659 try stack.append(RenderState { .Text = "-> "});
4660 },
4661 }
4662 try stack.append(RenderState { .Text = " ("});
4663 try stack.append(RenderState { .Expression = asm_output.constraint });
4664 try stack.append(RenderState { .Text = "] "});
4665 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
4666 try stack.append(RenderState { .Text = "["});
4667 },
4668
4669 ast.Node.Id.StructField,
4670 ast.Node.Id.UnionTag,
4671 ast.Node.Id.EnumTag,
4672 ast.Node.Id.ErrorTag,
4673 ast.Node.Id.Root,
4674 ast.Node.Id.VarDecl,
4675 ast.Node.Id.Use,
4676 ast.Node.Id.TestDecl,
4677 ast.Node.Id.ParamDecl => unreachable,
4678 },
4679 RenderState.Statement => |base| {
4680 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment } );
4681 switch (base.id) {
4682 ast.Node.Id.VarDecl => {
4683 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
4684 try stack.append(RenderState { .VarDecl = var_decl});
4685 },
4686 else => {
4687 if (requireSemiColon(base)) {
4688 try stack.append(RenderState { .Text = ";" });
4689 }
4690 try stack.append(RenderState { .Expression = base });
4691 },
4692 }
4693 },
4694 RenderState.Indent => |new_indent| indent = new_indent,
4695 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
4696 RenderState.PrintSameLineComment => |maybe_comment| blk: {
4697 const comment_token = maybe_comment ?? break :blk;
4698 try stream.print(" {}", self.tokenizer.getTokenSlice(comment_token));
4699 },
4700 RenderState.PrintLineComment => |comment_token| {
4701 try stream.write(self.tokenizer.getTokenSlice(comment_token));
4702 },
4703 }
4704 }
4705 }
4706
4707 fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
4708 const comment = node.doc_comments ?? return;
4709 for (comment.lines.toSliceConst()) |line_token| {
4710 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4711 try stream.writeByteNTimes(' ', indent);
4712 }
4713 }
4714
4715 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
4716 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
4717 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
4718 const typed_slice = ([]T)(self.utility_bytes);
4719 return ArrayList(T) {
4720 .allocator = self.util_allocator,
4721 .items = typed_slice,
4722 .len = 0,
4723 };
4724 }
4725
4726 fn deinitUtilityArrayList(self: &Parser, list: var) void {
4727 self.utility_bytes = ([]align(utility_bytes_align) u8)(list.items);
4728 }
4729
4730};
4731
4732test "std.zig.parser" {
4733 _ = @import("parser_test.zig");
4734}
std/zig/parser_test.zig+81-59
......@@ -1,28 +1,71 @@
1test "zig fmt: same-line comment after a statement" {
2 try testCanonical(
3 \\test "" {
4 \\ a = b;
5 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
6 \\ a = b;
7 \\}
8 \\
9 );
10}
11
12test "zig fmt: same-line comment after var decl in struct" {
13 try testCanonical(
14 \\pub const vfs_cap_data = extern struct {
15 \\ const Data = struct {}; // when on disk.
16 \\};
17 \\
18 );
19}
20
21test "zig fmt: same-line comment after field decl" {
22 try testCanonical(
23 \\pub const dirent = extern struct {
24 \\ d_name: u8,
25 \\ d_name: u8, // comment 1
26 \\ d_name: u8,
27 \\ d_name: u8, // comment 2
28 \\ d_name: u8,
29 \\};
30 \\
31 );
32}
33
34test "zig fmt: same-line comment after switch prong" {
35 try testCanonical(
36 \\test "" {
37 \\ switch (err) {
38 \\ error.PathAlreadyExists => {}, // comment 2
39 \\ else => return err, // comment 1
40 \\ }
41 \\}
42 \\
43 );
44}
45
146test "zig fmt: same-line comment after non-block if expression" {
247 try testCanonical(
348 \\comptime {
4 \\ if (sr > n_uword_bits - 1) {
5 \\ // d > r
49 \\ if (sr > n_uword_bits - 1) // d > r
650 \\ return 0;
7 \\ }
851 \\}
952 \\
1053 );
1154}
1255
13test "zig fmt: switch with empty body" {
56test "zig fmt: same-line comment on comptime expression" {
1457 try testCanonical(
1558 \\test "" {
16 \\ foo() catch |err| switch (err) {};
59 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
1760 \\}
1861 \\
1962 );
2063}
2164
22test "zig fmt: same-line comment on comptime expression" {
65test "zig fmt: switch with empty body" {
2366 try testCanonical(
2467 \\test "" {
25 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
68 \\ foo() catch |err| switch (err) {};
2669 \\}
2770 \\
2871 );
......@@ -154,18 +197,6 @@ test "zig fmt: comments before switch prong" {
154197 );
155198}
156199
157test "zig fmt: same-line comment after switch prong" {
158 try testCanonical(
159 \\test "" {
160 \\ switch (err) {
161 \\ error.PathAlreadyExists => {}, // comment 2
162 \\ else => return err, // comment 1
163 \\ }
164 \\}
165 \\
166 );
167}
168
169200test "zig fmt: comments before var decl in struct" {
170201 try testCanonical(
171202 \\pub const vfs_cap_data = extern struct {
......@@ -191,28 +222,6 @@ test "zig fmt: comments before var decl in struct" {
191222 );
192223}
193224
194test "zig fmt: same-line comment after var decl in struct" {
195 try testCanonical(
196 \\pub const vfs_cap_data = extern struct {
197 \\ const Data = struct {}; // when on disk.
198 \\};
199 \\
200 );
201}
202
203test "zig fmt: same-line comment after field decl" {
204 try testCanonical(
205 \\pub const dirent = extern struct {
206 \\ d_name: u8,
207 \\ d_name: u8, // comment 1
208 \\ d_name: u8,
209 \\ d_name: u8, // comment 2
210 \\ d_name: u8,
211 \\};
212 \\
213 );
214}
215
216225test "zig fmt: array literal with 1 item on 1 line" {
217226 try testCanonical(
218227 \\var s = []const u64{0} ** 25;
......@@ -220,17 +229,6 @@ test "zig fmt: array literal with 1 item on 1 line" {
220229 );
221230}
222231
223test "zig fmt: same-line comment after a statement" {
224 try testCanonical(
225 \\test "" {
226 \\ a = b;
227 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
228 \\ a = b;
229 \\}
230 \\
231 );
232}
233
234232test "zig fmt: comments before global variables" {
235233 try testCanonical(
236234 \\/// Foo copies keys and values before they go into the map, and
......@@ -1094,25 +1092,48 @@ test "zig fmt: error return" {
10941092const std = @import("std");
10951093const mem = std.mem;
10961094const warn = std.debug.warn;
1097const Tokenizer = std.zig.Tokenizer;
1098const Parser = std.zig.Parser;
10991095const io = std.io;
11001096
11011097var fixed_buffer_mem: [100 * 1024]u8 = undefined;
11021098
11031099fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1104 var tokenizer = Tokenizer.init(source);
1105 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");
1106 defer parser.deinit();
1100 var stderr_file = try io.getStdErr();
1101 var stderr = &io.FileOutStream.init(&stderr_file).stream;
11071102
1108 var tree = try parser.parse();
1103 var tree = try std.zig.parse(allocator, source);
11091104 defer tree.deinit();
11101105
1106 var error_it = tree.errors.iterator(0);
1107 while (error_it.next()) |parse_error| {
1108 const token = tree.tokens.at(parse_error.loc());
1109 const loc = tree.tokenLocation(0, parse_error.loc());
1110 try stderr.print("(memory buffer):{}:{}: error: ", loc.line + 1, loc.column + 1);
1111 try tree.renderError(parse_error, stderr);
1112 try stderr.print("\n{}\n", source[loc.line_start..loc.line_end]);
1113 {
1114 var i: usize = 0;
1115 while (i < loc.column) : (i += 1) {
1116 try stderr.write(" ");
1117 }
1118 }
1119 {
1120 const caret_count = token.end - token.start;
1121 var i: usize = 0;
1122 while (i < caret_count) : (i += 1) {
1123 try stderr.write("~");
1124 }
1125 }
1126 try stderr.write("\n");
1127 }
1128 if (tree.errors.len != 0) {
1129 return error.ParseError;
1130 }
1131
11111132 var buffer = try std.Buffer.initSize(allocator, 0);
11121133 errdefer buffer.deinit();
11131134
11141135 var buffer_out_stream = io.BufferOutStream.init(&buffer);
1115 try parser.renderSource(&buffer_out_stream.stream, tree.root_node);
1136 try std.zig.render(allocator, &buffer_out_stream.stream, &tree);
11161137 return buffer.toOwnedSlice();
11171138}
11181139
......@@ -1151,6 +1172,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
11511172 }
11521173 },
11531174 error.ParseError => @panic("test failed"),
1175 else => @panic("test failed"),
11541176 }
11551177 }
11561178}
std/zig/render.zig created+1227
......@@ -0,0 +1,1227 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Token = std.zig.Token;
7
8const indent_delta = 4;
9
10pub const Error = error {
11 /// Ran out of memory allocating call stack frames to complete rendering.
12 OutOfMemory,
13};
14
15pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(stream).Child.Error || Error)!void {
16 comptime assert(@typeId(@typeOf(stream)) == builtin.TypeId.Pointer);
17
18 var it = tree.root_node.decls.iterator(0);
19 while (it.next()) |decl| {
20 try renderTopLevelDecl(allocator, stream, tree, 0, *decl);
21 if (it.peek()) |next_decl| {
22 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
23 try stream.writeByteNTimes('\n', n);
24 }
25 }
26 try stream.write("\n");
27}
28
29fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {
30 const a_last_token = tree.tokens.at(a.lastToken());
31 const loc = tree.tokenLocation(a_last_token.end, b.firstToken());
32 return loc.line;
33}
34
35fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
36 switch (decl.id) {
37 ast.Node.Id.FnProto => {
38 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
39
40 try renderComments(tree, stream, fn_proto, indent);
41 try renderExpression(allocator, stream, tree, indent, decl);
42
43 if (fn_proto.body_node) |body_node| {
44 try stream.write(" ");
45 try renderExpression(allocator, stream, tree, indent, body_node);
46 } else {
47 try stream.write(";");
48 }
49 },
50 ast.Node.Id.Use => {
51 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
52
53 if (use_decl.visib_token) |visib_token| {
54 try stream.print("{} ", tree.tokenSlice(visib_token));
55 }
56 try stream.write("use ");
57 try renderExpression(allocator, stream, tree, indent, use_decl.expr);
58 try stream.write(";");
59 },
60 ast.Node.Id.VarDecl => {
61 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
62
63 try renderComments(tree, stream, var_decl, indent);
64 try renderVarDecl(allocator, stream, tree, indent, var_decl);
65 },
66 ast.Node.Id.TestDecl => {
67 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
68
69 try renderComments(tree, stream, test_decl, indent);
70 try stream.write("test ");
71 try renderExpression(allocator, stream, tree, indent, test_decl.name);
72 try stream.write(" ");
73 try renderExpression(allocator, stream, tree, indent, test_decl.body_node);
74 },
75 ast.Node.Id.StructField => {
76 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
77
78 try renderComments(tree, stream, field, indent);
79 if (field.visib_token) |visib_token| {
80 try stream.print("{} ", tree.tokenSlice(visib_token));
81 }
82 try stream.print("{}: ", tree.tokenSlice(field.name_token));
83 try renderExpression(allocator, stream, tree, indent, field.type_expr);
84 try renderToken(tree, stream, field.lastToken() + 1, indent, true);
85 },
86 ast.Node.Id.UnionTag => {
87 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
88
89 try renderComments(tree, stream, tag, indent);
90 try stream.print("{}", tree.tokenSlice(tag.name_token));
91
92 if (tag.type_expr) |type_expr| {
93 try stream.print(": ");
94 try renderExpression(allocator, stream, tree, indent, type_expr);
95 }
96
97 if (tag.value_expr) |value_expr| {
98 try stream.print(" = ");
99 try renderExpression(allocator, stream, tree, indent, value_expr);
100 }
101
102 try stream.write(",");
103 },
104 ast.Node.Id.EnumTag => {
105 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
106
107 try renderComments(tree, stream, tag, indent);
108 try stream.print("{}", tree.tokenSlice(tag.name_token));
109
110 if (tag.value) |value| {
111 try stream.print(" = ");
112 try renderExpression(allocator, stream, tree, indent, value);
113 }
114
115 try stream.write(",");
116 },
117 ast.Node.Id.ErrorTag => {
118 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
119
120 try renderComments(tree, stream, tag, indent);
121 try stream.print("{}", tree.tokenSlice(tag.name_token));
122 },
123 ast.Node.Id.Comptime => {
124 try renderExpression(allocator, stream, tree, indent, decl);
125 try maybeRenderSemicolon(stream, tree, indent, decl);
126 },
127 ast.Node.Id.LineComment => {
128 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
129
130 try stream.write(tree.tokenSlice(line_comment_node.token));
131 },
132 else => unreachable,
133 }
134}
135
136fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
137 switch (base.id) {
138 ast.Node.Id.Identifier => {
139 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
140 try stream.print("{}", tree.tokenSlice(identifier.token));
141 },
142 ast.Node.Id.Block => {
143 const block = @fieldParentPtr(ast.Node.Block, "base", base);
144 if (block.label) |label| {
145 try stream.print("{}: ", tree.tokenSlice(label));
146 }
147
148 if (block.statements.len == 0) {
149 try stream.write("{}");
150 } else {
151 try stream.write("{\n");
152 const block_indent = indent + indent_delta;
153
154 var it = block.statements.iterator(0);
155 while (it.next()) |statement| {
156 try stream.writeByteNTimes(' ', block_indent);
157 try renderStatement(allocator, stream, tree, block_indent, *statement);
158
159 if (it.peek()) |next_statement| {
160 const n = if (nodeLineOffset(tree, *statement, *next_statement) >= 2) u8(2) else u8(1);
161 try stream.writeByteNTimes('\n', n);
162 }
163 }
164
165 try stream.write("\n");
166 try stream.writeByteNTimes(' ', indent);
167 try stream.write("}");
168 }
169 },
170 ast.Node.Id.Defer => {
171 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
172 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
173 try renderExpression(allocator, stream, tree, indent, defer_node.expr);
174 },
175 ast.Node.Id.Comptime => {
176 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
177 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
178 try renderExpression(allocator, stream, tree, indent, comptime_node.expr);
179 },
180 ast.Node.Id.AsyncAttribute => {
181 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
182 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
183
184 if (async_attr.allocator_type) |allocator_type| {
185 try stream.write("<");
186 try renderExpression(allocator, stream, tree, indent, allocator_type);
187 try stream.write(">");
188 }
189 },
190 ast.Node.Id.Suspend => {
191 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
192 if (suspend_node.label) |label| {
193 try stream.print("{}: ", tree.tokenSlice(label));
194 }
195 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
196
197 if (suspend_node.payload) |payload| {
198 try stream.write(" ");
199 try renderExpression(allocator, stream, tree, indent, payload);
200 }
201
202 if (suspend_node.body) |body| {
203 try stream.write(" ");
204 try renderExpression(allocator, stream, tree, indent, body);
205 }
206
207 },
208
209 ast.Node.Id.InfixOp => {
210 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
211
212 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs);
213
214 const text = switch (infix_op_node.op) {
215 ast.Node.InfixOp.Op.Add => " + ",
216 ast.Node.InfixOp.Op.AddWrap => " +% ",
217 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
218 ast.Node.InfixOp.Op.ArrayMult => " ** ",
219 ast.Node.InfixOp.Op.Assign => " = ",
220 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
221 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
222 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
223 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
224 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
225 ast.Node.InfixOp.Op.AssignDiv => " /= ",
226 ast.Node.InfixOp.Op.AssignMinus => " -= ",
227 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
228 ast.Node.InfixOp.Op.AssignMod => " %= ",
229 ast.Node.InfixOp.Op.AssignPlus => " += ",
230 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
231 ast.Node.InfixOp.Op.AssignTimes => " *= ",
232 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
233 ast.Node.InfixOp.Op.BangEqual => " != ",
234 ast.Node.InfixOp.Op.BitAnd => " & ",
235 ast.Node.InfixOp.Op.BitOr => " | ",
236 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
237 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
238 ast.Node.InfixOp.Op.BitXor => " ^ ",
239 ast.Node.InfixOp.Op.BoolAnd => " and ",
240 ast.Node.InfixOp.Op.BoolOr => " or ",
241 ast.Node.InfixOp.Op.Div => " / ",
242 ast.Node.InfixOp.Op.EqualEqual => " == ",
243 ast.Node.InfixOp.Op.ErrorUnion => "!",
244 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
245 ast.Node.InfixOp.Op.GreaterThan => " > ",
246 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
247 ast.Node.InfixOp.Op.LessThan => " < ",
248 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
249 ast.Node.InfixOp.Op.Mod => " % ",
250 ast.Node.InfixOp.Op.Mult => " * ",
251 ast.Node.InfixOp.Op.MultWrap => " *% ",
252 ast.Node.InfixOp.Op.Period => ".",
253 ast.Node.InfixOp.Op.Sub => " - ",
254 ast.Node.InfixOp.Op.SubWrap => " -% ",
255 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
256 ast.Node.InfixOp.Op.Range => " ... ",
257 ast.Node.InfixOp.Op.Catch => |maybe_payload| blk: {
258 try stream.write(" catch ");
259 if (maybe_payload) |payload| {
260 try renderExpression(allocator, stream, tree, indent, payload);
261 try stream.write(" ");
262 }
263 break :blk "";
264 },
265 };
266
267 try stream.write(text);
268 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs);
269 },
270
271 ast.Node.Id.PrefixOp => {
272 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
273
274 switch (prefix_op_node.op) {
275 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
276 try stream.write("&");
277 if (addr_of_info.align_expr) |align_expr| {
278 try stream.write("align(");
279 try renderExpression(allocator, stream, tree, indent, align_expr);
280 try stream.write(") ");
281 }
282 if (addr_of_info.const_token != null) {
283 try stream.write("const ");
284 }
285 if (addr_of_info.volatile_token != null) {
286 try stream.write("volatile ");
287 }
288 },
289 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
290 try stream.write("[]");
291 if (addr_of_info.align_expr) |align_expr| {
292 try stream.print("align(");
293 try renderExpression(allocator, stream, tree, indent, align_expr);
294 try stream.print(") ");
295 }
296 if (addr_of_info.const_token != null) {
297 try stream.print("const ");
298 }
299 if (addr_of_info.volatile_token != null) {
300 try stream.print("volatile ");
301 }
302 },
303 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
304 try stream.print("[");
305 try renderExpression(allocator, stream, tree, indent, array_index);
306 try stream.print("]");
307 },
308 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
309 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
310 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
311 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
312 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
313 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
314 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
315 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
316 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
317 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
318 }
319
320 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs);
321 },
322
323 ast.Node.Id.SuffixOp => {
324 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
325
326 switch (suffix_op.op) {
327 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
328 if (call_info.async_attr) |async_attr| {
329 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
330 try stream.write(" ");
331 }
332
333 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
334 try stream.write("(");
335
336 var it = call_info.params.iterator(0);
337 while (it.next()) |param_node| {
338 try renderExpression(allocator, stream, tree, indent, *param_node);
339 if (it.peek() != null) {
340 try stream.write(", ");
341 }
342 }
343
344 try stream.write(")");
345 },
346
347 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
348 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
349 try stream.write("[");
350 try renderExpression(allocator, stream, tree, indent, index_expr);
351 try stream.write("]");
352 },
353
354 ast.Node.SuffixOp.Op.SuffixOp {
355 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
356 try stream.write(".*");
357 },
358
359 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
360 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
361 try stream.write("[");
362 try renderExpression(allocator, stream, tree, indent, range.start);
363 try stream.write("..");
364 if (range.end) |end| {
365 try renderExpression(allocator, stream, tree, indent, end);
366 }
367 try stream.write("]");
368 },
369
370 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
371 if (field_inits.len == 0) {
372 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
373 try stream.write("{}");
374 return;
375 }
376
377 if (field_inits.len == 1) {
378 const field_init = *field_inits.at(0);
379
380 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
381 try stream.write("{ ");
382 try renderExpression(allocator, stream, tree, indent, field_init);
383 try stream.write(" }");
384 return;
385 }
386
387 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
388 try stream.write("{\n");
389
390 const new_indent = indent + indent_delta;
391
392 var it = field_inits.iterator(0);
393 while (it.next()) |field_init| {
394 try stream.writeByteNTimes(' ', new_indent);
395 try renderExpression(allocator, stream, tree, new_indent, *field_init);
396 if ((*field_init).id != ast.Node.Id.LineComment) {
397 try stream.write(",");
398 }
399 if (it.peek()) |next_field_init| {
400 const n = if (nodeLineOffset(tree, *field_init, *next_field_init) >= 2) u8(2) else u8(1);
401 try stream.writeByteNTimes('\n', n);
402 }
403 }
404
405 try stream.write("\n");
406 try stream.writeByteNTimes(' ', indent);
407 try stream.write("}");
408 },
409
410 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
411
412 if (exprs.len == 0) {
413 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
414 try stream.write("{}");
415 return;
416 }
417 if (exprs.len == 1) {
418 const expr = *exprs.at(0);
419
420 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
421 try stream.write("{");
422 try renderExpression(allocator, stream, tree, indent, expr);
423 try stream.write("}");
424 return;
425 }
426
427 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
428
429 const new_indent = indent + indent_delta;
430 try stream.write("{\n");
431
432 var it = exprs.iterator(0);
433 while (it.next()) |expr| {
434 try stream.writeByteNTimes(' ', new_indent);
435 try renderExpression(allocator, stream, tree, new_indent, *expr);
436 try stream.write(",");
437
438 if (it.peek()) |next_expr| {
439 const n = if (nodeLineOffset(tree, *expr, *next_expr) >= 2) u8(2) else u8(1);
440 try stream.writeByteNTimes('\n', n);
441 }
442 }
443
444 try stream.write("\n");
445 try stream.writeByteNTimes(' ', indent);
446 try stream.write("}");
447 },
448 }
449 },
450
451 ast.Node.Id.ControlFlowExpression => {
452 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
453
454 switch (flow_expr.kind) {
455 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
456 try stream.print("break");
457 if (maybe_label) |label| {
458 try stream.print(" :");
459 try renderExpression(allocator, stream, tree, indent, label);
460 }
461 },
462 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
463 try stream.print("continue");
464 if (maybe_label) |label| {
465 try stream.print(" :");
466 try renderExpression(allocator, stream, tree, indent, label);
467 }
468 },
469 ast.Node.ControlFlowExpression.Kind.Return => {
470 try stream.print("return");
471 },
472
473 }
474
475 if (flow_expr.rhs) |rhs| {
476 try stream.write(" ");
477 try renderExpression(allocator, stream, tree, indent, rhs);
478 }
479 },
480
481 ast.Node.Id.Payload => {
482 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
483
484 try stream.write("|");
485 try renderExpression(allocator, stream, tree, indent, payload.error_symbol);
486 try stream.write("|");
487 },
488
489 ast.Node.Id.PointerPayload => {
490 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
491
492 try stream.write("|");
493 if (payload.ptr_token) |ptr_token| {
494 try stream.write(tree.tokenSlice(ptr_token));
495 }
496 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
497 try stream.write("|");
498 },
499
500 ast.Node.Id.PointerIndexPayload => {
501 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
502
503 try stream.write("|");
504 if (payload.ptr_token) |ptr_token| {
505 try stream.write(tree.tokenSlice(ptr_token));
506 }
507 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
508
509 if (payload.index_symbol) |index_symbol| {
510 try stream.write(", ");
511 try renderExpression(allocator, stream, tree, indent, index_symbol);
512 }
513
514 try stream.write("|");
515 },
516
517 ast.Node.Id.GroupedExpression => {
518 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
519
520 try stream.write("(");
521 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr);
522 try stream.write(")");
523 },
524
525 ast.Node.Id.FieldInitializer => {
526 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
527
528 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
529 try renderExpression(allocator, stream, tree, indent, field_init.expr);
530 },
531
532 ast.Node.Id.IntegerLiteral => {
533 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
534 try stream.print("{}", tree.tokenSlice(integer_literal.token));
535 },
536 ast.Node.Id.FloatLiteral => {
537 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
538 try stream.print("{}", tree.tokenSlice(float_literal.token));
539 },
540 ast.Node.Id.StringLiteral => {
541 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
542 try stream.print("{}", tree.tokenSlice(string_literal.token));
543 },
544 ast.Node.Id.CharLiteral => {
545 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
546 try stream.print("{}", tree.tokenSlice(char_literal.token));
547 },
548 ast.Node.Id.BoolLiteral => {
549 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
550 try stream.print("{}", tree.tokenSlice(bool_literal.token));
551 },
552 ast.Node.Id.NullLiteral => {
553 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
554 try stream.print("{}", tree.tokenSlice(null_literal.token));
555 },
556 ast.Node.Id.ThisLiteral => {
557 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
558 try stream.print("{}", tree.tokenSlice(this_literal.token));
559 },
560 ast.Node.Id.Unreachable => {
561 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
562 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
563 },
564 ast.Node.Id.ErrorType => {
565 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
566 try stream.print("{}", tree.tokenSlice(error_type.token));
567 },
568 ast.Node.Id.VarType => {
569 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
570 try stream.print("{}", tree.tokenSlice(var_type.token));
571 },
572 ast.Node.Id.ContainerDecl => {
573 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
574
575 switch (container_decl.layout) {
576 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
577 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
578 ast.Node.ContainerDecl.Layout.Auto => { },
579 }
580
581 switch (container_decl.kind) {
582 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
583 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
584 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
585 }
586
587 switch (container_decl.init_arg_expr) {
588 ast.Node.ContainerDecl.InitArg.None => try stream.write(" "),
589 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
590 if (enum_tag_type) |expr| {
591 try stream.write("(enum(");
592 try renderExpression(allocator, stream, tree, indent, expr);
593 try stream.write(")) ");
594 } else {
595 try stream.write("(enum) ");
596 }
597 },
598 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
599 try stream.write("(");
600 try renderExpression(allocator, stream, tree, indent, type_expr);
601 try stream.write(") ");
602 },
603 }
604
605 if (container_decl.fields_and_decls.len == 0) {
606 try stream.write("{}");
607 } else {
608 try stream.write("{\n");
609 const new_indent = indent + indent_delta;
610
611 var it = container_decl.fields_and_decls.iterator(0);
612 while (it.next()) |decl| {
613 try stream.writeByteNTimes(' ', new_indent);
614 try renderTopLevelDecl(allocator, stream, tree, new_indent, *decl);
615
616 if (it.peek()) |next_decl| {
617 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
618 try stream.writeByteNTimes('\n', n);
619 }
620 }
621
622 try stream.write("\n");
623 try stream.writeByteNTimes(' ', indent);
624 try stream.write("}");
625 }
626 },
627
628 ast.Node.Id.ErrorSetDecl => {
629 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
630
631 if (err_set_decl.decls.len == 0) {
632 try stream.write("error{}");
633 return;
634 }
635
636 if (err_set_decl.decls.len == 1) blk: {
637 const node = *err_set_decl.decls.at(0);
638
639 // if there are any doc comments or same line comments
640 // don't try to put it all on one line
641 if (node.cast(ast.Node.ErrorTag)) |tag| {
642 if (tag.doc_comments != null) break :blk;
643 } else {
644 break :blk;
645 }
646
647
648 try stream.write("error{");
649 try renderTopLevelDecl(allocator, stream, tree, indent, node);
650 try stream.write("}");
651 return;
652 }
653
654 try stream.write("error{\n");
655 const new_indent = indent + indent_delta;
656
657 var it = err_set_decl.decls.iterator(0);
658 while (it.next()) |node| {
659 try stream.writeByteNTimes(' ', new_indent);
660 try renderTopLevelDecl(allocator, stream, tree, new_indent, *node);
661 if ((*node).id != ast.Node.Id.LineComment) {
662 try stream.write(",");
663 }
664 if (it.peek()) |next_node| {
665 const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
666 try stream.writeByteNTimes('\n', n);
667 }
668 }
669
670 try stream.write("\n");
671 try stream.writeByteNTimes(' ', indent);
672 try stream.write("}");
673 },
674
675 ast.Node.Id.MultilineStringLiteral => {
676 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
677 try stream.print("\n");
678
679 var i : usize = 0;
680 while (i < multiline_str_literal.lines.len) : (i += 1) {
681 const t = *multiline_str_literal.lines.at(i);
682 try stream.writeByteNTimes(' ', indent + indent_delta);
683 try stream.print("{}", tree.tokenSlice(t));
684 }
685 try stream.writeByteNTimes(' ', indent);
686 },
687 ast.Node.Id.UndefinedLiteral => {
688 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
689 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
690 },
691
692 ast.Node.Id.BuiltinCall => {
693 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
694 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
695
696 var it = builtin_call.params.iterator(0);
697 while (it.next()) |param_node| {
698 try renderExpression(allocator, stream, tree, indent, *param_node);
699 if (it.peek() != null) {
700 try stream.write(", ");
701 }
702 }
703 try stream.write(")");
704 },
705
706 ast.Node.Id.FnProto => {
707 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
708
709 if (fn_proto.visib_token) |visib_token_index| {
710 const visib_token = tree.tokens.at(visib_token_index);
711 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
712 try stream.print("{} ", tree.tokenSlice(visib_token_index));
713 }
714
715 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
716 try stream.print("{} ", tree.tokenSlice(extern_export_inline_token));
717 }
718
719 if (fn_proto.lib_name) |lib_name| {
720 try renderExpression(allocator, stream, tree, indent, lib_name);
721 try stream.write(" ");
722 }
723
724 if (fn_proto.cc_token) |cc_token| {
725 try stream.print("{} ", tree.tokenSlice(cc_token));
726 }
727
728 if (fn_proto.async_attr) |async_attr| {
729 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
730 try stream.write(" ");
731 }
732
733 try stream.write("fn");
734
735 if (fn_proto.name_token) |name_token| {
736 try stream.print(" {}", tree.tokenSlice(name_token));
737 }
738
739 try stream.write("(");
740
741 var it = fn_proto.params.iterator(0);
742 while (it.next()) |param_decl_node| {
743 try renderParamDecl(allocator, stream, tree, indent, *param_decl_node);
744
745 if (it.peek() != null) {
746 try stream.write(", ");
747 }
748 }
749
750 try stream.write(") ");
751
752 if (fn_proto.align_expr) |align_expr| {
753 try stream.write("align(");
754 try renderExpression(allocator, stream, tree, indent, align_expr);
755 try stream.write(") ");
756 }
757
758 switch (fn_proto.return_type) {
759 ast.Node.FnProto.ReturnType.Explicit => |node| {
760 try renderExpression(allocator, stream, tree, indent, node);
761 },
762 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
763 try stream.write("!");
764 try renderExpression(allocator, stream, tree, indent, node);
765 },
766 }
767
768 },
769
770 ast.Node.Id.PromiseType => {
771 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
772 try stream.write(tree.tokenSlice(promise_type.promise_token));
773 if (promise_type.result) |result| {
774 try stream.write(tree.tokenSlice(result.arrow_token));
775 try renderExpression(allocator, stream, tree, indent, result.return_type);
776 }
777 },
778
779 ast.Node.Id.LineComment => {
780 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
781 try stream.write(tree.tokenSlice(line_comment_node.token));
782 },
783
784 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
785
786 ast.Node.Id.Switch => {
787 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
788
789 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
790 if (switch_node.cases.len == 0) {
791 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
792 try stream.write(") {}");
793 return;
794 }
795
796 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
797 try stream.write(") {\n");
798
799 const new_indent = indent + indent_delta;
800
801 var it = switch_node.cases.iterator(0);
802 while (it.next()) |node| {
803 try stream.writeByteNTimes(' ', new_indent);
804 try renderExpression(allocator, stream, tree, new_indent, *node);
805
806 if (it.peek()) |next_node| {
807 const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
808 try stream.writeByteNTimes('\n', n);
809 }
810 }
811
812 try stream.write("\n");
813 try stream.writeByteNTimes(' ', indent);
814 try stream.write("}");
815 },
816
817 ast.Node.Id.SwitchCase => {
818 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
819
820 var it = switch_case.items.iterator(0);
821 while (it.next()) |node| {
822 try renderExpression(allocator, stream, tree, indent, *node);
823
824 if (it.peek() != null) {
825 try stream.write(",\n");
826 try stream.writeByteNTimes(' ', indent);
827 }
828 }
829
830 try stream.write(" => ");
831
832 if (switch_case.payload) |payload| {
833 try renderExpression(allocator, stream, tree, indent, payload);
834 try stream.write(" ");
835 }
836
837 try renderExpression(allocator, stream, tree, indent, switch_case.expr);
838 try renderToken(tree, stream, switch_case.lastToken() + 1, indent, true);
839 },
840 ast.Node.Id.SwitchElse => {
841 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
842 try stream.print("{}", tree.tokenSlice(switch_else.token));
843 },
844 ast.Node.Id.Else => {
845 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
846 try stream.print("{}", tree.tokenSlice(else_node.else_token));
847
848 const block_body = switch (else_node.body.id) {
849 ast.Node.Id.Block, ast.Node.Id.If,
850 ast.Node.Id.For, ast.Node.Id.While,
851 ast.Node.Id.Switch => true,
852 else => false,
853 };
854
855 if (block_body) {
856 try stream.write(" ");
857 }
858
859 if (else_node.payload) |payload| {
860 try renderExpression(allocator, stream, tree, indent, payload);
861 try stream.write(" ");
862 }
863
864 if (block_body) {
865 try renderExpression(allocator, stream, tree, indent, else_node.body);
866 } else {
867 try stream.write("\n");
868 try stream.writeByteNTimes(' ', indent + indent_delta);
869 try renderExpression(allocator, stream, tree, indent, else_node.body);
870 }
871 },
872
873 ast.Node.Id.While => {
874 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
875
876 if (while_node.label) |label| {
877 try stream.print("{}: ", tree.tokenSlice(label));
878 }
879
880 if (while_node.inline_token) |inline_token| {
881 try stream.print("{} ", tree.tokenSlice(inline_token));
882 }
883
884 try stream.print("{} (", tree.tokenSlice(while_node.while_token));
885 try renderExpression(allocator, stream, tree, indent, while_node.condition);
886 try stream.write(")");
887
888 if (while_node.payload) |payload| {
889 try stream.write(" ");
890 try renderExpression(allocator, stream, tree, indent, payload);
891 }
892
893 if (while_node.continue_expr) |continue_expr| {
894 try stream.write(" : (");
895 try renderExpression(allocator, stream, tree, indent, continue_expr);
896 try stream.write(")");
897 }
898
899 if (while_node.body.id == ast.Node.Id.Block) {
900 try stream.write(" ");
901 try renderExpression(allocator, stream, tree, indent, while_node.body);
902 } else {
903 try stream.write("\n");
904 try stream.writeByteNTimes(' ', indent + indent_delta);
905 try renderExpression(allocator, stream, tree, indent, while_node.body);
906 }
907
908 if (while_node.@"else") |@"else"| {
909 if (while_node.body.id == ast.Node.Id.Block) {
910 try stream.write(" ");
911 } else {
912 try stream.write("\n");
913 try stream.writeByteNTimes(' ', indent);
914 }
915
916 try renderExpression(allocator, stream, tree, indent, &@"else".base);
917 }
918 },
919
920 ast.Node.Id.For => {
921 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
922 if (for_node.label) |label| {
923 try stream.print("{}: ", tree.tokenSlice(label));
924 }
925
926 if (for_node.inline_token) |inline_token| {
927 try stream.print("{} ", tree.tokenSlice(inline_token));
928 }
929
930 try stream.print("{} (", tree.tokenSlice(for_node.for_token));
931 try renderExpression(allocator, stream, tree, indent, for_node.array_expr);
932 try stream.write(")");
933
934 if (for_node.payload) |payload| {
935 try stream.write(" ");
936 try renderExpression(allocator, stream, tree, indent, payload);
937 }
938
939 if (for_node.body.id == ast.Node.Id.Block) {
940 try stream.write(" ");
941 try renderExpression(allocator, stream, tree, indent, for_node.body);
942 } else {
943 try stream.write("\n");
944 try stream.writeByteNTimes(' ', indent + indent_delta);
945 try renderExpression(allocator, stream, tree, indent, for_node.body);
946 }
947
948 if (for_node.@"else") |@"else"| {
949 if (for_node.body.id == ast.Node.Id.Block) {
950 try stream.write(" ");
951 } else {
952 try stream.write("\n");
953 try stream.writeByteNTimes(' ', indent);
954 }
955
956 try renderExpression(allocator, stream, tree, indent, &@"else".base);
957 }
958 },
959
960 ast.Node.Id.If => {
961 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
962 try stream.print("{} (", tree.tokenSlice(if_node.if_token));
963
964 try renderExpression(allocator, stream, tree, indent, if_node.condition);
965 try renderToken(tree, stream, if_node.condition.lastToken() + 1, indent, false);
966
967 if (if_node.payload) |payload| {
968 try renderExpression(allocator, stream, tree, indent, payload);
969 try stream.write(" ");
970 }
971
972 try renderExpression(allocator, stream, tree, indent, if_node.body);
973
974 switch (if_node.body.id) {
975 ast.Node.Id.Block, ast.Node.Id.If, ast.Node.Id.For, ast.Node.Id.While, ast.Node.Id.Switch => {
976 if (if_node.@"else") |@"else"| {
977 if (if_node.body.id == ast.Node.Id.Block) {
978 try stream.write(" ");
979 } else {
980 try stream.write("\n");
981 try stream.writeByteNTimes(' ', indent);
982 }
983
984 try renderExpression(allocator, stream, tree, indent, &@"else".base);
985 }
986 },
987 else => {
988 if (if_node.@"else") |@"else"| {
989 try stream.print(" {} ", tree.tokenSlice(@"else".else_token));
990
991 if (@"else".payload) |payload| {
992 try renderExpression(allocator, stream, tree, indent, payload);
993 try stream.write(" ");
994 }
995
996 try renderExpression(allocator, stream, tree, indent, @"else".body);
997 }
998 }
999 }
1000 },
1001
1002 ast.Node.Id.Asm => {
1003 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1004 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
1005
1006 if (asm_node.volatile_token) |volatile_token| {
1007 try stream.print("{} ", tree.tokenSlice(volatile_token));
1008 }
1009
1010 try stream.print("(");
1011 try renderExpression(allocator, stream, tree, indent, asm_node.template);
1012 try stream.print("\n");
1013 const indent_once = indent + indent_delta;
1014 try stream.writeByteNTimes(' ', indent_once);
1015 try stream.print(": ");
1016 const indent_extra = indent_once + 2;
1017
1018 {
1019 var it = asm_node.outputs.iterator(0);
1020 while (it.next()) |asm_output| {
1021 const node = &(*asm_output).base;
1022 try renderExpression(allocator, stream, tree, indent_extra, node);
1023
1024 if (it.peek()) |next_asm_output| {
1025 const next_node = &(*next_asm_output).base;
1026 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1027 try stream.writeByte(',');
1028 try stream.writeByteNTimes('\n', n);
1029 try stream.writeByteNTimes(' ', indent_extra);
1030 }
1031 }
1032 }
1033
1034 try stream.write("\n");
1035 try stream.writeByteNTimes(' ', indent_once);
1036 try stream.write(": ");
1037
1038 {
1039 var it = asm_node.inputs.iterator(0);
1040 while (it.next()) |asm_input| {
1041 const node = &(*asm_input).base;
1042 try renderExpression(allocator, stream, tree, indent_extra, node);
1043
1044 if (it.peek()) |next_asm_input| {
1045 const next_node = &(*next_asm_input).base;
1046 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1047 try stream.writeByte(',');
1048 try stream.writeByteNTimes('\n', n);
1049 try stream.writeByteNTimes(' ', indent_extra);
1050 }
1051 }
1052 }
1053
1054 try stream.write("\n");
1055 try stream.writeByteNTimes(' ', indent_once);
1056 try stream.write(": ");
1057
1058 {
1059 var it = asm_node.clobbers.iterator(0);
1060 while (it.next()) |node| {
1061 try renderExpression(allocator, stream, tree, indent_once, *node);
1062
1063 if (it.peek() != null) {
1064 try stream.write(", ");
1065 }
1066 }
1067 }
1068
1069 try stream.write(")");
1070 },
1071
1072 ast.Node.Id.AsmInput => {
1073 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1074
1075 try stream.write("[");
1076 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name);
1077 try stream.write("] ");
1078 try renderExpression(allocator, stream, tree, indent, asm_input.constraint);
1079 try stream.write(" (");
1080 try renderExpression(allocator, stream, tree, indent, asm_input.expr);
1081 try stream.write(")");
1082 },
1083
1084 ast.Node.Id.AsmOutput => {
1085 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1086
1087 try stream.write("[");
1088 try renderExpression(allocator, stream, tree, indent, asm_output.symbolic_name);
1089 try stream.write("] ");
1090 try renderExpression(allocator, stream, tree, indent, asm_output.constraint);
1091 try stream.write(" (");
1092
1093 switch (asm_output.kind) {
1094 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1095 try renderExpression(allocator, stream, tree, indent, &variable_name.base);
1096 },
1097 ast.Node.AsmOutput.Kind.Return => |return_type| {
1098 try stream.write("-> ");
1099 try renderExpression(allocator, stream, tree, indent, return_type);
1100 },
1101 }
1102
1103 try stream.write(")");
1104 },
1105
1106 ast.Node.Id.StructField,
1107 ast.Node.Id.UnionTag,
1108 ast.Node.Id.EnumTag,
1109 ast.Node.Id.ErrorTag,
1110 ast.Node.Id.Root,
1111 ast.Node.Id.VarDecl,
1112 ast.Node.Id.Use,
1113 ast.Node.Id.TestDecl,
1114 ast.Node.Id.ParamDecl => unreachable,
1115 }
1116}
1117
1118fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void {
1119 if (var_decl.visib_token) |visib_token| {
1120 try stream.print("{} ", tree.tokenSlice(visib_token));
1121 }
1122
1123 if (var_decl.extern_export_token) |extern_export_token| {
1124 try stream.print("{} ", tree.tokenSlice(extern_export_token));
1125
1126 if (var_decl.lib_name) |lib_name| {
1127 try renderExpression(allocator, stream, tree, indent, lib_name);
1128 try stream.write(" ");
1129 }
1130 }
1131
1132 if (var_decl.comptime_token) |comptime_token| {
1133 try stream.print("{} ", tree.tokenSlice(comptime_token));
1134 }
1135
1136 try stream.print("{} {}", tree.tokenSlice(var_decl.mut_token), tree.tokenSlice(var_decl.name_token));
1137
1138 if (var_decl.type_node) |type_node| {
1139 try stream.write(": ");
1140 try renderExpression(allocator, stream, tree, indent, type_node);
1141 }
1142
1143 if (var_decl.align_node) |align_node| {
1144 try stream.write(" align(");
1145 try renderExpression(allocator, stream, tree, indent, align_node);
1146 try stream.write(")");
1147 }
1148
1149 if (var_decl.init_node) |init_node| {
1150 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
1151 try stream.write(text);
1152 try renderExpression(allocator, stream, tree, indent, init_node);
1153 }
1154
1155 try renderToken(tree, stream, var_decl.semicolon_token, indent, true);
1156}
1157
1158fn maybeRenderSemicolon(stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1159 if (base.requireSemiColon()) {
1160 const semicolon_index = base.lastToken() + 1;
1161 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1162 try renderToken(tree, stream, semicolon_index, indent, true);
1163 }
1164}
1165
1166fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1167 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1168 if (param_decl.comptime_token) |comptime_token| {
1169 try stream.print("{} ", tree.tokenSlice(comptime_token));
1170 }
1171 if (param_decl.noalias_token) |noalias_token| {
1172 try stream.print("{} ", tree.tokenSlice(noalias_token));
1173 }
1174 if (param_decl.name_token) |name_token| {
1175 try stream.print("{}: ", tree.tokenSlice(name_token));
1176 }
1177 if (param_decl.var_args_token) |var_args_token| {
1178 try stream.print("{}", tree.tokenSlice(var_args_token));
1179 } else {
1180 try renderExpression(allocator, stream, tree, indent, param_decl.type_node);
1181 }
1182}
1183
1184fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1185 switch (base.id) {
1186 ast.Node.Id.VarDecl => {
1187 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1188 try renderVarDecl(allocator, stream, tree, indent, var_decl);
1189 },
1190 else => {
1191 try renderExpression(allocator, stream, tree, indent, base);
1192 try maybeRenderSemicolon(stream, tree, indent, base);
1193 },
1194 }
1195}
1196
1197fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) (@typeOf(stream).Child.Error || Error)!void {
1198 const token = tree.tokens.at(token_index);
1199 try stream.write(tree.tokenSlicePtr(token));
1200
1201 const next_token = tree.tokens.at(token_index + 1);
1202 if (next_token.id == Token.Id.LineComment) {
1203 const loc = tree.tokenLocationPtr(token.end, next_token);
1204 if (loc.line == 0) {
1205 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1206 if (!line_break) {
1207 try stream.write("\n");
1208 try stream.writeByteNTimes(' ', indent + indent_delta);
1209 return;
1210 }
1211 }
1212 }
1213
1214 if (!line_break) {
1215 try stream.writeByte(' ');
1216 }
1217}
1218
1219fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@typeOf(stream).Child.Error || Error)!void {
1220 const comment = node.doc_comments ?? return;
1221 var it = comment.lines.iterator(0);
1222 while (it.next()) |line_token_index| {
1223 try stream.print("{}\n", tree.tokenSlice(*line_token_index));
1224 try stream.writeByteNTimes(' ', indent);
1225 }
1226}
1227
std/zig/tokenizer.zig-35
......@@ -195,37 +195,6 @@ pub const Tokenizer = struct {
195195 index: usize,
196196 pending_invalid_token: ?Token,
197197
198 pub const Location = struct {
199 line: usize,
200 column: usize,
201 line_start: usize,
202 line_end: usize,
203 };
204
205 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
206 var loc = Location {
207 .line = 0,
208 .column = 0,
209 .line_start = start_index,
210 .line_end = self.buffer.len,
211 };
212 for (self.buffer[start_index..]) |c, i| {
213 if (i + start_index == token.start) {
214 loc.line_end = i + start_index;
215 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
216 return loc;
217 }
218 if (c == '\n') {
219 loc.line += 1;
220 loc.column = 0;
221 loc.line_start = i + 1;
222 } else {
223 loc.column += 1;
224 }
225 }
226 return loc;
227 }
228
229198 /// For debugging purposes
230199 pub fn dump(self: &Tokenizer, token: &const Token) void {
231200 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);
......@@ -1047,10 +1016,6 @@ pub const Tokenizer = struct {
10471016 return result;
10481017 }
10491018
1050 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) []const u8 {
1051 return self.buffer[token.start..token.end];
1052 }
1053
10541019 fn checkLiteralCharacter(self: &Tokenizer) void {
10551020 if (self.pending_invalid_token != null) return;
10561021 const invalid_length = self.getInvalidCharacterLength();
test/behavior.zig+3-2
......@@ -23,6 +23,7 @@ comptime {
2323 _ = @import("cases/eval.zig");
2424 _ = @import("cases/field_parent_ptr.zig");
2525 _ = @import("cases/fn.zig");
26 _ = @import("cases/fn_in_struct_in_comptime.zig");
2627 _ = @import("cases/for.zig");
2728 _ = @import("cases/generics.zig");
2829 _ = @import("cases/if.zig");
......@@ -32,12 +33,12 @@ comptime {
3233 _ = @import("cases/math.zig");
3334 _ = @import("cases/misc.zig");
3435 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
36 _ = @import("cases/new_stack_call.zig");
3537 _ = @import("cases/null.zig");
3638 _ = @import("cases/pointers.zig");
3739 _ = @import("cases/pub_enum/index.zig");
3840 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
3941 _ = @import("cases/reflection.zig");
40 _ = @import("cases/type_info.zig");
4142 _ = @import("cases/sizeof_and_typeof.zig");
4243 _ = @import("cases/slice.zig");
4344 _ = @import("cases/struct.zig");
......@@ -49,10 +50,10 @@ comptime {
4950 _ = @import("cases/syntax.zig");
5051 _ = @import("cases/this.zig");
5152 _ = @import("cases/try.zig");
53 _ = @import("cases/type_info.zig");
5254 _ = @import("cases/undefined.zig");
5355 _ = @import("cases/union.zig");
5456 _ = @import("cases/var_args.zig");
5557 _ = @import("cases/void.zig");
5658 _ = @import("cases/while.zig");
57 _ = @import("cases/fn_in_struct_in_comptime.zig");
5859}
test/cases/eval.zig+17
......@@ -569,3 +569,20 @@ test "runtime 128 bit integer division" {
569569 var c = a / b;
570570 assert(c == 15231399999);
571571}
572
573pub const Info = struct {
574 version: u8,
575};
576
577pub const diamond_info = Info {
578 .version = 0,
579};
580
581test "comptime modification of const struct field" {
582 comptime {
583 var res = diamond_info;
584 res.version = 1;
585 assert(diamond_info.version == 0);
586 assert(res.version == 1);
587 }
588}
test/cases/math.zig+8
......@@ -352,6 +352,14 @@ test "big number multi-limb shift and mask" {
352352 }
353353}
354354
355test "big number multi-limb partial shift right" {
356 comptime {
357 var a = 0x1ffffffffeeeeeeee;
358 a >>= 16;
359 assert(a == 0x1ffffffffeeee);
360 }
361}
362
355363test "xor" {
356364 test_xor();
357365 comptime test_xor();
test/cases/new_stack_call.zig created+26
......@@ -0,0 +1,26 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4var new_stack_bytes: [1024]u8 = undefined;
5
6test "calling a function with a new stack" {
7 const arg = 1234;
8
9 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
10 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
11 _ = targetFunction(arg);
12
13 assert(arg == 1234);
14 assert(a < b);
15}
16
17fn targetFunction(x: i32) usize {
18 assert(x == 1234);
19
20 var local_variable: i32 = 42;
21 const ptr = &local_variable;
22 ptr.* += 1;
23
24 assert(local_variable == 43);
25 return @ptrToInt(ptr);
26}