| ... | @@ -1,11 +1,14 @@ | ... | @@ -1,11 +1,14 @@ |
| | 1 | const std = @import("std"); |
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const io = @import("std").io; | 3 | const io = std.io; |
| 3 | const os = @import("std").os; | 4 | const os = std.os; |
| 4 | const heap = @import("std").heap; | 5 | const heap = std.heap; |
| 5 | const warn = @import("std").debug.warn; | 6 | const warn = std.debug.warn; |
| 6 | const assert = @import("std").debug.assert; | 7 | const assert = std.debug.assert; |
| 7 | const mem = @import("std").mem; | 8 | const mem = std.mem; |
| 8 | const ArrayList = @import("std").ArrayList; | 9 | const ArrayList = std.ArrayList; |
| | 10 | const AlignedArrayList = std.AlignedArrayList; |
| | 11 | const math = std.math; |
| 9 | | 12 | |
| 10 | | 13 | |
| 11 | const Token = struct { | 14 | const Token = struct { |
| ... | @@ -474,6 +477,10 @@ const Tokenizer = struct { | ... | @@ -474,6 +477,10 @@ const Tokenizer = struct { |
| 474 | // TODO check state when returning EOF | 477 | // TODO check state when returning EOF |
| 475 | return result; | 478 | return result; |
| 476 | } | 479 | } |
| | 480 | |
| | 481 | pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 { |
| | 482 | return self.buffer[token.start..token.end]; |
| | 483 | } |
| 477 | }; | 484 | }; |
| 478 | | 485 | |
| 479 | const Comptime = enum { No, Yes }; | 486 | const Comptime = enum { No, Yes }; |
| ... | @@ -525,6 +532,17 @@ const AstNode = struct { | ... | @@ -525,6 +532,17 @@ const AstNode = struct { |
| 525 | Id.AddrOfExpr => @fieldParentPtr(AstNodeAddrOfExpr, "base", base).iterate(index), | 532 | Id.AddrOfExpr => @fieldParentPtr(AstNodeAddrOfExpr, "base", base).iterate(index), |
| 526 | }; | 533 | }; |
| 527 | } | 534 | } |
| | 535 | |
| | 536 | fn destroy(base: &AstNode, allocator: &mem.Allocator) { |
| | 537 | return switch (base.id) { |
| | 538 | Id.Root => allocator.destroy(@fieldParentPtr(AstNodeRoot, "base", base)), |
| | 539 | Id.VarDecl => allocator.destroy(@fieldParentPtr(AstNodeVarDecl, "base", base)), |
| | 540 | Id.Identifier => allocator.destroy(@fieldParentPtr(AstNodeIdentifier, "base", base)), |
| | 541 | Id.FnProto => allocator.destroy(@fieldParentPtr(AstNodeFnProto, "base", base)), |
| | 542 | Id.ParamDecl => allocator.destroy(@fieldParentPtr(AstNodeParamDecl, "base", base)), |
| | 543 | Id.AddrOfExpr => allocator.destroy(@fieldParentPtr(AstNodeAddrOfExpr, "base", base)), |
| | 544 | }; |
| | 545 | } |
| 528 | }; | 546 | }; |
| 529 | | 547 | |
| 530 | const AstNodeRoot = struct { | 548 | const AstNodeRoot = struct { |
| ... | @@ -541,7 +559,7 @@ const AstNodeRoot = struct { | ... | @@ -541,7 +559,7 @@ const AstNodeRoot = struct { |
| 541 | | 559 | |
| 542 | const AstNodeVarDecl = struct { | 560 | const AstNodeVarDecl = struct { |
| 543 | base: AstNode, | 561 | base: AstNode, |
| 544 | visib: Visibility, | 562 | visib_token: ?Token, |
| 545 | name_token: Token, | 563 | name_token: Token, |
| 546 | eq_token: Token, | 564 | eq_token: Token, |
| 547 | mut: Mutability, | 565 | mut: Mutability, |
| ... | @@ -585,7 +603,7 @@ const AstNodeIdentifier = struct { | ... | @@ -585,7 +603,7 @@ const AstNodeIdentifier = struct { |
| 585 | | 603 | |
| 586 | const AstNodeFnProto = struct { | 604 | const AstNodeFnProto = struct { |
| 587 | base: AstNode, | 605 | base: AstNode, |
| 588 | visib: Visibility, | 606 | visib_token: ?Token, |
| 589 | fn_token: Token, | 607 | fn_token: Token, |
| 590 | name_token: ?Token, | 608 | name_token: ?Token, |
| 591 | params: ArrayList(&AstNode), | 609 | params: ArrayList(&AstNode), |
| ... | @@ -648,8 +666,8 @@ const AstNodeParamDecl = struct { | ... | @@ -648,8 +666,8 @@ const AstNodeParamDecl = struct { |
| 648 | | 666 | |
| 649 | const AstNodeAddrOfExpr = struct { | 667 | const AstNodeAddrOfExpr = struct { |
| 650 | base: AstNode, | 668 | base: AstNode, |
| 651 | align_expr: ?&AstNode, | | |
| 652 | op_token: Token, | 669 | op_token: Token, |
| | 670 | align_expr: ?&AstNode, |
| 653 | bit_offset_start_token: ?Token, | 671 | bit_offset_start_token: ?Token, |
| 654 | bit_offset_end_token: ?Token, | 672 | bit_offset_end_token: ?Token, |
| 655 | const_token: ?Token, | 673 | const_token: ?Token, |
| ... | @@ -674,26 +692,47 @@ const AstNodeAddrOfExpr = struct { | ... | @@ -674,26 +692,47 @@ const AstNodeAddrOfExpr = struct { |
| 674 | error ParseError; | 692 | error ParseError; |
| 675 | | 693 | |
| 676 | const Parser = struct { | 694 | const Parser = struct { |
| 677 | tokenizer: &Tokenizer, | | |
| 678 | allocator: &mem.Allocator, | 695 | allocator: &mem.Allocator, |
| | 696 | tokenizer: &Tokenizer, |
| 679 | put_back_tokens: [2]Token, | 697 | put_back_tokens: [2]Token, |
| 680 | put_back_count: usize, | 698 | put_back_count: usize, |
| 681 | source_file_name: []const u8, | 699 | source_file_name: []const u8, |
| 682 | | 700 | |
| 683 | fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) -> Parser { | 701 | // This memory contents are used only during a function call. It's used to repurpose memory; |
| | 702 | // specifically so that freeAst can be guaranteed to succeed. |
| | 703 | const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } ); |
| | 704 | utility_bytes: []align(utility_bytes_align) u8, |
| | 705 | |
| | 706 | fn initUtilityArrayList(self: &Parser, comptime T: type) -> ArrayList(T) { |
| | 707 | const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T); |
| | 708 | self.utility_bytes = self.allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count); |
| | 709 | const typed_slice = ([]T)(self.utility_bytes); |
| | 710 | return ArrayList(T).fromOwnedSlice(self.allocator, typed_slice); |
| | 711 | } |
| | 712 | |
| | 713 | fn deinitUtilityArrayList(self: &Parser, list: var) { |
| | 714 | self.utility_bytes = ([]align(utility_bytes_align) u8)(list.toOwnedSlice()); |
| | 715 | } |
| | 716 | |
| | 717 | pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) -> Parser { |
| 684 | return Parser { | 718 | return Parser { |
| 685 | .tokenizer = tokenizer, | | |
| 686 | .allocator = allocator, | 719 | .allocator = allocator, |
| | 720 | .tokenizer = tokenizer, |
| 687 | .put_back_tokens = undefined, | 721 | .put_back_tokens = undefined, |
| 688 | .put_back_count = 0, | 722 | .put_back_count = 0, |
| 689 | .source_file_name = source_file_name, | 723 | .source_file_name = source_file_name, |
| | 724 | .utility_bytes = []align(utility_bytes_align) u8{}, |
| 690 | }; | 725 | }; |
| 691 | } | 726 | } |
| 692 | | 727 | |
| | 728 | pub fn deinit(self: &Parser) { |
| | 729 | self.allocator.free(self.utility_bytes); |
| | 730 | } |
| | 731 | |
| 693 | const State = union(enum) { | 732 | const State = union(enum) { |
| 694 | TopLevel, | 733 | TopLevel, |
| 695 | TopLevelModifier: Visibility, | 734 | TopLevelModifier: ?Token, |
| 696 | TopLevelExtern: Visibility, | 735 | TopLevelExtern: ?Token, |
| 697 | Expression: &&AstNode, | 736 | Expression: &&AstNode, |
| 698 | GroupedExpression: &&AstNode, | 737 | GroupedExpression: &&AstNode, |
| 699 | UnwrapExpression: &&AstNode, | 738 | UnwrapExpression: &&AstNode, |
| ... | @@ -721,14 +760,36 @@ const Parser = struct { | ... | @@ -721,14 +760,36 @@ const Parser = struct { |
| 721 | ParamDeclComma, | 760 | ParamDeclComma, |
| 722 | }; | 761 | }; |
| 723 | | 762 | |
| 724 | pub fn parse(self: &Parser) -> %&AstNode { | 763 | pub fn freeAst(self: &Parser, root_node: &AstNodeRoot) { |
| 725 | var stack = ArrayList(State).init(self.allocator); | 764 | // utility_bytes is big enough to do this iteration since we were able to do |
| 726 | defer stack.deinit(); | 765 | // the parsing in the first place |
| | 766 | comptime assert(@sizeOf(State) >= @sizeOf(&AstNode)); |
| 727 | | 767 | |
| 728 | %return stack.append(State.TopLevel); | 768 | var stack = self.initUtilityArrayList(&AstNode); |
| | 769 | defer self.deinitUtilityArrayList(stack); |
| | 770 | |
| | 771 | stack.append(&root_node.base) %% unreachable; |
| | 772 | while (stack.popOrNull()) |node| { |
| | 773 | var i: usize = 0; |
| | 774 | while (node.iterate(i)) |child| : (i += 1) { |
| | 775 | if (child.iterate(0) != null) { |
| | 776 | stack.append(child) %% unreachable; |
| | 777 | } else { |
| | 778 | child.destroy(self.allocator); |
| | 779 | } |
| | 780 | } |
| | 781 | node.destroy(self.allocator); |
| | 782 | } |
| | 783 | } |
| | 784 | |
| | 785 | pub fn parse(self: &Parser) -> %&AstNodeRoot { |
| | 786 | var stack = self.initUtilityArrayList(State); |
| | 787 | defer self.deinitUtilityArrayList(stack); |
| 729 | | 788 | |
| 730 | const root_node = %return self.createRoot(); | 789 | const root_node = %return self.createRoot(); |
| 731 | // TODO %defer self.freeAst(); | 790 | %defer self.allocator.destroy(root_node); |
| | 791 | %return stack.append(State.TopLevel); |
| | 792 | %defer self.freeAst(root_node); |
| 732 | | 793 | |
| 733 | while (true) { | 794 | while (true) { |
| 734 | // This gives us 1 free append that can't fail | 795 | // This gives us 1 free append that can't fail |
| ... | @@ -738,95 +799,74 @@ const Parser = struct { | ... | @@ -738,95 +799,74 @@ const Parser = struct { |
| 738 | State.TopLevel => { | 799 | State.TopLevel => { |
| 739 | const token = self.getNextToken(); | 800 | const token = self.getNextToken(); |
| 740 | switch (token.id) { | 801 | switch (token.id) { |
| 741 | Token.Id.Keyword_pub => { | 802 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { |
| 742 | stack.append(State {.TopLevelModifier = Visibility.Pub }) %% unreachable; | 803 | stack.append(State { .TopLevelModifier = token }) %% unreachable; |
| 743 | continue; | | |
| 744 | }, | | |
| 745 | Token.Id.Keyword_export => { | | |
| 746 | stack.append(State {.TopLevelModifier = Visibility.Export }) %% unreachable; | | |
| 747 | continue; | 804 | continue; |
| 748 | }, | 805 | }, |
| 749 | Token.Id.Keyword_const => { | 806 | Token.Id.Keyword_const => { |
| 750 | stack.append(State.TopLevel) %% unreachable; | 807 | stack.append(State.TopLevel) %% unreachable; |
| 751 | const var_decl_node = { | 808 | // TODO shouldn't need this cast |
| 752 | const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Const, Comptime.No, Extern.No); | 809 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 753 | %defer self.allocator.destroy(var_decl_node); | 810 | Mutability.Const, Comptime.No, Extern.No); |
| 754 | %return root_node.decls.append(&var_decl_node.base); | | |
| 755 | var_decl_node | | |
| 756 | }; | | |
| 757 | %return stack.append(State { .VarDecl = var_decl_node }); | 811 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 758 | continue; | 812 | continue; |
| 759 | }, | 813 | }, |
| 760 | Token.Id.Keyword_var => { | 814 | Token.Id.Keyword_var => { |
| 761 | stack.append(State.TopLevel) %% unreachable; | 815 | stack.append(State.TopLevel) %% unreachable; |
| 762 | const var_decl_node = { | 816 | // TODO shouldn't need this cast |
| 763 | const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Var, Comptime.No, Extern.No); | 817 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 764 | %defer self.allocator.destroy(var_decl_node); | 818 | Mutability.Var, Comptime.No, Extern.No); |
| 765 | %return root_node.decls.append(&var_decl_node.base); | | |
| 766 | var_decl_node | | |
| 767 | }; | | |
| 768 | %return stack.append(State { .VarDecl = var_decl_node }); | 819 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 769 | continue; | 820 | continue; |
| 770 | }, | 821 | }, |
| 771 | Token.Id.Eof => return &root_node.base, | 822 | Token.Id.Eof => return root_node, |
| 772 | Token.Id.Keyword_extern => { | 823 | Token.Id.Keyword_extern => { |
| 773 | stack.append(State { .TopLevelExtern = Visibility.Private }) %% unreachable; | 824 | stack.append(State { .TopLevelExtern = null }) %% unreachable; |
| 774 | continue; | 825 | continue; |
| 775 | }, | 826 | }, |
| 776 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), | 827 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), |
| 777 | } | 828 | } |
| 778 | }, | 829 | }, |
| 779 | State.TopLevelModifier => |visib| { | 830 | State.TopLevelModifier => |visib_token| { |
| 780 | const token = self.getNextToken(); | 831 | const token = self.getNextToken(); |
| 781 | switch (token.id) { | 832 | switch (token.id) { |
| 782 | Token.Id.Keyword_const => { | 833 | Token.Id.Keyword_const => { |
| 783 | stack.append(State.TopLevel) %% unreachable; | 834 | stack.append(State.TopLevel) %% unreachable; |
| 784 | const var_decl_node = { | 835 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 785 | const var_decl_node = %return self.createVarDecl(visib, Mutability.Const, Comptime.No, Extern.No); | 836 | Mutability.Const, Comptime.No, Extern.No); |
| 786 | %defer self.allocator.destroy(var_decl_node); | | |
| 787 | %return root_node.decls.append(&var_decl_node.base); | | |
| 788 | var_decl_node | | |
| 789 | }; | | |
| 790 | %return stack.append(State { .VarDecl = var_decl_node }); | 837 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 791 | continue; | 838 | continue; |
| 792 | }, | 839 | }, |
| 793 | Token.Id.Keyword_var => { | 840 | Token.Id.Keyword_var => { |
| 794 | stack.append(State.TopLevel) %% unreachable; | 841 | stack.append(State.TopLevel) %% unreachable; |
| 795 | const var_decl_node = { | 842 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 796 | const var_decl_node = %return self.createVarDecl(visib, Mutability.Var, Comptime.No, Extern.No); | 843 | Mutability.Var, Comptime.No, Extern.No); |
| 797 | %defer self.allocator.destroy(var_decl_node); | | |
| 798 | %return root_node.decls.append(&var_decl_node.base); | | |
| 799 | var_decl_node | | |
| 800 | }; | | |
| 801 | %return stack.append(State { .VarDecl = var_decl_node }); | 844 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 802 | continue; | 845 | continue; |
| 803 | }, | 846 | }, |
| 804 | Token.Id.Keyword_extern => { | 847 | Token.Id.Keyword_extern => { |
| 805 | stack.append(State { .TopLevelExtern = visib }) %% unreachable; | 848 | stack.append(State { .TopLevelExtern = visib_token }) %% unreachable; |
| 806 | continue; | 849 | continue; |
| 807 | }, | 850 | }, |
| 808 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), | 851 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), |
| 809 | } | 852 | } |
| 810 | }, | 853 | }, |
| 811 | State.TopLevelExtern => |visib| { | 854 | State.TopLevelExtern => |visib_token| { |
| 812 | const token = self.getNextToken(); | 855 | const token = self.getNextToken(); |
| 813 | switch (token.id) { | 856 | switch (token.id) { |
| 814 | Token.Id.Keyword_var => { | 857 | Token.Id.Keyword_var => { |
| 815 | stack.append(State.TopLevel) %% unreachable; | 858 | stack.append(State.TopLevel) %% unreachable; |
| 816 | const var_decl_node = { | 859 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 817 | const var_decl_node = %return self.createVarDecl(visib, Mutability.Var, Comptime.No, Extern.Yes); | 860 | Mutability.Var, Comptime.No, Extern.Yes); |
| 818 | %defer self.allocator.destroy(var_decl_node); | | |
| 819 | %return root_node.decls.append(&var_decl_node.base); | | |
| 820 | var_decl_node | | |
| 821 | }; | | |
| 822 | %return stack.append(State { .VarDecl = var_decl_node }); | 861 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 823 | continue; | 862 | continue; |
| 824 | }, | 863 | }, |
| 825 | Token.Id.Keyword_fn => { | 864 | Token.Id.Keyword_fn => { |
| 826 | stack.append(State.TopLevel) %% unreachable; | 865 | stack.append(State.TopLevel) %% unreachable; |
| 827 | %return stack.append(State { .ExpectToken = Token.Id.Semicolon }); | 866 | %return stack.append(State { .ExpectToken = Token.Id.Semicolon }); |
| | 867 | // TODO shouldn't need this cast |
| 828 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token, | 868 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token, |
| 829 | Extern.Yes, CallingConvention.Auto, visib, Inline.Auto); | 869 | Extern.Yes, CallingConvention.Auto, (?Token)(null), Inline.Auto); |
| 830 | %return stack.append(State { .FnProto = fn_proto_node }); | 870 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 831 | continue; | 871 | continue; |
| 832 | }, | 872 | }, |
| ... | @@ -843,8 +883,9 @@ const Parser = struct { | ... | @@ -843,8 +883,9 @@ const Parser = struct { |
| 843 | else => unreachable, | 883 | else => unreachable, |
| 844 | }; | 884 | }; |
| 845 | const fn_token = %return self.eatToken(Token.Id.Keyword_fn); | 885 | const fn_token = %return self.eatToken(Token.Id.Keyword_fn); |
| | 886 | // TODO shouldn't need this cast |
| 846 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token, | 887 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token, |
| 847 | Extern.Yes, cc, visib, Inline.Auto); | 888 | Extern.Yes, cc, (?Token)(null), Inline.Auto); |
| 848 | %return stack.append(State { .FnProto = fn_proto_node }); | 889 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 849 | continue; | 890 | continue; |
| 850 | }, | 891 | }, |
| ... | @@ -1054,6 +1095,8 @@ const Parser = struct { | ... | @@ -1054,6 +1095,8 @@ const Parser = struct { |
| 1054 | } | 1095 | } |
| 1055 | if (token.id == Token.Id.Ellipsis3) { | 1096 | if (token.id == Token.Id.Ellipsis3) { |
| 1056 | param_decl.var_args_token = token; | 1097 | param_decl.var_args_token = token; |
| | 1098 | stack.append(State { .ExpectToken = Token.Id.RParen }) %% unreachable; |
| | 1099 | continue; |
| 1057 | } else { | 1100 | } else { |
| 1058 | self.putBackToken(token); | 1101 | self.putBackToken(token); |
| 1059 | } | 1102 | } |
| ... | @@ -1094,7 +1137,7 @@ const Parser = struct { | ... | @@ -1094,7 +1137,7 @@ const Parser = struct { |
| 1094 | return node; | 1137 | return node; |
| 1095 | } | 1138 | } |
| 1096 | | 1139 | |
| 1097 | fn createVarDecl(self: &Parser, visib: Visibility, mut: Mutability, is_comptime: Comptime, | 1140 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut: Mutability, is_comptime: Comptime, |
| 1098 | is_extern: Extern) -> %&AstNodeVarDecl | 1141 | is_extern: Extern) -> %&AstNodeVarDecl |
| 1099 | { | 1142 | { |
| 1100 | const node = %return self.allocator.create(AstNodeVarDecl); | 1143 | const node = %return self.allocator.create(AstNodeVarDecl); |
| ... | @@ -1102,7 +1145,7 @@ const Parser = struct { | ... | @@ -1102,7 +1145,7 @@ const Parser = struct { |
| 1102 | | 1145 | |
| 1103 | *node = AstNodeVarDecl { | 1146 | *node = AstNodeVarDecl { |
| 1104 | .base = AstNode {.id = AstNode.Id.VarDecl}, | 1147 | .base = AstNode {.id = AstNode.Id.VarDecl}, |
| 1105 | .visib = visib, | 1148 | .visib_token = *visib_token, |
| 1106 | .mut = mut, | 1149 | .mut = mut, |
| 1107 | .is_comptime = is_comptime, | 1150 | .is_comptime = is_comptime, |
| 1108 | .is_extern = is_extern, | 1151 | .is_extern = is_extern, |
| ... | @@ -1129,14 +1172,14 @@ const Parser = struct { | ... | @@ -1129,14 +1172,14 @@ const Parser = struct { |
| 1129 | } | 1172 | } |
| 1130 | | 1173 | |
| 1131 | fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern, | 1174 | fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern, |
| 1132 | cc: CallingConvention, visib: Visibility, is_inline: Inline) -> %&AstNodeFnProto | 1175 | cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto |
| 1133 | { | 1176 | { |
| 1134 | const node = %return self.allocator.create(AstNodeFnProto); | 1177 | const node = %return self.allocator.create(AstNodeFnProto); |
| 1135 | %defer self.allocator.destroy(node); | 1178 | %defer self.allocator.destroy(node); |
| 1136 | | 1179 | |
| 1137 | *node = AstNodeFnProto { | 1180 | *node = AstNodeFnProto { |
| 1138 | .base = AstNode {.id = AstNode.Id.FnProto}, | 1181 | .base = AstNode {.id = AstNode.Id.FnProto}, |
| 1139 | .visib = visib, | 1182 | .visib_token = *visib_token, |
| 1140 | .name_token = null, | 1183 | .name_token = null, |
| 1141 | .fn_token = *fn_token, | 1184 | .fn_token = *fn_token, |
| 1142 | .params = ArrayList(&AstNode).init(self.allocator), | 1185 | .params = ArrayList(&AstNode).init(self.allocator), |
| ... | @@ -1199,9 +1242,18 @@ const Parser = struct { | ... | @@ -1199,9 +1242,18 @@ const Parser = struct { |
| 1199 | } | 1242 | } |
| 1200 | | 1243 | |
| 1201 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token, | 1244 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token, |
| 1202 | is_extern: Extern, cc: CallingConvention, visib: Visibility, is_inline: Inline) -> %&AstNodeFnProto | 1245 | is_extern: Extern, cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto |
| 1203 | { | 1246 | { |
| 1204 | const node = %return self.createFnProto(fn_token, is_extern, cc, visib, is_inline); | 1247 | const node = %return self.createFnProto(fn_token, is_extern, cc, visib_token, is_inline); |
| | 1248 | %defer self.allocator.destroy(node); |
| | 1249 | %return list.append(&node.base); |
| | 1250 | return node; |
| | 1251 | } |
| | 1252 | |
| | 1253 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token, mut: Mutability, |
| | 1254 | is_comptime: Comptime, is_extern: Extern) -> %&AstNodeVarDecl |
| | 1255 | { |
| | 1256 | const node = %return self.createVarDecl(visib_token, mut, is_comptime, is_extern); |
| 1205 | %defer self.allocator.destroy(node); | 1257 | %defer self.allocator.destroy(node); |
| 1206 | %return list.append(&node.base); | 1258 | %return list.append(&node.base); |
| 1207 | return node; | 1259 | return node; |
| ... | @@ -1255,8 +1307,171 @@ const Parser = struct { | ... | @@ -1255,8 +1307,171 @@ const Parser = struct { |
| 1255 | self.tokenizer.next() | 1307 | self.tokenizer.next() |
| 1256 | }; | 1308 | }; |
| 1257 | } | 1309 | } |
| 1258 | }; | | |
| 1259 | | 1310 | |
| | 1311 | const RenderAstFrame = struct { |
| | 1312 | node: &AstNode, |
| | 1313 | indent: usize, |
| | 1314 | }; |
| | 1315 | |
| | 1316 | pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &AstNodeRoot) -> %void { |
| | 1317 | var stack = self.initUtilityArrayList(RenderAstFrame); |
| | 1318 | defer self.deinitUtilityArrayList(stack); |
| | 1319 | |
| | 1320 | %return stack.append(RenderAstFrame { |
| | 1321 | .node = &root_node.base, |
| | 1322 | .indent = 0, |
| | 1323 | }); |
| | 1324 | |
| | 1325 | while (stack.popOrNull()) |frame| { |
| | 1326 | { |
| | 1327 | var i: usize = 0; |
| | 1328 | while (i < frame.indent) : (i += 1) { |
| | 1329 | %return stream.print(" "); |
| | 1330 | } |
| | 1331 | } |
| | 1332 | %return stream.print("{}\n", @tagName(frame.node.id)); |
| | 1333 | var child_i: usize = 0; |
| | 1334 | while (frame.node.iterate(child_i)) |child| : (child_i += 1) { |
| | 1335 | %return stack.append(RenderAstFrame { |
| | 1336 | .node = child, |
| | 1337 | .indent = frame.indent + 2, |
| | 1338 | }); |
| | 1339 | } |
| | 1340 | } |
| | 1341 | } |
| | 1342 | |
| | 1343 | |
| | 1344 | pub const RenderState = union(enum) { |
| | 1345 | TopLevelDecl: &AstNode, |
| | 1346 | FnProtoRParen: &AstNodeFnProto, |
| | 1347 | ParamDecl: &AstNode, |
| | 1348 | Text: []const u8, |
| | 1349 | Expression: &AstNode, |
| | 1350 | AddrOfExprBit: &AstNodeAddrOfExpr, |
| | 1351 | }; |
| | 1352 | |
| | 1353 | pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &AstNodeRoot) -> %void { |
| | 1354 | var stack = self.initUtilityArrayList(RenderState); |
| | 1355 | defer self.deinitUtilityArrayList(stack); |
| | 1356 | |
| | 1357 | { |
| | 1358 | var i = root_node.decls.len; |
| | 1359 | while (i != 0) { |
| | 1360 | i -= 1; |
| | 1361 | const decl = root_node.decls.items[i]; |
| | 1362 | %return stack.append(RenderState {.TopLevelDecl = decl}); |
| | 1363 | } |
| | 1364 | } |
| | 1365 | |
| | 1366 | while (stack.popOrNull()) |state| { |
| | 1367 | switch (state) { |
| | 1368 | RenderState.TopLevelDecl => |decl| { |
| | 1369 | switch (decl.id) { |
| | 1370 | AstNode.Id.FnProto => { |
| | 1371 | const fn_proto = @fieldParentPtr(AstNodeFnProto, "base", decl); |
| | 1372 | if (fn_proto.visib_token) |visib_token| { |
| | 1373 | switch (visib_token.id) { |
| | 1374 | Token.Id.Keyword_pub => %return stream.print("pub "), |
| | 1375 | Token.Id.Keyword_export => %return stream.print("export "), |
| | 1376 | else => unreachable, |
| | 1377 | }; |
| | 1378 | } |
| | 1379 | if (fn_proto.is_extern == Extern.Yes) { |
| | 1380 | %return stream.print("extern "); |
| | 1381 | } |
| | 1382 | %return stream.print("fn"); |
| | 1383 | |
| | 1384 | if (fn_proto.name_token) |name_token| { |
| | 1385 | %return stream.print(" {}", self.tokenizer.getTokenSlice(name_token)); |
| | 1386 | } |
| | 1387 | |
| | 1388 | %return stream.print("("); |
| | 1389 | |
| | 1390 | if (fn_proto.fn_def_node == null) { |
| | 1391 | %return stack.append(RenderState { .Text = ";" }); |
| | 1392 | } |
| | 1393 | |
| | 1394 | %return stack.append(RenderState { .FnProtoRParen = fn_proto}); |
| | 1395 | var i = fn_proto.params.len; |
| | 1396 | while (i != 0) { |
| | 1397 | i -= 1; |
| | 1398 | const param_decl_node = fn_proto.params.items[i]; |
| | 1399 | %return stack.append(RenderState { .ParamDecl = param_decl_node}); |
| | 1400 | if (i != 0) { |
| | 1401 | %return stack.append(RenderState { .Text = ", " }); |
| | 1402 | } |
| | 1403 | } |
| | 1404 | }, |
| | 1405 | else => unreachable, |
| | 1406 | } |
| | 1407 | }, |
| | 1408 | RenderState.ParamDecl => |base| { |
| | 1409 | const param_decl = @fieldParentPtr(AstNodeParamDecl, "base", base); |
| | 1410 | if (param_decl.comptime_token) |comptime_token| { |
| | 1411 | %return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token)); |
| | 1412 | } |
| | 1413 | if (param_decl.noalias_token) |noalias_token| { |
| | 1414 | %return stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token)); |
| | 1415 | } |
| | 1416 | if (param_decl.name_token) |name_token| { |
| | 1417 | %return stream.print("{}: ", self.tokenizer.getTokenSlice(name_token)); |
| | 1418 | } |
| | 1419 | if (param_decl.var_args_token) |var_args_token| { |
| | 1420 | %return stream.print("{}", self.tokenizer.getTokenSlice(var_args_token)); |
| | 1421 | } else { |
| | 1422 | %return stack.append(RenderState { .Expression = param_decl.type_node}); |
| | 1423 | } |
| | 1424 | }, |
| | 1425 | RenderState.Text => |bytes| { |
| | 1426 | %return stream.write(bytes); |
| | 1427 | }, |
| | 1428 | RenderState.Expression => |base| switch (base.id) { |
| | 1429 | AstNode.Id.Identifier => { |
| | 1430 | const identifier = @fieldParentPtr(AstNodeIdentifier, "base", base); |
| | 1431 | %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token)); |
| | 1432 | }, |
| | 1433 | AstNode.Id.AddrOfExpr => { |
| | 1434 | const addr_of_expr = @fieldParentPtr(AstNodeAddrOfExpr, "base", base); |
| | 1435 | %return stream.print("{}", self.tokenizer.getTokenSlice(addr_of_expr.op_token)); |
| | 1436 | %return stack.append(RenderState { .AddrOfExprBit = addr_of_expr}); |
| | 1437 | |
| | 1438 | if (addr_of_expr.align_expr) |align_expr| { |
| | 1439 | %return stream.print("align("); |
| | 1440 | %return stack.append(RenderState { .Text = ")"}); |
| | 1441 | %return stack.append(RenderState { .Expression = align_expr}); |
| | 1442 | } |
| | 1443 | }, |
| | 1444 | else => unreachable, |
| | 1445 | }, |
| | 1446 | RenderState.AddrOfExprBit => |addr_of_expr| { |
| | 1447 | if (addr_of_expr.bit_offset_start_token) |bit_offset_start_token| { |
| | 1448 | %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_start_token)); |
| | 1449 | } |
| | 1450 | if (addr_of_expr.bit_offset_end_token) |bit_offset_end_token| { |
| | 1451 | %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_end_token)); |
| | 1452 | } |
| | 1453 | if (addr_of_expr.const_token) |const_token| { |
| | 1454 | %return stream.print("{} ", self.tokenizer.getTokenSlice(const_token)); |
| | 1455 | } |
| | 1456 | if (addr_of_expr.volatile_token) |volatile_token| { |
| | 1457 | %return stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token)); |
| | 1458 | } |
| | 1459 | %return stack.append(RenderState { .Expression = addr_of_expr.op_expr}); |
| | 1460 | }, |
| | 1461 | RenderState.FnProtoRParen => |fn_proto| { |
| | 1462 | %return stream.print(")"); |
| | 1463 | if (fn_proto.align_expr != null) { |
| | 1464 | @panic("TODO"); |
| | 1465 | } |
| | 1466 | if (fn_proto.return_type) |return_type| { |
| | 1467 | %return stream.print(" -> "); |
| | 1468 | %return stack.append(RenderState { .Expression = return_type}); |
| | 1469 | } |
| | 1470 | }, |
| | 1471 | } |
| | 1472 | } |
| | 1473 | } |
| | 1474 | }; |
| 1260 | | 1475 | |
| 1261 | pub fn main() -> %void { | 1476 | pub fn main() -> %void { |
| 1262 | main2() %% |err| { | 1477 | main2() %% |err| { |
| ... | @@ -1277,6 +1492,11 @@ pub fn main2() -> %void { | ... | @@ -1277,6 +1492,11 @@ pub fn main2() -> %void { |
| 1277 | const target_file = args[1]; | 1492 | const target_file = args[1]; |
| 1278 | | 1493 | |
| 1279 | const target_file_buf = %return io.readFileAlloc(target_file, allocator); | 1494 | const target_file_buf = %return io.readFileAlloc(target_file, allocator); |
| | 1495 | defer allocator.free(target_file_buf); |
| | 1496 | |
| | 1497 | var stderr_file = %return std.io.getStdErr(); |
| | 1498 | var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); |
| | 1499 | const out_stream = &stderr_file_out_stream.stream; |
| 1280 | | 1500 | |
| 1281 | warn("====input:====\n"); | 1501 | warn("====input:====\n"); |
| 1282 | | 1502 | |
| ... | @@ -1298,24 +1518,15 @@ pub fn main2() -> %void { | ... | @@ -1298,24 +1518,15 @@ pub fn main2() -> %void { |
| 1298 | | 1518 | |
| 1299 | var tokenizer = Tokenizer.init(target_file_buf); | 1519 | var tokenizer = Tokenizer.init(target_file_buf); |
| 1300 | var parser = Parser.init(&tokenizer, allocator, target_file); | 1520 | var parser = Parser.init(&tokenizer, allocator, target_file); |
| 1301 | const node = %return parser.parse(); | 1521 | defer parser.deinit(); |
| 1302 | | 1522 | |
| | 1523 | const root_node = %return parser.parse(); |
| | 1524 | defer parser.freeAst(root_node); |
| 1303 | | 1525 | |
| 1304 | render(node, 0); | 1526 | %return parser.renderAst(out_stream, root_node); |
| 1305 | } | | |
| 1306 | | 1527 | |
| 1307 | fn render(node: &AstNode, indent: usize) { | 1528 | warn("====fmt:====\n"); |
| 1308 | { | 1529 | %return parser.renderSource(out_stream, root_node); |
| 1309 | var i: usize = 0; | | |
| 1310 | while (i < indent) : (i += 1) { | | |
| 1311 | warn(" "); | | |
| 1312 | } | | |
| 1313 | } | | |
| 1314 | warn("{}\n", @tagName(node.id)); | | |
| 1315 | var i: usize = 0; | | |
| 1316 | while (node.iterate(i)) |child| : (i += 1) { | | |
| 1317 | render(child, indent + 2); | | |
| 1318 | } | | |
| 1319 | } | 1530 | } |
| 1320 | | 1531 | |
| 1321 | fn removeNullCast(x: var) -> {const InnerPtr = @typeOf(x).Child.Child; &InnerPtr} { | 1532 | fn removeNullCast(x: var) -> {const InnerPtr = @typeOf(x).Child.Child; &InnerPtr} { |