| author | |
| committer | |
| log | 6b103324d2d935260138584877dbe1593790b953 |
| tree | 3d1dc5c5378ac41ab5ca24f549721a882583454f |
| parent | a7c3cec65f1639195e787b98900c3f126953f880 |
| parent | c5b7322319a9559423fcda5c20c3b2e22338b2b4 |
| signature |
stage2: introduce the concept of "trailer flags" to the AST9 files changed, 773 insertions(+), 421 deletions(-)
lib/std/meta.zig+1| ... | ... | @@ -6,6 +6,7 @@ const math = std.math; |
| 6 | 6 | const testing = std.testing; |
| 7 | 7 | |
| 8 | 8 | pub const trait = @import("meta/trait.zig"); |
| 9 | pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags; | |
| 9 | 10 | |
| 10 | 11 | const TypeInfo = builtin.TypeInfo; |
| 11 | 12 |
lib/std/meta/trailer_flags.zig created+145| ... | ... | @@ -0,0 +1,145 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const meta = std.meta; | |
| 3 | const testing = std.testing; | |
| 4 | const mem = std.mem; | |
| 5 | const assert = std.debug.assert; | |
| 6 | ||
| 7 | /// This is useful for saving memory when allocating an object that has many | |
| 8 | /// optional components. The optional objects are allocated sequentially in | |
| 9 | /// memory, and a single integer is used to represent each optional object | |
| 10 | /// and whether it is present based on each corresponding bit. | |
| 11 | pub fn TrailerFlags(comptime Fields: type) type { | |
| 12 | return struct { | |
| 13 | bits: Int, | |
| 14 | ||
| 15 | pub const Int = @Type(.{ .Int = .{ .bits = bit_count, .is_signed = false } }); | |
| 16 | pub const bit_count = @typeInfo(Fields).Struct.fields.len; | |
| 17 | ||
| 18 | pub const Self = @This(); | |
| 19 | ||
| 20 | pub fn has(self: Self, comptime name: []const u8) bool { | |
| 21 | const field_index = meta.fieldIndex(Fields, name).?; | |
| 22 | return (self.bits & (1 << field_index)) != 0; | |
| 23 | } | |
| 24 | ||
| 25 | pub fn get(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) ?Field(name) { | |
| 26 | if (!self.has(name)) | |
| 27 | return null; | |
| 28 | return self.ptrConst(p, name).*; | |
| 29 | } | |
| 30 | ||
| 31 | pub fn setFlag(self: *Self, comptime name: []const u8) void { | |
| 32 | const field_index = meta.fieldIndex(Fields, name).?; | |
| 33 | self.bits |= 1 << field_index; | |
| 34 | } | |
| 35 | ||
| 36 | /// `fields` is a struct with each field set to an optional value. | |
| 37 | /// Missing fields are assumed to be `null`. | |
| 38 | /// Only the non-null bits are observed and are used to set the flag bits. | |
| 39 | pub fn init(fields: anytype) Self { | |
| 40 | var self: Self = .{ .bits = 0 }; | |
| 41 | inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { | |
| 42 | const opt: ?Field(field.name) = @field(fields, field.name); | |
| 43 | const field_index = meta.fieldIndex(Fields, field.name).?; | |
| 44 | self.bits |= @as(Int, @boolToInt(opt != null)) << field_index; | |
| 45 | } | |
| 46 | return self; | |
| 47 | } | |
| 48 | ||
| 49 | /// `fields` is a struct with each field set to an optional value (same as `init`). | |
| 50 | /// Missing fields are assumed to be `null`. | |
| 51 | pub fn setMany(self: Self, p: [*]align(@alignOf(Fields)) u8, fields: anytype) void { | |
| 52 | inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { | |
| 53 | const opt: ?Field(field.name) = @field(fields, field.name); | |
| 54 | if (opt) |value| { | |
| 55 | self.set(p, field.name, value); | |
| 56 | } | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | pub fn set( | |
| 61 | self: Self, | |
| 62 | p: [*]align(@alignOf(Fields)) u8, | |
| 63 | comptime name: []const u8, | |
| 64 | value: Field(name), | |
| 65 | ) void { | |
| 66 | self.ptr(p, name).* = value; | |
| 67 | } | |
| 68 | ||
| 69 | pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) { | |
| 70 | if (@sizeOf(Field(name)) == 0) | |
| 71 | return undefined; | |
| 72 | const off = self.offset(p, name); | |
| 73 | return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off)); | |
| 74 | } | |
| 75 | ||
| 76 | pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) { | |
| 77 | if (@sizeOf(Field(name)) == 0) | |
| 78 | return undefined; | |
| 79 | const off = self.offset(p, name); | |
| 80 | return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off)); | |
| 81 | } | |
| 82 | ||
| 83 | pub fn offset(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) usize { | |
| 84 | var off: usize = 0; | |
| 85 | inline for (@typeInfo(Fields).Struct.fields) |field, i| { | |
| 86 | const active = (self.bits & (1 << i)) != 0; | |
| 87 | if (comptime mem.eql(u8, field.name, name)) { | |
| 88 | assert(active); | |
| 89 | return mem.alignForwardGeneric(usize, off, @alignOf(field.field_type)); | |
| 90 | } else if (active) { | |
| 91 | off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type)); | |
| 92 | off += @sizeOf(field.field_type); | |
| 93 | } | |
| 94 | } | |
| 95 | @compileError("no field named " ++ name ++ " in type " ++ @typeName(Fields)); | |
| 96 | } | |
| 97 | ||
| 98 | pub fn Field(comptime name: []const u8) type { | |
| 99 | return meta.fieldInfo(Fields, name).field_type; | |
| 100 | } | |
| 101 | ||
| 102 | pub fn sizeInBytes(self: Self) usize { | |
| 103 | var off: usize = 0; | |
| 104 | inline for (@typeInfo(Fields).Struct.fields) |field, i| { | |
| 105 | if (@sizeOf(field.field_type) == 0) | |
| 106 | continue; | |
| 107 | if ((self.bits & (1 << i)) != 0) { | |
| 108 | off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type)); | |
| 109 | off += @sizeOf(field.field_type); | |
| 110 | } | |
| 111 | } | |
| 112 | return off; | |
| 113 | } | |
| 114 | }; | |
| 115 | } | |
| 116 | ||
| 117 | test "TrailerFlags" { | |
| 118 | const Flags = TrailerFlags(struct { | |
| 119 | a: i32, | |
| 120 | b: bool, | |
| 121 | c: u64, | |
| 122 | }); | |
| 123 | var flags = Flags.init(.{ | |
| 124 | .b = true, | |
| 125 | .c = 1234, | |
| 126 | }); | |
| 127 | const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact); | |
| 128 | defer testing.allocator.free(slice); | |
| 129 | ||
| 130 | flags.set(slice.ptr, "b", false); | |
| 131 | flags.set(slice.ptr, "c", 12345678); | |
| 132 | ||
| 133 | testing.expect(flags.get(slice.ptr, "a") == null); | |
| 134 | testing.expect(!flags.get(slice.ptr, "b").?); | |
| 135 | testing.expect(flags.get(slice.ptr, "c").? == 12345678); | |
| 136 | ||
| 137 | flags.setMany(slice.ptr, .{ | |
| 138 | .b = true, | |
| 139 | .c = 5678, | |
| 140 | }); | |
| 141 | ||
| 142 | testing.expect(flags.get(slice.ptr, "a") == null); | |
| 143 | testing.expect(flags.get(slice.ptr, "b").?); | |
| 144 | testing.expect(flags.get(slice.ptr, "c").? == 5678); | |
| 145 | } |
lib/std/zig/ast.zig+159-60| ... | ... | @@ -675,42 +675,84 @@ pub const Node = struct { |
| 675 | 675 | } |
| 676 | 676 | }; |
| 677 | 677 | |
| 678 | /// Trailed in memory by possibly many things, with each optional thing | |
| 679 | /// determined by a bit in `trailer_flags`. | |
| 678 | 680 | pub const VarDecl = struct { |
| 679 | 681 | base: Node = Node{ .id = .VarDecl }, |
| 680 | doc_comments: ?*DocComment, | |
| 681 | visib_token: ?TokenIndex, | |
| 682 | thread_local_token: ?TokenIndex, | |
| 683 | name_token: TokenIndex, | |
| 684 | eq_token: ?TokenIndex, | |
| 682 | trailer_flags: TrailerFlags, | |
| 685 | 683 | mut_token: TokenIndex, |
| 686 | comptime_token: ?TokenIndex, | |
| 687 | extern_export_token: ?TokenIndex, | |
| 688 | lib_name: ?*Node, | |
| 689 | type_node: ?*Node, | |
| 690 | align_node: ?*Node, | |
| 691 | section_node: ?*Node, | |
| 692 | init_node: ?*Node, | |
| 684 | name_token: TokenIndex, | |
| 693 | 685 | semicolon_token: TokenIndex, |
| 694 | 686 | |
| 687 | pub const TrailerFlags = std.meta.TrailerFlags(struct { | |
| 688 | doc_comments: *DocComment, | |
| 689 | visib_token: TokenIndex, | |
| 690 | thread_local_token: TokenIndex, | |
| 691 | eq_token: TokenIndex, | |
| 692 | comptime_token: TokenIndex, | |
| 693 | extern_export_token: TokenIndex, | |
| 694 | lib_name: *Node, | |
| 695 | type_node: *Node, | |
| 696 | align_node: *Node, | |
| 697 | section_node: *Node, | |
| 698 | init_node: *Node, | |
| 699 | }); | |
| 700 | ||
| 701 | pub const RequiredFields = struct { | |
| 702 | mut_token: TokenIndex, | |
| 703 | name_token: TokenIndex, | |
| 704 | semicolon_token: TokenIndex, | |
| 705 | }; | |
| 706 | ||
| 707 | pub fn getTrailer(self: *const VarDecl, comptime name: []const u8) ?TrailerFlags.Field(name) { | |
| 708 | const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(VarDecl); | |
| 709 | return self.trailer_flags.get(trailers_start, name); | |
| 710 | } | |
| 711 | ||
| 712 | pub fn setTrailer(self: *VarDecl, comptime name: []const u8, value: TrailerFlags.Field(name)) void { | |
| 713 | const trailers_start = @ptrCast([*]u8, self) + @sizeOf(VarDecl); | |
| 714 | self.trailer_flags.set(trailers_start, name, value); | |
| 715 | } | |
| 716 | ||
| 717 | pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*VarDecl { | |
| 718 | const trailer_flags = TrailerFlags.init(trailers); | |
| 719 | const bytes = try allocator.alignedAlloc(u8, @alignOf(VarDecl), sizeInBytes(trailer_flags)); | |
| 720 | const var_decl = @ptrCast(*VarDecl, bytes.ptr); | |
| 721 | var_decl.* = .{ | |
| 722 | .trailer_flags = trailer_flags, | |
| 723 | .mut_token = required.mut_token, | |
| 724 | .name_token = required.name_token, | |
| 725 | .semicolon_token = required.semicolon_token, | |
| 726 | }; | |
| 727 | const trailers_start = bytes.ptr + @sizeOf(VarDecl); | |
| 728 | trailer_flags.setMany(trailers_start, trailers); | |
| 729 | return var_decl; | |
| 730 | } | |
| 731 | ||
| 732 | pub fn destroy(self: *VarDecl, allocator: *mem.Allocator) void { | |
| 733 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)]; | |
| 734 | allocator.free(bytes); | |
| 735 | } | |
| 736 | ||
| 695 | 737 | pub fn iterate(self: *const VarDecl, index: usize) ?*Node { |
| 696 | 738 | var i = index; |
| 697 | 739 | |
| 698 | if (self.type_node) |type_node| { | |
| 740 | if (self.getTrailer("type_node")) |type_node| { | |
| 699 | 741 | if (i < 1) return type_node; |
| 700 | 742 | i -= 1; |
| 701 | 743 | } |
| 702 | 744 | |
| 703 | if (self.align_node) |align_node| { | |
| 745 | if (self.getTrailer("align_node")) |align_node| { | |
| 704 | 746 | if (i < 1) return align_node; |
| 705 | 747 | i -= 1; |
| 706 | 748 | } |
| 707 | 749 | |
| 708 | if (self.section_node) |section_node| { | |
| 750 | if (self.getTrailer("section_node")) |section_node| { | |
| 709 | 751 | if (i < 1) return section_node; |
| 710 | 752 | i -= 1; |
| 711 | 753 | } |
| 712 | 754 | |
| 713 | if (self.init_node) |init_node| { | |
| 755 | if (self.getTrailer("init_node")) |init_node| { | |
| 714 | 756 | if (i < 1) return init_node; |
| 715 | 757 | i -= 1; |
| 716 | 758 | } |
| ... | ... | @@ -719,17 +761,21 @@ pub const Node = struct { |
| 719 | 761 | } |
| 720 | 762 | |
| 721 | 763 | pub fn firstToken(self: *const VarDecl) TokenIndex { |
| 722 | if (self.visib_token) |visib_token| return visib_token; | |
| 723 | if (self.thread_local_token) |thread_local_token| return thread_local_token; | |
| 724 | if (self.comptime_token) |comptime_token| return comptime_token; | |
| 725 | if (self.extern_export_token) |extern_export_token| return extern_export_token; | |
| 726 | assert(self.lib_name == null); | |
| 764 | if (self.getTrailer("visib_token")) |visib_token| return visib_token; | |
| 765 | if (self.getTrailer("thread_local_token")) |thread_local_token| return thread_local_token; | |
| 766 | if (self.getTrailer("comptime_token")) |comptime_token| return comptime_token; | |
| 767 | if (self.getTrailer("extern_export_token")) |extern_export_token| return extern_export_token; | |
| 768 | assert(self.getTrailer("lib_name") == null); | |
| 727 | 769 | return self.mut_token; |
| 728 | 770 | } |
| 729 | 771 | |
| 730 | 772 | pub fn lastToken(self: *const VarDecl) TokenIndex { |
| 731 | 773 | return self.semicolon_token; |
| 732 | 774 | } |
| 775 | ||
| 776 | fn sizeInBytes(trailer_flags: TrailerFlags) usize { | |
| 777 | return @sizeOf(VarDecl) + trailer_flags.sizeInBytes(); | |
| 778 | } | |
| 733 | 779 | }; |
| 734 | 780 | |
| 735 | 781 | pub const Use = struct { |
| ... | ... | @@ -972,25 +1018,34 @@ pub const Node = struct { |
| 972 | 1018 | }; |
| 973 | 1019 | |
| 974 | 1020 | /// The params are directly after the FnProto in memory. |
| 975 | /// TODO have a flags field for the optional nodes, and have them appended | |
| 976 | /// before or after the parameters in memory. | |
| 1021 | /// Next, each optional thing determined by a bit in `trailer_flags`. | |
| 977 | 1022 | pub const FnProto = struct { |
| 978 | 1023 | base: Node = Node{ .id = .FnProto }, |
| 979 | doc_comments: ?*DocComment, | |
| 980 | visib_token: ?TokenIndex, | |
| 1024 | trailer_flags: TrailerFlags, | |
| 981 | 1025 | fn_token: TokenIndex, |
| 982 | name_token: ?TokenIndex, | |
| 983 | 1026 | params_len: NodeIndex, |
| 984 | 1027 | return_type: ReturnType, |
| 985 | var_args_token: ?TokenIndex, | |
| 986 | extern_export_inline_token: ?TokenIndex, | |
| 987 | body_node: ?*Node, | |
| 988 | lib_name: ?*Node, // populated if this is an extern declaration | |
| 989 | align_expr: ?*Node, // populated if align(A) is present | |
| 990 | section_expr: ?*Node, // populated if linksection(A) is present | |
| 991 | callconv_expr: ?*Node, // populated if callconv(A) is present | |
| 992 | is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is | |
| 993 | is_async: bool = false, // TODO: remove once async fn rewriting is | |
| 1028 | ||
| 1029 | pub const TrailerFlags = std.meta.TrailerFlags(struct { | |
| 1030 | doc_comments: *DocComment, | |
| 1031 | body_node: *Node, | |
| 1032 | lib_name: *Node, // populated if this is an extern declaration | |
| 1033 | align_expr: *Node, // populated if align(A) is present | |
| 1034 | section_expr: *Node, // populated if linksection(A) is present | |
| 1035 | callconv_expr: *Node, // populated if callconv(A) is present | |
| 1036 | visib_token: TokenIndex, | |
| 1037 | name_token: TokenIndex, | |
| 1038 | var_args_token: TokenIndex, | |
| 1039 | extern_export_inline_token: TokenIndex, | |
| 1040 | is_extern_prototype: void, // TODO: Remove once extern fn rewriting is | |
| 1041 | is_async: void, // TODO: remove once async fn rewriting is | |
| 1042 | }); | |
| 1043 | ||
| 1044 | pub const RequiredFields = struct { | |
| 1045 | fn_token: TokenIndex, | |
| 1046 | params_len: NodeIndex, | |
| 1047 | return_type: ReturnType, | |
| 1048 | }; | |
| 994 | 1049 | |
| 995 | 1050 | pub const ReturnType = union(enum) { |
| 996 | 1051 | Explicit: *Node, |
| ... | ... | @@ -1007,7 +1062,6 @@ pub const Node = struct { |
| 1007 | 1062 | |
| 1008 | 1063 | pub const ParamType = union(enum) { |
| 1009 | 1064 | any_type: *Node, |
| 1010 | var_args: TokenIndex, | |
| 1011 | 1065 | type_expr: *Node, |
| 1012 | 1066 | }; |
| 1013 | 1067 | |
| ... | ... | @@ -1016,7 +1070,6 @@ pub const Node = struct { |
| 1016 | 1070 | |
| 1017 | 1071 | if (i < 1) { |
| 1018 | 1072 | switch (self.param_type) { |
| 1019 | .var_args => return null, | |
| 1020 | 1073 | .any_type, .type_expr => |node| return node, |
| 1021 | 1074 | } |
| 1022 | 1075 | } |
| ... | ... | @@ -1030,34 +1083,79 @@ pub const Node = struct { |
| 1030 | 1083 | if (self.noalias_token) |noalias_token| return noalias_token; |
| 1031 | 1084 | if (self.name_token) |name_token| return name_token; |
| 1032 | 1085 | switch (self.param_type) { |
| 1033 | .var_args => |tok| return tok, | |
| 1034 | 1086 | .any_type, .type_expr => |node| return node.firstToken(), |
| 1035 | 1087 | } |
| 1036 | 1088 | } |
| 1037 | 1089 | |
| 1038 | 1090 | pub fn lastToken(self: *const ParamDecl) TokenIndex { |
| 1039 | 1091 | switch (self.param_type) { |
| 1040 | .var_args => |tok| return tok, | |
| 1041 | 1092 | .any_type, .type_expr => |node| return node.lastToken(), |
| 1042 | 1093 | } |
| 1043 | 1094 | } |
| 1044 | 1095 | }; |
| 1045 | 1096 | |
| 1097 | /// For debugging purposes. | |
| 1098 | pub fn dump(self: *const FnProto) void { | |
| 1099 | const trailers_start = @alignCast( | |
| 1100 | @alignOf(ParamDecl), | |
| 1101 | @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len, | |
| 1102 | ); | |
| 1103 | std.debug.print("{*} flags: {b} name_token: {} {*} params_len: {}\n", .{ | |
| 1104 | self, | |
| 1105 | self.trailer_flags.bits, | |
| 1106 | self.getTrailer("name_token"), | |
| 1107 | self.trailer_flags.ptrConst(trailers_start, "name_token"), | |
| 1108 | self.params_len, | |
| 1109 | }); | |
| 1110 | } | |
| 1111 | ||
| 1112 | pub fn getTrailer(self: *const FnProto, comptime name: []const u8) ?TrailerFlags.Field(name) { | |
| 1113 | const trailers_start = @alignCast( | |
| 1114 | @alignOf(ParamDecl), | |
| 1115 | @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len, | |
| 1116 | ); | |
| 1117 | return self.trailer_flags.get(trailers_start, name); | |
| 1118 | } | |
| 1119 | ||
| 1120 | pub fn setTrailer(self: *FnProto, comptime name: []const u8, value: TrailerFlags.Field(name)) void { | |
| 1121 | const trailers_start = @alignCast( | |
| 1122 | @alignOf(ParamDecl), | |
| 1123 | @ptrCast([*]u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len, | |
| 1124 | ); | |
| 1125 | self.trailer_flags.set(trailers_start, name, value); | |
| 1126 | } | |
| 1127 | ||
| 1046 | 1128 | /// After this the caller must initialize the params list. |
| 1047 | pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto { | |
| 1048 | const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len)); | |
| 1049 | return @ptrCast(*FnProto, bytes.ptr); | |
| 1129 | pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*FnProto { | |
| 1130 | const trailer_flags = TrailerFlags.init(trailers); | |
| 1131 | const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes( | |
| 1132 | required.params_len, | |
| 1133 | trailer_flags, | |
| 1134 | )); | |
| 1135 | const fn_proto = @ptrCast(*FnProto, bytes.ptr); | |
| 1136 | fn_proto.* = .{ | |
| 1137 | .trailer_flags = trailer_flags, | |
| 1138 | .fn_token = required.fn_token, | |
| 1139 | .params_len = required.params_len, | |
| 1140 | .return_type = required.return_type, | |
| 1141 | }; | |
| 1142 | const trailers_start = @alignCast( | |
| 1143 | @alignOf(ParamDecl), | |
| 1144 | bytes.ptr + @sizeOf(FnProto) + @sizeOf(ParamDecl) * required.params_len, | |
| 1145 | ); | |
| 1146 | trailer_flags.setMany(trailers_start, trailers); | |
| 1147 | return fn_proto; | |
| 1050 | 1148 | } |
| 1051 | 1149 | |
| 1052 | pub fn free(self: *FnProto, allocator: *mem.Allocator) void { | |
| 1053 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)]; | |
| 1150 | pub fn destroy(self: *FnProto, allocator: *mem.Allocator) void { | |
| 1151 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len, self.trailer_flags)]; | |
| 1054 | 1152 | allocator.free(bytes); |
| 1055 | 1153 | } |
| 1056 | 1154 | |
| 1057 | 1155 | pub fn iterate(self: *const FnProto, index: usize) ?*Node { |
| 1058 | 1156 | var i = index; |
| 1059 | 1157 | |
| 1060 | if (self.lib_name) |lib_name| { | |
| 1158 | if (self.getTrailer("lib_name")) |lib_name| { | |
| 1061 | 1159 | if (i < 1) return lib_name; |
| 1062 | 1160 | i -= 1; |
| 1063 | 1161 | } |
| ... | ... | @@ -1066,23 +1164,21 @@ pub const Node = struct { |
| 1066 | 1164 | 0 |
| 1067 | 1165 | else switch (self.paramsConst()[self.params_len - 1].param_type) { |
| 1068 | 1166 | .any_type, .type_expr => self.params_len, |
| 1069 | .var_args => self.params_len - 1, | |
| 1070 | 1167 | }; |
| 1071 | 1168 | if (i < params_len) { |
| 1072 | 1169 | switch (self.paramsConst()[i].param_type) { |
| 1073 | 1170 | .any_type => |n| return n, |
| 1074 | .var_args => unreachable, | |
| 1075 | 1171 | .type_expr => |n| return n, |
| 1076 | 1172 | } |
| 1077 | 1173 | } |
| 1078 | 1174 | i -= params_len; |
| 1079 | 1175 | |
| 1080 | if (self.align_expr) |align_expr| { | |
| 1176 | if (self.getTrailer("align_expr")) |align_expr| { | |
| 1081 | 1177 | if (i < 1) return align_expr; |
| 1082 | 1178 | i -= 1; |
| 1083 | 1179 | } |
| 1084 | 1180 | |
| 1085 | if (self.section_expr) |section_expr| { | |
| 1181 | if (self.getTrailer("section_expr")) |section_expr| { | |
| 1086 | 1182 | if (i < 1) return section_expr; |
| 1087 | 1183 | i -= 1; |
| 1088 | 1184 | } |
| ... | ... | @@ -1095,7 +1191,7 @@ pub const Node = struct { |
| 1095 | 1191 | .Invalid => {}, |
| 1096 | 1192 | } |
| 1097 | 1193 | |
| 1098 | if (self.body_node) |body_node| { | |
| 1194 | if (self.getTrailer("body_node")) |body_node| { | |
| 1099 | 1195 | if (i < 1) return body_node; |
| 1100 | 1196 | i -= 1; |
| 1101 | 1197 | } |
| ... | ... | @@ -1104,14 +1200,14 @@ pub const Node = struct { |
| 1104 | 1200 | } |
| 1105 | 1201 | |
| 1106 | 1202 | pub fn firstToken(self: *const FnProto) TokenIndex { |
| 1107 | if (self.visib_token) |visib_token| return visib_token; | |
| 1108 | if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token; | |
| 1109 | assert(self.lib_name == null); | |
| 1203 | if (self.getTrailer("visib_token")) |visib_token| return visib_token; | |
| 1204 | if (self.getTrailer("extern_export_inline_token")) |extern_export_inline_token| return extern_export_inline_token; | |
| 1205 | assert(self.getTrailer("lib_name") == null); | |
| 1110 | 1206 | return self.fn_token; |
| 1111 | 1207 | } |
| 1112 | 1208 | |
| 1113 | 1209 | pub fn lastToken(self: *const FnProto) TokenIndex { |
| 1114 | if (self.body_node) |body_node| return body_node.lastToken(); | |
| 1210 | if (self.getTrailer("body_node")) |body_node| return body_node.lastToken(); | |
| 1115 | 1211 | switch (self.return_type) { |
| 1116 | 1212 | .Explicit, .InferErrorSet => |node| return node.lastToken(), |
| 1117 | 1213 | .Invalid => |tok| return tok, |
| ... | ... | @@ -1119,17 +1215,17 @@ pub const Node = struct { |
| 1119 | 1215 | } |
| 1120 | 1216 | |
| 1121 | 1217 | pub fn params(self: *FnProto) []ParamDecl { |
| 1122 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto); | |
| 1123 | return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len]; | |
| 1218 | const params_start = @ptrCast([*]u8, self) + @sizeOf(FnProto); | |
| 1219 | return @ptrCast([*]ParamDecl, params_start)[0..self.params_len]; | |
| 1124 | 1220 | } |
| 1125 | 1221 | |
| 1126 | 1222 | pub fn paramsConst(self: *const FnProto) []const ParamDecl { |
| 1127 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto); | |
| 1128 | return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len]; | |
| 1223 | const params_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto); | |
| 1224 | return @ptrCast([*]const ParamDecl, params_start)[0..self.params_len]; | |
| 1129 | 1225 | } |
| 1130 | 1226 | |
| 1131 | fn sizeInBytes(params_len: NodeIndex) usize { | |
| 1132 | return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len); | |
| 1227 | fn sizeInBytes(params_len: NodeIndex, trailer_flags: TrailerFlags) usize { | |
| 1228 | return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len) + trailer_flags.sizeInBytes(); | |
| 1133 | 1229 | } |
| 1134 | 1230 | }; |
| 1135 | 1231 | |
| ... | ... | @@ -2829,6 +2925,9 @@ pub const Node = struct { |
| 2829 | 2925 | } |
| 2830 | 2926 | }; |
| 2831 | 2927 | |
| 2928 | /// TODO remove from the Node base struct | |
| 2929 | /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken() | |
| 2930 | /// and forwards to find same-line doc comments. | |
| 2832 | 2931 | pub const DocComment = struct { |
| 2833 | 2932 | base: Node = Node{ .id = .DocComment }, |
| 2834 | 2933 | /// Points to the first doc comment token. API users are expected to iterate over the |
lib/std/zig/parse.zig+92-100| ... | ... | @@ -150,7 +150,7 @@ const Parser = struct { |
| 150 | 150 | |
| 151 | 151 | const visib_token = p.eatToken(.Keyword_pub); |
| 152 | 152 | |
| 153 | if (p.parseTopLevelDecl() catch |err| switch (err) { | |
| 153 | if (p.parseTopLevelDecl(doc_comments, visib_token) catch |err| switch (err) { | |
| 154 | 154 | error.OutOfMemory => return error.OutOfMemory, |
| 155 | 155 | error.ParseError => { |
| 156 | 156 | p.findNextContainerMember(); |
| ... | ... | @@ -160,30 +160,7 @@ const Parser = struct { |
| 160 | 160 | if (field_state == .seen) { |
| 161 | 161 | field_state = .{ .end = visib_token orelse node.firstToken() }; |
| 162 | 162 | } |
| 163 | switch (node.id) { | |
| 164 | .FnProto => { | |
| 165 | node.cast(Node.FnProto).?.doc_comments = doc_comments; | |
| 166 | node.cast(Node.FnProto).?.visib_token = visib_token; | |
| 167 | }, | |
| 168 | .VarDecl => { | |
| 169 | node.cast(Node.VarDecl).?.doc_comments = doc_comments; | |
| 170 | node.cast(Node.VarDecl).?.visib_token = visib_token; | |
| 171 | }, | |
| 172 | .Use => { | |
| 173 | node.cast(Node.Use).?.doc_comments = doc_comments; | |
| 174 | node.cast(Node.Use).?.visib_token = visib_token; | |
| 175 | }, | |
| 176 | else => unreachable, | |
| 177 | } | |
| 178 | 163 | try list.append(node); |
| 179 | if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| { | |
| 180 | switch (node.id) { | |
| 181 | .FnProto => {}, | |
| 182 | .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment, | |
| 183 | .Use => node.cast(Node.Use).?.doc_comments = appended_comment, | |
| 184 | else => unreachable, | |
| 185 | } | |
| 186 | } | |
| 187 | 164 | continue; |
| 188 | 165 | } |
| 189 | 166 | |
| ... | ... | @@ -417,7 +394,7 @@ const Parser = struct { |
| 417 | 394 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) |
| 418 | 395 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl |
| 419 | 396 | /// / KEYWORD_usingnamespace Expr SEMICOLON |
| 420 | fn parseTopLevelDecl(p: *Parser) !?*Node { | |
| 397 | fn parseTopLevelDecl(p: *Parser, doc_comments: ?*Node.DocComment, visib_token: ?TokenIndex) !?*Node { | |
| 421 | 398 | var lib_name: ?*Node = null; |
| 422 | 399 | const extern_export_inline_token = blk: { |
| 423 | 400 | if (p.eatToken(.Keyword_export)) |token| break :blk token; |
| ... | ... | @@ -430,20 +407,12 @@ const Parser = struct { |
| 430 | 407 | break :blk null; |
| 431 | 408 | }; |
| 432 | 409 | |
| 433 | if (try p.parseFnProto()) |node| { | |
| 434 | const fn_node = node.cast(Node.FnProto).?; | |
| 435 | fn_node.*.extern_export_inline_token = extern_export_inline_token; | |
| 436 | fn_node.*.lib_name = lib_name; | |
| 437 | if (p.eatToken(.Semicolon)) |_| return node; | |
| 438 | ||
| 439 | if (try p.expectNodeRecoverable(parseBlock, .{ | |
| 440 | // since parseBlock only return error.ParseError on | |
| 441 | // a missing '}' we can assume this function was | |
| 442 | // supposed to end here. | |
| 443 | .ExpectedSemiOrLBrace = .{ .token = p.tok_i }, | |
| 444 | })) |body_node| { | |
| 445 | fn_node.body_node = body_node; | |
| 446 | } | |
| 410 | if (try p.parseFnProto(.top_level, .{ | |
| 411 | .doc_comments = doc_comments, | |
| 412 | .visib_token = visib_token, | |
| 413 | .extern_export_inline_token = extern_export_inline_token, | |
| 414 | .lib_name = lib_name, | |
| 415 | })) |node| { | |
| 447 | 416 | return node; |
| 448 | 417 | } |
| 449 | 418 | |
| ... | ... | @@ -460,12 +429,13 @@ const Parser = struct { |
| 460 | 429 | |
| 461 | 430 | const thread_local_token = p.eatToken(.Keyword_threadlocal); |
| 462 | 431 | |
| 463 | if (try p.parseVarDecl()) |node| { | |
| 464 | var var_decl = node.cast(Node.VarDecl).?; | |
| 465 | var_decl.*.thread_local_token = thread_local_token; | |
| 466 | var_decl.*.comptime_token = null; | |
| 467 | var_decl.*.extern_export_token = extern_export_inline_token; | |
| 468 | var_decl.*.lib_name = lib_name; | |
| 432 | if (try p.parseVarDecl(.{ | |
| 433 | .doc_comments = doc_comments, | |
| 434 | .visib_token = visib_token, | |
| 435 | .thread_local_token = thread_local_token, | |
| 436 | .extern_export_token = extern_export_inline_token, | |
| 437 | .lib_name = lib_name, | |
| 438 | })) |node| { | |
| 469 | 439 | return node; |
| 470 | 440 | } |
| 471 | 441 | |
| ... | ... | @@ -485,21 +455,41 @@ const Parser = struct { |
| 485 | 455 | return error.ParseError; |
| 486 | 456 | } |
| 487 | 457 | |
| 488 | return p.parseUse(); | |
| 458 | const use_token = p.eatToken(.Keyword_usingnamespace) orelse return null; | |
| 459 | const expr = try p.expectNode(parseExpr, .{ | |
| 460 | .ExpectedExpr = .{ .token = p.tok_i }, | |
| 461 | }); | |
| 462 | const semicolon_token = try p.expectToken(.Semicolon); | |
| 463 | ||
| 464 | const node = try p.arena.allocator.create(Node.Use); | |
| 465 | node.* = .{ | |
| 466 | .doc_comments = doc_comments orelse try p.parseAppendedDocComment(semicolon_token), | |
| 467 | .visib_token = visib_token, | |
| 468 | .use_token = use_token, | |
| 469 | .expr = expr, | |
| 470 | .semicolon_token = semicolon_token, | |
| 471 | }; | |
| 472 | ||
| 473 | return &node.base; | |
| 489 | 474 | } |
| 490 | 475 | |
| 491 | 476 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr) |
| 492 | fn parseFnProto(p: *Parser) !?*Node { | |
| 477 | fn parseFnProto(p: *Parser, level: enum { top_level, as_type }, fields: struct { | |
| 478 | doc_comments: ?*Node.DocComment = null, | |
| 479 | visib_token: ?TokenIndex = null, | |
| 480 | extern_export_inline_token: ?TokenIndex = null, | |
| 481 | lib_name: ?*Node = null, | |
| 482 | }) !?*Node { | |
| 493 | 483 | // TODO: Remove once extern/async fn rewriting is |
| 494 | var is_async = false; | |
| 495 | var is_extern = false; | |
| 484 | var is_async: ?void = null; | |
| 485 | var is_extern_prototype: ?void = null; | |
| 496 | 486 | const cc_token: ?TokenIndex = blk: { |
| 497 | 487 | if (p.eatToken(.Keyword_extern)) |token| { |
| 498 | is_extern = true; | |
| 488 | is_extern_prototype = {}; | |
| 499 | 489 | break :blk token; |
| 500 | 490 | } |
| 501 | 491 | if (p.eatToken(.Keyword_async)) |token| { |
| 502 | is_async = true; | |
| 492 | is_async = {}; | |
| 503 | 493 | break :blk token; |
| 504 | 494 | } |
| 505 | 495 | break :blk null; |
| ... | ... | @@ -513,6 +503,7 @@ const Parser = struct { |
| 513 | 503 | const lparen = try p.expectToken(.LParen); |
| 514 | 504 | const params = try p.parseParamDeclList(); |
| 515 | 505 | defer p.gpa.free(params); |
| 506 | const var_args_token = p.eatToken(.Ellipsis3); | |
| 516 | 507 | const rparen = try p.expectToken(.RParen); |
| 517 | 508 | const align_expr = try p.parseByteAlign(); |
| 518 | 509 | const section_expr = try p.parseLinkSection(); |
| ... | ... | @@ -535,37 +526,53 @@ const Parser = struct { |
| 535 | 526 | else |
| 536 | 527 | R{ .Explicit = return_type_expr.? }; |
| 537 | 528 | |
| 538 | const var_args_token = if (params.len > 0) blk: { | |
| 539 | const param_type = params[params.len - 1].param_type; | |
| 540 | break :blk if (param_type == .var_args) param_type.var_args else null; | |
| 541 | } else | |
| 542 | null; | |
| 529 | const body_node: ?*Node = switch (level) { | |
| 530 | .top_level => blk: { | |
| 531 | if (p.eatToken(.Semicolon)) |_| { | |
| 532 | break :blk null; | |
| 533 | } | |
| 534 | break :blk try p.expectNodeRecoverable(parseBlock, .{ | |
| 535 | // Since parseBlock only return error.ParseError on | |
| 536 | // a missing '}' we can assume this function was | |
| 537 | // supposed to end here. | |
| 538 | .ExpectedSemiOrLBrace = .{ .token = p.tok_i }, | |
| 539 | }); | |
| 540 | }, | |
| 541 | .as_type => null, | |
| 542 | }; | |
| 543 | 543 | |
| 544 | const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len); | |
| 545 | fn_proto_node.* = .{ | |
| 546 | .doc_comments = null, | |
| 547 | .visib_token = null, | |
| 548 | .fn_token = fn_token, | |
| 549 | .name_token = name_token, | |
| 544 | const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{ | |
| 550 | 545 | .params_len = params.len, |
| 546 | .fn_token = fn_token, | |
| 551 | 547 | .return_type = return_type, |
| 548 | }, .{ | |
| 549 | .doc_comments = fields.doc_comments, | |
| 550 | .visib_token = fields.visib_token, | |
| 551 | .name_token = name_token, | |
| 552 | 552 | .var_args_token = var_args_token, |
| 553 | .extern_export_inline_token = null, | |
| 554 | .body_node = null, | |
| 555 | .lib_name = null, | |
| 553 | .extern_export_inline_token = fields.extern_export_inline_token, | |
| 554 | .body_node = body_node, | |
| 555 | .lib_name = fields.lib_name, | |
| 556 | 556 | .align_expr = align_expr, |
| 557 | 557 | .section_expr = section_expr, |
| 558 | 558 | .callconv_expr = callconv_expr, |
| 559 | .is_extern_prototype = is_extern, | |
| 559 | .is_extern_prototype = is_extern_prototype, | |
| 560 | 560 | .is_async = is_async, |
| 561 | }; | |
| 561 | }); | |
| 562 | 562 | std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params); |
| 563 | 563 | |
| 564 | 564 | return &fn_proto_node.base; |
| 565 | 565 | } |
| 566 | 566 | |
| 567 | 567 | /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON |
| 568 | fn parseVarDecl(p: *Parser) !?*Node { | |
| 568 | fn parseVarDecl(p: *Parser, fields: struct { | |
| 569 | doc_comments: ?*Node.DocComment = null, | |
| 570 | visib_token: ?TokenIndex = null, | |
| 571 | thread_local_token: ?TokenIndex = null, | |
| 572 | extern_export_token: ?TokenIndex = null, | |
| 573 | lib_name: ?*Node = null, | |
| 574 | comptime_token: ?TokenIndex = null, | |
| 575 | }) !?*Node { | |
| 569 | 576 | const mut_token = p.eatToken(.Keyword_const) orelse |
| 570 | 577 | p.eatToken(.Keyword_var) orelse |
| 571 | 578 | return null; |
| ... | ... | @@ -587,23 +594,25 @@ const Parser = struct { |
| 587 | 594 | } else null; |
| 588 | 595 | const semicolon_token = try p.expectToken(.Semicolon); |
| 589 | 596 | |
| 590 | const node = try p.arena.allocator.create(Node.VarDecl); | |
| 591 | node.* = .{ | |
| 592 | .doc_comments = null, | |
| 593 | .visib_token = null, | |
| 594 | .thread_local_token = null, | |
| 597 | const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token); | |
| 598 | ||
| 599 | const node = try Node.VarDecl.create(&p.arena.allocator, .{ | |
| 600 | .mut_token = mut_token, | |
| 595 | 601 | .name_token = name_token, |
| 602 | .semicolon_token = semicolon_token, | |
| 603 | }, .{ | |
| 604 | .doc_comments = doc_comments, | |
| 605 | .visib_token = fields.visib_token, | |
| 606 | .thread_local_token = fields.thread_local_token, | |
| 596 | 607 | .eq_token = eq_token, |
| 597 | .mut_token = mut_token, | |
| 598 | .comptime_token = null, | |
| 599 | .extern_export_token = null, | |
| 600 | .lib_name = null, | |
| 608 | .comptime_token = fields.comptime_token, | |
| 609 | .extern_export_token = fields.extern_export_token, | |
| 610 | .lib_name = fields.lib_name, | |
| 601 | 611 | .type_node = type_node, |
| 602 | 612 | .align_node = align_node, |
| 603 | 613 | .section_node = section_node, |
| 604 | 614 | .init_node = init_node, |
| 605 | .semicolon_token = semicolon_token, | |
| 606 | }; | |
| 615 | }); | |
| 607 | 616 | return &node.base; |
| 608 | 617 | } |
| 609 | 618 | |
| ... | ... | @@ -663,10 +672,9 @@ const Parser = struct { |
| 663 | 672 | fn parseStatement(p: *Parser) Error!?*Node { |
| 664 | 673 | const comptime_token = p.eatToken(.Keyword_comptime); |
| 665 | 674 | |
| 666 | const var_decl_node = try p.parseVarDecl(); | |
| 667 | if (var_decl_node) |node| { | |
| 668 | const var_decl = node.cast(Node.VarDecl).?; | |
| 669 | var_decl.comptime_token = comptime_token; | |
| 675 | if (try p.parseVarDecl(.{ | |
| 676 | .comptime_token = comptime_token, | |
| 677 | })) |node| { | |
| 670 | 678 | return node; |
| 671 | 679 | } |
| 672 | 680 | |
| ... | ... | @@ -1527,7 +1535,7 @@ const Parser = struct { |
| 1527 | 1535 | if (try p.parseAnonLiteral()) |node| return node; |
| 1528 | 1536 | if (try p.parseErrorSetDecl()) |node| return node; |
| 1529 | 1537 | if (try p.parseFloatLiteral()) |node| return node; |
| 1530 | if (try p.parseFnProto()) |node| return node; | |
| 1538 | if (try p.parseFnProto(.as_type, .{})) |node| return node; | |
| 1531 | 1539 | if (try p.parseGroupedExpr()) |node| return node; |
| 1532 | 1540 | if (try p.parseLabeledTypeExpr()) |node| return node; |
| 1533 | 1541 | if (try p.parseIdentifier()) |node| return node; |
| ... | ... | @@ -2028,7 +2036,6 @@ const Parser = struct { |
| 2028 | 2036 | // TODO cast from tuple to error union is broken |
| 2029 | 2037 | const P = Node.FnProto.ParamDecl.ParamType; |
| 2030 | 2038 | if (try p.parseAnyType()) |node| return P{ .any_type = node }; |
| 2031 | if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token }; | |
| 2032 | 2039 | if (try p.parseTypeExpr()) |node| return P{ .type_expr = node }; |
| 2033 | 2040 | return null; |
| 2034 | 2041 | } |
| ... | ... | @@ -3149,21 +3156,6 @@ const Parser = struct { |
| 3149 | 3156 | return &node.base; |
| 3150 | 3157 | } |
| 3151 | 3158 | |
| 3152 | fn parseUse(p: *Parser) !?*Node { | |
| 3153 | const token = p.eatToken(.Keyword_usingnamespace) orelse return null; | |
| 3154 | const node = try p.arena.allocator.create(Node.Use); | |
| 3155 | node.* = .{ | |
| 3156 | .doc_comments = null, | |
| 3157 | .visib_token = null, | |
| 3158 | .use_token = token, | |
| 3159 | .expr = try p.expectNode(parseExpr, .{ | |
| 3160 | .ExpectedExpr = .{ .token = p.tok_i }, | |
| 3161 | }), | |
| 3162 | .semicolon_token = try p.expectToken(.Semicolon), | |
| 3163 | }; | |
| 3164 | return &node.base; | |
| 3165 | } | |
| 3166 | ||
| 3167 | 3159 | /// IfPrefix Body (KEYWORD_else Payload? Body)? |
| 3168 | 3160 | fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node { |
| 3169 | 3161 | const node = (try p.parseIfPrefix()) orelse return null; |
lib/std/zig/parser_test.zig+32-27| ... | ... | @@ -1,4 +1,32 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | test "zig fmt: convert var to anytype" { | |
| 2 | // TODO remove in next release cycle | |
| 3 | try testTransform( | |
| 4 | \\pub fn main( | |
| 5 | \\ a: var, | |
| 6 | \\ bar: var, | |
| 7 | \\) void {} | |
| 8 | , | |
| 9 | \\pub fn main( | |
| 10 | \\ a: anytype, | |
| 11 | \\ bar: anytype, | |
| 12 | \\) void {} | |
| 13 | \\ | |
| 14 | ); | |
| 15 | } | |
| 16 | ||
| 17 | test "zig fmt: noasync to nosuspend" { | |
| 18 | // TODO: remove this | |
| 19 | try testTransform( | |
| 20 | \\pub fn main() void { | |
| 21 | \\ noasync call(); | |
| 22 | \\} | |
| 23 | , | |
| 24 | \\pub fn main() void { | |
| 25 | \\ nosuspend call(); | |
| 26 | \\} | |
| 27 | \\ | |
| 28 | ); | |
| 29 | } | |
| 2 | 30 | |
| 3 | 31 | test "recovery: top level" { |
| 4 | 32 | try testError( |
| ... | ... | @@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" { |
| 3146 | 3174 | ); |
| 3147 | 3175 | } |
| 3148 | 3176 | |
| 3149 | test "zig fmt: noasync to nosuspend" { | |
| 3150 | // TODO: remove this | |
| 3151 | try testTransform( | |
| 3152 | \\pub fn main() void { | |
| 3153 | \\ noasync call(); | |
| 3154 | \\} | |
| 3155 | , | |
| 3156 | \\pub fn main() void { | |
| 3157 | \\ nosuspend call(); | |
| 3158 | \\} | |
| 3159 | \\ | |
| 3160 | ); | |
| 3161 | } | |
| 3162 | ||
| 3163 | 3177 | test "zig fmt: convert async fn into callconv(.Async)" { |
| 3164 | 3178 | try testTransform( |
| 3165 | 3179 | \\async fn foo() void {} |
| ... | ... | @@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" { |
| 3180 | 3194 | ); |
| 3181 | 3195 | } |
| 3182 | 3196 | |
| 3183 | test "zig fmt: convert var to anytype" { | |
| 3184 | // TODO remove in next release cycle | |
| 3185 | try testTransform( | |
| 3186 | \\pub fn main( | |
| 3187 | \\ a: var, | |
| 3188 | \\ bar: var, | |
| 3189 | \\) void {} | |
| 3190 | , | |
| 3191 | \\pub fn main( | |
| 3192 | \\ a: anytype, | |
| 3193 | \\ bar: anytype, | |
| 3194 | \\) void {} | |
| 3197 | test "zig fmt: C var args" { | |
| 3198 | try testCanonical( | |
| 3199 | \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; | |
| 3195 | 3200 | \\ |
| 3196 | 3201 | ); |
| 3197 | 3202 | } |
lib/std/zig/render.zig+52-40| ... | ... | @@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr |
| 227 | 227 | .FnProto => { |
| 228 | 228 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); |
| 229 | 229 | |
| 230 | try renderDocComments(tree, stream, fn_proto, indent, start_col); | |
| 230 | try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col); | |
| 231 | 231 | |
| 232 | if (fn_proto.body_node) |body_node| { | |
| 232 | if (fn_proto.getTrailer("body_node")) |body_node| { | |
| 233 | 233 | try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space); |
| 234 | 234 | try renderExpression(allocator, stream, tree, indent, start_col, body_node, space); |
| 235 | 235 | } else { |
| ... | ... | @@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr |
| 252 | 252 | .VarDecl => { |
| 253 | 253 | const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl); |
| 254 | 254 | |
| 255 | try renderDocComments(tree, stream, var_decl, indent, start_col); | |
| 255 | try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col); | |
| 256 | 256 | try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl); |
| 257 | 257 | }, |
| 258 | 258 | |
| 259 | 259 | .TestDecl => { |
| 260 | 260 | const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); |
| 261 | 261 | |
| 262 | try renderDocComments(tree, stream, test_decl, indent, start_col); | |
| 262 | try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col); | |
| 263 | 263 | try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space); |
| 264 | 264 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space); |
| 265 | 265 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space); |
| ... | ... | @@ -268,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr |
| 268 | 268 | .ContainerField => { |
| 269 | 269 | const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl); |
| 270 | 270 | |
| 271 | try renderDocComments(tree, stream, field, indent, start_col); | |
| 271 | try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col); | |
| 272 | 272 | if (field.comptime_token) |t| { |
| 273 | 273 | try renderToken(tree, stream, t, indent, start_col, .Space); // comptime |
| 274 | 274 | } |
| ... | ... | @@ -1409,7 +1409,7 @@ fn renderExpression( |
| 1409 | 1409 | .ErrorTag => { |
| 1410 | 1410 | const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base); |
| 1411 | 1411 | |
| 1412 | try renderDocComments(tree, stream, tag, indent, start_col); | |
| 1412 | try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col); | |
| 1413 | 1413 | return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name |
| 1414 | 1414 | }, |
| 1415 | 1415 | |
| ... | ... | @@ -1483,23 +1483,23 @@ fn renderExpression( |
| 1483 | 1483 | .FnProto => { |
| 1484 | 1484 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base); |
| 1485 | 1485 | |
| 1486 | if (fn_proto.visib_token) |visib_token_index| { | |
| 1486 | if (fn_proto.getTrailer("visib_token")) |visib_token_index| { | |
| 1487 | 1487 | const visib_token = tree.token_ids[visib_token_index]; |
| 1488 | 1488 | assert(visib_token == .Keyword_pub or visib_token == .Keyword_export); |
| 1489 | 1489 | |
| 1490 | 1490 | try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub |
| 1491 | 1491 | } |
| 1492 | 1492 | |
| 1493 | if (fn_proto.extern_export_inline_token) |extern_export_inline_token| { | |
| 1494 | if (!fn_proto.is_extern_prototype) | |
| 1493 | if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| { | |
| 1494 | if (fn_proto.getTrailer("is_extern_prototype") == null) | |
| 1495 | 1495 | try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline |
| 1496 | 1496 | } |
| 1497 | 1497 | |
| 1498 | if (fn_proto.lib_name) |lib_name| { | |
| 1498 | if (fn_proto.getTrailer("lib_name")) |lib_name| { | |
| 1499 | 1499 | try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); |
| 1500 | 1500 | } |
| 1501 | 1501 | |
| 1502 | const lparen = if (fn_proto.name_token) |name_token| blk: { | |
| 1502 | const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: { | |
| 1503 | 1503 | try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn |
| 1504 | 1504 | try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name |
| 1505 | 1505 | break :blk tree.nextToken(name_token); |
| ... | ... | @@ -1512,11 +1512,11 @@ fn renderExpression( |
| 1512 | 1512 | const rparen = tree.prevToken( |
| 1513 | 1513 | // the first token for the annotation expressions is the left |
| 1514 | 1514 | // parenthesis, hence the need for two prevToken |
| 1515 | if (fn_proto.align_expr) |align_expr| | |
| 1515 | if (fn_proto.getTrailer("align_expr")) |align_expr| | |
| 1516 | 1516 | tree.prevToken(tree.prevToken(align_expr.firstToken())) |
| 1517 | else if (fn_proto.section_expr) |section_expr| | |
| 1517 | else if (fn_proto.getTrailer("section_expr")) |section_expr| | |
| 1518 | 1518 | tree.prevToken(tree.prevToken(section_expr.firstToken())) |
| 1519 | else if (fn_proto.callconv_expr) |callconv_expr| | |
| 1519 | else if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| | |
| 1520 | 1520 | tree.prevToken(tree.prevToken(callconv_expr.firstToken())) |
| 1521 | 1521 | else switch (fn_proto.return_type) { |
| 1522 | 1522 | .Explicit => |node| node.firstToken(), |
| ... | ... | @@ -1537,11 +1537,14 @@ fn renderExpression( |
| 1537 | 1537 | for (fn_proto.params()) |param_decl, i| { |
| 1538 | 1538 | try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None); |
| 1539 | 1539 | |
| 1540 | if (i + 1 < fn_proto.params_len) { | |
| 1540 | if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) { | |
| 1541 | 1541 | const comma = tree.nextToken(param_decl.lastToken()); |
| 1542 | 1542 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , |
| 1543 | 1543 | } |
| 1544 | 1544 | } |
| 1545 | if (fn_proto.getTrailer("var_args_token")) |var_args_token| { | |
| 1546 | try renderToken(tree, stream, var_args_token, indent, start_col, Space.None); | |
| 1547 | } | |
| 1545 | 1548 | } else { |
| 1546 | 1549 | // one param per line |
| 1547 | 1550 | const new_indent = indent + indent_delta; |
| ... | ... | @@ -1551,12 +1554,16 @@ fn renderExpression( |
| 1551 | 1554 | try stream.writeByteNTimes(' ', new_indent); |
| 1552 | 1555 | try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma); |
| 1553 | 1556 | } |
| 1557 | if (fn_proto.getTrailer("var_args_token")) |var_args_token| { | |
| 1558 | try stream.writeByteNTimes(' ', new_indent); | |
| 1559 | try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma); | |
| 1560 | } | |
| 1554 | 1561 | try stream.writeByteNTimes(' ', indent); |
| 1555 | 1562 | } |
| 1556 | 1563 | |
| 1557 | 1564 | try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // ) |
| 1558 | 1565 | |
| 1559 | if (fn_proto.align_expr) |align_expr| { | |
| 1566 | if (fn_proto.getTrailer("align_expr")) |align_expr| { | |
| 1560 | 1567 | const align_rparen = tree.nextToken(align_expr.lastToken()); |
| 1561 | 1568 | const align_lparen = tree.prevToken(align_expr.firstToken()); |
| 1562 | 1569 | const align_kw = tree.prevToken(align_lparen); |
| ... | ... | @@ -1567,7 +1574,7 @@ fn renderExpression( |
| 1567 | 1574 | try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // ) |
| 1568 | 1575 | } |
| 1569 | 1576 | |
| 1570 | if (fn_proto.section_expr) |section_expr| { | |
| 1577 | if (fn_proto.getTrailer("section_expr")) |section_expr| { | |
| 1571 | 1578 | const section_rparen = tree.nextToken(section_expr.lastToken()); |
| 1572 | 1579 | const section_lparen = tree.prevToken(section_expr.firstToken()); |
| 1573 | 1580 | const section_kw = tree.prevToken(section_lparen); |
| ... | ... | @@ -1578,7 +1585,7 @@ fn renderExpression( |
| 1578 | 1585 | try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // ) |
| 1579 | 1586 | } |
| 1580 | 1587 | |
| 1581 | if (fn_proto.callconv_expr) |callconv_expr| { | |
| 1588 | if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| { | |
| 1582 | 1589 | const callconv_rparen = tree.nextToken(callconv_expr.lastToken()); |
| 1583 | 1590 | const callconv_lparen = tree.prevToken(callconv_expr.firstToken()); |
| 1584 | 1591 | const callconv_kw = tree.prevToken(callconv_lparen); |
| ... | ... | @@ -1587,9 +1594,9 @@ fn renderExpression( |
| 1587 | 1594 | try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // ( |
| 1588 | 1595 | try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None); |
| 1589 | 1596 | try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // ) |
| 1590 | } else if (fn_proto.is_extern_prototype) { | |
| 1597 | } else if (fn_proto.getTrailer("is_extern_prototype") != null) { | |
| 1591 | 1598 | try stream.writeAll("callconv(.C) "); |
| 1592 | } else if (fn_proto.is_async) { | |
| 1599 | } else if (fn_proto.getTrailer("is_async") != null) { | |
| 1593 | 1600 | try stream.writeAll("callconv(.Async) "); |
| 1594 | 1601 | } |
| 1595 | 1602 | |
| ... | ... | @@ -2177,64 +2184,69 @@ fn renderVarDecl( |
| 2177 | 2184 | start_col: *usize, |
| 2178 | 2185 | var_decl: *ast.Node.VarDecl, |
| 2179 | 2186 | ) (@TypeOf(stream).Error || Error)!void { |
| 2180 | if (var_decl.visib_token) |visib_token| { | |
| 2187 | if (var_decl.getTrailer("visib_token")) |visib_token| { | |
| 2181 | 2188 | try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub |
| 2182 | 2189 | } |
| 2183 | 2190 | |
| 2184 | if (var_decl.extern_export_token) |extern_export_token| { | |
| 2191 | if (var_decl.getTrailer("extern_export_token")) |extern_export_token| { | |
| 2185 | 2192 | try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern |
| 2186 | 2193 | |
| 2187 | if (var_decl.lib_name) |lib_name| { | |
| 2194 | if (var_decl.getTrailer("lib_name")) |lib_name| { | |
| 2188 | 2195 | try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib" |
| 2189 | 2196 | } |
| 2190 | 2197 | } |
| 2191 | 2198 | |
| 2192 | if (var_decl.comptime_token) |comptime_token| { | |
| 2199 | if (var_decl.getTrailer("comptime_token")) |comptime_token| { | |
| 2193 | 2200 | try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime |
| 2194 | 2201 | } |
| 2195 | 2202 | |
| 2196 | if (var_decl.thread_local_token) |thread_local_token| { | |
| 2203 | if (var_decl.getTrailer("thread_local_token")) |thread_local_token| { | |
| 2197 | 2204 | try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal |
| 2198 | 2205 | } |
| 2199 | 2206 | try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var |
| 2200 | 2207 | |
| 2201 | const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or | |
| 2202 | var_decl.section_node != null or var_decl.init_node != null)) Space.Space else Space.None; | |
| 2208 | const name_space = if (var_decl.getTrailer("type_node") == null and | |
| 2209 | (var_decl.getTrailer("align_node") != null or | |
| 2210 | var_decl.getTrailer("section_node") != null or | |
| 2211 | var_decl.getTrailer("init_node") != null)) | |
| 2212 | Space.Space | |
| 2213 | else | |
| 2214 | Space.None; | |
| 2203 | 2215 | try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space); |
| 2204 | 2216 | |
| 2205 | if (var_decl.type_node) |type_node| { | |
| 2217 | if (var_decl.getTrailer("type_node")) |type_node| { | |
| 2206 | 2218 | try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space); |
| 2207 | const s = if (var_decl.align_node != null or | |
| 2208 | var_decl.section_node != null or | |
| 2209 | var_decl.init_node != null) Space.Space else Space.None; | |
| 2219 | const s = if (var_decl.getTrailer("align_node") != null or | |
| 2220 | var_decl.getTrailer("section_node") != null or | |
| 2221 | var_decl.getTrailer("init_node") != null) Space.Space else Space.None; | |
| 2210 | 2222 | try renderExpression(allocator, stream, tree, indent, start_col, type_node, s); |
| 2211 | 2223 | } |
| 2212 | 2224 | |
| 2213 | if (var_decl.align_node) |align_node| { | |
| 2225 | if (var_decl.getTrailer("align_node")) |align_node| { | |
| 2214 | 2226 | const lparen = tree.prevToken(align_node.firstToken()); |
| 2215 | 2227 | const align_kw = tree.prevToken(lparen); |
| 2216 | 2228 | const rparen = tree.nextToken(align_node.lastToken()); |
| 2217 | 2229 | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align |
| 2218 | 2230 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( |
| 2219 | 2231 | try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None); |
| 2220 | const s = if (var_decl.section_node != null or var_decl.init_node != null) Space.Space else Space.None; | |
| 2232 | const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None; | |
| 2221 | 2233 | try renderToken(tree, stream, rparen, indent, start_col, s); // ) |
| 2222 | 2234 | } |
| 2223 | 2235 | |
| 2224 | if (var_decl.section_node) |section_node| { | |
| 2236 | if (var_decl.getTrailer("section_node")) |section_node| { | |
| 2225 | 2237 | const lparen = tree.prevToken(section_node.firstToken()); |
| 2226 | 2238 | const section_kw = tree.prevToken(lparen); |
| 2227 | 2239 | const rparen = tree.nextToken(section_node.lastToken()); |
| 2228 | 2240 | try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection |
| 2229 | 2241 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( |
| 2230 | 2242 | try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None); |
| 2231 | const s = if (var_decl.init_node != null) Space.Space else Space.None; | |
| 2243 | const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None; | |
| 2232 | 2244 | try renderToken(tree, stream, rparen, indent, start_col, s); // ) |
| 2233 | 2245 | } |
| 2234 | 2246 | |
| 2235 | if (var_decl.init_node) |init_node| { | |
| 2247 | if (var_decl.getTrailer("init_node")) |init_node| { | |
| 2236 | 2248 | const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space; |
| 2237 | try renderToken(tree, stream, var_decl.eq_token.?, indent, start_col, s); // = | |
| 2249 | try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // = | |
| 2238 | 2250 | try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None); |
| 2239 | 2251 | } |
| 2240 | 2252 | |
| ... | ... | @@ -2250,7 +2262,7 @@ fn renderParamDecl( |
| 2250 | 2262 | param_decl: ast.Node.FnProto.ParamDecl, |
| 2251 | 2263 | space: Space, |
| 2252 | 2264 | ) (@TypeOf(stream).Error || Error)!void { |
| 2253 | try renderDocComments(tree, stream, param_decl, indent, start_col); | |
| 2265 | try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col); | |
| 2254 | 2266 | |
| 2255 | 2267 | if (param_decl.comptime_token) |comptime_token| { |
| 2256 | 2268 | try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); |
| ... | ... | @@ -2263,7 +2275,6 @@ fn renderParamDecl( |
| 2263 | 2275 | try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // : |
| 2264 | 2276 | } |
| 2265 | 2277 | switch (param_decl.param_type) { |
| 2266 | .var_args => |token| try renderToken(tree, stream, token, indent, start_col, space), | |
| 2267 | 2278 | .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space), |
| 2268 | 2279 | } |
| 2269 | 2280 | } |
| ... | ... | @@ -2519,10 +2530,11 @@ fn renderDocComments( |
| 2519 | 2530 | tree: *ast.Tree, |
| 2520 | 2531 | stream: anytype, |
| 2521 | 2532 | node: anytype, |
| 2533 | doc_comments: ?*ast.Node.DocComment, | |
| 2522 | 2534 | indent: usize, |
| 2523 | 2535 | start_col: *usize, |
| 2524 | 2536 | ) (@TypeOf(stream).Error || Error)!void { |
| 2525 | const comment = node.doc_comments orelse return; | |
| 2537 | const comment = doc_comments orelse return; | |
| 2526 | 2538 | return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col); |
| 2527 | 2539 | } |
| 2528 | 2540 |
src-self-hosted/Module.zig+12-10| ... | ... | @@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1130 | 1130 | }; |
| 1131 | 1131 | defer fn_type_scope.instructions.deinit(self.gpa); |
| 1132 | 1132 | |
| 1133 | const body_node = fn_proto.body_node orelse | |
| 1133 | const body_node = fn_proto.getTrailer("body_node") orelse | |
| 1134 | 1134 | return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); |
| 1135 | 1135 | |
| 1136 | 1136 | const param_decls = fn_proto.params(); |
| ... | ... | @@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1138 | 1138 | for (param_decls) |param_decl, i| { |
| 1139 | 1139 | const param_type_node = switch (param_decl.param_type) { |
| 1140 | 1140 | .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}), |
| 1141 | .var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}), | |
| 1142 | 1141 | .type_expr => |node| node, |
| 1143 | 1142 | }; |
| 1144 | 1143 | param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node); |
| 1145 | 1144 | } |
| 1146 | if (fn_proto.lib_name) |lib_name| { | |
| 1145 | if (fn_proto.getTrailer("var_args_token")) |var_args_token| { | |
| 1146 | return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{}); | |
| 1147 | } | |
| 1148 | if (fn_proto.getTrailer("lib_name")) |lib_name| { | |
| 1147 | 1149 | return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{}); |
| 1148 | 1150 | } |
| 1149 | if (fn_proto.align_expr) |align_expr| { | |
| 1151 | if (fn_proto.getTrailer("align_expr")) |align_expr| { | |
| 1150 | 1152 | return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{}); |
| 1151 | 1153 | } |
| 1152 | if (fn_proto.section_expr) |sect_expr| { | |
| 1154 | if (fn_proto.getTrailer("section_expr")) |sect_expr| { | |
| 1153 | 1155 | return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{}); |
| 1154 | 1156 | } |
| 1155 | if (fn_proto.callconv_expr) |callconv_expr| { | |
| 1157 | if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| { | |
| 1156 | 1158 | return self.failNode( |
| 1157 | 1159 | &fn_type_scope.base, |
| 1158 | 1160 | callconv_expr, |
| ... | ... | @@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1265 | 1267 | self.bin_file.freeDecl(decl); |
| 1266 | 1268 | } |
| 1267 | 1269 | |
| 1268 | if (fn_proto.extern_export_inline_token) |maybe_export_token| { | |
| 1270 | if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| { | |
| 1269 | 1271 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1270 | 1272 | const export_src = tree.token_locs[maybe_export_token].start; |
| 1271 | const name_loc = tree.token_locs[fn_proto.name_token.?]; | |
| 1273 | const name_loc = tree.token_locs[fn_proto.getTrailer("name_token").?]; | |
| 1272 | 1274 | const name = tree.tokenSliceLoc(name_loc); |
| 1273 | 1275 | // The scope needs to have the decl in it. |
| 1274 | 1276 | try self.analyzeExport(&block_scope.base, export_src, name, decl); |
| ... | ... | @@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1867 | 1869 | for (decls) |src_decl, decl_i| { |
| 1868 | 1870 | if (src_decl.cast(ast.Node.FnProto)) |fn_proto| { |
| 1869 | 1871 | // We will create a Decl for it regardless of analysis status. |
| 1870 | const name_tok = fn_proto.name_token orelse { | |
| 1872 | const name_tok = fn_proto.getTrailer("name_token") orelse { | |
| 1871 | 1873 | @panic("TODO missing function name"); |
| 1872 | 1874 | }; |
| 1873 | 1875 | |
| ... | ... | @@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1893 | 1895 | } else { |
| 1894 | 1896 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); |
| 1895 | 1897 | root_scope.decls.appendAssumeCapacity(new_decl); |
| 1896 | if (fn_proto.extern_export_inline_token) |maybe_export_token| { | |
| 1898 | if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| { | |
| 1897 | 1899 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1898 | 1900 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); |
| 1899 | 1901 | } |
src-self-hosted/translate_c.zig+279-183| ... | ... | @@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 586 | 586 | for (proto_node.params()) |*param, i| { |
| 587 | 587 | const param_name = if (param.name_token) |name_tok| |
| 588 | 588 | tokenSlice(c, name_tok) |
| 589 | else if (param.param_type == .var_args) { | |
| 590 | assert(i + 1 == proto_node.params_len); | |
| 591 | proto_node.params_len -= 1; | |
| 592 | break; | |
| 593 | } else | |
| 589 | else | |
| 594 | 590 | return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name}); |
| 595 | 591 | |
| 596 | 592 | const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id); |
| ... | ... | @@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 602 | 598 | if (!is_const) { |
| 603 | 599 | const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name}); |
| 604 | 600 | const arg_name = try block_scope.makeMangledName(c, bare_arg_name); |
| 605 | const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name); | |
| 606 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 607 | node.init_node = try transCreateNodeIdentifier(c, arg_name); | |
| 608 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 601 | ||
| 602 | const mut_tok = try appendToken(c, .Keyword_var, "var"); | |
| 603 | const name_tok = try appendIdentifier(c, mangled_param_name); | |
| 604 | const eq_token = try appendToken(c, .Equal, "="); | |
| 605 | const init_node = try transCreateNodeIdentifier(c, arg_name); | |
| 606 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 607 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 608 | .mut_token = mut_tok, | |
| 609 | .name_token = name_tok, | |
| 610 | .semicolon_token = semicolon_token, | |
| 611 | }, .{ | |
| 612 | .eq_token = eq_token, | |
| 613 | .init_node = init_node, | |
| 614 | }); | |
| 609 | 615 | try block_scope.statements.append(&node.base); |
| 610 | 616 | param.name_token = try appendIdentifier(c, arg_name); |
| 611 | 617 | _ = try appendToken(c, .Colon, ":"); |
| ... | ... | @@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 622 | 628 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), |
| 623 | 629 | }; |
| 624 | 630 | const body_node = try block_scope.complete(rp.c); |
| 625 | proto_node.body_node = &body_node.base; | |
| 631 | proto_node.setTrailer("body_node", &body_node.base); | |
| 626 | 632 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 627 | 633 | } |
| 628 | 634 | |
| ... | ... | @@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 725 | 731 | break :blk null; |
| 726 | 732 | }; |
| 727 | 733 | |
| 728 | const node = try c.arena.create(ast.Node.VarDecl); | |
| 729 | node.* = .{ | |
| 730 | .doc_comments = null, | |
| 734 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 735 | .name_token = name_tok, | |
| 736 | .mut_token = mut_tok, | |
| 737 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | |
| 738 | }, .{ | |
| 731 | 739 | .visib_token = visib_tok, |
| 732 | 740 | .thread_local_token = thread_local_token, |
| 733 | .name_token = name_tok, | |
| 734 | 741 | .eq_token = eq_tok, |
| 735 | .mut_token = mut_tok, | |
| 736 | .comptime_token = null, | |
| 737 | 742 | .extern_export_token = extern_tok, |
| 738 | .lib_name = null, | |
| 739 | 743 | .type_node = type_node, |
| 740 | 744 | .align_node = align_expr, |
| 741 | 745 | .section_node = linksection_expr, |
| 742 | 746 | .init_node = init_node, |
| 743 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | |
| 744 | }; | |
| 747 | }); | |
| 745 | 748 | return addTopLevelDecl(c, checked_name, &node.base); |
| 746 | 749 | } |
| 747 | 750 | |
| ... | ... | @@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l |
| 795 | 798 | |
| 796 | 799 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name); |
| 797 | 800 | const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null; |
| 798 | try addTopLevelDecl(c, checked_name, &node.base); | |
| 801 | try addTopLevelDecl(c, checked_name, node); | |
| 799 | 802 | return transCreateNodeIdentifier(c, checked_name); |
| 800 | 803 | } |
| 801 | 804 | |
| 802 | fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl { | |
| 803 | const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name); | |
| 804 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 805 | ||
| 805 | fn transCreateNodeTypedef( | |
| 806 | rp: RestorePoint, | |
| 807 | typedef_decl: *const ZigClangTypedefNameDecl, | |
| 808 | toplevel: bool, | |
| 809 | checked_name: []const u8, | |
| 810 | ) Error!?*ast.Node { | |
| 811 | const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null; | |
| 812 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 813 | const name_tok = try appendIdentifier(rp.c, checked_name); | |
| 814 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 806 | 815 | const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); |
| 807 | 816 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); |
| 808 | node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { | |
| 817 | const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { | |
| 809 | 818 | error.UnsupportedType => { |
| 810 | 819 | try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{}); |
| 811 | 820 | return null; |
| 812 | 821 | }, |
| 813 | 822 | error.OutOfMemory => |e| return e, |
| 814 | 823 | }; |
| 824 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 815 | 825 | |
| 816 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 817 | return node; | |
| 826 | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 827 | .name_token = name_tok, | |
| 828 | .mut_token = mut_tok, | |
| 829 | .semicolon_token = semicolon_token, | |
| 830 | }, .{ | |
| 831 | .visib_token = visib_tok, | |
| 832 | .eq_token = eq_token, | |
| 833 | .init_node = init_node, | |
| 834 | }); | |
| 835 | return &node.base; | |
| 818 | 836 | } |
| 819 | 837 | |
| 820 | 838 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { |
| ... | ... | @@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 847 | 865 | const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name }); |
| 848 | 866 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| 849 | 867 | |
| 850 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | |
| 868 | const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null; | |
| 869 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 870 | const name_tok = try appendIdentifier(c, name); | |
| 851 | 871 | |
| 852 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 872 | const eq_token = try appendToken(c, .Equal, "="); | |
| 853 | 873 | |
| 854 | 874 | var semicolon: ast.TokenIndex = undefined; |
| 855 | node.init_node = blk: { | |
| 875 | const init_node = blk: { | |
| 856 | 876 | const rp = makeRestorePoint(c); |
| 857 | 877 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { |
| 858 | 878 | const opaque = try transCreateNodeOpaqueType(c); |
| ... | ... | @@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 959 | 979 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 960 | 980 | break :blk &container_node.base; |
| 961 | 981 | }; |
| 962 | node.semicolon_token = semicolon; | |
| 982 | ||
| 983 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 984 | .name_token = name_tok, | |
| 985 | .mut_token = mut_tok, | |
| 986 | .semicolon_token = semicolon, | |
| 987 | }, .{ | |
| 988 | .visib_token = visib_tok, | |
| 989 | .eq_token = eq_token, | |
| 990 | .init_node = init_node, | |
| 991 | }); | |
| 963 | 992 | |
| 964 | 993 | try addTopLevelDecl(c, name, &node.base); |
| 965 | 994 | if (!is_unnamed) |
| ... | ... | @@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 982 | 1011 | |
| 983 | 1012 | const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name}); |
| 984 | 1013 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); |
| 985 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | |
| 986 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 987 | 1014 | |
| 988 | node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { | |
| 1015 | const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null; | |
| 1016 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 1017 | const name_tok = try appendIdentifier(c, name); | |
| 1018 | const eq_token = try appendToken(c, .Equal, "="); | |
| 1019 | ||
| 1020 | const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { | |
| 989 | 1021 | var pure_enum = true; |
| 990 | 1022 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 991 | 1023 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| ... | ... | @@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1063 | 1095 | |
| 1064 | 1096 | // In C each enum value is in the global namespace. So we put them there too. |
| 1065 | 1097 | // At this point we can rely on the enum emitting successfully. |
| 1066 | const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); | |
| 1067 | tld_node.eq_token = try appendToken(c, .Equal, "="); | |
| 1098 | const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 1099 | const tld_mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 1100 | const tld_name_tok = try appendIdentifier(c, enum_val_name); | |
| 1101 | const tld_eq_token = try appendToken(c, .Equal, "="); | |
| 1068 | 1102 | const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1); |
| 1069 | 1103 | const enum_ident = try transCreateNodeIdentifier(c, name); |
| 1070 | 1104 | const period_tok = try appendToken(c, .Period, "."); |
| ... | ... | @@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1078 | 1112 | }; |
| 1079 | 1113 | cast_node.params()[0] = &field_access_node.base; |
| 1080 | 1114 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1081 | tld_node.init_node = &cast_node.base; | |
| 1082 | tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1115 | const tld_init_node = &cast_node.base; | |
| 1116 | const tld_semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1117 | const tld_node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 1118 | .name_token = tld_name_tok, | |
| 1119 | .mut_token = tld_mut_tok, | |
| 1120 | .semicolon_token = tld_semicolon_token, | |
| 1121 | }, .{ | |
| 1122 | .visib_token = tld_visib_tok, | |
| 1123 | .eq_token = tld_eq_token, | |
| 1124 | .init_node = tld_init_node, | |
| 1125 | }); | |
| 1083 | 1126 | try addTopLevelDecl(c, field_name, &tld_node.base); |
| 1084 | 1127 | } |
| 1085 | 1128 | // make non exhaustive |
| ... | ... | @@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1109 | 1152 | } else |
| 1110 | 1153 | try transCreateNodeOpaqueType(c); |
| 1111 | 1154 | |
| 1112 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1155 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1156 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 1157 | .name_token = name_tok, | |
| 1158 | .mut_token = mut_tok, | |
| 1159 | .semicolon_token = semicolon_token, | |
| 1160 | }, .{ | |
| 1161 | .visib_token = visib_tok, | |
| 1162 | .eq_token = eq_token, | |
| 1163 | .init_node = init_node, | |
| 1164 | }); | |
| 1113 | 1165 | |
| 1114 | 1166 | try addTopLevelDecl(c, name, &node.base); |
| 1115 | 1167 | if (!is_unnamed) |
| ... | ... | @@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1118 | 1170 | } |
| 1119 | 1171 | |
| 1120 | 1172 | fn createAlias(c: *Context, alias: anytype) !void { |
| 1121 | const node = try transCreateNodeVarDecl(c, true, true, alias.alias); | |
| 1122 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 1123 | node.init_node = try transCreateNodeIdentifier(c, alias.name); | |
| 1124 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1173 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 1174 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 1175 | const name_tok = try appendIdentifier(c, alias.alias); | |
| 1176 | const eq_token = try appendToken(c, .Equal, "="); | |
| 1177 | const init_node = try transCreateNodeIdentifier(c, alias.name); | |
| 1178 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1179 | ||
| 1180 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 1181 | .name_token = name_tok, | |
| 1182 | .mut_token = mut_tok, | |
| 1183 | .semicolon_token = semicolon_token, | |
| 1184 | }, .{ | |
| 1185 | .visib_token = visib_tok, | |
| 1186 | .eq_token = eq_token, | |
| 1187 | .init_node = init_node, | |
| 1188 | }); | |
| 1125 | 1189 | return addTopLevelDecl(c, alias.alias, &node.base); |
| 1126 | 1190 | } |
| 1127 | 1191 | |
| ... | ... | @@ -1461,13 +1525,17 @@ fn transDeclStmtOne( |
| 1461 | 1525 | @ptrCast(*const ZigClangNamedDecl, var_decl), |
| 1462 | 1526 | )); |
| 1463 | 1527 | const mangled_name = try block_scope.makeMangledName(c, name); |
| 1464 | const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name); | |
| 1528 | const mut_tok = if (ZigClangQualType_isConstQualified(qual_type)) | |
| 1529 | try appendToken(c, .Keyword_const, "const") | |
| 1530 | else | |
| 1531 | try appendToken(c, .Keyword_var, "var"); | |
| 1532 | const name_tok = try appendIdentifier(c, mangled_name); | |
| 1465 | 1533 | |
| 1466 | 1534 | _ = try appendToken(c, .Colon, ":"); |
| 1467 | 1535 | const loc = ZigClangDecl_getLocation(decl); |
| 1468 | node.type_node = try transQualType(rp, qual_type, loc); | |
| 1536 | const type_node = try transQualType(rp, qual_type, loc); | |
| 1469 | 1537 | |
| 1470 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 1538 | const eq_token = try appendToken(c, .Equal, "="); | |
| 1471 | 1539 | var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 1472 | 1540 | try transExprCoercing(rp, scope, expr, .used, .r_value) |
| 1473 | 1541 | else |
| ... | ... | @@ -1478,8 +1546,17 @@ fn transDeclStmtOne( |
| 1478 | 1546 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1479 | 1547 | init_node = &builtin_node.base; |
| 1480 | 1548 | } |
| 1481 | node.init_node = init_node; | |
| 1482 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1549 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1550 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 1551 | .name_token = name_tok, | |
| 1552 | .mut_token = mut_tok, | |
| 1553 | .semicolon_token = semicolon_token, | |
| 1554 | }, .{ | |
| 1555 | .thread_local_token = thread_local_token, | |
| 1556 | .eq_token = eq_token, | |
| 1557 | .type_node = type_node, | |
| 1558 | .init_node = init_node, | |
| 1559 | }); | |
| 1483 | 1560 | return &node.base; |
| 1484 | 1561 | }, |
| 1485 | 1562 | .Typedef => { |
| ... | ... | @@ -1494,7 +1571,7 @@ fn transDeclStmtOne( |
| 1494 | 1571 | const mangled_name = try block_scope.makeMangledName(c, name); |
| 1495 | 1572 | const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse |
| 1496 | 1573 | return error.UnsupportedTranslation; |
| 1497 | return &node.base; | |
| 1574 | return node; | |
| 1498 | 1575 | }, |
| 1499 | 1576 | else => |kind| return revertAndWarn( |
| 1500 | 1577 | rp, |
| ... | ... | @@ -3105,12 +3182,21 @@ fn transCreatePreCrement( |
| 3105 | 3182 | defer block_scope.deinit(); |
| 3106 | 3183 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3107 | 3184 | |
| 3108 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | |
| 3109 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3185 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 3186 | const name_tok = try appendIdentifier(rp.c, ref); | |
| 3187 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3110 | 3188 | const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3111 | 3189 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3112 | node.init_node = &rhs_node.base; | |
| 3113 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3190 | const init_node = &rhs_node.base; | |
| 3191 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3192 | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 3193 | .name_token = name_tok, | |
| 3194 | .mut_token = mut_tok, | |
| 3195 | .semicolon_token = semicolon_token, | |
| 3196 | }, .{ | |
| 3197 | .eq_token = eq_token, | |
| 3198 | .init_node = init_node, | |
| 3199 | }); | |
| 3114 | 3200 | try block_scope.statements.append(&node.base); |
| 3115 | 3201 | |
| 3116 | 3202 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| ... | ... | @@ -3171,12 +3257,21 @@ fn transCreatePostCrement( |
| 3171 | 3257 | defer block_scope.deinit(); |
| 3172 | 3258 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3173 | 3259 | |
| 3174 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | |
| 3175 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3260 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 3261 | const name_tok = try appendIdentifier(rp.c, ref); | |
| 3262 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3176 | 3263 | const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3177 | 3264 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3178 | node.init_node = &rhs_node.base; | |
| 3179 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3265 | const init_node = &rhs_node.base; | |
| 3266 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3267 | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 3268 | .name_token = name_tok, | |
| 3269 | .mut_token = mut_tok, | |
| 3270 | .semicolon_token = semicolon_token, | |
| 3271 | }, .{ | |
| 3272 | .eq_token = eq_token, | |
| 3273 | .init_node = init_node, | |
| 3274 | }); | |
| 3180 | 3275 | try block_scope.statements.append(&node.base); |
| 3181 | 3276 | |
| 3182 | 3277 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| ... | ... | @@ -3184,10 +3279,19 @@ fn transCreatePostCrement( |
| 3184 | 3279 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3185 | 3280 | |
| 3186 | 3281 | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); |
| 3187 | const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | |
| 3188 | tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3189 | tmp_node.init_node = ref_node; | |
| 3190 | tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3282 | const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 3283 | const tmp_name_tok = try appendIdentifier(rp.c, tmp); | |
| 3284 | const tmp_eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3285 | const tmp_init_node = ref_node; | |
| 3286 | const tmp_semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3287 | const tmp_node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 3288 | .name_token = tmp_name_tok, | |
| 3289 | .mut_token = tmp_mut_tok, | |
| 3290 | .semicolon_token = semicolon_token, | |
| 3291 | }, .{ | |
| 3292 | .eq_token = tmp_eq_token, | |
| 3293 | .init_node = tmp_init_node, | |
| 3294 | }); | |
| 3191 | 3295 | try block_scope.statements.append(&tmp_node.base); |
| 3192 | 3296 | |
| 3193 | 3297 | const token = try appendToken(rp.c, op_tok_id, bytes); |
| ... | ... | @@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign( |
| 3325 | 3429 | defer block_scope.deinit(); |
| 3326 | 3430 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3327 | 3431 | |
| 3328 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | |
| 3329 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3432 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 3433 | const name_tok = try appendIdentifier(rp.c, ref); | |
| 3434 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3330 | 3435 | const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3331 | 3436 | addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3332 | node.init_node = &addr_node.base; | |
| 3333 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3437 | const init_node = &addr_node.base; | |
| 3438 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3439 | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 3440 | .name_token = name_tok, | |
| 3441 | .mut_token = mut_tok, | |
| 3442 | .semicolon_token = semicolon_token, | |
| 3443 | }, .{ | |
| 3444 | .eq_token = eq_token, | |
| 3445 | .init_node = init_node, | |
| 3446 | }); | |
| 3334 | 3447 | try block_scope.statements.append(&node.base); |
| 3335 | 3448 | |
| 3336 | 3449 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| ... | ... | @@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign( |
| 3375 | 3488 | const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false); |
| 3376 | 3489 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3377 | 3490 | |
| 3378 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3379 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); | |
| 3491 | const ass_eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3492 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false); | |
| 3380 | 3493 | try block_scope.statements.append(assign); |
| 3381 | 3494 | } |
| 3382 | 3495 | |
| ... | ... | @@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const |
| 3494 | 3607 | defer block_scope.deinit(); |
| 3495 | 3608 | |
| 3496 | 3609 | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); |
| 3497 | const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name); | |
| 3498 | tmp_var.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3499 | tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); | |
| 3500 | tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3610 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 3611 | const name_tok = try appendIdentifier(rp.c, mangled_name); | |
| 3612 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3613 | const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); | |
| 3614 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 3615 | const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 3616 | .name_token = name_tok, | |
| 3617 | .mut_token = mut_tok, | |
| 3618 | .semicolon_token = semicolon_token, | |
| 3619 | }, .{ | |
| 3620 | .eq_token = eq_token, | |
| 3621 | .init_node = init_node, | |
| 3622 | }); | |
| 3501 | 3623 | try block_scope.statements.append(&tmp_var.base); |
| 3502 | 3624 | |
| 3503 | 3625 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| ... | ... | @@ -3932,9 +4054,9 @@ fn transCreateNodeAssign( |
| 3932 | 4054 | defer block_scope.deinit(); |
| 3933 | 4055 | |
| 3934 | 4056 | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); |
| 3935 | ||
| 3936 | const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | |
| 3937 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 4057 | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); | |
| 4058 | const name_tok = try appendIdentifier(rp.c, tmp); | |
| 4059 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3938 | 4060 | var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value); |
| 3939 | 4061 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { |
| 3940 | 4062 | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| ... | ... | @@ -3942,16 +4064,24 @@ fn transCreateNodeAssign( |
| 3942 | 4064 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3943 | 4065 | rhs_node = &builtin_node.base; |
| 3944 | 4066 | } |
| 3945 | node.init_node = rhs_node; | |
| 3946 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 4067 | const init_node = rhs_node; | |
| 4068 | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 4069 | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ | |
| 4070 | .name_token = name_tok, | |
| 4071 | .mut_token = mut_tok, | |
| 4072 | .semicolon_token = semicolon_token, | |
| 4073 | }, .{ | |
| 4074 | .eq_token = eq_token, | |
| 4075 | .init_node = init_node, | |
| 4076 | }); | |
| 3947 | 4077 | try block_scope.statements.append(&node.base); |
| 3948 | 4078 | |
| 3949 | 4079 | const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value); |
| 3950 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 4080 | const lhs_eq_token = try appendToken(rp.c, .Equal, "="); | |
| 3951 | 4081 | const ident = try transCreateNodeIdentifier(rp.c, tmp); |
| 3952 | 4082 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3953 | 4083 | |
| 3954 | const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false); | |
| 4084 | const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false); | |
| 3955 | 4085 | try block_scope.statements.append(assign); |
| 3956 | 4086 | |
| 3957 | 4087 | const break_node = try transCreateNodeBreak(rp.c, label_name); |
| ... | ... | @@ -4232,28 +4362,10 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 4232 | 4362 | |
| 4233 | 4363 | _ = try appendToken(c, .RParen, ")"); |
| 4234 | 4364 | |
| 4235 | const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len); | |
| 4236 | fn_proto.* = .{ | |
| 4237 | .doc_comments = null, | |
| 4238 | .visib_token = pub_tok, | |
| 4239 | .fn_token = fn_tok, | |
| 4240 | .name_token = name_tok, | |
| 4241 | .params_len = fn_params.items.len, | |
| 4242 | .return_type = proto_alias.return_type, | |
| 4243 | .var_args_token = null, | |
| 4244 | .extern_export_inline_token = inline_tok, | |
| 4245 | .body_node = null, | |
| 4246 | .lib_name = null, | |
| 4247 | .align_expr = null, | |
| 4248 | .section_expr = null, | |
| 4249 | .callconv_expr = null, | |
| 4250 | }; | |
| 4251 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | |
| 4252 | ||
| 4253 | 4365 | const block_lbrace = try appendToken(c, .LBrace, "{"); |
| 4254 | 4366 | |
| 4255 | 4367 | const return_expr = try transCreateNodeReturnExpr(c); |
| 4256 | const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); | |
| 4368 | const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?); | |
| 4257 | 4369 | |
| 4258 | 4370 | const call_expr = try c.createCall(unwrap_expr, fn_params.items.len); |
| 4259 | 4371 | const call_params = call_expr.params(); |
| ... | ... | @@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 4277 | 4389 | .rbrace = try appendToken(c, .RBrace, "}"), |
| 4278 | 4390 | }; |
| 4279 | 4391 | block.statements()[0] = &return_expr.base; |
| 4280 | fn_proto.body_node = &block.base; | |
| 4392 | ||
| 4393 | const fn_proto = try ast.Node.FnProto.create(c.arena, .{ | |
| 4394 | .params_len = fn_params.items.len, | |
| 4395 | .fn_token = fn_tok, | |
| 4396 | .return_type = proto_alias.return_type, | |
| 4397 | }, .{ | |
| 4398 | .visib_token = pub_tok, | |
| 4399 | .name_token = name_tok, | |
| 4400 | .extern_export_inline_token = inline_tok, | |
| 4401 | .body_node = &block.base, | |
| 4402 | }); | |
| 4403 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | |
| 4281 | 4404 | return &fn_proto.base; |
| 4282 | 4405 | } |
| 4283 | 4406 | |
| ... | ... | @@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE |
| 4356 | 4479 | return node; |
| 4357 | 4480 | } |
| 4358 | 4481 | |
| 4359 | fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []const u8) !*ast.Node.VarDecl { | |
| 4360 | const visib_tok = if (is_pub) try appendToken(c, .Keyword_pub, "pub") else null; | |
| 4361 | const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var"); | |
| 4362 | const name_tok = try appendIdentifier(c, name); | |
| 4363 | ||
| 4364 | const node = try c.arena.create(ast.Node.VarDecl); | |
| 4365 | node.* = .{ | |
| 4366 | .doc_comments = null, | |
| 4367 | .visib_token = visib_tok, | |
| 4368 | .thread_local_token = null, | |
| 4369 | .name_token = name_tok, | |
| 4370 | .eq_token = undefined, | |
| 4371 | .mut_token = mut_tok, | |
| 4372 | .comptime_token = null, | |
| 4373 | .extern_export_token = null, | |
| 4374 | .lib_name = null, | |
| 4375 | .type_node = null, | |
| 4376 | .align_node = null, | |
| 4377 | .section_node = null, | |
| 4378 | .init_node = null, | |
| 4379 | .semicolon_token = undefined, | |
| 4380 | }; | |
| 4381 | return node; | |
| 4382 | } | |
| 4383 | ||
| 4384 | 4482 | fn transCreateNodeWhile(c: *Context) !*ast.Node.While { |
| 4385 | 4483 | const while_tok = try appendToken(c, .Keyword_while, "while"); |
| 4386 | 4484 | _ = try appendToken(c, .LParen, "("); |
| ... | ... | @@ -4782,19 +4880,12 @@ fn finishTransFnProto( |
| 4782 | 4880 | } |
| 4783 | 4881 | } |
| 4784 | 4882 | |
| 4785 | if (is_var_args) { | |
| 4883 | const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: { | |
| 4786 | 4884 | if (param_count > 0) { |
| 4787 | 4885 | _ = try appendToken(rp.c, .Comma, ","); |
| 4788 | 4886 | } |
| 4789 | ||
| 4790 | fn_params.addOneAssumeCapacity().* = .{ | |
| 4791 | .doc_comments = null, | |
| 4792 | .comptime_token = null, | |
| 4793 | .noalias_token = null, | |
| 4794 | .name_token = null, | |
| 4795 | .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") }, | |
| 4796 | }; | |
| 4797 | } | |
| 4887 | break :blk try appendToken(rp.c, .Ellipsis3, "..."); | |
| 4888 | } else null; | |
| 4798 | 4889 | |
| 4799 | 4890 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| 4800 | 4891 | |
| ... | ... | @@ -4860,22 +4951,31 @@ fn finishTransFnProto( |
| 4860 | 4951 | } |
| 4861 | 4952 | }; |
| 4862 | 4953 | |
| 4863 | const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len); | |
| 4864 | fn_proto.* = .{ | |
| 4865 | .doc_comments = null, | |
| 4866 | .visib_token = pub_tok, | |
| 4867 | .fn_token = fn_tok, | |
| 4868 | .name_token = name_tok, | |
| 4954 | // We need to reserve an undefined (but non-null) body node to set later. | |
| 4955 | var body_node: ?*ast.Node = null; | |
| 4956 | if (fn_decl_context) |ctx| { | |
| 4957 | if (ctx.has_body) { | |
| 4958 | // TODO: we should be able to use undefined here but | |
| 4959 | // it causes a bug. This is undefined without zig language | |
| 4960 | // being aware of it. | |
| 4961 | body_node = @intToPtr(*ast.Node, 0x08); | |
| 4962 | } | |
| 4963 | } | |
| 4964 | ||
| 4965 | const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{ | |
| 4869 | 4966 | .params_len = fn_params.items.len, |
| 4870 | 4967 | .return_type = .{ .Explicit = return_type_node }, |
| 4871 | .var_args_token = null, // TODO this field is broken in the AST data model | |
| 4968 | .fn_token = fn_tok, | |
| 4969 | }, .{ | |
| 4970 | .visib_token = pub_tok, | |
| 4971 | .name_token = name_tok, | |
| 4872 | 4972 | .extern_export_inline_token = extern_export_inline_tok, |
| 4873 | .body_node = null, | |
| 4874 | .lib_name = null, | |
| 4875 | 4973 | .align_expr = align_expr, |
| 4876 | 4974 | .section_expr = linksection_expr, |
| 4877 | 4975 | .callconv_expr = callconv_expr, |
| 4878 | }; | |
| 4976 | .body_node = body_node, | |
| 4977 | .var_args_token = var_args_token, | |
| 4978 | }); | |
| 4879 | 4979 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); |
| 4880 | 4980 | return fn_proto; |
| 4881 | 4981 | } |
| ... | ... | @@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp |
| 4923 | 5023 | }; |
| 4924 | 5024 | call_node.params()[0] = &msg_node.base; |
| 4925 | 5025 | |
| 4926 | const var_decl_node = try c.arena.create(ast.Node.VarDecl); | |
| 4927 | var_decl_node.* = .{ | |
| 4928 | .doc_comments = null, | |
| 4929 | .visib_token = pub_tok, | |
| 4930 | .thread_local_token = null, | |
| 5026 | const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 4931 | 5027 | .name_token = name_tok, |
| 4932 | .eq_token = eq_tok, | |
| 4933 | 5028 | .mut_token = const_tok, |
| 4934 | .comptime_token = null, | |
| 4935 | .extern_export_token = null, | |
| 4936 | .lib_name = null, | |
| 4937 | .type_node = null, | |
| 4938 | .align_node = null, | |
| 4939 | .section_node = null, | |
| 4940 | .init_node = &call_node.base, | |
| 4941 | 5029 | .semicolon_token = semi_tok, |
| 4942 | }; | |
| 5030 | }, .{ | |
| 5031 | .visib_token = pub_tok, | |
| 5032 | .eq_token = eq_tok, | |
| 5033 | .init_node = &call_node.base, | |
| 5034 | }); | |
| 4943 | 5035 | try addTopLevelDecl(c, name, &var_decl_node.base); |
| 4944 | 5036 | } |
| 4945 | 5037 | |
| ... | ... | @@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 5132 | 5224 | fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 5133 | 5225 | const scope = &c.global_scope.base; |
| 5134 | 5226 | |
| 5135 | const node = try transCreateNodeVarDecl(c, true, true, name); | |
| 5136 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 5227 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 5228 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 5229 | const name_tok = try appendIdentifier(c, name); | |
| 5230 | const eq_token = try appendToken(c, .Equal, "="); | |
| 5137 | 5231 | |
| 5138 | node.init_node = try parseCExpr(c, it, source, source_loc, scope); | |
| 5232 | const init_node = try parseCExpr(c, it, source, source_loc, scope); | |
| 5139 | 5233 | const last = it.next().?; |
| 5140 | 5234 | if (last.id != .Eof and last.id != .Nl) |
| 5141 | 5235 | return failDecl( |
| ... | ... | @@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n |
| 5146 | 5240 | .{@tagName(last.id)}, |
| 5147 | 5241 | ); |
| 5148 | 5242 | |
| 5149 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 5243 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 5244 | const node = try ast.Node.VarDecl.create(c.arena, .{ | |
| 5245 | .name_token = name_tok, | |
| 5246 | .mut_token = mut_tok, | |
| 5247 | .semicolon_token = semicolon_token, | |
| 5248 | }, .{ | |
| 5249 | .visib_token = visib_tok, | |
| 5250 | .eq_token = eq_token, | |
| 5251 | .init_node = init_node, | |
| 5252 | }); | |
| 5150 | 5253 | _ = try c.global_scope.macro_table.put(name, &node.base); |
| 5151 | 5254 | } |
| 5152 | 5255 | |
| ... | ... | @@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5223 | 5326 | |
| 5224 | 5327 | const type_of = try c.createBuiltinCall("@TypeOf", 1); |
| 5225 | 5328 | |
| 5226 | const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len); | |
| 5227 | fn_proto.* = .{ | |
| 5228 | .visib_token = pub_tok, | |
| 5229 | .extern_export_inline_token = inline_tok, | |
| 5230 | .fn_token = fn_tok, | |
| 5231 | .name_token = name_tok, | |
| 5232 | .params_len = fn_params.items.len, | |
| 5233 | .return_type = .{ .Explicit = &type_of.base }, | |
| 5234 | .doc_comments = null, | |
| 5235 | .var_args_token = null, | |
| 5236 | .body_node = null, | |
| 5237 | .lib_name = null, | |
| 5238 | .align_expr = null, | |
| 5239 | .section_expr = null, | |
| 5240 | .callconv_expr = null, | |
| 5241 | }; | |
| 5242 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | |
| 5243 | ||
| 5244 | 5329 | const return_expr = try transCreateNodeReturnExpr(c); |
| 5245 | 5330 | const expr = try parseCExpr(c, it, source, source_loc, scope); |
| 5246 | 5331 | const last = it.next().?; |
| ... | ... | @@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5266 | 5351 | |
| 5267 | 5352 | try block_scope.statements.append(&return_expr.base); |
| 5268 | 5353 | const block_node = try block_scope.complete(c); |
| 5269 | fn_proto.body_node = &block_node.base; | |
| 5354 | const fn_proto = try ast.Node.FnProto.create(c.arena, .{ | |
| 5355 | .fn_token = fn_tok, | |
| 5356 | .params_len = fn_params.items.len, | |
| 5357 | .return_type = .{ .Explicit = &type_of.base }, | |
| 5358 | }, .{ | |
| 5359 | .visib_token = pub_tok, | |
| 5360 | .extern_export_inline_token = inline_tok, | |
| 5361 | .name_token = name_tok, | |
| 5362 | .body_node = &block_node.base, | |
| 5363 | }); | |
| 5364 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | |
| 5365 | ||
| 5270 | 5366 | _ = try c.global_scope.macro_table.put(name, &fn_proto.base); |
| 5271 | 5367 | } |
| 5272 | 5368 | |
| ... | ... | @@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { |
| 6030 | 6126 | const ident = node.cast(ast.Node.Identifier).?; |
| 6031 | 6127 | if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| { |
| 6032 | 6128 | if (value.cast(ast.Node.VarDecl)) |var_decl| |
| 6033 | return getContainer(c, var_decl.init_node.?); | |
| 6129 | return getContainer(c, var_decl.getTrailer("init_node").?); | |
| 6034 | 6130 | } |
| 6035 | 6131 | }, |
| 6036 | 6132 | |
| ... | ... | @@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 6060 | 6156 | if (ref.cast(ast.Node.Identifier)) |ident| { |
| 6061 | 6157 | if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| { |
| 6062 | 6158 | if (value.cast(ast.Node.VarDecl)) |var_decl| { |
| 6063 | if (var_decl.type_node) |ty| | |
| 6159 | if (var_decl.getTrailer("type_node")) |ty| | |
| 6064 | 6160 | return getContainer(c, ty); |
| 6065 | 6161 | } |
| 6066 | 6162 | } |
| ... | ... | @@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 6084 | 6180 | } |
| 6085 | 6181 | |
| 6086 | 6182 | fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto { |
| 6087 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; | |
| 6183 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null; | |
| 6088 | 6184 | if (getContainerTypeOf(c, init)) |ty_node| { |
| 6089 | 6185 | if (ty_node.cast(ast.Node.OptionalType)) |prefix| { |
| 6090 | 6186 | if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| { |
test/translate_c.zig+1-1| ... | ... | @@ -2797,7 +2797,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2797 | 2797 | \\pub fn a() callconv(.C) void {} |
| 2798 | 2798 | \\pub fn b() callconv(.C) void {} |
| 2799 | 2799 | \\pub export fn c() void {} |
| 2800 | \\pub fn foo() callconv(.C) void {} | |
| 2800 | \\pub fn foo(...) callconv(.C) void {} | |
| 2801 | 2801 | }); |
| 2802 | 2802 | |
| 2803 | 2803 | cases.add("casting away const and volatile", |