| ... | ... | @@ -52,7 +52,6 @@ pub const Node = extern union { |
| 52 | 52 | var_decl, |
| 53 | 53 | func, |
| 54 | 54 | warning, |
| 55 | | failed_decl, |
| 56 | 55 | /// All enums are non-exhaustive |
| 57 | 56 | @"enum", |
| 58 | 57 | @"struct", |
| ... | ... | @@ -339,9 +338,7 @@ pub const Node = extern union { |
| 339 | 338 | .char_literal, |
| 340 | 339 | .identifier, |
| 341 | 340 | .warning, |
| 342 | | .failed_decl, |
| 343 | 341 | .type, |
| 344 | | .fail_decl, |
| 345 | 342 | => Payload.Value, |
| 346 | 343 | .@"if" => Payload.If, |
| 347 | 344 | .@"while" => Payload.While, |
| ... | ... | @@ -359,7 +356,7 @@ pub const Node = extern union { |
| 359 | 356 | .block => Payload.Block, |
| 360 | 357 | .c_pointer, .single_pointer => Payload.Pointer, |
| 361 | 358 | .array_type => Payload.Array, |
| 362 | | .arg_redecl, .alias => Payload.ArgRedecl, |
| 359 | .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl, |
| 363 | 360 | .log2_int_type => Payload.Log2IntType, |
| 364 | 361 | .typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl, |
| 365 | 362 | .enum_redecl => Payload.EnumRedecl, |
| ... | ... | @@ -695,7 +692,7 @@ const Context = struct { |
| 695 | 692 | extra_data: std.ArrayListUnmanaged(std.zig.ast.Node.Index) = .{}, |
| 696 | 693 | tokens: std.zig.ast.TokenList = .{}, |
| 697 | 694 | |
| 698 | | fn appendTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { |
| 695 | fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { |
| 699 | 696 | const start_index = c.buf.items.len; |
| 700 | 697 | try c.buf.writer().print(format ++ " ", args); |
| 701 | 698 | |
| ... | ... | @@ -707,13 +704,13 @@ const Context = struct { |
| 707 | 704 | return @intCast(u32, c.tokens.len - 1); |
| 708 | 705 | } |
| 709 | 706 | |
| 710 | | fn appendToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex { |
| 711 | | std.debug.assert(tag != .identifier); // use appendIdentifier |
| 712 | | return appendTokenFmt(c, tag, "{s}", .{bytes}); |
| 707 | fn addToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex { |
| 708 | std.debug.assert(tag != .identifier); // use addIdentifier |
| 709 | return addTokenFmt(c, tag, "{s}", .{bytes}); |
| 713 | 710 | } |
| 714 | 711 | |
| 715 | | fn appendIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { |
| 716 | | return appendTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)}); |
| 712 | fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { |
| 713 | return addTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)}); |
| 717 | 714 | } |
| 718 | 715 | |
| 719 | 716 | fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange { |
| ... | ... | @@ -724,14 +721,14 @@ const Context = struct { |
| 724 | 721 | }; |
| 725 | 722 | } |
| 726 | 723 | |
| 727 | | fn appendNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex { |
| 724 | fn addNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex { |
| 728 | 725 | const result = @intCast(NodeIndex, c.nodes.len); |
| 729 | 726 | try c.nodes.append(c.gpa, elem); |
| 730 | 727 | return result; |
| 731 | 728 | } |
| 732 | 729 | }; |
| 733 | 730 | |
| 734 | | fn renderNodes(c: *Context, nodes: []const Node) !NodeSubRange { |
| 731 | fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange { |
| 735 | 732 | var result = std.ArrayList(NodeIndex).init(c.gpa); |
| 736 | 733 | defer result.deinit(); |
| 737 | 734 | |
| ... | ... | @@ -744,7 +741,7 @@ fn renderNodes(c: *Context, nodes: []const Node) !NodeSubRange { |
| 744 | 741 | return try c.listToSpan(result.items); |
| 745 | 742 | } |
| 746 | 743 | |
| 747 | | fn renderNode(c: *Context, node: Node) !NodeIndex { |
| 744 | fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 748 | 745 | switch (node.tag()) { |
| 749 | 746 | .warning => { |
| 750 | 747 | const payload = node.castTag(.warning).?; |
| ... | ... | @@ -754,12 +751,12 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { |
| 754 | 751 | }, |
| 755 | 752 | .usingnamespace_builtins => { |
| 756 | 753 | // pub usingnamespace @import("std").c.builtins; |
| 757 | | _ = try c.appendToken(.keyword_pub, "pub"); |
| 758 | | const usingnamespace_token = try c.appendToken(.keyword_usingnamespace, "usingnamespace"); |
| 754 | _ = try c.addToken(.keyword_pub, "pub"); |
| 755 | const usingnamespace_token = try c.addToken(.keyword_usingnamespace, "usingnamespace"); |
| 759 | 756 | const import_node = try renderStdImport(c, "c", "builtins"); |
| 760 | | _ = try c.appendToken(.semicolon, ";"); |
| 757 | _ = try c.addToken(.semicolon, ";"); |
| 761 | 758 | |
| 762 | | return c.appendNode(.{ |
| 759 | return c.addNode(.{ |
| 763 | 760 | .tag = .@"usingnamespace", |
| 764 | 761 | .main_token = usingnamespace_token, |
| 765 | 762 | .data = .{ |
| ... | ... | @@ -768,6 +765,196 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { |
| 768 | 765 | }, |
| 769 | 766 | }); |
| 770 | 767 | }, |
| 768 | .std_math_Log2Int => { |
| 769 | const payload = node.castTag(.std_math_Log2Int).?; |
| 770 | const import_node = try renderStdImport(c, "math", "Log2Int"); |
| 771 | return renderCall(c, import_node, &.{payload.data}); |
| 772 | }, |
| 773 | .std_meta_cast => { |
| 774 | const payload = node.castTag(.std_meta_cast).?; |
| 775 | const import_node = try renderStdImport(c, "meta", "cast"); |
| 776 | return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs }); |
| 777 | }, |
| 778 | .std_meta_sizeof => { |
| 779 | const payload = node.castTag(.std_meta_sizeof).?; |
| 780 | const import_node = try renderStdImport(c, "meta", "sizeof"); |
| 781 | return renderCall(c, import_node, &.{payload.data}); |
| 782 | }, |
| 783 | .std_mem_zeroes => { |
| 784 | const payload = node.castTag(.std_mem_zeroes).?; |
| 785 | const import_node = try renderStdImport(c, "mem", "zeroes"); |
| 786 | return renderCall(c, import_node, &.{payload.data}); |
| 787 | }, |
| 788 | .std_mem_zeroinit => { |
| 789 | const payload = node.castTag(.std_mem_zeroinit).?; |
| 790 | const import_node = try renderStdImport(c, "mem", "zeroInit"); |
| 791 | return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs }); |
| 792 | }, |
| 793 | .call => { |
| 794 | const payload = node.castTag(.call).?; |
| 795 | const lhs = try renderNode(c, payload.data.lhs); |
| 796 | return renderCall(c, lhs, payload.data.args); |
| 797 | }, |
| 798 | .null_literal => return c.addNode(.{ |
| 799 | .tag = .null_literal, |
| 800 | .main_token = try c.addToken(.keyword_null, "null"), |
| 801 | .data = .{ |
| 802 | .lhs = undefined, |
| 803 | .rhs = undefined, |
| 804 | }, |
| 805 | }), |
| 806 | .undefined_literal => return c.addNode(.{ |
| 807 | .tag = .undefined_literal, |
| 808 | .main_token = try c.addToken(.keyword_undefined, "undefined"), |
| 809 | .data = .{ |
| 810 | .lhs = undefined, |
| 811 | .rhs = undefined, |
| 812 | }, |
| 813 | }), |
| 814 | .true_literal => return c.addNode(.{ |
| 815 | .tag = .true_literal, |
| 816 | .main_token = try c.addToken(.keyword_true, "true"), |
| 817 | .data = .{ |
| 818 | .lhs = undefined, |
| 819 | .rhs = undefined, |
| 820 | }, |
| 821 | }), |
| 822 | .false_literal => return c.addNode(.{ |
| 823 | .tag = .false_literal, |
| 824 | .main_token = try c.addToken(.keyword_false, "false"), |
| 825 | .data = .{ |
| 826 | .lhs = undefined, |
| 827 | .rhs = undefined, |
| 828 | }, |
| 829 | }), |
| 830 | .zero_literal => return c.addNode(.{ |
| 831 | .tag = .integer_literal, |
| 832 | .main_token = try c.addToken(.integer_literal, "0"), |
| 833 | .data = .{ |
| 834 | .lhs = undefined, |
| 835 | .rhs = undefined, |
| 836 | }, |
| 837 | }), |
| 838 | .one_literal => return c.addNode(.{ |
| 839 | .tag = .integer_literal, |
| 840 | .main_token = try c.addToken(.integer_literal, "1"), |
| 841 | .data = .{ |
| 842 | .lhs = undefined, |
| 843 | .rhs = undefined, |
| 844 | }, |
| 845 | }), |
| 846 | .void_type => return c.addNode(.{ |
| 847 | .tag = .identifier, |
| 848 | .main_token = try c.addToken(.identifier, "void"), |
| 849 | .data = .{ |
| 850 | .lhs = undefined, |
| 851 | .rhs = undefined, |
| 852 | }, |
| 853 | }), |
| 854 | .@"anytype" => return try c.addNode(.{ |
| 855 | .tag = .@"anytype", |
| 856 | .main_token = try c.addToken(.keyword_anytype, "anytype"), |
| 857 | .data = .{ |
| 858 | .lhs = undefined, |
| 859 | .rhs = undefined, |
| 860 | }, |
| 861 | }), |
| 862 | .type => { |
| 863 | const payload = node.castTag(.type).?; |
| 864 | return c.addNode(.{ |
| 865 | .tag = .identifier, |
| 866 | .main_token = try c.addToken(.identifier, payload.data), |
| 867 | .data = .{ |
| 868 | .lhs = undefined, |
| 869 | .rhs = undefined, |
| 870 | }, |
| 871 | }); |
| 872 | }, |
| 873 | .identifier => { |
| 874 | const payload = node.castTag(.identifier).?; |
| 875 | return c.addNode(.{ |
| 876 | .tag = .identifier, |
| 877 | .main_token = try c.addIdentifier(payload.data), |
| 878 | .data = .{ |
| 879 | .lhs = undefined, |
| 880 | .rhs = undefined, |
| 881 | }, |
| 882 | }); |
| 883 | }, |
| 884 | .number_literal => { |
| 885 | const payload = node.castTag(.number_literal).?; |
| 886 | return c.addNode(.{ |
| 887 | .tag = .identifier, |
| 888 | // might be integer or float, but it doesn't matter for rendering |
| 889 | .main_token = try c.addToken(.integer_literal, payload.data), |
| 890 | .data = .{ |
| 891 | .lhs = undefined, |
| 892 | .rhs = undefined, |
| 893 | }, |
| 894 | }); |
| 895 | }, |
| 896 | .string_literal => { |
| 897 | const payload = node.castTag(.string_literal).?; |
| 898 | return c.addNode(.{ |
| 899 | .tag = .identifier, |
| 900 | .main_token = try c.addToken(.char_literal, payload.data), |
| 901 | .data = .{ |
| 902 | .lhs = undefined, |
| 903 | .rhs = undefined, |
| 904 | }, |
| 905 | }); |
| 906 | }, |
| 907 | .char_literal => { |
| 908 | const payload = node.castTag(.char_literal).?; |
| 909 | return c.addNode(.{ |
| 910 | .tag = .identifier, |
| 911 | .main_token = try c.addToken(.string_literal, payload.data), |
| 912 | .data = .{ |
| 913 | .lhs = undefined, |
| 914 | .rhs = undefined, |
| 915 | }, |
| 916 | }); |
| 917 | }, |
| 918 | .fail_decl => { |
| 919 | const payload = node.castTag(.fail_decl).?; |
| 920 | // pub const name = @compileError(msg); |
| 921 | _ = try c.addToken(.keyword_pub, "pub"); |
| 922 | const const_kw = try c.addToken(.keyword_const, "const"); |
| 923 | _ = try c.addIdentifier(payload.data.actual); |
| 924 | _ = try c.addToken(.equal, "="); |
| 925 | |
| 926 | |
| 927 | const compile_error_tok = try c.addToken(.builtin, "@compileError"); |
| 928 | _ = try c.addToken(.l_paren, "("); |
| 929 | const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.data.mangled)}); |
| 930 | const err_msg = try c.addNode(.{ |
| 931 | .tag = .string_literal, |
| 932 | .main_token = err_msg_tok, |
| 933 | .data = .{ |
| 934 | .lhs = undefined, |
| 935 | .rhs = undefined, |
| 936 | }, |
| 937 | }); |
| 938 | _ = try c.addToken(.r_paren, ")"); |
| 939 | const compile_error = try c.addNode(.{ |
| 940 | .tag = .builtin_call_two, |
| 941 | .main_token = compile_error_tok, |
| 942 | .data = .{ |
| 943 | .lhs = err_msg, |
| 944 | .rhs = 0, |
| 945 | }, |
| 946 | }); |
| 947 | _ = try c.addToken(.semicolon, ";"); |
| 948 | |
| 949 | return c.addNode(.{ |
| 950 | .tag = .simple_var_decl, |
| 951 | .main_token = const_kw, |
| 952 | .data = .{ |
| 953 | .lhs = 0, |
| 954 | .rhs = compile_error, |
| 955 | } |
| 956 | }); |
| 957 | }, |
| 771 | 958 | else => { |
| 772 | 959 | try c.buf.writer().print("// TODO renderNode {}\n", .{node.tag()}); |
| 773 | 960 | return @as(u32, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32' |
| ... | ... | @@ -776,22 +963,20 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { |
| 776 | 963 | } |
| 777 | 964 | |
| 778 | 965 | fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeIndex { |
| 779 | | const import_tok = try c.appendToken(.builtin, "@import"); |
| 780 | | _ = try c.appendToken(.l_paren, "("); |
| 781 | | |
| 782 | | const std_tok = try c.appendToken(.string_literal, "\"std\""); |
| 783 | | const std_node = try c.appendNode(.{ |
| 966 | const import_tok = try c.addToken(.builtin, "@import"); |
| 967 | _ = try c.addToken(.l_paren, "("); |
| 968 | const std_tok = try c.addToken(.string_literal, "\"std\""); |
| 969 | const std_node = try c.addNode(.{ |
| 784 | 970 | .tag = .string_literal, |
| 785 | 971 | .main_token = std_tok, |
| 786 | 972 | .data = .{ |
| 787 | | .lhs = std_tok, |
| 788 | | .rhs = std_tok, |
| 973 | .lhs = undefined, |
| 974 | .rhs = undefined, |
| 789 | 975 | }, |
| 790 | 976 | }); |
| 977 | _ = try c.addToken(.r_paren, ")"); |
| 791 | 978 | |
| 792 | | _ = try c.appendToken(.r_paren, ")"); |
| 793 | | |
| 794 | | const import_node = try c.appendNode(.{ |
| 979 | const import_node = try c.addNode(.{ |
| 795 | 980 | .tag = .builtin_call_two, |
| 796 | 981 | .main_token = import_tok, |
| 797 | 982 | .data = .{ |
| ... | ... | @@ -801,21 +986,67 @@ fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeInde |
| 801 | 986 | }); |
| 802 | 987 | |
| 803 | 988 | var access_chain = import_node; |
| 804 | | access_chain = try c.appendNode(.{ |
| 989 | access_chain = try c.addNode(.{ |
| 805 | 990 | .tag = .field_access, |
| 806 | | .main_token = try c.appendToken(.period, "."), |
| 991 | .main_token = try c.addToken(.period, "."), |
| 807 | 992 | .data = .{ |
| 808 | 993 | .lhs = access_chain, |
| 809 | | .rhs = try c.appendIdentifier(first), |
| 994 | .rhs = try c.addIdentifier(first), |
| 810 | 995 | }, |
| 811 | 996 | }); |
| 812 | | access_chain = try c.appendNode(.{ |
| 997 | access_chain = try c.addNode(.{ |
| 813 | 998 | .tag = .field_access, |
| 814 | | .main_token = try c.appendToken(.period, "."), |
| 999 | .main_token = try c.addToken(.period, "."), |
| 815 | 1000 | .data = .{ |
| 816 | 1001 | .lhs = access_chain, |
| 817 | | .rhs = try c.appendIdentifier(second), |
| 1002 | .rhs = try c.addIdentifier(second), |
| 818 | 1003 | }, |
| 819 | 1004 | }); |
| 820 | 1005 | return access_chain; |
| 821 | 1006 | } |
| 1007 | |
| 1008 | fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex { |
| 1009 | const lparen = try c.addToken(.l_paren, "("); |
| 1010 | const res = switch (args.len) { |
| 1011 | 0 => try c.addNode(.{ |
| 1012 | .tag = .call_one, |
| 1013 | .main_token = lparen, |
| 1014 | .data = .{ |
| 1015 | .lhs = lhs, |
| 1016 | .rhs = 0, |
| 1017 | }, |
| 1018 | }), |
| 1019 | 1 => blk: { |
| 1020 | const arg = try renderNode(c, args[0]); |
| 1021 | break :blk try c.addNode(.{ |
| 1022 | .tag = .call_one, |
| 1023 | .main_token = lparen, |
| 1024 | .data = .{ |
| 1025 | .lhs = lhs, |
| 1026 | .rhs = arg, |
| 1027 | }, |
| 1028 | }); |
| 1029 | }, |
| 1030 | else => blk: { |
| 1031 | const start = @intCast(u32, c.extra_data.items.len); |
| 1032 | const end = @intCast(u32, start + args.len); |
| 1033 | try c.extra_data.ensureCapacity(c.gpa, end + 2); // + 2 for span start + end |
| 1034 | for (args) |arg, i| { |
| 1035 | if (i != 0) _ = try c.addToken(.comma, ","); |
| 1036 | c.extra_data.appendAssumeCapacity(try renderNode(c, arg)); |
| 1037 | } |
| 1038 | c.extra_data.appendAssumeCapacity(start); |
| 1039 | c.extra_data.appendAssumeCapacity(end); |
| 1040 | break :blk try c.addNode(.{ |
| 1041 | .tag = .call_comma, |
| 1042 | .main_token = lparen, |
| 1043 | .data = .{ |
| 1044 | .lhs = lhs, |
| 1045 | .rhs = end + 2, |
| 1046 | }, |
| 1047 | }); |
| 1048 | }, |
| 1049 | }; |
| 1050 | _ = try c.addToken(.r_paren, ")"); |
| 1051 | return res; |
| 1052 | } |