authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-10 11:37:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-10 11:37:25-04:00
log284ab109c4b83f7bb9a832f284f706e641b002fd
treed7dc258a7e0676a9867e7941d8605074b57ea74a
parent7e37d268c86ccc823c4a381a42029722d36c3975
parentefa39c5343e13a13e65210f55da5df23ee3feb3e

Merge remote-tracking branch 'origin/master' into llvm7


30 files changed, 6232 insertions(+), 5271 deletions(-)

CMakeLists.txt+31-29
...@@ -416,8 +416,8 @@ set(ZIG_CPP_SOURCES...@@ -416,8 +416,8 @@ set(ZIG_CPP_SOURCES
416set(ZIG_STD_FILES416set(ZIG_STD_FILES
417 "array_list.zig"417 "array_list.zig"
418 "atomic/index.zig"418 "atomic/index.zig"
419 "atomic/stack.zig"
420 "atomic/queue.zig"419 "atomic/queue.zig"
420 "atomic/stack.zig"
421 "base64.zig"421 "base64.zig"
422 "buf_map.zig"422 "buf_map.zig"
423 "buf_set.zig"423 "buf_set.zig"
...@@ -427,13 +427,13 @@ set(ZIG_STD_FILES...@@ -427,13 +427,13 @@ set(ZIG_STD_FILES
427 "c/index.zig"427 "c/index.zig"
428 "c/linux.zig"428 "c/linux.zig"
429 "c/windows.zig"429 "c/windows.zig"
430 "crypto/blake2.zig"
431 "crypto/hmac.zig"
430 "crypto/index.zig"432 "crypto/index.zig"
431 "crypto/md5.zig"433 "crypto/md5.zig"
432 "crypto/sha1.zig"434 "crypto/sha1.zig"
433 "crypto/sha2.zig"435 "crypto/sha2.zig"
434 "crypto/sha3.zig"436 "crypto/sha3.zig"
435 "crypto/blake2.zig"
436 "crypto/hmac.zig"
437 "cstr.zig"437 "cstr.zig"
438 "debug/failing_allocator.zig"438 "debug/failing_allocator.zig"
439 "debug/index.zig"439 "debug/index.zig"
...@@ -445,12 +445,12 @@ set(ZIG_STD_FILES...@@ -445,12 +445,12 @@ set(ZIG_STD_FILES
445 "fmt/errol/index.zig"445 "fmt/errol/index.zig"
446 "fmt/errol/lookup.zig"446 "fmt/errol/lookup.zig"
447 "fmt/index.zig"447 "fmt/index.zig"
448 "hash_map.zig"
449 "hash/index.zig"
450 "hash/adler.zig"448 "hash/adler.zig"
451 "hash/crc.zig"449 "hash/crc.zig"
452 "hash/fnv.zig"450 "hash/fnv.zig"
451 "hash/index.zig"
453 "hash/siphash.zig"452 "hash/siphash.zig"
453 "hash_map.zig"
454 "heap.zig"454 "heap.zig"
455 "index.zig"455 "index.zig"
456 "io.zig"456 "io.zig"
...@@ -466,6 +466,28 @@ set(ZIG_STD_FILES...@@ -466,6 +466,28 @@ set(ZIG_STD_FILES
466 "math/atanh.zig"466 "math/atanh.zig"
467 "math/cbrt.zig"467 "math/cbrt.zig"
468 "math/ceil.zig"468 "math/ceil.zig"
469 "math/complex/abs.zig"
470 "math/complex/acos.zig"
471 "math/complex/acosh.zig"
472 "math/complex/arg.zig"
473 "math/complex/asin.zig"
474 "math/complex/asinh.zig"
475 "math/complex/atan.zig"
476 "math/complex/atanh.zig"
477 "math/complex/conj.zig"
478 "math/complex/cos.zig"
479 "math/complex/cosh.zig"
480 "math/complex/exp.zig"
481 "math/complex/index.zig"
482 "math/complex/ldexp.zig"
483 "math/complex/log.zig"
484 "math/complex/pow.zig"
485 "math/complex/proj.zig"
486 "math/complex/sin.zig"
487 "math/complex/sinh.zig"
488 "math/complex/sqrt.zig"
489 "math/complex/tan.zig"
490 "math/complex/tanh.zig"
469 "math/copysign.zig"491 "math/copysign.zig"
470 "math/cos.zig"492 "math/cos.zig"
471 "math/cosh.zig"493 "math/cosh.zig"
...@@ -502,33 +524,12 @@ set(ZIG_STD_FILES...@@ -502,33 +524,12 @@ set(ZIG_STD_FILES
502 "math/tan.zig"524 "math/tan.zig"
503 "math/tanh.zig"525 "math/tanh.zig"
504 "math/trunc.zig"526 "math/trunc.zig"
505 "math/complex/abs.zig"
506 "math/complex/acosh.zig"
507 "math/complex/acos.zig"
508 "math/complex/arg.zig"
509 "math/complex/asinh.zig"
510 "math/complex/asin.zig"
511 "math/complex/atanh.zig"
512 "math/complex/atan.zig"
513 "math/complex/conj.zig"
514 "math/complex/cosh.zig"
515 "math/complex/cos.zig"
516 "math/complex/exp.zig"
517 "math/complex/index.zig"
518 "math/complex/ldexp.zig"
519 "math/complex/log.zig"
520 "math/complex/pow.zig"
521 "math/complex/proj.zig"
522 "math/complex/sinh.zig"
523 "math/complex/sin.zig"
524 "math/complex/sqrt.zig"
525 "math/complex/tanh.zig"
526 "math/complex/tan.zig"
527 "mem.zig"527 "mem.zig"
528 "net.zig"528 "net.zig"
529 "os/child_process.zig"529 "os/child_process.zig"
530 "os/darwin.zig"530 "os/darwin.zig"
531 "os/darwin_errno.zig"531 "os/darwin_errno.zig"
532 "os/epoch.zig"
532 "os/file.zig"533 "os/file.zig"
533 "os/get_user_id.zig"534 "os/get_user_id.zig"
534 "os/index.zig"535 "os/index.zig"
...@@ -538,13 +539,13 @@ set(ZIG_STD_FILES...@@ -538,13 +539,13 @@ set(ZIG_STD_FILES
538 "os/linux/x86_64.zig"539 "os/linux/x86_64.zig"
539 "os/path.zig"540 "os/path.zig"
540 "os/time.zig"541 "os/time.zig"
541 "os/epoch.zig"
542 "os/windows/error.zig"542 "os/windows/error.zig"
543 "os/windows/index.zig"543 "os/windows/index.zig"
544 "os/windows/util.zig"544 "os/windows/util.zig"
545 "os/zen.zig"545 "os/zen.zig"
546 "rand/index.zig"546 "rand/index.zig"
547 "rand/ziggurat.zig"547 "rand/ziggurat.zig"
548 "segmented_list.zig"
548 "sort.zig"549 "sort.zig"
549 "special/bootstrap.zig"550 "special/bootstrap.zig"
550 "special/bootstrap_lib.zig"551 "special/bootstrap_lib.zig"
...@@ -575,7 +576,8 @@ set(ZIG_STD_FILES...@@ -575,7 +576,8 @@ set(ZIG_STD_FILES
575 "unicode.zig"576 "unicode.zig"
576 "zig/ast.zig"577 "zig/ast.zig"
577 "zig/index.zig"578 "zig/index.zig"
578 "zig/parser.zig"579 "zig/parse.zig"
580 "zig/render.zig"
579 "zig/tokenizer.zig"581 "zig/tokenizer.zig"
580)582)
581583
src-self-hosted/main.zig+30-18
...@@ -671,34 +671,46 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {...@@ -671,34 +671,46 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
671 };671 };
672 defer allocator.free(source_code);672 defer allocator.free(source_code);
673673
674 var tokenizer = std.zig.Tokenizer.init(source_code);674 var tree = std.zig.parse(allocator, source_code) catch |err| {
675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
676 defer parser.deinit();
677
678 var tree = parser.parse() catch |err| {
679 try stderr.print("error parsing file '{}': {}\n", file_path, err);675 try stderr.print("error parsing file '{}': {}\n", file_path, err);
680 continue;676 continue;
681 };677 };
682 defer tree.deinit();678 defer tree.deinit();
683679
684 var original_file_backup = try Buffer.init(allocator, file_path);
685 defer original_file_backup.deinit();
686 try original_file_backup.append(".backup");
687680
688 try os.rename(allocator, file_path, original_file_backup.toSliceConst());681 var error_it = tree.errors.iterator(0);
682 while (error_it.next()) |parse_error| {
683 const token = tree.tokens.at(parse_error.loc());
684 const loc = tree.tokenLocation(0, parse_error.loc());
685 try stderr.print("{}:{}:{}: error: ", file_path, loc.line + 1, loc.column + 1);
686 try tree.renderError(parse_error, stderr);
687 try stderr.print("\n{}\n", source_code[loc.line_start..loc.line_end]);
688 {
689 var i: usize = 0;
690 while (i < loc.column) : (i += 1) {
691 try stderr.write(" ");
692 }
693 }
694 {
695 const caret_count = token.end - token.start;
696 var i: usize = 0;
697 while (i < caret_count) : (i += 1) {
698 try stderr.write("~");
699 }
700 }
701 try stderr.write("\n");
702 }
703 if (tree.errors.len != 0) {
704 continue;
705 }
689706
690 try stderr.print("{}\n", file_path);707 try stderr.print("{}\n", file_path);
691708
692 // TODO: BufferedAtomicFile has some access problems.709 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
693 var out_file = try os.File.openWrite(allocator, file_path);710 defer baf.destroy();
694 defer out_file.close();
695711
696 var out_file_stream = io.FileOutStream.init(&out_file);712 try std.zig.render(allocator, baf.stream(), &tree);
697 try parser.renderSource(out_file_stream.stream, tree.root_node);713 try baf.finish();
698
699 if (!flags.present("keep-backups")) {
700 try os.deleteFile(allocator, original_file_backup.toSliceConst());
701 }
702 }714 }
703}715}
704716
src-self-hosted/module.zig+2-21
...@@ -8,9 +8,7 @@ const c = @import("c.zig");...@@ -8,9 +8,7 @@ const c = @import("c.zig");
8const builtin = @import("builtin");8const builtin = @import("builtin");
9const Target = @import("target.zig").Target;9const Target = @import("target.zig").Target;
10const warn = std.debug.warn;10const warn = std.debug.warn;
11const Tokenizer = std.zig.Tokenizer;
12const Token = std.zig.Token;11const Token = std.zig.Token;
13const Parser = std.zig.Parser;
14const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
1513
16pub const Module = struct {14pub const Module = struct {
...@@ -246,34 +244,17 @@ pub const Module = struct {...@@ -246,34 +244,17 @@ pub const Module = struct {
246244
247 warn("{}", source_code);245 warn("{}", source_code);
248246
249 warn("====tokenization:====\n");
250 {
251 var tokenizer = Tokenizer.init(source_code);
252 while (true) {
253 const token = tokenizer.next();
254 tokenizer.dump(token);
255 if (token.id == Token.Id.Eof) {
256 break;
257 }
258 }
259 }
260
261 warn("====parse:====\n");247 warn("====parse:====\n");
262248
263 var tokenizer = Tokenizer.init(source_code);249 var tree = try std.zig.parse(self.allocator, source_code);
264 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
265 defer parser.deinit();
266
267 var tree = try parser.parse();
268 defer tree.deinit();250 defer tree.deinit();
269251
270 var stderr_file = try std.io.getStdErr();252 var stderr_file = try std.io.getStdErr();
271 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);253 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
272 const out_stream = &stderr_file_out_stream.stream;254 const out_stream = &stderr_file_out_stream.stream;
273 try parser.renderAst(out_stream, tree.root_node);
274255
275 warn("====fmt:====\n");256 warn("====fmt:====\n");
276 try parser.renderSource(out_stream, tree.root_node);257 try std.zig.render(self.allocator, out_stream, &tree);
277258
278 warn("====ir:====\n");259 warn("====ir:====\n");
279 warn("TODO\n\n");260 warn("TODO\n\n");
src/analyze.cpp+4-2
...@@ -5931,8 +5931,8 @@ size_t type_id_len() {...@@ -5931,8 +5931,8 @@ size_t type_id_len() {
5931 return array_length(all_type_ids);5931 return array_length(all_type_ids);
5932}5932}
59335933
5934size_t type_id_index(TypeTableEntryId id) {5934size_t type_id_index(TypeTableEntry *entry) {
5935 switch (id) {5935 switch (entry->id) {
5936 case TypeTableEntryIdInvalid:5936 case TypeTableEntryIdInvalid:
5937 zig_unreachable();5937 zig_unreachable();
5938 case TypeTableEntryIdMetaType:5938 case TypeTableEntryIdMetaType:
...@@ -5952,6 +5952,8 @@ size_t type_id_index(TypeTableEntryId id) {...@@ -5952,6 +5952,8 @@ size_t type_id_index(TypeTableEntryId id) {
5952 case TypeTableEntryIdArray:5952 case TypeTableEntryIdArray:
5953 return 7;5953 return 7;
5954 case TypeTableEntryIdStruct:5954 case TypeTableEntryIdStruct:
5955 if (entry->data.structure.is_slice)
5956 return 25;
5955 return 8;5957 return 8;
5956 case TypeTableEntryIdNumLitFloat:5958 case TypeTableEntryIdNumLitFloat:
5957 return 9;5959 return 9;
src/analyze.hpp+1-1
...@@ -174,7 +174,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);...@@ -174,7 +174,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
174const char *type_id_name(TypeTableEntryId id);174const char *type_id_name(TypeTableEntryId id);
175TypeTableEntryId type_id_at_index(size_t index);175TypeTableEntryId type_id_at_index(size_t index);
176size_t type_id_len();176size_t type_id_len();
177size_t type_id_index(TypeTableEntryId id);177size_t type_id_index(TypeTableEntry *entry);
178TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);178TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
179bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);179bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
180LinkLib *create_link_lib(Buf *name);180LinkLib *create_link_lib(Buf *name);
src/bigint.cpp+4-6
...@@ -1259,12 +1259,11 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1259,12 +1259,11 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1259 bigint_normalize(dest);1259 bigint_normalize(dest);
1260 return;1260 return;
1261 }1261 }
1262 // TODO this code path is untested1262
1263 uint64_t first_digit = dest->data.digit;
1264 dest->digit_count = max(op1->digit_count, op2->digit_count);1263 dest->digit_count = max(op1->digit_count, op2->digit_count);
1265 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);1264 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);
1266 dest->data.digits[0] = first_digit;1265
1267 size_t i = 1;1266 size_t i = 0;
1268 for (; i < op1->digit_count && i < op2->digit_count; i += 1) {1267 for (; i < op1->digit_count && i < op2->digit_count; i += 1) {
1269 dest->data.digits[i] = op1_digits[i] & op2_digits[i];1268 dest->data.digits[i] = op1_digits[i] & op2_digits[i];
1270 }1269 }
...@@ -1412,7 +1411,6 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1412,7 +1411,6 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1412 return;1411 return;
1413 }1412 }
14141413
1415 // TODO this code path is untested
1416 size_t digit_shift_count = shift_amt / 64;1414 size_t digit_shift_count = shift_amt / 64;
1417 size_t leftover_shift_count = shift_amt % 64;1415 size_t leftover_shift_count = shift_amt % 64;
14181416
...@@ -1427,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1427,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1427 uint64_t digit = op1_digits[op_digit_index];1425 uint64_t digit = op1_digits[op_digit_index];
1428 size_t dest_digit_index = op_digit_index - digit_shift_count;1426 size_t dest_digit_index = op_digit_index - digit_shift_count;
1429 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);1427 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
1430 carry = (0xffffffffffffffffULL << leftover_shift_count) & digit;1428 carry = digit << (64 - leftover_shift_count);
14311429
1432 if (dest_digit_index == 0) { break; }1430 if (dest_digit_index == 0) { break; }
1433 op_digit_index -= 1;1431 op_digit_index -= 1;
src/codegen.cpp+4
...@@ -6260,6 +6260,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -6260,6 +6260,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
6260 const TypeTableEntryId id = type_id_at_index(i);6260 const TypeTableEntryId id = type_id_at_index(i);
6261 buf_appendf(contents, " %s,\n", type_id_name(id));6261 buf_appendf(contents, " %s,\n", type_id_name(id));
6262 }6262 }
6263 buf_appendf(contents, " Slice,\n");
6263 buf_appendf(contents, "};\n\n");6264 buf_appendf(contents, "};\n\n");
6264 }6265 }
6265 {6266 {
...@@ -6272,6 +6273,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -6272,6 +6273,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
6272 " Int: Int,\n"6273 " Int: Int,\n"
6273 " Float: Float,\n"6274 " Float: Float,\n"
6274 " Pointer: Pointer,\n"6275 " Pointer: Pointer,\n"
6276 " Slice: Slice,\n"
6275 " Array: Array,\n"6277 " Array: Array,\n"
6276 " Struct: Struct,\n"6278 " Struct: Struct,\n"
6277 " FloatLiteral: void,\n"6279 " FloatLiteral: void,\n"
...@@ -6307,6 +6309,8 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -6307,6 +6309,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
6307 " child: type,\n"6309 " child: type,\n"
6308 " };\n"6310 " };\n"
6309 "\n"6311 "\n"
6312 " pub const Slice = Pointer;\n"
6313 "\n"
6310 " pub const Array = struct {\n"6314 " pub const Array = struct {\n"
6311 " len: usize,\n"6315 " len: usize,\n"
6312 " child: type,\n"6316 " child: type,\n"
src/ir.cpp+59-43
...@@ -13736,7 +13736,16 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -13736,7 +13736,16 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
13736 create_const_enum(child_type, &field->value), child_type,13736 create_const_enum(child_type, &field->value), child_type,
13737 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);13737 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
13738 }13738 }
13739 } else if (child_type->id == TypeTableEntryIdUnion &&13739 }
13740 ScopeDecls *container_scope = get_container_scope(child_type);
13741 if (container_scope != nullptr) {
13742 auto entry = container_scope->decl_table.maybe_get(field_name);
13743 Tld *tld = entry ? entry->value : nullptr;
13744 if (tld) {
13745 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
13746 }
13747 }
13748 if (child_type->id == TypeTableEntryIdUnion &&
13740 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||13749 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
13741 child_type->data.unionation.decl_node->data.container_decl.auto_enum))13750 child_type->data.unionation.decl_node->data.container_decl.auto_enum))
13742 {13751 {
...@@ -13753,14 +13762,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -13753,14 +13762,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
13753 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);13762 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
13754 }13763 }
13755 }13764 }
13756 ScopeDecls *container_scope = get_container_scope(child_type);
13757 if (container_scope != nullptr) {
13758 auto entry = container_scope->decl_table.maybe_get(field_name);
13759 Tld *tld = entry ? entry->value : nullptr;
13760 if (tld) {
13761 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
13762 }
13763 }
13764 ir_add_error(ira, &field_ptr_instruction->base,13765 ir_add_error(ira, &field_ptr_instruction->base,
13765 buf_sprintf("container '%s' has no member called '%s'",13766 buf_sprintf("container '%s' has no member called '%s'",
13766 buf_ptr(&child_type->name), buf_ptr(field_name)));13767 buf_ptr(&child_type->name), buf_ptr(field_name)));
...@@ -14708,7 +14709,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source...@@ -14708,7 +14709,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
14708 }14709 }
1470914710
14710 if (value->value.type->id != TypeTableEntryIdUnion) {14711 if (value->value.type->id != TypeTableEntryIdUnion) {
14711 ir_add_error(ira, source_instr,14712 ir_add_error(ira, value,
14712 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));14713 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
14713 return ira->codegen->invalid_instruction;14714 return ira->codegen->invalid_instruction;
14714 }14715 }
...@@ -15784,11 +15785,10 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na...@@ -15784,11 +15785,10 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na
1578415785
15785 Buf field_name = BUF_INIT;15786 Buf field_name = BUF_INIT;
15786 buf_init_from_str(&field_name, type_name);15787 buf_init_from_str(&field_name, type_name);
15787 auto entry = type_info_scope->decl_table.maybe_get(&field_name);15788 auto entry = type_info_scope->decl_table.get(&field_name);
15788 buf_deinit(&field_name);15789 buf_deinit(&field_name);
15789 assert(entry != nullptr);
1579015790
15791 TldVar *tld = (TldVar *)entry->value;15791 TldVar *tld = (TldVar *)entry;
15792 assert(tld->base.id == TldIdVar);15792 assert(tld->base.id == TldIdVar);
1579315793
15794 VariableTableEntry *var = tld->var;15794 VariableTableEntry *var = tld->var;
...@@ -16070,6 +16070,38 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16070,6 +16070,38 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16070 enum_field_val->data.x_struct.fields = inner_fields;16070 enum_field_val->data.x_struct.fields = inner_fields;
16071 };16071 };
1607216072
16073 const auto create_ptr_like_type_info = [ira](const char *name, TypeTableEntry *ptr_type_entry) {
16074 ConstExprValue *result = create_const_vals(1);
16075 result->special = ConstValSpecialStatic;
16076 result->type = ir_type_info_get_type(ira, name);
16077
16078 ConstExprValue *fields = create_const_vals(4);
16079 result->data.x_struct.fields = fields;
16080
16081 // is_const: bool
16082 ensure_field_index(result->type, "is_const", 0);
16083 fields[0].special = ConstValSpecialStatic;
16084 fields[0].type = ira->codegen->builtin_types.entry_bool;
16085 fields[0].data.x_bool = ptr_type_entry->data.pointer.is_const;
16086 // is_volatile: bool
16087 ensure_field_index(result->type, "is_volatile", 1);
16088 fields[1].special = ConstValSpecialStatic;
16089 fields[1].type = ira->codegen->builtin_types.entry_bool;
16090 fields[1].data.x_bool = ptr_type_entry->data.pointer.is_volatile;
16091 // alignment: u32
16092 ensure_field_index(result->type, "alignment", 2);
16093 fields[2].special = ConstValSpecialStatic;
16094 fields[2].type = ira->codegen->builtin_types.entry_u32;
16095 bigint_init_unsigned(&fields[2].data.x_bigint, ptr_type_entry->data.pointer.alignment);
16096 // child: type
16097 ensure_field_index(result->type, "child", 3);
16098 fields[3].special = ConstValSpecialStatic;
16099 fields[3].type = ira->codegen->builtin_types.entry_type;
16100 fields[3].data.x_type = ptr_type_entry->data.pointer.child_type;
16101
16102 return result;
16103 };
16104
16073 ConstExprValue *result = nullptr;16105 ConstExprValue *result = nullptr;
16074 switch (type_entry->id)16106 switch (type_entry->id)
16075 {16107 {
...@@ -16138,34 +16170,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16138,34 +16170,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16138 }16170 }
16139 case TypeTableEntryIdPointer:16171 case TypeTableEntryIdPointer:
16140 {16172 {
16141 result = create_const_vals(1);16173 result = create_ptr_like_type_info("Pointer", type_entry);
16142 result->special = ConstValSpecialStatic;
16143 result->type = ir_type_info_get_type(ira, "Pointer");
16144
16145 ConstExprValue *fields = create_const_vals(4);
16146 result->data.x_struct.fields = fields;
16147
16148 // is_const: bool
16149 ensure_field_index(result->type, "is_const", 0);
16150 fields[0].special = ConstValSpecialStatic;
16151 fields[0].type = ira->codegen->builtin_types.entry_bool;
16152 fields[0].data.x_bool = type_entry->data.pointer.is_const;
16153 // is_volatile: bool
16154 ensure_field_index(result->type, "is_volatile", 1);
16155 fields[1].special = ConstValSpecialStatic;
16156 fields[1].type = ira->codegen->builtin_types.entry_bool;
16157 fields[1].data.x_bool = type_entry->data.pointer.is_volatile;
16158 // alignment: u32
16159 ensure_field_index(result->type, "alignment", 2);
16160 fields[2].special = ConstValSpecialStatic;
16161 fields[2].type = ira->codegen->builtin_types.entry_u32;
16162 bigint_init_unsigned(&fields[2].data.x_bigint, type_entry->data.pointer.alignment);
16163 // child: type
16164 ensure_field_index(result->type, "child", 3);
16165 fields[3].special = ConstValSpecialStatic;
16166 fields[3].type = ira->codegen->builtin_types.entry_type;
16167 fields[3].data.x_type = type_entry->data.pointer.child_type;
16168
16169 break;16174 break;
16170 }16175 }
16171 case TypeTableEntryIdArray:16176 case TypeTableEntryIdArray:
...@@ -16435,6 +16440,17 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16435,6 +16440,17 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16435 }16440 }
16436 case TypeTableEntryIdStruct:16441 case TypeTableEntryIdStruct:
16437 {16442 {
16443 if (type_entry->data.structure.is_slice) {
16444 Buf ptr_field_name = BUF_INIT;
16445 buf_init_from_str(&ptr_field_name, "ptr");
16446 TypeTableEntry *ptr_type = type_entry->data.structure.fields_by_name.get(&ptr_field_name)->type_entry;
16447 ensure_complete_type(ira->codegen, ptr_type);
16448 buf_deinit(&ptr_field_name);
16449
16450 result = create_ptr_like_type_info("Slice", ptr_type);
16451 break;
16452 }
16453
16438 result = create_const_vals(1);16454 result = create_const_vals(1);
16439 result->special = ConstValSpecialStatic;16455 result->special = ConstValSpecialStatic;
16440 result->type = ir_type_info_get_type(ira, "Struct");16456 result->type = ir_type_info_get_type(ira, "Struct");
...@@ -16621,7 +16637,7 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,...@@ -16621,7 +16637,7 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,
1662116637
16622 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16638 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16623 out_val->type = result_type;16639 out_val->type = result_type;
16624 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry->id));16640 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry));
1662516641
16626 ConstExprValue *payload = ir_make_type_info_value(ira, type_entry);16642 ConstExprValue *payload = ir_make_type_info_value(ira, type_entry);
16627 out_val->data.x_union.payload = payload;16643 out_val->data.x_union.payload = payload;
...@@ -16649,7 +16665,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,...@@ -16649,7 +16665,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
16649 TypeTableEntry *result_type = var_value->data.x_type;16665 TypeTableEntry *result_type = var_value->data.x_type;
1665016666
16651 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16667 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16652 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id));16668 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry));
16653 return result_type;16669 return result_type;
16654}16670}
1665516671
src/translate_c.cpp+6-2
...@@ -3669,6 +3669,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_...@@ -3669,6 +3669,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
3669 if (existing_entry) {3669 if (existing_entry) {
3670 return existing_entry->value;3670 return existing_entry->value;
3671 }3671 }
3672
3672 QualType child_qt = typedef_decl->getUnderlyingType();3673 QualType child_qt = typedef_decl->getUnderlyingType();
3673 Buf *type_name = buf_create_from_str(decl_name(typedef_decl));3674 Buf *type_name = buf_create_from_str(decl_name(typedef_decl));
36743675
...@@ -3702,16 +3703,19 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_...@@ -3702,16 +3703,19 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
3702 // use the name of this typedef3703 // use the name of this typedef
3703 // TODO3704 // TODO
37043705
3706 // trans_qual_type here might cause us to look at this typedef again so we put the item in the map first
3707 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3708 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
3709
3705 AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation());3710 AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation());
3706 if (type_node == nullptr) {3711 if (type_node == nullptr) {
3707 emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name));3712 emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name));
3708 c->decl_table.put(typedef_decl, nullptr);3713 c->decl_table.put(typedef_decl, nullptr);
3714 // TODO add global var with type_name equal to @compileError("unable to resolve C type")
3709 return nullptr;3715 return nullptr;
3710 }3716 }
3711 add_global_var(c, type_name, type_node);3717 add_global_var(c, type_name, type_node);
37123718
3713 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3714 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
3715 return symbol_node;3719 return symbol_node;
3716}3720}
37173721
std/array_list.zig+12-4
...@@ -28,11 +28,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -28,11 +28,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
28 };28 };
29 }29 }
3030
31 pub fn deinit(l: &Self) void {31 pub fn deinit(l: &const Self) void {
32 l.allocator.free(l.items);32 l.allocator.free(l.items);
33 }33 }
3434
35 pub fn toSlice(l: &Self) []align(A) T {35 pub fn toSlice(l: &const Self) []align(A) T {
36 return l.items[0..l.len];36 return l.items[0..l.len];
37 }37 }
3838
...@@ -150,7 +150,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -150,7 +150,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
150 }150 }
151 };151 };
152152
153 pub fn iterator(self: &Self) Iterator {153 pub fn iterator(self: &const Self) Iterator {
154 return Iterator { .list = self, .count = 0 };154 return Iterator { .list = self, .count = 0 };
155 }155 }
156 };156 };
...@@ -168,6 +168,14 @@ test "basic ArrayList test" {...@@ -168,6 +168,14 @@ test "basic ArrayList test" {
168 assert(list.items[i] == i32(i + 1));168 assert(list.items[i] == i32(i + 1));
169 }}169 }}
170170
171 for (list.toSlice()) |v, i| {
172 assert(v == i32(i + 1));
173 }
174
175 for (list.toSliceConst()) |v, i| {
176 assert(v == i32(i + 1));
177 }
178
171 assert(list.pop() == 10);179 assert(list.pop() == 10);
172 assert(list.len == 9);180 assert(list.len == 9);
173181
...@@ -228,4 +236,4 @@ test "insert ArrayList test" {...@@ -228,4 +236,4 @@ test "insert ArrayList test" {
228 const items = []const i32 { 1 };236 const items = []const i32 { 1 };
229 try list.insertSlice(0, items[0..0]);237 try list.insertSlice(0, items[0..0]);
230 assert(list.items[0] == 5);238 assert(list.items[0] == 5);
231}
\ No newline at end of file
239}
std/buf_map.zig+6-6
...@@ -18,10 +18,10 @@ pub const BufMap = struct {...@@ -18,10 +18,10 @@ pub const BufMap = struct {
18 return self;18 return self;
19 }19 }
2020
21 pub fn deinit(self: &BufMap) void {21 pub fn deinit(self: &const BufMap) void {
22 var it = self.hash_map.iterator();22 var it = self.hash_map.iterator();
23 while (true) {23 while (true) {
24 const entry = it.next() ?? break; 24 const entry = it.next() ?? break;
25 self.free(entry.key);25 self.free(entry.key);
26 self.free(entry.value);26 self.free(entry.value);
27 }27 }
...@@ -38,7 +38,7 @@ pub const BufMap = struct {...@@ -38,7 +38,7 @@ pub const BufMap = struct {
38 _ = try self.hash_map.put(key_copy, value_copy);38 _ = try self.hash_map.put(key_copy, value_copy);
39 }39 }
4040
41 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {41 pub fn get(self: &const BufMap, key: []const u8) ?[]const u8 {
42 const entry = self.hash_map.get(key) ?? return null;42 const entry = self.hash_map.get(key) ?? return null;
43 return entry.value;43 return entry.value;
44 }44 }
...@@ -57,11 +57,11 @@ pub const BufMap = struct {...@@ -57,11 +57,11 @@ pub const BufMap = struct {
57 return self.hash_map.iterator();57 return self.hash_map.iterator();
58 }58 }
5959
60 fn free(self: &BufMap, value: []const u8) void {60 fn free(self: &const BufMap, value: []const u8) void {
61 self.hash_map.allocator.free(value);61 self.hash_map.allocator.free(value);
62 }62 }
6363
64 fn copy(self: &BufMap, value: []const u8) ![]const u8 {64 fn copy(self: &const BufMap, value: []const u8) ![]const u8 {
65 return mem.dupe(self.hash_map.allocator, u8, value);65 return mem.dupe(self.hash_map.allocator, u8, value);
66 }66 }
67};67};
...@@ -87,4 +87,4 @@ test "BufMap" {...@@ -87,4 +87,4 @@ test "BufMap" {
8787
88 bufmap.delete("x");88 bufmap.delete("x");
89 assert(0 == bufmap.count());89 assert(0 == bufmap.count());
90}
\ No newline at end of file
90}
std/buf_set.zig+23-4
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const std = @import("index.zig");
1const HashMap = @import("hash_map.zig").HashMap;2const HashMap = @import("hash_map.zig").HashMap;
2const mem = @import("mem.zig");3const mem = @import("mem.zig");
3const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
5const assert = std.debug.assert;
46
5pub const BufSet = struct {7pub const BufSet = struct {
6 hash_map: BufSetHashMap,8 hash_map: BufSetHashMap,
...@@ -14,10 +16,10 @@ pub const BufSet = struct {...@@ -14,10 +16,10 @@ pub const BufSet = struct {
14 return self;16 return self;
15 }17 }
1618
17 pub fn deinit(self: &BufSet) void {19 pub fn deinit(self: &const BufSet) void {
18 var it = self.hash_map.iterator();20 var it = self.hash_map.iterator();
19 while (true) {21 while (true) {
20 const entry = it.next() ?? break; 22 const entry = it.next() ?? break;
21 self.free(entry.key);23 self.free(entry.key);
22 }24 }
2325
...@@ -49,13 +51,30 @@ pub const BufSet = struct {...@@ -49,13 +51,30 @@ pub const BufSet = struct {
49 return self.hash_map.allocator;51 return self.hash_map.allocator;
50 }52 }
5153
52 fn free(self: &BufSet, value: []const u8) void {54 fn free(self: &const BufSet, value: []const u8) void {
53 self.hash_map.allocator.free(value);55 self.hash_map.allocator.free(value);
54 }56 }
5557
56 fn copy(self: &BufSet, value: []const u8) ![]const u8 {58 fn copy(self: &const BufSet, value: []const u8) ![]const u8 {
57 const result = try self.hash_map.allocator.alloc(u8, value.len);59 const result = try self.hash_map.allocator.alloc(u8, value.len);
58 mem.copy(u8, result, value);60 mem.copy(u8, result, value);
59 return result;61 return result;
60 }62 }
61};63};
64
65test "BufSet" {
66 var direct_allocator = std.heap.DirectAllocator.init();
67 defer direct_allocator.deinit();
68
69 var bufset = BufSet.init(&direct_allocator.allocator);
70 defer bufset.deinit();
71
72 try bufset.put("x");
73 assert(bufset.count() == 1);
74 bufset.delete("x");
75 assert(bufset.count() == 0);
76
77 try bufset.put("x");
78 try bufset.put("y");
79 try bufset.put("z");
80}
std/buffer.zig+2-2
...@@ -66,7 +66,7 @@ pub const Buffer = struct {...@@ -66,7 +66,7 @@ pub const Buffer = struct {
66 self.list.deinit();66 self.list.deinit();
67 }67 }
6868
69 pub fn toSlice(self: &Buffer) []u8 {69 pub fn toSlice(self: &const Buffer) []u8 {
70 return self.list.toSlice()[0..self.len()];70 return self.list.toSlice()[0..self.len()];
71 }71 }
7272
...@@ -166,5 +166,5 @@ test "simple Buffer" {...@@ -166,5 +166,5 @@ test "simple Buffer" {
166 assert(buf.endsWith("orld"));166 assert(buf.endsWith("orld"));
167167
168 try buf2.resize(4);168 try buf2.resize(4);
169 assert(buf.startsWith(buf2.toSliceConst()));169 assert(buf.startsWith(buf2.toSlice()));
170}170}
std/hash_map.zig+8-7
...@@ -74,7 +74,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -74,7 +74,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
74 };74 };
75 }75 }
7676
77 pub fn deinit(hm: &Self) void {77 pub fn deinit(hm: &const Self) void {
78 hm.allocator.free(hm.entries);78 hm.allocator.free(hm.entries);
79 }79 }
8080
...@@ -114,14 +114,14 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -114,14 +114,14 @@ pub fn HashMap(comptime K: type, comptime V: type,
114 return hm.internalPut(key, value);114 return hm.internalPut(key, value);
115 }115 }
116116
117 pub fn get(hm: &Self, key: K) ?&Entry {117 pub fn get(hm: &const Self, key: K) ?&Entry {
118 if (hm.entries.len == 0) {118 if (hm.entries.len == 0) {
119 return null;119 return null;
120 }120 }
121 return hm.internalGet(key);121 return hm.internalGet(key);
122 }122 }
123123
124 pub fn contains(hm: &Self, key: K) bool {124 pub fn contains(hm: &const Self, key: K) bool {
125 return hm.get(key) != null;125 return hm.get(key) != null;
126 }126 }
127127
...@@ -230,7 +230,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -230,7 +230,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
230 unreachable; // put into a full map230 unreachable; // put into a full map
231 }231 }
232232
233 fn internalGet(hm: &Self, key: K) ?&Entry {233 fn internalGet(hm: &const Self, key: K) ?&Entry {
234 const start_index = hm.keyToIndex(key);234 const start_index = hm.keyToIndex(key);
235 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {235 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
236 const index = (start_index + roll_over) % hm.entries.len;236 const index = (start_index + roll_over) % hm.entries.len;
...@@ -242,7 +242,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -242,7 +242,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
242 return null;242 return null;
243 }243 }
244244
245 fn keyToIndex(hm: &Self, key: K) usize {245 fn keyToIndex(hm: &const Self, key: K) usize {
246 return usize(hash(key)) % hm.entries.len;246 return usize(hash(key)) % hm.entries.len;
247 }247 }
248 };248 };
...@@ -264,6 +264,7 @@ test "basic hash map usage" {...@@ -264,6 +264,7 @@ test "basic hash map usage" {
264 assert(??(map.put(5, 66) catch unreachable) == 55);264 assert(??(map.put(5, 66) catch unreachable) == 55);
265 assert(??(map.put(5, 55) catch unreachable) == 66);265 assert(??(map.put(5, 55) catch unreachable) == 66);
266266
267 assert(map.contains(2));
267 assert((??map.get(2)).value == 22);268 assert((??map.get(2)).value == 22);
268 _ = map.remove(2);269 _ = map.remove(2);
269 assert(map.remove(2) == null);270 assert(map.remove(2) == null);
...@@ -273,7 +274,7 @@ test "basic hash map usage" {...@@ -273,7 +274,7 @@ test "basic hash map usage" {
273test "iterator hash map" {274test "iterator hash map" {
274 var direct_allocator = std.heap.DirectAllocator.init();275 var direct_allocator = std.heap.DirectAllocator.init();
275 defer direct_allocator.deinit();276 defer direct_allocator.deinit();
276 277
277 var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);278 var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
278 defer reset_map.deinit();279 defer reset_map.deinit();
279280
...@@ -315,4 +316,4 @@ fn hash_i32(x: i32) u32 {...@@ -315,4 +316,4 @@ fn hash_i32(x: i32) u32 {
315316
316fn eql_i32(a: i32, b: i32) bool {317fn eql_i32(a: i32, b: i32) bool {
317 return a == b;318 return a == b;
318}
\ No newline at end of file
319}
std/index.zig+2
...@@ -7,6 +7,7 @@ pub const BufferOutStream = @import("buffer.zig").BufferOutStream;...@@ -7,6 +7,7 @@ pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
7pub const HashMap = @import("hash_map.zig").HashMap;7pub const HashMap = @import("hash_map.zig").HashMap;
8pub const LinkedList = @import("linked_list.zig").LinkedList;8pub const LinkedList = @import("linked_list.zig").LinkedList;
9pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;9pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;
10pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
1011
11pub const atomic = @import("atomic/index.zig");12pub const atomic = @import("atomic/index.zig");
12pub const base64 = @import("base64.zig");13pub const base64 = @import("base64.zig");
...@@ -43,6 +44,7 @@ test "std" {...@@ -43,6 +44,7 @@ test "std" {
43 _ = @import("buffer.zig");44 _ = @import("buffer.zig");
44 _ = @import("hash_map.zig");45 _ = @import("hash_map.zig");
45 _ = @import("linked_list.zig");46 _ = @import("linked_list.zig");
47 _ = @import("segmented_list.zig");
4648
47 _ = @import("base64.zig");49 _ = @import("base64.zig");
48 _ = @import("build.zig");50 _ = @import("build.zig");
std/math/index.zig+26
...@@ -558,6 +558,32 @@ test "math.floorPowerOfTwo" {...@@ -558,6 +558,32 @@ test "math.floorPowerOfTwo" {
558 comptime testFloorPowerOfTwo();558 comptime testFloorPowerOfTwo();
559}559}
560560
561pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
562 assert(x != 0);
563 return Log2Int(T)(T.bit_count - 1 - @clz(x));
564}
565
566pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
567 assert(x != 0);
568 const log2_val = log2_int(T, x);
569 if (T(1) << log2_val == x)
570 return log2_val;
571 return log2_val + 1;
572}
573
574test "std.math.log2_int_ceil" {
575 assert(log2_int_ceil(u32, 1) == 0);
576 assert(log2_int_ceil(u32, 2) == 1);
577 assert(log2_int_ceil(u32, 3) == 2);
578 assert(log2_int_ceil(u32, 4) == 2);
579 assert(log2_int_ceil(u32, 5) == 3);
580 assert(log2_int_ceil(u32, 6) == 3);
581 assert(log2_int_ceil(u32, 7) == 3);
582 assert(log2_int_ceil(u32, 8) == 3);
583 assert(log2_int_ceil(u32, 9) == 4);
584 assert(log2_int_ceil(u32, 10) == 4);
585}
586
561fn testFloorPowerOfTwo() void {587fn testFloorPowerOfTwo() void {
562 assert(floorPowerOfTwo(u32, 63) == 32);588 assert(floorPowerOfTwo(u32, 63) == 32);
563 assert(floorPowerOfTwo(u32, 64) == 64);589 assert(floorPowerOfTwo(u32, 64) == 64);
std/math/log2.zig+1-6
...@@ -31,17 +31,12 @@ pub fn log2(x: var) @typeOf(x) {...@@ -31,17 +31,12 @@ pub fn log2(x: var) @typeOf(x) {
31 return result;31 return result;
32 },32 },
33 TypeId.Int => {33 TypeId.Int => {
34 return log2_int(T, x);34 return math.log2_int(T, x);
35 },35 },
36 else => @compileError("log2 not implemented for " ++ @typeName(T)),36 else => @compileError("log2 not implemented for " ++ @typeName(T)),
37 }37 }
38}38}
3939
40pub fn log2_int(comptime T: type, x: T) T {
41 assert(x != 0);
42 return T.bit_count - 1 - T(@clz(x));
43}
44
45pub fn log2_32(x_: f32) f32 {40pub fn log2_32(x_: f32) f32 {
46 const ivln2hi: f32 = 1.4428710938e+00;41 const ivln2hi: f32 = 1.4428710938e+00;
47 const ivln2lo: f32 = -1.7605285393e-04;42 const ivln2lo: f32 = -1.7605285393e-04;
std/segmented_list.zig created+379
...@@ -0,0 +1,379 @@
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4
5// Imagine that `fn at(self: &Self, index: usize) &T` is a customer asking for a box
6// from a warehouse, based on a flat array, boxes ordered from 0 to N - 1.
7// But the warehouse actually stores boxes in shelves of increasing powers of 2 sizes.
8// So when the customer requests a box index, we have to translate it to shelf index
9// and box index within that shelf. Illustration:
10//
11// customer indexes:
12// shelf 0: 0
13// shelf 1: 1 2
14// shelf 2: 3 4 5 6
15// shelf 3: 7 8 9 10 11 12 13 14
16// shelf 4: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
17// shelf 5: 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
18// ...
19//
20// warehouse indexes:
21// shelf 0: 0
22// shelf 1: 0 1
23// shelf 2: 0 1 2 3
24// shelf 3: 0 1 2 3 4 5 6 7
25// shelf 4: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
26// shelf 5: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
27// ...
28//
29// With this arrangement, here are the equations to get the shelf index and
30// box index based on customer box index:
31//
32// shelf_index = floor(log2(customer_index + 1))
33// shelf_count = ceil(log2(box_count + 1))
34// box_index = customer_index + 1 - 2 ** shelf
35// shelf_size = 2 ** shelf_index
36//
37// Now we complicate it a little bit further by adding a preallocated shelf, which must be
38// a power of 2:
39// prealloc=4
40//
41// customer indexes:
42// prealloc: 0 1 2 3
43// shelf 0: 4 5 6 7 8 9 10 11
44// shelf 1: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
45// shelf 2: 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
46// ...
47//
48// warehouse indexes:
49// prealloc: 0 1 2 3
50// shelf 0: 0 1 2 3 4 5 6 7
51// shelf 1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
52// shelf 2: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
53// ...
54//
55// Now the equations are:
56//
57// shelf_index = floor(log2(customer_index + prealloc)) - log2(prealloc) - 1
58// shelf_count = ceil(log2(box_count + prealloc)) - log2(prealloc) - 1
59// box_index = customer_index + prealloc - 2 ** (log2(prealloc) + 1 + shelf)
60// shelf_size = prealloc * 2 ** (shelf_index + 1)
61
62/// This is a stack data structure where pointers to indexes have the same lifetime as the data structure
63/// itself, unlike ArrayList where push() invalidates all existing element pointers.
64/// The tradeoff is that elements are not guaranteed to be contiguous. For that, use ArrayList.
65/// Note however that most elements are contiguous, making this data structure cache-friendly.
66///
67/// Because it never has to copy elements from an old location to a new location, it does not require
68/// its elements to be copyable, and it avoids wasting memory when backed by an ArenaAllocator.
69/// Note that the push() and pop() convenience methods perform a copy, but you can instead use
70/// addOne(), at(), setCapacity(), and shrinkCapacity() to avoid copying items.
71///
72/// This data structure has O(1) push and O(1) pop.
73///
74/// It supports preallocated elements, making it especially well suited when the expected maximum
75/// size is small. `prealloc_item_count` must be 0, or a power of 2.
76pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
77 return struct {
78 const Self = this;
79 const prealloc_exp = blk: {
80 // we don't use the prealloc_exp constant when prealloc_item_count is 0.
81 assert(prealloc_item_count != 0);
82
83 const value = std.math.log2_int(usize, prealloc_item_count);
84 assert((1 << value) == prealloc_item_count); // prealloc_item_count must be a power of 2
85 break :blk @typeOf(1)(value);
86 };
87 const ShelfIndex = std.math.Log2Int(usize);
88
89 prealloc_segment: [prealloc_item_count]T,
90 dynamic_segments: []&T,
91 allocator: &Allocator,
92 len: usize,
93
94 pub const prealloc_count = prealloc_item_count;
95
96 /// Deinitialize with `deinit`
97 pub fn init(allocator: &Allocator) Self {
98 return Self {
99 .allocator = allocator,
100 .len = 0,
101 .prealloc_segment = undefined,
102 .dynamic_segments = []&T{},
103 };
104 }
105
106 pub fn deinit(self: &Self) void {
107 self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);
108 self.allocator.free(self.dynamic_segments);
109 *self = undefined;
110 }
111
112 pub fn at(self: &Self, i: usize) &T {
113 assert(i < self.len);
114 return self.uncheckedAt(i);
115 }
116
117 pub fn count(self: &const Self) usize {
118 return self.len;
119 }
120
121 pub fn push(self: &Self, item: &const T) !void {
122 const new_item_ptr = try self.addOne();
123 *new_item_ptr = *item;
124 }
125
126 pub fn pushMany(self: &Self, items: []const T) !void {
127 for (items) |item| {
128 try self.push(item);
129 }
130 }
131
132 pub fn pop(self: &Self) ?T {
133 if (self.len == 0)
134 return null;
135
136 const index = self.len - 1;
137 const result = *self.uncheckedAt(index);
138 self.len = index;
139 return result;
140 }
141
142 pub fn addOne(self: &Self) !&T {
143 const new_length = self.len + 1;
144 try self.growCapacity(new_length);
145 const result = self.uncheckedAt(self.len);
146 self.len = new_length;
147 return result;
148 }
149
150 /// Grows or shrinks capacity to match usage.
151 pub fn setCapacity(self: &Self, new_capacity: usize) !void {
152 if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
153 return self.shrinkCapacity(new_capacity);
154 } else {
155 return self.growCapacity(new_capacity);
156 }
157 }
158
159 /// Only grows capacity, or retains current capacity
160 pub fn growCapacity(self: &Self, new_capacity: usize) !void {
161 const new_cap_shelf_count = shelfCount(new_capacity);
162 const old_shelf_count = ShelfIndex(self.dynamic_segments.len);
163 if (new_cap_shelf_count > old_shelf_count) {
164 self.dynamic_segments = try self.allocator.realloc(&T, self.dynamic_segments, new_cap_shelf_count);
165 var i = old_shelf_count;
166 errdefer {
167 self.freeShelves(i, old_shelf_count);
168 self.dynamic_segments = self.allocator.shrink(&T, self.dynamic_segments, old_shelf_count);
169 }
170 while (i < new_cap_shelf_count) : (i += 1) {
171 self.dynamic_segments[i] = (try self.allocator.alloc(T, shelfSize(i))).ptr;
172 }
173 }
174 }
175
176 /// Only shrinks capacity or retains current capacity
177 pub fn shrinkCapacity(self: &Self, new_capacity: usize) void {
178 if (new_capacity <= prealloc_item_count) {
179 const len = ShelfIndex(self.dynamic_segments.len);
180 self.freeShelves(len, 0);
181 self.allocator.free(self.dynamic_segments);
182 self.dynamic_segments = []&T{};
183 return;
184 }
185
186 const new_cap_shelf_count = shelfCount(new_capacity);
187 const old_shelf_count = ShelfIndex(self.dynamic_segments.len);
188 assert(new_cap_shelf_count <= old_shelf_count);
189 if (new_cap_shelf_count == old_shelf_count) {
190 return;
191 }
192
193 self.freeShelves(old_shelf_count, new_cap_shelf_count);
194 self.dynamic_segments = self.allocator.shrink(&T, self.dynamic_segments, new_cap_shelf_count);
195 }
196
197 pub fn uncheckedAt(self: &Self, index: usize) &T {
198 if (index < prealloc_item_count) {
199 return &self.prealloc_segment[index];
200 }
201 const shelf_index = shelfIndex(index);
202 const box_index = boxIndex(index, shelf_index);
203 return &self.dynamic_segments[shelf_index][box_index];
204 }
205
206 fn shelfCount(box_count: usize) ShelfIndex {
207 if (prealloc_item_count == 0) {
208 return std.math.log2_int_ceil(usize, box_count + 1);
209 }
210 return std.math.log2_int_ceil(usize, box_count + prealloc_item_count) - prealloc_exp - 1;
211 }
212
213 fn shelfSize(shelf_index: ShelfIndex) usize {
214 if (prealloc_item_count == 0) {
215 return usize(1) << shelf_index;
216 }
217 return usize(1) << (shelf_index + (prealloc_exp + 1));
218 }
219
220 fn shelfIndex(list_index: usize) ShelfIndex {
221 if (prealloc_item_count == 0) {
222 return std.math.log2_int(usize, list_index + 1);
223 }
224 return std.math.log2_int(usize, list_index + prealloc_item_count) - prealloc_exp - 1;
225 }
226
227 fn boxIndex(list_index: usize, shelf_index: ShelfIndex) usize {
228 if (prealloc_item_count == 0) {
229 return (list_index + 1) - (usize(1) << shelf_index);
230 }
231 return list_index + prealloc_item_count - (usize(1) << ((prealloc_exp + 1) + shelf_index));
232 }
233
234 fn freeShelves(self: &Self, from_count: ShelfIndex, to_count: ShelfIndex) void {
235 var i = from_count;
236 while (i != to_count) {
237 i -= 1;
238 self.allocator.free(self.dynamic_segments[i][0..shelfSize(i)]);
239 }
240 }
241
242 pub const Iterator = struct {
243 list: &Self,
244 index: usize,
245 box_index: usize,
246 shelf_index: ShelfIndex,
247 shelf_size: usize,
248
249 pub fn next(it: &Iterator) ?&T {
250 if (it.index >= it.list.len)
251 return null;
252 if (it.index < prealloc_item_count) {
253 const ptr = &it.list.prealloc_segment[it.index];
254 it.index += 1;
255 if (it.index == prealloc_item_count) {
256 it.box_index = 0;
257 it.shelf_index = 0;
258 it.shelf_size = prealloc_item_count * 2;
259 }
260 return ptr;
261 }
262
263 const ptr = &it.list.dynamic_segments[it.shelf_index][it.box_index];
264 it.index += 1;
265 it.box_index += 1;
266 if (it.box_index == it.shelf_size) {
267 it.shelf_index += 1;
268 it.box_index = 0;
269 it.shelf_size *= 2;
270 }
271 return ptr;
272 }
273
274 pub fn prev(it: &Iterator) ?&T {
275 if (it.index == 0)
276 return null;
277
278 it.index -= 1;
279 if (it.index < prealloc_item_count)
280 return &it.list.prealloc_segment[it.index];
281
282 if (it.box_index == 0) {
283 it.shelf_index -= 1;
284 it.shelf_size /= 2;
285 it.box_index = it.shelf_size - 1;
286 } else {
287 it.box_index -= 1;
288 }
289
290 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
291 }
292
293 pub fn peek(it: &Iterator) ?&T {
294 if (it.index >= it.list.len)
295 return null;
296 if (it.index < prealloc_item_count)
297 return &it.list.prealloc_segment[it.index];
298
299 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
300 }
301 };
302
303 pub fn iterator(self: &Self, start_index: usize) Iterator {
304 var it = Iterator {
305 .list = self,
306 .index = start_index,
307 .shelf_index = undefined,
308 .box_index = undefined,
309 .shelf_size = undefined,
310 };
311 if (start_index >= prealloc_item_count) {
312 it.shelf_index = shelfIndex(start_index);
313 it.box_index = boxIndex(start_index, it.shelf_index);
314 it.shelf_size = shelfSize(it.shelf_index);
315 }
316 return it;
317 }
318 };
319}
320
321test "std.SegmentedList" {
322 var da = std.heap.DirectAllocator.init();
323 defer da.deinit();
324 var a = &da.allocator;
325
326 try testSegmentedList(0, a);
327 try testSegmentedList(1, a);
328 try testSegmentedList(2, a);
329 try testSegmentedList(4, a);
330 try testSegmentedList(8, a);
331 try testSegmentedList(16, a);
332}
333
334fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
335 var list = SegmentedList(i32, prealloc).init(allocator);
336 defer list.deinit();
337
338 {var i: usize = 0; while (i < 100) : (i += 1) {
339 try list.push(i32(i + 1));
340 assert(list.len == i + 1);
341 }}
342
343 {var i: usize = 0; while (i < 100) : (i += 1) {
344 assert(*list.at(i) == i32(i + 1));
345 }}
346
347 {
348 var it = list.iterator(0);
349 var x: i32 = 0;
350 while (it.next()) |item| {
351 x += 1;
352 assert(*item == x);
353 }
354 assert(x == 100);
355 while (it.prev()) |item| : (x -= 1) {
356 assert(*item == x);
357 }
358 assert(x == 0);
359 }
360
361 assert(??list.pop() == 100);
362 assert(list.len == 99);
363
364 try list.pushMany([]i32 { 1, 2, 3 });
365 assert(list.len == 102);
366 assert(??list.pop() == 3);
367 assert(??list.pop() == 2);
368 assert(??list.pop() == 1);
369 assert(list.len == 99);
370
371 try list.pushMany([]const i32 {});
372 assert(list.len == 99);
373
374 var i: i32 = 99;
375 while (list.pop()) |item| : (i -= 1) {
376 assert(item == i);
377 list.shrinkCapacity(list.len);
378 }
379}
std/zig/ast.zig+563-247
...@@ -1,12 +1,227 @@...@@ -1,12 +1,227 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;3const SegmentedList = std.SegmentedList;
4const Token = std.zig.Token;
5const mem = std.mem;4const mem = std.mem;
5const Token = std.zig.Token;
6
7pub const TokenIndex = usize;
8
9pub const Tree = struct {
10 source: []const u8,
11 tokens: TokenList,
12 root_node: &Node.Root,
13 arena_allocator: std.heap.ArenaAllocator,
14 errors: ErrorList,
15
16 pub const TokenList = SegmentedList(Token, 64);
17 pub const ErrorList = SegmentedList(Error, 0);
18
19 pub fn deinit(self: &Tree) void {
20 self.arena_allocator.deinit();
21 }
22
23 pub fn renderError(self: &Tree, parse_error: &Error, stream: var) !void {
24 return parse_error.render(&self.tokens, stream);
25 }
26
27 pub fn tokenSlice(self: &Tree, token_index: TokenIndex) []const u8 {
28 return self.tokenSlicePtr(self.tokens.at(token_index));
29 }
30
31 pub fn tokenSlicePtr(self: &Tree, token: &const Token) []const u8 {
32 return self.source[token.start..token.end];
33 }
34
35 pub const Location = struct {
36 line: usize,
37 column: usize,
38 line_start: usize,
39 line_end: usize,
40 };
41
42 pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {
43 var loc = Location {
44 .line = 0,
45 .column = 0,
46 .line_start = start_index,
47 .line_end = self.source.len,
48 };
49 const token_start = token.start;
50 for (self.source[start_index..]) |c, i| {
51 if (i + start_index == token_start) {
52 loc.line_end = i + start_index;
53 while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') : (loc.line_end += 1) {}
54 return loc;
55 }
56 if (c == '\n') {
57 loc.line += 1;
58 loc.column = 0;
59 loc.line_start = i + 1;
60 } else {
61 loc.column += 1;
62 }
63 }
64 return loc;
65 }
66
67 pub fn tokenLocation(self: &Tree, start_index: usize, token_index: TokenIndex) Location {
68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
69 }
70};
71
72pub const Error = union(enum) {
73 InvalidToken: InvalidToken,
74 ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
75 ExpectedAggregateKw: ExpectedAggregateKw,
76 UnattachedDocComment: UnattachedDocComment,
77 ExpectedEqOrSemi: ExpectedEqOrSemi,
78 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
79 ExpectedLabelable: ExpectedLabelable,
80 ExpectedInlinable: ExpectedInlinable,
81 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
82 ExpectedCall: ExpectedCall,
83 ExpectedCallOrFnProto: ExpectedCallOrFnProto,
84 ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
85 ExtraAlignQualifier: ExtraAlignQualifier,
86 ExtraConstQualifier: ExtraConstQualifier,
87 ExtraVolatileQualifier: ExtraVolatileQualifier,
88 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
89 ExpectedToken: ExpectedToken,
90 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
91
92 pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
93 switch (*self) {
94 // TODO https://github.com/zig-lang/zig/issues/683
95 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
96 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
97 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
98 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
99 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
100 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
101 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
102 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
103 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
104 @TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
105 @TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
106 @TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
107 @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
108 @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
109 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
110 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
111 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
112 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
113 }
114 }
115
116 pub fn loc(self: &Error) TokenIndex {
117 switch (*self) {
118 // TODO https://github.com/zig-lang/zig/issues/683
119 @TagType(Error).InvalidToken => |x| return x.token,
120 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
121 @TagType(Error).ExpectedAggregateKw => |x| return x.token,
122 @TagType(Error).UnattachedDocComment => |x| return x.token,
123 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
124 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
125 @TagType(Error).ExpectedLabelable => |x| return x.token,
126 @TagType(Error).ExpectedInlinable => |x| return x.token,
127 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
128 @TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
129 @TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
130 @TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
131 @TagType(Error).ExtraAlignQualifier => |x| return x.token,
132 @TagType(Error).ExtraConstQualifier => |x| return x.token,
133 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
134 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
135 @TagType(Error).ExpectedToken => |x| return x.token,
136 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
137 }
138 }
139
140 pub const InvalidToken = SingleTokenError("Invalid token {}");
141 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
142 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++
143 @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++
144 @tagName(Token.Id.Keyword_enum) ++ ", found {}");
145 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
146 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
147 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
148 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
149 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++
150 @tagName(Token.Id.Identifier) ++ ", found {}");
151 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
152 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
153
154 pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
155 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
156 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
157 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
158
159 pub const ExpectedCall = struct {
160 node: &Node,
161
162 pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
163 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}",
164 @tagName(self.node.id));
165 }
166 };
167
168 pub const ExpectedCallOrFnProto = struct {
169 node: &Node,
170
171 pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
172 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
173 @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
174 }
175 };
176
177 pub const ExpectedToken = struct {
178 token: TokenIndex,
179 expected_id: @TagType(Token.Id),
180
181 pub fn render(self: &ExpectedToken, tokens: &Tree.TokenList, stream: var) !void {
182 const token_name = @tagName(tokens.at(self.token).id);
183 return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
184 }
185 };
186
187 pub const ExpectedCommaOrEnd = struct {
188 token: TokenIndex,
189 end_id: @TagType(Token.Id),
190
191 pub fn render(self: &ExpectedCommaOrEnd, tokens: &Tree.TokenList, stream: var) !void {
192 const token_name = @tagName(tokens.at(self.token).id);
193 return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name);
194 }
195 };
196
197 fn SingleTokenError(comptime msg: []const u8) type {
198 return struct {
199 const ThisError = this;
200
201 token: TokenIndex,
202
203 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
204 const token_name = @tagName(tokens.at(self.token).id);
205 return stream.print(msg, token_name);
206 }
207 };
208 }
209
210 fn SimpleError(comptime msg: []const u8) type {
211 return struct {
212 const ThisError = this;
213
214 token: TokenIndex,
215
216 pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
217 return stream.write(msg);
218 }
219 };
220 }
221};
6222
7pub const Node = struct {223pub const Node = struct {
8 id: Id,224 id: Id,
9 same_line_comment: ?&Token,
10225
11 pub const Id = enum {226 pub const Id = enum {
12 // Top level227 // Top level
...@@ -95,7 +310,7 @@ pub const Node = struct {...@@ -95,7 +310,7 @@ pub const Node = struct {
95 unreachable;310 unreachable;
96 }311 }
97312
98 pub fn firstToken(base: &Node) Token {313 pub fn firstToken(base: &Node) TokenIndex {
99 comptime var i = 0;314 comptime var i = 0;
100 inline while (i < @memberCount(Id)) : (i += 1) {315 inline while (i < @memberCount(Id)) : (i += 1) {
101 if (base.id == @field(Id, @memberName(Id, i))) {316 if (base.id == @field(Id, @memberName(Id, i))) {
...@@ -106,7 +321,7 @@ pub const Node = struct {...@@ -106,7 +321,7 @@ pub const Node = struct {
106 unreachable;321 unreachable;
107 }322 }
108323
109 pub fn lastToken(base: &Node) Token {324 pub fn lastToken(base: &Node) TokenIndex {
110 comptime var i = 0;325 comptime var i = 0;
111 inline while (i < @memberCount(Id)) : (i += 1) {326 inline while (i < @memberCount(Id)) : (i += 1) {
112 if (base.id == @field(Id, @memberName(Id, i))) {327 if (base.id == @field(Id, @memberName(Id, i))) {
...@@ -127,11 +342,87 @@ pub const Node = struct {...@@ -127,11 +342,87 @@ pub const Node = struct {
127 unreachable;342 unreachable;
128 }343 }
129344
345 pub fn requireSemiColon(base: &const Node) bool {
346 var n = base;
347 while (true) {
348 switch (n.id) {
349 Id.Root,
350 Id.StructField,
351 Id.UnionTag,
352 Id.EnumTag,
353 Id.ParamDecl,
354 Id.Block,
355 Id.Payload,
356 Id.PointerPayload,
357 Id.PointerIndexPayload,
358 Id.Switch,
359 Id.SwitchCase,
360 Id.SwitchElse,
361 Id.FieldInitializer,
362 Id.DocComment,
363 Id.LineComment,
364 Id.TestDecl => return false,
365 Id.While => {
366 const while_node = @fieldParentPtr(While, "base", n);
367 if (while_node.@"else") |@"else"| {
368 n = @"else".base;
369 continue;
370 }
371
372 return while_node.body.id != Id.Block;
373 },
374 Id.For => {
375 const for_node = @fieldParentPtr(For, "base", n);
376 if (for_node.@"else") |@"else"| {
377 n = @"else".base;
378 continue;
379 }
380
381 return for_node.body.id != Id.Block;
382 },
383 Id.If => {
384 const if_node = @fieldParentPtr(If, "base", n);
385 if (if_node.@"else") |@"else"| {
386 n = @"else".base;
387 continue;
388 }
389
390 return if_node.body.id != Id.Block;
391 },
392 Id.Else => {
393 const else_node = @fieldParentPtr(Else, "base", n);
394 n = else_node.body;
395 continue;
396 },
397 Id.Defer => {
398 const defer_node = @fieldParentPtr(Defer, "base", n);
399 return defer_node.expr.id != Id.Block;
400 },
401 Id.Comptime => {
402 const comptime_node = @fieldParentPtr(Comptime, "base", n);
403 return comptime_node.expr.id != Id.Block;
404 },
405 Id.Suspend => {
406 const suspend_node = @fieldParentPtr(Suspend, "base", n);
407 if (suspend_node.body) |body| {
408 return body.id != Id.Block;
409 }
410
411 return true;
412 },
413 else => return true,
414 }
415 }
416 }
417
418
130 pub const Root = struct {419 pub const Root = struct {
131 base: Node,420 base: Node,
132 doc_comments: ?&DocComment,421 doc_comments: ?&DocComment,
133 decls: ArrayList(&Node),422 decls: DeclList,
134 eof_token: Token,423 eof_token: TokenIndex,
424
425 pub const DeclList = SegmentedList(&Node, 4);
135426
136 pub fn iterate(self: &Root, index: usize) ?&Node {427 pub fn iterate(self: &Root, index: usize) ?&Node {
137 if (index < self.decls.len) {428 if (index < self.decls.len) {
...@@ -140,29 +431,29 @@ pub const Node = struct {...@@ -140,29 +431,29 @@ pub const Node = struct {
140 return null;431 return null;
141 }432 }
142433
143 pub fn firstToken(self: &Root) Token {434 pub fn firstToken(self: &Root) TokenIndex {
144 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();435 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(0)).firstToken();
145 }436 }
146437
147 pub fn lastToken(self: &Root) Token {438 pub fn lastToken(self: &Root) TokenIndex {
148 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();439 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(self.decls.len - 1)).lastToken();
149 }440 }
150 };441 };
151442
152 pub const VarDecl = struct {443 pub const VarDecl = struct {
153 base: Node,444 base: Node,
154 doc_comments: ?&DocComment,445 doc_comments: ?&DocComment,
155 visib_token: ?Token,446 visib_token: ?TokenIndex,
156 name_token: Token,447 name_token: TokenIndex,
157 eq_token: Token,448 eq_token: TokenIndex,
158 mut_token: Token,449 mut_token: TokenIndex,
159 comptime_token: ?Token,450 comptime_token: ?TokenIndex,
160 extern_export_token: ?Token,451 extern_export_token: ?TokenIndex,
161 lib_name: ?&Node,452 lib_name: ?&Node,
162 type_node: ?&Node,453 type_node: ?&Node,
163 align_node: ?&Node,454 align_node: ?&Node,
164 init_node: ?&Node,455 init_node: ?&Node,
165 semicolon_token: Token,456 semicolon_token: TokenIndex,
166457
167 pub fn iterate(self: &VarDecl, index: usize) ?&Node {458 pub fn iterate(self: &VarDecl, index: usize) ?&Node {
168 var i = index;459 var i = index;
...@@ -185,7 +476,7 @@ pub const Node = struct {...@@ -185,7 +476,7 @@ pub const Node = struct {
185 return null;476 return null;
186 }477 }
187478
188 pub fn firstToken(self: &VarDecl) Token {479 pub fn firstToken(self: &VarDecl) TokenIndex {
189 if (self.visib_token) |visib_token| return visib_token;480 if (self.visib_token) |visib_token| return visib_token;
190 if (self.comptime_token) |comptime_token| return comptime_token;481 if (self.comptime_token) |comptime_token| return comptime_token;
191 if (self.extern_export_token) |extern_export_token| return extern_export_token;482 if (self.extern_export_token) |extern_export_token| return extern_export_token;
...@@ -193,7 +484,7 @@ pub const Node = struct {...@@ -193,7 +484,7 @@ pub const Node = struct {
193 return self.mut_token;484 return self.mut_token;
194 }485 }
195486
196 pub fn lastToken(self: &VarDecl) Token {487 pub fn lastToken(self: &VarDecl) TokenIndex {
197 return self.semicolon_token;488 return self.semicolon_token;
198 }489 }
199 };490 };
...@@ -201,9 +492,9 @@ pub const Node = struct {...@@ -201,9 +492,9 @@ pub const Node = struct {
201 pub const Use = struct {492 pub const Use = struct {
202 base: Node,493 base: Node,
203 doc_comments: ?&DocComment,494 doc_comments: ?&DocComment,
204 visib_token: ?Token,495 visib_token: ?TokenIndex,
205 expr: &Node,496 expr: &Node,
206 semicolon_token: Token,497 semicolon_token: TokenIndex,
207498
208 pub fn iterate(self: &Use, index: usize) ?&Node {499 pub fn iterate(self: &Use, index: usize) ?&Node {
209 var i = index;500 var i = index;
...@@ -214,48 +505,52 @@ pub const Node = struct {...@@ -214,48 +505,52 @@ pub const Node = struct {
214 return null;505 return null;
215 }506 }
216507
217 pub fn firstToken(self: &Use) Token {508 pub fn firstToken(self: &Use) TokenIndex {
218 if (self.visib_token) |visib_token| return visib_token;509 if (self.visib_token) |visib_token| return visib_token;
219 return self.expr.firstToken();510 return self.expr.firstToken();
220 }511 }
221512
222 pub fn lastToken(self: &Use) Token {513 pub fn lastToken(self: &Use) TokenIndex {
223 return self.semicolon_token;514 return self.semicolon_token;
224 }515 }
225 };516 };
226517
227 pub const ErrorSetDecl = struct {518 pub const ErrorSetDecl = struct {
228 base: Node,519 base: Node,
229 error_token: Token,520 error_token: TokenIndex,
230 decls: ArrayList(&Node),521 decls: DeclList,
231 rbrace_token: Token,522 rbrace_token: TokenIndex,
523
524 pub const DeclList = SegmentedList(&Node, 2);
232525
233 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {526 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
234 var i = index;527 var i = index;
235528
236 if (i < self.decls.len) return self.decls.at(i);529 if (i < self.decls.len) return *self.decls.at(i);
237 i -= self.decls.len;530 i -= self.decls.len;
238531
239 return null;532 return null;
240 }533 }
241534
242 pub fn firstToken(self: &ErrorSetDecl) Token {535 pub fn firstToken(self: &ErrorSetDecl) TokenIndex {
243 return self.error_token;536 return self.error_token;
244 }537 }
245538
246 pub fn lastToken(self: &ErrorSetDecl) Token {539 pub fn lastToken(self: &ErrorSetDecl) TokenIndex {
247 return self.rbrace_token;540 return self.rbrace_token;
248 }541 }
249 };542 };
250543
251 pub const ContainerDecl = struct {544 pub const ContainerDecl = struct {
252 base: Node,545 base: Node,
253 ltoken: Token,546 ltoken: TokenIndex,
254 layout: Layout,547 layout: Layout,
255 kind: Kind,548 kind: Kind,
256 init_arg_expr: InitArg,549 init_arg_expr: InitArg,
257 fields_and_decls: ArrayList(&Node),550 fields_and_decls: DeclList,
258 rbrace_token: Token,551 rbrace_token: TokenIndex,
552
553 pub const DeclList = Root.DeclList;
259554
260 const Layout = enum {555 const Layout = enum {
261 Auto,556 Auto,
...@@ -287,17 +582,17 @@ pub const Node = struct {...@@ -287,17 +582,17 @@ pub const Node = struct {
287 InitArg.Enum => { }582 InitArg.Enum => { }
288 }583 }
289584
290 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);585 if (i < self.fields_and_decls.len) return *self.fields_and_decls.at(i);
291 i -= self.fields_and_decls.len;586 i -= self.fields_and_decls.len;
292587
293 return null;588 return null;
294 }589 }
295590
296 pub fn firstToken(self: &ContainerDecl) Token {591 pub fn firstToken(self: &ContainerDecl) TokenIndex {
297 return self.ltoken;592 return self.ltoken;
298 }593 }
299594
300 pub fn lastToken(self: &ContainerDecl) Token {595 pub fn lastToken(self: &ContainerDecl) TokenIndex {
301 return self.rbrace_token;596 return self.rbrace_token;
302 }597 }
303 };598 };
...@@ -305,8 +600,8 @@ pub const Node = struct {...@@ -305,8 +600,8 @@ pub const Node = struct {
305 pub const StructField = struct {600 pub const StructField = struct {
306 base: Node,601 base: Node,
307 doc_comments: ?&DocComment,602 doc_comments: ?&DocComment,
308 visib_token: ?Token,603 visib_token: ?TokenIndex,
309 name_token: Token,604 name_token: TokenIndex,
310 type_expr: &Node,605 type_expr: &Node,
311606
312 pub fn iterate(self: &StructField, index: usize) ?&Node {607 pub fn iterate(self: &StructField, index: usize) ?&Node {
...@@ -318,12 +613,12 @@ pub const Node = struct {...@@ -318,12 +613,12 @@ pub const Node = struct {
318 return null;613 return null;
319 }614 }
320615
321 pub fn firstToken(self: &StructField) Token {616 pub fn firstToken(self: &StructField) TokenIndex {
322 if (self.visib_token) |visib_token| return visib_token;617 if (self.visib_token) |visib_token| return visib_token;
323 return self.name_token;618 return self.name_token;
324 }619 }
325620
326 pub fn lastToken(self: &StructField) Token {621 pub fn lastToken(self: &StructField) TokenIndex {
327 return self.type_expr.lastToken();622 return self.type_expr.lastToken();
328 }623 }
329 };624 };
...@@ -331,7 +626,7 @@ pub const Node = struct {...@@ -331,7 +626,7 @@ pub const Node = struct {
331 pub const UnionTag = struct {626 pub const UnionTag = struct {
332 base: Node,627 base: Node,
333 doc_comments: ?&DocComment,628 doc_comments: ?&DocComment,
334 name_token: Token,629 name_token: TokenIndex,
335 type_expr: ?&Node,630 type_expr: ?&Node,
336 value_expr: ?&Node,631 value_expr: ?&Node,
337632
...@@ -351,11 +646,11 @@ pub const Node = struct {...@@ -351,11 +646,11 @@ pub const Node = struct {
351 return null;646 return null;
352 }647 }
353648
354 pub fn firstToken(self: &UnionTag) Token {649 pub fn firstToken(self: &UnionTag) TokenIndex {
355 return self.name_token;650 return self.name_token;
356 }651 }
357652
358 pub fn lastToken(self: &UnionTag) Token {653 pub fn lastToken(self: &UnionTag) TokenIndex {
359 if (self.value_expr) |value_expr| {654 if (self.value_expr) |value_expr| {
360 return value_expr.lastToken();655 return value_expr.lastToken();
361 }656 }
...@@ -370,7 +665,7 @@ pub const Node = struct {...@@ -370,7 +665,7 @@ pub const Node = struct {
370 pub const EnumTag = struct {665 pub const EnumTag = struct {
371 base: Node,666 base: Node,
372 doc_comments: ?&DocComment,667 doc_comments: ?&DocComment,
373 name_token: Token,668 name_token: TokenIndex,
374 value: ?&Node,669 value: ?&Node,
375670
376 pub fn iterate(self: &EnumTag, index: usize) ?&Node {671 pub fn iterate(self: &EnumTag, index: usize) ?&Node {
...@@ -384,11 +679,11 @@ pub const Node = struct {...@@ -384,11 +679,11 @@ pub const Node = struct {
384 return null;679 return null;
385 }680 }
386681
387 pub fn firstToken(self: &EnumTag) Token {682 pub fn firstToken(self: &EnumTag) TokenIndex {
388 return self.name_token;683 return self.name_token;
389 }684 }
390685
391 pub fn lastToken(self: &EnumTag) Token {686 pub fn lastToken(self: &EnumTag) TokenIndex {
392 if (self.value) |value| {687 if (self.value) |value| {
393 return value.lastToken();688 return value.lastToken();
394 }689 }
...@@ -400,7 +695,7 @@ pub const Node = struct {...@@ -400,7 +695,7 @@ pub const Node = struct {
400 pub const ErrorTag = struct {695 pub const ErrorTag = struct {
401 base: Node,696 base: Node,
402 doc_comments: ?&DocComment,697 doc_comments: ?&DocComment,
403 name_token: Token,698 name_token: TokenIndex,
404699
405 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {700 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {
406 var i = index;701 var i = index;
...@@ -413,37 +708,37 @@ pub const Node = struct {...@@ -413,37 +708,37 @@ pub const Node = struct {
413 return null;708 return null;
414 }709 }
415710
416 pub fn firstToken(self: &ErrorTag) Token {711 pub fn firstToken(self: &ErrorTag) TokenIndex {
417 return self.name_token;712 return self.name_token;
418 }713 }
419714
420 pub fn lastToken(self: &ErrorTag) Token {715 pub fn lastToken(self: &ErrorTag) TokenIndex {
421 return self.name_token;716 return self.name_token;
422 }717 }
423 };718 };
424719
425 pub const Identifier = struct {720 pub const Identifier = struct {
426 base: Node,721 base: Node,
427 token: Token,722 token: TokenIndex,
428723
429 pub fn iterate(self: &Identifier, index: usize) ?&Node {724 pub fn iterate(self: &Identifier, index: usize) ?&Node {
430 return null;725 return null;
431 }726 }
432727
433 pub fn firstToken(self: &Identifier) Token {728 pub fn firstToken(self: &Identifier) TokenIndex {
434 return self.token;729 return self.token;
435 }730 }
436731
437 pub fn lastToken(self: &Identifier) Token {732 pub fn lastToken(self: &Identifier) TokenIndex {
438 return self.token;733 return self.token;
439 }734 }
440 };735 };
441736
442 pub const AsyncAttribute = struct {737 pub const AsyncAttribute = struct {
443 base: Node,738 base: Node,
444 async_token: Token,739 async_token: TokenIndex,
445 allocator_type: ?&Node,740 allocator_type: ?&Node,
446 rangle_bracket: ?Token,741 rangle_bracket: ?TokenIndex,
447742
448 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {743 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {
449 var i = index;744 var i = index;
...@@ -456,11 +751,11 @@ pub const Node = struct {...@@ -456,11 +751,11 @@ pub const Node = struct {
456 return null;751 return null;
457 }752 }
458753
459 pub fn firstToken(self: &AsyncAttribute) Token {754 pub fn firstToken(self: &AsyncAttribute) TokenIndex {
460 return self.async_token;755 return self.async_token;
461 }756 }
462757
463 pub fn lastToken(self: &AsyncAttribute) Token {758 pub fn lastToken(self: &AsyncAttribute) TokenIndex {
464 if (self.rangle_bracket) |rangle_bracket| {759 if (self.rangle_bracket) |rangle_bracket| {
465 return rangle_bracket;760 return rangle_bracket;
466 }761 }
...@@ -472,19 +767,21 @@ pub const Node = struct {...@@ -472,19 +767,21 @@ pub const Node = struct {
472 pub const FnProto = struct {767 pub const FnProto = struct {
473 base: Node,768 base: Node,
474 doc_comments: ?&DocComment,769 doc_comments: ?&DocComment,
475 visib_token: ?Token,770 visib_token: ?TokenIndex,
476 fn_token: Token,771 fn_token: TokenIndex,
477 name_token: ?Token,772 name_token: ?TokenIndex,
478 params: ArrayList(&Node),773 params: ParamList,
479 return_type: ReturnType,774 return_type: ReturnType,
480 var_args_token: ?Token,775 var_args_token: ?TokenIndex,
481 extern_export_inline_token: ?Token,776 extern_export_inline_token: ?TokenIndex,
482 cc_token: ?Token,777 cc_token: ?TokenIndex,
483 async_attr: ?&AsyncAttribute,778 async_attr: ?&AsyncAttribute,
484 body_node: ?&Node,779 body_node: ?&Node,
485 lib_name: ?&Node, // populated if this is an extern declaration780 lib_name: ?&Node, // populated if this is an extern declaration
486 align_expr: ?&Node, // populated if align(A) is present781 align_expr: ?&Node, // populated if align(A) is present
487782
783 pub const ParamList = SegmentedList(&Node, 2);
784
488 pub const ReturnType = union(enum) {785 pub const ReturnType = union(enum) {
489 Explicit: &Node,786 Explicit: &Node,
490 InferErrorSet: &Node,787 InferErrorSet: &Node,
...@@ -526,7 +823,7 @@ pub const Node = struct {...@@ -526,7 +823,7 @@ pub const Node = struct {
526 return null;823 return null;
527 }824 }
528825
529 pub fn firstToken(self: &FnProto) Token {826 pub fn firstToken(self: &FnProto) TokenIndex {
530 if (self.visib_token) |visib_token| return visib_token;827 if (self.visib_token) |visib_token| return visib_token;
531 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;828 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
532 assert(self.lib_name == null);829 assert(self.lib_name == null);
...@@ -534,7 +831,7 @@ pub const Node = struct {...@@ -534,7 +831,7 @@ pub const Node = struct {
534 return self.fn_token;831 return self.fn_token;
535 }832 }
536833
537 pub fn lastToken(self: &FnProto) Token {834 pub fn lastToken(self: &FnProto) TokenIndex {
538 if (self.body_node) |body_node| return body_node.lastToken();835 if (self.body_node) |body_node| return body_node.lastToken();
539 switch (self.return_type) {836 switch (self.return_type) {
540 // TODO allow this and next prong to share bodies since the types are the same837 // TODO allow this and next prong to share bodies since the types are the same
...@@ -546,11 +843,11 @@ pub const Node = struct {...@@ -546,11 +843,11 @@ pub const Node = struct {
546843
547 pub const PromiseType = struct {844 pub const PromiseType = struct {
548 base: Node,845 base: Node,
549 promise_token: Token,846 promise_token: TokenIndex,
550 result: ?Result,847 result: ?Result,
551848
552 pub const Result = struct {849 pub const Result = struct {
553 arrow_token: Token,850 arrow_token: TokenIndex,
554 return_type: &Node,851 return_type: &Node,
555 };852 };
556853
...@@ -565,11 +862,11 @@ pub const Node = struct {...@@ -565,11 +862,11 @@ pub const Node = struct {
565 return null;862 return null;
566 }863 }
567864
568 pub fn firstToken(self: &PromiseType) Token {865 pub fn firstToken(self: &PromiseType) TokenIndex {
569 return self.promise_token;866 return self.promise_token;
570 }867 }
571868
572 pub fn lastToken(self: &PromiseType) Token {869 pub fn lastToken(self: &PromiseType) TokenIndex {
573 if (self.result) |result| return result.return_type.lastToken();870 if (self.result) |result| return result.return_type.lastToken();
574 return self.promise_token;871 return self.promise_token;
575 }872 }
...@@ -577,11 +874,11 @@ pub const Node = struct {...@@ -577,11 +874,11 @@ pub const Node = struct {
577874
578 pub const ParamDecl = struct {875 pub const ParamDecl = struct {
579 base: Node,876 base: Node,
580 comptime_token: ?Token,877 comptime_token: ?TokenIndex,
581 noalias_token: ?Token,878 noalias_token: ?TokenIndex,
582 name_token: ?Token,879 name_token: ?TokenIndex,
583 type_node: &Node,880 type_node: &Node,
584 var_args_token: ?Token,881 var_args_token: ?TokenIndex,
585882
586 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {883 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {
587 var i = index;884 var i = index;
...@@ -592,14 +889,14 @@ pub const Node = struct {...@@ -592,14 +889,14 @@ pub const Node = struct {
592 return null;889 return null;
593 }890 }
594891
595 pub fn firstToken(self: &ParamDecl) Token {892 pub fn firstToken(self: &ParamDecl) TokenIndex {
596 if (self.comptime_token) |comptime_token| return comptime_token;893 if (self.comptime_token) |comptime_token| return comptime_token;
597 if (self.noalias_token) |noalias_token| return noalias_token;894 if (self.noalias_token) |noalias_token| return noalias_token;
598 if (self.name_token) |name_token| return name_token;895 if (self.name_token) |name_token| return name_token;
599 return self.type_node.firstToken();896 return self.type_node.firstToken();
600 }897 }
601898
602 pub fn lastToken(self: &ParamDecl) Token {899 pub fn lastToken(self: &ParamDecl) TokenIndex {
603 if (self.var_args_token) |var_args_token| return var_args_token;900 if (self.var_args_token) |var_args_token| return var_args_token;
604 return self.type_node.lastToken();901 return self.type_node.lastToken();
605 }902 }
...@@ -607,10 +904,12 @@ pub const Node = struct {...@@ -607,10 +904,12 @@ pub const Node = struct {
607904
608 pub const Block = struct {905 pub const Block = struct {
609 base: Node,906 base: Node,
610 label: ?Token,907 label: ?TokenIndex,
611 lbrace: Token,908 lbrace: TokenIndex,
612 statements: ArrayList(&Node),909 statements: StatementList,
613 rbrace: Token,910 rbrace: TokenIndex,
911
912 pub const StatementList = Root.DeclList;
614913
615 pub fn iterate(self: &Block, index: usize) ?&Node {914 pub fn iterate(self: &Block, index: usize) ?&Node {
616 var i = index;915 var i = index;
...@@ -621,7 +920,7 @@ pub const Node = struct {...@@ -621,7 +920,7 @@ pub const Node = struct {
621 return null;920 return null;
622 }921 }
623922
624 pub fn firstToken(self: &Block) Token {923 pub fn firstToken(self: &Block) TokenIndex {
625 if (self.label) |label| {924 if (self.label) |label| {
626 return label;925 return label;
627 }926 }
...@@ -629,14 +928,14 @@ pub const Node = struct {...@@ -629,14 +928,14 @@ pub const Node = struct {
629 return self.lbrace;928 return self.lbrace;
630 }929 }
631930
632 pub fn lastToken(self: &Block) Token {931 pub fn lastToken(self: &Block) TokenIndex {
633 return self.rbrace;932 return self.rbrace;
634 }933 }
635 };934 };
636935
637 pub const Defer = struct {936 pub const Defer = struct {
638 base: Node,937 base: Node,
639 defer_token: Token,938 defer_token: TokenIndex,
640 kind: Kind,939 kind: Kind,
641 expr: &Node,940 expr: &Node,
642941
...@@ -654,11 +953,11 @@ pub const Node = struct {...@@ -654,11 +953,11 @@ pub const Node = struct {
654 return null;953 return null;
655 }954 }
656955
657 pub fn firstToken(self: &Defer) Token {956 pub fn firstToken(self: &Defer) TokenIndex {
658 return self.defer_token;957 return self.defer_token;
659 }958 }
660959
661 pub fn lastToken(self: &Defer) Token {960 pub fn lastToken(self: &Defer) TokenIndex {
662 return self.expr.lastToken();961 return self.expr.lastToken();
663 }962 }
664 };963 };
...@@ -666,7 +965,7 @@ pub const Node = struct {...@@ -666,7 +965,7 @@ pub const Node = struct {
666 pub const Comptime = struct {965 pub const Comptime = struct {
667 base: Node,966 base: Node,
668 doc_comments: ?&DocComment,967 doc_comments: ?&DocComment,
669 comptime_token: Token,968 comptime_token: TokenIndex,
670 expr: &Node,969 expr: &Node,
671970
672 pub fn iterate(self: &Comptime, index: usize) ?&Node {971 pub fn iterate(self: &Comptime, index: usize) ?&Node {
...@@ -678,20 +977,20 @@ pub const Node = struct {...@@ -678,20 +977,20 @@ pub const Node = struct {
678 return null;977 return null;
679 }978 }
680979
681 pub fn firstToken(self: &Comptime) Token {980 pub fn firstToken(self: &Comptime) TokenIndex {
682 return self.comptime_token;981 return self.comptime_token;
683 }982 }
684983
685 pub fn lastToken(self: &Comptime) Token {984 pub fn lastToken(self: &Comptime) TokenIndex {
686 return self.expr.lastToken();985 return self.expr.lastToken();
687 }986 }
688 };987 };
689988
690 pub const Payload = struct {989 pub const Payload = struct {
691 base: Node,990 base: Node,
692 lpipe: Token,991 lpipe: TokenIndex,
693 error_symbol: &Node,992 error_symbol: &Node,
694 rpipe: Token,993 rpipe: TokenIndex,
695994
696 pub fn iterate(self: &Payload, index: usize) ?&Node {995 pub fn iterate(self: &Payload, index: usize) ?&Node {
697 var i = index;996 var i = index;
...@@ -702,21 +1001,21 @@ pub const Node = struct {...@@ -702,21 +1001,21 @@ pub const Node = struct {
702 return null;1001 return null;
703 }1002 }
7041003
705 pub fn firstToken(self: &Payload) Token {1004 pub fn firstToken(self: &Payload) TokenIndex {
706 return self.lpipe;1005 return self.lpipe;
707 }1006 }
7081007
709 pub fn lastToken(self: &Payload) Token {1008 pub fn lastToken(self: &Payload) TokenIndex {
710 return self.rpipe;1009 return self.rpipe;
711 }1010 }
712 };1011 };
7131012
714 pub const PointerPayload = struct {1013 pub const PointerPayload = struct {
715 base: Node,1014 base: Node,
716 lpipe: Token,1015 lpipe: TokenIndex,
717 ptr_token: ?Token,1016 ptr_token: ?TokenIndex,
718 value_symbol: &Node,1017 value_symbol: &Node,
719 rpipe: Token,1018 rpipe: TokenIndex,
7201019
721 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {1020 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {
722 var i = index;1021 var i = index;
...@@ -727,22 +1026,22 @@ pub const Node = struct {...@@ -727,22 +1026,22 @@ pub const Node = struct {
727 return null;1026 return null;
728 }1027 }
7291028
730 pub fn firstToken(self: &PointerPayload) Token {1029 pub fn firstToken(self: &PointerPayload) TokenIndex {
731 return self.lpipe;1030 return self.lpipe;
732 }1031 }
7331032
734 pub fn lastToken(self: &PointerPayload) Token {1033 pub fn lastToken(self: &PointerPayload) TokenIndex {
735 return self.rpipe;1034 return self.rpipe;
736 }1035 }
737 };1036 };
7381037
739 pub const PointerIndexPayload = struct {1038 pub const PointerIndexPayload = struct {
740 base: Node,1039 base: Node,
741 lpipe: Token,1040 lpipe: TokenIndex,
742 ptr_token: ?Token,1041 ptr_token: ?TokenIndex,
743 value_symbol: &Node,1042 value_symbol: &Node,
744 index_symbol: ?&Node,1043 index_symbol: ?&Node,
745 rpipe: Token,1044 rpipe: TokenIndex,
7461045
747 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {1046 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {
748 var i = index;1047 var i = index;
...@@ -758,18 +1057,18 @@ pub const Node = struct {...@@ -758,18 +1057,18 @@ pub const Node = struct {
758 return null;1057 return null;
759 }1058 }
7601059
761 pub fn firstToken(self: &PointerIndexPayload) Token {1060 pub fn firstToken(self: &PointerIndexPayload) TokenIndex {
762 return self.lpipe;1061 return self.lpipe;
763 }1062 }
7641063
765 pub fn lastToken(self: &PointerIndexPayload) Token {1064 pub fn lastToken(self: &PointerIndexPayload) TokenIndex {
766 return self.rpipe;1065 return self.rpipe;
767 }1066 }
768 };1067 };
7691068
770 pub const Else = struct {1069 pub const Else = struct {
771 base: Node,1070 base: Node,
772 else_token: Token,1071 else_token: TokenIndex,
773 payload: ?&Node,1072 payload: ?&Node,
774 body: &Node,1073 body: &Node,
7751074
...@@ -787,22 +1086,24 @@ pub const Node = struct {...@@ -787,22 +1086,24 @@ pub const Node = struct {
787 return null;1086 return null;
788 }1087 }
7891088
790 pub fn firstToken(self: &Else) Token {1089 pub fn firstToken(self: &Else) TokenIndex {
791 return self.else_token;1090 return self.else_token;
792 }1091 }
7931092
794 pub fn lastToken(self: &Else) Token {1093 pub fn lastToken(self: &Else) TokenIndex {
795 return self.body.lastToken();1094 return self.body.lastToken();
796 }1095 }
797 };1096 };
7981097
799 pub const Switch = struct {1098 pub const Switch = struct {
800 base: Node,1099 base: Node,
801 switch_token: Token,1100 switch_token: TokenIndex,
802 expr: &Node,1101 expr: &Node,
803 /// these can be SwitchCase nodes or LineComment nodes1102 /// these can be SwitchCase nodes or LineComment nodes
804 cases: ArrayList(&Node),1103 cases: CaseList,
805 rbrace: Token,1104 rbrace: TokenIndex,
1105
1106 pub const CaseList = SegmentedList(&Node, 2);
8061107
807 pub fn iterate(self: &Switch, index: usize) ?&Node {1108 pub fn iterate(self: &Switch, index: usize) ?&Node {
808 var i = index;1109 var i = index;
...@@ -810,31 +1111,33 @@ pub const Node = struct {...@@ -810,31 +1111,33 @@ pub const Node = struct {
810 if (i < 1) return self.expr;1111 if (i < 1) return self.expr;
811 i -= 1;1112 i -= 1;
8121113
813 if (i < self.cases.len) return self.cases.at(i);1114 if (i < self.cases.len) return *self.cases.at(i);
814 i -= self.cases.len;1115 i -= self.cases.len;
8151116
816 return null;1117 return null;
817 }1118 }
8181119
819 pub fn firstToken(self: &Switch) Token {1120 pub fn firstToken(self: &Switch) TokenIndex {
820 return self.switch_token;1121 return self.switch_token;
821 }1122 }
8221123
823 pub fn lastToken(self: &Switch) Token {1124 pub fn lastToken(self: &Switch) TokenIndex {
824 return self.rbrace;1125 return self.rbrace;
825 }1126 }
826 };1127 };
8271128
828 pub const SwitchCase = struct {1129 pub const SwitchCase = struct {
829 base: Node,1130 base: Node,
830 items: ArrayList(&Node),1131 items: ItemList,
831 payload: ?&Node,1132 payload: ?&Node,
832 expr: &Node,1133 expr: &Node,
8331134
1135 pub const ItemList = SegmentedList(&Node, 1);
1136
834 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {1137 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
835 var i = index;1138 var i = index;
8361139
837 if (i < self.items.len) return self.items.at(i);1140 if (i < self.items.len) return *self.items.at(i);
838 i -= self.items.len;1141 i -= self.items.len;
8391142
840 if (self.payload) |payload| {1143 if (self.payload) |payload| {
...@@ -848,37 +1151,37 @@ pub const Node = struct {...@@ -848,37 +1151,37 @@ pub const Node = struct {
848 return null;1151 return null;
849 }1152 }
8501153
851 pub fn firstToken(self: &SwitchCase) Token {1154 pub fn firstToken(self: &SwitchCase) TokenIndex {
852 return self.items.at(0).firstToken();1155 return (*self.items.at(0)).firstToken();
853 }1156 }
8541157
855 pub fn lastToken(self: &SwitchCase) Token {1158 pub fn lastToken(self: &SwitchCase) TokenIndex {
856 return self.expr.lastToken();1159 return self.expr.lastToken();
857 }1160 }
858 };1161 };
8591162
860 pub const SwitchElse = struct {1163 pub const SwitchElse = struct {
861 base: Node,1164 base: Node,
862 token: Token,1165 token: TokenIndex,
8631166
864 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {1167 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {
865 return null;1168 return null;
866 }1169 }
8671170
868 pub fn firstToken(self: &SwitchElse) Token {1171 pub fn firstToken(self: &SwitchElse) TokenIndex {
869 return self.token;1172 return self.token;
870 }1173 }
8711174
872 pub fn lastToken(self: &SwitchElse) Token {1175 pub fn lastToken(self: &SwitchElse) TokenIndex {
873 return self.token;1176 return self.token;
874 }1177 }
875 };1178 };
8761179
877 pub const While = struct {1180 pub const While = struct {
878 base: Node,1181 base: Node,
879 label: ?Token,1182 label: ?TokenIndex,
880 inline_token: ?Token,1183 inline_token: ?TokenIndex,
881 while_token: Token,1184 while_token: TokenIndex,
882 condition: &Node,1185 condition: &Node,
883 payload: ?&Node,1186 payload: ?&Node,
884 continue_expr: ?&Node,1187 continue_expr: ?&Node,
...@@ -912,7 +1215,7 @@ pub const Node = struct {...@@ -912,7 +1215,7 @@ pub const Node = struct {
912 return null;1215 return null;
913 }1216 }
9141217
915 pub fn firstToken(self: &While) Token {1218 pub fn firstToken(self: &While) TokenIndex {
916 if (self.label) |label| {1219 if (self.label) |label| {
917 return label;1220 return label;
918 }1221 }
...@@ -924,7 +1227,7 @@ pub const Node = struct {...@@ -924,7 +1227,7 @@ pub const Node = struct {
924 return self.while_token;1227 return self.while_token;
925 }1228 }
9261229
927 pub fn lastToken(self: &While) Token {1230 pub fn lastToken(self: &While) TokenIndex {
928 if (self.@"else") |@"else"| {1231 if (self.@"else") |@"else"| {
929 return @"else".body.lastToken();1232 return @"else".body.lastToken();
930 }1233 }
...@@ -935,9 +1238,9 @@ pub const Node = struct {...@@ -935,9 +1238,9 @@ pub const Node = struct {
9351238
936 pub const For = struct {1239 pub const For = struct {
937 base: Node,1240 base: Node,
938 label: ?Token,1241 label: ?TokenIndex,
939 inline_token: ?Token,1242 inline_token: ?TokenIndex,
940 for_token: Token,1243 for_token: TokenIndex,
941 array_expr: &Node,1244 array_expr: &Node,
942 payload: ?&Node,1245 payload: ?&Node,
943 body: &Node,1246 body: &Node,
...@@ -965,7 +1268,7 @@ pub const Node = struct {...@@ -965,7 +1268,7 @@ pub const Node = struct {
965 return null;1268 return null;
966 }1269 }
9671270
968 pub fn firstToken(self: &For) Token {1271 pub fn firstToken(self: &For) TokenIndex {
969 if (self.label) |label| {1272 if (self.label) |label| {
970 return label;1273 return label;
971 }1274 }
...@@ -977,7 +1280,7 @@ pub const Node = struct {...@@ -977,7 +1280,7 @@ pub const Node = struct {
977 return self.for_token;1280 return self.for_token;
978 }1281 }
9791282
980 pub fn lastToken(self: &For) Token {1283 pub fn lastToken(self: &For) TokenIndex {
981 if (self.@"else") |@"else"| {1284 if (self.@"else") |@"else"| {
982 return @"else".body.lastToken();1285 return @"else".body.lastToken();
983 }1286 }
...@@ -988,7 +1291,7 @@ pub const Node = struct {...@@ -988,7 +1291,7 @@ pub const Node = struct {
9881291
989 pub const If = struct {1292 pub const If = struct {
990 base: Node,1293 base: Node,
991 if_token: Token,1294 if_token: TokenIndex,
992 condition: &Node,1295 condition: &Node,
993 payload: ?&Node,1296 payload: ?&Node,
994 body: &Node,1297 body: &Node,
...@@ -1016,11 +1319,11 @@ pub const Node = struct {...@@ -1016,11 +1319,11 @@ pub const Node = struct {
1016 return null;1319 return null;
1017 }1320 }
10181321
1019 pub fn firstToken(self: &If) Token {1322 pub fn firstToken(self: &If) TokenIndex {
1020 return self.if_token;1323 return self.if_token;
1021 }1324 }
10221325
1023 pub fn lastToken(self: &If) Token {1326 pub fn lastToken(self: &If) TokenIndex {
1024 if (self.@"else") |@"else"| {1327 if (self.@"else") |@"else"| {
1025 return @"else".body.lastToken();1328 return @"else".body.lastToken();
1026 }1329 }
...@@ -1031,7 +1334,7 @@ pub const Node = struct {...@@ -1031,7 +1334,7 @@ pub const Node = struct {
10311334
1032 pub const InfixOp = struct {1335 pub const InfixOp = struct {
1033 base: Node,1336 base: Node,
1034 op_token: Token,1337 op_token: TokenIndex,
1035 lhs: &Node,1338 lhs: &Node,
1036 op: Op,1339 op: Op,
1037 rhs: &Node,1340 rhs: &Node,
...@@ -1146,18 +1449,18 @@ pub const Node = struct {...@@ -1146,18 +1449,18 @@ pub const Node = struct {
1146 return null;1449 return null;
1147 }1450 }
11481451
1149 pub fn firstToken(self: &InfixOp) Token {1452 pub fn firstToken(self: &InfixOp) TokenIndex {
1150 return self.lhs.firstToken();1453 return self.lhs.firstToken();
1151 }1454 }
11521455
1153 pub fn lastToken(self: &InfixOp) Token {1456 pub fn lastToken(self: &InfixOp) TokenIndex {
1154 return self.rhs.lastToken();1457 return self.rhs.lastToken();
1155 }1458 }
1156 };1459 };
11571460
1158 pub const PrefixOp = struct {1461 pub const PrefixOp = struct {
1159 base: Node,1462 base: Node,
1160 op_token: Token,1463 op_token: TokenIndex,
1161 op: Op,1464 op: Op,
1162 rhs: &Node,1465 rhs: &Node,
11631466
...@@ -1180,10 +1483,10 @@ pub const Node = struct {...@@ -1180,10 +1483,10 @@ pub const Node = struct {
11801483
1181 const AddrOfInfo = struct {1484 const AddrOfInfo = struct {
1182 align_expr: ?&Node,1485 align_expr: ?&Node,
1183 bit_offset_start_token: ?Token,1486 bit_offset_start_token: ?TokenIndex,
1184 bit_offset_end_token: ?Token,1487 bit_offset_end_token: ?TokenIndex,
1185 const_token: ?Token,1488 const_token: ?TokenIndex,
1186 volatile_token: ?Token,1489 volatile_token: ?TokenIndex,
1187 };1490 };
11881491
1189 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {1492 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
...@@ -1225,19 +1528,19 @@ pub const Node = struct {...@@ -1225,19 +1528,19 @@ pub const Node = struct {
1225 return null;1528 return null;
1226 }1529 }
12271530
1228 pub fn firstToken(self: &PrefixOp) Token {1531 pub fn firstToken(self: &PrefixOp) TokenIndex {
1229 return self.op_token;1532 return self.op_token;
1230 }1533 }
12311534
1232 pub fn lastToken(self: &PrefixOp) Token {1535 pub fn lastToken(self: &PrefixOp) TokenIndex {
1233 return self.rhs.lastToken();1536 return self.rhs.lastToken();
1234 }1537 }
1235 };1538 };
12361539
1237 pub const FieldInitializer = struct {1540 pub const FieldInitializer = struct {
1238 base: Node,1541 base: Node,
1239 period_token: Token,1542 period_token: TokenIndex,
1240 name_token: Token,1543 name_token: TokenIndex,
1241 expr: &Node,1544 expr: &Node,
12421545
1243 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {1546 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {
...@@ -1249,11 +1552,11 @@ pub const Node = struct {...@@ -1249,11 +1552,11 @@ pub const Node = struct {
1249 return null;1552 return null;
1250 }1553 }
12511554
1252 pub fn firstToken(self: &FieldInitializer) Token {1555 pub fn firstToken(self: &FieldInitializer) TokenIndex {
1253 return self.period_token;1556 return self.period_token;
1254 }1557 }
12551558
1256 pub fn lastToken(self: &FieldInitializer) Token {1559 pub fn lastToken(self: &FieldInitializer) TokenIndex {
1257 return self.expr.lastToken();1560 return self.expr.lastToken();
1258 }1561 }
1259 };1562 };
...@@ -1262,24 +1565,28 @@ pub const Node = struct {...@@ -1262,24 +1565,28 @@ pub const Node = struct {
1262 base: Node,1565 base: Node,
1263 lhs: &Node,1566 lhs: &Node,
1264 op: Op,1567 op: Op,
1265 rtoken: Token,1568 rtoken: TokenIndex,
12661569
1267 const Op = union(enum) {1570 pub const Op = union(enum) {
1268 Call: CallInfo,1571 Call: Call,
1269 ArrayAccess: &Node,1572 ArrayAccess: &Node,
1270 Slice: SliceRange,1573 Slice: Slice,
1271 ArrayInitializer: ArrayList(&Node),1574 ArrayInitializer: InitList,
1272 StructInitializer: ArrayList(&Node),1575 StructInitializer: InitList,
1273 };
12741576
1275 const CallInfo = struct {1577 pub const InitList = SegmentedList(&Node, 2);
1276 params: ArrayList(&Node),1578
1277 async_attr: ?&AsyncAttribute,1579 pub const Call = struct {
1278 };1580 params: ParamList,
1581 async_attr: ?&AsyncAttribute,
1582
1583 pub const ParamList = SegmentedList(&Node, 2);
1584 };
12791585
1280 const SliceRange = struct {1586 pub const Slice = struct {
1281 start: &Node,1587 start: &Node,
1282 end: ?&Node,1588 end: ?&Node,
1589 };
1283 };1590 };
12841591
1285 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {1592 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {
...@@ -1290,7 +1597,7 @@ pub const Node = struct {...@@ -1290,7 +1597,7 @@ pub const Node = struct {
12901597
1291 switch (self.op) {1598 switch (self.op) {
1292 Op.Call => |call_info| {1599 Op.Call => |call_info| {
1293 if (i < call_info.params.len) return call_info.params.at(i);1600 if (i < call_info.params.len) return *call_info.params.at(i);
1294 i -= call_info.params.len;1601 i -= call_info.params.len;
1295 },1602 },
1296 Op.ArrayAccess => |index_expr| {1603 Op.ArrayAccess => |index_expr| {
...@@ -1307,11 +1614,11 @@ pub const Node = struct {...@@ -1307,11 +1614,11 @@ pub const Node = struct {
1307 }1614 }
1308 },1615 },
1309 Op.ArrayInitializer => |exprs| {1616 Op.ArrayInitializer => |exprs| {
1310 if (i < exprs.len) return exprs.at(i);1617 if (i < exprs.len) return *exprs.at(i);
1311 i -= exprs.len;1618 i -= exprs.len;
1312 },1619 },
1313 Op.StructInitializer => |fields| {1620 Op.StructInitializer => |fields| {
1314 if (i < fields.len) return fields.at(i);1621 if (i < fields.len) return *fields.at(i);
1315 i -= fields.len;1622 i -= fields.len;
1316 },1623 },
1317 }1624 }
...@@ -1319,20 +1626,20 @@ pub const Node = struct {...@@ -1319,20 +1626,20 @@ pub const Node = struct {
1319 return null;1626 return null;
1320 }1627 }
13211628
1322 pub fn firstToken(self: &SuffixOp) Token {1629 pub fn firstToken(self: &SuffixOp) TokenIndex {
1323 return self.lhs.firstToken();1630 return self.lhs.firstToken();
1324 }1631 }
13251632
1326 pub fn lastToken(self: &SuffixOp) Token {1633 pub fn lastToken(self: &SuffixOp) TokenIndex {
1327 return self.rtoken;1634 return self.rtoken;
1328 }1635 }
1329 };1636 };
13301637
1331 pub const GroupedExpression = struct {1638 pub const GroupedExpression = struct {
1332 base: Node,1639 base: Node,
1333 lparen: Token,1640 lparen: TokenIndex,
1334 expr: &Node,1641 expr: &Node,
1335 rparen: Token,1642 rparen: TokenIndex,
13361643
1337 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {1644 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {
1338 var i = index;1645 var i = index;
...@@ -1343,18 +1650,18 @@ pub const Node = struct {...@@ -1343,18 +1650,18 @@ pub const Node = struct {
1343 return null;1650 return null;
1344 }1651 }
13451652
1346 pub fn firstToken(self: &GroupedExpression) Token {1653 pub fn firstToken(self: &GroupedExpression) TokenIndex {
1347 return self.lparen;1654 return self.lparen;
1348 }1655 }
13491656
1350 pub fn lastToken(self: &GroupedExpression) Token {1657 pub fn lastToken(self: &GroupedExpression) TokenIndex {
1351 return self.rparen;1658 return self.rparen;
1352 }1659 }
1353 };1660 };
13541661
1355 pub const ControlFlowExpression = struct {1662 pub const ControlFlowExpression = struct {
1356 base: Node,1663 base: Node,
1357 ltoken: Token,1664 ltoken: TokenIndex,
1358 kind: Kind,1665 kind: Kind,
1359 rhs: ?&Node,1666 rhs: ?&Node,
13601667
...@@ -1391,11 +1698,11 @@ pub const Node = struct {...@@ -1391,11 +1698,11 @@ pub const Node = struct {
1391 return null;1698 return null;
1392 }1699 }
13931700
1394 pub fn firstToken(self: &ControlFlowExpression) Token {1701 pub fn firstToken(self: &ControlFlowExpression) TokenIndex {
1395 return self.ltoken;1702 return self.ltoken;
1396 }1703 }
13971704
1398 pub fn lastToken(self: &ControlFlowExpression) Token {1705 pub fn lastToken(self: &ControlFlowExpression) TokenIndex {
1399 if (self.rhs) |rhs| {1706 if (self.rhs) |rhs| {
1400 return rhs.lastToken();1707 return rhs.lastToken();
1401 }1708 }
...@@ -1420,8 +1727,8 @@ pub const Node = struct {...@@ -1420,8 +1727,8 @@ pub const Node = struct {
14201727
1421 pub const Suspend = struct {1728 pub const Suspend = struct {
1422 base: Node,1729 base: Node,
1423 label: ?Token,1730 label: ?TokenIndex,
1424 suspend_token: Token,1731 suspend_token: TokenIndex,
1425 payload: ?&Node,1732 payload: ?&Node,
1426 body: ?&Node,1733 body: ?&Node,
14271734
...@@ -1441,12 +1748,12 @@ pub const Node = struct {...@@ -1441,12 +1748,12 @@ pub const Node = struct {
1441 return null;1748 return null;
1442 }1749 }
14431750
1444 pub fn firstToken(self: &Suspend) Token {1751 pub fn firstToken(self: &Suspend) TokenIndex {
1445 if (self.label) |label| return label;1752 if (self.label) |label| return label;
1446 return self.suspend_token;1753 return self.suspend_token;
1447 }1754 }
14481755
1449 pub fn lastToken(self: &Suspend) Token {1756 pub fn lastToken(self: &Suspend) TokenIndex {
1450 if (self.body) |body| {1757 if (self.body) |body| {
1451 return body.lastToken();1758 return body.lastToken();
1452 }1759 }
...@@ -1461,177 +1768,181 @@ pub const Node = struct {...@@ -1461,177 +1768,181 @@ pub const Node = struct {
14611768
1462 pub const IntegerLiteral = struct {1769 pub const IntegerLiteral = struct {
1463 base: Node,1770 base: Node,
1464 token: Token,1771 token: TokenIndex,
14651772
1466 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {1773 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {
1467 return null;1774 return null;
1468 }1775 }
14691776
1470 pub fn firstToken(self: &IntegerLiteral) Token {1777 pub fn firstToken(self: &IntegerLiteral) TokenIndex {
1471 return self.token;1778 return self.token;
1472 }1779 }
14731780
1474 pub fn lastToken(self: &IntegerLiteral) Token {1781 pub fn lastToken(self: &IntegerLiteral) TokenIndex {
1475 return self.token;1782 return self.token;
1476 }1783 }
1477 };1784 };
14781785
1479 pub const FloatLiteral = struct {1786 pub const FloatLiteral = struct {
1480 base: Node,1787 base: Node,
1481 token: Token,1788 token: TokenIndex,
14821789
1483 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {1790 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {
1484 return null;1791 return null;
1485 }1792 }
14861793
1487 pub fn firstToken(self: &FloatLiteral) Token {1794 pub fn firstToken(self: &FloatLiteral) TokenIndex {
1488 return self.token;1795 return self.token;
1489 }1796 }
14901797
1491 pub fn lastToken(self: &FloatLiteral) Token {1798 pub fn lastToken(self: &FloatLiteral) TokenIndex {
1492 return self.token;1799 return self.token;
1493 }1800 }
1494 };1801 };
14951802
1496 pub const BuiltinCall = struct {1803 pub const BuiltinCall = struct {
1497 base: Node,1804 base: Node,
1498 builtin_token: Token,1805 builtin_token: TokenIndex,
1499 params: ArrayList(&Node),1806 params: ParamList,
1500 rparen_token: Token,1807 rparen_token: TokenIndex,
1808
1809 pub const ParamList = SegmentedList(&Node, 2);
15011810
1502 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {1811 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
1503 var i = index;1812 var i = index;
15041813
1505 if (i < self.params.len) return self.params.at(i);1814 if (i < self.params.len) return *self.params.at(i);
1506 i -= self.params.len;1815 i -= self.params.len;
15071816
1508 return null;1817 return null;
1509 }1818 }
15101819
1511 pub fn firstToken(self: &BuiltinCall) Token {1820 pub fn firstToken(self: &BuiltinCall) TokenIndex {
1512 return self.builtin_token;1821 return self.builtin_token;
1513 }1822 }
15141823
1515 pub fn lastToken(self: &BuiltinCall) Token {1824 pub fn lastToken(self: &BuiltinCall) TokenIndex {
1516 return self.rparen_token;1825 return self.rparen_token;
1517 }1826 }
1518 };1827 };
15191828
1520 pub const StringLiteral = struct {1829 pub const StringLiteral = struct {
1521 base: Node,1830 base: Node,
1522 token: Token,1831 token: TokenIndex,
15231832
1524 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {1833 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {
1525 return null;1834 return null;
1526 }1835 }
15271836
1528 pub fn firstToken(self: &StringLiteral) Token {1837 pub fn firstToken(self: &StringLiteral) TokenIndex {
1529 return self.token;1838 return self.token;
1530 }1839 }
15311840
1532 pub fn lastToken(self: &StringLiteral) Token {1841 pub fn lastToken(self: &StringLiteral) TokenIndex {
1533 return self.token;1842 return self.token;
1534 }1843 }
1535 };1844 };
15361845
1537 pub const MultilineStringLiteral = struct {1846 pub const MultilineStringLiteral = struct {
1538 base: Node,1847 base: Node,
1539 tokens: ArrayList(Token),1848 lines: LineList,
1849
1850 pub const LineList = SegmentedList(TokenIndex, 4);
15401851
1541 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {1852 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {
1542 return null;1853 return null;
1543 }1854 }
15441855
1545 pub fn firstToken(self: &MultilineStringLiteral) Token {1856 pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {
1546 return self.tokens.at(0);1857 return *self.lines.at(0);
1547 }1858 }
15481859
1549 pub fn lastToken(self: &MultilineStringLiteral) Token {1860 pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {
1550 return self.tokens.at(self.tokens.len - 1);1861 return *self.lines.at(self.lines.len - 1);
1551 }1862 }
1552 };1863 };
15531864
1554 pub const CharLiteral = struct {1865 pub const CharLiteral = struct {
1555 base: Node,1866 base: Node,
1556 token: Token,1867 token: TokenIndex,
15571868
1558 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {1869 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {
1559 return null;1870 return null;
1560 }1871 }
15611872
1562 pub fn firstToken(self: &CharLiteral) Token {1873 pub fn firstToken(self: &CharLiteral) TokenIndex {
1563 return self.token;1874 return self.token;
1564 }1875 }
15651876
1566 pub fn lastToken(self: &CharLiteral) Token {1877 pub fn lastToken(self: &CharLiteral) TokenIndex {
1567 return self.token;1878 return self.token;
1568 }1879 }
1569 };1880 };
15701881
1571 pub const BoolLiteral = struct {1882 pub const BoolLiteral = struct {
1572 base: Node,1883 base: Node,
1573 token: Token,1884 token: TokenIndex,
15741885
1575 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {1886 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {
1576 return null;1887 return null;
1577 }1888 }
15781889
1579 pub fn firstToken(self: &BoolLiteral) Token {1890 pub fn firstToken(self: &BoolLiteral) TokenIndex {
1580 return self.token;1891 return self.token;
1581 }1892 }
15821893
1583 pub fn lastToken(self: &BoolLiteral) Token {1894 pub fn lastToken(self: &BoolLiteral) TokenIndex {
1584 return self.token;1895 return self.token;
1585 }1896 }
1586 };1897 };
15871898
1588 pub const NullLiteral = struct {1899 pub const NullLiteral = struct {
1589 base: Node,1900 base: Node,
1590 token: Token,1901 token: TokenIndex,
15911902
1592 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {1903 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {
1593 return null;1904 return null;
1594 }1905 }
15951906
1596 pub fn firstToken(self: &NullLiteral) Token {1907 pub fn firstToken(self: &NullLiteral) TokenIndex {
1597 return self.token;1908 return self.token;
1598 }1909 }
15991910
1600 pub fn lastToken(self: &NullLiteral) Token {1911 pub fn lastToken(self: &NullLiteral) TokenIndex {
1601 return self.token;1912 return self.token;
1602 }1913 }
1603 };1914 };
16041915
1605 pub const UndefinedLiteral = struct {1916 pub const UndefinedLiteral = struct {
1606 base: Node,1917 base: Node,
1607 token: Token,1918 token: TokenIndex,
16081919
1609 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {1920 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {
1610 return null;1921 return null;
1611 }1922 }
16121923
1613 pub fn firstToken(self: &UndefinedLiteral) Token {1924 pub fn firstToken(self: &UndefinedLiteral) TokenIndex {
1614 return self.token;1925 return self.token;
1615 }1926 }
16161927
1617 pub fn lastToken(self: &UndefinedLiteral) Token {1928 pub fn lastToken(self: &UndefinedLiteral) TokenIndex {
1618 return self.token;1929 return self.token;
1619 }1930 }
1620 };1931 };
16211932
1622 pub const ThisLiteral = struct {1933 pub const ThisLiteral = struct {
1623 base: Node,1934 base: Node,
1624 token: Token,1935 token: TokenIndex,
16251936
1626 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {1937 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {
1627 return null;1938 return null;
1628 }1939 }
16291940
1630 pub fn firstToken(self: &ThisLiteral) Token {1941 pub fn firstToken(self: &ThisLiteral) TokenIndex {
1631 return self.token;1942 return self.token;
1632 }1943 }
16331944
1634 pub fn lastToken(self: &ThisLiteral) Token {1945 pub fn lastToken(self: &ThisLiteral) TokenIndex {
1635 return self.token;1946 return self.token;
1636 }1947 }
1637 };1948 };
...@@ -1670,11 +1981,11 @@ pub const Node = struct {...@@ -1670,11 +1981,11 @@ pub const Node = struct {
1670 return null;1981 return null;
1671 }1982 }
16721983
1673 pub fn firstToken(self: &AsmOutput) Token {1984 pub fn firstToken(self: &AsmOutput) TokenIndex {
1674 return self.symbolic_name.firstToken();1985 return self.symbolic_name.firstToken();
1675 }1986 }
16761987
1677 pub fn lastToken(self: &AsmOutput) Token {1988 pub fn lastToken(self: &AsmOutput) TokenIndex {
1678 return switch (self.kind) {1989 return switch (self.kind) {
1679 Kind.Variable => |variable_name| variable_name.lastToken(),1990 Kind.Variable => |variable_name| variable_name.lastToken(),
1680 Kind.Return => |return_type| return_type.lastToken(),1991 Kind.Return => |return_type| return_type.lastToken(),
...@@ -1703,139 +2014,144 @@ pub const Node = struct {...@@ -1703,139 +2014,144 @@ pub const Node = struct {
1703 return null;2014 return null;
1704 }2015 }
17052016
1706 pub fn firstToken(self: &AsmInput) Token {2017 pub fn firstToken(self: &AsmInput) TokenIndex {
1707 return self.symbolic_name.firstToken();2018 return self.symbolic_name.firstToken();
1708 }2019 }
17092020
1710 pub fn lastToken(self: &AsmInput) Token {2021 pub fn lastToken(self: &AsmInput) TokenIndex {
1711 return self.expr.lastToken();2022 return self.expr.lastToken();
1712 }2023 }
1713 };2024 };
17142025
1715 pub const Asm = struct {2026 pub const Asm = struct {
1716 base: Node,2027 base: Node,
1717 asm_token: Token,2028 asm_token: TokenIndex,
1718 volatile_token: ?Token,2029 volatile_token: ?TokenIndex,
1719 template: &Node,2030 template: &Node,
1720 //tokens: ArrayList(AsmToken),2031 outputs: OutputList,
1721 outputs: ArrayList(&AsmOutput),2032 inputs: InputList,
1722 inputs: ArrayList(&AsmInput),2033 clobbers: ClobberList,
1723 cloppers: ArrayList(&Node),2034 rparen: TokenIndex,
1724 rparen: Token,2035
2036 const OutputList = SegmentedList(&AsmOutput, 2);
2037 const InputList = SegmentedList(&AsmInput, 2);
2038 const ClobberList = SegmentedList(&Node, 2);
17252039
1726 pub fn iterate(self: &Asm, index: usize) ?&Node {2040 pub fn iterate(self: &Asm, index: usize) ?&Node {
1727 var i = index;2041 var i = index;
17282042
1729 if (i < self.outputs.len) return &self.outputs.at(index).base;2043 if (i < self.outputs.len) return &(*self.outputs.at(index)).base;
1730 i -= self.outputs.len;2044 i -= self.outputs.len;
17312045
1732 if (i < self.inputs.len) return &self.inputs.at(index).base;2046 if (i < self.inputs.len) return &(*self.inputs.at(index)).base;
1733 i -= self.inputs.len;2047 i -= self.inputs.len;
17342048
1735 if (i < self.cloppers.len) return self.cloppers.at(index);2049 if (i < self.clobbers.len) return *self.clobbers.at(index);
1736 i -= self.cloppers.len;2050 i -= self.clobbers.len;
17372051
1738 return null;2052 return null;
1739 }2053 }
17402054
1741 pub fn firstToken(self: &Asm) Token {2055 pub fn firstToken(self: &Asm) TokenIndex {
1742 return self.asm_token;2056 return self.asm_token;
1743 }2057 }
17442058
1745 pub fn lastToken(self: &Asm) Token {2059 pub fn lastToken(self: &Asm) TokenIndex {
1746 return self.rparen;2060 return self.rparen;
1747 }2061 }
1748 };2062 };
17492063
1750 pub const Unreachable = struct {2064 pub const Unreachable = struct {
1751 base: Node,2065 base: Node,
1752 token: Token,2066 token: TokenIndex,
17532067
1754 pub fn iterate(self: &Unreachable, index: usize) ?&Node {2068 pub fn iterate(self: &Unreachable, index: usize) ?&Node {
1755 return null;2069 return null;
1756 }2070 }
17572071
1758 pub fn firstToken(self: &Unreachable) Token {2072 pub fn firstToken(self: &Unreachable) TokenIndex {
1759 return self.token;2073 return self.token;
1760 }2074 }
17612075
1762 pub fn lastToken(self: &Unreachable) Token {2076 pub fn lastToken(self: &Unreachable) TokenIndex {
1763 return self.token;2077 return self.token;
1764 }2078 }
1765 };2079 };
17662080
1767 pub const ErrorType = struct {2081 pub const ErrorType = struct {
1768 base: Node,2082 base: Node,
1769 token: Token,2083 token: TokenIndex,
17702084
1771 pub fn iterate(self: &ErrorType, index: usize) ?&Node {2085 pub fn iterate(self: &ErrorType, index: usize) ?&Node {
1772 return null;2086 return null;
1773 }2087 }
17742088
1775 pub fn firstToken(self: &ErrorType) Token {2089 pub fn firstToken(self: &ErrorType) TokenIndex {
1776 return self.token;2090 return self.token;
1777 }2091 }
17782092
1779 pub fn lastToken(self: &ErrorType) Token {2093 pub fn lastToken(self: &ErrorType) TokenIndex {
1780 return self.token;2094 return self.token;
1781 }2095 }
1782 };2096 };
17832097
1784 pub const VarType = struct {2098 pub const VarType = struct {
1785 base: Node,2099 base: Node,
1786 token: Token,2100 token: TokenIndex,
17872101
1788 pub fn iterate(self: &VarType, index: usize) ?&Node {2102 pub fn iterate(self: &VarType, index: usize) ?&Node {
1789 return null;2103 return null;
1790 }2104 }
17912105
1792 pub fn firstToken(self: &VarType) Token {2106 pub fn firstToken(self: &VarType) TokenIndex {
1793 return self.token;2107 return self.token;
1794 }2108 }
17952109
1796 pub fn lastToken(self: &VarType) Token {2110 pub fn lastToken(self: &VarType) TokenIndex {
1797 return self.token;2111 return self.token;
1798 }2112 }
1799 };2113 };
18002114
1801 pub const LineComment = struct {2115 pub const LineComment = struct {
1802 base: Node,2116 base: Node,
1803 token: Token,2117 token: TokenIndex,
18042118
1805 pub fn iterate(self: &LineComment, index: usize) ?&Node {2119 pub fn iterate(self: &LineComment, index: usize) ?&Node {
1806 return null;2120 return null;
1807 }2121 }
18082122
1809 pub fn firstToken(self: &LineComment) Token {2123 pub fn firstToken(self: &LineComment) TokenIndex {
1810 return self.token;2124 return self.token;
1811 }2125 }
18122126
1813 pub fn lastToken(self: &LineComment) Token {2127 pub fn lastToken(self: &LineComment) TokenIndex {
1814 return self.token;2128 return self.token;
1815 }2129 }
1816 };2130 };
18172131
1818 pub const DocComment = struct {2132 pub const DocComment = struct {
1819 base: Node,2133 base: Node,
1820 lines: ArrayList(Token),2134 lines: LineList,
2135
2136 pub const LineList = SegmentedList(TokenIndex, 4);
18212137
1822 pub fn iterate(self: &DocComment, index: usize) ?&Node {2138 pub fn iterate(self: &DocComment, index: usize) ?&Node {
1823 return null;2139 return null;
1824 }2140 }
18252141
1826 pub fn firstToken(self: &DocComment) Token {2142 pub fn firstToken(self: &DocComment) TokenIndex {
1827 return self.lines.at(0);2143 return *self.lines.at(0);
1828 }2144 }
18292145
1830 pub fn lastToken(self: &DocComment) Token {2146 pub fn lastToken(self: &DocComment) TokenIndex {
1831 return self.lines.at(self.lines.len - 1);2147 return *self.lines.at(self.lines.len - 1);
1832 }2148 }
1833 };2149 };
18342150
1835 pub const TestDecl = struct {2151 pub const TestDecl = struct {
1836 base: Node,2152 base: Node,
1837 doc_comments: ?&DocComment,2153 doc_comments: ?&DocComment,
1838 test_token: Token,2154 test_token: TokenIndex,
1839 name: &Node,2155 name: &Node,
1840 body_node: &Node,2156 body_node: &Node,
18412157
...@@ -1848,11 +2164,11 @@ pub const Node = struct {...@@ -1848,11 +2164,11 @@ pub const Node = struct {
1848 return null;2164 return null;
1849 }2165 }
18502166
1851 pub fn firstToken(self: &TestDecl) Token {2167 pub fn firstToken(self: &TestDecl) TokenIndex {
1852 return self.test_token;2168 return self.test_token;
1853 }2169 }
18542170
1855 pub fn lastToken(self: &TestDecl) Token {2171 pub fn lastToken(self: &TestDecl) TokenIndex {
1856 return self.body_node.lastToken();2172 return self.body_node.lastToken();
1857 }2173 }
1858 };2174 };
std/zig/bench.zig created+38
...@@ -0,0 +1,38 @@
1const std = @import("std");
2const mem = std.mem;
3const warn = std.debug.warn;
4const Tokenizer = std.zig.Tokenizer;
5const Parser = std.zig.Parser;
6const io = std.io;
7
8const source = @embedFile("../os/index.zig");
9var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
10
11pub fn main() !void {
12 var i: usize = 0;
13 var timer = try std.os.time.Timer.start();
14 const start = timer.lap();
15 const iterations = 100;
16 var memory_used: usize = 0;
17 while (i < iterations) : (i += 1) {
18 memory_used += testOnce();
19 }
20 const end = timer.read();
21 memory_used /= iterations;
22 const elapsed_s = f64(end - start) / std.os.time.ns_per_s;
23 const bytes_per_sec = f64(source.len * iterations) / elapsed_s;
24 const mb_per_sec = bytes_per_sec / (1024 * 1024);
25
26 var stdout_file = try std.io.getStdOut();
27 const stdout = &std.io.FileOutStream.init(&stdout_file).stream;
28 try stdout.print("{.3} MB/s, {} KB used \n", mb_per_sec, memory_used / 1024);
29}
30
31fn testOnce() usize {
32 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
33 var allocator = &fixed_buf_alloc.allocator;
34 var tokenizer = Tokenizer.init(source);
35 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");
36 _ = parser.parse() catch @panic("parse failure");
37 return fixed_buf_alloc.end_index;
38}
std/zig/index.zig+5-3
...@@ -1,11 +1,13 @@...@@ -1,11 +1,13 @@
1const tokenizer = @import("tokenizer.zig");1const tokenizer = @import("tokenizer.zig");
2pub const Token = tokenizer.Token;2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;3pub const Tokenizer = tokenizer.Tokenizer;
4pub const Parser = @import("parser.zig").Parser;4pub const parse = @import("parse.zig").parse;
5pub const render = @import("render.zig").render;
5pub const ast = @import("ast.zig");6pub const ast = @import("ast.zig");
67
7test "std.zig tests" {8test "std.zig tests" {
8 _ = @import("tokenizer.zig");
9 _ = @import("parser.zig");
10 _ = @import("ast.zig");9 _ = @import("ast.zig");
10 _ = @import("parse.zig");
11 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");
11}13}
std/zig/parse.zig created+3503
...@@ -0,0 +1,3503 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Tokenizer = std.zig.Tokenizer;
6const Token = std.zig.Token;
7const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;
9
10/// Returns an AST tree, allocated with the parser's allocator.
11/// Result should be freed with tree.deinit() when there are
12/// no more references to any AST nodes of the tree.
13pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
14 var tree_arena = std.heap.ArenaAllocator.init(allocator);
15 errdefer tree_arena.deinit();
16
17 var stack = std.ArrayList(State).init(allocator);
18 defer stack.deinit();
19
20 const arena = &tree_arena.allocator;
21 const root_node = try createNode(arena, ast.Node.Root,
22 ast.Node.Root {
23 .base = undefined,
24 .decls = ast.Node.Root.DeclList.init(arena),
25 .doc_comments = null,
26 // initialized when we get the eof token
27 .eof_token = undefined,
28 }
29 );
30
31 var tree = ast.Tree {
32 .source = source,
33 .root_node = root_node,
34 .arena_allocator = tree_arena,
35 .tokens = ast.Tree.TokenList.init(arena),
36 .errors = ast.Tree.ErrorList.init(arena),
37 };
38
39 var tokenizer = Tokenizer.init(tree.source);
40 while (true) {
41 const token_ptr = try tree.tokens.addOne();
42 *token_ptr = tokenizer.next();
43 if (token_ptr.id == Token.Id.Eof)
44 break;
45 }
46 var tok_it = tree.tokens.iterator(0);
47
48 try stack.append(State.TopLevel);
49
50 while (true) {
51 // This gives us 1 free push that can't fail
52 const state = stack.pop();
53
54 switch (state) {
55 State.TopLevel => {
56 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
57 try root_node.decls.push(&line_comment.base);
58 }
59
60 const comments = try eatDocComments(arena, &tok_it, &tree);
61
62 const token = nextToken(&tok_it, &tree);
63 const token_index = token.index;
64 const token_ptr = token.ptr;
65 switch (token_ptr.id) {
66 Token.Id.Keyword_test => {
67 stack.append(State.TopLevel) catch unreachable;
68
69 const block = try arena.construct(ast.Node.Block {
70 .base = ast.Node {
71 .id = ast.Node.Id.Block,
72 },
73 .label = null,
74 .lbrace = undefined,
75 .statements = ast.Node.Block.StatementList.init(arena),
76 .rbrace = undefined,
77 });
78 const test_node = try arena.construct(ast.Node.TestDecl {
79 .base = ast.Node {
80 .id = ast.Node.Id.TestDecl,
81 },
82 .doc_comments = comments,
83 .test_token = token_index,
84 .name = undefined,
85 .body_node = &block.base,
86 });
87 try root_node.decls.push(&test_node.base);
88 try stack.append(State { .Block = block });
89 try stack.append(State {
90 .ExpectTokenSave = ExpectTokenSave {
91 .id = Token.Id.LBrace,
92 .ptr = &block.rbrace,
93 }
94 });
95 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
96 continue;
97 },
98 Token.Id.Eof => {
99 root_node.eof_token = token_index;
100 root_node.doc_comments = comments;
101 return tree;
102 },
103 Token.Id.Keyword_pub => {
104 stack.append(State.TopLevel) catch unreachable;
105 try stack.append(State {
106 .TopLevelExtern = TopLevelDeclCtx {
107 .decls = &root_node.decls,
108 .visib_token = token_index,
109 .extern_export_inline_token = null,
110 .lib_name = null,
111 .comments = comments,
112 }
113 });
114 continue;
115 },
116 Token.Id.Keyword_comptime => {
117 const block = try createNode(arena, ast.Node.Block,
118 ast.Node.Block {
119 .base = undefined,
120 .label = null,
121 .lbrace = undefined,
122 .statements = ast.Node.Block.StatementList.init(arena),
123 .rbrace = undefined,
124 }
125 );
126 const node = try arena.construct(ast.Node.Comptime {
127 .base = ast.Node {
128 .id = ast.Node.Id.Comptime,
129 },
130 .comptime_token = token_index,
131 .expr = &block.base,
132 .doc_comments = comments,
133 });
134 try root_node.decls.push(&node.base);
135
136 stack.append(State.TopLevel) catch unreachable;
137 try stack.append(State { .Block = block });
138 try stack.append(State {
139 .ExpectTokenSave = ExpectTokenSave {
140 .id = Token.Id.LBrace,
141 .ptr = &block.rbrace,
142 }
143 });
144 continue;
145 },
146 else => {
147 putBackToken(&tok_it, &tree);
148 stack.append(State.TopLevel) catch unreachable;
149 try stack.append(State {
150 .TopLevelExtern = TopLevelDeclCtx {
151 .decls = &root_node.decls,
152 .visib_token = null,
153 .extern_export_inline_token = null,
154 .lib_name = null,
155 .comments = comments,
156 }
157 });
158 continue;
159 },
160 }
161 },
162 State.TopLevelExtern => |ctx| {
163 const token = nextToken(&tok_it, &tree);
164 const token_index = token.index;
165 const token_ptr = token.ptr;
166 switch (token_ptr.id) {
167 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
168 stack.append(State {
169 .TopLevelDecl = TopLevelDeclCtx {
170 .decls = ctx.decls,
171 .visib_token = ctx.visib_token,
172 .extern_export_inline_token = AnnotatedToken {
173 .index = token_index,
174 .ptr = token_ptr,
175 },
176 .lib_name = null,
177 .comments = ctx.comments,
178 },
179 }) catch unreachable;
180 continue;
181 },
182 Token.Id.Keyword_extern => {
183 stack.append(State {
184 .TopLevelLibname = TopLevelDeclCtx {
185 .decls = ctx.decls,
186 .visib_token = ctx.visib_token,
187 .extern_export_inline_token = AnnotatedToken {
188 .index = token_index,
189 .ptr = token_ptr,
190 },
191 .lib_name = null,
192 .comments = ctx.comments,
193 },
194 }) catch unreachable;
195 continue;
196 },
197 else => {
198 putBackToken(&tok_it, &tree);
199 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
200 continue;
201 }
202 }
203 },
204 State.TopLevelLibname => |ctx| {
205 const lib_name = blk: {
206 const lib_name_token = nextToken(&tok_it, &tree);
207 const lib_name_token_index = lib_name_token.index;
208 const lib_name_token_ptr = lib_name_token.ptr;
209 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
210 putBackToken(&tok_it, &tree);
211 break :blk null;
212 };
213 };
214
215 stack.append(State {
216 .TopLevelDecl = TopLevelDeclCtx {
217 .decls = ctx.decls,
218 .visib_token = ctx.visib_token,
219 .extern_export_inline_token = ctx.extern_export_inline_token,
220 .lib_name = lib_name,
221 .comments = ctx.comments,
222 },
223 }) catch unreachable;
224 continue;
225 },
226 State.TopLevelDecl => |ctx| {
227 const token = nextToken(&tok_it, &tree);
228 const token_index = token.index;
229 const token_ptr = token.ptr;
230 switch (token_ptr.id) {
231 Token.Id.Keyword_use => {
232 if (ctx.extern_export_inline_token) |annotated_token| {
233 *(try tree.errors.addOne()) = Error {
234 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
235 };
236 return tree;
237 }
238
239 const node = try arena.construct(ast.Node.Use {
240 .base = ast.Node {.id = ast.Node.Id.Use },
241 .visib_token = ctx.visib_token,
242 .expr = undefined,
243 .semicolon_token = undefined,
244 .doc_comments = ctx.comments,
245 });
246 try ctx.decls.push(&node.base);
247
248 stack.append(State {
249 .ExpectTokenSave = ExpectTokenSave {
250 .id = Token.Id.Semicolon,
251 .ptr = &node.semicolon_token,
252 }
253 }) catch unreachable;
254 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
255 continue;
256 },
257 Token.Id.Keyword_var, Token.Id.Keyword_const => {
258 if (ctx.extern_export_inline_token) |annotated_token| {
259 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
260 *(try tree.errors.addOne()) = Error {
261 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
262 };
263 return tree;
264 }
265 }
266
267 try stack.append(State {
268 .VarDecl = VarDeclCtx {
269 .comments = ctx.comments,
270 .visib_token = ctx.visib_token,
271 .lib_name = ctx.lib_name,
272 .comptime_token = null,
273 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
274 .mut_token = token_index,
275 .list = ctx.decls
276 }
277 });
278 continue;
279 },
280 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
281 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
282 const fn_proto = try arena.construct(ast.Node.FnProto {
283 .base = ast.Node {
284 .id = ast.Node.Id.FnProto,
285 },
286 .doc_comments = ctx.comments,
287 .visib_token = ctx.visib_token,
288 .name_token = null,
289 .fn_token = undefined,
290 .params = ast.Node.FnProto.ParamList.init(arena),
291 .return_type = undefined,
292 .var_args_token = null,
293 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
294 .cc_token = null,
295 .async_attr = null,
296 .body_node = null,
297 .lib_name = ctx.lib_name,
298 .align_expr = null,
299 });
300 try ctx.decls.push(&fn_proto.base);
301 stack.append(State { .FnDef = fn_proto }) catch unreachable;
302 try stack.append(State { .FnProto = fn_proto });
303
304 switch (token_ptr.id) {
305 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
306 fn_proto.cc_token = token_index;
307 try stack.append(State {
308 .ExpectTokenSave = ExpectTokenSave {
309 .id = Token.Id.Keyword_fn,
310 .ptr = &fn_proto.fn_token,
311 }
312 });
313 continue;
314 },
315 Token.Id.Keyword_async => {
316 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
317 ast.Node.AsyncAttribute {
318 .base = undefined,
319 .async_token = token_index,
320 .allocator_type = null,
321 .rangle_bracket = null,
322 }
323 );
324 fn_proto.async_attr = async_node;
325
326 try stack.append(State {
327 .ExpectTokenSave = ExpectTokenSave {
328 .id = Token.Id.Keyword_fn,
329 .ptr = &fn_proto.fn_token,
330 }
331 });
332 try stack.append(State { .AsyncAllocator = async_node });
333 continue;
334 },
335 Token.Id.Keyword_fn => {
336 fn_proto.fn_token = token_index;
337 continue;
338 },
339 else => unreachable,
340 }
341 },
342 else => {
343 *(try tree.errors.addOne()) = Error {
344 .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn { .token = token_index },
345 };
346 return tree;
347 },
348 }
349 },
350 State.TopLevelExternOrField => |ctx| {
351 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
352 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
353 const node = try arena.construct(ast.Node.StructField {
354 .base = ast.Node {
355 .id = ast.Node.Id.StructField,
356 },
357 .doc_comments = ctx.comments,
358 .visib_token = ctx.visib_token,
359 .name_token = identifier,
360 .type_expr = undefined,
361 });
362 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
363 *node_ptr = &node.base;
364
365 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
366 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
367 try stack.append(State { .ExpectToken = Token.Id.Colon });
368 continue;
369 }
370
371 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
372 try stack.append(State {
373 .TopLevelExtern = TopLevelDeclCtx {
374 .decls = &ctx.container_decl.fields_and_decls,
375 .visib_token = ctx.visib_token,
376 .extern_export_inline_token = null,
377 .lib_name = null,
378 .comments = ctx.comments,
379 }
380 });
381 continue;
382 },
383
384 State.FieldInitValue => |ctx| {
385 const eq_tok = nextToken(&tok_it, &tree);
386 const eq_tok_index = eq_tok.index;
387 const eq_tok_ptr = eq_tok.ptr;
388 if (eq_tok_ptr.id != Token.Id.Equal) {
389 putBackToken(&tok_it, &tree);
390 continue;
391 }
392 stack.append(State { .Expression = ctx }) catch unreachable;
393 continue;
394 },
395
396 State.ContainerKind => |ctx| {
397 const token = nextToken(&tok_it, &tree);
398 const token_index = token.index;
399 const token_ptr = token.ptr;
400 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
401 ast.Node.ContainerDecl {
402 .base = undefined,
403 .ltoken = ctx.ltoken,
404 .layout = ctx.layout,
405 .kind = switch (token_ptr.id) {
406 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
407 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
408 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
409 else => {
410 *(try tree.errors.addOne()) = Error {
411 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
412 };
413 return tree;
414 },
415 },
416 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
417 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
418 .rbrace_token = undefined,
419 }
420 );
421
422 stack.append(State { .ContainerDecl = node }) catch unreachable;
423 try stack.append(State { .ExpectToken = Token.Id.LBrace });
424 try stack.append(State { .ContainerInitArgStart = node });
425 continue;
426 },
427
428 State.ContainerInitArgStart => |container_decl| {
429 if (eatToken(&tok_it, &tree, Token.Id.LParen) == null) {
430 continue;
431 }
432
433 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
434 try stack.append(State { .ContainerInitArg = container_decl });
435 continue;
436 },
437
438 State.ContainerInitArg => |container_decl| {
439 const init_arg_token = nextToken(&tok_it, &tree);
440 const init_arg_token_index = init_arg_token.index;
441 const init_arg_token_ptr = init_arg_token.ptr;
442 switch (init_arg_token_ptr.id) {
443 Token.Id.Keyword_enum => {
444 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
445 const lparen_tok = nextToken(&tok_it, &tree);
446 const lparen_tok_index = lparen_tok.index;
447 const lparen_tok_ptr = lparen_tok.ptr;
448 if (lparen_tok_ptr.id == Token.Id.LParen) {
449 try stack.append(State { .ExpectToken = Token.Id.RParen } );
450 try stack.append(State { .Expression = OptionalCtx {
451 .RequiredNull = &container_decl.init_arg_expr.Enum,
452 } });
453 } else {
454 putBackToken(&tok_it, &tree);
455 }
456 },
457 else => {
458 putBackToken(&tok_it, &tree);
459 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
460 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
461 },
462 }
463 continue;
464 },
465
466 State.ContainerDecl => |container_decl| {
467 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
468 try container_decl.fields_and_decls.push(&line_comment.base);
469 }
470
471 const comments = try eatDocComments(arena, &tok_it, &tree);
472 const token = nextToken(&tok_it, &tree);
473 const token_index = token.index;
474 const token_ptr = token.ptr;
475 switch (token_ptr.id) {
476 Token.Id.Identifier => {
477 switch (container_decl.kind) {
478 ast.Node.ContainerDecl.Kind.Struct => {
479 const node = try arena.construct(ast.Node.StructField {
480 .base = ast.Node {
481 .id = ast.Node.Id.StructField,
482 },
483 .doc_comments = comments,
484 .visib_token = null,
485 .name_token = token_index,
486 .type_expr = undefined,
487 });
488 const node_ptr = try container_decl.fields_and_decls.addOne();
489 *node_ptr = &node.base;
490
491 try stack.append(State { .FieldListCommaOrEnd = container_decl });
492 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
493 try stack.append(State { .ExpectToken = Token.Id.Colon });
494 continue;
495 },
496 ast.Node.ContainerDecl.Kind.Union => {
497 const node = try arena.construct(ast.Node.UnionTag {
498 .base = ast.Node {.id = ast.Node.Id.UnionTag },
499 .name_token = token_index,
500 .type_expr = null,
501 .value_expr = null,
502 .doc_comments = comments,
503 });
504 try container_decl.fields_and_decls.push(&node.base);
505
506 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
507 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
508 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
509 try stack.append(State { .IfToken = Token.Id.Colon });
510 continue;
511 },
512 ast.Node.ContainerDecl.Kind.Enum => {
513 const node = try arena.construct(ast.Node.EnumTag {
514 .base = ast.Node { .id = ast.Node.Id.EnumTag },
515 .name_token = token_index,
516 .value = null,
517 .doc_comments = comments,
518 });
519 try container_decl.fields_and_decls.push(&node.base);
520
521 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
522 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
523 try stack.append(State { .IfToken = Token.Id.Equal });
524 continue;
525 },
526 }
527 },
528 Token.Id.Keyword_pub => {
529 switch (container_decl.kind) {
530 ast.Node.ContainerDecl.Kind.Struct => {
531 try stack.append(State {
532 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
533 .visib_token = token_index,
534 .container_decl = container_decl,
535 .comments = comments,
536 }
537 });
538 continue;
539 },
540 else => {
541 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
542 try stack.append(State {
543 .TopLevelExtern = TopLevelDeclCtx {
544 .decls = &container_decl.fields_and_decls,
545 .visib_token = token_index,
546 .extern_export_inline_token = null,
547 .lib_name = null,
548 .comments = comments,
549 }
550 });
551 continue;
552 }
553 }
554 },
555 Token.Id.Keyword_export => {
556 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
557 try stack.append(State {
558 .TopLevelExtern = TopLevelDeclCtx {
559 .decls = &container_decl.fields_and_decls,
560 .visib_token = token_index,
561 .extern_export_inline_token = null,
562 .lib_name = null,
563 .comments = comments,
564 }
565 });
566 continue;
567 },
568 Token.Id.RBrace => {
569 if (comments != null) {
570 *(try tree.errors.addOne()) = Error {
571 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
572 };
573 return tree;
574 }
575 container_decl.rbrace_token = token_index;
576 continue;
577 },
578 else => {
579 putBackToken(&tok_it, &tree);
580 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
581 try stack.append(State {
582 .TopLevelExtern = TopLevelDeclCtx {
583 .decls = &container_decl.fields_and_decls,
584 .visib_token = null,
585 .extern_export_inline_token = null,
586 .lib_name = null,
587 .comments = comments,
588 }
589 });
590 continue;
591 }
592 }
593 },
594
595
596 State.VarDecl => |ctx| {
597 const var_decl = try arena.construct(ast.Node.VarDecl {
598 .base = ast.Node {
599 .id = ast.Node.Id.VarDecl,
600 },
601 .doc_comments = ctx.comments,
602 .visib_token = ctx.visib_token,
603 .mut_token = ctx.mut_token,
604 .comptime_token = ctx.comptime_token,
605 .extern_export_token = ctx.extern_export_token,
606 .type_node = null,
607 .align_node = null,
608 .init_node = null,
609 .lib_name = ctx.lib_name,
610 // initialized later
611 .name_token = undefined,
612 .eq_token = undefined,
613 .semicolon_token = undefined,
614 });
615 try ctx.list.push(&var_decl.base);
616
617 try stack.append(State { .VarDeclAlign = var_decl });
618 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
619 try stack.append(State { .IfToken = Token.Id.Colon });
620 try stack.append(State {
621 .ExpectTokenSave = ExpectTokenSave {
622 .id = Token.Id.Identifier,
623 .ptr = &var_decl.name_token,
624 }
625 });
626 continue;
627 },
628 State.VarDeclAlign => |var_decl| {
629 try stack.append(State { .VarDeclEq = var_decl });
630
631 const next_token = nextToken(&tok_it, &tree);
632 const next_token_index = next_token.index;
633 const next_token_ptr = next_token.ptr;
634 if (next_token_ptr.id == Token.Id.Keyword_align) {
635 try stack.append(State { .ExpectToken = Token.Id.RParen });
636 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
637 try stack.append(State { .ExpectToken = Token.Id.LParen });
638 continue;
639 }
640
641 putBackToken(&tok_it, &tree);
642 continue;
643 },
644 State.VarDeclEq => |var_decl| {
645 const token = nextToken(&tok_it, &tree);
646 const token_index = token.index;
647 const token_ptr = token.ptr;
648 switch (token_ptr.id) {
649 Token.Id.Equal => {
650 var_decl.eq_token = token_index;
651 stack.append(State {
652 .ExpectTokenSave = ExpectTokenSave {
653 .id = Token.Id.Semicolon,
654 .ptr = &var_decl.semicolon_token,
655 },
656 }) catch unreachable;
657 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
658 continue;
659 },
660 Token.Id.Semicolon => {
661 var_decl.semicolon_token = token_index;
662 continue;
663 },
664 else => {
665 *(try tree.errors.addOne()) = Error {
666 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
667 };
668 return tree;
669 }
670 }
671 },
672
673
674 State.FnDef => |fn_proto| {
675 const token = nextToken(&tok_it, &tree);
676 const token_index = token.index;
677 const token_ptr = token.ptr;
678 switch(token_ptr.id) {
679 Token.Id.LBrace => {
680 const block = try arena.construct(ast.Node.Block {
681 .base = ast.Node { .id = ast.Node.Id.Block },
682 .label = null,
683 .lbrace = token_index,
684 .statements = ast.Node.Block.StatementList.init(arena),
685 .rbrace = undefined,
686 });
687 fn_proto.body_node = &block.base;
688 stack.append(State { .Block = block }) catch unreachable;
689 continue;
690 },
691 Token.Id.Semicolon => continue,
692 else => {
693 *(try tree.errors.addOne()) = Error {
694 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
695 };
696 return tree;
697 },
698 }
699 },
700 State.FnProto => |fn_proto| {
701 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
702 try stack.append(State { .ParamDecl = fn_proto });
703 try stack.append(State { .ExpectToken = Token.Id.LParen });
704
705 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {
706 fn_proto.name_token = name_token;
707 }
708 continue;
709 },
710 State.FnProtoAlign => |fn_proto| {
711 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
712
713 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {
714 try stack.append(State { .ExpectToken = Token.Id.RParen });
715 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
716 try stack.append(State { .ExpectToken = Token.Id.LParen });
717 }
718 continue;
719 },
720 State.FnProtoReturnType => |fn_proto| {
721 const token = nextToken(&tok_it, &tree);
722 const token_index = token.index;
723 const token_ptr = token.ptr;
724 switch (token_ptr.id) {
725 Token.Id.Bang => {
726 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
727 stack.append(State {
728 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
729 }) catch unreachable;
730 continue;
731 },
732 else => {
733 // TODO: this is a special case. Remove this when #760 is fixed
734 if (token_ptr.id == Token.Id.Keyword_error) {
735 if ((??tok_it.peek()).id == Token.Id.LBrace) {
736 const error_type_node = try arena.construct(ast.Node.ErrorType {
737 .base = ast.Node { .id = ast.Node.Id.ErrorType },
738 .token = token_index,
739 });
740 fn_proto.return_type = ast.Node.FnProto.ReturnType {
741 .Explicit = &error_type_node.base,
742 };
743 continue;
744 }
745 }
746
747 putBackToken(&tok_it, &tree);
748 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
749 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
750 continue;
751 },
752 }
753 },
754
755
756 State.ParamDecl => |fn_proto| {
757 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
758 continue;
759 }
760 const param_decl = try arena.construct(ast.Node.ParamDecl {
761 .base = ast.Node {.id = ast.Node.Id.ParamDecl },
762 .comptime_token = null,
763 .noalias_token = null,
764 .name_token = null,
765 .type_node = undefined,
766 .var_args_token = null,
767 });
768 try fn_proto.params.push(&param_decl.base);
769
770 stack.append(State {
771 .ParamDeclEnd = ParamDeclEndCtx {
772 .param_decl = param_decl,
773 .fn_proto = fn_proto,
774 }
775 }) catch unreachable;
776 try stack.append(State { .ParamDeclName = param_decl });
777 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
778 continue;
779 },
780 State.ParamDeclAliasOrComptime => |param_decl| {
781 if (eatToken(&tok_it, &tree, Token.Id.Keyword_comptime)) |comptime_token| {
782 param_decl.comptime_token = comptime_token;
783 } else if (eatToken(&tok_it, &tree, Token.Id.Keyword_noalias)) |noalias_token| {
784 param_decl.noalias_token = noalias_token;
785 }
786 continue;
787 },
788 State.ParamDeclName => |param_decl| {
789 // TODO: Here, we eat two tokens in one state. This means that we can't have
790 // comments between these two tokens.
791 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
792 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
793 param_decl.name_token = ident_token;
794 } else {
795 putBackToken(&tok_it, &tree);
796 }
797 }
798 continue;
799 },
800 State.ParamDeclEnd => |ctx| {
801 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
802 ctx.param_decl.var_args_token = ellipsis3;
803 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
804 continue;
805 }
806
807 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
808 try stack.append(State {
809 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
810 });
811 continue;
812 },
813 State.ParamDeclComma => |fn_proto| {
814 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
815 ExpectCommaOrEndResult.end_token => |t| {
816 if (t == null) {
817 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
818 }
819 continue;
820 },
821 ExpectCommaOrEndResult.parse_error => |e| {
822 try tree.errors.push(e);
823 return tree;
824 },
825 }
826 },
827
828 State.MaybeLabeledExpression => |ctx| {
829 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
830 stack.append(State {
831 .LabeledExpression = LabelCtx {
832 .label = ctx.label,
833 .opt_ctx = ctx.opt_ctx,
834 }
835 }) catch unreachable;
836 continue;
837 }
838
839 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
840 continue;
841 },
842 State.LabeledExpression => |ctx| {
843 const token = nextToken(&tok_it, &tree);
844 const token_index = token.index;
845 const token_ptr = token.ptr;
846 switch (token_ptr.id) {
847 Token.Id.LBrace => {
848 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
849 ast.Node.Block {
850 .base = undefined,
851 .label = ctx.label,
852 .lbrace = token_index,
853 .statements = ast.Node.Block.StatementList.init(arena),
854 .rbrace = undefined,
855 }
856 );
857 stack.append(State { .Block = block }) catch unreachable;
858 continue;
859 },
860 Token.Id.Keyword_while => {
861 stack.append(State {
862 .While = LoopCtx {
863 .label = ctx.label,
864 .inline_token = null,
865 .loop_token = token_index,
866 .opt_ctx = ctx.opt_ctx.toRequired(),
867 }
868 }) catch unreachable;
869 continue;
870 },
871 Token.Id.Keyword_for => {
872 stack.append(State {
873 .For = LoopCtx {
874 .label = ctx.label,
875 .inline_token = null,
876 .loop_token = token_index,
877 .opt_ctx = ctx.opt_ctx.toRequired(),
878 }
879 }) catch unreachable;
880 continue;
881 },
882 Token.Id.Keyword_suspend => {
883 const node = try arena.construct(ast.Node.Suspend {
884 .base = ast.Node {
885 .id = ast.Node.Id.Suspend,
886 },
887 .label = ctx.label,
888 .suspend_token = token_index,
889 .payload = null,
890 .body = null,
891 });
892 ctx.opt_ctx.store(&node.base);
893 stack.append(State { .SuspendBody = node }) catch unreachable;
894 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
895 continue;
896 },
897 Token.Id.Keyword_inline => {
898 stack.append(State {
899 .Inline = InlineCtx {
900 .label = ctx.label,
901 .inline_token = token_index,
902 .opt_ctx = ctx.opt_ctx.toRequired(),
903 }
904 }) catch unreachable;
905 continue;
906 },
907 else => {
908 if (ctx.opt_ctx != OptionalCtx.Optional) {
909 *(try tree.errors.addOne()) = Error {
910 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
911 };
912 return tree;
913 }
914
915 putBackToken(&tok_it, &tree);
916 continue;
917 },
918 }
919 },
920 State.Inline => |ctx| {
921 const token = nextToken(&tok_it, &tree);
922 const token_index = token.index;
923 const token_ptr = token.ptr;
924 switch (token_ptr.id) {
925 Token.Id.Keyword_while => {
926 stack.append(State {
927 .While = LoopCtx {
928 .inline_token = ctx.inline_token,
929 .label = ctx.label,
930 .loop_token = token_index,
931 .opt_ctx = ctx.opt_ctx.toRequired(),
932 }
933 }) catch unreachable;
934 continue;
935 },
936 Token.Id.Keyword_for => {
937 stack.append(State {
938 .For = LoopCtx {
939 .inline_token = ctx.inline_token,
940 .label = ctx.label,
941 .loop_token = token_index,
942 .opt_ctx = ctx.opt_ctx.toRequired(),
943 }
944 }) catch unreachable;
945 continue;
946 },
947 else => {
948 if (ctx.opt_ctx != OptionalCtx.Optional) {
949 *(try tree.errors.addOne()) = Error {
950 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
951 };
952 return tree;
953 }
954
955 putBackToken(&tok_it, &tree);
956 continue;
957 },
958 }
959 },
960 State.While => |ctx| {
961 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
962 ast.Node.While {
963 .base = undefined,
964 .label = ctx.label,
965 .inline_token = ctx.inline_token,
966 .while_token = ctx.loop_token,
967 .condition = undefined,
968 .payload = null,
969 .continue_expr = null,
970 .body = undefined,
971 .@"else" = null,
972 }
973 );
974 stack.append(State { .Else = &node.@"else" }) catch unreachable;
975 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
976 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
977 try stack.append(State { .IfToken = Token.Id.Colon });
978 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
979 try stack.append(State { .ExpectToken = Token.Id.RParen });
980 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
981 try stack.append(State { .ExpectToken = Token.Id.LParen });
982 continue;
983 },
984 State.WhileContinueExpr => |dest| {
985 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
986 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
987 try stack.append(State { .ExpectToken = Token.Id.LParen });
988 continue;
989 },
990 State.For => |ctx| {
991 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
992 ast.Node.For {
993 .base = undefined,
994 .label = ctx.label,
995 .inline_token = ctx.inline_token,
996 .for_token = ctx.loop_token,
997 .array_expr = undefined,
998 .payload = null,
999 .body = undefined,
1000 .@"else" = null,
1001 }
1002 );
1003 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1004 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1005 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1006 try stack.append(State { .ExpectToken = Token.Id.RParen });
1007 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1008 try stack.append(State { .ExpectToken = Token.Id.LParen });
1009 continue;
1010 },
1011 State.Else => |dest| {
1012 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
1013 const node = try createNode(arena, ast.Node.Else,
1014 ast.Node.Else {
1015 .base = undefined,
1016 .else_token = else_token,
1017 .payload = null,
1018 .body = undefined,
1019 }
1020 );
1021 *dest = node;
1022
1023 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1024 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1025 continue;
1026 } else {
1027 continue;
1028 }
1029 },
1030
1031
1032 State.Block => |block| {
1033 const token = nextToken(&tok_it, &tree);
1034 const token_index = token.index;
1035 const token_ptr = token.ptr;
1036 switch (token_ptr.id) {
1037 Token.Id.RBrace => {
1038 block.rbrace = token_index;
1039 continue;
1040 },
1041 else => {
1042 putBackToken(&tok_it, &tree);
1043 stack.append(State { .Block = block }) catch unreachable;
1044
1045 var any_comments = false;
1046 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1047 try block.statements.push(&line_comment.base);
1048 any_comments = true;
1049 }
1050 if (any_comments) continue;
1051
1052 try stack.append(State { .Statement = block });
1053 continue;
1054 },
1055 }
1056 },
1057 State.Statement => |block| {
1058 const token = nextToken(&tok_it, &tree);
1059 const token_index = token.index;
1060 const token_ptr = token.ptr;
1061 switch (token_ptr.id) {
1062 Token.Id.Keyword_comptime => {
1063 stack.append(State {
1064 .ComptimeStatement = ComptimeStatementCtx {
1065 .comptime_token = token_index,
1066 .block = block,
1067 }
1068 }) catch unreachable;
1069 continue;
1070 },
1071 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1072 stack.append(State {
1073 .VarDecl = VarDeclCtx {
1074 .comments = null,
1075 .visib_token = null,
1076 .comptime_token = null,
1077 .extern_export_token = null,
1078 .lib_name = null,
1079 .mut_token = token_index,
1080 .list = &block.statements,
1081 }
1082 }) catch unreachable;
1083 continue;
1084 },
1085 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1086 const node = try arena.construct(ast.Node.Defer {
1087 .base = ast.Node {
1088 .id = ast.Node.Id.Defer,
1089 },
1090 .defer_token = token_index,
1091 .kind = switch (token_ptr.id) {
1092 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1093 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1094 else => unreachable,
1095 },
1096 .expr = undefined,
1097 });
1098 const node_ptr = try block.statements.addOne();
1099 *node_ptr = &node.base;
1100
1101 stack.append(State { .Semicolon = node_ptr }) catch unreachable;
1102 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1103 continue;
1104 },
1105 Token.Id.LBrace => {
1106 const inner_block = try arena.construct(ast.Node.Block {
1107 .base = ast.Node { .id = ast.Node.Id.Block },
1108 .label = null,
1109 .lbrace = token_index,
1110 .statements = ast.Node.Block.StatementList.init(arena),
1111 .rbrace = undefined,
1112 });
1113 try block.statements.push(&inner_block.base);
1114
1115 stack.append(State { .Block = inner_block }) catch unreachable;
1116 continue;
1117 },
1118 else => {
1119 putBackToken(&tok_it, &tree);
1120 const statement = try block.statements.addOne();
1121 try stack.append(State { .Semicolon = statement });
1122 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1123 continue;
1124 }
1125 }
1126 },
1127 State.ComptimeStatement => |ctx| {
1128 const token = nextToken(&tok_it, &tree);
1129 const token_index = token.index;
1130 const token_ptr = token.ptr;
1131 switch (token_ptr.id) {
1132 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1133 stack.append(State {
1134 .VarDecl = VarDeclCtx {
1135 .comments = null,
1136 .visib_token = null,
1137 .comptime_token = ctx.comptime_token,
1138 .extern_export_token = null,
1139 .lib_name = null,
1140 .mut_token = token_index,
1141 .list = &ctx.block.statements,
1142 }
1143 }) catch unreachable;
1144 continue;
1145 },
1146 else => {
1147 putBackToken(&tok_it, &tree);
1148 putBackToken(&tok_it, &tree);
1149 const statement = try ctx.block.statements.addOne();
1150 try stack.append(State { .Semicolon = statement });
1151 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1152 continue;
1153 }
1154 }
1155 },
1156 State.Semicolon => |node_ptr| {
1157 const node = *node_ptr;
1158 if (node.requireSemiColon()) {
1159 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1160 continue;
1161 }
1162 continue;
1163 },
1164
1165 State.AsmOutputItems => |items| {
1166 const lbracket = nextToken(&tok_it, &tree);
1167 const lbracket_index = lbracket.index;
1168 const lbracket_ptr = lbracket.ptr;
1169 if (lbracket_ptr.id != Token.Id.LBracket) {
1170 putBackToken(&tok_it, &tree);
1171 continue;
1172 }
1173
1174 const node = try createNode(arena, ast.Node.AsmOutput,
1175 ast.Node.AsmOutput {
1176 .base = undefined,
1177 .symbolic_name = undefined,
1178 .constraint = undefined,
1179 .kind = undefined,
1180 }
1181 );
1182 try items.push(node);
1183
1184 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1185 try stack.append(State { .IfToken = Token.Id.Comma });
1186 try stack.append(State { .ExpectToken = Token.Id.RParen });
1187 try stack.append(State { .AsmOutputReturnOrType = node });
1188 try stack.append(State { .ExpectToken = Token.Id.LParen });
1189 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1190 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1191 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1192 continue;
1193 },
1194 State.AsmOutputReturnOrType => |node| {
1195 const token = nextToken(&tok_it, &tree);
1196 const token_index = token.index;
1197 const token_ptr = token.ptr;
1198 switch (token_ptr.id) {
1199 Token.Id.Identifier => {
1200 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1201 continue;
1202 },
1203 Token.Id.Arrow => {
1204 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1205 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1206 continue;
1207 },
1208 else => {
1209 *(try tree.errors.addOne()) = Error {
1210 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1211 .token = token_index,
1212 },
1213 };
1214 return tree;
1215 },
1216 }
1217 },
1218 State.AsmInputItems => |items| {
1219 const lbracket = nextToken(&tok_it, &tree);
1220 const lbracket_index = lbracket.index;
1221 const lbracket_ptr = lbracket.ptr;
1222 if (lbracket_ptr.id != Token.Id.LBracket) {
1223 putBackToken(&tok_it, &tree);
1224 continue;
1225 }
1226
1227 const node = try createNode(arena, ast.Node.AsmInput,
1228 ast.Node.AsmInput {
1229 .base = undefined,
1230 .symbolic_name = undefined,
1231 .constraint = undefined,
1232 .expr = undefined,
1233 }
1234 );
1235 try items.push(node);
1236
1237 stack.append(State { .AsmInputItems = items }) catch unreachable;
1238 try stack.append(State { .IfToken = Token.Id.Comma });
1239 try stack.append(State { .ExpectToken = Token.Id.RParen });
1240 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1241 try stack.append(State { .ExpectToken = Token.Id.LParen });
1242 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1243 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1244 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1245 continue;
1246 },
1247 State.AsmClobberItems => |items| {
1248 stack.append(State { .AsmClobberItems = items }) catch unreachable;
1249 try stack.append(State { .IfToken = Token.Id.Comma });
1250 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1251 continue;
1252 },
1253
1254
1255 State.ExprListItemOrEnd => |list_state| {
1256 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {
1257 *list_state.ptr = token_index;
1258 continue;
1259 }
1260
1261 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1262 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1263 continue;
1264 },
1265 State.ExprListCommaOrEnd => |list_state| {
1266 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {
1267 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1268 *list_state.ptr = end;
1269 continue;
1270 } else {
1271 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1272 continue;
1273 },
1274 ExpectCommaOrEndResult.parse_error => |e| {
1275 try tree.errors.push(e);
1276 return tree;
1277 },
1278 }
1279 },
1280 State.FieldInitListItemOrEnd => |list_state| {
1281 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1282 try list_state.list.push(&line_comment.base);
1283 }
1284
1285 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1286 *list_state.ptr = rbrace;
1287 continue;
1288 }
1289
1290 const node = try arena.construct(ast.Node.FieldInitializer {
1291 .base = ast.Node {
1292 .id = ast.Node.Id.FieldInitializer,
1293 },
1294 .period_token = undefined,
1295 .name_token = undefined,
1296 .expr = undefined,
1297 });
1298 try list_state.list.push(&node.base);
1299
1300 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1301 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1302 try stack.append(State { .ExpectToken = Token.Id.Equal });
1303 try stack.append(State {
1304 .ExpectTokenSave = ExpectTokenSave {
1305 .id = Token.Id.Identifier,
1306 .ptr = &node.name_token,
1307 }
1308 });
1309 try stack.append(State {
1310 .ExpectTokenSave = ExpectTokenSave {
1311 .id = Token.Id.Period,
1312 .ptr = &node.period_token,
1313 }
1314 });
1315 continue;
1316 },
1317 State.FieldInitListCommaOrEnd => |list_state| {
1318 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1319 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1320 *list_state.ptr = end;
1321 continue;
1322 } else {
1323 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1324 continue;
1325 },
1326 ExpectCommaOrEndResult.parse_error => |e| {
1327 try tree.errors.push(e);
1328 return tree;
1329 },
1330 }
1331 },
1332 State.FieldListCommaOrEnd => |container_decl| {
1333 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1334 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1335 container_decl.rbrace_token = end;
1336 continue;
1337 } else {
1338 try stack.append(State { .ContainerDecl = container_decl });
1339 continue;
1340 },
1341 ExpectCommaOrEndResult.parse_error => |e| {
1342 try tree.errors.push(e);
1343 return tree;
1344 },
1345 }
1346 },
1347 State.ErrorTagListItemOrEnd => |list_state| {
1348 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1349 try list_state.list.push(&line_comment.base);
1350 }
1351
1352 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1353 *list_state.ptr = rbrace;
1354 continue;
1355 }
1356
1357 const node_ptr = try list_state.list.addOne();
1358
1359 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1360 try stack.append(State { .ErrorTag = node_ptr });
1361 continue;
1362 },
1363 State.ErrorTagListCommaOrEnd => |list_state| {
1364 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1365 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1366 *list_state.ptr = end;
1367 continue;
1368 } else {
1369 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1370 continue;
1371 },
1372 ExpectCommaOrEndResult.parse_error => |e| {
1373 try tree.errors.push(e);
1374 return tree;
1375 },
1376 }
1377 },
1378 State.SwitchCaseOrEnd => |list_state| {
1379 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1380 try list_state.list.push(&line_comment.base);
1381 }
1382
1383 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1384 *list_state.ptr = rbrace;
1385 continue;
1386 }
1387
1388 const comments = try eatDocComments(arena, &tok_it, &tree);
1389 const node = try arena.construct(ast.Node.SwitchCase {
1390 .base = ast.Node {
1391 .id = ast.Node.Id.SwitchCase,
1392 },
1393 .items = ast.Node.SwitchCase.ItemList.init(arena),
1394 .payload = null,
1395 .expr = undefined,
1396 });
1397 try list_state.list.push(&node.base);
1398 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1399 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1400 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1401 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1402
1403 continue;
1404 },
1405
1406 State.SwitchCaseCommaOrEnd => |list_state| {
1407 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
1408 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1409 *list_state.ptr = end;
1410 continue;
1411 } else {
1412 try stack.append(State { .SwitchCaseOrEnd = list_state });
1413 continue;
1414 },
1415 ExpectCommaOrEndResult.parse_error => |e| {
1416 try tree.errors.push(e);
1417 return tree;
1418 },
1419 }
1420 },
1421
1422 State.SwitchCaseFirstItem => |case_items| {
1423 const token = nextToken(&tok_it, &tree);
1424 const token_index = token.index;
1425 const token_ptr = token.ptr;
1426 if (token_ptr.id == Token.Id.Keyword_else) {
1427 const else_node = try arena.construct(ast.Node.SwitchElse {
1428 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},
1429 .token = token_index,
1430 });
1431 try case_items.push(&else_node.base);
1432
1433 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1434 continue;
1435 } else {
1436 putBackToken(&tok_it, &tree);
1437 try stack.append(State { .SwitchCaseItem = case_items });
1438 continue;
1439 }
1440 },
1441 State.SwitchCaseItem => |case_items| {
1442 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1443 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1444 },
1445 State.SwitchCaseItemCommaOrEnd => |case_items| {
1446 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1447 ExpectCommaOrEndResult.end_token => |t| {
1448 if (t == null) {
1449 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1450 }
1451 continue;
1452 },
1453 ExpectCommaOrEndResult.parse_error => |e| {
1454 try tree.errors.push(e);
1455 return tree;
1456 },
1457 }
1458 continue;
1459 },
1460
1461
1462 State.SuspendBody => |suspend_node| {
1463 if (suspend_node.payload != null) {
1464 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1465 }
1466 continue;
1467 },
1468 State.AsyncAllocator => |async_node| {
1469 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
1470 continue;
1471 }
1472
1473 async_node.rangle_bracket = TokenIndex(0);
1474 try stack.append(State {
1475 .ExpectTokenSave = ExpectTokenSave {
1476 .id = Token.Id.AngleBracketRight,
1477 .ptr = &??async_node.rangle_bracket,
1478 }
1479 });
1480 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1481 continue;
1482 },
1483 State.AsyncEnd => |ctx| {
1484 const node = ctx.ctx.get() ?? continue;
1485
1486 switch (node.id) {
1487 ast.Node.Id.FnProto => {
1488 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1489 fn_proto.async_attr = ctx.attribute;
1490 continue;
1491 },
1492 ast.Node.Id.SuffixOp => {
1493 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1494 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1495 suffix_op.op.Call.async_attr = ctx.attribute;
1496 continue;
1497 }
1498
1499 *(try tree.errors.addOne()) = Error {
1500 .ExpectedCall = Error.ExpectedCall { .node = node },
1501 };
1502 return tree;
1503 },
1504 else => {
1505 *(try tree.errors.addOne()) = Error {
1506 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1507 };
1508 return tree;
1509 }
1510 }
1511 },
1512
1513
1514 State.ExternType => |ctx| {
1515 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1516 const fn_proto = try arena.construct(ast.Node.FnProto {
1517 .base = ast.Node {
1518 .id = ast.Node.Id.FnProto,
1519 },
1520 .doc_comments = ctx.comments,
1521 .visib_token = null,
1522 .name_token = null,
1523 .fn_token = fn_token,
1524 .params = ast.Node.FnProto.ParamList.init(arena),
1525 .return_type = undefined,
1526 .var_args_token = null,
1527 .extern_export_inline_token = ctx.extern_token,
1528 .cc_token = null,
1529 .async_attr = null,
1530 .body_node = null,
1531 .lib_name = null,
1532 .align_expr = null,
1533 });
1534 ctx.opt_ctx.store(&fn_proto.base);
1535 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1536 continue;
1537 }
1538
1539 stack.append(State {
1540 .ContainerKind = ContainerKindCtx {
1541 .opt_ctx = ctx.opt_ctx,
1542 .ltoken = ctx.extern_token,
1543 .layout = ast.Node.ContainerDecl.Layout.Extern,
1544 },
1545 }) catch unreachable;
1546 continue;
1547 },
1548 State.SliceOrArrayAccess => |node| {
1549 const token = nextToken(&tok_it, &tree);
1550 const token_index = token.index;
1551 const token_ptr = token.ptr;
1552 switch (token_ptr.id) {
1553 Token.Id.Ellipsis2 => {
1554 const start = node.op.ArrayAccess;
1555 node.op = ast.Node.SuffixOp.Op {
1556 .Slice = ast.Node.SuffixOp.Op.Slice {
1557 .start = start,
1558 .end = null,
1559 }
1560 };
1561
1562 stack.append(State {
1563 .ExpectTokenSave = ExpectTokenSave {
1564 .id = Token.Id.RBracket,
1565 .ptr = &node.rtoken,
1566 }
1567 }) catch unreachable;
1568 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1569 continue;
1570 },
1571 Token.Id.RBracket => {
1572 node.rtoken = token_index;
1573 continue;
1574 },
1575 else => {
1576 *(try tree.errors.addOne()) = Error {
1577 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1578 };
1579 return tree;
1580 }
1581 }
1582 },
1583 State.SliceOrArrayType => |node| {
1584 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {
1585 node.op = ast.Node.PrefixOp.Op {
1586 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1587 .align_expr = null,
1588 .bit_offset_start_token = null,
1589 .bit_offset_end_token = null,
1590 .const_token = null,
1591 .volatile_token = null,
1592 }
1593 };
1594 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1595 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1596 continue;
1597 }
1598
1599 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1600 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1601 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1602 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1603 continue;
1604 },
1605 State.AddrOfModifiers => |addr_of_info| {
1606 const token = nextToken(&tok_it, &tree);
1607 const token_index = token.index;
1608 const token_ptr = token.ptr;
1609 switch (token_ptr.id) {
1610 Token.Id.Keyword_align => {
1611 stack.append(state) catch unreachable;
1612 if (addr_of_info.align_expr != null) {
1613 *(try tree.errors.addOne()) = Error {
1614 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1615 };
1616 return tree;
1617 }
1618 try stack.append(State { .ExpectToken = Token.Id.RParen });
1619 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1620 try stack.append(State { .ExpectToken = Token.Id.LParen });
1621 continue;
1622 },
1623 Token.Id.Keyword_const => {
1624 stack.append(state) catch unreachable;
1625 if (addr_of_info.const_token != null) {
1626 *(try tree.errors.addOne()) = Error {
1627 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1628 };
1629 return tree;
1630 }
1631 addr_of_info.const_token = token_index;
1632 continue;
1633 },
1634 Token.Id.Keyword_volatile => {
1635 stack.append(state) catch unreachable;
1636 if (addr_of_info.volatile_token != null) {
1637 *(try tree.errors.addOne()) = Error {
1638 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1639 };
1640 return tree;
1641 }
1642 addr_of_info.volatile_token = token_index;
1643 continue;
1644 },
1645 else => {
1646 putBackToken(&tok_it, &tree);
1647 continue;
1648 },
1649 }
1650 },
1651
1652
1653 State.Payload => |opt_ctx| {
1654 const token = nextToken(&tok_it, &tree);
1655 const token_index = token.index;
1656 const token_ptr = token.ptr;
1657 if (token_ptr.id != Token.Id.Pipe) {
1658 if (opt_ctx != OptionalCtx.Optional) {
1659 *(try tree.errors.addOne()) = Error {
1660 .ExpectedToken = Error.ExpectedToken {
1661 .token = token_index,
1662 .expected_id = Token.Id.Pipe,
1663 },
1664 };
1665 return tree;
1666 }
1667
1668 putBackToken(&tok_it, &tree);
1669 continue;
1670 }
1671
1672 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1673 ast.Node.Payload {
1674 .base = undefined,
1675 .lpipe = token_index,
1676 .error_symbol = undefined,
1677 .rpipe = undefined
1678 }
1679 );
1680
1681 stack.append(State {
1682 .ExpectTokenSave = ExpectTokenSave {
1683 .id = Token.Id.Pipe,
1684 .ptr = &node.rpipe,
1685 }
1686 }) catch unreachable;
1687 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1688 continue;
1689 },
1690 State.PointerPayload => |opt_ctx| {
1691 const token = nextToken(&tok_it, &tree);
1692 const token_index = token.index;
1693 const token_ptr = token.ptr;
1694 if (token_ptr.id != Token.Id.Pipe) {
1695 if (opt_ctx != OptionalCtx.Optional) {
1696 *(try tree.errors.addOne()) = Error {
1697 .ExpectedToken = Error.ExpectedToken {
1698 .token = token_index,
1699 .expected_id = Token.Id.Pipe,
1700 },
1701 };
1702 return tree;
1703 }
1704
1705 putBackToken(&tok_it, &tree);
1706 continue;
1707 }
1708
1709 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1710 ast.Node.PointerPayload {
1711 .base = undefined,
1712 .lpipe = token_index,
1713 .ptr_token = null,
1714 .value_symbol = undefined,
1715 .rpipe = undefined
1716 }
1717 );
1718
1719 try stack.append(State {
1720 .ExpectTokenSave = ExpectTokenSave {
1721 .id = Token.Id.Pipe,
1722 .ptr = &node.rpipe,
1723 }
1724 });
1725 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1726 try stack.append(State {
1727 .OptionalTokenSave = OptionalTokenSave {
1728 .id = Token.Id.Asterisk,
1729 .ptr = &node.ptr_token,
1730 }
1731 });
1732 continue;
1733 },
1734 State.PointerIndexPayload => |opt_ctx| {
1735 const token = nextToken(&tok_it, &tree);
1736 const token_index = token.index;
1737 const token_ptr = token.ptr;
1738 if (token_ptr.id != Token.Id.Pipe) {
1739 if (opt_ctx != OptionalCtx.Optional) {
1740 *(try tree.errors.addOne()) = Error {
1741 .ExpectedToken = Error.ExpectedToken {
1742 .token = token_index,
1743 .expected_id = Token.Id.Pipe,
1744 },
1745 };
1746 return tree;
1747 }
1748
1749 putBackToken(&tok_it, &tree);
1750 continue;
1751 }
1752
1753 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1754 ast.Node.PointerIndexPayload {
1755 .base = undefined,
1756 .lpipe = token_index,
1757 .ptr_token = null,
1758 .value_symbol = undefined,
1759 .index_symbol = null,
1760 .rpipe = undefined
1761 }
1762 );
1763
1764 stack.append(State {
1765 .ExpectTokenSave = ExpectTokenSave {
1766 .id = Token.Id.Pipe,
1767 .ptr = &node.rpipe,
1768 }
1769 }) catch unreachable;
1770 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1771 try stack.append(State { .IfToken = Token.Id.Comma });
1772 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1773 try stack.append(State {
1774 .OptionalTokenSave = OptionalTokenSave {
1775 .id = Token.Id.Asterisk,
1776 .ptr = &node.ptr_token,
1777 }
1778 });
1779 continue;
1780 },
1781
1782
1783 State.Expression => |opt_ctx| {
1784 const token = nextToken(&tok_it, &tree);
1785 const token_index = token.index;
1786 const token_ptr = token.ptr;
1787 switch (token_ptr.id) {
1788 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1789 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1790 ast.Node.ControlFlowExpression {
1791 .base = undefined,
1792 .ltoken = token_index,
1793 .kind = undefined,
1794 .rhs = null,
1795 }
1796 );
1797
1798 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1799
1800 switch (token_ptr.id) {
1801 Token.Id.Keyword_break => {
1802 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1803 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1804 try stack.append(State { .IfToken = Token.Id.Colon });
1805 },
1806 Token.Id.Keyword_continue => {
1807 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1808 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1809 try stack.append(State { .IfToken = Token.Id.Colon });
1810 },
1811 Token.Id.Keyword_return => {
1812 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1813 },
1814 else => unreachable,
1815 }
1816 continue;
1817 },
1818 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1819 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1820 ast.Node.PrefixOp {
1821 .base = undefined,
1822 .op_token = token_index,
1823 .op = switch (token_ptr.id) {
1824 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1825 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1826 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1827 else => unreachable,
1828 },
1829 .rhs = undefined,
1830 }
1831 );
1832
1833 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1834 continue;
1835 },
1836 else => {
1837 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1838 putBackToken(&tok_it, &tree);
1839 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1840 }
1841 continue;
1842 }
1843 }
1844 },
1845 State.RangeExpressionBegin => |opt_ctx| {
1846 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1847 try stack.append(State { .Expression = opt_ctx });
1848 continue;
1849 },
1850 State.RangeExpressionEnd => |opt_ctx| {
1851 const lhs = opt_ctx.get() ?? continue;
1852
1853 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1854 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1855 ast.Node.InfixOp {
1856 .base = undefined,
1857 .lhs = lhs,
1858 .op_token = ellipsis3,
1859 .op = ast.Node.InfixOp.Op.Range,
1860 .rhs = undefined,
1861 }
1862 );
1863 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1864 continue;
1865 }
1866 },
1867 State.AssignmentExpressionBegin => |opt_ctx| {
1868 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1869 try stack.append(State { .Expression = opt_ctx });
1870 continue;
1871 },
1872
1873 State.AssignmentExpressionEnd => |opt_ctx| {
1874 const lhs = opt_ctx.get() ?? continue;
1875
1876 const token = nextToken(&tok_it, &tree);
1877 const token_index = token.index;
1878 const token_ptr = token.ptr;
1879 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1880 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1881 ast.Node.InfixOp {
1882 .base = undefined,
1883 .lhs = lhs,
1884 .op_token = token_index,
1885 .op = ass_id,
1886 .rhs = undefined,
1887 }
1888 );
1889 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1890 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1891 continue;
1892 } else {
1893 putBackToken(&tok_it, &tree);
1894 continue;
1895 }
1896 },
1897
1898 State.UnwrapExpressionBegin => |opt_ctx| {
1899 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1900 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1901 continue;
1902 },
1903
1904 State.UnwrapExpressionEnd => |opt_ctx| {
1905 const lhs = opt_ctx.get() ?? continue;
1906
1907 const token = nextToken(&tok_it, &tree);
1908 const token_index = token.index;
1909 const token_ptr = token.ptr;
1910 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1911 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1912 ast.Node.InfixOp {
1913 .base = undefined,
1914 .lhs = lhs,
1915 .op_token = token_index,
1916 .op = unwrap_id,
1917 .rhs = undefined,
1918 }
1919 );
1920
1921 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1922 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1923
1924 if (node.op == ast.Node.InfixOp.Op.Catch) {
1925 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1926 }
1927 continue;
1928 } else {
1929 putBackToken(&tok_it, &tree);
1930 continue;
1931 }
1932 },
1933
1934 State.BoolOrExpressionBegin => |opt_ctx| {
1935 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1936 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1937 continue;
1938 },
1939
1940 State.BoolOrExpressionEnd => |opt_ctx| {
1941 const lhs = opt_ctx.get() ?? continue;
1942
1943 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1944 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1945 ast.Node.InfixOp {
1946 .base = undefined,
1947 .lhs = lhs,
1948 .op_token = or_token,
1949 .op = ast.Node.InfixOp.Op.BoolOr,
1950 .rhs = undefined,
1951 }
1952 );
1953 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1954 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1955 continue;
1956 }
1957 },
1958
1959 State.BoolAndExpressionBegin => |opt_ctx| {
1960 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1961 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1962 continue;
1963 },
1964
1965 State.BoolAndExpressionEnd => |opt_ctx| {
1966 const lhs = opt_ctx.get() ?? continue;
1967
1968 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1969 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1970 ast.Node.InfixOp {
1971 .base = undefined,
1972 .lhs = lhs,
1973 .op_token = and_token,
1974 .op = ast.Node.InfixOp.Op.BoolAnd,
1975 .rhs = undefined,
1976 }
1977 );
1978 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1979 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1980 continue;
1981 }
1982 },
1983
1984 State.ComparisonExpressionBegin => |opt_ctx| {
1985 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1986 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
1987 continue;
1988 },
1989
1990 State.ComparisonExpressionEnd => |opt_ctx| {
1991 const lhs = opt_ctx.get() ?? continue;
1992
1993 const token = nextToken(&tok_it, &tree);
1994 const token_index = token.index;
1995 const token_ptr = token.ptr;
1996 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1997 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1998 ast.Node.InfixOp {
1999 .base = undefined,
2000 .lhs = lhs,
2001 .op_token = token_index,
2002 .op = comp_id,
2003 .rhs = undefined,
2004 }
2005 );
2006 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2007 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2008 continue;
2009 } else {
2010 putBackToken(&tok_it, &tree);
2011 continue;
2012 }
2013 },
2014
2015 State.BinaryOrExpressionBegin => |opt_ctx| {
2016 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2017 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2018 continue;
2019 },
2020
2021 State.BinaryOrExpressionEnd => |opt_ctx| {
2022 const lhs = opt_ctx.get() ?? continue;
2023
2024 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
2025 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2026 ast.Node.InfixOp {
2027 .base = undefined,
2028 .lhs = lhs,
2029 .op_token = pipe,
2030 .op = ast.Node.InfixOp.Op.BitOr,
2031 .rhs = undefined,
2032 }
2033 );
2034 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2035 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2036 continue;
2037 }
2038 },
2039
2040 State.BinaryXorExpressionBegin => |opt_ctx| {
2041 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2042 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2043 continue;
2044 },
2045
2046 State.BinaryXorExpressionEnd => |opt_ctx| {
2047 const lhs = opt_ctx.get() ?? continue;
2048
2049 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2050 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2051 ast.Node.InfixOp {
2052 .base = undefined,
2053 .lhs = lhs,
2054 .op_token = caret,
2055 .op = ast.Node.InfixOp.Op.BitXor,
2056 .rhs = undefined,
2057 }
2058 );
2059 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2060 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2061 continue;
2062 }
2063 },
2064
2065 State.BinaryAndExpressionBegin => |opt_ctx| {
2066 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2067 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2068 continue;
2069 },
2070
2071 State.BinaryAndExpressionEnd => |opt_ctx| {
2072 const lhs = opt_ctx.get() ?? continue;
2073
2074 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2075 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2076 ast.Node.InfixOp {
2077 .base = undefined,
2078 .lhs = lhs,
2079 .op_token = ampersand,
2080 .op = ast.Node.InfixOp.Op.BitAnd,
2081 .rhs = undefined,
2082 }
2083 );
2084 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2085 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2086 continue;
2087 }
2088 },
2089
2090 State.BitShiftExpressionBegin => |opt_ctx| {
2091 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2092 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2093 continue;
2094 },
2095
2096 State.BitShiftExpressionEnd => |opt_ctx| {
2097 const lhs = opt_ctx.get() ?? continue;
2098
2099 const token = nextToken(&tok_it, &tree);
2100 const token_index = token.index;
2101 const token_ptr = token.ptr;
2102 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2103 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2104 ast.Node.InfixOp {
2105 .base = undefined,
2106 .lhs = lhs,
2107 .op_token = token_index,
2108 .op = bitshift_id,
2109 .rhs = undefined,
2110 }
2111 );
2112 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2113 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2114 continue;
2115 } else {
2116 putBackToken(&tok_it, &tree);
2117 continue;
2118 }
2119 },
2120
2121 State.AdditionExpressionBegin => |opt_ctx| {
2122 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2123 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2124 continue;
2125 },
2126
2127 State.AdditionExpressionEnd => |opt_ctx| {
2128 const lhs = opt_ctx.get() ?? continue;
2129
2130 const token = nextToken(&tok_it, &tree);
2131 const token_index = token.index;
2132 const token_ptr = token.ptr;
2133 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2134 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2135 ast.Node.InfixOp {
2136 .base = undefined,
2137 .lhs = lhs,
2138 .op_token = token_index,
2139 .op = add_id,
2140 .rhs = undefined,
2141 }
2142 );
2143 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2144 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2145 continue;
2146 } else {
2147 putBackToken(&tok_it, &tree);
2148 continue;
2149 }
2150 },
2151
2152 State.MultiplyExpressionBegin => |opt_ctx| {
2153 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2154 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2155 continue;
2156 },
2157
2158 State.MultiplyExpressionEnd => |opt_ctx| {
2159 const lhs = opt_ctx.get() ?? continue;
2160
2161 const token = nextToken(&tok_it, &tree);
2162 const token_index = token.index;
2163 const token_ptr = token.ptr;
2164 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2165 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2166 ast.Node.InfixOp {
2167 .base = undefined,
2168 .lhs = lhs,
2169 .op_token = token_index,
2170 .op = mult_id,
2171 .rhs = undefined,
2172 }
2173 );
2174 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2175 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2176 continue;
2177 } else {
2178 putBackToken(&tok_it, &tree);
2179 continue;
2180 }
2181 },
2182
2183 State.CurlySuffixExpressionBegin => |opt_ctx| {
2184 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2185 try stack.append(State { .IfToken = Token.Id.LBrace });
2186 try stack.append(State { .TypeExprBegin = opt_ctx });
2187 continue;
2188 },
2189
2190 State.CurlySuffixExpressionEnd => |opt_ctx| {
2191 const lhs = opt_ctx.get() ?? continue;
2192
2193 if ((??tok_it.peek()).id == Token.Id.Period) {
2194 const node = try arena.construct(ast.Node.SuffixOp {
2195 .base = ast.Node { .id = ast.Node.Id.SuffixOp },
2196 .lhs = lhs,
2197 .op = ast.Node.SuffixOp.Op {
2198 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2199 },
2200 .rtoken = undefined,
2201 });
2202 opt_ctx.store(&node.base);
2203
2204 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2205 try stack.append(State { .IfToken = Token.Id.LBrace });
2206 try stack.append(State {
2207 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {
2208 .list = &node.op.StructInitializer,
2209 .ptr = &node.rtoken,
2210 }
2211 });
2212 continue;
2213 }
2214
2215 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2216 ast.Node.SuffixOp {
2217 .base = undefined,
2218 .lhs = lhs,
2219 .op = ast.Node.SuffixOp.Op {
2220 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2221 },
2222 .rtoken = undefined,
2223 }
2224 );
2225 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2226 try stack.append(State { .IfToken = Token.Id.LBrace });
2227 try stack.append(State {
2228 .ExprListItemOrEnd = ExprListCtx {
2229 .list = &node.op.ArrayInitializer,
2230 .end = Token.Id.RBrace,
2231 .ptr = &node.rtoken,
2232 }
2233 });
2234 continue;
2235 },
2236
2237 State.TypeExprBegin => |opt_ctx| {
2238 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2239 try stack.append(State { .PrefixOpExpression = opt_ctx });
2240 continue;
2241 },
2242
2243 State.TypeExprEnd => |opt_ctx| {
2244 const lhs = opt_ctx.get() ?? continue;
2245
2246 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2247 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2248 ast.Node.InfixOp {
2249 .base = undefined,
2250 .lhs = lhs,
2251 .op_token = bang,
2252 .op = ast.Node.InfixOp.Op.ErrorUnion,
2253 .rhs = undefined,
2254 }
2255 );
2256 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2257 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2258 continue;
2259 }
2260 },
2261
2262 State.PrefixOpExpression => |opt_ctx| {
2263 const token = nextToken(&tok_it, &tree);
2264 const token_index = token.index;
2265 const token_ptr = token.ptr;
2266 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2267 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2268 ast.Node.PrefixOp {
2269 .base = undefined,
2270 .op_token = token_index,
2271 .op = prefix_id,
2272 .rhs = undefined,
2273 }
2274 );
2275
2276 // Treat '**' token as two derefs
2277 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2278 const child = try createNode(arena, ast.Node.PrefixOp,
2279 ast.Node.PrefixOp {
2280 .base = undefined,
2281 .op_token = token_index,
2282 .op = prefix_id,
2283 .rhs = undefined,
2284 }
2285 );
2286 node.rhs = &child.base;
2287 node = child;
2288 }
2289
2290 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2291 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2292 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2293 }
2294 continue;
2295 } else {
2296 putBackToken(&tok_it, &tree);
2297 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2298 continue;
2299 }
2300 },
2301
2302 State.SuffixOpExpressionBegin => |opt_ctx| {
2303 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2304 const async_node = try createNode(arena, ast.Node.AsyncAttribute,
2305 ast.Node.AsyncAttribute {
2306 .base = undefined,
2307 .async_token = async_token,
2308 .allocator_type = null,
2309 .rangle_bracket = null,
2310 }
2311 );
2312 stack.append(State {
2313 .AsyncEnd = AsyncEndCtx {
2314 .ctx = opt_ctx,
2315 .attribute = async_node,
2316 }
2317 }) catch unreachable;
2318 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2319 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2320 try stack.append(State { .AsyncAllocator = async_node });
2321 continue;
2322 }
2323
2324 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2325 try stack.append(State { .PrimaryExpression = opt_ctx });
2326 continue;
2327 },
2328
2329 State.SuffixOpExpressionEnd => |opt_ctx| {
2330 const lhs = opt_ctx.get() ?? continue;
2331
2332 const token = nextToken(&tok_it, &tree);
2333 const token_index = token.index;
2334 const token_ptr = token.ptr;
2335 switch (token_ptr.id) {
2336 Token.Id.LParen => {
2337 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2338 ast.Node.SuffixOp {
2339 .base = undefined,
2340 .lhs = lhs,
2341 .op = ast.Node.SuffixOp.Op {
2342 .Call = ast.Node.SuffixOp.Op.Call {
2343 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2344 .async_attr = null,
2345 }
2346 },
2347 .rtoken = undefined,
2348 }
2349 );
2350 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2351 try stack.append(State {
2352 .ExprListItemOrEnd = ExprListCtx {
2353 .list = &node.op.Call.params,
2354 .end = Token.Id.RParen,
2355 .ptr = &node.rtoken,
2356 }
2357 });
2358 continue;
2359 },
2360 Token.Id.LBracket => {
2361 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2362 ast.Node.SuffixOp {
2363 .base = undefined,
2364 .lhs = lhs,
2365 .op = ast.Node.SuffixOp.Op {
2366 .ArrayAccess = undefined,
2367 },
2368 .rtoken = undefined
2369 }
2370 );
2371 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2372 try stack.append(State { .SliceOrArrayAccess = node });
2373 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2374 continue;
2375 },
2376 Token.Id.Period => {
2377 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2378 ast.Node.InfixOp {
2379 .base = undefined,
2380 .lhs = lhs,
2381 .op_token = token_index,
2382 .op = ast.Node.InfixOp.Op.Period,
2383 .rhs = undefined,
2384 }
2385 );
2386 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2387 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2388 continue;
2389 },
2390 else => {
2391 putBackToken(&tok_it, &tree);
2392 continue;
2393 },
2394 }
2395 },
2396
2397 State.PrimaryExpression => |opt_ctx| {
2398 const token = nextToken(&tok_it, &tree);
2399 switch (token.ptr.id) {
2400 Token.Id.IntegerLiteral => {
2401 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token.index);
2402 continue;
2403 },
2404 Token.Id.FloatLiteral => {
2405 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index);
2406 continue;
2407 },
2408 Token.Id.CharLiteral => {
2409 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token.index);
2410 continue;
2411 },
2412 Token.Id.Keyword_undefined => {
2413 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2414 continue;
2415 },
2416 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2417 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
2418 continue;
2419 },
2420 Token.Id.Keyword_null => {
2421 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token.index);
2422 continue;
2423 },
2424 Token.Id.Keyword_this => {
2425 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token.index);
2426 continue;
2427 },
2428 Token.Id.Keyword_var => {
2429 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token.index);
2430 continue;
2431 },
2432 Token.Id.Keyword_unreachable => {
2433 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token.index);
2434 continue;
2435 },
2436 Token.Id.Keyword_promise => {
2437 const node = try arena.construct(ast.Node.PromiseType {
2438 .base = ast.Node {
2439 .id = ast.Node.Id.PromiseType,
2440 },
2441 .promise_token = token.index,
2442 .result = null,
2443 });
2444 opt_ctx.store(&node.base);
2445 const next_token = nextToken(&tok_it, &tree);
2446 const next_token_index = next_token.index;
2447 const next_token_ptr = next_token.ptr;
2448 if (next_token_ptr.id != Token.Id.Arrow) {
2449 putBackToken(&tok_it, &tree);
2450 continue;
2451 }
2452 node.result = ast.Node.PromiseType.Result {
2453 .arrow_token = next_token_index,
2454 .return_type = undefined,
2455 };
2456 const return_type_ptr = &((??node.result).return_type);
2457 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2458 continue;
2459 },
2460 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2461 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
2462 continue;
2463 },
2464 Token.Id.LParen => {
2465 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2466 ast.Node.GroupedExpression {
2467 .base = undefined,
2468 .lparen = token.index,
2469 .expr = undefined,
2470 .rparen = undefined,
2471 }
2472 );
2473 stack.append(State {
2474 .ExpectTokenSave = ExpectTokenSave {
2475 .id = Token.Id.RParen,
2476 .ptr = &node.rparen,
2477 }
2478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2480 continue;
2481 },
2482 Token.Id.Builtin => {
2483 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2484 ast.Node.BuiltinCall {
2485 .base = undefined,
2486 .builtin_token = token.index,
2487 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2488 .rparen_token = undefined,
2489 }
2490 );
2491 stack.append(State {
2492 .ExprListItemOrEnd = ExprListCtx {
2493 .list = &node.params,
2494 .end = Token.Id.RParen,
2495 .ptr = &node.rparen_token,
2496 }
2497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2499 continue;
2500 },
2501 Token.Id.LBracket => {
2502 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2503 ast.Node.PrefixOp {
2504 .base = undefined,
2505 .op_token = token.index,
2506 .op = undefined,
2507 .rhs = undefined,
2508 }
2509 );
2510 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2511 continue;
2512 },
2513 Token.Id.Keyword_error => {
2514 stack.append(State {
2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2516 .error_token = token.index,
2517 .opt_ctx = opt_ctx
2518 }
2519 }) catch unreachable;
2520 continue;
2521 },
2522 Token.Id.Keyword_packed => {
2523 stack.append(State {
2524 .ContainerKind = ContainerKindCtx {
2525 .opt_ctx = opt_ctx,
2526 .ltoken = token.index,
2527 .layout = ast.Node.ContainerDecl.Layout.Packed,
2528 },
2529 }) catch unreachable;
2530 continue;
2531 },
2532 Token.Id.Keyword_extern => {
2533 stack.append(State {
2534 .ExternType = ExternTypeCtx {
2535 .opt_ctx = opt_ctx,
2536 .extern_token = token.index,
2537 .comments = null,
2538 },
2539 }) catch unreachable;
2540 continue;
2541 },
2542 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2543 putBackToken(&tok_it, &tree);
2544 stack.append(State {
2545 .ContainerKind = ContainerKindCtx {
2546 .opt_ctx = opt_ctx,
2547 .ltoken = token.index,
2548 .layout = ast.Node.ContainerDecl.Layout.Auto,
2549 },
2550 }) catch unreachable;
2551 continue;
2552 },
2553 Token.Id.Identifier => {
2554 stack.append(State {
2555 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2556 .label = token.index,
2557 .opt_ctx = opt_ctx
2558 }
2559 }) catch unreachable;
2560 continue;
2561 },
2562 Token.Id.Keyword_fn => {
2563 const fn_proto = try arena.construct(ast.Node.FnProto {
2564 .base = ast.Node {
2565 .id = ast.Node.Id.FnProto,
2566 },
2567 .doc_comments = null,
2568 .visib_token = null,
2569 .name_token = null,
2570 .fn_token = token.index,
2571 .params = ast.Node.FnProto.ParamList.init(arena),
2572 .return_type = undefined,
2573 .var_args_token = null,
2574 .extern_export_inline_token = null,
2575 .cc_token = null,
2576 .async_attr = null,
2577 .body_node = null,
2578 .lib_name = null,
2579 .align_expr = null,
2580 });
2581 opt_ctx.store(&fn_proto.base);
2582 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2583 continue;
2584 },
2585 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2586 const fn_proto = try arena.construct(ast.Node.FnProto {
2587 .base = ast.Node {
2588 .id = ast.Node.Id.FnProto,
2589 },
2590 .doc_comments = null,
2591 .visib_token = null,
2592 .name_token = null,
2593 .fn_token = undefined,
2594 .params = ast.Node.FnProto.ParamList.init(arena),
2595 .return_type = undefined,
2596 .var_args_token = null,
2597 .extern_export_inline_token = null,
2598 .cc_token = token.index,
2599 .async_attr = null,
2600 .body_node = null,
2601 .lib_name = null,
2602 .align_expr = null,
2603 });
2604 opt_ctx.store(&fn_proto.base);
2605 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2606 try stack.append(State {
2607 .ExpectTokenSave = ExpectTokenSave {
2608 .id = Token.Id.Keyword_fn,
2609 .ptr = &fn_proto.fn_token
2610 }
2611 });
2612 continue;
2613 },
2614 Token.Id.Keyword_asm => {
2615 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2616 ast.Node.Asm {
2617 .base = undefined,
2618 .asm_token = token.index,
2619 .volatile_token = null,
2620 .template = undefined,
2621 .outputs = ast.Node.Asm.OutputList.init(arena),
2622 .inputs = ast.Node.Asm.InputList.init(arena),
2623 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2624 .rparen = undefined,
2625 }
2626 );
2627 stack.append(State {
2628 .ExpectTokenSave = ExpectTokenSave {
2629 .id = Token.Id.RParen,
2630 .ptr = &node.rparen,
2631 }
2632 }) catch unreachable;
2633 try stack.append(State { .AsmClobberItems = &node.clobbers });
2634 try stack.append(State { .IfToken = Token.Id.Colon });
2635 try stack.append(State { .AsmInputItems = &node.inputs });
2636 try stack.append(State { .IfToken = Token.Id.Colon });
2637 try stack.append(State { .AsmOutputItems = &node.outputs });
2638 try stack.append(State { .IfToken = Token.Id.Colon });
2639 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2640 try stack.append(State { .ExpectToken = Token.Id.LParen });
2641 try stack.append(State {
2642 .OptionalTokenSave = OptionalTokenSave {
2643 .id = Token.Id.Keyword_volatile,
2644 .ptr = &node.volatile_token,
2645 }
2646 });
2647 },
2648 Token.Id.Keyword_inline => {
2649 stack.append(State {
2650 .Inline = InlineCtx {
2651 .label = null,
2652 .inline_token = token.index,
2653 .opt_ctx = opt_ctx,
2654 }
2655 }) catch unreachable;
2656 continue;
2657 },
2658 else => {
2659 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2660 putBackToken(&tok_it, &tree);
2661 if (opt_ctx != OptionalCtx.Optional) {
2662 *(try tree.errors.addOne()) = Error {
2663 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token.index },
2664 };
2665 return tree;
2666 }
2667 }
2668 continue;
2669 }
2670 }
2671 },
2672
2673
2674 State.ErrorTypeOrSetDecl => |ctx| {
2675 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
2676 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2677 continue;
2678 }
2679
2680 const node = try arena.construct(ast.Node.ErrorSetDecl {
2681 .base = ast.Node {
2682 .id = ast.Node.Id.ErrorSetDecl,
2683 },
2684 .error_token = ctx.error_token,
2685 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2686 .rbrace_token = undefined,
2687 });
2688 ctx.opt_ctx.store(&node.base);
2689
2690 stack.append(State {
2691 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {
2692 .list = &node.decls,
2693 .ptr = &node.rbrace_token,
2694 }
2695 }) catch unreachable;
2696 continue;
2697 },
2698 State.StringLiteral => |opt_ctx| {
2699 const token = nextToken(&tok_it, &tree);
2700 const token_index = token.index;
2701 const token_ptr = token.ptr;
2702 opt_ctx.store(
2703 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2704 putBackToken(&tok_it, &tree);
2705 if (opt_ctx != OptionalCtx.Optional) {
2706 *(try tree.errors.addOne()) = Error {
2707 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2708 };
2709 return tree;
2710 }
2711
2712 continue;
2713 }
2714 );
2715 },
2716
2717 State.Identifier => |opt_ctx| {
2718 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
2719 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2720 continue;
2721 }
2722
2723 if (opt_ctx != OptionalCtx.Optional) {
2724 const token = nextToken(&tok_it, &tree);
2725 const token_index = token.index;
2726 const token_ptr = token.ptr;
2727 *(try tree.errors.addOne()) = Error {
2728 .ExpectedToken = Error.ExpectedToken {
2729 .token = token_index,
2730 .expected_id = Token.Id.Identifier,
2731 },
2732 };
2733 return tree;
2734 }
2735 },
2736
2737 State.ErrorTag => |node_ptr| {
2738 const comments = try eatDocComments(arena, &tok_it, &tree);
2739 const ident_token = nextToken(&tok_it, &tree);
2740 const ident_token_index = ident_token.index;
2741 const ident_token_ptr = ident_token.ptr;
2742 if (ident_token_ptr.id != Token.Id.Identifier) {
2743 *(try tree.errors.addOne()) = Error {
2744 .ExpectedToken = Error.ExpectedToken {
2745 .token = ident_token_index,
2746 .expected_id = Token.Id.Identifier,
2747 },
2748 };
2749 return tree;
2750 }
2751
2752 const node = try arena.construct(ast.Node.ErrorTag {
2753 .base = ast.Node {
2754 .id = ast.Node.Id.ErrorTag,
2755 },
2756 .doc_comments = comments,
2757 .name_token = ident_token_index,
2758 });
2759 *node_ptr = &node.base;
2760 continue;
2761 },
2762
2763 State.ExpectToken => |token_id| {
2764 const token = nextToken(&tok_it, &tree);
2765 const token_index = token.index;
2766 const token_ptr = token.ptr;
2767 if (token_ptr.id != token_id) {
2768 *(try tree.errors.addOne()) = Error {
2769 .ExpectedToken = Error.ExpectedToken {
2770 .token = token_index,
2771 .expected_id = token_id,
2772 },
2773 };
2774 return tree;
2775 }
2776 continue;
2777 },
2778 State.ExpectTokenSave => |expect_token_save| {
2779 const token = nextToken(&tok_it, &tree);
2780 const token_index = token.index;
2781 const token_ptr = token.ptr;
2782 if (token_ptr.id != expect_token_save.id) {
2783 *(try tree.errors.addOne()) = Error {
2784 .ExpectedToken = Error.ExpectedToken {
2785 .token = token_index,
2786 .expected_id = expect_token_save.id,
2787 },
2788 };
2789 return tree;
2790 }
2791 *expect_token_save.ptr = token_index;
2792 continue;
2793 },
2794 State.IfToken => |token_id| {
2795 if (eatToken(&tok_it, &tree, token_id)) |_| {
2796 continue;
2797 }
2798
2799 _ = stack.pop();
2800 continue;
2801 },
2802 State.IfTokenSave => |if_token_save| {
2803 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {
2804 *if_token_save.ptr = token_index;
2805 continue;
2806 }
2807
2808 _ = stack.pop();
2809 continue;
2810 },
2811 State.OptionalTokenSave => |optional_token_save| {
2812 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {
2813 *optional_token_save.ptr = token_index;
2814 continue;
2815 }
2816
2817 continue;
2818 },
2819 }
2820 }
2821}
2822
2823const AnnotatedToken = struct {
2824 ptr: &Token,
2825 index: TokenIndex,
2826};
2827
2828const TopLevelDeclCtx = struct {
2829 decls: &ast.Node.Root.DeclList,
2830 visib_token: ?TokenIndex,
2831 extern_export_inline_token: ?AnnotatedToken,
2832 lib_name: ?&ast.Node,
2833 comments: ?&ast.Node.DocComment,
2834};
2835
2836const VarDeclCtx = struct {
2837 mut_token: TokenIndex,
2838 visib_token: ?TokenIndex,
2839 comptime_token: ?TokenIndex,
2840 extern_export_token: ?TokenIndex,
2841 lib_name: ?&ast.Node,
2842 list: &ast.Node.Root.DeclList,
2843 comments: ?&ast.Node.DocComment,
2844};
2845
2846const TopLevelExternOrFieldCtx = struct {
2847 visib_token: TokenIndex,
2848 container_decl: &ast.Node.ContainerDecl,
2849 comments: ?&ast.Node.DocComment,
2850};
2851
2852const ExternTypeCtx = struct {
2853 opt_ctx: OptionalCtx,
2854 extern_token: TokenIndex,
2855 comments: ?&ast.Node.DocComment,
2856};
2857
2858const ContainerKindCtx = struct {
2859 opt_ctx: OptionalCtx,
2860 ltoken: TokenIndex,
2861 layout: ast.Node.ContainerDecl.Layout,
2862};
2863
2864const ExpectTokenSave = struct {
2865 id: @TagType(Token.Id),
2866 ptr: &TokenIndex,
2867};
2868
2869const OptionalTokenSave = struct {
2870 id: @TagType(Token.Id),
2871 ptr: &?TokenIndex,
2872};
2873
2874const ExprListCtx = struct {
2875 list: &ast.Node.SuffixOp.Op.InitList,
2876 end: Token.Id,
2877 ptr: &TokenIndex,
2878};
2879
2880fn ListSave(comptime List: type) type {
2881 return struct {
2882 list: &List,
2883 ptr: &TokenIndex,
2884 };
2885}
2886
2887const MaybeLabeledExpressionCtx = struct {
2888 label: TokenIndex,
2889 opt_ctx: OptionalCtx,
2890};
2891
2892const LabelCtx = struct {
2893 label: ?TokenIndex,
2894 opt_ctx: OptionalCtx,
2895};
2896
2897const InlineCtx = struct {
2898 label: ?TokenIndex,
2899 inline_token: ?TokenIndex,
2900 opt_ctx: OptionalCtx,
2901};
2902
2903const LoopCtx = struct {
2904 label: ?TokenIndex,
2905 inline_token: ?TokenIndex,
2906 loop_token: TokenIndex,
2907 opt_ctx: OptionalCtx,
2908};
2909
2910const AsyncEndCtx = struct {
2911 ctx: OptionalCtx,
2912 attribute: &ast.Node.AsyncAttribute,
2913};
2914
2915const ErrorTypeOrSetDeclCtx = struct {
2916 opt_ctx: OptionalCtx,
2917 error_token: TokenIndex,
2918};
2919
2920const ParamDeclEndCtx = struct {
2921 fn_proto: &ast.Node.FnProto,
2922 param_decl: &ast.Node.ParamDecl,
2923};
2924
2925const ComptimeStatementCtx = struct {
2926 comptime_token: TokenIndex,
2927 block: &ast.Node.Block,
2928};
2929
2930const OptionalCtx = union(enum) {
2931 Optional: &?&ast.Node,
2932 RequiredNull: &?&ast.Node,
2933 Required: &&ast.Node,
2934
2935 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2936 switch (*self) {
2937 OptionalCtx.Optional => |ptr| *ptr = value,
2938 OptionalCtx.RequiredNull => |ptr| *ptr = value,
2939 OptionalCtx.Required => |ptr| *ptr = value,
2940 }
2941 }
2942
2943 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2944 switch (*self) {
2945 OptionalCtx.Optional => |ptr| return *ptr,
2946 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
2947 OptionalCtx.Required => |ptr| return *ptr,
2948 }
2949 }
2950
2951 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2952 switch (*self) {
2953 OptionalCtx.Optional => |ptr| {
2954 return OptionalCtx { .RequiredNull = ptr };
2955 },
2956 OptionalCtx.RequiredNull => |ptr| return *self,
2957 OptionalCtx.Required => |ptr| return *self,
2958 }
2959 }
2960};
2961
2962const AddCommentsCtx = struct {
2963 node_ptr: &&ast.Node,
2964 comments: ?&ast.Node.DocComment,
2965};
2966
2967const State = union(enum) {
2968 TopLevel,
2969 TopLevelExtern: TopLevelDeclCtx,
2970 TopLevelLibname: TopLevelDeclCtx,
2971 TopLevelDecl: TopLevelDeclCtx,
2972 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2973
2974 ContainerKind: ContainerKindCtx,
2975 ContainerInitArgStart: &ast.Node.ContainerDecl,
2976 ContainerInitArg: &ast.Node.ContainerDecl,
2977 ContainerDecl: &ast.Node.ContainerDecl,
2978
2979 VarDecl: VarDeclCtx,
2980 VarDeclAlign: &ast.Node.VarDecl,
2981 VarDeclEq: &ast.Node.VarDecl,
2982
2983 FnDef: &ast.Node.FnProto,
2984 FnProto: &ast.Node.FnProto,
2985 FnProtoAlign: &ast.Node.FnProto,
2986 FnProtoReturnType: &ast.Node.FnProto,
2987
2988 ParamDecl: &ast.Node.FnProto,
2989 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
2990 ParamDeclName: &ast.Node.ParamDecl,
2991 ParamDeclEnd: ParamDeclEndCtx,
2992 ParamDeclComma: &ast.Node.FnProto,
2993
2994 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2995 LabeledExpression: LabelCtx,
2996 Inline: InlineCtx,
2997 While: LoopCtx,
2998 WhileContinueExpr: &?&ast.Node,
2999 For: LoopCtx,
3000 Else: &?&ast.Node.Else,
3001
3002 Block: &ast.Node.Block,
3003 Statement: &ast.Node.Block,
3004 ComptimeStatement: ComptimeStatementCtx,
3005 Semicolon: &&ast.Node,
3006
3007 AsmOutputItems: &ast.Node.Asm.OutputList,
3008 AsmOutputReturnOrType: &ast.Node.AsmOutput,
3009 AsmInputItems: &ast.Node.Asm.InputList,
3010 AsmClobberItems: &ast.Node.Asm.ClobberList,
3011
3012 ExprListItemOrEnd: ExprListCtx,
3013 ExprListCommaOrEnd: ExprListCtx,
3014 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3015 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
3016 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
3017 FieldInitValue: OptionalCtx,
3018 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3019 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3020 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
3021 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
3022 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
3023 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
3024 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
3025
3026 SuspendBody: &ast.Node.Suspend,
3027 AsyncAllocator: &ast.Node.AsyncAttribute,
3028 AsyncEnd: AsyncEndCtx,
3029
3030 ExternType: ExternTypeCtx,
3031 SliceOrArrayAccess: &ast.Node.SuffixOp,
3032 SliceOrArrayType: &ast.Node.PrefixOp,
3033 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
3034
3035 Payload: OptionalCtx,
3036 PointerPayload: OptionalCtx,
3037 PointerIndexPayload: OptionalCtx,
3038
3039 Expression: OptionalCtx,
3040 RangeExpressionBegin: OptionalCtx,
3041 RangeExpressionEnd: OptionalCtx,
3042 AssignmentExpressionBegin: OptionalCtx,
3043 AssignmentExpressionEnd: OptionalCtx,
3044 UnwrapExpressionBegin: OptionalCtx,
3045 UnwrapExpressionEnd: OptionalCtx,
3046 BoolOrExpressionBegin: OptionalCtx,
3047 BoolOrExpressionEnd: OptionalCtx,
3048 BoolAndExpressionBegin: OptionalCtx,
3049 BoolAndExpressionEnd: OptionalCtx,
3050 ComparisonExpressionBegin: OptionalCtx,
3051 ComparisonExpressionEnd: OptionalCtx,
3052 BinaryOrExpressionBegin: OptionalCtx,
3053 BinaryOrExpressionEnd: OptionalCtx,
3054 BinaryXorExpressionBegin: OptionalCtx,
3055 BinaryXorExpressionEnd: OptionalCtx,
3056 BinaryAndExpressionBegin: OptionalCtx,
3057 BinaryAndExpressionEnd: OptionalCtx,
3058 BitShiftExpressionBegin: OptionalCtx,
3059 BitShiftExpressionEnd: OptionalCtx,
3060 AdditionExpressionBegin: OptionalCtx,
3061 AdditionExpressionEnd: OptionalCtx,
3062 MultiplyExpressionBegin: OptionalCtx,
3063 MultiplyExpressionEnd: OptionalCtx,
3064 CurlySuffixExpressionBegin: OptionalCtx,
3065 CurlySuffixExpressionEnd: OptionalCtx,
3066 TypeExprBegin: OptionalCtx,
3067 TypeExprEnd: OptionalCtx,
3068 PrefixOpExpression: OptionalCtx,
3069 SuffixOpExpressionBegin: OptionalCtx,
3070 SuffixOpExpressionEnd: OptionalCtx,
3071 PrimaryExpression: OptionalCtx,
3072
3073 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3074 StringLiteral: OptionalCtx,
3075 Identifier: OptionalCtx,
3076 ErrorTag: &&ast.Node,
3077
3078
3079 IfToken: @TagType(Token.Id),
3080 IfTokenSave: ExpectTokenSave,
3081 ExpectToken: @TagType(Token.Id),
3082 ExpectTokenSave: ExpectTokenSave,
3083 OptionalTokenSave: OptionalTokenSave,
3084};
3085
3086fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment {
3087 var result: ?&ast.Node.DocComment = null;
3088 while (true) {
3089 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3090 const node = blk: {
3091 if (result) |comment_node| {
3092 break :blk comment_node;
3093 } else {
3094 const comment_node = try arena.construct(ast.Node.DocComment {
3095 .base = ast.Node {
3096 .id = ast.Node.Id.DocComment,
3097 },
3098 .lines = ast.Node.DocComment.LineList.init(arena),
3099 });
3100 result = comment_node;
3101 break :blk comment_node;
3102 }
3103 };
3104 try node.lines.push(line_comment);
3105 continue;
3106 }
3107 break;
3108 }
3109 return result;
3110}
3111
3112fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.LineComment {
3113 const token = eatToken(tok_it, tree, Token.Id.LineComment) ?? return null;
3114 return try arena.construct(ast.Node.LineComment {
3115 .base = ast.Node {
3116 .id = ast.Node.Id.LineComment,
3117 },
3118 .token = token,
3119 });
3120}
3121
3122fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3123 token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node
3124{
3125 switch (token_ptr.id) {
3126 Token.Id.StringLiteral => {
3127 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3128 },
3129 Token.Id.MultilineStringLiteralLine => {
3130 const node = try arena.construct(ast.Node.MultilineStringLiteral {
3131 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },
3132 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3133 });
3134 try node.lines.push(token_index);
3135 while (true) {
3136 const multiline_str = nextToken(tok_it, tree);
3137 const multiline_str_index = multiline_str.index;
3138 const multiline_str_ptr = multiline_str.ptr;
3139 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3140 putBackToken(tok_it, tree);
3141 break;
3142 }
3143
3144 try node.lines.push(multiline_str_index);
3145 }
3146
3147 return &node.base;
3148 },
3149 // TODO: We shouldn't need a cast, but:
3150 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
3151 else => return (?&ast.Node)(null),
3152 }
3153}
3154
3155fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx,
3156 token_ptr: &const Token, token_index: TokenIndex) !bool {
3157 switch (token_ptr.id) {
3158 Token.Id.Keyword_suspend => {
3159 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,
3160 ast.Node.Suspend {
3161 .base = undefined,
3162 .label = null,
3163 .suspend_token = token_index,
3164 .payload = null,
3165 .body = null,
3166 }
3167 );
3168
3169 stack.append(State { .SuspendBody = node }) catch unreachable;
3170 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3171 return true;
3172 },
3173 Token.Id.Keyword_if => {
3174 const node = try createToCtxNode(arena, ctx, ast.Node.If,
3175 ast.Node.If {
3176 .base = undefined,
3177 .if_token = token_index,
3178 .condition = undefined,
3179 .payload = null,
3180 .body = undefined,
3181 .@"else" = null,
3182 }
3183 );
3184
3185 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3186 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3187 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3188 try stack.append(State { .ExpectToken = Token.Id.RParen });
3189 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3190 try stack.append(State { .ExpectToken = Token.Id.LParen });
3191 return true;
3192 },
3193 Token.Id.Keyword_while => {
3194 stack.append(State {
3195 .While = LoopCtx {
3196 .label = null,
3197 .inline_token = null,
3198 .loop_token = token_index,
3199 .opt_ctx = *ctx,
3200 }
3201 }) catch unreachable;
3202 return true;
3203 },
3204 Token.Id.Keyword_for => {
3205 stack.append(State {
3206 .For = LoopCtx {
3207 .label = null,
3208 .inline_token = null,
3209 .loop_token = token_index,
3210 .opt_ctx = *ctx,
3211 }
3212 }) catch unreachable;
3213 return true;
3214 },
3215 Token.Id.Keyword_switch => {
3216 const node = try arena.construct(ast.Node.Switch {
3217 .base = ast.Node {
3218 .id = ast.Node.Id.Switch,
3219 },
3220 .switch_token = token_index,
3221 .expr = undefined,
3222 .cases = ast.Node.Switch.CaseList.init(arena),
3223 .rbrace = undefined,
3224 });
3225 ctx.store(&node.base);
3226
3227 stack.append(State {
3228 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {
3229 .list = &node.cases,
3230 .ptr = &node.rbrace,
3231 },
3232 }) catch unreachable;
3233 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3234 try stack.append(State { .ExpectToken = Token.Id.RParen });
3235 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3236 try stack.append(State { .ExpectToken = Token.Id.LParen });
3237 return true;
3238 },
3239 Token.Id.Keyword_comptime => {
3240 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,
3241 ast.Node.Comptime {
3242 .base = undefined,
3243 .comptime_token = token_index,
3244 .expr = undefined,
3245 .doc_comments = null,
3246 }
3247 );
3248 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3249 return true;
3250 },
3251 Token.Id.LBrace => {
3252 const block = try arena.construct(ast.Node.Block {
3253 .base = ast.Node {.id = ast.Node.Id.Block },
3254 .label = null,
3255 .lbrace = token_index,
3256 .statements = ast.Node.Block.StatementList.init(arena),
3257 .rbrace = undefined,
3258 });
3259 ctx.store(&block.base);
3260 stack.append(State { .Block = block }) catch unreachable;
3261 return true;
3262 },
3263 else => {
3264 return false;
3265 }
3266 }
3267}
3268
3269const ExpectCommaOrEndResult = union(enum) {
3270 end_token: ?TokenIndex,
3271 parse_error: Error,
3272};
3273
3274fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3275 const token = nextToken(tok_it, tree);
3276 const token_index = token.index;
3277 const token_ptr = token.ptr;
3278 switch (token_ptr.id) {
3279 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},
3280 else => {
3281 if (end == token_ptr.id) {
3282 return ExpectCommaOrEndResult { .end_token = token_index };
3283 }
3284
3285 return ExpectCommaOrEndResult {
3286 .parse_error = Error {
3287 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {
3288 .token = token_index,
3289 .end_id = end,
3290 },
3291 },
3292 };
3293 },
3294 }
3295}
3296
3297fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3298 // TODO: We have to cast all cases because of this:
3299 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3300 return switch (*id) {
3301 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },
3302 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },
3303 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },
3304 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },
3305 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },
3306 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },
3307 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },
3308 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },
3309 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },
3310 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },
3311 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },
3312 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },
3313 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },
3314 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },
3315 else => null,
3316 };
3317}
3318
3319fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3320 return switch (id) {
3321 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3322 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3323 else => null,
3324 };
3325}
3326
3327fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3328 return switch (id) {
3329 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3330 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3331 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3332 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3333 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3334 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3335 else => null,
3336 };
3337}
3338
3339fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3340 return switch (id) {
3341 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3342 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3343 else => null,
3344 };
3345}
3346
3347fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3348 return switch (id) {
3349 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3350 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3351 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3352 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3353 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3354 else => null,
3355 };
3356}
3357
3358fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3359 return switch (id) {
3360 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3361 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3362 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3363 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3364 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3365 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3366 else => null,
3367 };
3368}
3369
3370fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3371 return switch (id) {
3372 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3373 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3374 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3375 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3376 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3377 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3378 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3379 .align_expr = null,
3380 .bit_offset_start_token = null,
3381 .bit_offset_end_token = null,
3382 .const_token = null,
3383 .volatile_token = null,
3384 },
3385 },
3386 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3387 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3388 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3389 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3390 else => null,
3391 };
3392}
3393
3394fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3395 const node = try arena.create(T);
3396 *node = *init_to;
3397 node.base = blk: {
3398 const id = ast.Node.typeToId(T);
3399 break :blk ast.Node {
3400 .id = id,
3401 };
3402 };
3403
3404 return node;
3405}
3406
3407fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3408 const node = try createNode(arena, T, init_to);
3409 opt_ctx.store(&node.base);
3410
3411 return node;
3412}
3413
3414fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3415 return createNode(arena, T,
3416 T {
3417 .base = undefined,
3418 .token = token_index,
3419 }
3420 );
3421}
3422
3423fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
3424 const node = try createLiteral(arena, T, token_index);
3425 opt_ctx.store(&node.base);
3426
3427 return node;
3428}
3429
3430fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3431 const token = nextToken(tok_it, tree);
3432
3433 if (token.ptr.id == id)
3434 return token.index;
3435
3436 putBackToken(tok_it, tree);
3437 return null;
3438}
3439
3440fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedToken {
3441 const result = AnnotatedToken {
3442 .index = tok_it.index,
3443 .ptr = ??tok_it.next(),
3444 };
3445 // possibly skip a following same line token
3446 const token = tok_it.next() ?? return result;
3447 if (token.id != Token.Id.LineComment) {
3448 putBackToken(tok_it, tree);
3449 return result;
3450 }
3451 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3452 if (loc.line != 0) {
3453 putBackToken(tok_it, tree);
3454 }
3455 return result;
3456}
3457
3458fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3459 const prev_tok = ??tok_it.prev();
3460 if (prev_tok.id == Token.Id.LineComment) {
3461 const minus2_tok = tok_it.prev() ?? return;
3462 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);
3463 if (loc.line != 0) {
3464 _ = tok_it.next();
3465 }
3466 }
3467}
3468
3469const RenderAstFrame = struct {
3470 node: &ast.Node,
3471 indent: usize,
3472};
3473
3474pub fn renderAst(allocator: &mem.Allocator, tree: &const ast.Tree, stream: var) !void {
3475 var stack = std.ArrayList(State).init(allocator);
3476 defer stack.deinit();
3477
3478 try stack.append(RenderAstFrame {
3479 .node = &root_node.base,
3480 .indent = 0,
3481 });
3482
3483 while (stack.popOrNull()) |frame| {
3484 {
3485 var i: usize = 0;
3486 while (i < frame.indent) : (i += 1) {
3487 try stream.print(" ");
3488 }
3489 }
3490 try stream.print("{}\n", @tagName(frame.node.id));
3491 var child_i: usize = 0;
3492 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3493 try stack.append(RenderAstFrame {
3494 .node = child,
3495 .indent = frame.indent + 2,
3496 });
3497 }
3498 }
3499}
3500
3501test "std.zig.parser" {
3502 _ = @import("parser_test.zig");
3503}
std/zig/parser.zig deleted-4704
...@@ -1,4704 +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 statememt = try ctx.block.statements.addOne();
1386 stack.append(State { .Semicolon = statememt }) catch unreachable;
1387 try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });
1388 continue;
1389 }
1390 }
1391 },
1392 State.Semicolon => |node_ptr| {
1393 const node = *node_ptr;
1394 if (requireSemiColon(node)) {
1395 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1396 continue;
1397 }
1398 continue;
1399 },
1400
1401 State.LookForSameLineComment => |node_ptr| {
1402 try self.lookForSameLineComment(arena, *node_ptr);
1403 continue;
1404 },
1405
1406 State.LookForSameLineCommentDirect => |node| {
1407 try self.lookForSameLineComment(arena, node);
1408 continue;
1409 },
1410
1411
1412 State.AsmOutputItems => |items| {
1413 const lbracket = self.getNextToken();
1414 if (lbracket.id != Token.Id.LBracket) {
1415 self.putBackToken(lbracket);
1416 continue;
1417 }
1418
1419 const node = try self.createNode(arena, ast.Node.AsmOutput,
1420 ast.Node.AsmOutput {
1421 .base = undefined,
1422 .symbolic_name = undefined,
1423 .constraint = undefined,
1424 .kind = undefined,
1425 }
1426 );
1427 try items.append(node);
1428
1429 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1430 try stack.append(State { .IfToken = Token.Id.Comma });
1431 try stack.append(State { .ExpectToken = Token.Id.RParen });
1432 try stack.append(State { .AsmOutputReturnOrType = node });
1433 try stack.append(State { .ExpectToken = Token.Id.LParen });
1434 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1435 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1436 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1437 continue;
1438 },
1439 State.AsmOutputReturnOrType => |node| {
1440 const token = self.getNextToken();
1441 switch (token.id) {
1442 Token.Id.Identifier => {
1443 node.kind = ast.Node.AsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.Node.Identifier, token) };
1444 continue;
1445 },
1446 Token.Id.Arrow => {
1447 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1448 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1449 continue;
1450 },
1451 else => {
1452 return self.parseError(token, "expected '->' or {}, found {}",
1453 @tagName(Token.Id.Identifier),
1454 @tagName(token.id));
1455 },
1456 }
1457 },
1458 State.AsmInputItems => |items| {
1459 const lbracket = self.getNextToken();
1460 if (lbracket.id != Token.Id.LBracket) {
1461 self.putBackToken(lbracket);
1462 continue;
1463 }
1464
1465 const node = try self.createNode(arena, ast.Node.AsmInput,
1466 ast.Node.AsmInput {
1467 .base = undefined,
1468 .symbolic_name = undefined,
1469 .constraint = undefined,
1470 .expr = undefined,
1471 }
1472 );
1473 try items.append(node);
1474
1475 stack.append(State { .AsmInputItems = items }) catch unreachable;
1476 try stack.append(State { .IfToken = Token.Id.Comma });
1477 try stack.append(State { .ExpectToken = Token.Id.RParen });
1478 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1479 try stack.append(State { .ExpectToken = Token.Id.LParen });
1480 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1481 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1482 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1483 continue;
1484 },
1485 State.AsmClopperItems => |items| {
1486 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1487 try stack.append(State { .IfToken = Token.Id.Comma });
1488 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1489 continue;
1490 },
1491
1492
1493 State.ExprListItemOrEnd => |list_state| {
1494 if (self.eatToken(list_state.end)) |token| {
1495 *list_state.ptr = token;
1496 continue;
1497 }
1498
1499 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1500 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1501 continue;
1502 },
1503 State.ExprListCommaOrEnd => |list_state| {
1504 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1505 *list_state.ptr = end;
1506 continue;
1507 } else {
1508 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1509 continue;
1510 }
1511 },
1512 State.FieldInitListItemOrEnd => |list_state| {
1513 while (try self.eatLineComment(arena)) |line_comment| {
1514 try list_state.list.append(&line_comment.base);
1515 }
1516
1517 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1518 *list_state.ptr = rbrace;
1519 continue;
1520 }
1521
1522 const node = try arena.construct(ast.Node.FieldInitializer {
1523 .base = ast.Node {
1524 .id = ast.Node.Id.FieldInitializer,
1525 .same_line_comment = null,
1526 },
1527 .period_token = undefined,
1528 .name_token = undefined,
1529 .expr = undefined,
1530 });
1531 try list_state.list.append(&node.base);
1532
1533 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1534 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1535 try stack.append(State { .ExpectToken = Token.Id.Equal });
1536 try stack.append(State {
1537 .ExpectTokenSave = ExpectTokenSave {
1538 .id = Token.Id.Identifier,
1539 .ptr = &node.name_token,
1540 }
1541 });
1542 try stack.append(State {
1543 .ExpectTokenSave = ExpectTokenSave {
1544 .id = Token.Id.Period,
1545 .ptr = &node.period_token,
1546 }
1547 });
1548 continue;
1549 },
1550 State.FieldInitListCommaOrEnd => |list_state| {
1551 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1552 *list_state.ptr = end;
1553 continue;
1554 } else {
1555 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1556 continue;
1557 }
1558 },
1559 State.FieldListCommaOrEnd => |container_decl| {
1560 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1561 container_decl.rbrace_token = end;
1562 continue;
1563 }
1564
1565 try self.lookForSameLineComment(arena, container_decl.fields_and_decls.toSlice()[container_decl.fields_and_decls.len - 1]);
1566 try stack.append(State { .ContainerDecl = container_decl });
1567 continue;
1568 },
1569 State.ErrorTagListItemOrEnd => |list_state| {
1570 while (try self.eatLineComment(arena)) |line_comment| {
1571 try list_state.list.append(&line_comment.base);
1572 }
1573
1574 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1575 *list_state.ptr = rbrace;
1576 continue;
1577 }
1578
1579 const node_ptr = try list_state.list.addOne();
1580
1581 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1582 try stack.append(State { .ErrorTag = node_ptr });
1583 continue;
1584 },
1585 State.ErrorTagListCommaOrEnd => |list_state| {
1586 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1587 *list_state.ptr = end;
1588 continue;
1589 } else {
1590 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1591 continue;
1592 }
1593 },
1594 State.SwitchCaseOrEnd => |list_state| {
1595 while (try self.eatLineComment(arena)) |line_comment| {
1596 try list_state.list.append(&line_comment.base);
1597 }
1598
1599 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1600 *list_state.ptr = rbrace;
1601 continue;
1602 }
1603
1604 const comments = try self.eatDocComments(arena);
1605 const node = try arena.construct(ast.Node.SwitchCase {
1606 .base = ast.Node {
1607 .id = ast.Node.Id.SwitchCase,
1608 .same_line_comment = null,
1609 },
1610 .items = ArrayList(&ast.Node).init(arena),
1611 .payload = null,
1612 .expr = undefined,
1613 });
1614 try list_state.list.append(&node.base);
1615 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });
1616 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1617 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1618 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1619
1620 continue;
1621 },
1622
1623 State.SwitchCaseCommaOrEnd => |list_state| {
1624 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1625 *list_state.ptr = end;
1626 continue;
1627 }
1628
1629 const node = list_state.list.toSlice()[list_state.list.len - 1];
1630 try self.lookForSameLineComment(arena, node);
1631 try stack.append(State { .SwitchCaseOrEnd = list_state });
1632 continue;
1633 },
1634
1635 State.SwitchCaseFirstItem => |case_items| {
1636 const token = self.getNextToken();
1637 if (token.id == Token.Id.Keyword_else) {
1638 const else_node = try self.createAttachNode(arena, case_items, ast.Node.SwitchElse,
1639 ast.Node.SwitchElse {
1640 .base = undefined,
1641 .token = token,
1642 }
1643 );
1644 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1645 continue;
1646 } else {
1647 self.putBackToken(token);
1648 try stack.append(State { .SwitchCaseItem = case_items });
1649 continue;
1650 }
1651 },
1652 State.SwitchCaseItem => |case_items| {
1653 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1654 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1655 },
1656 State.SwitchCaseItemCommaOrEnd => |case_items| {
1657 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1658 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1659 }
1660 continue;
1661 },
1662
1663
1664 State.SuspendBody => |suspend_node| {
1665 if (suspend_node.payload != null) {
1666 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1667 }
1668 continue;
1669 },
1670 State.AsyncAllocator => |async_node| {
1671 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
1672 continue;
1673 }
1674
1675 async_node.rangle_bracket = Token(undefined);
1676 try stack.append(State {
1677 .ExpectTokenSave = ExpectTokenSave {
1678 .id = Token.Id.AngleBracketRight,
1679 .ptr = &??async_node.rangle_bracket,
1680 }
1681 });
1682 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1683 continue;
1684 },
1685 State.AsyncEnd => |ctx| {
1686 const node = ctx.ctx.get() ?? continue;
1687
1688 switch (node.id) {
1689 ast.Node.Id.FnProto => {
1690 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1691 fn_proto.async_attr = ctx.attribute;
1692 continue;
1693 },
1694 ast.Node.Id.SuffixOp => {
1695 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1696 if (suffix_op.op == ast.Node.SuffixOp.Op.Call) {
1697 suffix_op.op.Call.async_attr = ctx.attribute;
1698 continue;
1699 }
1700
1701 return self.parseError(node.firstToken(), "expected {}, found {}.",
1702 @tagName(ast.Node.SuffixOp.Op.Call),
1703 @tagName(suffix_op.op));
1704 },
1705 else => {
1706 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1707 @tagName(ast.Node.SuffixOp.Op.Call),
1708 @tagName(ast.Node.Id.FnProto),
1709 @tagName(node.id));
1710 }
1711 }
1712 },
1713
1714
1715 State.ExternType => |ctx| {
1716 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1717 const fn_proto = try arena.construct(ast.Node.FnProto {
1718 .base = ast.Node {
1719 .id = ast.Node.Id.FnProto,
1720 .same_line_comment = null,
1721 },
1722 .doc_comments = ctx.comments,
1723 .visib_token = null,
1724 .name_token = null,
1725 .fn_token = fn_token,
1726 .params = ArrayList(&ast.Node).init(arena),
1727 .return_type = undefined,
1728 .var_args_token = null,
1729 .extern_export_inline_token = ctx.extern_token,
1730 .cc_token = null,
1731 .async_attr = null,
1732 .body_node = null,
1733 .lib_name = null,
1734 .align_expr = null,
1735 });
1736 ctx.opt_ctx.store(&fn_proto.base);
1737 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1738 continue;
1739 }
1740
1741 stack.append(State {
1742 .ContainerKind = ContainerKindCtx {
1743 .opt_ctx = ctx.opt_ctx,
1744 .ltoken = ctx.extern_token,
1745 .layout = ast.Node.ContainerDecl.Layout.Extern,
1746 },
1747 }) catch unreachable;
1748 continue;
1749 },
1750 State.SliceOrArrayAccess => |node| {
1751 var token = self.getNextToken();
1752 switch (token.id) {
1753 Token.Id.Ellipsis2 => {
1754 const start = node.op.ArrayAccess;
1755 node.op = ast.Node.SuffixOp.Op {
1756 .Slice = ast.Node.SuffixOp.SliceRange {
1757 .start = start,
1758 .end = null,
1759 }
1760 };
1761
1762 stack.append(State {
1763 .ExpectTokenSave = ExpectTokenSave {
1764 .id = Token.Id.RBracket,
1765 .ptr = &node.rtoken,
1766 }
1767 }) catch unreachable;
1768 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1769 continue;
1770 },
1771 Token.Id.RBracket => {
1772 node.rtoken = token;
1773 continue;
1774 },
1775 else => {
1776 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1777 }
1778 }
1779 },
1780 State.SliceOrArrayType => |node| {
1781 if (self.eatToken(Token.Id.RBracket)) |_| {
1782 node.op = ast.Node.PrefixOp.Op {
1783 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1784 .align_expr = null,
1785 .bit_offset_start_token = null,
1786 .bit_offset_end_token = null,
1787 .const_token = null,
1788 .volatile_token = null,
1789 }
1790 };
1791 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1792 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1793 continue;
1794 }
1795
1796 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1797 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1798 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1799 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1800 continue;
1801 },
1802 State.AddrOfModifiers => |addr_of_info| {
1803 var token = self.getNextToken();
1804 switch (token.id) {
1805 Token.Id.Keyword_align => {
1806 stack.append(state) catch unreachable;
1807 if (addr_of_info.align_expr != null) {
1808 return self.parseError(token, "multiple align qualifiers");
1809 }
1810 try stack.append(State { .ExpectToken = Token.Id.RParen });
1811 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1812 try stack.append(State { .ExpectToken = Token.Id.LParen });
1813 continue;
1814 },
1815 Token.Id.Keyword_const => {
1816 stack.append(state) catch unreachable;
1817 if (addr_of_info.const_token != null) {
1818 return self.parseError(token, "duplicate qualifier: const");
1819 }
1820 addr_of_info.const_token = token;
1821 continue;
1822 },
1823 Token.Id.Keyword_volatile => {
1824 stack.append(state) catch unreachable;
1825 if (addr_of_info.volatile_token != null) {
1826 return self.parseError(token, "duplicate qualifier: volatile");
1827 }
1828 addr_of_info.volatile_token = token;
1829 continue;
1830 },
1831 else => {
1832 self.putBackToken(token);
1833 continue;
1834 },
1835 }
1836 },
1837
1838
1839 State.Payload => |opt_ctx| {
1840 const token = self.getNextToken();
1841 if (token.id != Token.Id.Pipe) {
1842 if (opt_ctx != OptionalCtx.Optional) {
1843 return self.parseError(token, "expected {}, found {}.",
1844 @tagName(Token.Id.Pipe),
1845 @tagName(token.id));
1846 }
1847
1848 self.putBackToken(token);
1849 continue;
1850 }
1851
1852 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1853 ast.Node.Payload {
1854 .base = undefined,
1855 .lpipe = token,
1856 .error_symbol = undefined,
1857 .rpipe = undefined
1858 }
1859 );
1860
1861 stack.append(State {
1862 .ExpectTokenSave = ExpectTokenSave {
1863 .id = Token.Id.Pipe,
1864 .ptr = &node.rpipe,
1865 }
1866 }) catch unreachable;
1867 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1868 continue;
1869 },
1870 State.PointerPayload => |opt_ctx| {
1871 const token = self.getNextToken();
1872 if (token.id != Token.Id.Pipe) {
1873 if (opt_ctx != OptionalCtx.Optional) {
1874 return self.parseError(token, "expected {}, found {}.",
1875 @tagName(Token.Id.Pipe),
1876 @tagName(token.id));
1877 }
1878
1879 self.putBackToken(token);
1880 continue;
1881 }
1882
1883 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1884 ast.Node.PointerPayload {
1885 .base = undefined,
1886 .lpipe = token,
1887 .ptr_token = null,
1888 .value_symbol = undefined,
1889 .rpipe = undefined
1890 }
1891 );
1892
1893 stack.append(State {
1894 .ExpectTokenSave = ExpectTokenSave {
1895 .id = Token.Id.Pipe,
1896 .ptr = &node.rpipe,
1897 }
1898 }) catch unreachable;
1899 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1900 try stack.append(State {
1901 .OptionalTokenSave = OptionalTokenSave {
1902 .id = Token.Id.Asterisk,
1903 .ptr = &node.ptr_token,
1904 }
1905 });
1906 continue;
1907 },
1908 State.PointerIndexPayload => |opt_ctx| {
1909 const token = self.getNextToken();
1910 if (token.id != Token.Id.Pipe) {
1911 if (opt_ctx != OptionalCtx.Optional) {
1912 return self.parseError(token, "expected {}, found {}.",
1913 @tagName(Token.Id.Pipe),
1914 @tagName(token.id));
1915 }
1916
1917 self.putBackToken(token);
1918 continue;
1919 }
1920
1921 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1922 ast.Node.PointerIndexPayload {
1923 .base = undefined,
1924 .lpipe = token,
1925 .ptr_token = null,
1926 .value_symbol = undefined,
1927 .index_symbol = null,
1928 .rpipe = undefined
1929 }
1930 );
1931
1932 stack.append(State {
1933 .ExpectTokenSave = ExpectTokenSave {
1934 .id = Token.Id.Pipe,
1935 .ptr = &node.rpipe,
1936 }
1937 }) catch unreachable;
1938 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1939 try stack.append(State { .IfToken = Token.Id.Comma });
1940 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1941 try stack.append(State {
1942 .OptionalTokenSave = OptionalTokenSave {
1943 .id = Token.Id.Asterisk,
1944 .ptr = &node.ptr_token,
1945 }
1946 });
1947 continue;
1948 },
1949
1950
1951 State.Expression => |opt_ctx| {
1952 const token = self.getNextToken();
1953 switch (token.id) {
1954 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1955 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1956 ast.Node.ControlFlowExpression {
1957 .base = undefined,
1958 .ltoken = token,
1959 .kind = undefined,
1960 .rhs = null,
1961 }
1962 );
1963
1964 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1965
1966 switch (token.id) {
1967 Token.Id.Keyword_break => {
1968 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1969 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1970 try stack.append(State { .IfToken = Token.Id.Colon });
1971 },
1972 Token.Id.Keyword_continue => {
1973 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1974 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1975 try stack.append(State { .IfToken = Token.Id.Colon });
1976 },
1977 Token.Id.Keyword_return => {
1978 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1979 },
1980 else => unreachable,
1981 }
1982 continue;
1983 },
1984 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1985 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1986 ast.Node.PrefixOp {
1987 .base = undefined,
1988 .op_token = token,
1989 .op = switch (token.id) {
1990 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1991 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1992 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1993 else => unreachable,
1994 },
1995 .rhs = undefined,
1996 }
1997 );
1998
1999 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2000 continue;
2001 },
2002 else => {
2003 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2004 self.putBackToken(token);
2005 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
2006 }
2007 continue;
2008 }
2009 }
2010 },
2011 State.RangeExpressionBegin => |opt_ctx| {
2012 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
2013 try stack.append(State { .Expression = opt_ctx });
2014 continue;
2015 },
2016 State.RangeExpressionEnd => |opt_ctx| {
2017 const lhs = opt_ctx.get() ?? continue;
2018
2019 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
2020 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2021 ast.Node.InfixOp {
2022 .base = undefined,
2023 .lhs = lhs,
2024 .op_token = ellipsis3,
2025 .op = ast.Node.InfixOp.Op.Range,
2026 .rhs = undefined,
2027 }
2028 );
2029 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2030 continue;
2031 }
2032 },
2033 State.AssignmentExpressionBegin => |opt_ctx| {
2034 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
2035 try stack.append(State { .Expression = opt_ctx });
2036 continue;
2037 },
2038
2039 State.AssignmentExpressionEnd => |opt_ctx| {
2040 const lhs = opt_ctx.get() ?? continue;
2041
2042 const token = self.getNextToken();
2043 if (tokenIdToAssignment(token.id)) |ass_id| {
2044 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2045 ast.Node.InfixOp {
2046 .base = undefined,
2047 .lhs = lhs,
2048 .op_token = token,
2049 .op = ass_id,
2050 .rhs = undefined,
2051 }
2052 );
2053 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2054 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
2055 continue;
2056 } else {
2057 self.putBackToken(token);
2058 continue;
2059 }
2060 },
2061
2062 State.UnwrapExpressionBegin => |opt_ctx| {
2063 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
2064 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
2065 continue;
2066 },
2067
2068 State.UnwrapExpressionEnd => |opt_ctx| {
2069 const lhs = opt_ctx.get() ?? continue;
2070
2071 const token = self.getNextToken();
2072 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
2073 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2074 ast.Node.InfixOp {
2075 .base = undefined,
2076 .lhs = lhs,
2077 .op_token = token,
2078 .op = unwrap_id,
2079 .rhs = undefined,
2080 }
2081 );
2082
2083 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2084 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
2085
2086 if (node.op == ast.Node.InfixOp.Op.Catch) {
2087 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
2088 }
2089 continue;
2090 } else {
2091 self.putBackToken(token);
2092 continue;
2093 }
2094 },
2095
2096 State.BoolOrExpressionBegin => |opt_ctx| {
2097 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
2098 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
2099 continue;
2100 },
2101
2102 State.BoolOrExpressionEnd => |opt_ctx| {
2103 const lhs = opt_ctx.get() ?? continue;
2104
2105 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
2106 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2107 ast.Node.InfixOp {
2108 .base = undefined,
2109 .lhs = lhs,
2110 .op_token = or_token,
2111 .op = ast.Node.InfixOp.Op.BoolOr,
2112 .rhs = undefined,
2113 }
2114 );
2115 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2116 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2117 continue;
2118 }
2119 },
2120
2121 State.BoolAndExpressionBegin => |opt_ctx| {
2122 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
2123 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
2124 continue;
2125 },
2126
2127 State.BoolAndExpressionEnd => |opt_ctx| {
2128 const lhs = opt_ctx.get() ?? continue;
2129
2130 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
2131 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2132 ast.Node.InfixOp {
2133 .base = undefined,
2134 .lhs = lhs,
2135 .op_token = and_token,
2136 .op = ast.Node.InfixOp.Op.BoolAnd,
2137 .rhs = undefined,
2138 }
2139 );
2140 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2141 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2142 continue;
2143 }
2144 },
2145
2146 State.ComparisonExpressionBegin => |opt_ctx| {
2147 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2148 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
2149 continue;
2150 },
2151
2152 State.ComparisonExpressionEnd => |opt_ctx| {
2153 const lhs = opt_ctx.get() ?? continue;
2154
2155 const token = self.getNextToken();
2156 if (tokenIdToComparison(token.id)) |comp_id| {
2157 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2158 ast.Node.InfixOp {
2159 .base = undefined,
2160 .lhs = lhs,
2161 .op_token = token,
2162 .op = comp_id,
2163 .rhs = undefined,
2164 }
2165 );
2166 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2167 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2168 continue;
2169 } else {
2170 self.putBackToken(token);
2171 continue;
2172 }
2173 },
2174
2175 State.BinaryOrExpressionBegin => |opt_ctx| {
2176 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2177 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2178 continue;
2179 },
2180
2181 State.BinaryOrExpressionEnd => |opt_ctx| {
2182 const lhs = opt_ctx.get() ?? continue;
2183
2184 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2185 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2186 ast.Node.InfixOp {
2187 .base = undefined,
2188 .lhs = lhs,
2189 .op_token = pipe,
2190 .op = ast.Node.InfixOp.Op.BitOr,
2191 .rhs = undefined,
2192 }
2193 );
2194 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2195 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2196 continue;
2197 }
2198 },
2199
2200 State.BinaryXorExpressionBegin => |opt_ctx| {
2201 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2202 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2203 continue;
2204 },
2205
2206 State.BinaryXorExpressionEnd => |opt_ctx| {
2207 const lhs = opt_ctx.get() ?? continue;
2208
2209 if (self.eatToken(Token.Id.Caret)) |caret| {
2210 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2211 ast.Node.InfixOp {
2212 .base = undefined,
2213 .lhs = lhs,
2214 .op_token = caret,
2215 .op = ast.Node.InfixOp.Op.BitXor,
2216 .rhs = undefined,
2217 }
2218 );
2219 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2220 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2221 continue;
2222 }
2223 },
2224
2225 State.BinaryAndExpressionBegin => |opt_ctx| {
2226 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2227 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2228 continue;
2229 },
2230
2231 State.BinaryAndExpressionEnd => |opt_ctx| {
2232 const lhs = opt_ctx.get() ?? continue;
2233
2234 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2235 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2236 ast.Node.InfixOp {
2237 .base = undefined,
2238 .lhs = lhs,
2239 .op_token = ampersand,
2240 .op = ast.Node.InfixOp.Op.BitAnd,
2241 .rhs = undefined,
2242 }
2243 );
2244 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2245 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2246 continue;
2247 }
2248 },
2249
2250 State.BitShiftExpressionBegin => |opt_ctx| {
2251 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2252 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2253 continue;
2254 },
2255
2256 State.BitShiftExpressionEnd => |opt_ctx| {
2257 const lhs = opt_ctx.get() ?? continue;
2258
2259 const token = self.getNextToken();
2260 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2261 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2262 ast.Node.InfixOp {
2263 .base = undefined,
2264 .lhs = lhs,
2265 .op_token = token,
2266 .op = bitshift_id,
2267 .rhs = undefined,
2268 }
2269 );
2270 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2271 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2272 continue;
2273 } else {
2274 self.putBackToken(token);
2275 continue;
2276 }
2277 },
2278
2279 State.AdditionExpressionBegin => |opt_ctx| {
2280 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2281 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2282 continue;
2283 },
2284
2285 State.AdditionExpressionEnd => |opt_ctx| {
2286 const lhs = opt_ctx.get() ?? continue;
2287
2288 const token = self.getNextToken();
2289 if (tokenIdToAddition(token.id)) |add_id| {
2290 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2291 ast.Node.InfixOp {
2292 .base = undefined,
2293 .lhs = lhs,
2294 .op_token = token,
2295 .op = add_id,
2296 .rhs = undefined,
2297 }
2298 );
2299 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2300 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2301 continue;
2302 } else {
2303 self.putBackToken(token);
2304 continue;
2305 }
2306 },
2307
2308 State.MultiplyExpressionBegin => |opt_ctx| {
2309 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2310 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2311 continue;
2312 },
2313
2314 State.MultiplyExpressionEnd => |opt_ctx| {
2315 const lhs = opt_ctx.get() ?? continue;
2316
2317 const token = self.getNextToken();
2318 if (tokenIdToMultiply(token.id)) |mult_id| {
2319 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2320 ast.Node.InfixOp {
2321 .base = undefined,
2322 .lhs = lhs,
2323 .op_token = token,
2324 .op = mult_id,
2325 .rhs = undefined,
2326 }
2327 );
2328 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2329 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2330 continue;
2331 } else {
2332 self.putBackToken(token);
2333 continue;
2334 }
2335 },
2336
2337 State.CurlySuffixExpressionBegin => |opt_ctx| {
2338 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2339 try stack.append(State { .IfToken = Token.Id.LBrace });
2340 try stack.append(State { .TypeExprBegin = opt_ctx });
2341 continue;
2342 },
2343
2344 State.CurlySuffixExpressionEnd => |opt_ctx| {
2345 const lhs = opt_ctx.get() ?? continue;
2346
2347 if (self.isPeekToken(Token.Id.Period)) {
2348 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2349 ast.Node.SuffixOp {
2350 .base = undefined,
2351 .lhs = lhs,
2352 .op = ast.Node.SuffixOp.Op {
2353 .StructInitializer = ArrayList(&ast.Node).init(arena),
2354 },
2355 .rtoken = undefined,
2356 }
2357 );
2358 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2359 try stack.append(State { .IfToken = Token.Id.LBrace });
2360 try stack.append(State {
2361 .FieldInitListItemOrEnd = ListSave(&ast.Node) {
2362 .list = &node.op.StructInitializer,
2363 .ptr = &node.rtoken,
2364 }
2365 });
2366 continue;
2367 }
2368
2369 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2370 ast.Node.SuffixOp {
2371 .base = undefined,
2372 .lhs = lhs,
2373 .op = ast.Node.SuffixOp.Op {
2374 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2375 },
2376 .rtoken = undefined,
2377 }
2378 );
2379 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2380 try stack.append(State { .IfToken = Token.Id.LBrace });
2381 try stack.append(State {
2382 .ExprListItemOrEnd = ExprListCtx {
2383 .list = &node.op.ArrayInitializer,
2384 .end = Token.Id.RBrace,
2385 .ptr = &node.rtoken,
2386 }
2387 });
2388 continue;
2389 },
2390
2391 State.TypeExprBegin => |opt_ctx| {
2392 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2393 try stack.append(State { .PrefixOpExpression = opt_ctx });
2394 continue;
2395 },
2396
2397 State.TypeExprEnd => |opt_ctx| {
2398 const lhs = opt_ctx.get() ?? continue;
2399
2400 if (self.eatToken(Token.Id.Bang)) |bang| {
2401 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2402 ast.Node.InfixOp {
2403 .base = undefined,
2404 .lhs = lhs,
2405 .op_token = bang,
2406 .op = ast.Node.InfixOp.Op.ErrorUnion,
2407 .rhs = undefined,
2408 }
2409 );
2410 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2411 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2412 continue;
2413 }
2414 },
2415
2416 State.PrefixOpExpression => |opt_ctx| {
2417 const token = self.getNextToken();
2418 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2419 var node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2420 ast.Node.PrefixOp {
2421 .base = undefined,
2422 .op_token = token,
2423 .op = prefix_id,
2424 .rhs = undefined,
2425 }
2426 );
2427
2428 // Treat '**' token as two derefs
2429 if (token.id == Token.Id.AsteriskAsterisk) {
2430 const child = try self.createNode(arena, ast.Node.PrefixOp,
2431 ast.Node.PrefixOp {
2432 .base = undefined,
2433 .op_token = token,
2434 .op = prefix_id,
2435 .rhs = undefined,
2436 }
2437 );
2438 node.rhs = &child.base;
2439 node = child;
2440 }
2441
2442 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2443 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2444 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2445 }
2446 continue;
2447 } else {
2448 self.putBackToken(token);
2449 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2450 continue;
2451 }
2452 },
2453
2454 State.SuffixOpExpressionBegin => |opt_ctx| {
2455 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2456 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
2457 ast.Node.AsyncAttribute {
2458 .base = undefined,
2459 .async_token = async_token,
2460 .allocator_type = null,
2461 .rangle_bracket = null,
2462 }
2463 );
2464 stack.append(State {
2465 .AsyncEnd = AsyncEndCtx {
2466 .ctx = opt_ctx,
2467 .attribute = async_node,
2468 }
2469 }) catch unreachable;
2470 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2471 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2472 try stack.append(State { .AsyncAllocator = async_node });
2473 continue;
2474 }
2475
2476 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2477 try stack.append(State { .PrimaryExpression = opt_ctx });
2478 continue;
2479 },
2480
2481 State.SuffixOpExpressionEnd => |opt_ctx| {
2482 const lhs = opt_ctx.get() ?? continue;
2483
2484 const token = self.getNextToken();
2485 switch (token.id) {
2486 Token.Id.LParen => {
2487 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2488 ast.Node.SuffixOp {
2489 .base = undefined,
2490 .lhs = lhs,
2491 .op = ast.Node.SuffixOp.Op {
2492 .Call = ast.Node.SuffixOp.CallInfo {
2493 .params = ArrayList(&ast.Node).init(arena),
2494 .async_attr = null,
2495 }
2496 },
2497 .rtoken = undefined,
2498 }
2499 );
2500 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2501 try stack.append(State {
2502 .ExprListItemOrEnd = ExprListCtx {
2503 .list = &node.op.Call.params,
2504 .end = Token.Id.RParen,
2505 .ptr = &node.rtoken,
2506 }
2507 });
2508 continue;
2509 },
2510 Token.Id.LBracket => {
2511 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2512 ast.Node.SuffixOp {
2513 .base = undefined,
2514 .lhs = lhs,
2515 .op = ast.Node.SuffixOp.Op {
2516 .ArrayAccess = undefined,
2517 },
2518 .rtoken = undefined
2519 }
2520 );
2521 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2522 try stack.append(State { .SliceOrArrayAccess = node });
2523 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2524 continue;
2525 },
2526 Token.Id.Period => {
2527 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2528 ast.Node.InfixOp {
2529 .base = undefined,
2530 .lhs = lhs,
2531 .op_token = token,
2532 .op = ast.Node.InfixOp.Op.Period,
2533 .rhs = undefined,
2534 }
2535 );
2536 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2537 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2538 continue;
2539 },
2540 else => {
2541 self.putBackToken(token);
2542 continue;
2543 },
2544 }
2545 },
2546
2547 State.PrimaryExpression => |opt_ctx| {
2548 const token = self.getNextToken();
2549 switch (token.id) {
2550 Token.Id.IntegerLiteral => {
2551 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token);
2552 continue;
2553 },
2554 Token.Id.FloatLiteral => {
2555 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token);
2556 continue;
2557 },
2558 Token.Id.CharLiteral => {
2559 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token);
2560 continue;
2561 },
2562 Token.Id.Keyword_undefined => {
2563 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token);
2564 continue;
2565 },
2566 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2567 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token);
2568 continue;
2569 },
2570 Token.Id.Keyword_null => {
2571 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token);
2572 continue;
2573 },
2574 Token.Id.Keyword_this => {
2575 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token);
2576 continue;
2577 },
2578 Token.Id.Keyword_var => {
2579 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token);
2580 continue;
2581 },
2582 Token.Id.Keyword_unreachable => {
2583 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
2584 continue;
2585 },
2586 Token.Id.Keyword_promise => {
2587 const node = try arena.construct(ast.Node.PromiseType {
2588 .base = ast.Node {
2589 .id = ast.Node.Id.PromiseType,
2590 .same_line_comment = null,
2591 },
2592 .promise_token = token,
2593 .result = null,
2594 });
2595 opt_ctx.store(&node.base);
2596 const next_token = self.getNextToken();
2597 if (next_token.id != Token.Id.Arrow) {
2598 self.putBackToken(next_token);
2599 continue;
2600 }
2601 node.result = ast.Node.PromiseType.Result {
2602 .arrow_token = next_token,
2603 .return_type = undefined,
2604 };
2605 const return_type_ptr = &((??node.result).return_type);
2606 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2607 continue;
2608 },
2609 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2610 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2611 continue;
2612 },
2613 Token.Id.LParen => {
2614 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2615 ast.Node.GroupedExpression {
2616 .base = undefined,
2617 .lparen = token,
2618 .expr = undefined,
2619 .rparen = undefined,
2620 }
2621 );
2622 stack.append(State {
2623 .ExpectTokenSave = ExpectTokenSave {
2624 .id = Token.Id.RParen,
2625 .ptr = &node.rparen,
2626 }
2627 }) catch unreachable;
2628 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2629 continue;
2630 },
2631 Token.Id.Builtin => {
2632 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2633 ast.Node.BuiltinCall {
2634 .base = undefined,
2635 .builtin_token = token,
2636 .params = ArrayList(&ast.Node).init(arena),
2637 .rparen_token = undefined,
2638 }
2639 );
2640 stack.append(State {
2641 .ExprListItemOrEnd = ExprListCtx {
2642 .list = &node.params,
2643 .end = Token.Id.RParen,
2644 .ptr = &node.rparen_token,
2645 }
2646 }) catch unreachable;
2647 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2648 continue;
2649 },
2650 Token.Id.LBracket => {
2651 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2652 ast.Node.PrefixOp {
2653 .base = undefined,
2654 .op_token = token,
2655 .op = undefined,
2656 .rhs = undefined,
2657 }
2658 );
2659 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2660 continue;
2661 },
2662 Token.Id.Keyword_error => {
2663 stack.append(State {
2664 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2665 .error_token = token,
2666 .opt_ctx = opt_ctx
2667 }
2668 }) catch unreachable;
2669 continue;
2670 },
2671 Token.Id.Keyword_packed => {
2672 stack.append(State {
2673 .ContainerKind = ContainerKindCtx {
2674 .opt_ctx = opt_ctx,
2675 .ltoken = token,
2676 .layout = ast.Node.ContainerDecl.Layout.Packed,
2677 },
2678 }) catch unreachable;
2679 continue;
2680 },
2681 Token.Id.Keyword_extern => {
2682 stack.append(State {
2683 .ExternType = ExternTypeCtx {
2684 .opt_ctx = opt_ctx,
2685 .extern_token = token,
2686 .comments = null,
2687 },
2688 }) catch unreachable;
2689 continue;
2690 },
2691 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2692 self.putBackToken(token);
2693 stack.append(State {
2694 .ContainerKind = ContainerKindCtx {
2695 .opt_ctx = opt_ctx,
2696 .ltoken = token,
2697 .layout = ast.Node.ContainerDecl.Layout.Auto,
2698 },
2699 }) catch unreachable;
2700 continue;
2701 },
2702 Token.Id.Identifier => {
2703 stack.append(State {
2704 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2705 .label = token,
2706 .opt_ctx = opt_ctx
2707 }
2708 }) catch unreachable;
2709 continue;
2710 },
2711 Token.Id.Keyword_fn => {
2712 const fn_proto = try arena.construct(ast.Node.FnProto {
2713 .base = ast.Node {
2714 .id = ast.Node.Id.FnProto,
2715 .same_line_comment = null,
2716 },
2717 .doc_comments = null,
2718 .visib_token = null,
2719 .name_token = null,
2720 .fn_token = token,
2721 .params = ArrayList(&ast.Node).init(arena),
2722 .return_type = undefined,
2723 .var_args_token = null,
2724 .extern_export_inline_token = null,
2725 .cc_token = null,
2726 .async_attr = null,
2727 .body_node = null,
2728 .lib_name = null,
2729 .align_expr = null,
2730 });
2731 opt_ctx.store(&fn_proto.base);
2732 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2733 continue;
2734 },
2735 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2736 const fn_proto = try arena.construct(ast.Node.FnProto {
2737 .base = ast.Node {
2738 .id = ast.Node.Id.FnProto,
2739 .same_line_comment = null,
2740 },
2741 .doc_comments = null,
2742 .visib_token = null,
2743 .name_token = null,
2744 .fn_token = undefined,
2745 .params = ArrayList(&ast.Node).init(arena),
2746 .return_type = undefined,
2747 .var_args_token = null,
2748 .extern_export_inline_token = null,
2749 .cc_token = token,
2750 .async_attr = null,
2751 .body_node = null,
2752 .lib_name = null,
2753 .align_expr = null,
2754 });
2755 opt_ctx.store(&fn_proto.base);
2756 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2757 try stack.append(State {
2758 .ExpectTokenSave = ExpectTokenSave {
2759 .id = Token.Id.Keyword_fn,
2760 .ptr = &fn_proto.fn_token
2761 }
2762 });
2763 continue;
2764 },
2765 Token.Id.Keyword_asm => {
2766 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2767 ast.Node.Asm {
2768 .base = undefined,
2769 .asm_token = token,
2770 .volatile_token = null,
2771 .template = undefined,
2772 //.tokens = ArrayList(ast.Node.Asm.AsmToken).init(arena),
2773 .outputs = ArrayList(&ast.Node.AsmOutput).init(arena),
2774 .inputs = ArrayList(&ast.Node.AsmInput).init(arena),
2775 .cloppers = ArrayList(&ast.Node).init(arena),
2776 .rparen = undefined,
2777 }
2778 );
2779 stack.append(State {
2780 .ExpectTokenSave = ExpectTokenSave {
2781 .id = Token.Id.RParen,
2782 .ptr = &node.rparen,
2783 }
2784 }) catch unreachable;
2785 try stack.append(State { .AsmClopperItems = &node.cloppers });
2786 try stack.append(State { .IfToken = Token.Id.Colon });
2787 try stack.append(State { .AsmInputItems = &node.inputs });
2788 try stack.append(State { .IfToken = Token.Id.Colon });
2789 try stack.append(State { .AsmOutputItems = &node.outputs });
2790 try stack.append(State { .IfToken = Token.Id.Colon });
2791 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2792 try stack.append(State { .ExpectToken = Token.Id.LParen });
2793 try stack.append(State {
2794 .OptionalTokenSave = OptionalTokenSave {
2795 .id = Token.Id.Keyword_volatile,
2796 .ptr = &node.volatile_token,
2797 }
2798 });
2799 },
2800 Token.Id.Keyword_inline => {
2801 stack.append(State {
2802 .Inline = InlineCtx {
2803 .label = null,
2804 .inline_token = token,
2805 .opt_ctx = opt_ctx,
2806 }
2807 }) catch unreachable;
2808 continue;
2809 },
2810 else => {
2811 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2812 self.putBackToken(token);
2813 if (opt_ctx != OptionalCtx.Optional) {
2814 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2815 }
2816 }
2817 continue;
2818 }
2819 }
2820 },
2821
2822
2823 State.ErrorTypeOrSetDecl => |ctx| {
2824 if (self.eatToken(Token.Id.LBrace) == null) {
2825 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2826 continue;
2827 }
2828
2829 const node = try arena.construct(ast.Node.ErrorSetDecl {
2830 .base = ast.Node {
2831 .id = ast.Node.Id.ErrorSetDecl,
2832 .same_line_comment = null,
2833 },
2834 .error_token = ctx.error_token,
2835 .decls = ArrayList(&ast.Node).init(arena),
2836 .rbrace_token = undefined,
2837 });
2838 ctx.opt_ctx.store(&node.base);
2839
2840 stack.append(State {
2841 .ErrorTagListItemOrEnd = ListSave(&ast.Node) {
2842 .list = &node.decls,
2843 .ptr = &node.rbrace_token,
2844 }
2845 }) catch unreachable;
2846 continue;
2847 },
2848 State.StringLiteral => |opt_ctx| {
2849 const token = self.getNextToken();
2850 opt_ctx.store(
2851 (try self.parseStringLiteral(arena, token)) ?? {
2852 self.putBackToken(token);
2853 if (opt_ctx != OptionalCtx.Optional) {
2854 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2855 }
2856
2857 continue;
2858 }
2859 );
2860 },
2861
2862 State.Identifier => |opt_ctx| {
2863 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2864 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2865 continue;
2866 }
2867
2868 if (opt_ctx != OptionalCtx.Optional) {
2869 const token = self.getNextToken();
2870 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2871 }
2872 },
2873
2874 State.ErrorTag => |node_ptr| {
2875 const comments = try self.eatDocComments(arena);
2876 const ident_token = self.getNextToken();
2877 if (ident_token.id != Token.Id.Identifier) {
2878 return self.parseError(ident_token, "expected {}, found {}",
2879 @tagName(Token.Id.Identifier), @tagName(ident_token.id));
2880 }
2881
2882 const node = try arena.construct(ast.Node.ErrorTag {
2883 .base = ast.Node {
2884 .id = ast.Node.Id.ErrorTag,
2885 .same_line_comment = null,
2886 },
2887 .doc_comments = comments,
2888 .name_token = ident_token,
2889 });
2890 *node_ptr = &node.base;
2891 continue;
2892 },
2893
2894 State.ExpectToken => |token_id| {
2895 _ = try self.expectToken(token_id);
2896 continue;
2897 },
2898 State.ExpectTokenSave => |expect_token_save| {
2899 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2900 continue;
2901 },
2902 State.IfToken => |token_id| {
2903 if (self.eatToken(token_id)) |_| {
2904 continue;
2905 }
2906
2907 _ = stack.pop();
2908 continue;
2909 },
2910 State.IfTokenSave => |if_token_save| {
2911 if (self.eatToken(if_token_save.id)) |token| {
2912 *if_token_save.ptr = token;
2913 continue;
2914 }
2915
2916 _ = stack.pop();
2917 continue;
2918 },
2919 State.OptionalTokenSave => |optional_token_save| {
2920 if (self.eatToken(optional_token_save.id)) |token| {
2921 *optional_token_save.ptr = token;
2922 continue;
2923 }
2924
2925 continue;
2926 },
2927 }
2928 }
2929 }
2930
2931 fn eatDocComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.DocComment {
2932 var result: ?&ast.Node.DocComment = null;
2933 while (true) {
2934 if (self.eatToken(Token.Id.DocComment)) |line_comment| {
2935 const node = blk: {
2936 if (result) |comment_node| {
2937 break :blk comment_node;
2938 } else {
2939 const comment_node = try arena.construct(ast.Node.DocComment {
2940 .base = ast.Node {
2941 .id = ast.Node.Id.DocComment,
2942 .same_line_comment = null,
2943 },
2944 .lines = ArrayList(Token).init(arena),
2945 });
2946 result = comment_node;
2947 break :blk comment_node;
2948 }
2949 };
2950 try node.lines.append(line_comment);
2951 continue;
2952 }
2953 break;
2954 }
2955 return result;
2956 }
2957
2958 fn eatLineComment(self: &Parser, arena: &mem.Allocator) !?&ast.Node.LineComment {
2959 const token = self.eatToken(Token.Id.LineComment) ?? return null;
2960 return try arena.construct(ast.Node.LineComment {
2961 .base = ast.Node {
2962 .id = ast.Node.Id.LineComment,
2963 .same_line_comment = null,
2964 },
2965 .token = token,
2966 });
2967 }
2968
2969 fn requireSemiColon(node: &const ast.Node) bool {
2970 var n = node;
2971 while (true) {
2972 switch (n.id) {
2973 ast.Node.Id.Root,
2974 ast.Node.Id.StructField,
2975 ast.Node.Id.UnionTag,
2976 ast.Node.Id.EnumTag,
2977 ast.Node.Id.ParamDecl,
2978 ast.Node.Id.Block,
2979 ast.Node.Id.Payload,
2980 ast.Node.Id.PointerPayload,
2981 ast.Node.Id.PointerIndexPayload,
2982 ast.Node.Id.Switch,
2983 ast.Node.Id.SwitchCase,
2984 ast.Node.Id.SwitchElse,
2985 ast.Node.Id.FieldInitializer,
2986 ast.Node.Id.DocComment,
2987 ast.Node.Id.LineComment,
2988 ast.Node.Id.TestDecl => return false,
2989 ast.Node.Id.While => {
2990 const while_node = @fieldParentPtr(ast.Node.While, "base", n);
2991 if (while_node.@"else") |@"else"| {
2992 n = @"else".base;
2993 continue;
2994 }
2995
2996 return while_node.body.id != ast.Node.Id.Block;
2997 },
2998 ast.Node.Id.For => {
2999 const for_node = @fieldParentPtr(ast.Node.For, "base", n);
3000 if (for_node.@"else") |@"else"| {
3001 n = @"else".base;
3002 continue;
3003 }
3004
3005 return for_node.body.id != ast.Node.Id.Block;
3006 },
3007 ast.Node.Id.If => {
3008 const if_node = @fieldParentPtr(ast.Node.If, "base", n);
3009 if (if_node.@"else") |@"else"| {
3010 n = @"else".base;
3011 continue;
3012 }
3013
3014 return if_node.body.id != ast.Node.Id.Block;
3015 },
3016 ast.Node.Id.Else => {
3017 const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
3018 n = else_node.body;
3019 continue;
3020 },
3021 ast.Node.Id.Defer => {
3022 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
3023 return defer_node.expr.id != ast.Node.Id.Block;
3024 },
3025 ast.Node.Id.Comptime => {
3026 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
3027 return comptime_node.expr.id != ast.Node.Id.Block;
3028 },
3029 ast.Node.Id.Suspend => {
3030 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
3031 if (suspend_node.body) |body| {
3032 return body.id != ast.Node.Id.Block;
3033 }
3034
3035 return true;
3036 },
3037 else => return true,
3038 }
3039 }
3040 }
3041
3042 fn lookForSameLineComment(self: &Parser, arena: &mem.Allocator, node: &ast.Node) !void {
3043 const node_last_token = node.lastToken();
3044
3045 const line_comment_token = self.getNextToken();
3046 if (line_comment_token.id != Token.Id.DocComment and line_comment_token.id != Token.Id.LineComment) {
3047 self.putBackToken(line_comment_token);
3048 return;
3049 }
3050
3051 const offset_loc = self.tokenizer.getTokenLocation(node_last_token.end, line_comment_token);
3052 const different_line = offset_loc.line != 0;
3053 if (different_line) {
3054 self.putBackToken(line_comment_token);
3055 return;
3056 }
3057
3058 node.same_line_comment = try arena.construct(line_comment_token);
3059 }
3060
3061 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
3062 switch (token.id) {
3063 Token.Id.StringLiteral => {
3064 return &(try self.createLiteral(arena, ast.Node.StringLiteral, token)).base;
3065 },
3066 Token.Id.MultilineStringLiteralLine => {
3067 const node = try self.createNode(arena, ast.Node.MultilineStringLiteral,
3068 ast.Node.MultilineStringLiteral {
3069 .base = undefined,
3070 .tokens = ArrayList(Token).init(arena),
3071 }
3072 );
3073 try node.tokens.append(token);
3074 while (true) {
3075 const multiline_str = self.getNextToken();
3076 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
3077 self.putBackToken(multiline_str);
3078 break;
3079 }
3080
3081 try node.tokens.append(multiline_str);
3082 }
3083
3084 return &node.base;
3085 },
3086 // TODO: We shouldn't need a cast, but:
3087 // 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.
3088 else => return (?&ast.Node)(null),
3089 }
3090 }
3091
3092 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
3093 switch (token.id) {
3094 Token.Id.Keyword_suspend => {
3095 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
3096 ast.Node.Suspend {
3097 .base = undefined,
3098 .label = null,
3099 .suspend_token = *token,
3100 .payload = null,
3101 .body = null,
3102 }
3103 );
3104
3105 stack.append(State { .SuspendBody = node }) catch unreachable;
3106 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
3107 return true;
3108 },
3109 Token.Id.Keyword_if => {
3110 const node = try self.createToCtxNode(arena, ctx, ast.Node.If,
3111 ast.Node.If {
3112 .base = undefined,
3113 .if_token = *token,
3114 .condition = undefined,
3115 .payload = null,
3116 .body = undefined,
3117 .@"else" = null,
3118 }
3119 );
3120
3121 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3122 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3123 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3124 try stack.append(State { .ExpectToken = Token.Id.RParen });
3125 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3126 try stack.append(State { .ExpectToken = Token.Id.LParen });
3127 return true;
3128 },
3129 Token.Id.Keyword_while => {
3130 stack.append(State {
3131 .While = LoopCtx {
3132 .label = null,
3133 .inline_token = null,
3134 .loop_token = *token,
3135 .opt_ctx = *ctx,
3136 }
3137 }) catch unreachable;
3138 return true;
3139 },
3140 Token.Id.Keyword_for => {
3141 stack.append(State {
3142 .For = LoopCtx {
3143 .label = null,
3144 .inline_token = null,
3145 .loop_token = *token,
3146 .opt_ctx = *ctx,
3147 }
3148 }) catch unreachable;
3149 return true;
3150 },
3151 Token.Id.Keyword_switch => {
3152 const node = try arena.construct(ast.Node.Switch {
3153 .base = ast.Node {
3154 .id = ast.Node.Id.Switch,
3155 .same_line_comment = null,
3156 },
3157 .switch_token = *token,
3158 .expr = undefined,
3159 .cases = ArrayList(&ast.Node).init(arena),
3160 .rbrace = undefined,
3161 });
3162 ctx.store(&node.base);
3163
3164 stack.append(State {
3165 .SwitchCaseOrEnd = ListSave(&ast.Node) {
3166 .list = &node.cases,
3167 .ptr = &node.rbrace,
3168 },
3169 }) catch unreachable;
3170 try stack.append(State { .ExpectToken = Token.Id.LBrace });
3171 try stack.append(State { .ExpectToken = Token.Id.RParen });
3172 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3173 try stack.append(State { .ExpectToken = Token.Id.LParen });
3174 return true;
3175 },
3176 Token.Id.Keyword_comptime => {
3177 const node = try self.createToCtxNode(arena, ctx, ast.Node.Comptime,
3178 ast.Node.Comptime {
3179 .base = undefined,
3180 .comptime_token = *token,
3181 .expr = undefined,
3182 .doc_comments = null,
3183 }
3184 );
3185 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3186 return true;
3187 },
3188 Token.Id.LBrace => {
3189 const block = try self.createToCtxNode(arena, ctx, ast.Node.Block,
3190 ast.Node.Block {
3191 .base = undefined,
3192 .label = null,
3193 .lbrace = *token,
3194 .statements = ArrayList(&ast.Node).init(arena),
3195 .rbrace = undefined,
3196 }
3197 );
3198 stack.append(State { .Block = block }) catch unreachable;
3199 return true;
3200 },
3201 else => {
3202 return false;
3203 }
3204 }
3205 }
3206
3207 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
3208 var token = self.getNextToken();
3209 switch (token.id) {
3210 Token.Id.Comma => return null,
3211 else => {
3212 if (end == token.id) {
3213 return token;
3214 }
3215
3216 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
3217 },
3218 }
3219 }
3220
3221 fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3222 // TODO: We have to cast all cases because of this:
3223 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3224 return switch (*id) {
3225 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = void{} },
3226 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = void{} },
3227 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = void{} },
3228 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = void{} },
3229 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = void{} },
3230 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = void{} },
3231 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = void{} },
3232 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = void{} },
3233 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = void{} },
3234 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = void{} },
3235 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = void{} },
3236 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = void{} },
3237 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = void{} },
3238 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = void{} },
3239 else => null,
3240 };
3241 }
3242
3243 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3244 return switch (id) {
3245 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3246 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
3247 else => null,
3248 };
3249 }
3250
3251 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3252 return switch (id) {
3253 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3254 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3255 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3256 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3257 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3258 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
3259 else => null,
3260 };
3261 }
3262
3263 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3264 return switch (id) {
3265 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3266 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
3267 else => null,
3268 };
3269 }
3270
3271 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3272 return switch (id) {
3273 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3274 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3275 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3276 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3277 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
3278 else => null,
3279 };
3280 }
3281
3282 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3283 return switch (id) {
3284 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3285 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3286 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3287 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3288 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3289 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3290 else => null,
3291 };
3292 }
3293
3294 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3295 return switch (id) {
3296 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3297 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3298 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3299 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3300 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3301 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3302 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
3303 .align_expr = null,
3304 .bit_offset_start_token = null,
3305 .bit_offset_end_token = null,
3306 .const_token = null,
3307 .volatile_token = null,
3308 },
3309 },
3310 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3311 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3312 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3313 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3314 else => null,
3315 };
3316 }
3317
3318 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3319 const node = try arena.create(T);
3320 *node = *init_to;
3321 node.base = blk: {
3322 const id = ast.Node.typeToId(T);
3323 break :blk ast.Node {
3324 .id = id,
3325 .same_line_comment = null,
3326 };
3327 };
3328
3329 return node;
3330 }
3331
3332 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
3333 const node = try self.createNode(arena, T, init_to);
3334 try list.append(&node.base);
3335
3336 return node;
3337 }
3338
3339 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3340 const node = try self.createNode(arena, T, init_to);
3341 opt_ctx.store(&node.base);
3342
3343 return node;
3344 }
3345
3346 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
3347 return self.createNode(arena, T,
3348 T {
3349 .base = undefined,
3350 .token = *token,
3351 }
3352 );
3353 }
3354
3355 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3356 const node = try self.createLiteral(arena, T, token);
3357 opt_ctx.store(&node.base);
3358
3359 return node;
3360 }
3361
3362 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3363 const loc = self.tokenizer.getTokenLocation(0, token);
3364 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3365 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3366 {
3367 var i: usize = 0;
3368 while (i < loc.column) : (i += 1) {
3369 warn(" ");
3370 }
3371 }
3372 {
3373 const caret_count = token.end - token.start;
3374 var i: usize = 0;
3375 while (i < caret_count) : (i += 1) {
3376 warn("~");
3377 }
3378 }
3379 warn("\n");
3380 return error.ParseError;
3381 }
3382
3383 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
3384 const token = self.getNextToken();
3385 if (token.id != id) {
3386 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3387 }
3388 return token;
3389 }
3390
3391 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3392 if (self.isPeekToken(id)) {
3393 return self.getNextToken();
3394 }
3395 return null;
3396 }
3397
3398 fn putBackToken(self: &Parser, token: &const Token) void {
3399 self.put_back_tokens[self.put_back_count] = *token;
3400 self.put_back_count += 1;
3401 }
3402
3403 fn getNextToken(self: &Parser) Token {
3404 if (self.put_back_count != 0) {
3405 const put_back_index = self.put_back_count - 1;
3406 const put_back_token = self.put_back_tokens[put_back_index];
3407 self.put_back_count = put_back_index;
3408 return put_back_token;
3409 } else {
3410 return self.tokenizer.next();
3411 }
3412 }
3413
3414 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3415 const token = self.getNextToken();
3416 defer self.putBackToken(token);
3417 return id == token.id;
3418 }
3419
3420 const RenderAstFrame = struct {
3421 node: &ast.Node,
3422 indent: usize,
3423 };
3424
3425 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3426 var stack = self.initUtilityArrayList(RenderAstFrame);
3427 defer self.deinitUtilityArrayList(stack);
3428
3429 try stack.append(RenderAstFrame {
3430 .node = &root_node.base,
3431 .indent = 0,
3432 });
3433
3434 while (stack.popOrNull()) |frame| {
3435 {
3436 var i: usize = 0;
3437 while (i < frame.indent) : (i += 1) {
3438 try stream.print(" ");
3439 }
3440 }
3441 try stream.print("{}\n", @tagName(frame.node.id));
3442 var child_i: usize = 0;
3443 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3444 try stack.append(RenderAstFrame {
3445 .node = child,
3446 .indent = frame.indent + 2,
3447 });
3448 }
3449 }
3450 }
3451
3452 const RenderState = union(enum) {
3453 TopLevelDecl: &ast.Node,
3454 ParamDecl: &ast.Node,
3455 Text: []const u8,
3456 Expression: &ast.Node,
3457 VarDecl: &ast.Node.VarDecl,
3458 Statement: &ast.Node,
3459 PrintIndent,
3460 Indent: usize,
3461 PrintSameLineComment: ?&Token,
3462 };
3463
3464 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
3465 var stack = self.initUtilityArrayList(RenderState);
3466 defer self.deinitUtilityArrayList(stack);
3467
3468 {
3469 try stack.append(RenderState { .Text = "\n"});
3470
3471 var i = root_node.decls.len;
3472 while (i != 0) {
3473 i -= 1;
3474 const decl = root_node.decls.items[i];
3475 try stack.append(RenderState {.TopLevelDecl = decl});
3476 if (i != 0) {
3477 try stack.append(RenderState {
3478 .Text = blk: {
3479 const prev_node = root_node.decls.at(i - 1);
3480 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
3481 if (loc.line >= 2) {
3482 break :blk "\n\n";
3483 }
3484 break :blk "\n";
3485 },
3486 });
3487 }
3488 }
3489 }
3490
3491 const indent_delta = 4;
3492 var indent: usize = 0;
3493 while (stack.popOrNull()) |state| {
3494 switch (state) {
3495 RenderState.TopLevelDecl => |decl| {
3496 try stack.append(RenderState { .PrintSameLineComment = decl.same_line_comment } );
3497 switch (decl.id) {
3498 ast.Node.Id.FnProto => {
3499 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3500 try self.renderComments(stream, fn_proto, indent);
3501
3502 if (fn_proto.body_node) |body_node| {
3503 stack.append(RenderState { .Expression = body_node}) catch unreachable;
3504 try stack.append(RenderState { .Text = " "});
3505 } else {
3506 stack.append(RenderState { .Text = ";" }) catch unreachable;
3507 }
3508
3509 try stack.append(RenderState { .Expression = decl });
3510 },
3511 ast.Node.Id.Use => {
3512 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
3513 if (use_decl.visib_token) |visib_token| {
3514 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3515 }
3516 try stream.print("use ");
3517 try stack.append(RenderState { .Text = ";" });
3518 try stack.append(RenderState { .Expression = use_decl.expr });
3519 },
3520 ast.Node.Id.VarDecl => {
3521 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
3522 try self.renderComments(stream, var_decl, indent);
3523 try stack.append(RenderState { .VarDecl = var_decl});
3524 },
3525 ast.Node.Id.TestDecl => {
3526 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3527 try self.renderComments(stream, test_decl, indent);
3528 try stream.print("test ");
3529 try stack.append(RenderState { .Expression = test_decl.body_node });
3530 try stack.append(RenderState { .Text = " " });
3531 try stack.append(RenderState { .Expression = test_decl.name });
3532 },
3533 ast.Node.Id.StructField => {
3534 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
3535 try self.renderComments(stream, field, indent);
3536 if (field.visib_token) |visib_token| {
3537 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3538 }
3539 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3540 try stack.append(RenderState { .Text = "," });
3541 try stack.append(RenderState { .Expression = field.type_expr});
3542 },
3543 ast.Node.Id.UnionTag => {
3544 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
3545 try self.renderComments(stream, tag, indent);
3546 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3547
3548 try stack.append(RenderState { .Text = "," });
3549
3550 if (tag.value_expr) |value_expr| {
3551 try stack.append(RenderState { .Expression = value_expr });
3552 try stack.append(RenderState { .Text = " = " });
3553 }
3554
3555 if (tag.type_expr) |type_expr| {
3556 try stream.print(": ");
3557 try stack.append(RenderState { .Expression = type_expr});
3558 }
3559 },
3560 ast.Node.Id.EnumTag => {
3561 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
3562 try self.renderComments(stream, tag, indent);
3563 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3564
3565 try stack.append(RenderState { .Text = "," });
3566 if (tag.value) |value| {
3567 try stream.print(" = ");
3568 try stack.append(RenderState { .Expression = value});
3569 }
3570 },
3571 ast.Node.Id.ErrorTag => {
3572 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
3573 try self.renderComments(stream, tag, indent);
3574 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3575 },
3576 ast.Node.Id.Comptime => {
3577 if (requireSemiColon(decl)) {
3578 try stack.append(RenderState { .Text = ";" });
3579 }
3580 try stack.append(RenderState { .Expression = decl });
3581 },
3582 ast.Node.Id.LineComment => {
3583 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
3584 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
3585 },
3586 else => unreachable,
3587 }
3588 },
3589
3590 RenderState.VarDecl => |var_decl| {
3591 try stack.append(RenderState { .Text = ";" });
3592 if (var_decl.init_node) |init_node| {
3593 try stack.append(RenderState { .Expression = init_node });
3594 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
3595 try stack.append(RenderState { .Text = text });
3596 }
3597 if (var_decl.align_node) |align_node| {
3598 try stack.append(RenderState { .Text = ")" });
3599 try stack.append(RenderState { .Expression = align_node });
3600 try stack.append(RenderState { .Text = " align(" });
3601 }
3602 if (var_decl.type_node) |type_node| {
3603 try stack.append(RenderState { .Expression = type_node });
3604 try stack.append(RenderState { .Text = ": " });
3605 }
3606 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3607 try stack.append(RenderState { .Text = " " });
3608 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3609
3610 if (var_decl.comptime_token) |comptime_token| {
3611 try stack.append(RenderState { .Text = " " });
3612 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3613 }
3614
3615 if (var_decl.extern_export_token) |extern_export_token| {
3616 if (var_decl.lib_name != null) {
3617 try stack.append(RenderState { .Text = " " });
3618 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3619 }
3620 try stack.append(RenderState { .Text = " " });
3621 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
3622 }
3623
3624 if (var_decl.visib_token) |visib_token| {
3625 try stack.append(RenderState { .Text = " " });
3626 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3627 }
3628 },
3629
3630 RenderState.ParamDecl => |base| {
3631 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
3632 if (param_decl.comptime_token) |comptime_token| {
3633 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
3634 }
3635 if (param_decl.noalias_token) |noalias_token| {
3636 try stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token));
3637 }
3638 if (param_decl.name_token) |name_token| {
3639 try stream.print("{}: ", self.tokenizer.getTokenSlice(name_token));
3640 }
3641 if (param_decl.var_args_token) |var_args_token| {
3642 try stream.print("{}", self.tokenizer.getTokenSlice(var_args_token));
3643 } else {
3644 try stack.append(RenderState { .Expression = param_decl.type_node});
3645 }
3646 },
3647 RenderState.Text => |bytes| {
3648 try stream.write(bytes);
3649 },
3650 RenderState.Expression => |base| switch (base.id) {
3651 ast.Node.Id.Identifier => {
3652 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
3653 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
3654 },
3655 ast.Node.Id.Block => {
3656 const block = @fieldParentPtr(ast.Node.Block, "base", base);
3657 if (block.label) |label| {
3658 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3659 }
3660
3661 if (block.statements.len == 0) {
3662 try stream.write("{}");
3663 } else {
3664 try stream.write("{");
3665 try stack.append(RenderState { .Text = "}"});
3666 try stack.append(RenderState.PrintIndent);
3667 try stack.append(RenderState { .Indent = indent});
3668 try stack.append(RenderState { .Text = "\n"});
3669 var i = block.statements.len;
3670 while (i != 0) {
3671 i -= 1;
3672 const statement_node = block.statements.items[i];
3673 try stack.append(RenderState { .Statement = statement_node});
3674 try stack.append(RenderState.PrintIndent);
3675 try stack.append(RenderState { .Indent = indent + indent_delta});
3676 try stack.append(RenderState {
3677 .Text = blk: {
3678 if (i != 0) {
3679 const prev_node = block.statements.items[i - 1];
3680 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
3681 if (loc.line >= 2) {
3682 break :blk "\n\n";
3683 }
3684 }
3685 break :blk "\n";
3686 },
3687 });
3688 }
3689 }
3690 },
3691 ast.Node.Id.Defer => {
3692 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
3693 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3694 try stack.append(RenderState { .Expression = defer_node.expr });
3695 },
3696 ast.Node.Id.Comptime => {
3697 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
3698 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3699 try stack.append(RenderState { .Expression = comptime_node.expr });
3700 },
3701 ast.Node.Id.AsyncAttribute => {
3702 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
3703 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3704
3705 if (async_attr.allocator_type) |allocator_type| {
3706 try stack.append(RenderState { .Text = ">" });
3707 try stack.append(RenderState { .Expression = allocator_type });
3708 try stack.append(RenderState { .Text = "<" });
3709 }
3710 },
3711 ast.Node.Id.Suspend => {
3712 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
3713 if (suspend_node.label) |label| {
3714 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3715 }
3716 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3717
3718 if (suspend_node.body) |body| {
3719 try stack.append(RenderState { .Expression = body });
3720 try stack.append(RenderState { .Text = " " });
3721 }
3722
3723 if (suspend_node.payload) |payload| {
3724 try stack.append(RenderState { .Expression = payload });
3725 try stack.append(RenderState { .Text = " " });
3726 }
3727 },
3728 ast.Node.Id.InfixOp => {
3729 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
3730 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3731
3732 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
3733 if (prefix_op_node.op.Catch) |payload| {
3734 try stack.append(RenderState { .Text = " " });
3735 try stack.append(RenderState { .Expression = payload });
3736 }
3737 try stack.append(RenderState { .Text = " catch " });
3738 } else {
3739 const text = switch (prefix_op_node.op) {
3740 ast.Node.InfixOp.Op.Add => " + ",
3741 ast.Node.InfixOp.Op.AddWrap => " +% ",
3742 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
3743 ast.Node.InfixOp.Op.ArrayMult => " ** ",
3744 ast.Node.InfixOp.Op.Assign => " = ",
3745 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
3746 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
3747 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
3748 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
3749 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
3750 ast.Node.InfixOp.Op.AssignDiv => " /= ",
3751 ast.Node.InfixOp.Op.AssignMinus => " -= ",
3752 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
3753 ast.Node.InfixOp.Op.AssignMod => " %= ",
3754 ast.Node.InfixOp.Op.AssignPlus => " += ",
3755 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
3756 ast.Node.InfixOp.Op.AssignTimes => " *= ",
3757 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
3758 ast.Node.InfixOp.Op.BangEqual => " != ",
3759 ast.Node.InfixOp.Op.BitAnd => " & ",
3760 ast.Node.InfixOp.Op.BitOr => " | ",
3761 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
3762 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
3763 ast.Node.InfixOp.Op.BitXor => " ^ ",
3764 ast.Node.InfixOp.Op.BoolAnd => " and ",
3765 ast.Node.InfixOp.Op.BoolOr => " or ",
3766 ast.Node.InfixOp.Op.Div => " / ",
3767 ast.Node.InfixOp.Op.EqualEqual => " == ",
3768 ast.Node.InfixOp.Op.ErrorUnion => "!",
3769 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
3770 ast.Node.InfixOp.Op.GreaterThan => " > ",
3771 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
3772 ast.Node.InfixOp.Op.LessThan => " < ",
3773 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
3774 ast.Node.InfixOp.Op.Mod => " % ",
3775 ast.Node.InfixOp.Op.Mult => " * ",
3776 ast.Node.InfixOp.Op.MultWrap => " *% ",
3777 ast.Node.InfixOp.Op.Period => ".",
3778 ast.Node.InfixOp.Op.Sub => " - ",
3779 ast.Node.InfixOp.Op.SubWrap => " -% ",
3780 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
3781 ast.Node.InfixOp.Op.Range => " ... ",
3782 ast.Node.InfixOp.Op.Catch => unreachable,
3783 };
3784
3785 try stack.append(RenderState { .Text = text });
3786 }
3787 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
3788 },
3789 ast.Node.Id.PrefixOp => {
3790 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
3791 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3792 switch (prefix_op_node.op) {
3793 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
3794 try stream.write("&");
3795 if (addr_of_info.volatile_token != null) {
3796 try stack.append(RenderState { .Text = "volatile "});
3797 }
3798 if (addr_of_info.const_token != null) {
3799 try stack.append(RenderState { .Text = "const "});
3800 }
3801 if (addr_of_info.align_expr) |align_expr| {
3802 try stream.print("align(");
3803 try stack.append(RenderState { .Text = ") "});
3804 try stack.append(RenderState { .Expression = align_expr});
3805 }
3806 },
3807 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
3808 try stream.write("[]");
3809 if (addr_of_info.volatile_token != null) {
3810 try stack.append(RenderState { .Text = "volatile "});
3811 }
3812 if (addr_of_info.const_token != null) {
3813 try stack.append(RenderState { .Text = "const "});
3814 }
3815 if (addr_of_info.align_expr) |align_expr| {
3816 try stream.print("align(");
3817 try stack.append(RenderState { .Text = ") "});
3818 try stack.append(RenderState { .Expression = align_expr});
3819 }
3820 },
3821 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
3822 try stack.append(RenderState { .Text = "]"});
3823 try stack.append(RenderState { .Expression = array_index});
3824 try stack.append(RenderState { .Text = "["});
3825 },
3826 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
3827 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
3828 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
3829 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
3830 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
3831 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
3832 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
3833 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
3834 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
3835 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
3836 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
3837 }
3838 },
3839 ast.Node.Id.SuffixOp => {
3840 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
3841
3842 switch (suffix_op.op) {
3843 ast.Node.SuffixOp.Op.Call => |call_info| {
3844 try stack.append(RenderState { .Text = ")"});
3845 var i = call_info.params.len;
3846 while (i != 0) {
3847 i -= 1;
3848 const param_node = call_info.params.at(i);
3849 try stack.append(RenderState { .Expression = param_node});
3850 if (i != 0) {
3851 try stack.append(RenderState { .Text = ", " });
3852 }
3853 }
3854 try stack.append(RenderState { .Text = "("});
3855 try stack.append(RenderState { .Expression = suffix_op.lhs });
3856
3857 if (call_info.async_attr) |async_attr| {
3858 try stack.append(RenderState { .Text = " "});
3859 try stack.append(RenderState { .Expression = &async_attr.base });
3860 }
3861 },
3862 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
3863 try stack.append(RenderState { .Text = "]"});
3864 try stack.append(RenderState { .Expression = index_expr});
3865 try stack.append(RenderState { .Text = "["});
3866 try stack.append(RenderState { .Expression = suffix_op.lhs });
3867 },
3868 ast.Node.SuffixOp.Op.Slice => |range| {
3869 try stack.append(RenderState { .Text = "]"});
3870 if (range.end) |end| {
3871 try stack.append(RenderState { .Expression = end});
3872 }
3873 try stack.append(RenderState { .Text = ".."});
3874 try stack.append(RenderState { .Expression = range.start});
3875 try stack.append(RenderState { .Text = "["});
3876 try stack.append(RenderState { .Expression = suffix_op.lhs });
3877 },
3878 ast.Node.SuffixOp.Op.StructInitializer => |field_inits| {
3879 if (field_inits.len == 0) {
3880 try stack.append(RenderState { .Text = "{}" });
3881 try stack.append(RenderState { .Expression = suffix_op.lhs });
3882 continue;
3883 }
3884 if (field_inits.len == 1) {
3885 const field_init = field_inits.at(0);
3886
3887 try stack.append(RenderState { .Text = " }" });
3888 try stack.append(RenderState { .Expression = field_init });
3889 try stack.append(RenderState { .Text = "{ " });
3890 try stack.append(RenderState { .Expression = suffix_op.lhs });
3891 continue;
3892 }
3893 try stack.append(RenderState { .Text = "}"});
3894 try stack.append(RenderState.PrintIndent);
3895 try stack.append(RenderState { .Indent = indent });
3896 try stack.append(RenderState { .Text = "\n" });
3897 var i = field_inits.len;
3898 while (i != 0) {
3899 i -= 1;
3900 const field_init = field_inits.at(i);
3901 if (field_init.id != ast.Node.Id.LineComment) {
3902 try stack.append(RenderState { .Text = "," });
3903 }
3904 try stack.append(RenderState { .Expression = field_init });
3905 try stack.append(RenderState.PrintIndent);
3906 if (i != 0) {
3907 try stack.append(RenderState { .Text = blk: {
3908 const prev_node = field_inits.at(i - 1);
3909 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, field_init.firstToken());
3910 if (loc.line >= 2) {
3911 break :blk "\n\n";
3912 }
3913 break :blk "\n";
3914 }});
3915 }
3916 }
3917 try stack.append(RenderState { .Indent = indent + indent_delta });
3918 try stack.append(RenderState { .Text = "{\n"});
3919 try stack.append(RenderState { .Expression = suffix_op.lhs });
3920 },
3921 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
3922 if (exprs.len == 0) {
3923 try stack.append(RenderState { .Text = "{}" });
3924 try stack.append(RenderState { .Expression = suffix_op.lhs });
3925 continue;
3926 }
3927 if (exprs.len == 1) {
3928 const expr = exprs.at(0);
3929
3930 try stack.append(RenderState { .Text = "}" });
3931 try stack.append(RenderState { .Expression = expr });
3932 try stack.append(RenderState { .Text = "{" });
3933 try stack.append(RenderState { .Expression = suffix_op.lhs });
3934 continue;
3935 }
3936
3937 try stack.append(RenderState { .Text = "}"});
3938 try stack.append(RenderState.PrintIndent);
3939 try stack.append(RenderState { .Indent = indent });
3940 var i = exprs.len;
3941 while (i != 0) {
3942 i -= 1;
3943 const expr = exprs.at(i);
3944 try stack.append(RenderState { .Text = ",\n" });
3945 try stack.append(RenderState { .Expression = expr });
3946 try stack.append(RenderState.PrintIndent);
3947 }
3948 try stack.append(RenderState { .Indent = indent + indent_delta });
3949 try stack.append(RenderState { .Text = "{\n"});
3950 try stack.append(RenderState { .Expression = suffix_op.lhs });
3951 },
3952 }
3953 },
3954 ast.Node.Id.ControlFlowExpression => {
3955 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
3956
3957 if (flow_expr.rhs) |rhs| {
3958 try stack.append(RenderState { .Expression = rhs });
3959 try stack.append(RenderState { .Text = " " });
3960 }
3961
3962 switch (flow_expr.kind) {
3963 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
3964 try stream.print("break");
3965 if (maybe_label) |label| {
3966 try stream.print(" :");
3967 try stack.append(RenderState { .Expression = label });
3968 }
3969 },
3970 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
3971 try stream.print("continue");
3972 if (maybe_label) |label| {
3973 try stream.print(" :");
3974 try stack.append(RenderState { .Expression = label });
3975 }
3976 },
3977 ast.Node.ControlFlowExpression.Kind.Return => {
3978 try stream.print("return");
3979 },
3980
3981 }
3982 },
3983 ast.Node.Id.Payload => {
3984 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
3985 try stack.append(RenderState { .Text = "|"});
3986 try stack.append(RenderState { .Expression = payload.error_symbol });
3987 try stack.append(RenderState { .Text = "|"});
3988 },
3989 ast.Node.Id.PointerPayload => {
3990 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
3991 try stack.append(RenderState { .Text = "|"});
3992 try stack.append(RenderState { .Expression = payload.value_symbol });
3993
3994 if (payload.ptr_token) |ptr_token| {
3995 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
3996 }
3997
3998 try stack.append(RenderState { .Text = "|"});
3999 },
4000 ast.Node.Id.PointerIndexPayload => {
4001 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
4002 try stack.append(RenderState { .Text = "|"});
4003
4004 if (payload.index_symbol) |index_symbol| {
4005 try stack.append(RenderState { .Expression = index_symbol });
4006 try stack.append(RenderState { .Text = ", "});
4007 }
4008
4009 try stack.append(RenderState { .Expression = payload.value_symbol });
4010
4011 if (payload.ptr_token) |ptr_token| {
4012 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
4013 }
4014
4015 try stack.append(RenderState { .Text = "|"});
4016 },
4017 ast.Node.Id.GroupedExpression => {
4018 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
4019 try stack.append(RenderState { .Text = ")"});
4020 try stack.append(RenderState { .Expression = grouped_expr.expr });
4021 try stack.append(RenderState { .Text = "("});
4022 },
4023 ast.Node.Id.FieldInitializer => {
4024 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
4025 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
4026 try stack.append(RenderState { .Expression = field_init.expr });
4027 },
4028 ast.Node.Id.IntegerLiteral => {
4029 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
4030 try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
4031 },
4032 ast.Node.Id.FloatLiteral => {
4033 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
4034 try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
4035 },
4036 ast.Node.Id.StringLiteral => {
4037 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
4038 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
4039 },
4040 ast.Node.Id.CharLiteral => {
4041 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4042 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
4043 },
4044 ast.Node.Id.BoolLiteral => {
4045 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
4046 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
4047 },
4048 ast.Node.Id.NullLiteral => {
4049 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
4050 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
4051 },
4052 ast.Node.Id.ThisLiteral => {
4053 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
4054 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
4055 },
4056 ast.Node.Id.Unreachable => {
4057 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
4058 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
4059 },
4060 ast.Node.Id.ErrorType => {
4061 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
4062 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
4063 },
4064 ast.Node.Id.VarType => {
4065 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
4066 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
4067 },
4068 ast.Node.Id.ContainerDecl => {
4069 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
4070
4071 switch (container_decl.layout) {
4072 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
4073 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
4074 ast.Node.ContainerDecl.Layout.Auto => { },
4075 }
4076
4077 switch (container_decl.kind) {
4078 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
4079 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
4080 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
4081 }
4082
4083 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
4084 if (fields_and_decls.len == 0) {
4085 try stack.append(RenderState { .Text = "{}"});
4086 } else {
4087 try stack.append(RenderState { .Text = "}"});
4088 try stack.append(RenderState.PrintIndent);
4089 try stack.append(RenderState { .Indent = indent });
4090 try stack.append(RenderState { .Text = "\n"});
4091
4092 var i = fields_and_decls.len;
4093 while (i != 0) {
4094 i -= 1;
4095 const node = fields_and_decls[i];
4096 try stack.append(RenderState { .TopLevelDecl = node});
4097 try stack.append(RenderState.PrintIndent);
4098 try stack.append(RenderState {
4099 .Text = blk: {
4100 if (i != 0) {
4101 const prev_node = fields_and_decls[i - 1];
4102 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4103 if (loc.line >= 2) {
4104 break :blk "\n\n";
4105 }
4106 }
4107 break :blk "\n";
4108 },
4109 });
4110 }
4111 try stack.append(RenderState { .Indent = indent + indent_delta});
4112 try stack.append(RenderState { .Text = "{"});
4113 }
4114
4115 switch (container_decl.init_arg_expr) {
4116 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
4117 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
4118 if (enum_tag_type) |expr| {
4119 try stack.append(RenderState { .Text = ")) "});
4120 try stack.append(RenderState { .Expression = expr});
4121 try stack.append(RenderState { .Text = "(enum("});
4122 } else {
4123 try stack.append(RenderState { .Text = "(enum) "});
4124 }
4125 },
4126 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
4127 try stack.append(RenderState { .Text = ") "});
4128 try stack.append(RenderState { .Expression = type_expr});
4129 try stack.append(RenderState { .Text = "("});
4130 },
4131 }
4132 },
4133 ast.Node.Id.ErrorSetDecl => {
4134 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
4135
4136 const decls = err_set_decl.decls.toSliceConst();
4137 if (decls.len == 0) {
4138 try stream.write("error{}");
4139 continue;
4140 }
4141
4142 if (decls.len == 1) blk: {
4143 const node = decls[0];
4144
4145 // if there are any doc comments or same line comments
4146 // don't try to put it all on one line
4147 if (node.same_line_comment != null) break :blk;
4148 if (node.cast(ast.Node.ErrorTag)) |tag| {
4149 if (tag.doc_comments != null) break :blk;
4150 } else {
4151 break :blk;
4152 }
4153
4154
4155 try stream.write("error{");
4156 try stack.append(RenderState { .Text = "}" });
4157 try stack.append(RenderState { .TopLevelDecl = node });
4158 continue;
4159 }
4160
4161 try stream.write("error{");
4162
4163 try stack.append(RenderState { .Text = "}"});
4164 try stack.append(RenderState.PrintIndent);
4165 try stack.append(RenderState { .Indent = indent });
4166 try stack.append(RenderState { .Text = "\n"});
4167
4168 var i = decls.len;
4169 while (i != 0) {
4170 i -= 1;
4171 const node = decls[i];
4172 if (node.id != ast.Node.Id.LineComment) {
4173 try stack.append(RenderState { .Text = "," });
4174 }
4175 try stack.append(RenderState { .TopLevelDecl = node });
4176 try stack.append(RenderState.PrintIndent);
4177 try stack.append(RenderState {
4178 .Text = blk: {
4179 if (i != 0) {
4180 const prev_node = decls[i - 1];
4181 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4182 if (loc.line >= 2) {
4183 break :blk "\n\n";
4184 }
4185 }
4186 break :blk "\n";
4187 },
4188 });
4189 }
4190 try stack.append(RenderState { .Indent = indent + indent_delta});
4191 },
4192 ast.Node.Id.MultilineStringLiteral => {
4193 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
4194 try stream.print("\n");
4195
4196 var i : usize = 0;
4197 while (i < multiline_str_literal.tokens.len) : (i += 1) {
4198 const t = multiline_str_literal.tokens.at(i);
4199 try stream.writeByteNTimes(' ', indent + indent_delta);
4200 try stream.print("{}", self.tokenizer.getTokenSlice(t));
4201 }
4202 try stream.writeByteNTimes(' ', indent);
4203 },
4204 ast.Node.Id.UndefinedLiteral => {
4205 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
4206 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
4207 },
4208 ast.Node.Id.BuiltinCall => {
4209 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
4210 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
4211 try stack.append(RenderState { .Text = ")"});
4212 var i = builtin_call.params.len;
4213 while (i != 0) {
4214 i -= 1;
4215 const param_node = builtin_call.params.at(i);
4216 try stack.append(RenderState { .Expression = param_node});
4217 if (i != 0) {
4218 try stack.append(RenderState { .Text = ", " });
4219 }
4220 }
4221 },
4222 ast.Node.Id.FnProto => {
4223 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
4224
4225 switch (fn_proto.return_type) {
4226 ast.Node.FnProto.ReturnType.Explicit => |node| {
4227 try stack.append(RenderState { .Expression = node});
4228 },
4229 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
4230 try stack.append(RenderState { .Expression = node});
4231 try stack.append(RenderState { .Text = "!"});
4232 },
4233 }
4234
4235 if (fn_proto.align_expr) |align_expr| {
4236 try stack.append(RenderState { .Text = ") " });
4237 try stack.append(RenderState { .Expression = align_expr});
4238 try stack.append(RenderState { .Text = "align(" });
4239 }
4240
4241 try stack.append(RenderState { .Text = ") " });
4242 var i = fn_proto.params.len;
4243 while (i != 0) {
4244 i -= 1;
4245 const param_decl_node = fn_proto.params.items[i];
4246 try stack.append(RenderState { .ParamDecl = param_decl_node});
4247 if (i != 0) {
4248 try stack.append(RenderState { .Text = ", " });
4249 }
4250 }
4251
4252 try stack.append(RenderState { .Text = "(" });
4253 if (fn_proto.name_token) |name_token| {
4254 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
4255 try stack.append(RenderState { .Text = " " });
4256 }
4257
4258 try stack.append(RenderState { .Text = "fn" });
4259
4260 if (fn_proto.async_attr) |async_attr| {
4261 try stack.append(RenderState { .Text = " " });
4262 try stack.append(RenderState { .Expression = &async_attr.base });
4263 }
4264
4265 if (fn_proto.cc_token) |cc_token| {
4266 try stack.append(RenderState { .Text = " " });
4267 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
4268 }
4269
4270 if (fn_proto.lib_name) |lib_name| {
4271 try stack.append(RenderState { .Text = " " });
4272 try stack.append(RenderState { .Expression = lib_name });
4273 }
4274 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
4275 try stack.append(RenderState { .Text = " " });
4276 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
4277 }
4278
4279 if (fn_proto.visib_token) |visib_token| {
4280 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
4281 try stack.append(RenderState { .Text = " " });
4282 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
4283 }
4284 },
4285 ast.Node.Id.PromiseType => {
4286 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
4287 try stream.write(self.tokenizer.getTokenSlice(promise_type.promise_token));
4288 if (promise_type.result) |result| {
4289 try stream.write(self.tokenizer.getTokenSlice(result.arrow_token));
4290 try stack.append(RenderState { .Expression = result.return_type});
4291 }
4292 },
4293 ast.Node.Id.LineComment => {
4294 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
4295 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
4296 },
4297 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
4298 ast.Node.Id.Switch => {
4299 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
4300 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
4301
4302 try stack.append(RenderState { .Text = "}"});
4303 try stack.append(RenderState.PrintIndent);
4304 try stack.append(RenderState { .Indent = indent });
4305 try stack.append(RenderState { .Text = "\n"});
4306
4307 const cases = switch_node.cases.toSliceConst();
4308 var i = cases.len;
4309 while (i != 0) {
4310 i -= 1;
4311 const node = cases[i];
4312 try stack.append(RenderState { .Expression = node});
4313 try stack.append(RenderState.PrintIndent);
4314 try stack.append(RenderState {
4315 .Text = blk: {
4316 if (i != 0) {
4317 const prev_node = cases[i - 1];
4318 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4319 if (loc.line >= 2) {
4320 break :blk "\n\n";
4321 }
4322 }
4323 break :blk "\n";
4324 },
4325 });
4326 }
4327 try stack.append(RenderState { .Indent = indent + indent_delta});
4328 try stack.append(RenderState { .Text = ") {"});
4329 try stack.append(RenderState { .Expression = switch_node.expr });
4330 },
4331 ast.Node.Id.SwitchCase => {
4332 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
4333
4334 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment });
4335 try stack.append(RenderState { .Text = "," });
4336 try stack.append(RenderState { .Expression = switch_case.expr });
4337 if (switch_case.payload) |payload| {
4338 try stack.append(RenderState { .Text = " " });
4339 try stack.append(RenderState { .Expression = payload });
4340 }
4341 try stack.append(RenderState { .Text = " => "});
4342
4343 const items = switch_case.items.toSliceConst();
4344 var i = items.len;
4345 while (i != 0) {
4346 i -= 1;
4347 try stack.append(RenderState { .Expression = items[i] });
4348
4349 if (i != 0) {
4350 try stack.append(RenderState.PrintIndent);
4351 try stack.append(RenderState { .Text = ",\n" });
4352 }
4353 }
4354 },
4355 ast.Node.Id.SwitchElse => {
4356 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
4357 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
4358 },
4359 ast.Node.Id.Else => {
4360 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
4361 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
4362
4363 switch (else_node.body.id) {
4364 ast.Node.Id.Block, ast.Node.Id.If,
4365 ast.Node.Id.For, ast.Node.Id.While,
4366 ast.Node.Id.Switch => {
4367 try stream.print(" ");
4368 try stack.append(RenderState { .Expression = else_node.body });
4369 },
4370 else => {
4371 try stack.append(RenderState { .Indent = indent });
4372 try stack.append(RenderState { .Expression = else_node.body });
4373 try stack.append(RenderState.PrintIndent);
4374 try stack.append(RenderState { .Indent = indent + indent_delta });
4375 try stack.append(RenderState { .Text = "\n" });
4376 }
4377 }
4378
4379 if (else_node.payload) |payload| {
4380 try stack.append(RenderState { .Text = " " });
4381 try stack.append(RenderState { .Expression = payload });
4382 }
4383 },
4384 ast.Node.Id.While => {
4385 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
4386 if (while_node.label) |label| {
4387 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4388 }
4389
4390 if (while_node.inline_token) |inline_token| {
4391 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4392 }
4393
4394 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
4395
4396 if (while_node.@"else") |@"else"| {
4397 try stack.append(RenderState { .Expression = &@"else".base });
4398
4399 if (while_node.body.id == ast.Node.Id.Block) {
4400 try stack.append(RenderState { .Text = " " });
4401 } else {
4402 try stack.append(RenderState.PrintIndent);
4403 try stack.append(RenderState { .Text = "\n" });
4404 }
4405 }
4406
4407 if (while_node.body.id == ast.Node.Id.Block) {
4408 try stack.append(RenderState { .Expression = while_node.body });
4409 try stack.append(RenderState { .Text = " " });
4410 } else {
4411 try stack.append(RenderState { .Indent = indent });
4412 try stack.append(RenderState { .Expression = while_node.body });
4413 try stack.append(RenderState.PrintIndent);
4414 try stack.append(RenderState { .Indent = indent + indent_delta });
4415 try stack.append(RenderState { .Text = "\n" });
4416 }
4417
4418 if (while_node.continue_expr) |continue_expr| {
4419 try stack.append(RenderState { .Text = ")" });
4420 try stack.append(RenderState { .Expression = continue_expr });
4421 try stack.append(RenderState { .Text = ": (" });
4422 try stack.append(RenderState { .Text = " " });
4423 }
4424
4425 if (while_node.payload) |payload| {
4426 try stack.append(RenderState { .Expression = payload });
4427 try stack.append(RenderState { .Text = " " });
4428 }
4429
4430 try stack.append(RenderState { .Text = ")" });
4431 try stack.append(RenderState { .Expression = while_node.condition });
4432 try stack.append(RenderState { .Text = "(" });
4433 },
4434 ast.Node.Id.For => {
4435 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
4436 if (for_node.label) |label| {
4437 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4438 }
4439
4440 if (for_node.inline_token) |inline_token| {
4441 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4442 }
4443
4444 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
4445
4446 if (for_node.@"else") |@"else"| {
4447 try stack.append(RenderState { .Expression = &@"else".base });
4448
4449 if (for_node.body.id == ast.Node.Id.Block) {
4450 try stack.append(RenderState { .Text = " " });
4451 } else {
4452 try stack.append(RenderState.PrintIndent);
4453 try stack.append(RenderState { .Text = "\n" });
4454 }
4455 }
4456
4457 if (for_node.body.id == ast.Node.Id.Block) {
4458 try stack.append(RenderState { .Expression = for_node.body });
4459 try stack.append(RenderState { .Text = " " });
4460 } else {
4461 try stack.append(RenderState { .Indent = indent });
4462 try stack.append(RenderState { .Expression = for_node.body });
4463 try stack.append(RenderState.PrintIndent);
4464 try stack.append(RenderState { .Indent = indent + indent_delta });
4465 try stack.append(RenderState { .Text = "\n" });
4466 }
4467
4468 if (for_node.payload) |payload| {
4469 try stack.append(RenderState { .Expression = payload });
4470 try stack.append(RenderState { .Text = " " });
4471 }
4472
4473 try stack.append(RenderState { .Text = ")" });
4474 try stack.append(RenderState { .Expression = for_node.array_expr });
4475 try stack.append(RenderState { .Text = "(" });
4476 },
4477 ast.Node.Id.If => {
4478 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
4479 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
4480
4481 switch (if_node.body.id) {
4482 ast.Node.Id.Block, ast.Node.Id.If,
4483 ast.Node.Id.For, ast.Node.Id.While,
4484 ast.Node.Id.Switch => {
4485 if (if_node.@"else") |@"else"| {
4486 try stack.append(RenderState { .Expression = &@"else".base });
4487
4488 if (if_node.body.id == ast.Node.Id.Block) {
4489 try stack.append(RenderState { .Text = " " });
4490 } else {
4491 try stack.append(RenderState.PrintIndent);
4492 try stack.append(RenderState { .Text = "\n" });
4493 }
4494 }
4495 },
4496 else => {
4497 if (if_node.@"else") |@"else"| {
4498 try stack.append(RenderState { .Expression = @"else".body });
4499
4500 if (@"else".payload) |payload| {
4501 try stack.append(RenderState { .Text = " " });
4502 try stack.append(RenderState { .Expression = payload });
4503 }
4504
4505 try stack.append(RenderState { .Text = " " });
4506 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
4507 try stack.append(RenderState { .Text = " " });
4508 }
4509 }
4510 }
4511
4512 try stack.append(RenderState { .Expression = if_node.body });
4513 try stack.append(RenderState { .Text = " " });
4514
4515 if (if_node.payload) |payload| {
4516 try stack.append(RenderState { .Expression = payload });
4517 try stack.append(RenderState { .Text = " " });
4518 }
4519
4520 try stack.append(RenderState { .Text = ")" });
4521 try stack.append(RenderState { .Expression = if_node.condition });
4522 try stack.append(RenderState { .Text = "(" });
4523 },
4524 ast.Node.Id.Asm => {
4525 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
4526 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4527
4528 if (asm_node.volatile_token) |volatile_token| {
4529 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
4530 }
4531
4532 try stack.append(RenderState { .Indent = indent });
4533 try stack.append(RenderState { .Text = ")" });
4534 {
4535 const cloppers = asm_node.cloppers.toSliceConst();
4536 var i = cloppers.len;
4537 while (i != 0) {
4538 i -= 1;
4539 try stack.append(RenderState { .Expression = cloppers[i] });
4540
4541 if (i != 0) {
4542 try stack.append(RenderState { .Text = ", " });
4543 }
4544 }
4545 }
4546 try stack.append(RenderState { .Text = ": " });
4547 try stack.append(RenderState.PrintIndent);
4548 try stack.append(RenderState { .Indent = indent + indent_delta });
4549 try stack.append(RenderState { .Text = "\n" });
4550 {
4551 const inputs = asm_node.inputs.toSliceConst();
4552 var i = inputs.len;
4553 while (i != 0) {
4554 i -= 1;
4555 const node = inputs[i];
4556 try stack.append(RenderState { .Expression = &node.base});
4557
4558 if (i != 0) {
4559 try stack.append(RenderState.PrintIndent);
4560 try stack.append(RenderState {
4561 .Text = blk: {
4562 const prev_node = inputs[i - 1];
4563 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4564 if (loc.line >= 2) {
4565 break :blk "\n\n";
4566 }
4567 break :blk "\n";
4568 },
4569 });
4570 try stack.append(RenderState { .Text = "," });
4571 }
4572 }
4573 }
4574 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4575 try stack.append(RenderState { .Text = ": "});
4576 try stack.append(RenderState.PrintIndent);
4577 try stack.append(RenderState { .Indent = indent + indent_delta});
4578 try stack.append(RenderState { .Text = "\n" });
4579 {
4580 const outputs = asm_node.outputs.toSliceConst();
4581 var i = outputs.len;
4582 while (i != 0) {
4583 i -= 1;
4584 const node = outputs[i];
4585 try stack.append(RenderState { .Expression = &node.base});
4586
4587 if (i != 0) {
4588 try stack.append(RenderState.PrintIndent);
4589 try stack.append(RenderState {
4590 .Text = blk: {
4591 const prev_node = outputs[i - 1];
4592 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4593 if (loc.line >= 2) {
4594 break :blk "\n\n";
4595 }
4596 break :blk "\n";
4597 },
4598 });
4599 try stack.append(RenderState { .Text = "," });
4600 }
4601 }
4602 }
4603 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4604 try stack.append(RenderState { .Text = ": "});
4605 try stack.append(RenderState.PrintIndent);
4606 try stack.append(RenderState { .Indent = indent + indent_delta});
4607 try stack.append(RenderState { .Text = "\n" });
4608 try stack.append(RenderState { .Expression = asm_node.template });
4609 try stack.append(RenderState { .Text = "(" });
4610 },
4611 ast.Node.Id.AsmInput => {
4612 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
4613
4614 try stack.append(RenderState { .Text = ")"});
4615 try stack.append(RenderState { .Expression = asm_input.expr});
4616 try stack.append(RenderState { .Text = " ("});
4617 try stack.append(RenderState { .Expression = asm_input.constraint });
4618 try stack.append(RenderState { .Text = "] "});
4619 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
4620 try stack.append(RenderState { .Text = "["});
4621 },
4622 ast.Node.Id.AsmOutput => {
4623 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
4624
4625 try stack.append(RenderState { .Text = ")"});
4626 switch (asm_output.kind) {
4627 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
4628 try stack.append(RenderState { .Expression = &variable_name.base});
4629 },
4630 ast.Node.AsmOutput.Kind.Return => |return_type| {
4631 try stack.append(RenderState { .Expression = return_type});
4632 try stack.append(RenderState { .Text = "-> "});
4633 },
4634 }
4635 try stack.append(RenderState { .Text = " ("});
4636 try stack.append(RenderState { .Expression = asm_output.constraint });
4637 try stack.append(RenderState { .Text = "] "});
4638 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
4639 try stack.append(RenderState { .Text = "["});
4640 },
4641
4642 ast.Node.Id.StructField,
4643 ast.Node.Id.UnionTag,
4644 ast.Node.Id.EnumTag,
4645 ast.Node.Id.ErrorTag,
4646 ast.Node.Id.Root,
4647 ast.Node.Id.VarDecl,
4648 ast.Node.Id.Use,
4649 ast.Node.Id.TestDecl,
4650 ast.Node.Id.ParamDecl => unreachable,
4651 },
4652 RenderState.Statement => |base| {
4653 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment } );
4654 switch (base.id) {
4655 ast.Node.Id.VarDecl => {
4656 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
4657 try stack.append(RenderState { .VarDecl = var_decl});
4658 },
4659 else => {
4660 if (requireSemiColon(base)) {
4661 try stack.append(RenderState { .Text = ";" });
4662 }
4663 try stack.append(RenderState { .Expression = base });
4664 },
4665 }
4666 },
4667 RenderState.Indent => |new_indent| indent = new_indent,
4668 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
4669 RenderState.PrintSameLineComment => |maybe_comment| blk: {
4670 const comment_token = maybe_comment ?? break :blk;
4671 try stream.print(" {}", self.tokenizer.getTokenSlice(comment_token));
4672 },
4673 }
4674 }
4675 }
4676
4677 fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
4678 const comment = node.doc_comments ?? return;
4679 for (comment.lines.toSliceConst()) |line_token| {
4680 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4681 try stream.writeByteNTimes(' ', indent);
4682 }
4683 }
4684
4685 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
4686 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
4687 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
4688 const typed_slice = ([]T)(self.utility_bytes);
4689 return ArrayList(T) {
4690 .allocator = self.util_allocator,
4691 .items = typed_slice,
4692 .len = 0,
4693 };
4694 }
4695
4696 fn deinitUtilityArrayList(self: &Parser, list: var) void {
4697 self.utility_bytes = ([]align(utility_bytes_align) u8)(list.items);
4698 }
4699
4700};
4701
4702test "std.zig.parser" {
4703 _ = @import("parser_test.zig");
4704}
std/zig/parser_test.zig+112-76
...@@ -1,29 +1,82 @@...@@ -1,29 +1,82 @@
1// TODO1test "zig fmt: same-line comment after a statement" {
2//if (sr > n_uword_bits - 1) // d > r2 try testCanonical(
3// return 0;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}
420
5// TODO switch with no body21test "zig fmt: same-line comment after field decl" {
6// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};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}
733
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}
845
9//TODO46test "zig fmt: same-line comment after non-block if expression" {
10//test "zig fmt: same-line comptime" {47 try testCanonical(
11// try testCanonical(48 \\comptime {
12// \\test "" {49 \\ if (sr > n_uword_bits - 1) // d > r
13// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt50 \\ return 0;
14// \\}51 \\}
15// \\52 \\
16// );53 );
17//}54}
1855
56test "zig fmt: same-line comment on comptime expression" {
57 try testCanonical(
58 \\test "" {
59 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
60 \\}
61 \\
62 );
63}
1964
20//TODO65test "zig fmt: switch with empty body" {
21//test "zig fmt: number literals" {66 try testCanonical(
22// try testCanonical(67 \\test "" {
23// \\pub const f64_true_min = 4.94065645841246544177e-324;68 \\ foo() catch |err| switch (err) {};
24// \\69 \\}
25// );70 \\
26//}71 );
72}
73
74test "zig fmt: float literal with exponent" {
75 try testCanonical(
76 \\pub const f64_true_min = 4.94065645841246544177e-324;
77 \\
78 );
79}
2780
28test "zig fmt: line comments in struct initializer" {81test "zig fmt: line comments in struct initializer" {
29 try testCanonical(82 try testCanonical(
...@@ -144,18 +197,6 @@ test "zig fmt: comments before switch prong" {...@@ -144,18 +197,6 @@ test "zig fmt: comments before switch prong" {
144 );197 );
145}198}
146199
147test "zig fmt: same-line comment after switch prong" {
148 try testCanonical(
149 \\test "" {
150 \\ switch (err) {
151 \\ error.PathAlreadyExists => {}, // comment 2
152 \\ else => return err, // comment 1
153 \\ }
154 \\}
155 \\
156 );
157}
158
159test "zig fmt: comments before var decl in struct" {200test "zig fmt: comments before var decl in struct" {
160 try testCanonical(201 try testCanonical(
161 \\pub const vfs_cap_data = extern struct {202 \\pub const vfs_cap_data = extern struct {
...@@ -181,28 +222,6 @@ test "zig fmt: comments before var decl in struct" {...@@ -181,28 +222,6 @@ test "zig fmt: comments before var decl in struct" {
181 );222 );
182}223}
183224
184test "zig fmt: same-line comment after var decl in struct" {
185 try testCanonical(
186 \\pub const vfs_cap_data = extern struct {
187 \\ const Data = struct {}; // when on disk.
188 \\};
189 \\
190 );
191}
192
193test "zig fmt: same-line comment after field decl" {
194 try testCanonical(
195 \\pub const dirent = extern struct {
196 \\ d_name: u8,
197 \\ d_name: u8, // comment 1
198 \\ d_name: u8,
199 \\ d_name: u8, // comment 2
200 \\ d_name: u8,
201 \\};
202 \\
203 );
204}
205
206test "zig fmt: array literal with 1 item on 1 line" {225test "zig fmt: array literal with 1 item on 1 line" {
207 try testCanonical(226 try testCanonical(
208 \\var s = []const u64{0} ** 25;227 \\var s = []const u64{0} ** 25;
...@@ -210,17 +229,6 @@ test "zig fmt: array literal with 1 item on 1 line" {...@@ -210,17 +229,6 @@ test "zig fmt: array literal with 1 item on 1 line" {
210 );229 );
211}230}
212231
213test "zig fmt: same-line comment after a statement" {
214 try testCanonical(
215 \\test "" {
216 \\ a = b;
217 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
218 \\ a = b;
219 \\}
220 \\
221 );
222}
223
224test "zig fmt: comments before global variables" {232test "zig fmt: comments before global variables" {
225 try testCanonical(233 try testCanonical(
226 \\/// Foo copies keys and values before they go into the map, and234 \\/// Foo copies keys and values before they go into the map, and
...@@ -1084,37 +1092,60 @@ test "zig fmt: error return" {...@@ -1084,37 +1092,60 @@ test "zig fmt: error return" {
1084const std = @import("std");1092const std = @import("std");
1085const mem = std.mem;1093const mem = std.mem;
1086const warn = std.debug.warn;1094const warn = std.debug.warn;
1087const Tokenizer = std.zig.Tokenizer;
1088const Parser = std.zig.Parser;
1089const io = std.io;1095const io = std.io;
10901096
1091var fixed_buffer_mem: [100 * 1024]u8 = undefined;1097var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10921098
1093fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {1099fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1094 var tokenizer = Tokenizer.init(source);1100 var stderr_file = try io.getStdErr();
1095 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");1101 var stderr = &io.FileOutStream.init(&stderr_file).stream;
1096 defer parser.deinit();
10971102
1098 var tree = try parser.parse();1103 var tree = try std.zig.parse(allocator, source);
1099 defer tree.deinit();1104 defer tree.deinit();
11001105
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
1101 var buffer = try std.Buffer.initSize(allocator, 0);1132 var buffer = try std.Buffer.initSize(allocator, 0);
1102 errdefer buffer.deinit();1133 errdefer buffer.deinit();
11031134
1104 var buffer_out_stream = io.BufferOutStream.init(&buffer);1135 var buffer_out_stream = io.BufferOutStream.init(&buffer);
1105 try parser.renderSource(&buffer_out_stream.stream, tree.root_node);1136 try std.zig.render(allocator, &buffer_out_stream.stream, &tree);
1106 return buffer.toOwnedSlice();1137 return buffer.toOwnedSlice();
1107}1138}
11081139
1109fn testCanonical(source: []const u8) !void {1140fn testTransform(source: []const u8, expected_source: []const u8) !void {
1110 const needed_alloc_count = x: {1141 const needed_alloc_count = x: {
1111 // Try it once with unlimited memory, make sure it works1142 // Try it once with unlimited memory, make sure it works
1112 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1143 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1113 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));1144 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
1114 const result_source = try testParse(source, &failing_allocator.allocator);1145 const result_source = try testParse(source, &failing_allocator.allocator);
1115 if (!mem.eql(u8, result_source, source)) {1146 if (!mem.eql(u8, result_source, expected_source)) {
1116 warn("\n====== expected this output: =========\n");1147 warn("\n====== expected this output: =========\n");
1117 warn("{}", source);1148 warn("{}", expected_source);
1118 warn("\n======== instead found this: =========\n");1149 warn("\n======== instead found this: =========\n");
1119 warn("{}", result_source);1150 warn("{}", result_source);
1120 warn("\n======================================\n");1151 warn("\n======================================\n");
...@@ -1141,7 +1172,12 @@ fn testCanonical(source: []const u8) !void {...@@ -1141,7 +1172,12 @@ fn testCanonical(source: []const u8) !void {
1141 }1172 }
1142 },1173 },
1143 error.ParseError => @panic("test failed"),1174 error.ParseError => @panic("test failed"),
1175 else => @panic("test failed"),
1144 }1176 }
1145 }1177 }
1146}1178}
11471179
1180fn testCanonical(source: []const u8) !void {
1181 return testTransform(source, source);
1182}
1183
std/zig/render.zig created+1270
...@@ -0,0 +1,1270 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Token = std.zig.Token;
6
7const RenderState = union(enum) {
8 TopLevelDecl: &ast.Node,
9 ParamDecl: &ast.Node,
10 Text: []const u8,
11 Expression: &ast.Node,
12 VarDecl: &ast.Node.VarDecl,
13 Statement: &ast.Node,
14 PrintIndent,
15 Indent: usize,
16 MaybeSemiColon: &ast.Node,
17 Token: ast.TokenIndex,
18 NonBreakToken: ast.TokenIndex,
19};
20
21const indent_delta = 4;
22
23pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {
24 var stack = std.ArrayList(RenderState).init(allocator);
25 defer stack.deinit();
26
27 {
28 try stack.append(RenderState { .Text = "\n"});
29
30 var i = tree.root_node.decls.len;
31 while (i != 0) {
32 i -= 1;
33 const decl = *tree.root_node.decls.at(i);
34 try stack.append(RenderState {.TopLevelDecl = decl});
35 if (i != 0) {
36 try stack.append(RenderState {
37 .Text = blk: {
38 const prev_node = *tree.root_node.decls.at(i - 1);
39 const prev_node_last_token = tree.tokens.at(prev_node.lastToken());
40 const loc = tree.tokenLocation(prev_node_last_token.end, decl.firstToken());
41 if (loc.line >= 2) {
42 break :blk "\n\n";
43 }
44 break :blk "\n";
45 },
46 });
47 }
48 }
49 }
50
51 var indent: usize = 0;
52 while (stack.popOrNull()) |state| {
53 switch (state) {
54 RenderState.TopLevelDecl => |decl| {
55 switch (decl.id) {
56 ast.Node.Id.FnProto => {
57 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
58 try renderComments(tree, stream, fn_proto, indent);
59
60 if (fn_proto.body_node) |body_node| {
61 stack.append(RenderState { .Expression = body_node}) catch unreachable;
62 try stack.append(RenderState { .Text = " "});
63 } else {
64 stack.append(RenderState { .Text = ";" }) catch unreachable;
65 }
66
67 try stack.append(RenderState { .Expression = decl });
68 },
69 ast.Node.Id.Use => {
70 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
71 if (use_decl.visib_token) |visib_token| {
72 try stream.print("{} ", tree.tokenSlice(visib_token));
73 }
74 try stream.print("use ");
75 try stack.append(RenderState { .Text = ";" });
76 try stack.append(RenderState { .Expression = use_decl.expr });
77 },
78 ast.Node.Id.VarDecl => {
79 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
80 try renderComments(tree, stream, var_decl, indent);
81 try stack.append(RenderState { .VarDecl = var_decl});
82 },
83 ast.Node.Id.TestDecl => {
84 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
85 try renderComments(tree, stream, test_decl, indent);
86 try stream.print("test ");
87 try stack.append(RenderState { .Expression = test_decl.body_node });
88 try stack.append(RenderState { .Text = " " });
89 try stack.append(RenderState { .Expression = test_decl.name });
90 },
91 ast.Node.Id.StructField => {
92 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
93 try renderComments(tree, stream, field, indent);
94 if (field.visib_token) |visib_token| {
95 try stream.print("{} ", tree.tokenSlice(visib_token));
96 }
97 try stream.print("{}: ", tree.tokenSlice(field.name_token));
98 try stack.append(RenderState { .Token = field.lastToken() + 1 });
99 try stack.append(RenderState { .Expression = field.type_expr});
100 },
101 ast.Node.Id.UnionTag => {
102 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
103 try renderComments(tree, stream, tag, indent);
104 try stream.print("{}", tree.tokenSlice(tag.name_token));
105
106 try stack.append(RenderState { .Text = "," });
107
108 if (tag.value_expr) |value_expr| {
109 try stack.append(RenderState { .Expression = value_expr });
110 try stack.append(RenderState { .Text = " = " });
111 }
112
113 if (tag.type_expr) |type_expr| {
114 try stream.print(": ");
115 try stack.append(RenderState { .Expression = type_expr});
116 }
117 },
118 ast.Node.Id.EnumTag => {
119 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
120 try renderComments(tree, stream, tag, indent);
121 try stream.print("{}", tree.tokenSlice(tag.name_token));
122
123 try stack.append(RenderState { .Text = "," });
124 if (tag.value) |value| {
125 try stream.print(" = ");
126 try stack.append(RenderState { .Expression = value});
127 }
128 },
129 ast.Node.Id.ErrorTag => {
130 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
131 try renderComments(tree, stream, tag, indent);
132 try stream.print("{}", tree.tokenSlice(tag.name_token));
133 },
134 ast.Node.Id.Comptime => {
135 try stack.append(RenderState { .MaybeSemiColon = decl });
136 try stack.append(RenderState { .Expression = decl });
137 },
138 ast.Node.Id.LineComment => {
139 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
140 try stream.write(tree.tokenSlice(line_comment_node.token));
141 },
142 else => unreachable,
143 }
144 },
145
146 RenderState.VarDecl => |var_decl| {
147 try stack.append(RenderState { .Token = var_decl.semicolon_token });
148 if (var_decl.init_node) |init_node| {
149 try stack.append(RenderState { .Expression = init_node });
150 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
151 try stack.append(RenderState { .Text = text });
152 }
153 if (var_decl.align_node) |align_node| {
154 try stack.append(RenderState { .Text = ")" });
155 try stack.append(RenderState { .Expression = align_node });
156 try stack.append(RenderState { .Text = " align(" });
157 }
158 if (var_decl.type_node) |type_node| {
159 try stack.append(RenderState { .Expression = type_node });
160 try stack.append(RenderState { .Text = ": " });
161 }
162 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
163 try stack.append(RenderState { .Text = " " });
164 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
165
166 if (var_decl.comptime_token) |comptime_token| {
167 try stack.append(RenderState { .Text = " " });
168 try stack.append(RenderState { .Text = tree.tokenSlice(comptime_token) });
169 }
170
171 if (var_decl.extern_export_token) |extern_export_token| {
172 if (var_decl.lib_name != null) {
173 try stack.append(RenderState { .Text = " " });
174 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
175 }
176 try stack.append(RenderState { .Text = " " });
177 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_token) });
178 }
179
180 if (var_decl.visib_token) |visib_token| {
181 try stack.append(RenderState { .Text = " " });
182 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token) });
183 }
184 },
185
186 RenderState.ParamDecl => |base| {
187 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
188 if (param_decl.comptime_token) |comptime_token| {
189 try stream.print("{} ", tree.tokenSlice(comptime_token));
190 }
191 if (param_decl.noalias_token) |noalias_token| {
192 try stream.print("{} ", tree.tokenSlice(noalias_token));
193 }
194 if (param_decl.name_token) |name_token| {
195 try stream.print("{}: ", tree.tokenSlice(name_token));
196 }
197 if (param_decl.var_args_token) |var_args_token| {
198 try stream.print("{}", tree.tokenSlice(var_args_token));
199 } else {
200 try stack.append(RenderState { .Expression = param_decl.type_node});
201 }
202 },
203 RenderState.Text => |bytes| {
204 try stream.write(bytes);
205 },
206 RenderState.Expression => |base| switch (base.id) {
207 ast.Node.Id.Identifier => {
208 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
209 try stream.print("{}", tree.tokenSlice(identifier.token));
210 },
211 ast.Node.Id.Block => {
212 const block = @fieldParentPtr(ast.Node.Block, "base", base);
213 if (block.label) |label| {
214 try stream.print("{}: ", tree.tokenSlice(label));
215 }
216
217 if (block.statements.len == 0) {
218 try stream.write("{}");
219 } else {
220 try stream.write("{");
221 try stack.append(RenderState { .Text = "}"});
222 try stack.append(RenderState.PrintIndent);
223 try stack.append(RenderState { .Indent = indent});
224 try stack.append(RenderState { .Text = "\n"});
225 var i = block.statements.len;
226 while (i != 0) {
227 i -= 1;
228 const statement_node = *block.statements.at(i);
229 try stack.append(RenderState { .Statement = statement_node});
230 try stack.append(RenderState.PrintIndent);
231 try stack.append(RenderState { .Indent = indent + indent_delta});
232 try stack.append(RenderState {
233 .Text = blk: {
234 if (i != 0) {
235 const prev_node = *block.statements.at(i - 1);
236 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
237 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());
238 if (loc.line >= 2) {
239 break :blk "\n\n";
240 }
241 }
242 break :blk "\n";
243 },
244 });
245 }
246 }
247 },
248 ast.Node.Id.Defer => {
249 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
250 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
251 try stack.append(RenderState { .Expression = defer_node.expr });
252 },
253 ast.Node.Id.Comptime => {
254 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
255 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
256 try stack.append(RenderState { .Expression = comptime_node.expr });
257 },
258 ast.Node.Id.AsyncAttribute => {
259 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
260 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
261
262 if (async_attr.allocator_type) |allocator_type| {
263 try stack.append(RenderState { .Text = ">" });
264 try stack.append(RenderState { .Expression = allocator_type });
265 try stack.append(RenderState { .Text = "<" });
266 }
267 },
268 ast.Node.Id.Suspend => {
269 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
270 if (suspend_node.label) |label| {
271 try stream.print("{}: ", tree.tokenSlice(label));
272 }
273 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
274
275 if (suspend_node.body) |body| {
276 try stack.append(RenderState { .Expression = body });
277 try stack.append(RenderState { .Text = " " });
278 }
279
280 if (suspend_node.payload) |payload| {
281 try stack.append(RenderState { .Expression = payload });
282 try stack.append(RenderState { .Text = " " });
283 }
284 },
285 ast.Node.Id.InfixOp => {
286 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
287 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
288
289 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
290 if (prefix_op_node.op.Catch) |payload| {
291 try stack.append(RenderState { .Text = " " });
292 try stack.append(RenderState { .Expression = payload });
293 }
294 try stack.append(RenderState { .Text = " catch " });
295 } else {
296 const text = switch (prefix_op_node.op) {
297 ast.Node.InfixOp.Op.Add => " + ",
298 ast.Node.InfixOp.Op.AddWrap => " +% ",
299 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
300 ast.Node.InfixOp.Op.ArrayMult => " ** ",
301 ast.Node.InfixOp.Op.Assign => " = ",
302 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
303 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
304 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
305 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
306 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
307 ast.Node.InfixOp.Op.AssignDiv => " /= ",
308 ast.Node.InfixOp.Op.AssignMinus => " -= ",
309 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
310 ast.Node.InfixOp.Op.AssignMod => " %= ",
311 ast.Node.InfixOp.Op.AssignPlus => " += ",
312 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
313 ast.Node.InfixOp.Op.AssignTimes => " *= ",
314 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
315 ast.Node.InfixOp.Op.BangEqual => " != ",
316 ast.Node.InfixOp.Op.BitAnd => " & ",
317 ast.Node.InfixOp.Op.BitOr => " | ",
318 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
319 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
320 ast.Node.InfixOp.Op.BitXor => " ^ ",
321 ast.Node.InfixOp.Op.BoolAnd => " and ",
322 ast.Node.InfixOp.Op.BoolOr => " or ",
323 ast.Node.InfixOp.Op.Div => " / ",
324 ast.Node.InfixOp.Op.EqualEqual => " == ",
325 ast.Node.InfixOp.Op.ErrorUnion => "!",
326 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
327 ast.Node.InfixOp.Op.GreaterThan => " > ",
328 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
329 ast.Node.InfixOp.Op.LessThan => " < ",
330 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
331 ast.Node.InfixOp.Op.Mod => " % ",
332 ast.Node.InfixOp.Op.Mult => " * ",
333 ast.Node.InfixOp.Op.MultWrap => " *% ",
334 ast.Node.InfixOp.Op.Period => ".",
335 ast.Node.InfixOp.Op.Sub => " - ",
336 ast.Node.InfixOp.Op.SubWrap => " -% ",
337 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
338 ast.Node.InfixOp.Op.Range => " ... ",
339 ast.Node.InfixOp.Op.Catch => unreachable,
340 };
341
342 try stack.append(RenderState { .Text = text });
343 }
344 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
345 },
346 ast.Node.Id.PrefixOp => {
347 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
348 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
349 switch (prefix_op_node.op) {
350 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
351 try stream.write("&");
352 if (addr_of_info.volatile_token != null) {
353 try stack.append(RenderState { .Text = "volatile "});
354 }
355 if (addr_of_info.const_token != null) {
356 try stack.append(RenderState { .Text = "const "});
357 }
358 if (addr_of_info.align_expr) |align_expr| {
359 try stream.print("align(");
360 try stack.append(RenderState { .Text = ") "});
361 try stack.append(RenderState { .Expression = align_expr});
362 }
363 },
364 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
365 try stream.write("[]");
366 if (addr_of_info.volatile_token != null) {
367 try stack.append(RenderState { .Text = "volatile "});
368 }
369 if (addr_of_info.const_token != null) {
370 try stack.append(RenderState { .Text = "const "});
371 }
372 if (addr_of_info.align_expr) |align_expr| {
373 try stream.print("align(");
374 try stack.append(RenderState { .Text = ") "});
375 try stack.append(RenderState { .Expression = align_expr});
376 }
377 },
378 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
379 try stack.append(RenderState { .Text = "]"});
380 try stack.append(RenderState { .Expression = array_index});
381 try stack.append(RenderState { .Text = "["});
382 },
383 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
384 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
385 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
386 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
387 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
388 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
389 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
390 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
391 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
392 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
393 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
394 }
395 },
396 ast.Node.Id.SuffixOp => {
397 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
398
399 switch (suffix_op.op) {
400 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
401 try stack.append(RenderState { .Text = ")"});
402 var i = call_info.params.len;
403 while (i != 0) {
404 i -= 1;
405 const param_node = *call_info.params.at(i);
406 try stack.append(RenderState { .Expression = param_node});
407 if (i != 0) {
408 try stack.append(RenderState { .Text = ", " });
409 }
410 }
411 try stack.append(RenderState { .Text = "("});
412 try stack.append(RenderState { .Expression = suffix_op.lhs });
413
414 if (call_info.async_attr) |async_attr| {
415 try stack.append(RenderState { .Text = " "});
416 try stack.append(RenderState { .Expression = &async_attr.base });
417 }
418 },
419 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
420 try stack.append(RenderState { .Text = "]"});
421 try stack.append(RenderState { .Expression = index_expr});
422 try stack.append(RenderState { .Text = "["});
423 try stack.append(RenderState { .Expression = suffix_op.lhs });
424 },
425 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
426 try stack.append(RenderState { .Text = "]"});
427 if (range.end) |end| {
428 try stack.append(RenderState { .Expression = end});
429 }
430 try stack.append(RenderState { .Text = ".."});
431 try stack.append(RenderState { .Expression = range.start});
432 try stack.append(RenderState { .Text = "["});
433 try stack.append(RenderState { .Expression = suffix_op.lhs });
434 },
435 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
436 if (field_inits.len == 0) {
437 try stack.append(RenderState { .Text = "{}" });
438 try stack.append(RenderState { .Expression = suffix_op.lhs });
439 continue;
440 }
441 if (field_inits.len == 1) {
442 const field_init = *field_inits.at(0);
443
444 try stack.append(RenderState { .Text = " }" });
445 try stack.append(RenderState { .Expression = field_init });
446 try stack.append(RenderState { .Text = "{ " });
447 try stack.append(RenderState { .Expression = suffix_op.lhs });
448 continue;
449 }
450 try stack.append(RenderState { .Text = "}"});
451 try stack.append(RenderState.PrintIndent);
452 try stack.append(RenderState { .Indent = indent });
453 try stack.append(RenderState { .Text = "\n" });
454 var i = field_inits.len;
455 while (i != 0) {
456 i -= 1;
457 const field_init = *field_inits.at(i);
458 if (field_init.id != ast.Node.Id.LineComment) {
459 try stack.append(RenderState { .Text = "," });
460 }
461 try stack.append(RenderState { .Expression = field_init });
462 try stack.append(RenderState.PrintIndent);
463 if (i != 0) {
464 try stack.append(RenderState { .Text = blk: {
465 const prev_node = *field_inits.at(i - 1);
466 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
467 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
468 if (loc.line >= 2) {
469 break :blk "\n\n";
470 }
471 break :blk "\n";
472 }});
473 }
474 }
475 try stack.append(RenderState { .Indent = indent + indent_delta });
476 try stack.append(RenderState { .Text = "{\n"});
477 try stack.append(RenderState { .Expression = suffix_op.lhs });
478 },
479 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
480 if (exprs.len == 0) {
481 try stack.append(RenderState { .Text = "{}" });
482 try stack.append(RenderState { .Expression = suffix_op.lhs });
483 continue;
484 }
485 if (exprs.len == 1) {
486 const expr = *exprs.at(0);
487
488 try stack.append(RenderState { .Text = "}" });
489 try stack.append(RenderState { .Expression = expr });
490 try stack.append(RenderState { .Text = "{" });
491 try stack.append(RenderState { .Expression = suffix_op.lhs });
492 continue;
493 }
494
495 try stack.append(RenderState { .Text = "}"});
496 try stack.append(RenderState.PrintIndent);
497 try stack.append(RenderState { .Indent = indent });
498 var i = exprs.len;
499 while (i != 0) {
500 i -= 1;
501 const expr = *exprs.at(i);
502 try stack.append(RenderState { .Text = ",\n" });
503 try stack.append(RenderState { .Expression = expr });
504 try stack.append(RenderState.PrintIndent);
505 }
506 try stack.append(RenderState { .Indent = indent + indent_delta });
507 try stack.append(RenderState { .Text = "{\n"});
508 try stack.append(RenderState { .Expression = suffix_op.lhs });
509 },
510 }
511 },
512 ast.Node.Id.ControlFlowExpression => {
513 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
514
515 if (flow_expr.rhs) |rhs| {
516 try stack.append(RenderState { .Expression = rhs });
517 try stack.append(RenderState { .Text = " " });
518 }
519
520 switch (flow_expr.kind) {
521 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
522 try stream.print("break");
523 if (maybe_label) |label| {
524 try stream.print(" :");
525 try stack.append(RenderState { .Expression = label });
526 }
527 },
528 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
529 try stream.print("continue");
530 if (maybe_label) |label| {
531 try stream.print(" :");
532 try stack.append(RenderState { .Expression = label });
533 }
534 },
535 ast.Node.ControlFlowExpression.Kind.Return => {
536 try stream.print("return");
537 },
538
539 }
540 },
541 ast.Node.Id.Payload => {
542 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
543 try stack.append(RenderState { .Text = "|"});
544 try stack.append(RenderState { .Expression = payload.error_symbol });
545 try stack.append(RenderState { .Text = "|"});
546 },
547 ast.Node.Id.PointerPayload => {
548 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
549 try stack.append(RenderState { .Text = "|"});
550 try stack.append(RenderState { .Expression = payload.value_symbol });
551
552 if (payload.ptr_token) |ptr_token| {
553 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
554 }
555
556 try stack.append(RenderState { .Text = "|"});
557 },
558 ast.Node.Id.PointerIndexPayload => {
559 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
560 try stack.append(RenderState { .Text = "|"});
561
562 if (payload.index_symbol) |index_symbol| {
563 try stack.append(RenderState { .Expression = index_symbol });
564 try stack.append(RenderState { .Text = ", "});
565 }
566
567 try stack.append(RenderState { .Expression = payload.value_symbol });
568
569 if (payload.ptr_token) |ptr_token| {
570 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
571 }
572
573 try stack.append(RenderState { .Text = "|"});
574 },
575 ast.Node.Id.GroupedExpression => {
576 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
577 try stack.append(RenderState { .Text = ")"});
578 try stack.append(RenderState { .Expression = grouped_expr.expr });
579 try stack.append(RenderState { .Text = "("});
580 },
581 ast.Node.Id.FieldInitializer => {
582 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
583 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
584 try stack.append(RenderState { .Expression = field_init.expr });
585 },
586 ast.Node.Id.IntegerLiteral => {
587 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
588 try stream.print("{}", tree.tokenSlice(integer_literal.token));
589 },
590 ast.Node.Id.FloatLiteral => {
591 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
592 try stream.print("{}", tree.tokenSlice(float_literal.token));
593 },
594 ast.Node.Id.StringLiteral => {
595 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
596 try stream.print("{}", tree.tokenSlice(string_literal.token));
597 },
598 ast.Node.Id.CharLiteral => {
599 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
600 try stream.print("{}", tree.tokenSlice(char_literal.token));
601 },
602 ast.Node.Id.BoolLiteral => {
603 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
604 try stream.print("{}", tree.tokenSlice(bool_literal.token));
605 },
606 ast.Node.Id.NullLiteral => {
607 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
608 try stream.print("{}", tree.tokenSlice(null_literal.token));
609 },
610 ast.Node.Id.ThisLiteral => {
611 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
612 try stream.print("{}", tree.tokenSlice(this_literal.token));
613 },
614 ast.Node.Id.Unreachable => {
615 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
616 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
617 },
618 ast.Node.Id.ErrorType => {
619 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
620 try stream.print("{}", tree.tokenSlice(error_type.token));
621 },
622 ast.Node.Id.VarType => {
623 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
624 try stream.print("{}", tree.tokenSlice(var_type.token));
625 },
626 ast.Node.Id.ContainerDecl => {
627 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
628
629 switch (container_decl.layout) {
630 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
631 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
632 ast.Node.ContainerDecl.Layout.Auto => { },
633 }
634
635 switch (container_decl.kind) {
636 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
637 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
638 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
639 }
640
641 if (container_decl.fields_and_decls.len == 0) {
642 try stack.append(RenderState { .Text = "{}"});
643 } else {
644 try stack.append(RenderState { .Text = "}"});
645 try stack.append(RenderState.PrintIndent);
646 try stack.append(RenderState { .Indent = indent });
647 try stack.append(RenderState { .Text = "\n"});
648
649 var i = container_decl.fields_and_decls.len;
650 while (i != 0) {
651 i -= 1;
652 const node = *container_decl.fields_and_decls.at(i);
653 try stack.append(RenderState { .TopLevelDecl = node});
654 try stack.append(RenderState.PrintIndent);
655 try stack.append(RenderState {
656 .Text = blk: {
657 if (i != 0) {
658 const prev_node = *container_decl.fields_and_decls.at(i - 1);
659 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
660 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
661 if (loc.line >= 2) {
662 break :blk "\n\n";
663 }
664 }
665 break :blk "\n";
666 },
667 });
668 }
669 try stack.append(RenderState { .Indent = indent + indent_delta});
670 try stack.append(RenderState { .Text = "{"});
671 }
672
673 switch (container_decl.init_arg_expr) {
674 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
675 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
676 if (enum_tag_type) |expr| {
677 try stack.append(RenderState { .Text = ")) "});
678 try stack.append(RenderState { .Expression = expr});
679 try stack.append(RenderState { .Text = "(enum("});
680 } else {
681 try stack.append(RenderState { .Text = "(enum) "});
682 }
683 },
684 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
685 try stack.append(RenderState { .Text = ") "});
686 try stack.append(RenderState { .Expression = type_expr});
687 try stack.append(RenderState { .Text = "("});
688 },
689 }
690 },
691 ast.Node.Id.ErrorSetDecl => {
692 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
693
694 if (err_set_decl.decls.len == 0) {
695 try stream.write("error{}");
696 continue;
697 }
698
699 if (err_set_decl.decls.len == 1) blk: {
700 const node = *err_set_decl.decls.at(0);
701
702 // if there are any doc comments or same line comments
703 // don't try to put it all on one line
704 if (node.cast(ast.Node.ErrorTag)) |tag| {
705 if (tag.doc_comments != null) break :blk;
706 } else {
707 break :blk;
708 }
709
710
711 try stream.write("error{");
712 try stack.append(RenderState { .Text = "}" });
713 try stack.append(RenderState { .TopLevelDecl = node });
714 continue;
715 }
716
717 try stream.write("error{");
718
719 try stack.append(RenderState { .Text = "}"});
720 try stack.append(RenderState.PrintIndent);
721 try stack.append(RenderState { .Indent = indent });
722 try stack.append(RenderState { .Text = "\n"});
723
724 var i = err_set_decl.decls.len;
725 while (i != 0) {
726 i -= 1;
727 const node = *err_set_decl.decls.at(i);
728 if (node.id != ast.Node.Id.LineComment) {
729 try stack.append(RenderState { .Text = "," });
730 }
731 try stack.append(RenderState { .TopLevelDecl = node });
732 try stack.append(RenderState.PrintIndent);
733 try stack.append(RenderState {
734 .Text = blk: {
735 if (i != 0) {
736 const prev_node = *err_set_decl.decls.at(i - 1);
737 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
738 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
739 if (loc.line >= 2) {
740 break :blk "\n\n";
741 }
742 }
743 break :blk "\n";
744 },
745 });
746 }
747 try stack.append(RenderState { .Indent = indent + indent_delta});
748 },
749 ast.Node.Id.MultilineStringLiteral => {
750 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
751 try stream.print("\n");
752
753 var i : usize = 0;
754 while (i < multiline_str_literal.lines.len) : (i += 1) {
755 const t = *multiline_str_literal.lines.at(i);
756 try stream.writeByteNTimes(' ', indent + indent_delta);
757 try stream.print("{}", tree.tokenSlice(t));
758 }
759 try stream.writeByteNTimes(' ', indent);
760 },
761 ast.Node.Id.UndefinedLiteral => {
762 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
763 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
764 },
765 ast.Node.Id.BuiltinCall => {
766 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
767 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
768 try stack.append(RenderState { .Text = ")"});
769 var i = builtin_call.params.len;
770 while (i != 0) {
771 i -= 1;
772 const param_node = *builtin_call.params.at(i);
773 try stack.append(RenderState { .Expression = param_node});
774 if (i != 0) {
775 try stack.append(RenderState { .Text = ", " });
776 }
777 }
778 },
779 ast.Node.Id.FnProto => {
780 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
781
782 switch (fn_proto.return_type) {
783 ast.Node.FnProto.ReturnType.Explicit => |node| {
784 try stack.append(RenderState { .Expression = node});
785 },
786 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
787 try stack.append(RenderState { .Expression = node});
788 try stack.append(RenderState { .Text = "!"});
789 },
790 }
791
792 if (fn_proto.align_expr) |align_expr| {
793 try stack.append(RenderState { .Text = ") " });
794 try stack.append(RenderState { .Expression = align_expr});
795 try stack.append(RenderState { .Text = "align(" });
796 }
797
798 try stack.append(RenderState { .Text = ") " });
799 var i = fn_proto.params.len;
800 while (i != 0) {
801 i -= 1;
802 const param_decl_node = *fn_proto.params.at(i);
803 try stack.append(RenderState { .ParamDecl = param_decl_node});
804 if (i != 0) {
805 try stack.append(RenderState { .Text = ", " });
806 }
807 }
808
809 try stack.append(RenderState { .Text = "(" });
810 if (fn_proto.name_token) |name_token| {
811 try stack.append(RenderState { .Text = tree.tokenSlice(name_token) });
812 try stack.append(RenderState { .Text = " " });
813 }
814
815 try stack.append(RenderState { .Text = "fn" });
816
817 if (fn_proto.async_attr) |async_attr| {
818 try stack.append(RenderState { .Text = " " });
819 try stack.append(RenderState { .Expression = &async_attr.base });
820 }
821
822 if (fn_proto.cc_token) |cc_token| {
823 try stack.append(RenderState { .Text = " " });
824 try stack.append(RenderState { .Text = tree.tokenSlice(cc_token) });
825 }
826
827 if (fn_proto.lib_name) |lib_name| {
828 try stack.append(RenderState { .Text = " " });
829 try stack.append(RenderState { .Expression = lib_name });
830 }
831 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
832 try stack.append(RenderState { .Text = " " });
833 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
834 }
835
836 if (fn_proto.visib_token) |visib_token_index| {
837 const visib_token = tree.tokens.at(visib_token_index);
838 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
839 try stack.append(RenderState { .Text = " " });
840 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token_index) });
841 }
842 },
843 ast.Node.Id.PromiseType => {
844 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
845 try stream.write(tree.tokenSlice(promise_type.promise_token));
846 if (promise_type.result) |result| {
847 try stream.write(tree.tokenSlice(result.arrow_token));
848 try stack.append(RenderState { .Expression = result.return_type});
849 }
850 },
851 ast.Node.Id.LineComment => {
852 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
853 try stream.write(tree.tokenSlice(line_comment_node.token));
854 },
855 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
856 ast.Node.Id.Switch => {
857 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
858
859 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
860
861 if (switch_node.cases.len == 0) {
862 try stack.append(RenderState { .Text = ") {}"});
863 try stack.append(RenderState { .Expression = switch_node.expr });
864 continue;
865 }
866
867 try stack.append(RenderState { .Text = "}"});
868 try stack.append(RenderState.PrintIndent);
869 try stack.append(RenderState { .Indent = indent });
870 try stack.append(RenderState { .Text = "\n"});
871
872 var i = switch_node.cases.len;
873 while (i != 0) {
874 i -= 1;
875 const node = *switch_node.cases.at(i);
876 try stack.append(RenderState { .Expression = node});
877 try stack.append(RenderState.PrintIndent);
878 try stack.append(RenderState {
879 .Text = blk: {
880 if (i != 0) {
881 const prev_node = *switch_node.cases.at(i - 1);
882 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
883 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
884 if (loc.line >= 2) {
885 break :blk "\n\n";
886 }
887 }
888 break :blk "\n";
889 },
890 });
891 }
892 try stack.append(RenderState { .Indent = indent + indent_delta});
893 try stack.append(RenderState { .Text = ") {"});
894 try stack.append(RenderState { .Expression = switch_node.expr });
895 },
896 ast.Node.Id.SwitchCase => {
897 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
898
899 try stack.append(RenderState { .Token = switch_case.lastToken() + 1 });
900 try stack.append(RenderState { .Expression = switch_case.expr });
901 if (switch_case.payload) |payload| {
902 try stack.append(RenderState { .Text = " " });
903 try stack.append(RenderState { .Expression = payload });
904 }
905 try stack.append(RenderState { .Text = " => "});
906
907 var i = switch_case.items.len;
908 while (i != 0) {
909 i -= 1;
910 try stack.append(RenderState { .Expression = *switch_case.items.at(i) });
911
912 if (i != 0) {
913 try stack.append(RenderState.PrintIndent);
914 try stack.append(RenderState { .Text = ",\n" });
915 }
916 }
917 },
918 ast.Node.Id.SwitchElse => {
919 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
920 try stream.print("{}", tree.tokenSlice(switch_else.token));
921 },
922 ast.Node.Id.Else => {
923 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
924 try stream.print("{}", tree.tokenSlice(else_node.else_token));
925
926 switch (else_node.body.id) {
927 ast.Node.Id.Block, ast.Node.Id.If,
928 ast.Node.Id.For, ast.Node.Id.While,
929 ast.Node.Id.Switch => {
930 try stream.print(" ");
931 try stack.append(RenderState { .Expression = else_node.body });
932 },
933 else => {
934 try stack.append(RenderState { .Indent = indent });
935 try stack.append(RenderState { .Expression = else_node.body });
936 try stack.append(RenderState.PrintIndent);
937 try stack.append(RenderState { .Indent = indent + indent_delta });
938 try stack.append(RenderState { .Text = "\n" });
939 }
940 }
941
942 if (else_node.payload) |payload| {
943 try stack.append(RenderState { .Text = " " });
944 try stack.append(RenderState { .Expression = payload });
945 }
946 },
947 ast.Node.Id.While => {
948 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
949 if (while_node.label) |label| {
950 try stream.print("{}: ", tree.tokenSlice(label));
951 }
952
953 if (while_node.inline_token) |inline_token| {
954 try stream.print("{} ", tree.tokenSlice(inline_token));
955 }
956
957 try stream.print("{} ", tree.tokenSlice(while_node.while_token));
958
959 if (while_node.@"else") |@"else"| {
960 try stack.append(RenderState { .Expression = &@"else".base });
961
962 if (while_node.body.id == ast.Node.Id.Block) {
963 try stack.append(RenderState { .Text = " " });
964 } else {
965 try stack.append(RenderState.PrintIndent);
966 try stack.append(RenderState { .Text = "\n" });
967 }
968 }
969
970 if (while_node.body.id == ast.Node.Id.Block) {
971 try stack.append(RenderState { .Expression = while_node.body });
972 try stack.append(RenderState { .Text = " " });
973 } else {
974 try stack.append(RenderState { .Indent = indent });
975 try stack.append(RenderState { .Expression = while_node.body });
976 try stack.append(RenderState.PrintIndent);
977 try stack.append(RenderState { .Indent = indent + indent_delta });
978 try stack.append(RenderState { .Text = "\n" });
979 }
980
981 if (while_node.continue_expr) |continue_expr| {
982 try stack.append(RenderState { .Text = ")" });
983 try stack.append(RenderState { .Expression = continue_expr });
984 try stack.append(RenderState { .Text = ": (" });
985 try stack.append(RenderState { .Text = " " });
986 }
987
988 if (while_node.payload) |payload| {
989 try stack.append(RenderState { .Expression = payload });
990 try stack.append(RenderState { .Text = " " });
991 }
992
993 try stack.append(RenderState { .Text = ")" });
994 try stack.append(RenderState { .Expression = while_node.condition });
995 try stack.append(RenderState { .Text = "(" });
996 },
997 ast.Node.Id.For => {
998 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
999 if (for_node.label) |label| {
1000 try stream.print("{}: ", tree.tokenSlice(label));
1001 }
1002
1003 if (for_node.inline_token) |inline_token| {
1004 try stream.print("{} ", tree.tokenSlice(inline_token));
1005 }
1006
1007 try stream.print("{} ", tree.tokenSlice(for_node.for_token));
1008
1009 if (for_node.@"else") |@"else"| {
1010 try stack.append(RenderState { .Expression = &@"else".base });
1011
1012 if (for_node.body.id == ast.Node.Id.Block) {
1013 try stack.append(RenderState { .Text = " " });
1014 } else {
1015 try stack.append(RenderState.PrintIndent);
1016 try stack.append(RenderState { .Text = "\n" });
1017 }
1018 }
1019
1020 if (for_node.body.id == ast.Node.Id.Block) {
1021 try stack.append(RenderState { .Expression = for_node.body });
1022 try stack.append(RenderState { .Text = " " });
1023 } else {
1024 try stack.append(RenderState { .Indent = indent });
1025 try stack.append(RenderState { .Expression = for_node.body });
1026 try stack.append(RenderState.PrintIndent);
1027 try stack.append(RenderState { .Indent = indent + indent_delta });
1028 try stack.append(RenderState { .Text = "\n" });
1029 }
1030
1031 if (for_node.payload) |payload| {
1032 try stack.append(RenderState { .Expression = payload });
1033 try stack.append(RenderState { .Text = " " });
1034 }
1035
1036 try stack.append(RenderState { .Text = ")" });
1037 try stack.append(RenderState { .Expression = for_node.array_expr });
1038 try stack.append(RenderState { .Text = "(" });
1039 },
1040 ast.Node.Id.If => {
1041 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1042 try stream.print("{} ", tree.tokenSlice(if_node.if_token));
1043
1044 switch (if_node.body.id) {
1045 ast.Node.Id.Block, ast.Node.Id.If,
1046 ast.Node.Id.For, ast.Node.Id.While,
1047 ast.Node.Id.Switch => {
1048 if (if_node.@"else") |@"else"| {
1049 try stack.append(RenderState { .Expression = &@"else".base });
1050
1051 if (if_node.body.id == ast.Node.Id.Block) {
1052 try stack.append(RenderState { .Text = " " });
1053 } else {
1054 try stack.append(RenderState.PrintIndent);
1055 try stack.append(RenderState { .Text = "\n" });
1056 }
1057 }
1058 },
1059 else => {
1060 if (if_node.@"else") |@"else"| {
1061 try stack.append(RenderState { .Expression = @"else".body });
1062
1063 if (@"else".payload) |payload| {
1064 try stack.append(RenderState { .Text = " " });
1065 try stack.append(RenderState { .Expression = payload });
1066 }
1067
1068 try stack.append(RenderState { .Text = " " });
1069 try stack.append(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
1070 try stack.append(RenderState { .Text = " " });
1071 }
1072 }
1073 }
1074
1075 try stack.append(RenderState { .Expression = if_node.body });
1076
1077 if (if_node.payload) |payload| {
1078 try stack.append(RenderState { .Text = " " });
1079 try stack.append(RenderState { .Expression = payload });
1080 }
1081
1082 try stack.append(RenderState { .NonBreakToken = if_node.condition.lastToken() + 1 });
1083 try stack.append(RenderState { .Expression = if_node.condition });
1084 try stack.append(RenderState { .Text = "(" });
1085 },
1086 ast.Node.Id.Asm => {
1087 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1088 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
1089
1090 if (asm_node.volatile_token) |volatile_token| {
1091 try stream.print("{} ", tree.tokenSlice(volatile_token));
1092 }
1093
1094 try stack.append(RenderState { .Indent = indent });
1095 try stack.append(RenderState { .Text = ")" });
1096 {
1097 var i = asm_node.clobbers.len;
1098 while (i != 0) {
1099 i -= 1;
1100 try stack.append(RenderState { .Expression = *asm_node.clobbers.at(i) });
1101
1102 if (i != 0) {
1103 try stack.append(RenderState { .Text = ", " });
1104 }
1105 }
1106 }
1107 try stack.append(RenderState { .Text = ": " });
1108 try stack.append(RenderState.PrintIndent);
1109 try stack.append(RenderState { .Indent = indent + indent_delta });
1110 try stack.append(RenderState { .Text = "\n" });
1111 {
1112 var i = asm_node.inputs.len;
1113 while (i != 0) {
1114 i -= 1;
1115 const node = *asm_node.inputs.at(i);
1116 try stack.append(RenderState { .Expression = &node.base});
1117
1118 if (i != 0) {
1119 try stack.append(RenderState.PrintIndent);
1120 try stack.append(RenderState {
1121 .Text = blk: {
1122 const prev_node = *asm_node.inputs.at(i - 1);
1123 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1124 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1125 if (loc.line >= 2) {
1126 break :blk "\n\n";
1127 }
1128 break :blk "\n";
1129 },
1130 });
1131 try stack.append(RenderState { .Text = "," });
1132 }
1133 }
1134 }
1135 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1136 try stack.append(RenderState { .Text = ": "});
1137 try stack.append(RenderState.PrintIndent);
1138 try stack.append(RenderState { .Indent = indent + indent_delta});
1139 try stack.append(RenderState { .Text = "\n" });
1140 {
1141 var i = asm_node.outputs.len;
1142 while (i != 0) {
1143 i -= 1;
1144 const node = *asm_node.outputs.at(i);
1145 try stack.append(RenderState { .Expression = &node.base});
1146
1147 if (i != 0) {
1148 try stack.append(RenderState.PrintIndent);
1149 try stack.append(RenderState {
1150 .Text = blk: {
1151 const prev_node = *asm_node.outputs.at(i - 1);
1152 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1153 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1154 if (loc.line >= 2) {
1155 break :blk "\n\n";
1156 }
1157 break :blk "\n";
1158 },
1159 });
1160 try stack.append(RenderState { .Text = "," });
1161 }
1162 }
1163 }
1164 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1165 try stack.append(RenderState { .Text = ": "});
1166 try stack.append(RenderState.PrintIndent);
1167 try stack.append(RenderState { .Indent = indent + indent_delta});
1168 try stack.append(RenderState { .Text = "\n" });
1169 try stack.append(RenderState { .Expression = asm_node.template });
1170 try stack.append(RenderState { .Text = "(" });
1171 },
1172 ast.Node.Id.AsmInput => {
1173 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1174
1175 try stack.append(RenderState { .Text = ")"});
1176 try stack.append(RenderState { .Expression = asm_input.expr});
1177 try stack.append(RenderState { .Text = " ("});
1178 try stack.append(RenderState { .Expression = asm_input.constraint });
1179 try stack.append(RenderState { .Text = "] "});
1180 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
1181 try stack.append(RenderState { .Text = "["});
1182 },
1183 ast.Node.Id.AsmOutput => {
1184 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1185
1186 try stack.append(RenderState { .Text = ")"});
1187 switch (asm_output.kind) {
1188 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1189 try stack.append(RenderState { .Expression = &variable_name.base});
1190 },
1191 ast.Node.AsmOutput.Kind.Return => |return_type| {
1192 try stack.append(RenderState { .Expression = return_type});
1193 try stack.append(RenderState { .Text = "-> "});
1194 },
1195 }
1196 try stack.append(RenderState { .Text = " ("});
1197 try stack.append(RenderState { .Expression = asm_output.constraint });
1198 try stack.append(RenderState { .Text = "] "});
1199 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
1200 try stack.append(RenderState { .Text = "["});
1201 },
1202
1203 ast.Node.Id.StructField,
1204 ast.Node.Id.UnionTag,
1205 ast.Node.Id.EnumTag,
1206 ast.Node.Id.ErrorTag,
1207 ast.Node.Id.Root,
1208 ast.Node.Id.VarDecl,
1209 ast.Node.Id.Use,
1210 ast.Node.Id.TestDecl,
1211 ast.Node.Id.ParamDecl => unreachable,
1212 },
1213 RenderState.Statement => |base| {
1214 switch (base.id) {
1215 ast.Node.Id.VarDecl => {
1216 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1217 try stack.append(RenderState { .VarDecl = var_decl});
1218 },
1219 else => {
1220 try stack.append(RenderState { .MaybeSemiColon = base });
1221 try stack.append(RenderState { .Expression = base });
1222 },
1223 }
1224 },
1225 RenderState.Indent => |new_indent| indent = new_indent,
1226 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
1227 RenderState.Token => |token_index| try renderToken(tree, stream, token_index, indent, true),
1228 RenderState.NonBreakToken => |token_index| try renderToken(tree, stream, token_index, indent, false),
1229 RenderState.MaybeSemiColon => |base| {
1230 if (base.requireSemiColon()) {
1231 const semicolon_index = base.lastToken() + 1;
1232 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1233 try renderToken(tree, stream, semicolon_index, indent, true);
1234 }
1235 },
1236 }
1237 }
1238}
1239
1240fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) !void {
1241 const token = tree.tokens.at(token_index);
1242 try stream.write(tree.tokenSlicePtr(token));
1243
1244 const next_token = tree.tokens.at(token_index + 1);
1245 if (next_token.id == Token.Id.LineComment) {
1246 const loc = tree.tokenLocationPtr(token.end, next_token);
1247 if (loc.line == 0) {
1248 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1249 if (!line_break) {
1250 try stream.write("\n");
1251 try stream.writeByteNTimes(' ', indent + indent_delta);
1252 return;
1253 }
1254 }
1255 }
1256
1257 if (!line_break) {
1258 try stream.writeByte(' ');
1259 }
1260}
1261
1262fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {
1263 const comment = node.doc_comments ?? return;
1264 var it = comment.lines.iterator(0);
1265 while (it.next()) |line_token_index| {
1266 try stream.print("{}\n", tree.tokenSlice(*line_token_index));
1267 try stream.writeByteNTimes(' ', indent);
1268 }
1269}
1270
std/zig/tokenizer.zig+61-87
...@@ -6,60 +6,60 @@ pub const Token = struct {...@@ -6,60 +6,60 @@ pub const Token = struct {
6 start: usize,6 start: usize,
7 end: usize,7 end: usize,
88
9 const KeywordId = struct {9 const Keyword = struct {
10 bytes: []const u8,10 bytes: []const u8,
11 id: Id,11 id: Id,
12 };12 };
1313
14 const keywords = []KeywordId {14 const keywords = []Keyword {
15 KeywordId{.bytes="align", .id = Id.Keyword_align},15 Keyword{.bytes="align", .id = Id.Keyword_align},
16 KeywordId{.bytes="and", .id = Id.Keyword_and},16 Keyword{.bytes="and", .id = Id.Keyword_and},
17 KeywordId{.bytes="asm", .id = Id.Keyword_asm},17 Keyword{.bytes="asm", .id = Id.Keyword_asm},
18 KeywordId{.bytes="async", .id = Id.Keyword_async},18 Keyword{.bytes="async", .id = Id.Keyword_async},
19 KeywordId{.bytes="await", .id = Id.Keyword_await},19 Keyword{.bytes="await", .id = Id.Keyword_await},
20 KeywordId{.bytes="break", .id = Id.Keyword_break},20 Keyword{.bytes="break", .id = Id.Keyword_break},
21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},21 Keyword{.bytes="catch", .id = Id.Keyword_catch},
22 KeywordId{.bytes="cancel", .id = Id.Keyword_cancel},22 Keyword{.bytes="cancel", .id = Id.Keyword_cancel},
23 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},23 Keyword{.bytes="comptime", .id = Id.Keyword_comptime},
24 KeywordId{.bytes="const", .id = Id.Keyword_const},24 Keyword{.bytes="const", .id = Id.Keyword_const},
25 KeywordId{.bytes="continue", .id = Id.Keyword_continue},25 Keyword{.bytes="continue", .id = Id.Keyword_continue},
26 KeywordId{.bytes="defer", .id = Id.Keyword_defer},26 Keyword{.bytes="defer", .id = Id.Keyword_defer},
27 KeywordId{.bytes="else", .id = Id.Keyword_else},27 Keyword{.bytes="else", .id = Id.Keyword_else},
28 KeywordId{.bytes="enum", .id = Id.Keyword_enum},28 Keyword{.bytes="enum", .id = Id.Keyword_enum},
29 KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer},29 Keyword{.bytes="errdefer", .id = Id.Keyword_errdefer},
30 KeywordId{.bytes="error", .id = Id.Keyword_error},30 Keyword{.bytes="error", .id = Id.Keyword_error},
31 KeywordId{.bytes="export", .id = Id.Keyword_export},31 Keyword{.bytes="export", .id = Id.Keyword_export},
32 KeywordId{.bytes="extern", .id = Id.Keyword_extern},32 Keyword{.bytes="extern", .id = Id.Keyword_extern},
33 KeywordId{.bytes="false", .id = Id.Keyword_false},33 Keyword{.bytes="false", .id = Id.Keyword_false},
34 KeywordId{.bytes="fn", .id = Id.Keyword_fn},34 Keyword{.bytes="fn", .id = Id.Keyword_fn},
35 KeywordId{.bytes="for", .id = Id.Keyword_for},35 Keyword{.bytes="for", .id = Id.Keyword_for},
36 KeywordId{.bytes="if", .id = Id.Keyword_if},36 Keyword{.bytes="if", .id = Id.Keyword_if},
37 KeywordId{.bytes="inline", .id = Id.Keyword_inline},37 Keyword{.bytes="inline", .id = Id.Keyword_inline},
38 KeywordId{.bytes="nakedcc", .id = Id.Keyword_nakedcc},38 Keyword{.bytes="nakedcc", .id = Id.Keyword_nakedcc},
39 KeywordId{.bytes="noalias", .id = Id.Keyword_noalias},39 Keyword{.bytes="noalias", .id = Id.Keyword_noalias},
40 KeywordId{.bytes="null", .id = Id.Keyword_null},40 Keyword{.bytes="null", .id = Id.Keyword_null},
41 KeywordId{.bytes="or", .id = Id.Keyword_or},41 Keyword{.bytes="or", .id = Id.Keyword_or},
42 KeywordId{.bytes="packed", .id = Id.Keyword_packed},42 Keyword{.bytes="packed", .id = Id.Keyword_packed},
43 KeywordId{.bytes="promise", .id = Id.Keyword_promise},43 Keyword{.bytes="promise", .id = Id.Keyword_promise},
44 KeywordId{.bytes="pub", .id = Id.Keyword_pub},44 Keyword{.bytes="pub", .id = Id.Keyword_pub},
45 KeywordId{.bytes="resume", .id = Id.Keyword_resume},45 Keyword{.bytes="resume", .id = Id.Keyword_resume},
46 KeywordId{.bytes="return", .id = Id.Keyword_return},46 Keyword{.bytes="return", .id = Id.Keyword_return},
47 KeywordId{.bytes="section", .id = Id.Keyword_section},47 Keyword{.bytes="section", .id = Id.Keyword_section},
48 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},48 Keyword{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},
49 KeywordId{.bytes="struct", .id = Id.Keyword_struct},49 Keyword{.bytes="struct", .id = Id.Keyword_struct},
50 KeywordId{.bytes="suspend", .id = Id.Keyword_suspend},50 Keyword{.bytes="suspend", .id = Id.Keyword_suspend},
51 KeywordId{.bytes="switch", .id = Id.Keyword_switch},51 Keyword{.bytes="switch", .id = Id.Keyword_switch},
52 KeywordId{.bytes="test", .id = Id.Keyword_test},52 Keyword{.bytes="test", .id = Id.Keyword_test},
53 KeywordId{.bytes="this", .id = Id.Keyword_this},53 Keyword{.bytes="this", .id = Id.Keyword_this},
54 KeywordId{.bytes="true", .id = Id.Keyword_true},54 Keyword{.bytes="true", .id = Id.Keyword_true},
55 KeywordId{.bytes="try", .id = Id.Keyword_try},55 Keyword{.bytes="try", .id = Id.Keyword_try},
56 KeywordId{.bytes="undefined", .id = Id.Keyword_undefined},56 Keyword{.bytes="undefined", .id = Id.Keyword_undefined},
57 KeywordId{.bytes="union", .id = Id.Keyword_union},57 Keyword{.bytes="union", .id = Id.Keyword_union},
58 KeywordId{.bytes="unreachable", .id = Id.Keyword_unreachable},58 Keyword{.bytes="unreachable", .id = Id.Keyword_unreachable},
59 KeywordId{.bytes="use", .id = Id.Keyword_use},59 Keyword{.bytes="use", .id = Id.Keyword_use},
60 KeywordId{.bytes="var", .id = Id.Keyword_var},60 Keyword{.bytes="var", .id = Id.Keyword_var},
61 KeywordId{.bytes="volatile", .id = Id.Keyword_volatile},61 Keyword{.bytes="volatile", .id = Id.Keyword_volatile},
62 KeywordId{.bytes="while", .id = Id.Keyword_while},62 Keyword{.bytes="while", .id = Id.Keyword_while},
63 };63 };
6464
65 fn getKeyword(bytes: []const u8) ?Id {65 fn getKeyword(bytes: []const u8) ?Id {
...@@ -195,37 +195,6 @@ pub const Tokenizer = struct {...@@ -195,37 +195,6 @@ pub const Tokenizer = struct {
195 index: usize,195 index: usize,
196 pending_invalid_token: ?Token,196 pending_invalid_token: ?Token,
197197
198 pub const Location = struct {
199 line: usize,
200 column: usize,
201 line_start: usize,
202 line_end: usize,
203 };
204
205 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
206 var loc = Location {
207 .line = 0,
208 .column = 0,
209 .line_start = start_index,
210 .line_end = self.buffer.len,
211 };
212 for (self.buffer[start_index..]) |c, i| {
213 if (i + start_index == token.start) {
214 loc.line_end = i + start_index;
215 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
216 return loc;
217 }
218 if (c == '\n') {
219 loc.line += 1;
220 loc.column = 0;
221 loc.line_start = i + 1;
222 } else {
223 loc.column += 1;
224 }
225 }
226 return loc;
227 }
228
229 /// For debugging purposes198 /// For debugging purposes
230 pub fn dump(self: &Tokenizer, token: &const Token) void {199 pub fn dump(self: &Tokenizer, token: &const Token) void {
231 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);200 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);
...@@ -912,10 +881,10 @@ pub const Tokenizer = struct {...@@ -912,10 +881,10 @@ pub const Tokenizer = struct {
912 },881 },
913 },882 },
914 State.FloatFraction => switch (c) {883 State.FloatFraction => switch (c) {
915 'p', 'P' => {884 'p', 'P', 'e', 'E' => {
916 state = State.FloatExponentUnsigned;885 state = State.FloatExponentUnsigned;
917 },886 },
918 '0'...'9', 'a'...'f', 'A'...'F' => {},887 '0'...'9' => {},
919 else => break,888 else => break,
920 },889 },
921 State.FloatExponentUnsigned => switch (c) {890 State.FloatExponentUnsigned => switch (c) {
...@@ -1047,10 +1016,6 @@ pub const Tokenizer = struct {...@@ -1047,10 +1016,6 @@ pub const Tokenizer = struct {
1047 return result;1016 return result;
1048 }1017 }
10491018
1050 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) []const u8 {
1051 return self.buffer[token.start..token.end];
1052 }
1053
1054 fn checkLiteralCharacter(self: &Tokenizer) void {1019 fn checkLiteralCharacter(self: &Tokenizer) void {
1055 if (self.pending_invalid_token != null) return;1020 if (self.pending_invalid_token != null) return;
1056 const invalid_length = self.getInvalidCharacterLength();1021 const invalid_length = self.getInvalidCharacterLength();
...@@ -1108,6 +1073,15 @@ test "tokenizer" {...@@ -1108,6 +1073,15 @@ test "tokenizer" {
1108 });1073 });
1109}1074}
11101075
1076test "tokenizer - float literal" {
1077 testTokenize("a = 4.94065645841246544177e-324;\n", []Token.Id {
1078 Token.Id.Identifier,
1079 Token.Id.Equal,
1080 Token.Id.FloatLiteral,
1081 Token.Id.Semicolon,
1082 });
1083}
1084
1111test "tokenizer - chars" {1085test "tokenizer - chars" {
1112 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});1086 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1113}1087}
test/cases/math.zig+25
...@@ -349,6 +349,31 @@ test "big number shifting" {...@@ -349,6 +349,31 @@ test "big number shifting" {
349 }349 }
350}350}
351351
352test "big number multi-limb shift and mask" {
353 comptime {
354 var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
355
356 assert(u32(a & 0xffffffff) == 0xaaaaaaab);
357 a >>= 32;
358 assert(u32(a & 0xffffffff) == 0xeeeeeeef);
359 a >>= 32;
360 assert(u32(a & 0xffffffff) == 0xa0000001);
361 a >>= 32;
362 assert(u32(a & 0xffffffff) == 0xefffffff);
363 a >>= 32;
364
365 assert(a == 0);
366 }
367}
368
369test "big number multi-limb partial shift right" {
370 comptime {
371 var a = 0x1ffffffffeeeeeeee;
372 a >>= 16;
373 assert(a == 0x1ffffffffeeee);
374 }
375}
376
352test "xor" {377test "xor" {
353 test_xor();378 test_xor();
354 comptime test_xor();379 comptime test_xor();
test/cases/type_info.zig+22-3
...@@ -25,7 +25,7 @@ test "type info: integer, floating point type info" {...@@ -25,7 +25,7 @@ test "type info: integer, floating point type info" {
25 }25 }
26}26}
2727
28test "type info: pointer, array and nullable type info" {28test "type info: pointer type info" {
29 comptime {29 comptime {
30 const u32_ptr_info = @typeInfo(&u32);30 const u32_ptr_info = @typeInfo(&u32);
31 assert(TypeId(u32_ptr_info) == TypeId.Pointer);31 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
...@@ -33,12 +33,31 @@ test "type info: pointer, array and nullable type info" {...@@ -33,12 +33,31 @@ test "type info: pointer, array and nullable type info" {
33 assert(u32_ptr_info.Pointer.is_volatile == false);33 assert(u32_ptr_info.Pointer.is_volatile == false);
34 assert(u32_ptr_info.Pointer.alignment == 4);34 assert(u32_ptr_info.Pointer.alignment == 4);
35 assert(u32_ptr_info.Pointer.child == u32);35 assert(u32_ptr_info.Pointer.child == u32);
36 }
37}
38
39test "type info: slice type info" {
40 comptime {
41 const u32_slice_info = @typeInfo([]u32);
42 assert(TypeId(u32_slice_info) == TypeId.Slice);
43 assert(u32_slice_info.Slice.is_const == false);
44 assert(u32_slice_info.Slice.is_volatile == false);
45 assert(u32_slice_info.Slice.alignment == 4);
46 assert(u32_slice_info.Slice.child == u32);
47 }
48}
3649
50test "type info: array type info" {
51 comptime {
37 const arr_info = @typeInfo([42]bool);52 const arr_info = @typeInfo([42]bool);
38 assert(TypeId(arr_info) == TypeId.Array);53 assert(TypeId(arr_info) == TypeId.Array);
39 assert(arr_info.Array.len == 42);54 assert(arr_info.Array.len == 42);
40 assert(arr_info.Array.child == bool);55 assert(arr_info.Array.child == bool);
56 }
57}
4158
59test "type info: nullable type info" {
60 comptime {
42 const null_info = @typeInfo(?void);61 const null_info = @typeInfo(?void);
43 assert(TypeId(null_info) == TypeId.Nullable);62 assert(TypeId(null_info) == TypeId.Nullable);
44 assert(null_info.Nullable.child == void);63 assert(null_info.Nullable.child == void);
...@@ -100,11 +119,11 @@ test "type info: union info" {...@@ -100,11 +119,11 @@ test "type info: union info" {
100 assert(TypeId(typeinfo_info) == TypeId.Union);119 assert(TypeId(typeinfo_info) == TypeId.Union);
101 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);120 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
102 assert(typeinfo_info.Union.tag_type == TypeId);121 assert(typeinfo_info.Union.tag_type == TypeId);
103 assert(typeinfo_info.Union.fields.len == 25);122 assert(typeinfo_info.Union.fields.len == 26);
104 assert(typeinfo_info.Union.fields[4].enum_field != null);123 assert(typeinfo_info.Union.fields[4].enum_field != null);
105 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);124 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
106 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));125 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
107 assert(typeinfo_info.Union.defs.len == 20);126 assert(typeinfo_info.Union.defs.len == 21);
108127
109 const TestNoTagUnion = union {128 const TestNoTagUnion = union {
110 Foo: void,129 Foo: void,
test/cases/union.zig+12
...@@ -272,3 +272,15 @@ const PartialInstWithPayload = union(enum) {...@@ -272,3 +272,15 @@ const PartialInstWithPayload = union(enum) {
272 Compiled: i32,272 Compiled: i32,
273};273};
274274
275
276test "access a member of tagged union with conflicting enum tag name" {
277 const Bar = union(enum) {
278 A: A,
279 B: B,
280
281 const A = u8;
282 const B = void;
283 };
284
285 comptime assert(Bar.A == u8);
286}
test/translate_c.zig+21
...@@ -1,6 +1,27 @@...@@ -1,6 +1,27 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.TranslateCContext) void {3pub fn addCases(cases: &tests.TranslateCContext) void {
4 cases.add("double define struct",
5 \\typedef struct Bar Bar;
6 \\typedef struct Foo Foo;
7 \\
8 \\struct Foo {
9 \\ Foo *a;
10 \\};
11 \\
12 \\struct Bar {
13 \\ Foo *a;
14 \\};
15 ,
16 \\pub const struct_Foo = extern struct {
17 \\ a: ?&Foo,
18 \\};
19 \\pub const Foo = struct_Foo;
20 \\pub const struct_Bar = extern struct {
21 \\ a: ?&Foo,
22 \\};
23 );
24
4 cases.addAllowWarnings("simple data types",25 cases.addAllowWarnings("simple data types",
5 \\#include <stdint.h>26 \\#include <stdint.h>
6 \\int foo(char a, unsigned char b, signed char c);27 \\int foo(char a, unsigned char b, signed char c);