| ... | ... | @@ -1,11 +1,14 @@ |
| 1 | const std = @import("std"); |
| 1 | 2 | const builtin = @import("builtin"); |
| 2 | | const io = @import("std").io; |
| 3 | | const os = @import("std").os; |
| 4 | | const heap = @import("std").heap; |
| 5 | | const warn = @import("std").debug.warn; |
| 6 | | const assert = @import("std").debug.assert; |
| 7 | | const mem = @import("std").mem; |
| 8 | | const ArrayList = @import("std").ArrayList; |
| 3 | const io = std.io; |
| 4 | const os = std.os; |
| 5 | const heap = std.heap; |
| 6 | const warn = std.debug.warn; |
| 7 | const assert = std.debug.assert; |
| 8 | const mem = std.mem; |
| 9 | const ArrayList = std.ArrayList; |
| 10 | const AlignedArrayList = std.AlignedArrayList; |
| 11 | const math = std.math; |
| 9 | 12 | |
| 10 | 13 | |
| 11 | 14 | const Token = struct { |
| ... | ... | @@ -474,6 +477,10 @@ const Tokenizer = struct { |
| 474 | 477 | // TODO check state when returning EOF |
| 475 | 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 | 486 | const Comptime = enum { No, Yes }; |
| ... | ... | @@ -525,6 +532,17 @@ const AstNode = struct { |
| 525 | 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 | 548 | const AstNodeRoot = struct { |
| ... | ... | @@ -541,7 +559,7 @@ const AstNodeRoot = struct { |
| 541 | 559 | |
| 542 | 560 | const AstNodeVarDecl = struct { |
| 543 | 561 | base: AstNode, |
| 544 | | visib: Visibility, |
| 562 | visib_token: ?Token, |
| 545 | 563 | name_token: Token, |
| 546 | 564 | eq_token: Token, |
| 547 | 565 | mut: Mutability, |
| ... | ... | @@ -585,7 +603,7 @@ const AstNodeIdentifier = struct { |
| 585 | 603 | |
| 586 | 604 | const AstNodeFnProto = struct { |
| 587 | 605 | base: AstNode, |
| 588 | | visib: Visibility, |
| 606 | visib_token: ?Token, |
| 589 | 607 | fn_token: Token, |
| 590 | 608 | name_token: ?Token, |
| 591 | 609 | params: ArrayList(&AstNode), |
| ... | ... | @@ -648,8 +666,8 @@ const AstNodeParamDecl = struct { |
| 648 | 666 | |
| 649 | 667 | const AstNodeAddrOfExpr = struct { |
| 650 | 668 | base: AstNode, |
| 651 | | align_expr: ?&AstNode, |
| 652 | 669 | op_token: Token, |
| 670 | align_expr: ?&AstNode, |
| 653 | 671 | bit_offset_start_token: ?Token, |
| 654 | 672 | bit_offset_end_token: ?Token, |
| 655 | 673 | const_token: ?Token, |
| ... | ... | @@ -674,26 +692,47 @@ const AstNodeAddrOfExpr = struct { |
| 674 | 692 | error ParseError; |
| 675 | 693 | |
| 676 | 694 | const Parser = struct { |
| 677 | | tokenizer: &Tokenizer, |
| 678 | 695 | allocator: &mem.Allocator, |
| 696 | tokenizer: &Tokenizer, |
| 679 | 697 | put_back_tokens: [2]Token, |
| 680 | 698 | put_back_count: usize, |
| 681 | 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 | 718 | return Parser { |
| 685 | | .tokenizer = tokenizer, |
| 686 | 719 | .allocator = allocator, |
| 720 | .tokenizer = tokenizer, |
| 687 | 721 | .put_back_tokens = undefined, |
| 688 | 722 | .put_back_count = 0, |
| 689 | 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 | 732 | const State = union(enum) { |
| 694 | | TopLevel, |
| 695 | | TopLevelModifier: Visibility, |
| 696 | | TopLevelExtern: Visibility, |
| 733 | TopLevel, |
| 734 | TopLevelModifier: ?Token, |
| 735 | TopLevelExtern: ?Token, |
| 697 | 736 | Expression: &&AstNode, |
| 698 | 737 | GroupedExpression: &&AstNode, |
| 699 | 738 | UnwrapExpression: &&AstNode, |
| ... | ... | @@ -721,14 +760,36 @@ const Parser = struct { |
| 721 | 760 | ParamDeclComma, |
| 722 | 761 | }; |
| 723 | 762 | |
| 724 | | pub fn parse(self: &Parser) -> %&AstNode { |
| 725 | | var stack = ArrayList(State).init(self.allocator); |
| 726 | | defer stack.deinit(); |
| 763 | pub fn freeAst(self: &Parser, root_node: &AstNodeRoot) { |
| 764 | // utility_bytes is big enough to do this iteration since we were able to do |
| 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 | 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 | 794 | while (true) { |
| 734 | 795 | // This gives us 1 free append that can't fail |
| ... | ... | @@ -738,95 +799,74 @@ const Parser = struct { |
| 738 | 799 | State.TopLevel => { |
| 739 | 800 | const token = self.getNextToken(); |
| 740 | 801 | switch (token.id) { |
| 741 | | Token.Id.Keyword_pub => { |
| 742 | | stack.append(State {.TopLevelModifier = Visibility.Pub }) %% unreachable; |
| 743 | | continue; |
| 744 | | }, |
| 745 | | Token.Id.Keyword_export => { |
| 746 | | stack.append(State {.TopLevelModifier = Visibility.Export }) %% unreachable; |
| 802 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { |
| 803 | stack.append(State { .TopLevelModifier = token }) %% unreachable; |
| 747 | 804 | continue; |
| 748 | 805 | }, |
| 749 | 806 | Token.Id.Keyword_const => { |
| 750 | 807 | stack.append(State.TopLevel) %% unreachable; |
| 751 | | const var_decl_node = { |
| 752 | | const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Const, Comptime.No, Extern.No); |
| 753 | | %defer self.allocator.destroy(var_decl_node); |
| 754 | | %return root_node.decls.append(&var_decl_node.base); |
| 755 | | var_decl_node |
| 756 | | }; |
| 808 | // TODO shouldn't need this cast |
| 809 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 810 | Mutability.Const, Comptime.No, Extern.No); |
| 757 | 811 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 758 | 812 | continue; |
| 759 | 813 | }, |
| 760 | 814 | Token.Id.Keyword_var => { |
| 761 | 815 | stack.append(State.TopLevel) %% unreachable; |
| 762 | | const var_decl_node = { |
| 763 | | const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Var, Comptime.No, Extern.No); |
| 764 | | %defer self.allocator.destroy(var_decl_node); |
| 765 | | %return root_node.decls.append(&var_decl_node.base); |
| 766 | | var_decl_node |
| 767 | | }; |
| 816 | // TODO shouldn't need this cast |
| 817 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 818 | Mutability.Var, Comptime.No, Extern.No); |
| 768 | 819 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 769 | 820 | continue; |
| 770 | 821 | }, |
| 771 | | Token.Id.Eof => return &root_node.base, |
| 822 | Token.Id.Eof => return root_node, |
| 772 | 823 | Token.Id.Keyword_extern => { |
| 773 | | stack.append(State { .TopLevelExtern = Visibility.Private }) %% unreachable; |
| 824 | stack.append(State { .TopLevelExtern = null }) %% unreachable; |
| 774 | 825 | continue; |
| 775 | 826 | }, |
| 776 | 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 | 831 | const token = self.getNextToken(); |
| 781 | 832 | switch (token.id) { |
| 782 | 833 | Token.Id.Keyword_const => { |
| 783 | 834 | stack.append(State.TopLevel) %% unreachable; |
| 784 | | const var_decl_node = { |
| 785 | | const var_decl_node = %return self.createVarDecl(visib, 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 | | }; |
| 835 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 836 | Mutability.Const, Comptime.No, Extern.No); |
| 790 | 837 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 791 | 838 | continue; |
| 792 | 839 | }, |
| 793 | 840 | Token.Id.Keyword_var => { |
| 794 | 841 | stack.append(State.TopLevel) %% unreachable; |
| 795 | | const var_decl_node = { |
| 796 | | const var_decl_node = %return self.createVarDecl(visib, 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 | | }; |
| 842 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 843 | Mutability.Var, Comptime.No, Extern.No); |
| 801 | 844 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 802 | 845 | continue; |
| 803 | 846 | }, |
| 804 | 847 | Token.Id.Keyword_extern => { |
| 805 | | stack.append(State { .TopLevelExtern = visib }) %% unreachable; |
| 848 | stack.append(State { .TopLevelExtern = visib_token }) %% unreachable; |
| 806 | 849 | continue; |
| 807 | 850 | }, |
| 808 | 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 | 855 | const token = self.getNextToken(); |
| 813 | 856 | switch (token.id) { |
| 814 | 857 | Token.Id.Keyword_var => { |
| 815 | 858 | stack.append(State.TopLevel) %% unreachable; |
| 816 | | const var_decl_node = { |
| 817 | | const var_decl_node = %return self.createVarDecl(visib, 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 | | }; |
| 859 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 860 | Mutability.Var, Comptime.No, Extern.Yes); |
| 822 | 861 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 823 | 862 | continue; |
| 824 | 863 | }, |
| 825 | 864 | Token.Id.Keyword_fn => { |
| 826 | 865 | stack.append(State.TopLevel) %% unreachable; |
| 827 | 866 | %return stack.append(State { .ExpectToken = Token.Id.Semicolon }); |
| 867 | // TODO shouldn't need this cast |
| 828 | 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 | 870 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 831 | 871 | continue; |
| 832 | 872 | }, |
| ... | ... | @@ -843,8 +883,9 @@ const Parser = struct { |
| 843 | 883 | else => unreachable, |
| 844 | 884 | }; |
| 845 | 885 | const fn_token = %return self.eatToken(Token.Id.Keyword_fn); |
| 886 | // TODO shouldn't need this cast |
| 846 | 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 | 889 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 849 | 890 | continue; |
| 850 | 891 | }, |
| ... | ... | @@ -1054,6 +1095,8 @@ const Parser = struct { |
| 1054 | 1095 | } |
| 1055 | 1096 | if (token.id == Token.Id.Ellipsis3) { |
| 1056 | 1097 | param_decl.var_args_token = token; |
| 1098 | stack.append(State { .ExpectToken = Token.Id.RParen }) %% unreachable; |
| 1099 | continue; |
| 1057 | 1100 | } else { |
| 1058 | 1101 | self.putBackToken(token); |
| 1059 | 1102 | } |
| ... | ... | @@ -1094,7 +1137,7 @@ const Parser = struct { |
| 1094 | 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 | 1141 | is_extern: Extern) -> %&AstNodeVarDecl |
| 1099 | 1142 | { |
| 1100 | 1143 | const node = %return self.allocator.create(AstNodeVarDecl); |
| ... | ... | @@ -1102,7 +1145,7 @@ const Parser = struct { |
| 1102 | 1145 | |
| 1103 | 1146 | *node = AstNodeVarDecl { |
| 1104 | 1147 | .base = AstNode {.id = AstNode.Id.VarDecl}, |
| 1105 | | .visib = visib, |
| 1148 | .visib_token = *visib_token, |
| 1106 | 1149 | .mut = mut, |
| 1107 | 1150 | .is_comptime = is_comptime, |
| 1108 | 1151 | .is_extern = is_extern, |
| ... | ... | @@ -1129,14 +1172,14 @@ const Parser = struct { |
| 1129 | 1172 | } |
| 1130 | 1173 | |
| 1131 | 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 | 1177 | const node = %return self.allocator.create(AstNodeFnProto); |
| 1135 | 1178 | %defer self.allocator.destroy(node); |
| 1136 | 1179 | |
| 1137 | 1180 | *node = AstNodeFnProto { |
| 1138 | 1181 | .base = AstNode {.id = AstNode.Id.FnProto}, |
| 1139 | | .visib = visib, |
| 1182 | .visib_token = *visib_token, |
| 1140 | 1183 | .name_token = null, |
| 1141 | 1184 | .fn_token = *fn_token, |
| 1142 | 1185 | .params = ArrayList(&AstNode).init(self.allocator), |
| ... | ... | @@ -1199,9 +1242,18 @@ const Parser = struct { |
| 1199 | 1242 | } |
| 1200 | 1243 | |
| 1201 | 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 | 1257 | %defer self.allocator.destroy(node); |
| 1206 | 1258 | %return list.append(&node.base); |
| 1207 | 1259 | return node; |
| ... | ... | @@ -1255,8 +1307,171 @@ const Parser = struct { |
| 1255 | 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 | 1476 | pub fn main() -> %void { |
| 1262 | 1477 | main2() %% |err| { |
| ... | ... | @@ -1277,6 +1492,11 @@ pub fn main2() -> %void { |
| 1277 | 1492 | const target_file = args[1]; |
| 1278 | 1493 | |
| 1279 | 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 | 1501 | warn("====input:====\n"); |
| 1282 | 1502 | |
| ... | ... | @@ -1298,24 +1518,15 @@ pub fn main2() -> %void { |
| 1298 | 1518 | |
| 1299 | 1519 | var tokenizer = Tokenizer.init(target_file_buf); |
| 1300 | 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); |
| 1305 | | } |
| 1526 | %return parser.renderAst(out_stream, root_node); |
| 1306 | 1527 | |
| 1307 | | fn render(node: &AstNode, indent: usize) { |
| 1308 | | { |
| 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 | | } |
| 1528 | warn("====fmt:====\n"); |
| 1529 | %return parser.renderSource(out_stream, root_node); |
| 1319 | 1530 | } |
| 1320 | 1531 | |
| 1321 | 1532 | fn removeNullCast(x: var) -> {const InnerPtr = @typeOf(x).Child.Child; &InnerPtr} { |