| author | |
| committer | |
| log | d2278f21560014c635afe4bc247a9096ecb845de |
| tree | e8bca82dcc8d09f6f287054b4c2ba171c190bf37 |
| parent | 0ff5d7b24e2017199566d1bab75254fa5ef68611 |
| parent | 05d284c842a5ba21cd836c2b212daa24227a9177 |
| signature |
Stage2 garbage collect decls12 files changed, 1043 insertions(+), 445 deletions(-)
lib/std/comptime_string_map.zig+24-24| ... | @@ -17,18 +17,18 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs: var) type { | ... | @@ -17,18 +17,18 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs: var) type { |
| 17 | }; | 17 | }; |
| 18 | var sorted_kvs: [kvs.len]KV = undefined; | 18 | var sorted_kvs: [kvs.len]KV = undefined; |
| 19 | const lenAsc = (struct { | 19 | const lenAsc = (struct { |
| 20 | fn lenAsc(a: KV, b: KV) bool { | 20 | fn lenAsc(context: void, a: KV, b: KV) bool { |
| 21 | return a.key.len < b.key.len; | 21 | return a.key.len < b.key.len; |
| 22 | } | 22 | } |
| 23 | }).lenAsc; | 23 | }).lenAsc; |
| 24 | for (kvs) |kv, i| { | 24 | for (kvs) |kv, i| { |
| 25 | if (V != void) { | 25 | if (V != void) { |
| 26 | sorted_kvs[i] = .{.key = kv.@"0", .value = kv.@"1"}; | 26 | sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" }; |
| 27 | } else { | 27 | } else { |
| 28 | sorted_kvs[i] = .{.key = kv.@"0", .value = {}}; | 28 | sorted_kvs[i] = .{ .key = kv.@"0", .value = {} }; |
| 29 | } | 29 | } |
| 30 | } | 30 | } |
| 31 | std.sort.sort(KV, &sorted_kvs, lenAsc); | 31 | std.sort.sort(KV, &sorted_kvs, {}, lenAsc); |
| 32 | const min_len = sorted_kvs[0].key.len; | 32 | const min_len = sorted_kvs[0].key.len; |
| 33 | const max_len = sorted_kvs[sorted_kvs.len - 1].key.len; | 33 | const max_len = sorted_kvs[sorted_kvs.len - 1].key.len; |
| 34 | var len_indexes: [max_len + 1]usize = undefined; | 34 | var len_indexes: [max_len + 1]usize = undefined; |
| ... | @@ -83,11 +83,11 @@ const TestEnum = enum { | ... | @@ -83,11 +83,11 @@ const TestEnum = enum { |
| 83 | 83 | ||
| 84 | test "ComptimeStringMap list literal of list literals" { | 84 | test "ComptimeStringMap list literal of list literals" { |
| 85 | const map = ComptimeStringMap(TestEnum, .{ | 85 | const map = ComptimeStringMap(TestEnum, .{ |
| 86 | .{"these", .D}, | 86 | .{ "these", .D }, |
| 87 | .{"have", .A}, | 87 | .{ "have", .A }, |
| 88 | .{"nothing", .B}, | 88 | .{ "nothing", .B }, |
| 89 | .{"incommon", .C}, | 89 | .{ "incommon", .C }, |
| 90 | .{"samelen", .E}, | 90 | .{ "samelen", .E }, |
| 91 | }); | 91 | }); |
| 92 | 92 | ||
| 93 | testMap(map); | 93 | testMap(map); |
| ... | @@ -99,11 +99,11 @@ test "ComptimeStringMap array of structs" { | ... | @@ -99,11 +99,11 @@ test "ComptimeStringMap array of structs" { |
| 99 | @"1": TestEnum, | 99 | @"1": TestEnum, |
| 100 | }; | 100 | }; |
| 101 | const map = ComptimeStringMap(TestEnum, [_]KV{ | 101 | const map = ComptimeStringMap(TestEnum, [_]KV{ |
| 102 | .{.@"0" = "these", .@"1" = .D}, | 102 | .{ .@"0" = "these", .@"1" = .D }, |
| 103 | .{.@"0" = "have", .@"1" = .A}, | 103 | .{ .@"0" = "have", .@"1" = .A }, |
| 104 | .{.@"0" = "nothing", .@"1" = .B}, | 104 | .{ .@"0" = "nothing", .@"1" = .B }, |
| 105 | .{.@"0" = "incommon", .@"1" = .C}, | 105 | .{ .@"0" = "incommon", .@"1" = .C }, |
| 106 | .{.@"0" = "samelen", .@"1" = .E}, | 106 | .{ .@"0" = "samelen", .@"1" = .E }, |
| 107 | }); | 107 | }); |
| 108 | 108 | ||
| 109 | testMap(map); | 109 | testMap(map); |
| ... | @@ -115,11 +115,11 @@ test "ComptimeStringMap slice of structs" { | ... | @@ -115,11 +115,11 @@ test "ComptimeStringMap slice of structs" { |
| 115 | @"1": TestEnum, | 115 | @"1": TestEnum, |
| 116 | }; | 116 | }; |
| 117 | const slice: []const KV = &[_]KV{ | 117 | const slice: []const KV = &[_]KV{ |
| 118 | .{.@"0" = "these", .@"1" = .D}, | 118 | .{ .@"0" = "these", .@"1" = .D }, |
| 119 | .{.@"0" = "have", .@"1" = .A}, | 119 | .{ .@"0" = "have", .@"1" = .A }, |
| 120 | .{.@"0" = "nothing", .@"1" = .B}, | 120 | .{ .@"0" = "nothing", .@"1" = .B }, |
| 121 | .{.@"0" = "incommon", .@"1" = .C}, | 121 | .{ .@"0" = "incommon", .@"1" = .C }, |
| 122 | .{.@"0" = "samelen", .@"1" = .E}, | 122 | .{ .@"0" = "samelen", .@"1" = .E }, |
| 123 | }; | 123 | }; |
| 124 | const map = ComptimeStringMap(TestEnum, slice); | 124 | const map = ComptimeStringMap(TestEnum, slice); |
| 125 | 125 | ||
| ... | @@ -142,11 +142,11 @@ test "ComptimeStringMap void value type, slice of structs" { | ... | @@ -142,11 +142,11 @@ test "ComptimeStringMap void value type, slice of structs" { |
| 142 | @"0": []const u8, | 142 | @"0": []const u8, |
| 143 | }; | 143 | }; |
| 144 | const slice: []const KV = &[_]KV{ | 144 | const slice: []const KV = &[_]KV{ |
| 145 | .{.@"0" = "these"}, | 145 | .{ .@"0" = "these" }, |
| 146 | .{.@"0" = "have"}, | 146 | .{ .@"0" = "have" }, |
| 147 | .{.@"0" = "nothing"}, | 147 | .{ .@"0" = "nothing" }, |
| 148 | .{.@"0" = "incommon"}, | 148 | .{ .@"0" = "incommon" }, |
| 149 | .{.@"0" = "samelen"}, | 149 | .{ .@"0" = "samelen" }, |
| 150 | }; | 150 | }; |
| 151 | const map = ComptimeStringMap(void, slice); | 151 | const map = ComptimeStringMap(void, slice); |
| 152 | 152 |
lib/std/debug.zig+3-3| ... | @@ -1003,7 +1003,7 @@ fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugI | ... | @@ -1003,7 +1003,7 @@ fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugI |
| 1003 | // Even though lld emits symbols in ascending order, this debug code | 1003 | // Even though lld emits symbols in ascending order, this debug code |
| 1004 | // should work for programs linked in any valid way. | 1004 | // should work for programs linked in any valid way. |
| 1005 | // This sort is so that we can binary search later. | 1005 | // This sort is so that we can binary search later. |
| 1006 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); | 1006 | std.sort.sort(MachoSymbol, symbols, {}, MachoSymbol.addressLessThan); |
| 1007 | 1007 | ||
| 1008 | return ModuleDebugInfo{ | 1008 | return ModuleDebugInfo{ |
| 1009 | .base_address = undefined, | 1009 | .base_address = undefined, |
| ... | @@ -1058,7 +1058,7 @@ const MachoSymbol = struct { | ... | @@ -1058,7 +1058,7 @@ const MachoSymbol = struct { |
| 1058 | return self.nlist.n_value; | 1058 | return self.nlist.n_value; |
| 1059 | } | 1059 | } |
| 1060 | 1060 | ||
| 1061 | fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool { | 1061 | fn addressLessThan(context: void, lhs: MachoSymbol, rhs: MachoSymbol) bool { |
| 1062 | return lhs.address() < rhs.address(); | 1062 | return lhs.address() < rhs.address(); |
| 1063 | } | 1063 | } |
| 1064 | }; | 1064 | }; |
| ... | @@ -1300,7 +1300,7 @@ pub const DebugInfo = struct { | ... | @@ -1300,7 +1300,7 @@ pub const DebugInfo = struct { |
| 1300 | fs.cwd().openFile(ctx.name, .{ .intended_io_mode = .blocking }) | 1300 | fs.cwd().openFile(ctx.name, .{ .intended_io_mode = .blocking }) |
| 1301 | else | 1301 | else |
| 1302 | fs.openSelfExe(.{ .intended_io_mode = .blocking }); | 1302 | fs.openSelfExe(.{ .intended_io_mode = .blocking }); |
| 1303 | 1303 | ||
| 1304 | const elf_file = copy catch |err| switch (err) { | 1304 | const elf_file = copy catch |err| switch (err) { |
| 1305 | error.FileNotFound => return error.MissingDebugInfo, | 1305 | error.FileNotFound => return error.MissingDebugInfo, |
| 1306 | else => return err, | 1306 | else => return err, |
lib/std/http/headers.zig+2-2| ... | @@ -58,7 +58,7 @@ const HeaderEntry = struct { | ... | @@ -58,7 +58,7 @@ const HeaderEntry = struct { |
| 58 | self.never_index = never_index orelse never_index_default(self.name); | 58 | self.never_index = never_index orelse never_index_default(self.name); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | fn compare(a: HeaderEntry, b: HeaderEntry) bool { | 61 | fn compare(context: void, a: HeaderEntry, b: HeaderEntry) bool { |
| 62 | if (a.name.ptr != b.name.ptr and a.name.len != b.name.len) { | 62 | if (a.name.ptr != b.name.ptr and a.name.len != b.name.len) { |
| 63 | // Things beginning with a colon *must* be before others | 63 | // Things beginning with a colon *must* be before others |
| 64 | const a_is_colon = a.name[0] == ':'; | 64 | const a_is_colon = a.name[0] == ':'; |
| ... | @@ -342,7 +342,7 @@ pub const Headers = struct { | ... | @@ -342,7 +342,7 @@ pub const Headers = struct { |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | pub fn sort(self: *Self) void { | 344 | pub fn sort(self: *Self) void { |
| 345 | std.sort.sort(HeaderEntry, self.data.items, HeaderEntry.compare); | 345 | std.sort.sort(HeaderEntry, self.data.items, {}, HeaderEntry.compare); |
| 346 | self.rebuild_index(); | 346 | self.rebuild_index(); |
| 347 | } | 347 | } |
| 348 | 348 |
lib/std/net.zig+2-2| ... | @@ -836,7 +836,7 @@ fn linuxLookupName( | ... | @@ -836,7 +836,7 @@ fn linuxLookupName( |
| 836 | key |= (MAXADDRS - @intCast(i32, i)) << DAS_ORDER_SHIFT; | 836 | key |= (MAXADDRS - @intCast(i32, i)) << DAS_ORDER_SHIFT; |
| 837 | addr.sortkey = key; | 837 | addr.sortkey = key; |
| 838 | } | 838 | } |
| 839 | std.sort.sort(LookupAddr, addrs.span(), addrCmpLessThan); | 839 | std.sort.sort(LookupAddr, addrs.span(), {}, addrCmpLessThan); |
| 840 | } | 840 | } |
| 841 | 841 | ||
| 842 | const Policy = struct { | 842 | const Policy = struct { |
| ... | @@ -953,7 +953,7 @@ fn IN6_IS_ADDR_SITELOCAL(a: [16]u8) bool { | ... | @@ -953,7 +953,7 @@ fn IN6_IS_ADDR_SITELOCAL(a: [16]u8) bool { |
| 953 | } | 953 | } |
| 954 | 954 | ||
| 955 | // Parameters `b` and `a` swapped to make this descending. | 955 | // Parameters `b` and `a` swapped to make this descending. |
| 956 | fn addrCmpLessThan(b: LookupAddr, a: LookupAddr) bool { | 956 | fn addrCmpLessThan(context: void, b: LookupAddr, a: LookupAddr) bool { |
| 957 | return a.sortkey < b.sortkey; | 957 | return a.sortkey < b.sortkey; |
| 958 | } | 958 | } |
| 959 | 959 |
lib/std/sort.zig+351-219| ... | @@ -5,7 +5,13 @@ const mem = std.mem; | ... | @@ -5,7 +5,13 @@ const mem = std.mem; |
| 5 | const math = std.math; | 5 | const math = std.math; |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compareFn: fn (lhs: T, rhs: T) math.Order) ?usize { | 8 | pub fn binarySearch( |
| 9 | comptime T: type, | ||
| 10 | key: T, | ||
| 11 | items: []const T, | ||
| 12 | context: var, | ||
| 13 | comptime compareFn: fn (context: @TypeOf(context), lhs: T, rhs: T) math.Order, | ||
| 14 | ) ?usize { | ||
| 9 | var left: usize = 0; | 15 | var left: usize = 0; |
| 10 | var right: usize = items.len; | 16 | var right: usize = items.len; |
| 11 | 17 | ||
| ... | @@ -13,7 +19,7 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare | ... | @@ -13,7 +19,7 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare |
| 13 | // Avoid overflowing in the midpoint calculation | 19 | // Avoid overflowing in the midpoint calculation |
| 14 | const mid = left + (right - left) / 2; | 20 | const mid = left + (right - left) / 2; |
| 15 | // Compare the key with the midpoint element | 21 | // Compare the key with the midpoint element |
| 16 | switch (compareFn(key, items[mid])) { | 22 | switch (compareFn(context, key, items[mid])) { |
| 17 | .eq => return mid, | 23 | .eq => return mid, |
| 18 | .gt => left = mid + 1, | 24 | .gt => left = mid + 1, |
| 19 | .lt => right = mid, | 25 | .lt => right = mid, |
| ... | @@ -23,56 +29,61 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare | ... | @@ -23,56 +29,61 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare |
| 23 | return null; | 29 | return null; |
| 24 | } | 30 | } |
| 25 | 31 | ||
| 26 | test "std.sort.binarySearch" { | 32 | test "binarySearch" { |
| 27 | const S = struct { | 33 | const S = struct { |
| 28 | fn order_u32(lhs: u32, rhs: u32) math.Order { | 34 | fn order_u32(context: void, lhs: u32, rhs: u32) math.Order { |
| 29 | return math.order(lhs, rhs); | 35 | return math.order(lhs, rhs); |
| 30 | } | 36 | } |
| 31 | fn order_i32(lhs: i32, rhs: i32) math.Order { | 37 | fn order_i32(context: void, lhs: i32, rhs: i32) math.Order { |
| 32 | return math.order(lhs, rhs); | 38 | return math.order(lhs, rhs); |
| 33 | } | 39 | } |
| 34 | }; | 40 | }; |
| 35 | testing.expectEqual( | 41 | testing.expectEqual( |
| 36 | @as(?usize, null), | 42 | @as(?usize, null), |
| 37 | binarySearch(u32, 1, &[_]u32{}, S.order_u32), | 43 | binarySearch(u32, 1, &[_]u32{}, {}, S.order_u32), |
| 38 | ); | 44 | ); |
| 39 | testing.expectEqual( | 45 | testing.expectEqual( |
| 40 | @as(?usize, 0), | 46 | @as(?usize, 0), |
| 41 | binarySearch(u32, 1, &[_]u32{1}, S.order_u32), | 47 | binarySearch(u32, 1, &[_]u32{1}, {}, S.order_u32), |
| 42 | ); | 48 | ); |
| 43 | testing.expectEqual( | 49 | testing.expectEqual( |
| 44 | @as(?usize, null), | 50 | @as(?usize, null), |
| 45 | binarySearch(u32, 1, &[_]u32{0}, S.order_u32), | 51 | binarySearch(u32, 1, &[_]u32{0}, {}, S.order_u32), |
| 46 | ); | 52 | ); |
| 47 | testing.expectEqual( | 53 | testing.expectEqual( |
| 48 | @as(?usize, null), | 54 | @as(?usize, null), |
| 49 | binarySearch(u32, 0, &[_]u32{1}, S.order_u32), | 55 | binarySearch(u32, 0, &[_]u32{1}, {}, S.order_u32), |
| 50 | ); | 56 | ); |
| 51 | testing.expectEqual( | 57 | testing.expectEqual( |
| 52 | @as(?usize, 4), | 58 | @as(?usize, 4), |
| 53 | binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, S.order_u32), | 59 | binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32), |
| 54 | ); | 60 | ); |
| 55 | testing.expectEqual( | 61 | testing.expectEqual( |
| 56 | @as(?usize, 0), | 62 | @as(?usize, 0), |
| 57 | binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, S.order_u32), | 63 | binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32), |
| 58 | ); | 64 | ); |
| 59 | testing.expectEqual( | 65 | testing.expectEqual( |
| 60 | @as(?usize, 1), | 66 | @as(?usize, 1), |
| 61 | binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, S.order_i32), | 67 | binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32), |
| 62 | ); | 68 | ); |
| 63 | testing.expectEqual( | 69 | testing.expectEqual( |
| 64 | @as(?usize, 3), | 70 | @as(?usize, 3), |
| 65 | binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, S.order_i32), | 71 | binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32), |
| 66 | ); | 72 | ); |
| 67 | } | 73 | } |
| 68 | 74 | ||
| 69 | /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). | 75 | /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). |
| 70 | pub fn insertionSort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void { | 76 | pub fn insertionSort( |
| 77 | comptime T: type, | ||
| 78 | items: []T, | ||
| 79 | context: var, | ||
| 80 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 81 | ) void { | ||
| 71 | var i: usize = 1; | 82 | var i: usize = 1; |
| 72 | while (i < items.len) : (i += 1) { | 83 | while (i < items.len) : (i += 1) { |
| 73 | const x = items[i]; | 84 | const x = items[i]; |
| 74 | var j: usize = i; | 85 | var j: usize = i; |
| 75 | while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) { | 86 | while (j > 0 and lessThan(context, x, items[j - 1])) : (j -= 1) { |
| 76 | items[j] = items[j - 1]; | 87 | items[j] = items[j - 1]; |
| 77 | } | 88 | } |
| 78 | items[j] = x; | 89 | items[j] = x; |
| ... | @@ -168,20 +179,25 @@ const Pull = struct { | ... | @@ -168,20 +179,25 @@ const Pull = struct { |
| 168 | 179 | ||
| 169 | /// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required). | 180 | /// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required). |
| 170 | /// Currently implemented as block sort. | 181 | /// Currently implemented as block sort. |
| 171 | pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void { | 182 | pub fn sort( |
| 183 | comptime T: type, | ||
| 184 | items: []T, | ||
| 185 | context: var, | ||
| 186 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 187 | ) void { | ||
| 172 | // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c | 188 | // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c |
| 173 | var cache: [512]T = undefined; | 189 | var cache: [512]T = undefined; |
| 174 | 190 | ||
| 175 | if (items.len < 4) { | 191 | if (items.len < 4) { |
| 176 | if (items.len == 3) { | 192 | if (items.len == 3) { |
| 177 | // hard coded insertion sort | 193 | // hard coded insertion sort |
| 178 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 194 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 179 | if (lessThan(items[2], items[1])) { | 195 | if (lessThan(context, items[2], items[1])) { |
| 180 | mem.swap(T, &items[1], &items[2]); | 196 | mem.swap(T, &items[1], &items[2]); |
| 181 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 197 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 182 | } | 198 | } |
| 183 | } else if (items.len == 2) { | 199 | } else if (items.len == 2) { |
| 184 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 200 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 185 | } | 201 | } |
| 186 | return; | 202 | return; |
| 187 | } | 203 | } |
| ... | @@ -197,75 +213,75 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -197,75 +213,75 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 197 | const sliced_items = items[range.start..]; | 213 | const sliced_items = items[range.start..]; |
| 198 | switch (range.length()) { | 214 | switch (range.length()) { |
| 199 | 8 => { | 215 | 8 => { |
| 200 | swap(T, sliced_items, lessThan, &order, 0, 1); | 216 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 201 | swap(T, sliced_items, lessThan, &order, 2, 3); | 217 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 202 | swap(T, sliced_items, lessThan, &order, 4, 5); | 218 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 203 | swap(T, sliced_items, lessThan, &order, 6, 7); | 219 | swap(T, sliced_items, context, lessThan, &order, 6, 7); |
| 204 | swap(T, sliced_items, lessThan, &order, 0, 2); | 220 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 205 | swap(T, sliced_items, lessThan, &order, 1, 3); | 221 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 206 | swap(T, sliced_items, lessThan, &order, 4, 6); | 222 | swap(T, sliced_items, context, lessThan, &order, 4, 6); |
| 207 | swap(T, sliced_items, lessThan, &order, 5, 7); | 223 | swap(T, sliced_items, context, lessThan, &order, 5, 7); |
| 208 | swap(T, sliced_items, lessThan, &order, 1, 2); | 224 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 209 | swap(T, sliced_items, lessThan, &order, 5, 6); | 225 | swap(T, sliced_items, context, lessThan, &order, 5, 6); |
| 210 | swap(T, sliced_items, lessThan, &order, 0, 4); | 226 | swap(T, sliced_items, context, lessThan, &order, 0, 4); |
| 211 | swap(T, sliced_items, lessThan, &order, 3, 7); | 227 | swap(T, sliced_items, context, lessThan, &order, 3, 7); |
| 212 | swap(T, sliced_items, lessThan, &order, 1, 5); | 228 | swap(T, sliced_items, context, lessThan, &order, 1, 5); |
| 213 | swap(T, sliced_items, lessThan, &order, 2, 6); | 229 | swap(T, sliced_items, context, lessThan, &order, 2, 6); |
| 214 | swap(T, sliced_items, lessThan, &order, 1, 4); | 230 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 215 | swap(T, sliced_items, lessThan, &order, 3, 6); | 231 | swap(T, sliced_items, context, lessThan, &order, 3, 6); |
| 216 | swap(T, sliced_items, lessThan, &order, 2, 4); | 232 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 217 | swap(T, sliced_items, lessThan, &order, 3, 5); | 233 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 218 | swap(T, sliced_items, lessThan, &order, 3, 4); | 234 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 219 | }, | 235 | }, |
| 220 | 7 => { | 236 | 7 => { |
| 221 | swap(T, sliced_items, lessThan, &order, 1, 2); | 237 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 222 | swap(T, sliced_items, lessThan, &order, 3, 4); | 238 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 223 | swap(T, sliced_items, lessThan, &order, 5, 6); | 239 | swap(T, sliced_items, context, lessThan, &order, 5, 6); |
| 224 | swap(T, sliced_items, lessThan, &order, 0, 2); | 240 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 225 | swap(T, sliced_items, lessThan, &order, 3, 5); | 241 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 226 | swap(T, sliced_items, lessThan, &order, 4, 6); | 242 | swap(T, sliced_items, context, lessThan, &order, 4, 6); |
| 227 | swap(T, sliced_items, lessThan, &order, 0, 1); | 243 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 228 | swap(T, sliced_items, lessThan, &order, 4, 5); | 244 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 229 | swap(T, sliced_items, lessThan, &order, 2, 6); | 245 | swap(T, sliced_items, context, lessThan, &order, 2, 6); |
| 230 | swap(T, sliced_items, lessThan, &order, 0, 4); | 246 | swap(T, sliced_items, context, lessThan, &order, 0, 4); |
| 231 | swap(T, sliced_items, lessThan, &order, 1, 5); | 247 | swap(T, sliced_items, context, lessThan, &order, 1, 5); |
| 232 | swap(T, sliced_items, lessThan, &order, 0, 3); | 248 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 233 | swap(T, sliced_items, lessThan, &order, 2, 5); | 249 | swap(T, sliced_items, context, lessThan, &order, 2, 5); |
| 234 | swap(T, sliced_items, lessThan, &order, 1, 3); | 250 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 235 | swap(T, sliced_items, lessThan, &order, 2, 4); | 251 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 236 | swap(T, sliced_items, lessThan, &order, 2, 3); | 252 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 237 | }, | 253 | }, |
| 238 | 6 => { | 254 | 6 => { |
| 239 | swap(T, sliced_items, lessThan, &order, 1, 2); | 255 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 240 | swap(T, sliced_items, lessThan, &order, 4, 5); | 256 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 241 | swap(T, sliced_items, lessThan, &order, 0, 2); | 257 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 242 | swap(T, sliced_items, lessThan, &order, 3, 5); | 258 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 243 | swap(T, sliced_items, lessThan, &order, 0, 1); | 259 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 244 | swap(T, sliced_items, lessThan, &order, 3, 4); | 260 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 245 | swap(T, sliced_items, lessThan, &order, 2, 5); | 261 | swap(T, sliced_items, context, lessThan, &order, 2, 5); |
| 246 | swap(T, sliced_items, lessThan, &order, 0, 3); | 262 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 247 | swap(T, sliced_items, lessThan, &order, 1, 4); | 263 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 248 | swap(T, sliced_items, lessThan, &order, 2, 4); | 264 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 249 | swap(T, sliced_items, lessThan, &order, 1, 3); | 265 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 250 | swap(T, sliced_items, lessThan, &order, 2, 3); | 266 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 251 | }, | 267 | }, |
| 252 | 5 => { | 268 | 5 => { |
| 253 | swap(T, sliced_items, lessThan, &order, 0, 1); | 269 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 254 | swap(T, sliced_items, lessThan, &order, 3, 4); | 270 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 255 | swap(T, sliced_items, lessThan, &order, 2, 4); | 271 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 256 | swap(T, sliced_items, lessThan, &order, 2, 3); | 272 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 257 | swap(T, sliced_items, lessThan, &order, 1, 4); | 273 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 258 | swap(T, sliced_items, lessThan, &order, 0, 3); | 274 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 259 | swap(T, sliced_items, lessThan, &order, 0, 2); | 275 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 260 | swap(T, sliced_items, lessThan, &order, 1, 3); | 276 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 261 | swap(T, sliced_items, lessThan, &order, 1, 2); | 277 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 262 | }, | 278 | }, |
| 263 | 4 => { | 279 | 4 => { |
| 264 | swap(T, sliced_items, lessThan, &order, 0, 1); | 280 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 265 | swap(T, sliced_items, lessThan, &order, 2, 3); | 281 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 266 | swap(T, sliced_items, lessThan, &order, 0, 2); | 282 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 267 | swap(T, sliced_items, lessThan, &order, 1, 3); | 283 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 268 | swap(T, sliced_items, lessThan, &order, 1, 2); | 284 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 269 | }, | 285 | }, |
| 270 | else => {}, | 286 | else => {}, |
| 271 | } | 287 | } |
| ... | @@ -288,16 +304,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -288,16 +304,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 288 | var A2 = iterator.nextRange(); | 304 | var A2 = iterator.nextRange(); |
| 289 | var B2 = iterator.nextRange(); | 305 | var B2 = iterator.nextRange(); |
| 290 | 306 | ||
| 291 | if (lessThan(items[B1.end - 1], items[A1.start])) { | 307 | if (lessThan(context, items[B1.end - 1], items[A1.start])) { |
| 292 | // the two ranges are in reverse order, so copy them in reverse order into the cache | 308 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| 293 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); | 309 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); |
| 294 | mem.copy(T, cache[0..], items[B1.start..B1.end]); | 310 | mem.copy(T, cache[0..], items[B1.start..B1.end]); |
| 295 | } else if (lessThan(items[B1.start], items[A1.end - 1])) { | 311 | } else if (lessThan(context, items[B1.start], items[A1.end - 1])) { |
| 296 | // these two ranges weren't already in order, so merge them into the cache | 312 | // these two ranges weren't already in order, so merge them into the cache |
| 297 | mergeInto(T, items, A1, B1, lessThan, cache[0..]); | 313 | mergeInto(T, items, A1, B1, context, lessThan, cache[0..]); |
| 298 | } else { | 314 | } else { |
| 299 | // if A1, B1, A2, and B2 are all in order, skip doing anything else | 315 | // if A1, B1, A2, and B2 are all in order, skip doing anything else |
| 300 | if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue; | 316 | if (!lessThan(context, items[B2.start], items[A2.end - 1]) and !lessThan(context, items[A2.start], items[B1.end - 1])) continue; |
| 301 | 317 | ||
| 302 | // copy A1 and B1 into the cache in the same order | 318 | // copy A1 and B1 into the cache in the same order |
| 303 | mem.copy(T, cache[0..], items[A1.start..A1.end]); | 319 | mem.copy(T, cache[0..], items[A1.start..A1.end]); |
| ... | @@ -306,13 +322,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -306,13 +322,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 306 | A1 = Range.init(A1.start, B1.end); | 322 | A1 = Range.init(A1.start, B1.end); |
| 307 | 323 | ||
| 308 | // merge A2 and B2 into the cache | 324 | // merge A2 and B2 into the cache |
| 309 | if (lessThan(items[B2.end - 1], items[A2.start])) { | 325 | if (lessThan(context, items[B2.end - 1], items[A2.start])) { |
| 310 | // the two ranges are in reverse order, so copy them in reverse order into the cache | 326 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| 311 | mem.copy(T, cache[A1.length() + B2.length() ..], items[A2.start..A2.end]); | 327 | mem.copy(T, cache[A1.length() + B2.length() ..], items[A2.start..A2.end]); |
| 312 | mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]); | 328 | mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]); |
| 313 | } else if (lessThan(items[B2.start], items[A2.end - 1])) { | 329 | } else if (lessThan(context, items[B2.start], items[A2.end - 1])) { |
| 314 | // these two ranges weren't already in order, so merge them into the cache | 330 | // these two ranges weren't already in order, so merge them into the cache |
| 315 | mergeInto(T, items, A2, B2, lessThan, cache[A1.length()..]); | 331 | mergeInto(T, items, A2, B2, context, lessThan, cache[A1.length()..]); |
| 316 | } else { | 332 | } else { |
| 317 | // copy A2 and B2 into the cache in the same order | 333 | // copy A2 and B2 into the cache in the same order |
| 318 | mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]); | 334 | mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]); |
| ... | @@ -324,13 +340,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -324,13 +340,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 324 | const A3 = Range.init(0, A1.length()); | 340 | const A3 = Range.init(0, A1.length()); |
| 325 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); | 341 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); |
| 326 | 342 | ||
| 327 | if (lessThan(cache[B3.end - 1], cache[A3.start])) { | 343 | if (lessThan(context, cache[B3.end - 1], cache[A3.start])) { |
| 328 | // the two ranges are in reverse order, so copy them in reverse order into the items | 344 | // the two ranges are in reverse order, so copy them in reverse order into the items |
| 329 | mem.copy(T, items[A1.start + A2.length() ..], cache[A3.start..A3.end]); | 345 | mem.copy(T, items[A1.start + A2.length() ..], cache[A3.start..A3.end]); |
| 330 | mem.copy(T, items[A1.start..], cache[B3.start..B3.end]); | 346 | mem.copy(T, items[A1.start..], cache[B3.start..B3.end]); |
| 331 | } else if (lessThan(cache[B3.start], cache[A3.end - 1])) { | 347 | } else if (lessThan(context, cache[B3.start], cache[A3.end - 1])) { |
| 332 | // these two ranges weren't already in order, so merge them back into the items | 348 | // these two ranges weren't already in order, so merge them back into the items |
| 333 | mergeInto(T, cache[0..], A3, B3, lessThan, items[A1.start..]); | 349 | mergeInto(T, cache[0..], A3, B3, context, lessThan, items[A1.start..]); |
| 334 | } else { | 350 | } else { |
| 335 | // copy A3 and B3 into the items in the same order | 351 | // copy A3 and B3 into the items in the same order |
| 336 | mem.copy(T, items[A1.start..], cache[A3.start..A3.end]); | 352 | mem.copy(T, items[A1.start..], cache[A3.start..A3.end]); |
| ... | @@ -347,13 +363,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -347,13 +363,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 347 | var A = iterator.nextRange(); | 363 | var A = iterator.nextRange(); |
| 348 | var B = iterator.nextRange(); | 364 | var B = iterator.nextRange(); |
| 349 | 365 | ||
| 350 | if (lessThan(items[B.end - 1], items[A.start])) { | 366 | if (lessThan(context, items[B.end - 1], items[A.start])) { |
| 351 | // the two ranges are in reverse order, so a simple rotation should fix it | 367 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 352 | mem.rotate(T, items[A.start..B.end], A.length()); | 368 | mem.rotate(T, items[A.start..B.end], A.length()); |
| 353 | } else if (lessThan(items[B.start], items[A.end - 1])) { | 369 | } else if (lessThan(context, items[B.start], items[A.end - 1])) { |
| 354 | // these two ranges weren't already in order, so we'll need to merge them! | 370 | // these two ranges weren't already in order, so we'll need to merge them! |
| 355 | mem.copy(T, cache[0..], items[A.start..A.end]); | 371 | mem.copy(T, cache[0..], items[A.start..A.end]); |
| 356 | mergeExternal(T, items, A, B, lessThan, cache[0..]); | 372 | mergeExternal(T, items, A, B, context, lessThan, cache[0..]); |
| 357 | } | 373 | } |
| 358 | } | 374 | } |
| 359 | } | 375 | } |
| ... | @@ -435,7 +451,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -435,7 +451,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 435 | last = index; | 451 | last = index; |
| 436 | count += 1; | 452 | count += 1; |
| 437 | }) { | 453 | }) { |
| 438 | index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count); | 454 | index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), context, lessThan, find - count); |
| 439 | if (index == A.end) break; | 455 | if (index == A.end) break; |
| 440 | } | 456 | } |
| 441 | index = last; | 457 | index = last; |
| ... | @@ -493,7 +509,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -493,7 +509,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 493 | last = index - 1; | 509 | last = index - 1; |
| 494 | count += 1; | 510 | count += 1; |
| 495 | }) { | 511 | }) { |
| 496 | index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count); | 512 | index = findFirstBackward(T, items, items[last], Range.init(B.start, last), context, lessThan, find - count); |
| 497 | if (index == B.start) break; | 513 | if (index == B.start) break; |
| 498 | } | 514 | } |
| 499 | index = last; | 515 | index = last; |
| ... | @@ -558,7 +574,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -558,7 +574,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 558 | index = pull[pull_index].from; | 574 | index = pull[pull_index].from; |
| 559 | count = 1; | 575 | count = 1; |
| 560 | while (count < length) : (count += 1) { | 576 | while (count < length) : (count += 1) { |
| 561 | index = findFirstBackward(T, items, items[index - 1], Range.init(pull[pull_index].to, pull[pull_index].from - (count - 1)), lessThan, length - count); | 577 | index = findFirstBackward(T, items, items[index - 1], Range.init(pull[pull_index].to, pull[pull_index].from - (count - 1)), context, lessThan, length - count); |
| 562 | const range = Range.init(index + 1, pull[pull_index].from + 1); | 578 | const range = Range.init(index + 1, pull[pull_index].from + 1); |
| 563 | mem.rotate(T, items[range.start..range.end], range.length() - count); | 579 | mem.rotate(T, items[range.start..range.end], range.length() - count); |
| 564 | pull[pull_index].from = index + count; | 580 | pull[pull_index].from = index + count; |
| ... | @@ -568,7 +584,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -568,7 +584,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 568 | index = pull[pull_index].from + 1; | 584 | index = pull[pull_index].from + 1; |
| 569 | count = 1; | 585 | count = 1; |
| 570 | while (count < length) : (count += 1) { | 586 | while (count < length) : (count += 1) { |
| 571 | index = findLastForward(T, items, items[index], Range.init(index, pull[pull_index].to), lessThan, length - count); | 587 | index = findLastForward(T, items, items[index], Range.init(index, pull[pull_index].to), context, lessThan, length - count); |
| 572 | const range = Range.init(pull[pull_index].from, index - 1); | 588 | const range = Range.init(pull[pull_index].from, index - 1); |
| 573 | mem.rotate(T, items[range.start..range.end], count); | 589 | mem.rotate(T, items[range.start..range.end], count); |
| 574 | pull[pull_index].from = index - 1 - count; | 590 | pull[pull_index].from = index - 1 - count; |
| ... | @@ -615,10 +631,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -615,10 +631,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 615 | } | 631 | } |
| 616 | } | 632 | } |
| 617 | 633 | ||
| 618 | if (lessThan(items[B.end - 1], items[A.start])) { | 634 | if (lessThan(context, items[B.end - 1], items[A.start])) { |
| 619 | // the two ranges are in reverse order, so a simple rotation should fix it | 635 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 620 | mem.rotate(T, items[A.start..B.end], A.length()); | 636 | mem.rotate(T, items[A.start..B.end], A.length()); |
| 621 | } else if (lessThan(items[A.end], items[A.end - 1])) { | 637 | } else if (lessThan(context, items[A.end], items[A.end - 1])) { |
| 622 | // these two ranges weren't already in order, so we'll need to merge them! | 638 | // these two ranges weren't already in order, so we'll need to merge them! |
| 623 | var findA: usize = undefined; | 639 | var findA: usize = undefined; |
| 624 | 640 | ||
| ... | @@ -656,16 +672,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -656,16 +672,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 656 | while (true) { | 672 | while (true) { |
| 657 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, | 673 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, |
| 658 | // then drop that minimum A block behind. or if there are no B blocks left then keep dropping the remaining A blocks. | 674 | // then drop that minimum A block behind. or if there are no B blocks left then keep dropping the remaining A blocks. |
| 659 | if ((lastB.length() > 0 and !lessThan(items[lastB.end - 1], items[indexA])) or blockB.length() == 0) { | 675 | if ((lastB.length() > 0 and !lessThan(context, items[lastB.end - 1], items[indexA])) or blockB.length() == 0) { |
| 660 | // figure out where to split the previous B block, and rotate it at the split | 676 | // figure out where to split the previous B block, and rotate it at the split |
| 661 | const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan); | 677 | const B_split = binaryFirst(T, items, items[indexA], lastB, context, lessThan); |
| 662 | const B_remaining = lastB.end - B_split; | 678 | const B_remaining = lastB.end - B_split; |
| 663 | 679 | ||
| 664 | // swap the minimum A block to the beginning of the rolling A blocks | 680 | // swap the minimum A block to the beginning of the rolling A blocks |
| 665 | var minA = blockA.start; | 681 | var minA = blockA.start; |
| 666 | findA = minA + block_size; | 682 | findA = minA + block_size; |
| 667 | while (findA < blockA.end) : (findA += block_size) { | 683 | while (findA < blockA.end) : (findA += block_size) { |
| 668 | if (lessThan(items[findA], items[minA])) { | 684 | if (lessThan(context, items[findA], items[minA])) { |
| 669 | minA = findA; | 685 | minA = findA; |
| 670 | } | 686 | } |
| 671 | } | 687 | } |
| ... | @@ -681,11 +697,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -681,11 +697,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 681 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) | 697 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) |
| 682 | 698 | ||
| 683 | if (lastA.length() <= cache.len) { | 699 | if (lastA.length() <= cache.len) { |
| 684 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]); | 700 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan, cache[0..]); |
| 685 | } else if (buffer2.length() > 0) { | 701 | } else if (buffer2.length() > 0) { |
| 686 | mergeInternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, buffer2); | 702 | mergeInternal(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan, buffer2); |
| 687 | } else { | 703 | } else { |
| 688 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan); | 704 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan); |
| 689 | } | 705 | } |
| 690 | 706 | ||
| 691 | if (buffer2.length() > 0 or block_size <= cache.len) { | 707 | if (buffer2.length() > 0 or block_size <= cache.len) { |
| ... | @@ -741,11 +757,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -741,11 +757,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 741 | 757 | ||
| 742 | // merge the last A block with the remaining B values | 758 | // merge the last A block with the remaining B values |
| 743 | if (lastA.length() <= cache.len) { | 759 | if (lastA.length() <= cache.len) { |
| 744 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]); | 760 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan, cache[0..]); |
| 745 | } else if (buffer2.length() > 0) { | 761 | } else if (buffer2.length() > 0) { |
| 746 | mergeInternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, buffer2); | 762 | mergeInternal(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan, buffer2); |
| 747 | } else { | 763 | } else { |
| 748 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B.end), lessThan); | 764 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan); |
| 749 | } | 765 | } |
| 750 | } | 766 | } |
| 751 | } | 767 | } |
| ... | @@ -755,7 +771,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -755,7 +771,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 755 | 771 | ||
| 756 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, | 772 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, |
| 757 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here | 773 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here |
| 758 | insertionSort(T, items[buffer2.start..buffer2.end], lessThan); | 774 | insertionSort(T, items[buffer2.start..buffer2.end], context, lessThan); |
| 759 | 775 | ||
| 760 | pull_index = 0; | 776 | pull_index = 0; |
| 761 | while (pull_index < 2) : (pull_index += 1) { | 777 | while (pull_index < 2) : (pull_index += 1) { |
| ... | @@ -764,7 +780,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -764,7 +780,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 764 | // the values were pulled out to the left, so redistribute them back to the right | 780 | // the values were pulled out to the left, so redistribute them back to the right |
| 765 | var buffer = Range.init(pull[pull_index].range.start, pull[pull_index].range.start + pull[pull_index].count); | 781 | var buffer = Range.init(pull[pull_index].range.start, pull[pull_index].range.start + pull[pull_index].count); |
| 766 | while (buffer.length() > 0) { | 782 | while (buffer.length() > 0) { |
| 767 | index = findFirstForward(T, items, items[buffer.start], Range.init(buffer.end, pull[pull_index].range.end), lessThan, unique); | 783 | index = findFirstForward(T, items, items[buffer.start], Range.init(buffer.end, pull[pull_index].range.end), context, lessThan, unique); |
| 768 | const amount = index - buffer.end; | 784 | const amount = index - buffer.end; |
| 769 | mem.rotate(T, items[buffer.start..index], buffer.length()); | 785 | mem.rotate(T, items[buffer.start..index], buffer.length()); |
| 770 | buffer.start += (amount + 1); | 786 | buffer.start += (amount + 1); |
| ... | @@ -775,7 +791,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -775,7 +791,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 775 | // the values were pulled out to the right, so redistribute them back to the left | 791 | // the values were pulled out to the right, so redistribute them back to the left |
| 776 | var buffer = Range.init(pull[pull_index].range.end - pull[pull_index].count, pull[pull_index].range.end); | 792 | var buffer = Range.init(pull[pull_index].range.end - pull[pull_index].count, pull[pull_index].range.end); |
| 777 | while (buffer.length() > 0) { | 793 | while (buffer.length() > 0) { |
| 778 | index = findLastBackward(T, items, items[buffer.end - 1], Range.init(pull[pull_index].range.start, buffer.start), lessThan, unique); | 794 | index = findLastBackward(T, items, items[buffer.end - 1], Range.init(pull[pull_index].range.start, buffer.start), context, lessThan, unique); |
| 779 | const amount = buffer.start - index; | 795 | const amount = buffer.start - index; |
| 780 | mem.rotate(T, items[index..buffer.end], amount); | 796 | mem.rotate(T, items[index..buffer.end], amount); |
| 781 | buffer.start -= amount; | 797 | buffer.start -= amount; |
| ... | @@ -792,7 +808,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -792,7 +808,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 792 | } | 808 | } |
| 793 | 809 | ||
| 794 | // merge operation without a buffer | 810 | // merge operation without a buffer |
| 795 | fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessThan: fn (T, T) bool) void { | 811 | fn mergeInPlace( |
| 812 | comptime T: type, | ||
| 813 | items: []T, | ||
| 814 | A_arg: Range, | ||
| 815 | B_arg: Range, | ||
| 816 | context: var, | ||
| 817 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 818 | ) void { | ||
| 796 | if (A_arg.length() == 0 or B_arg.length() == 0) return; | 819 | if (A_arg.length() == 0 or B_arg.length() == 0) return; |
| 797 | 820 | ||
| 798 | // this just repeatedly binary searches into B and rotates A into position. | 821 | // this just repeatedly binary searches into B and rotates A into position. |
| ... | @@ -818,7 +841,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh | ... | @@ -818,7 +841,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh |
| 818 | 841 | ||
| 819 | while (true) { | 842 | while (true) { |
| 820 | // find the first place in B where the first item in A needs to be inserted | 843 | // find the first place in B where the first item in A needs to be inserted |
| 821 | const mid = binaryFirst(T, items, items[A.start], B, lessThan); | 844 | const mid = binaryFirst(T, items, items[A.start], B, context, lessThan); |
| 822 | 845 | ||
| 823 | // rotate A into place | 846 | // rotate A into place |
| 824 | const amount = mid - A.end; | 847 | const amount = mid - A.end; |
| ... | @@ -828,13 +851,21 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh | ... | @@ -828,13 +851,21 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh |
| 828 | // calculate the new A and B ranges | 851 | // calculate the new A and B ranges |
| 829 | B.start = mid; | 852 | B.start = mid; |
| 830 | A = Range.init(A.start + amount, B.start); | 853 | A = Range.init(A.start + amount, B.start); |
| 831 | A.start = binaryLast(T, items, items[A.start], A, lessThan); | 854 | A.start = binaryLast(T, items, items[A.start], A, context, lessThan); |
| 832 | if (A.length() == 0) break; | 855 | if (A.length() == 0) break; |
| 833 | } | 856 | } |
| 834 | } | 857 | } |
| 835 | 858 | ||
| 836 | // merge operation using an internal buffer | 859 | // merge operation using an internal buffer |
| 837 | fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, buffer: Range) void { | 860 | fn mergeInternal( |
| 861 | comptime T: type, | ||
| 862 | items: []T, | ||
| 863 | A: Range, | ||
| 864 | B: Range, | ||
| 865 | context: var, | ||
| 866 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 867 | buffer: Range, | ||
| 868 | ) void { | ||
| 838 | // whenever we find a value to add to the final array, swap it with the value that's already in that spot | 869 | // whenever we find a value to add to the final array, swap it with the value that's already in that spot |
| 839 | // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order | 870 | // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order |
| 840 | var A_count: usize = 0; | 871 | var A_count: usize = 0; |
| ... | @@ -843,7 +874,7 @@ fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -843,7 +874,7 @@ fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 843 | 874 | ||
| 844 | if (B.length() > 0 and A.length() > 0) { | 875 | if (B.length() > 0 and A.length() > 0) { |
| 845 | while (true) { | 876 | while (true) { |
| 846 | if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) { | 877 | if (!lessThan(context, items[B.start + B_count], items[buffer.start + A_count])) { |
| 847 | mem.swap(T, &items[A.start + insert], &items[buffer.start + A_count]); | 878 | mem.swap(T, &items[A.start + insert], &items[buffer.start + A_count]); |
| 848 | A_count += 1; | 879 | A_count += 1; |
| 849 | insert += 1; | 880 | insert += 1; |
| ... | @@ -870,63 +901,102 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s | ... | @@ -870,63 +901,102 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s |
| 870 | 901 | ||
| 871 | // combine a linear search with a binary search to reduce the number of comparisons in situations | 902 | // combine a linear search with a binary search to reduce the number of comparisons in situations |
| 872 | // where have some idea as to how many unique values there are and where the next value might be | 903 | // where have some idea as to how many unique values there are and where the next value might be |
| 873 | fn findFirstForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 904 | fn findFirstForward( |
| 905 | comptime T: type, | ||
| 906 | items: []T, | ||
| 907 | value: T, | ||
| 908 | range: Range, | ||
| 909 | context: var, | ||
| 910 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 911 | unique: usize, | ||
| 912 | ) usize { | ||
| 874 | if (range.length() == 0) return range.start; | 913 | if (range.length() == 0) return range.start; |
| 875 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 914 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 876 | 915 | ||
| 877 | var index = range.start + skip; | 916 | var index = range.start + skip; |
| 878 | while (lessThan(items[index - 1], value)) : (index += skip) { | 917 | while (lessThan(context, items[index - 1], value)) : (index += skip) { |
| 879 | if (index >= range.end - skip) { | 918 | if (index >= range.end - skip) { |
| 880 | return binaryFirst(T, items, value, Range.init(index, range.end), lessThan); | 919 | return binaryFirst(T, items, value, Range.init(index, range.end), context, lessThan); |
| 881 | } | 920 | } |
| 882 | } | 921 | } |
| 883 | 922 | ||
| 884 | return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan); | 923 | return binaryFirst(T, items, value, Range.init(index - skip, index), context, lessThan); |
| 885 | } | 924 | } |
| 886 | 925 | ||
| 887 | fn findFirstBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 926 | fn findFirstBackward( |
| 927 | comptime T: type, | ||
| 928 | items: []T, | ||
| 929 | value: T, | ||
| 930 | range: Range, | ||
| 931 | context: var, | ||
| 932 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 933 | unique: usize, | ||
| 934 | ) usize { | ||
| 888 | if (range.length() == 0) return range.start; | 935 | if (range.length() == 0) return range.start; |
| 889 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 936 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 890 | 937 | ||
| 891 | var index = range.end - skip; | 938 | var index = range.end - skip; |
| 892 | while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) { | 939 | while (index > range.start and !lessThan(context, items[index - 1], value)) : (index -= skip) { |
| 893 | if (index < range.start + skip) { | 940 | if (index < range.start + skip) { |
| 894 | return binaryFirst(T, items, value, Range.init(range.start, index), lessThan); | 941 | return binaryFirst(T, items, value, Range.init(range.start, index), context, lessThan); |
| 895 | } | 942 | } |
| 896 | } | 943 | } |
| 897 | 944 | ||
| 898 | return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan); | 945 | return binaryFirst(T, items, value, Range.init(index, index + skip), context, lessThan); |
| 899 | } | 946 | } |
| 900 | 947 | ||
| 901 | fn findLastForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 948 | fn findLastForward( |
| 949 | comptime T: type, | ||
| 950 | items: []T, | ||
| 951 | value: T, | ||
| 952 | range: Range, | ||
| 953 | context: var, | ||
| 954 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 955 | unique: usize, | ||
| 956 | ) usize { | ||
| 902 | if (range.length() == 0) return range.start; | 957 | if (range.length() == 0) return range.start; |
| 903 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 958 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 904 | 959 | ||
| 905 | var index = range.start + skip; | 960 | var index = range.start + skip; |
| 906 | while (!lessThan(value, items[index - 1])) : (index += skip) { | 961 | while (!lessThan(context, value, items[index - 1])) : (index += skip) { |
| 907 | if (index >= range.end - skip) { | 962 | if (index >= range.end - skip) { |
| 908 | return binaryLast(T, items, value, Range.init(index, range.end), lessThan); | 963 | return binaryLast(T, items, value, Range.init(index, range.end), context, lessThan); |
| 909 | } | 964 | } |
| 910 | } | 965 | } |
| 911 | 966 | ||
| 912 | return binaryLast(T, items, value, Range.init(index - skip, index), lessThan); | 967 | return binaryLast(T, items, value, Range.init(index - skip, index), context, lessThan); |
| 913 | } | 968 | } |
| 914 | 969 | ||
| 915 | fn findLastBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 970 | fn findLastBackward( |
| 971 | comptime T: type, | ||
| 972 | items: []T, | ||
| 973 | value: T, | ||
| 974 | range: Range, | ||
| 975 | context: var, | ||
| 976 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 977 | unique: usize, | ||
| 978 | ) usize { | ||
| 916 | if (range.length() == 0) return range.start; | 979 | if (range.length() == 0) return range.start; |
| 917 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 980 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 918 | 981 | ||
| 919 | var index = range.end - skip; | 982 | var index = range.end - skip; |
| 920 | while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) { | 983 | while (index > range.start and lessThan(context, value, items[index - 1])) : (index -= skip) { |
| 921 | if (index < range.start + skip) { | 984 | if (index < range.start + skip) { |
| 922 | return binaryLast(T, items, value, Range.init(range.start, index), lessThan); | 985 | return binaryLast(T, items, value, Range.init(range.start, index), context, lessThan); |
| 923 | } | 986 | } |
| 924 | } | 987 | } |
| 925 | 988 | ||
| 926 | return binaryLast(T, items, value, Range.init(index, index + skip), lessThan); | 989 | return binaryLast(T, items, value, Range.init(index, index + skip), context, lessThan); |
| 927 | } | 990 | } |
| 928 | 991 | ||
| 929 | fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize { | 992 | fn binaryFirst( |
| 993 | comptime T: type, | ||
| 994 | items: []T, | ||
| 995 | value: T, | ||
| 996 | range: Range, | ||
| 997 | context: var, | ||
| 998 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 999 | ) usize { | ||
| 930 | var curr = range.start; | 1000 | var curr = range.start; |
| 931 | var size = range.length(); | 1001 | var size = range.length(); |
| 932 | if (range.start >= range.end) return range.end; | 1002 | if (range.start >= range.end) return range.end; |
| ... | @@ -935,14 +1005,21 @@ fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: f | ... | @@ -935,14 +1005,21 @@ fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: f |
| 935 | 1005 | ||
| 936 | size /= 2; | 1006 | size /= 2; |
| 937 | const mid = items[curr + size]; | 1007 | const mid = items[curr + size]; |
| 938 | if (lessThan(mid, value)) { | 1008 | if (lessThan(context, mid, value)) { |
| 939 | curr += size + offset; | 1009 | curr += size + offset; |
| 940 | } | 1010 | } |
| 941 | } | 1011 | } |
| 942 | return curr; | 1012 | return curr; |
| 943 | } | 1013 | } |
| 944 | 1014 | ||
| 945 | fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize { | 1015 | fn binaryLast( |
| 1016 | comptime T: type, | ||
| 1017 | items: []T, | ||
| 1018 | value: T, | ||
| 1019 | range: Range, | ||
| 1020 | context: var, | ||
| 1021 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 1022 | ) usize { | ||
| 946 | var curr = range.start; | 1023 | var curr = range.start; |
| 947 | var size = range.length(); | 1024 | var size = range.length(); |
| 948 | if (range.start >= range.end) return range.end; | 1025 | if (range.start >= range.end) return range.end; |
| ... | @@ -951,14 +1028,22 @@ fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn | ... | @@ -951,14 +1028,22 @@ fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn |
| 951 | 1028 | ||
| 952 | size /= 2; | 1029 | size /= 2; |
| 953 | const mid = items[curr + size]; | 1030 | const mid = items[curr + size]; |
| 954 | if (!lessThan(value, mid)) { | 1031 | if (!lessThan(context, value, mid)) { |
| 955 | curr += size + offset; | 1032 | curr += size + offset; |
| 956 | } | 1033 | } |
| 957 | } | 1034 | } |
| 958 | return curr; | 1035 | return curr; |
| 959 | } | 1036 | } |
| 960 | 1037 | ||
| 961 | fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T) bool, into: []T) void { | 1038 | fn mergeInto( |
| 1039 | comptime T: type, | ||
| 1040 | from: []T, | ||
| 1041 | A: Range, | ||
| 1042 | B: Range, | ||
| 1043 | context: var, | ||
| 1044 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 1045 | into: []T, | ||
| 1046 | ) void { | ||
| 962 | var A_index: usize = A.start; | 1047 | var A_index: usize = A.start; |
| 963 | var B_index: usize = B.start; | 1048 | var B_index: usize = B.start; |
| 964 | const A_last = A.end; | 1049 | const A_last = A.end; |
| ... | @@ -966,7 +1051,7 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T | ... | @@ -966,7 +1051,7 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T |
| 966 | var insert_index: usize = 0; | 1051 | var insert_index: usize = 0; |
| 967 | 1052 | ||
| 968 | while (true) { | 1053 | while (true) { |
| 969 | if (!lessThan(from[B_index], from[A_index])) { | 1054 | if (!lessThan(context, from[B_index], from[A_index])) { |
| 970 | into[insert_index] = from[A_index]; | 1055 | into[insert_index] = from[A_index]; |
| 971 | A_index += 1; | 1056 | A_index += 1; |
| 972 | insert_index += 1; | 1057 | insert_index += 1; |
| ... | @@ -988,7 +1073,15 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T | ... | @@ -988,7 +1073,15 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T |
| 988 | } | 1073 | } |
| 989 | } | 1074 | } |
| 990 | 1075 | ||
| 991 | fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, cache: []T) void { | 1076 | fn mergeExternal( |
| 1077 | comptime T: type, | ||
| 1078 | items: []T, | ||
| 1079 | A: Range, | ||
| 1080 | B: Range, | ||
| 1081 | context: var, | ||
| 1082 | comptime lessThan: fn (@TypeOf(context), T, T) bool, | ||
| 1083 | cache: []T, | ||
| 1084 | ) void { | ||
| 992 | // A fits into the cache, so use that instead of the internal buffer | 1085 | // A fits into the cache, so use that instead of the internal buffer |
| 993 | var A_index: usize = 0; | 1086 | var A_index: usize = 0; |
| 994 | var B_index: usize = B.start; | 1087 | var B_index: usize = B.start; |
| ... | @@ -998,7 +1091,7 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -998,7 +1091,7 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 998 | 1091 | ||
| 999 | if (B.length() > 0 and A.length() > 0) { | 1092 | if (B.length() > 0 and A.length() > 0) { |
| 1000 | while (true) { | 1093 | while (true) { |
| 1001 | if (!lessThan(items[B_index], cache[A_index])) { | 1094 | if (!lessThan(context, items[B_index], cache[A_index])) { |
| 1002 | items[insert_index] = cache[A_index]; | 1095 | items[insert_index] = cache[A_index]; |
| 1003 | A_index += 1; | 1096 | A_index += 1; |
| 1004 | insert_index += 1; | 1097 | insert_index += 1; |
| ... | @@ -1016,17 +1109,25 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -1016,17 +1109,25 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 1016 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); | 1109 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); |
| 1017 | } | 1110 | } |
| 1018 | 1111 | ||
| 1019 | fn swap(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool, order: *[8]u8, x: usize, y: usize) void { | 1112 | fn swap( |
| 1020 | if (lessThan(items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(items[x], items[y]))) { | 1113 | comptime T: type, |
| 1114 | items: []T, | ||
| 1115 | context: var, | ||
| 1116 | comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1117 | order: *[8]u8, | ||
| 1118 | x: usize, | ||
| 1119 | y: usize, | ||
| 1120 | ) void { | ||
| 1121 | if (lessThan(context, items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(context, items[x], items[y]))) { | ||
| 1021 | mem.swap(T, &items[x], &items[y]); | 1122 | mem.swap(T, &items[x], &items[y]); |
| 1022 | mem.swap(u8, &(order.*)[x], &(order.*)[y]); | 1123 | mem.swap(u8, &(order.*)[x], &(order.*)[y]); |
| 1023 | } | 1124 | } |
| 1024 | } | 1125 | } |
| 1025 | 1126 | ||
| 1026 | // Use these to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. | 1127 | /// Use to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. |
| 1027 | pub fn asc(comptime T: type) fn (T, T) bool { | 1128 | pub fn asc(comptime T: type) fn (void, T, T) bool { |
| 1028 | const impl = struct { | 1129 | const impl = struct { |
| 1029 | fn inner(a: T, b: T) bool { | 1130 | fn inner(context: void, a: T, b: T) bool { |
| 1030 | return a < b; | 1131 | return a < b; |
| 1031 | } | 1132 | } |
| 1032 | }; | 1133 | }; |
| ... | @@ -1034,9 +1135,10 @@ pub fn asc(comptime T: type) fn (T, T) bool { | ... | @@ -1034,9 +1135,10 @@ pub fn asc(comptime T: type) fn (T, T) bool { |
| 1034 | return impl.inner; | 1135 | return impl.inner; |
| 1035 | } | 1136 | } |
| 1036 | 1137 | ||
| 1037 | pub fn desc(comptime T: type) fn (T, T) bool { | 1138 | /// Use to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. |
| 1139 | pub fn desc(comptime T: type) fn (void, T, T) bool { | ||
| 1038 | const impl = struct { | 1140 | const impl = struct { |
| 1039 | fn inner(a: T, b: T) bool { | 1141 | fn inner(context: void, a: T, b: T) bool { |
| 1040 | return a > b; | 1142 | return a > b; |
| 1041 | } | 1143 | } |
| 1042 | }; | 1144 | }; |
| ... | @@ -1085,7 +1187,7 @@ fn testStableSort() void { | ... | @@ -1085,7 +1187,7 @@ fn testStableSort() void { |
| 1085 | }, | 1187 | }, |
| 1086 | }; | 1188 | }; |
| 1087 | for (cases) |*case| { | 1189 | for (cases) |*case| { |
| 1088 | insertionSort(IdAndValue, (case.*)[0..], cmpByValue); | 1190 | insertionSort(IdAndValue, (case.*)[0..], {}, cmpByValue); |
| 1089 | for (case.*) |item, i| { | 1191 | for (case.*) |item, i| { |
| 1090 | testing.expect(item.id == expected[i].id); | 1192 | testing.expect(item.id == expected[i].id); |
| 1091 | testing.expect(item.value == expected[i].value); | 1193 | testing.expect(item.value == expected[i].value); |
| ... | @@ -1096,11 +1198,16 @@ const IdAndValue = struct { | ... | @@ -1096,11 +1198,16 @@ const IdAndValue = struct { |
| 1096 | id: usize, | 1198 | id: usize, |
| 1097 | value: i32, | 1199 | value: i32, |
| 1098 | }; | 1200 | }; |
| 1099 | fn cmpByValue(a: IdAndValue, b: IdAndValue) bool { | 1201 | fn cmpByValue(context: void, a: IdAndValue, b: IdAndValue) bool { |
| 1100 | return asc(i32)(a.value, b.value); | 1202 | return asc_i32(context, a.value, b.value); |
| 1101 | } | 1203 | } |
| 1102 | 1204 | ||
| 1103 | test "std.sort" { | 1205 | const asc_u8 = asc(u8); |
| 1206 | const asc_i32 = asc(i32); | ||
| 1207 | const desc_u8 = desc(u8); | ||
| 1208 | const desc_i32 = desc(i32); | ||
| 1209 | |||
| 1210 | test "sort" { | ||
| 1104 | const u8cases = [_][]const []const u8{ | 1211 | const u8cases = [_][]const []const u8{ |
| 1105 | &[_][]const u8{ | 1212 | &[_][]const u8{ |
| 1106 | "", | 1213 | "", |
| ... | @@ -1132,7 +1239,7 @@ test "std.sort" { | ... | @@ -1132,7 +1239,7 @@ test "std.sort" { |
| 1132 | var buf: [8]u8 = undefined; | 1239 | var buf: [8]u8 = undefined; |
| 1133 | const slice = buf[0..case[0].len]; | 1240 | const slice = buf[0..case[0].len]; |
| 1134 | mem.copy(u8, slice, case[0]); | 1241 | mem.copy(u8, slice, case[0]); |
| 1135 | sort(u8, slice, asc(u8)); | 1242 | sort(u8, slice, {}, asc_u8); |
| 1136 | testing.expect(mem.eql(u8, slice, case[1])); | 1243 | testing.expect(mem.eql(u8, slice, case[1])); |
| 1137 | } | 1244 | } |
| 1138 | 1245 | ||
| ... | @@ -1167,12 +1274,12 @@ test "std.sort" { | ... | @@ -1167,12 +1274,12 @@ test "std.sort" { |
| 1167 | var buf: [8]i32 = undefined; | 1274 | var buf: [8]i32 = undefined; |
| 1168 | const slice = buf[0..case[0].len]; | 1275 | const slice = buf[0..case[0].len]; |
| 1169 | mem.copy(i32, slice, case[0]); | 1276 | mem.copy(i32, slice, case[0]); |
| 1170 | sort(i32, slice, asc(i32)); | 1277 | sort(i32, slice, {}, asc_i32); |
| 1171 | testing.expect(mem.eql(i32, slice, case[1])); | 1278 | testing.expect(mem.eql(i32, slice, case[1])); |
| 1172 | } | 1279 | } |
| 1173 | } | 1280 | } |
| 1174 | 1281 | ||
| 1175 | test "std.sort descending" { | 1282 | test "sort descending" { |
| 1176 | const rev_cases = [_][]const []const i32{ | 1283 | const rev_cases = [_][]const []const i32{ |
| 1177 | &[_][]const i32{ | 1284 | &[_][]const i32{ |
| 1178 | &[_]i32{}, | 1285 | &[_]i32{}, |
| ... | @@ -1204,14 +1311,14 @@ test "std.sort descending" { | ... | @@ -1204,14 +1311,14 @@ test "std.sort descending" { |
| 1204 | var buf: [8]i32 = undefined; | 1311 | var buf: [8]i32 = undefined; |
| 1205 | const slice = buf[0..case[0].len]; | 1312 | const slice = buf[0..case[0].len]; |
| 1206 | mem.copy(i32, slice, case[0]); | 1313 | mem.copy(i32, slice, case[0]); |
| 1207 | sort(i32, slice, desc(i32)); | 1314 | sort(i32, slice, {}, desc_i32); |
| 1208 | testing.expect(mem.eql(i32, slice, case[1])); | 1315 | testing.expect(mem.eql(i32, slice, case[1])); |
| 1209 | } | 1316 | } |
| 1210 | } | 1317 | } |
| 1211 | 1318 | ||
| 1212 | test "another sort case" { | 1319 | test "another sort case" { |
| 1213 | var arr = [_]i32{ 5, 3, 1, 2, 4 }; | 1320 | var arr = [_]i32{ 5, 3, 1, 2, 4 }; |
| 1214 | sort(i32, arr[0..], asc(i32)); | 1321 | sort(i32, arr[0..], {}, asc_i32); |
| 1215 | 1322 | ||
| 1216 | testing.expect(mem.eql(i32, &arr, &[_]i32{ 1, 2, 3, 4, 5 })); | 1323 | testing.expect(mem.eql(i32, &arr, &[_]i32{ 1, 2, 3, 4, 5 })); |
| 1217 | } | 1324 | } |
| ... | @@ -1236,7 +1343,7 @@ fn fuzzTest(rng: *std.rand.Random) !void { | ... | @@ -1236,7 +1343,7 @@ fn fuzzTest(rng: *std.rand.Random) !void { |
| 1236 | item.id = index; | 1343 | item.id = index; |
| 1237 | item.value = rng.intRangeLessThan(i32, 0, 100); | 1344 | item.value = rng.intRangeLessThan(i32, 0, 100); |
| 1238 | } | 1345 | } |
| 1239 | sort(IdAndValue, array, cmpByValue); | 1346 | sort(IdAndValue, array, {}, cmpByValue); |
| 1240 | 1347 | ||
| 1241 | var index: usize = 1; | 1348 | var index: usize = 1; |
| 1242 | while (index < array.len) : (index += 1) { | 1349 | while (index < array.len) : (index += 1) { |
| ... | @@ -1248,7 +1355,12 @@ fn fuzzTest(rng: *std.rand.Random) !void { | ... | @@ -1248,7 +1355,12 @@ fn fuzzTest(rng: *std.rand.Random) !void { |
| 1248 | } | 1355 | } |
| 1249 | } | 1356 | } |
| 1250 | 1357 | ||
| 1251 | pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?usize { | 1358 | pub fn argMin( |
| 1359 | comptime T: type, | ||
| 1360 | items: []const T, | ||
| 1361 | context: var, | ||
| 1362 | comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1363 | ) ?usize { | ||
| 1252 | if (items.len == 0) { | 1364 | if (items.len == 0) { |
| 1253 | return null; | 1365 | return null; |
| 1254 | } | 1366 | } |
| ... | @@ -1256,7 +1368,7 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1256,7 +1368,7 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1256 | var smallest = items[0]; | 1368 | var smallest = items[0]; |
| 1257 | var smallest_index: usize = 0; | 1369 | var smallest_index: usize = 0; |
| 1258 | for (items[1..]) |item, i| { | 1370 | for (items[1..]) |item, i| { |
| 1259 | if (lessThan(item, smallest)) { | 1371 | if (lessThan(context, item, smallest)) { |
| 1260 | smallest = item; | 1372 | smallest = item; |
| 1261 | smallest_index = i + 1; | 1373 | smallest_index = i + 1; |
| 1262 | } | 1374 | } |
| ... | @@ -1265,32 +1377,42 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1265,32 +1377,42 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1265 | return smallest_index; | 1377 | return smallest_index; |
| 1266 | } | 1378 | } |
| 1267 | 1379 | ||
| 1268 | test "std.sort.argMin" { | 1380 | test "argMin" { |
| 1269 | testing.expectEqual(@as(?usize, null), argMin(i32, &[_]i32{}, asc(i32))); | 1381 | testing.expectEqual(@as(?usize, null), argMin(i32, &[_]i32{}, {}, asc_i32)); |
| 1270 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{1}, asc(i32))); | 1382 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{1}, {}, asc_i32)); |
| 1271 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1383 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1272 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1384 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1273 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1385 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1274 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1386 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1275 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1387 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1276 | } | 1388 | } |
| 1277 | 1389 | ||
| 1278 | pub fn min(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?T { | 1390 | pub fn min( |
| 1279 | const i = argMin(T, items, lessThan) orelse return null; | 1391 | comptime T: type, |
| 1392 | items: []const T, | ||
| 1393 | context: var, | ||
| 1394 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1395 | ) ?T { | ||
| 1396 | const i = argMin(T, items, context, lessThan) orelse return null; | ||
| 1280 | return items[i]; | 1397 | return items[i]; |
| 1281 | } | 1398 | } |
| 1282 | 1399 | ||
| 1283 | test "std.sort.min" { | 1400 | test "min" { |
| 1284 | testing.expectEqual(@as(?i32, null), min(i32, &[_]i32{}, asc(i32))); | 1401 | testing.expectEqual(@as(?i32, null), min(i32, &[_]i32{}, {}, asc_i32)); |
| 1285 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{1}, asc(i32))); | 1402 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{1}, {}, asc_i32)); |
| 1286 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1403 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1287 | testing.expectEqual(@as(?i32, 2), min(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1404 | testing.expectEqual(@as(?i32, 2), min(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1288 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1405 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1289 | testing.expectEqual(@as(?i32, -10), min(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1406 | testing.expectEqual(@as(?i32, -10), min(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1290 | testing.expectEqual(@as(?i32, 7), min(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1407 | testing.expectEqual(@as(?i32, 7), min(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1291 | } | 1408 | } |
| 1292 | 1409 | ||
| 1293 | pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?usize { | 1410 | pub fn argMax( |
| 1411 | comptime T: type, | ||
| 1412 | items: []const T, | ||
| 1413 | context: var, | ||
| 1414 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1415 | ) ?usize { | ||
| 1294 | if (items.len == 0) { | 1416 | if (items.len == 0) { |
| 1295 | return null; | 1417 | return null; |
| 1296 | } | 1418 | } |
| ... | @@ -1298,7 +1420,7 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1298,7 +1420,7 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1298 | var biggest = items[0]; | 1420 | var biggest = items[0]; |
| 1299 | var biggest_index: usize = 0; | 1421 | var biggest_index: usize = 0; |
| 1300 | for (items[1..]) |item, i| { | 1422 | for (items[1..]) |item, i| { |
| 1301 | if (lessThan(biggest, item)) { | 1423 | if (lessThan(context, biggest, item)) { |
| 1302 | biggest = item; | 1424 | biggest = item; |
| 1303 | biggest_index = i + 1; | 1425 | biggest_index = i + 1; |
| 1304 | } | 1426 | } |
| ... | @@ -1307,35 +1429,45 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1307,35 +1429,45 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1307 | return biggest_index; | 1429 | return biggest_index; |
| 1308 | } | 1430 | } |
| 1309 | 1431 | ||
| 1310 | test "std.sort.argMax" { | 1432 | test "argMax" { |
| 1311 | testing.expectEqual(@as(?usize, null), argMax(i32, &[_]i32{}, asc(i32))); | 1433 | testing.expectEqual(@as(?usize, null), argMax(i32, &[_]i32{}, {}, asc_i32)); |
| 1312 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{1}, asc(i32))); | 1434 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{1}, {}, asc_i32)); |
| 1313 | testing.expectEqual(@as(?usize, 4), argMax(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1435 | testing.expectEqual(@as(?usize, 4), argMax(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1314 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1436 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1315 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1437 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1316 | testing.expectEqual(@as(?usize, 2), argMax(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1438 | testing.expectEqual(@as(?usize, 2), argMax(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1317 | testing.expectEqual(@as(?usize, 1), argMax(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1439 | testing.expectEqual(@as(?usize, 1), argMax(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1318 | } | 1440 | } |
| 1319 | 1441 | ||
| 1320 | pub fn max(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?T { | 1442 | pub fn max( |
| 1321 | const i = argMax(T, items, lessThan) orelse return null; | 1443 | comptime T: type, |
| 1444 | items: []const T, | ||
| 1445 | context: var, | ||
| 1446 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1447 | ) ?T { | ||
| 1448 | const i = argMax(T, items, context, lessThan) orelse return null; | ||
| 1322 | return items[i]; | 1449 | return items[i]; |
| 1323 | } | 1450 | } |
| 1324 | 1451 | ||
| 1325 | test "std.sort.max" { | 1452 | test "max" { |
| 1326 | testing.expectEqual(@as(?i32, null), max(i32, &[_]i32{}, asc(i32))); | 1453 | testing.expectEqual(@as(?i32, null), max(i32, &[_]i32{}, {}, asc_i32)); |
| 1327 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{1}, asc(i32))); | 1454 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{1}, {}, asc_i32)); |
| 1328 | testing.expectEqual(@as(?i32, 5), max(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1455 | testing.expectEqual(@as(?i32, 5), max(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1329 | testing.expectEqual(@as(?i32, 9), max(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1456 | testing.expectEqual(@as(?i32, 9), max(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1330 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1457 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1331 | testing.expectEqual(@as(?i32, 10), max(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1458 | testing.expectEqual(@as(?i32, 10), max(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1332 | testing.expectEqual(@as(?i32, 3), max(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1459 | testing.expectEqual(@as(?i32, 3), max(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1333 | } | 1460 | } |
| 1334 | 1461 | ||
| 1335 | pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) bool { | 1462 | pub fn isSorted( |
| 1463 | comptime T: type, | ||
| 1464 | items: []const T, | ||
| 1465 | context: var, | ||
| 1466 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, | ||
| 1467 | ) bool { | ||
| 1336 | var i: usize = 1; | 1468 | var i: usize = 1; |
| 1337 | while (i < items.len) : (i += 1) { | 1469 | while (i < items.len) : (i += 1) { |
| 1338 | if (lessThan(items[i], items[i - 1])) { | 1470 | if (lessThan(context, items[i], items[i - 1])) { |
| 1339 | return false; | 1471 | return false; |
| 1340 | } | 1472 | } |
| 1341 | } | 1473 | } |
| ... | @@ -1343,29 +1475,29 @@ pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T | ... | @@ -1343,29 +1475,29 @@ pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T |
| 1343 | return true; | 1475 | return true; |
| 1344 | } | 1476 | } |
| 1345 | 1477 | ||
| 1346 | test "std.sort.isSorted" { | 1478 | test "isSorted" { |
| 1347 | testing.expect(isSorted(i32, &[_]i32{}, asc(i32))); | 1479 | testing.expect(isSorted(i32, &[_]i32{}, {}, asc_i32)); |
| 1348 | testing.expect(isSorted(i32, &[_]i32{10}, asc(i32))); | 1480 | testing.expect(isSorted(i32, &[_]i32{10}, {}, asc_i32)); |
| 1349 | testing.expect(isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1481 | testing.expect(isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1350 | testing.expect(isSorted(i32, &[_]i32{ -10, 1, 1, 1, 10 }, asc(i32))); | 1482 | testing.expect(isSorted(i32, &[_]i32{ -10, 1, 1, 1, 10 }, {}, asc_i32)); |
| 1351 | 1483 | ||
| 1352 | testing.expect(isSorted(i32, &[_]i32{}, desc(i32))); | 1484 | testing.expect(isSorted(i32, &[_]i32{}, {}, desc_i32)); |
| 1353 | testing.expect(isSorted(i32, &[_]i32{-20}, desc(i32))); | 1485 | testing.expect(isSorted(i32, &[_]i32{-20}, {}, desc_i32)); |
| 1354 | testing.expect(isSorted(i32, &[_]i32{ 3, 2, 1, 0, -1 }, desc(i32))); | 1486 | testing.expect(isSorted(i32, &[_]i32{ 3, 2, 1, 0, -1 }, {}, desc_i32)); |
| 1355 | testing.expect(isSorted(i32, &[_]i32{ 10, -10 }, desc(i32))); | 1487 | testing.expect(isSorted(i32, &[_]i32{ 10, -10 }, {}, desc_i32)); |
| 1356 | 1488 | ||
| 1357 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1489 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1358 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, desc(i32))); | 1490 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, desc_i32)); |
| 1359 | 1491 | ||
| 1360 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 5, 4, 3, 2, 1 }, asc(i32))); | 1492 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 5, 4, 3, 2, 1 }, {}, asc_i32)); |
| 1361 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, desc(i32))); | 1493 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, desc_i32)); |
| 1362 | 1494 | ||
| 1363 | testing.expect(isSorted(u8, "abcd", asc(u8))); | 1495 | testing.expect(isSorted(u8, "abcd", {}, asc_u8)); |
| 1364 | testing.expect(isSorted(u8, "zyxw", desc(u8))); | 1496 | testing.expect(isSorted(u8, "zyxw", {}, desc_u8)); |
| 1365 | 1497 | ||
| 1366 | testing.expectEqual(false, isSorted(u8, "abcd", desc(u8))); | 1498 | testing.expectEqual(false, isSorted(u8, "abcd", {}, desc_u8)); |
| 1367 | testing.expectEqual(false, isSorted(u8, "zyxw", asc(u8))); | 1499 | testing.expectEqual(false, isSorted(u8, "zyxw", {}, asc_u8)); |
| 1368 | 1500 | ||
| 1369 | testing.expect(isSorted(u8, "ffff", asc(u8))); | 1501 | testing.expect(isSorted(u8, "ffff", {}, asc_u8)); |
| 1370 | testing.expect(isSorted(u8, "ffff", desc(u8))); | 1502 | testing.expect(isSorted(u8, "ffff", {}, desc_u8)); |
| 1371 | } | 1503 | } |
src-self-hosted/Module.zig+57-12| ... | @@ -576,6 +576,8 @@ pub fn update(self: *Module) !void { | ... | @@ -576,6 +576,8 @@ pub fn update(self: *Module) !void { |
| 576 | // TODO Use the cache hash file system to detect which source files changed. | 576 | // TODO Use the cache hash file system to detect which source files changed. |
| 577 | // Here we simulate a full cache miss. | 577 | // Here we simulate a full cache miss. |
| 578 | // Analyze the root source file now. | 578 | // Analyze the root source file now. |
| 579 | // Source files could have been loaded for any reason; to force a refresh we unload now. | ||
| 580 | self.root_scope.unload(self.allocator); | ||
| 579 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { | 581 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { |
| 580 | error.AnalysisFail => { | 582 | error.AnalysisFail => { |
| 581 | assert(self.totalErrorCount() != 0); | 583 | assert(self.totalErrorCount() != 0); |
| ... | @@ -594,8 +596,11 @@ pub fn update(self: *Module) !void { | ... | @@ -594,8 +596,11 @@ pub fn update(self: *Module) !void { |
| 594 | try self.deleteDecl(decl); | 596 | try self.deleteDecl(decl); |
| 595 | } | 597 | } |
| 596 | 598 | ||
| 597 | // Unload all the source files from memory. | 599 | // If there are any errors, we anticipate the source files being loaded |
| 598 | self.root_scope.unload(self.allocator); | 600 | // to report error messages. Otherwise we unload all source files to save memory. |
| 601 | if (self.totalErrorCount() == 0) { | ||
| 602 | self.root_scope.unload(self.allocator); | ||
| 603 | } | ||
| 599 | 604 | ||
| 600 | try self.bin_file.flush(); | 605 | try self.bin_file.flush(); |
| 601 | self.link_error_flags = self.bin_file.error_flags; | 606 | self.link_error_flags = self.bin_file.error_flags; |
| ... | @@ -668,8 +673,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { | ... | @@ -668,8 +673,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 668 | assert(errors.items.len == self.totalErrorCount()); | 673 | assert(errors.items.len == self.totalErrorCount()); |
| 669 | 674 | ||
| 670 | return AllErrors{ | 675 | return AllErrors{ |
| 671 | .arena = arena.state, | ||
| 672 | .list = try arena.allocator.dupe(AllErrors.Message, errors.items), | 676 | .list = try arena.allocator.dupe(AllErrors.Message, errors.items), |
| 677 | .arena = arena.state, | ||
| 673 | }; | 678 | }; |
| 674 | } | 679 | } |
| 675 | 680 | ||
| ... | @@ -878,11 +883,11 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { | ... | @@ -878,11 +883,11 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 878 | const decl = kv.value; | 883 | const decl = kv.value; |
| 879 | deleted_decls.removeAssertDiscard(decl); | 884 | deleted_decls.removeAssertDiscard(decl); |
| 880 | const new_contents_hash = Decl.hashSimpleName(src_decl.contents); | 885 | const new_contents_hash = Decl.hashSimpleName(src_decl.contents); |
| 886 | //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents }); | ||
| 881 | if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) { | 887 | if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) { |
| 882 | //std.debug.warn("noticed '{}' source changed\n", .{src_decl.name}); | 888 | //std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash }); |
| 883 | decl.analysis = .outdated; | 889 | try self.markOutdatedDecl(decl); |
| 884 | decl.contents_hash = new_contents_hash; | 890 | decl.contents_hash = new_contents_hash; |
| 885 | try self.work_queue.writeItem(.{ .re_analyze_decl = decl }); | ||
| 886 | } | 891 | } |
| 887 | } else if (src_decl.cast(zir.Inst.Export)) |export_inst| { | 892 | } else if (src_decl.cast(zir.Inst.Export)) |export_inst| { |
| 888 | try exports_to_resolve.append(&export_inst.base); | 893 | try exports_to_resolve.append(&export_inst.base); |
| ... | @@ -905,6 +910,8 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { | ... | @@ -905,6 +910,8 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 905 | } | 910 | } |
| 906 | 911 | ||
| 907 | fn deleteDecl(self: *Module, decl: *Decl) !void { | 912 | fn deleteDecl(self: *Module, decl: *Decl) !void { |
| 913 | try self.deletion_set.ensureCapacity(self.allocator, self.deletion_set.items.len + decl.dependencies.items.len); | ||
| 914 | |||
| 908 | //std.debug.warn("deleting decl '{}'\n", .{decl.name}); | 915 | //std.debug.warn("deleting decl '{}'\n", .{decl.name}); |
| 909 | const name_hash = decl.fullyQualifiedNameHash(); | 916 | const name_hash = decl.fullyQualifiedNameHash(); |
| 910 | self.decl_table.removeAssertDiscard(name_hash); | 917 | self.decl_table.removeAssertDiscard(name_hash); |
| ... | @@ -916,17 +923,20 @@ fn deleteDecl(self: *Module, decl: *Decl) !void { | ... | @@ -916,17 +923,20 @@ fn deleteDecl(self: *Module, decl: *Decl) !void { |
| 916 | // another reference to it may turn up. | 923 | // another reference to it may turn up. |
| 917 | assert(!dep.deletion_flag); | 924 | assert(!dep.deletion_flag); |
| 918 | dep.deletion_flag = true; | 925 | dep.deletion_flag = true; |
| 919 | try self.deletion_set.append(self.allocator, dep); | 926 | self.deletion_set.appendAssumeCapacity(dep); |
| 920 | } | 927 | } |
| 921 | } | 928 | } |
| 922 | // Anything that depends on this deleted decl certainly needs to be re-analyzed. | 929 | // Anything that depends on this deleted decl certainly needs to be re-analyzed. |
| 923 | for (decl.dependants.items) |dep| { | 930 | for (decl.dependants.items) |dep| { |
| 924 | dep.removeDependency(decl); | 931 | dep.removeDependency(decl); |
| 925 | if (dep.analysis != .outdated) { | 932 | if (dep.analysis != .outdated) { |
| 926 | dep.analysis = .outdated; | 933 | // TODO Move this failure possibility to the top of the function. |
| 927 | try self.work_queue.writeItem(.{ .re_analyze_decl = dep }); | 934 | try self.markOutdatedDecl(dep); |
| 928 | } | 935 | } |
| 929 | } | 936 | } |
| 937 | if (self.failed_decls.remove(decl)) |entry| { | ||
| 938 | entry.value.destroy(self.allocator); | ||
| 939 | } | ||
| 930 | self.deleteDeclExports(decl); | 940 | self.deleteDeclExports(decl); |
| 931 | self.bin_file.freeDecl(decl); | 941 | self.bin_file.freeDecl(decl); |
| 932 | decl.destroy(self.allocator); | 942 | decl.destroy(self.allocator); |
| ... | @@ -1083,20 +1093,31 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi | ... | @@ -1083,20 +1093,31 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi |
| 1083 | .codegen_failure_retryable, | 1093 | .codegen_failure_retryable, |
| 1084 | .complete, | 1094 | .complete, |
| 1085 | => if (dep.generation != self.generation) { | 1095 | => if (dep.generation != self.generation) { |
| 1086 | dep.analysis = .outdated; | 1096 | try self.markOutdatedDecl(dep); |
| 1087 | try self.work_queue.writeItem(.{ .re_analyze_decl = dep }); | ||
| 1088 | }, | 1097 | }, |
| 1089 | } | 1098 | } |
| 1090 | } | 1099 | } |
| 1091 | } | 1100 | } |
| 1092 | } | 1101 | } |
| 1093 | 1102 | ||
| 1103 | fn markOutdatedDecl(self: *Module, decl: *Decl) !void { | ||
| 1104 | //std.debug.warn("mark {} outdated\n", .{decl.name}); | ||
| 1105 | try self.work_queue.writeItem(.{ .re_analyze_decl = decl }); | ||
| 1106 | if (self.failed_decls.remove(decl)) |entry| { | ||
| 1107 | entry.value.destroy(self.allocator); | ||
| 1108 | } | ||
| 1109 | decl.analysis = .outdated; | ||
| 1110 | } | ||
| 1111 | |||
| 1094 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl { | 1112 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl { |
| 1095 | const hash = Decl.hashSimpleName(old_inst.name); | 1113 | const hash = Decl.hashSimpleName(old_inst.name); |
| 1096 | if (self.decl_table.get(hash)) |kv| { | 1114 | if (self.decl_table.get(hash)) |kv| { |
| 1097 | const decl = kv.value; | 1115 | const decl = kv.value; |
| 1098 | try self.reAnalyzeDecl(decl, old_inst); | 1116 | try self.reAnalyzeDecl(decl, old_inst); |
| 1099 | return decl; | 1117 | return decl; |
| 1118 | } else if (old_inst.cast(zir.Inst.DeclVal)) |decl_val| { | ||
| 1119 | // This is just a named reference to another decl. | ||
| 1120 | return self.analyzeDeclVal(scope, decl_val); | ||
| 1100 | } else { | 1121 | } else { |
| 1101 | const new_decl = blk: { | 1122 | const new_decl = blk: { |
| 1102 | try self.decl_table.ensureCapacity(self.decl_table.size + 1); | 1123 | try self.decl_table.ensureCapacity(self.decl_table.size + 1); |
| ... | @@ -1442,7 +1463,9 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In | ... | @@ -1442,7 +1463,9 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 1442 | switch (old_inst.tag) { | 1463 | switch (old_inst.tag) { |
| 1443 | .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?), | 1464 | .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?), |
| 1444 | .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?), | 1465 | .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?), |
| 1466 | .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?), | ||
| 1445 | .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?), | 1467 | .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?), |
| 1468 | .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?), | ||
| 1446 | .str => { | 1469 | .str => { |
| 1447 | const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes; | 1470 | const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes; |
| 1448 | // The bytes references memory inside the ZIR module, which can get deallocated | 1471 | // The bytes references memory inside the ZIR module, which can get deallocated |
| ... | @@ -1480,6 +1503,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In | ... | @@ -1480,6 +1503,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 1480 | } | 1503 | } |
| 1481 | } | 1504 | } |
| 1482 | 1505 | ||
| 1506 | fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst { | ||
| 1507 | return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg}); | ||
| 1508 | } | ||
| 1509 | |||
| 1483 | fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst { | 1510 | fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst { |
| 1484 | const b = try self.requireRuntimeBlock(scope, inst.base.src); | 1511 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 1485 | return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){}); | 1512 | return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){}); |
| ... | @@ -1501,6 +1528,24 @@ fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) Inn | ... | @@ -1501,6 +1528,24 @@ fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) Inn |
| 1501 | return self.analyzeDeclRef(scope, inst.base.src, decl); | 1528 | return self.analyzeDeclRef(scope, inst.base.src, decl); |
| 1502 | } | 1529 | } |
| 1503 | 1530 | ||
| 1531 | fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl { | ||
| 1532 | const decl_name = inst.positionals.name; | ||
| 1533 | // This will need to get more fleshed out when there are proper structs & namespaces. | ||
| 1534 | const zir_module = scope.namespace(); | ||
| 1535 | const src_decl = zir_module.contents.module.findDecl(decl_name) orelse | ||
| 1536 | return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name}); | ||
| 1537 | |||
| 1538 | const decl = try self.resolveCompleteDecl(scope, src_decl); | ||
| 1539 | |||
| 1540 | return decl; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | fn analyzeInstDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst { | ||
| 1544 | const decl = try self.analyzeDeclVal(scope, inst); | ||
| 1545 | const ptr = try self.analyzeDeclRef(scope, inst.base.src, decl); | ||
| 1546 | return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src); | ||
| 1547 | } | ||
| 1548 | |||
| 1504 | fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { | 1549 | fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { |
| 1505 | const decl_tv = try decl.typedValue(); | 1550 | const decl_tv = try decl.typedValue(); |
| 1506 | const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer); | 1551 | const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer); |
| ... | @@ -1621,7 +1666,7 @@ fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inn | ... | @@ -1621,7 +1666,7 @@ fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inn |
| 1621 | } | 1666 | } |
| 1622 | 1667 | ||
| 1623 | fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst { | 1668 | fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst { |
| 1624 | return self.constType(scope, primitive.base.src, primitive.positionals.tag.toType()); | 1669 | return self.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue()); |
| 1625 | } | 1670 | } |
| 1626 | 1671 | ||
| 1627 | fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.As) InnerError!*Inst { | 1672 | fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.As) InnerError!*Inst { |
src-self-hosted/main.zig+15-1| ... | @@ -407,7 +407,21 @@ fn buildOutputType( | ... | @@ -407,7 +407,21 @@ fn buildOutputType( |
| 407 | std.debug.warn("-fno-emit-bin not supported yet", .{}); | 407 | std.debug.warn("-fno-emit-bin not supported yet", .{}); |
| 408 | process.exit(1); | 408 | process.exit(1); |
| 409 | }, | 409 | }, |
| 410 | .yes_default_path => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }), | 410 | .yes_default_path => switch (output_mode) { |
| 411 | .Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }), | ||
| 412 | .Lib => blk: { | ||
| 413 | const suffix = switch (link_mode orelse .Static) { | ||
| 414 | .Static => target_info.target.staticLibSuffix(), | ||
| 415 | .Dynamic => target_info.target.dynamicLibSuffix(), | ||
| 416 | }; | ||
| 417 | break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{ | ||
| 418 | target_info.target.libPrefix(), | ||
| 419 | root_name, | ||
| 420 | suffix, | ||
| 421 | }); | ||
| 422 | }, | ||
| 423 | .Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }), | ||
| 424 | }, | ||
| 411 | .yes => |p| p, | 425 | .yes => |p| p, |
| 412 | }; | 426 | }; |
| 413 | 427 |
src-self-hosted/test.zig+111-29| ... | @@ -27,9 +27,32 @@ pub const TestContext = struct { | ... | @@ -27,9 +27,32 @@ pub const TestContext = struct { |
| 27 | 27 | ||
| 28 | pub const ZIRTransformCase = struct { | 28 | pub const ZIRTransformCase = struct { |
| 29 | name: []const u8, | 29 | name: []const u8, |
| 30 | src: [:0]const u8, | ||
| 31 | expected_zir: []const u8, | ||
| 32 | cross_target: std.zig.CrossTarget, | 30 | cross_target: std.zig.CrossTarget, |
| 31 | updates: std.ArrayList(Update), | ||
| 32 | |||
| 33 | pub const Update = struct { | ||
| 34 | expected: Expected, | ||
| 35 | src: [:0]const u8, | ||
| 36 | }; | ||
| 37 | |||
| 38 | pub const Expected = union(enum) { | ||
| 39 | zir: []const u8, | ||
| 40 | errors: []const []const u8, | ||
| 41 | }; | ||
| 42 | |||
| 43 | pub fn addZIR(case: *ZIRTransformCase, src: [:0]const u8, zir_text: []const u8) void { | ||
| 44 | case.updates.append(.{ | ||
| 45 | .src = src, | ||
| 46 | .expected = .{ .zir = zir_text }, | ||
| 47 | }) catch unreachable; | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn addError(case: *ZIRTransformCase, src: [:0]const u8, errors: []const []const u8) void { | ||
| 51 | case.updates.append(.{ | ||
| 52 | .src = src, | ||
| 53 | .expected = .{ .errors = errors }, | ||
| 54 | }) catch unreachable; | ||
| 55 | } | ||
| 33 | }; | 56 | }; |
| 34 | 57 | ||
| 35 | pub fn addZIRCompareOutput( | 58 | pub fn addZIRCompareOutput( |
| ... | @@ -52,14 +75,32 @@ pub const TestContext = struct { | ... | @@ -52,14 +75,32 @@ pub const TestContext = struct { |
| 52 | src: [:0]const u8, | 75 | src: [:0]const u8, |
| 53 | expected_zir: []const u8, | 76 | expected_zir: []const u8, |
| 54 | ) void { | 77 | ) void { |
| 55 | ctx.zir_transform_cases.append(.{ | 78 | const case = ctx.zir_transform_cases.addOne() catch unreachable; |
| 79 | case.* = .{ | ||
| 56 | .name = name, | 80 | .name = name, |
| 57 | .src = src, | ||
| 58 | .expected_zir = expected_zir, | ||
| 59 | .cross_target = cross_target, | 81 | .cross_target = cross_target, |
| 82 | .updates = std.ArrayList(ZIRTransformCase.Update).init(std.heap.page_allocator), | ||
| 83 | }; | ||
| 84 | case.updates.append(.{ | ||
| 85 | .src = src, | ||
| 86 | .expected = .{ .zir = expected_zir }, | ||
| 60 | }) catch unreachable; | 87 | }) catch unreachable; |
| 61 | } | 88 | } |
| 62 | 89 | ||
| 90 | pub fn addZIRMulti( | ||
| 91 | ctx: *TestContext, | ||
| 92 | name: []const u8, | ||
| 93 | cross_target: std.zig.CrossTarget, | ||
| 94 | ) *ZIRTransformCase { | ||
| 95 | const case = ctx.zir_transform_cases.addOne() catch unreachable; | ||
| 96 | case.* = .{ | ||
| 97 | .name = name, | ||
| 98 | .cross_target = cross_target, | ||
| 99 | .updates = std.ArrayList(ZIRTransformCase.Update).init(std.heap.page_allocator), | ||
| 100 | }; | ||
| 101 | return case; | ||
| 102 | } | ||
| 103 | |||
| 63 | fn init(self: *TestContext) !void { | 104 | fn init(self: *TestContext) !void { |
| 64 | self.* = .{ | 105 | self.* = .{ |
| 65 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), | 106 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), |
| ... | @@ -178,13 +219,11 @@ pub const TestContext = struct { | ... | @@ -178,13 +219,11 @@ pub const TestContext = struct { |
| 178 | var tmp = std.testing.tmpDir(.{}); | 219 | var tmp = std.testing.tmpDir(.{}); |
| 179 | defer tmp.cleanup(); | 220 | defer tmp.cleanup(); |
| 180 | 221 | ||
| 181 | var prg_node = root_node.start(case.name, 3); | 222 | var update_node = root_node.start(case.name, case.updates.items.len); |
| 182 | prg_node.activate(); | 223 | update_node.activate(); |
| 183 | defer prg_node.end(); | 224 | defer update_node.end(); |
| 184 | 225 | ||
| 185 | const tmp_src_path = "test-case.zir"; | 226 | const tmp_src_path = "test-case.zir"; |
| 186 | try tmp.dir.writeFile(tmp_src_path, case.src); | ||
| 187 | |||
| 188 | const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path); | 227 | const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path); |
| 189 | defer root_pkg.destroy(); | 228 | defer root_pkg.destroy(); |
| 190 | 229 | ||
| ... | @@ -198,25 +237,68 @@ pub const TestContext = struct { | ... | @@ -198,25 +237,68 @@ pub const TestContext = struct { |
| 198 | }); | 237 | }); |
| 199 | defer module.deinit(); | 238 | defer module.deinit(); |
| 200 | 239 | ||
| 201 | var module_node = prg_node.start("parse/analysis/codegen", null); | 240 | for (case.updates.items) |update| { |
| 202 | module_node.activate(); | 241 | var prg_node = update_node.start("", 3); |
| 203 | try module.update(); | 242 | prg_node.activate(); |
| 204 | module_node.end(); | 243 | defer prg_node.end(); |
| 205 | 244 | ||
| 206 | var emit_node = prg_node.start("emit", null); | 245 | try tmp.dir.writeFile(tmp_src_path, update.src); |
| 207 | emit_node.activate(); | 246 | |
| 208 | var new_zir_module = try zir.emit(allocator, module); | 247 | var module_node = prg_node.start("parse/analysis/codegen", null); |
| 209 | defer new_zir_module.deinit(allocator); | 248 | module_node.activate(); |
| 210 | emit_node.end(); | 249 | try module.update(); |
| 211 | 250 | module_node.end(); | |
| 212 | var write_node = prg_node.start("write", null); | 251 | |
| 213 | write_node.activate(); | 252 | switch (update.expected) { |
| 214 | var out_zir = std.ArrayList(u8).init(allocator); | 253 | .zir => |expected_zir| { |
| 215 | defer out_zir.deinit(); | 254 | var emit_node = prg_node.start("emit", null); |
| 216 | try new_zir_module.writeToStream(allocator, out_zir.outStream()); | 255 | emit_node.activate(); |
| 217 | write_node.end(); | 256 | var new_zir_module = try zir.emit(allocator, module); |
| 218 | 257 | defer new_zir_module.deinit(allocator); | |
| 219 | std.testing.expectEqualSlices(u8, case.expected_zir, out_zir.items); | 258 | emit_node.end(); |
| 259 | |||
| 260 | var write_node = prg_node.start("write", null); | ||
| 261 | write_node.activate(); | ||
| 262 | var out_zir = std.ArrayList(u8).init(allocator); | ||
| 263 | defer out_zir.deinit(); | ||
| 264 | try new_zir_module.writeToStream(allocator, out_zir.outStream()); | ||
| 265 | write_node.end(); | ||
| 266 | |||
| 267 | std.testing.expectEqualSlices(u8, expected_zir, out_zir.items); | ||
| 268 | }, | ||
| 269 | .errors => |expected_errors| { | ||
| 270 | var all_errors = try module.getAllErrorsAlloc(); | ||
| 271 | defer all_errors.deinit(module.allocator); | ||
| 272 | for (expected_errors) |expected_error| { | ||
| 273 | for (all_errors.list) |full_err_msg| { | ||
| 274 | const text = try std.fmt.allocPrint(allocator, ":{}:{}: error: {}", .{ | ||
| 275 | full_err_msg.line + 1, | ||
| 276 | full_err_msg.column + 1, | ||
| 277 | full_err_msg.msg, | ||
| 278 | }); | ||
| 279 | defer allocator.free(text); | ||
| 280 | if (std.mem.eql(u8, text, expected_error)) { | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | std.debug.warn( | ||
| 285 | "{}\nExpected this error:\n================\n{}\n================\nBut found these errors:\n================\n", | ||
| 286 | .{ case.name, expected_error }, | ||
| 287 | ); | ||
| 288 | for (all_errors.list) |full_err_msg| { | ||
| 289 | std.debug.warn(":{}:{}: error: {}\n", .{ | ||
| 290 | full_err_msg.line + 1, | ||
| 291 | full_err_msg.column + 1, | ||
| 292 | full_err_msg.msg, | ||
| 293 | }); | ||
| 294 | } | ||
| 295 | std.debug.warn("================\nTest failed\n", .{}); | ||
| 296 | std.process.exit(1); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | }, | ||
| 300 | } | ||
| 301 | } | ||
| 220 | } | 302 | } |
| 221 | }; | 303 | }; |
| 222 | 304 |
src-self-hosted/type.zig+22| ... | @@ -51,6 +51,7 @@ pub const Type = extern union { | ... | @@ -51,6 +51,7 @@ pub const Type = extern union { |
| 51 | .comptime_float => return .ComptimeFloat, | 51 | .comptime_float => return .ComptimeFloat, |
| 52 | .noreturn => return .NoReturn, | 52 | .noreturn => return .NoReturn, |
| 53 | .@"null" => return .Null, | 53 | .@"null" => return .Null, |
| 54 | .@"undefined" => return .Undefined, | ||
| 54 | 55 | ||
| 55 | .fn_noreturn_no_args => return .Fn, | 56 | .fn_noreturn_no_args => return .Fn, |
| 56 | .fn_naked_noreturn_no_args => return .Fn, | 57 | .fn_naked_noreturn_no_args => return .Fn, |
| ... | @@ -201,6 +202,7 @@ pub const Type = extern union { | ... | @@ -201,6 +202,7 @@ pub const Type = extern union { |
| 201 | => return out_stream.writeAll(@tagName(t)), | 202 | => return out_stream.writeAll(@tagName(t)), |
| 202 | 203 | ||
| 203 | .@"null" => return out_stream.writeAll("@TypeOf(null)"), | 204 | .@"null" => return out_stream.writeAll("@TypeOf(null)"), |
| 205 | .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"), | ||
| 204 | 206 | ||
| 205 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), | 207 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), |
| 206 | .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"), | 208 | .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"), |
| ... | @@ -265,6 +267,7 @@ pub const Type = extern union { | ... | @@ -265,6 +267,7 @@ pub const Type = extern union { |
| 265 | .comptime_float => return Value.initTag(.comptime_float_type), | 267 | .comptime_float => return Value.initTag(.comptime_float_type), |
| 266 | .noreturn => return Value.initTag(.noreturn_type), | 268 | .noreturn => return Value.initTag(.noreturn_type), |
| 267 | .@"null" => return Value.initTag(.null_type), | 269 | .@"null" => return Value.initTag(.null_type), |
| 270 | .@"undefined" => return Value.initTag(.undefined_type), | ||
| 268 | .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type), | 271 | .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type), |
| 269 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), | 272 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), |
| 270 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), | 273 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), |
| ... | @@ -318,6 +321,7 @@ pub const Type = extern union { | ... | @@ -318,6 +321,7 @@ pub const Type = extern union { |
| 318 | .comptime_float, | 321 | .comptime_float, |
| 319 | .noreturn, | 322 | .noreturn, |
| 320 | .@"null", | 323 | .@"null", |
| 324 | .@"undefined", | ||
| 321 | => false, | 325 | => false, |
| 322 | }; | 326 | }; |
| 323 | } | 327 | } |
| ... | @@ -378,6 +382,7 @@ pub const Type = extern union { | ... | @@ -378,6 +382,7 @@ pub const Type = extern union { |
| 378 | .comptime_float, | 382 | .comptime_float, |
| 379 | .noreturn, | 383 | .noreturn, |
| 380 | .@"null", | 384 | .@"null", |
| 385 | .@"undefined", | ||
| 381 | => unreachable, | 386 | => unreachable, |
| 382 | }; | 387 | }; |
| 383 | } | 388 | } |
| ... | @@ -410,6 +415,7 @@ pub const Type = extern union { | ... | @@ -410,6 +415,7 @@ pub const Type = extern union { |
| 410 | .comptime_float, | 415 | .comptime_float, |
| 411 | .noreturn, | 416 | .noreturn, |
| 412 | .@"null", | 417 | .@"null", |
| 418 | .@"undefined", | ||
| 413 | .array, | 419 | .array, |
| 414 | .array_u8_sentinel_0, | 420 | .array_u8_sentinel_0, |
| 415 | .const_slice_u8, | 421 | .const_slice_u8, |
| ... | @@ -454,6 +460,7 @@ pub const Type = extern union { | ... | @@ -454,6 +460,7 @@ pub const Type = extern union { |
| 454 | .comptime_float, | 460 | .comptime_float, |
| 455 | .noreturn, | 461 | .noreturn, |
| 456 | .@"null", | 462 | .@"null", |
| 463 | .@"undefined", | ||
| 457 | .array, | 464 | .array, |
| 458 | .array_u8_sentinel_0, | 465 | .array_u8_sentinel_0, |
| 459 | .single_const_pointer, | 466 | .single_const_pointer, |
| ... | @@ -498,6 +505,7 @@ pub const Type = extern union { | ... | @@ -498,6 +505,7 @@ pub const Type = extern union { |
| 498 | .comptime_float, | 505 | .comptime_float, |
| 499 | .noreturn, | 506 | .noreturn, |
| 500 | .@"null", | 507 | .@"null", |
| 508 | .@"undefined", | ||
| 501 | .array, | 509 | .array, |
| 502 | .array_u8_sentinel_0, | 510 | .array_u8_sentinel_0, |
| 503 | .fn_noreturn_no_args, | 511 | .fn_noreturn_no_args, |
| ... | @@ -543,6 +551,7 @@ pub const Type = extern union { | ... | @@ -543,6 +551,7 @@ pub const Type = extern union { |
| 543 | .comptime_float, | 551 | .comptime_float, |
| 544 | .noreturn, | 552 | .noreturn, |
| 545 | .@"null", | 553 | .@"null", |
| 554 | .@"undefined", | ||
| 546 | .fn_noreturn_no_args, | 555 | .fn_noreturn_no_args, |
| 547 | .fn_naked_noreturn_no_args, | 556 | .fn_naked_noreturn_no_args, |
| 548 | .fn_ccc_void_no_args, | 557 | .fn_ccc_void_no_args, |
| ... | @@ -586,6 +595,7 @@ pub const Type = extern union { | ... | @@ -586,6 +595,7 @@ pub const Type = extern union { |
| 586 | .comptime_float, | 595 | .comptime_float, |
| 587 | .noreturn, | 596 | .noreturn, |
| 588 | .@"null", | 597 | .@"null", |
| 598 | .@"undefined", | ||
| 589 | .fn_noreturn_no_args, | 599 | .fn_noreturn_no_args, |
| 590 | .fn_naked_noreturn_no_args, | 600 | .fn_naked_noreturn_no_args, |
| 591 | .fn_ccc_void_no_args, | 601 | .fn_ccc_void_no_args, |
| ... | @@ -630,6 +640,7 @@ pub const Type = extern union { | ... | @@ -630,6 +640,7 @@ pub const Type = extern union { |
| 630 | .comptime_float, | 640 | .comptime_float, |
| 631 | .noreturn, | 641 | .noreturn, |
| 632 | .@"null", | 642 | .@"null", |
| 643 | .@"undefined", | ||
| 633 | .fn_noreturn_no_args, | 644 | .fn_noreturn_no_args, |
| 634 | .fn_naked_noreturn_no_args, | 645 | .fn_naked_noreturn_no_args, |
| 635 | .fn_ccc_void_no_args, | 646 | .fn_ccc_void_no_args, |
| ... | @@ -662,6 +673,7 @@ pub const Type = extern union { | ... | @@ -662,6 +673,7 @@ pub const Type = extern union { |
| 662 | .comptime_float, | 673 | .comptime_float, |
| 663 | .noreturn, | 674 | .noreturn, |
| 664 | .@"null", | 675 | .@"null", |
| 676 | .@"undefined", | ||
| 665 | .fn_noreturn_no_args, | 677 | .fn_noreturn_no_args, |
| 666 | .fn_naked_noreturn_no_args, | 678 | .fn_naked_noreturn_no_args, |
| 667 | .fn_ccc_void_no_args, | 679 | .fn_ccc_void_no_args, |
| ... | @@ -707,6 +719,7 @@ pub const Type = extern union { | ... | @@ -707,6 +719,7 @@ pub const Type = extern union { |
| 707 | .comptime_float, | 719 | .comptime_float, |
| 708 | .noreturn, | 720 | .noreturn, |
| 709 | .@"null", | 721 | .@"null", |
| 722 | .@"undefined", | ||
| 710 | .fn_noreturn_no_args, | 723 | .fn_noreturn_no_args, |
| 711 | .fn_naked_noreturn_no_args, | 724 | .fn_naked_noreturn_no_args, |
| 712 | .fn_ccc_void_no_args, | 725 | .fn_ccc_void_no_args, |
| ... | @@ -781,6 +794,7 @@ pub const Type = extern union { | ... | @@ -781,6 +794,7 @@ pub const Type = extern union { |
| 781 | .comptime_float, | 794 | .comptime_float, |
| 782 | .noreturn, | 795 | .noreturn, |
| 783 | .@"null", | 796 | .@"null", |
| 797 | .@"undefined", | ||
| 784 | .array, | 798 | .array, |
| 785 | .single_const_pointer, | 799 | .single_const_pointer, |
| 786 | .single_const_pointer_to_comptime_int, | 800 | .single_const_pointer_to_comptime_int, |
| ... | @@ -826,6 +840,7 @@ pub const Type = extern union { | ... | @@ -826,6 +840,7 @@ pub const Type = extern union { |
| 826 | .comptime_float, | 840 | .comptime_float, |
| 827 | .noreturn, | 841 | .noreturn, |
| 828 | .@"null", | 842 | .@"null", |
| 843 | .@"undefined", | ||
| 829 | .array, | 844 | .array, |
| 830 | .single_const_pointer, | 845 | .single_const_pointer, |
| 831 | .single_const_pointer_to_comptime_int, | 846 | .single_const_pointer_to_comptime_int, |
| ... | @@ -870,6 +885,7 @@ pub const Type = extern union { | ... | @@ -870,6 +885,7 @@ pub const Type = extern union { |
| 870 | .comptime_float, | 885 | .comptime_float, |
| 871 | .noreturn, | 886 | .noreturn, |
| 872 | .@"null", | 887 | .@"null", |
| 888 | .@"undefined", | ||
| 873 | .array, | 889 | .array, |
| 874 | .single_const_pointer, | 890 | .single_const_pointer, |
| 875 | .single_const_pointer_to_comptime_int, | 891 | .single_const_pointer_to_comptime_int, |
| ... | @@ -914,6 +930,7 @@ pub const Type = extern union { | ... | @@ -914,6 +930,7 @@ pub const Type = extern union { |
| 914 | .comptime_float, | 930 | .comptime_float, |
| 915 | .noreturn, | 931 | .noreturn, |
| 916 | .@"null", | 932 | .@"null", |
| 933 | .@"undefined", | ||
| 917 | .array, | 934 | .array, |
| 918 | .single_const_pointer, | 935 | .single_const_pointer, |
| 919 | .single_const_pointer_to_comptime_int, | 936 | .single_const_pointer_to_comptime_int, |
| ... | @@ -958,6 +975,7 @@ pub const Type = extern union { | ... | @@ -958,6 +975,7 @@ pub const Type = extern union { |
| 958 | .comptime_float, | 975 | .comptime_float, |
| 959 | .noreturn, | 976 | .noreturn, |
| 960 | .@"null", | 977 | .@"null", |
| 978 | .@"undefined", | ||
| 961 | .array, | 979 | .array, |
| 962 | .single_const_pointer, | 980 | .single_const_pointer, |
| 963 | .single_const_pointer_to_comptime_int, | 981 | .single_const_pointer_to_comptime_int, |
| ... | @@ -1013,6 +1031,7 @@ pub const Type = extern union { | ... | @@ -1013,6 +1031,7 @@ pub const Type = extern union { |
| 1013 | .anyerror, | 1031 | .anyerror, |
| 1014 | .noreturn, | 1032 | .noreturn, |
| 1015 | .@"null", | 1033 | .@"null", |
| 1034 | .@"undefined", | ||
| 1016 | .fn_noreturn_no_args, | 1035 | .fn_noreturn_no_args, |
| 1017 | .fn_naked_noreturn_no_args, | 1036 | .fn_naked_noreturn_no_args, |
| 1018 | .fn_ccc_void_no_args, | 1037 | .fn_ccc_void_no_args, |
| ... | @@ -1062,6 +1081,7 @@ pub const Type = extern union { | ... | @@ -1062,6 +1081,7 @@ pub const Type = extern union { |
| 1062 | .void, | 1081 | .void, |
| 1063 | .noreturn, | 1082 | .noreturn, |
| 1064 | .@"null", | 1083 | .@"null", |
| 1084 | .@"undefined", | ||
| 1065 | => return true, | 1085 | => return true, |
| 1066 | 1086 | ||
| 1067 | .int_unsigned => return ty.cast(Payload.IntUnsigned).?.bits == 0, | 1087 | .int_unsigned => return ty.cast(Payload.IntUnsigned).?.bits == 0, |
| ... | @@ -1115,6 +1135,7 @@ pub const Type = extern union { | ... | @@ -1115,6 +1135,7 @@ pub const Type = extern union { |
| 1115 | .void, | 1135 | .void, |
| 1116 | .noreturn, | 1136 | .noreturn, |
| 1117 | .@"null", | 1137 | .@"null", |
| 1138 | .@"undefined", | ||
| 1118 | .int_unsigned, | 1139 | .int_unsigned, |
| 1119 | .int_signed, | 1140 | .int_signed, |
| 1120 | .array, | 1141 | .array, |
| ... | @@ -1157,6 +1178,7 @@ pub const Type = extern union { | ... | @@ -1157,6 +1178,7 @@ pub const Type = extern union { |
| 1157 | comptime_float, | 1178 | comptime_float, |
| 1158 | noreturn, | 1179 | noreturn, |
| 1159 | @"null", | 1180 | @"null", |
| 1181 | @"undefined", | ||
| 1160 | fn_noreturn_no_args, | 1182 | fn_noreturn_no_args, |
| 1161 | fn_naked_noreturn_no_args, | 1183 | fn_naked_noreturn_no_args, |
| 1162 | fn_ccc_void_no_args, | 1184 | fn_ccc_void_no_args, |
src-self-hosted/value.zig+12| ... | @@ -47,6 +47,7 @@ pub const Value = extern union { | ... | @@ -47,6 +47,7 @@ pub const Value = extern union { |
| 47 | comptime_float_type, | 47 | comptime_float_type, |
| 48 | noreturn_type, | 48 | noreturn_type, |
| 49 | null_type, | 49 | null_type, |
| 50 | undefined_type, | ||
| 50 | fn_noreturn_no_args_type, | 51 | fn_noreturn_no_args_type, |
| 51 | fn_naked_noreturn_no_args_type, | 52 | fn_naked_noreturn_no_args_type, |
| 52 | fn_ccc_void_no_args_type, | 53 | fn_ccc_void_no_args_type, |
| ... | @@ -141,6 +142,7 @@ pub const Value = extern union { | ... | @@ -141,6 +142,7 @@ pub const Value = extern union { |
| 141 | .comptime_float_type => return out_stream.writeAll("comptime_float"), | 142 | .comptime_float_type => return out_stream.writeAll("comptime_float"), |
| 142 | .noreturn_type => return out_stream.writeAll("noreturn"), | 143 | .noreturn_type => return out_stream.writeAll("noreturn"), |
| 143 | .null_type => return out_stream.writeAll("@TypeOf(null)"), | 144 | .null_type => return out_stream.writeAll("@TypeOf(null)"), |
| 145 | .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"), | ||
| 144 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), | 146 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), |
| 145 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 147 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), |
| 146 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), | 148 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), |
| ... | @@ -225,6 +227,7 @@ pub const Value = extern union { | ... | @@ -225,6 +227,7 @@ pub const Value = extern union { |
| 225 | .comptime_float_type => Type.initTag(.comptime_float), | 227 | .comptime_float_type => Type.initTag(.comptime_float), |
| 226 | .noreturn_type => Type.initTag(.noreturn), | 228 | .noreturn_type => Type.initTag(.noreturn), |
| 227 | .null_type => Type.initTag(.@"null"), | 229 | .null_type => Type.initTag(.@"null"), |
| 230 | .undefined_type => Type.initTag(.@"undefined"), | ||
| 228 | .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), | 231 | .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), |
| 229 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), | 232 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), |
| 230 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), | 233 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), |
| ... | @@ -281,6 +284,7 @@ pub const Value = extern union { | ... | @@ -281,6 +284,7 @@ pub const Value = extern union { |
| 281 | .comptime_float_type, | 284 | .comptime_float_type, |
| 282 | .noreturn_type, | 285 | .noreturn_type, |
| 283 | .null_type, | 286 | .null_type, |
| 287 | .undefined_type, | ||
| 284 | .fn_noreturn_no_args_type, | 288 | .fn_noreturn_no_args_type, |
| 285 | .fn_naked_noreturn_no_args_type, | 289 | .fn_naked_noreturn_no_args_type, |
| 286 | .fn_ccc_void_no_args_type, | 290 | .fn_ccc_void_no_args_type, |
| ... | @@ -339,6 +343,7 @@ pub const Value = extern union { | ... | @@ -339,6 +343,7 @@ pub const Value = extern union { |
| 339 | .comptime_float_type, | 343 | .comptime_float_type, |
| 340 | .noreturn_type, | 344 | .noreturn_type, |
| 341 | .null_type, | 345 | .null_type, |
| 346 | .undefined_type, | ||
| 342 | .fn_noreturn_no_args_type, | 347 | .fn_noreturn_no_args_type, |
| 343 | .fn_naked_noreturn_no_args_type, | 348 | .fn_naked_noreturn_no_args_type, |
| 344 | .fn_ccc_void_no_args_type, | 349 | .fn_ccc_void_no_args_type, |
| ... | @@ -398,6 +403,7 @@ pub const Value = extern union { | ... | @@ -398,6 +403,7 @@ pub const Value = extern union { |
| 398 | .comptime_float_type, | 403 | .comptime_float_type, |
| 399 | .noreturn_type, | 404 | .noreturn_type, |
| 400 | .null_type, | 405 | .null_type, |
| 406 | .undefined_type, | ||
| 401 | .fn_noreturn_no_args_type, | 407 | .fn_noreturn_no_args_type, |
| 402 | .fn_naked_noreturn_no_args_type, | 408 | .fn_naked_noreturn_no_args_type, |
| 403 | .fn_ccc_void_no_args_type, | 409 | .fn_ccc_void_no_args_type, |
| ... | @@ -462,6 +468,7 @@ pub const Value = extern union { | ... | @@ -462,6 +468,7 @@ pub const Value = extern union { |
| 462 | .comptime_float_type, | 468 | .comptime_float_type, |
| 463 | .noreturn_type, | 469 | .noreturn_type, |
| 464 | .null_type, | 470 | .null_type, |
| 471 | .undefined_type, | ||
| 465 | .fn_noreturn_no_args_type, | 472 | .fn_noreturn_no_args_type, |
| 466 | .fn_naked_noreturn_no_args_type, | 473 | .fn_naked_noreturn_no_args_type, |
| 467 | .fn_ccc_void_no_args_type, | 474 | .fn_ccc_void_no_args_type, |
| ... | @@ -555,6 +562,7 @@ pub const Value = extern union { | ... | @@ -555,6 +562,7 @@ pub const Value = extern union { |
| 555 | .comptime_float_type, | 562 | .comptime_float_type, |
| 556 | .noreturn_type, | 563 | .noreturn_type, |
| 557 | .null_type, | 564 | .null_type, |
| 565 | .undefined_type, | ||
| 558 | .fn_noreturn_no_args_type, | 566 | .fn_noreturn_no_args_type, |
| 559 | .fn_naked_noreturn_no_args_type, | 567 | .fn_naked_noreturn_no_args_type, |
| 560 | .fn_ccc_void_no_args_type, | 568 | .fn_ccc_void_no_args_type, |
| ... | @@ -610,6 +618,7 @@ pub const Value = extern union { | ... | @@ -610,6 +618,7 @@ pub const Value = extern union { |
| 610 | .comptime_float_type, | 618 | .comptime_float_type, |
| 611 | .noreturn_type, | 619 | .noreturn_type, |
| 612 | .null_type, | 620 | .null_type, |
| 621 | .undefined_type, | ||
| 613 | .fn_noreturn_no_args_type, | 622 | .fn_noreturn_no_args_type, |
| 614 | .fn_naked_noreturn_no_args_type, | 623 | .fn_naked_noreturn_no_args_type, |
| 615 | .fn_ccc_void_no_args_type, | 624 | .fn_ccc_void_no_args_type, |
| ... | @@ -710,6 +719,7 @@ pub const Value = extern union { | ... | @@ -710,6 +719,7 @@ pub const Value = extern union { |
| 710 | .comptime_float_type, | 719 | .comptime_float_type, |
| 711 | .noreturn_type, | 720 | .noreturn_type, |
| 712 | .null_type, | 721 | .null_type, |
| 722 | .undefined_type, | ||
| 713 | .fn_noreturn_no_args_type, | 723 | .fn_noreturn_no_args_type, |
| 714 | .fn_naked_noreturn_no_args_type, | 724 | .fn_naked_noreturn_no_args_type, |
| 715 | .fn_ccc_void_no_args_type, | 725 | .fn_ccc_void_no_args_type, |
| ... | @@ -771,6 +781,7 @@ pub const Value = extern union { | ... | @@ -771,6 +781,7 @@ pub const Value = extern union { |
| 771 | .comptime_float_type, | 781 | .comptime_float_type, |
| 772 | .noreturn_type, | 782 | .noreturn_type, |
| 773 | .null_type, | 783 | .null_type, |
| 784 | .undefined_type, | ||
| 774 | .fn_noreturn_no_args_type, | 785 | .fn_noreturn_no_args_type, |
| 775 | .fn_naked_noreturn_no_args_type, | 786 | .fn_naked_noreturn_no_args_type, |
| 776 | .fn_ccc_void_no_args_type, | 787 | .fn_ccc_void_no_args_type, |
| ... | @@ -849,6 +860,7 @@ pub const Value = extern union { | ... | @@ -849,6 +860,7 @@ pub const Value = extern union { |
| 849 | .comptime_float_type, | 860 | .comptime_float_type, |
| 850 | .noreturn_type, | 861 | .noreturn_type, |
| 851 | .null_type, | 862 | .null_type, |
| 863 | .undefined_type, | ||
| 852 | .fn_noreturn_no_args_type, | 864 | .fn_noreturn_no_args_type, |
| 853 | .fn_naked_noreturn_no_args_type, | 865 | .fn_naked_noreturn_no_args_type, |
| 854 | .fn_ccc_void_no_args_type, | 866 | .fn_ccc_void_no_args_type, |
src-self-hosted/zir.zig+302-141| ... | @@ -27,9 +27,12 @@ pub const Inst = struct { | ... | @@ -27,9 +27,12 @@ pub const Inst = struct { |
| 27 | pub const Tag = enum { | 27 | pub const Tag = enum { |
| 28 | breakpoint, | 28 | breakpoint, |
| 29 | call, | 29 | call, |
| 30 | /// Represents a reference to a global decl by name. | 30 | compileerror, |
| 31 | /// The syntax `@foo` is equivalent to `declref("foo")`. | 31 | /// Represents a pointer to a global decl by name. |
| 32 | declref, | 32 | declref, |
| 33 | /// The syntax `@foo` is equivalent to `declval("foo")`. | ||
| 34 | /// declval is equivalent to declref followed by deref. | ||
| 35 | declval, | ||
| 33 | str, | 36 | str, |
| 34 | int, | 37 | int, |
| 35 | ptrtoint, | 38 | ptrtoint, |
| ... | @@ -59,6 +62,8 @@ pub const Inst = struct { | ... | @@ -59,6 +62,8 @@ pub const Inst = struct { |
| 59 | .breakpoint => Breakpoint, | 62 | .breakpoint => Breakpoint, |
| 60 | .call => Call, | 63 | .call => Call, |
| 61 | .declref => DeclRef, | 64 | .declref => DeclRef, |
| 65 | .declval => DeclVal, | ||
| 66 | .compileerror => CompileError, | ||
| 62 | .str => Str, | 67 | .str => Str, |
| 63 | .int => Int, | 68 | .int => Int, |
| 64 | .ptrtoint => PtrToInt, | 69 | .ptrtoint => PtrToInt, |
| ... | @@ -122,6 +127,26 @@ pub const Inst = struct { | ... | @@ -122,6 +127,26 @@ pub const Inst = struct { |
| 122 | kw_args: struct {}, | 127 | kw_args: struct {}, |
| 123 | }; | 128 | }; |
| 124 | 129 | ||
| 130 | pub const DeclVal = struct { | ||
| 131 | pub const base_tag = Tag.declval; | ||
| 132 | base: Inst, | ||
| 133 | |||
| 134 | positionals: struct { | ||
| 135 | name: []const u8, | ||
| 136 | }, | ||
| 137 | kw_args: struct {}, | ||
| 138 | }; | ||
| 139 | |||
| 140 | pub const CompileError = struct { | ||
| 141 | pub const base_tag = Tag.compileerror; | ||
| 142 | base: Inst, | ||
| 143 | |||
| 144 | positionals: struct { | ||
| 145 | msg: []const u8, | ||
| 146 | }, | ||
| 147 | kw_args: struct {}, | ||
| 148 | }; | ||
| 149 | |||
| 125 | pub const Str = struct { | 150 | pub const Str = struct { |
| 126 | pub const base_tag = Tag.str; | 151 | pub const base_tag = Tag.str; |
| 127 | base: Inst, | 152 | base: Inst, |
| ... | @@ -254,11 +279,11 @@ pub const Inst = struct { | ... | @@ -254,11 +279,11 @@ pub const Inst = struct { |
| 254 | base: Inst, | 279 | base: Inst, |
| 255 | 280 | ||
| 256 | positionals: struct { | 281 | positionals: struct { |
| 257 | tag: BuiltinType, | 282 | tag: Builtin, |
| 258 | }, | 283 | }, |
| 259 | kw_args: struct {}, | 284 | kw_args: struct {}, |
| 260 | 285 | ||
| 261 | pub const BuiltinType = enum { | 286 | pub const Builtin = enum { |
| 262 | isize, | 287 | isize, |
| 263 | usize, | 288 | usize, |
| 264 | c_short, | 289 | c_short, |
| ... | @@ -282,32 +307,42 @@ pub const Inst = struct { | ... | @@ -282,32 +307,42 @@ pub const Inst = struct { |
| 282 | anyerror, | 307 | anyerror, |
| 283 | comptime_int, | 308 | comptime_int, |
| 284 | comptime_float, | 309 | comptime_float, |
| 310 | @"true", | ||
| 311 | @"false", | ||
| 312 | @"null", | ||
| 313 | @"undefined", | ||
| 314 | void_value, | ||
| 285 | 315 | ||
| 286 | pub fn toType(self: BuiltinType) Type { | 316 | pub fn toTypedValue(self: Builtin) TypedValue { |
| 287 | return switch (self) { | 317 | return switch (self) { |
| 288 | .isize => Type.initTag(.isize), | 318 | .isize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.isize_type) }, |
| 289 | .usize => Type.initTag(.usize), | 319 | .usize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.usize_type) }, |
| 290 | .c_short => Type.initTag(.c_short), | 320 | .c_short => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_short_type) }, |
| 291 | .c_ushort => Type.initTag(.c_ushort), | 321 | .c_ushort => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ushort_type) }, |
| 292 | .c_int => Type.initTag(.c_int), | 322 | .c_int => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_int_type) }, |
| 293 | .c_uint => Type.initTag(.c_uint), | 323 | .c_uint => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_uint_type) }, |
| 294 | .c_long => Type.initTag(.c_long), | 324 | .c_long => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_long_type) }, |
| 295 | .c_ulong => Type.initTag(.c_ulong), | 325 | .c_ulong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ulong_type) }, |
| 296 | .c_longlong => Type.initTag(.c_longlong), | 326 | .c_longlong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_longlong_type) }, |
| 297 | .c_ulonglong => Type.initTag(.c_ulonglong), | 327 | .c_ulonglong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ulonglong_type) }, |
| 298 | .c_longdouble => Type.initTag(.c_longdouble), | 328 | .c_longdouble => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_longdouble_type) }, |
| 299 | .c_void => Type.initTag(.c_void), | 329 | .c_void => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_void_type) }, |
| 300 | .f16 => Type.initTag(.f16), | 330 | .f16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f16_type) }, |
| 301 | .f32 => Type.initTag(.f32), | 331 | .f32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f32_type) }, |
| 302 | .f64 => Type.initTag(.f64), | 332 | .f64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f64_type) }, |
| 303 | .f128 => Type.initTag(.f128), | 333 | .f128 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f128_type) }, |
| 304 | .bool => Type.initTag(.bool), | 334 | .bool => .{ .ty = Type.initTag(.type), .val = Value.initTag(.bool_type) }, |
| 305 | .void => Type.initTag(.void), | 335 | .void => .{ .ty = Type.initTag(.type), .val = Value.initTag(.void_type) }, |
| 306 | .noreturn => Type.initTag(.noreturn), | 336 | .noreturn => .{ .ty = Type.initTag(.type), .val = Value.initTag(.noreturn_type) }, |
| 307 | .type => Type.initTag(.type), | 337 | .type => .{ .ty = Type.initTag(.type), .val = Value.initTag(.type_type) }, |
| 308 | .anyerror => Type.initTag(.anyerror), | 338 | .anyerror => .{ .ty = Type.initTag(.type), .val = Value.initTag(.anyerror_type) }, |
| 309 | .comptime_int => Type.initTag(.comptime_int), | 339 | .comptime_int => .{ .ty = Type.initTag(.type), .val = Value.initTag(.comptime_int_type) }, |
| 310 | .comptime_float => Type.initTag(.comptime_float), | 340 | .comptime_float => .{ .ty = Type.initTag(.type), .val = Value.initTag(.comptime_float_type) }, |
| 341 | .@"true" => .{ .ty = Type.initTag(.bool), .val = Value.initTag(.bool_true) }, | ||
| 342 | .@"false" => .{ .ty = Type.initTag(.bool), .val = Value.initTag(.bool_false) }, | ||
| 343 | .@"null" => .{ .ty = Type.initTag(.@"null"), .val = Value.initTag(.null_value) }, | ||
| 344 | .@"undefined" => .{ .ty = Type.initTag(.@"undefined"), .val = Value.initTag(.undef) }, | ||
| 345 | .void_value => .{ .ty = Type.initTag(.void), .val = Value.initTag(.the_one_possible_value) }, | ||
| 311 | }; | 346 | }; |
| 312 | } | 347 | } |
| 313 | }; | 348 | }; |
| ... | @@ -440,7 +475,7 @@ pub const Module = struct { | ... | @@ -440,7 +475,7 @@ pub const Module = struct { |
| 440 | self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {}; | 475 | self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {}; |
| 441 | } | 476 | } |
| 442 | 477 | ||
| 443 | const InstPtrTable = std.AutoHashMap(*Inst, struct { index: usize, fn_body: ?*Module.Body }); | 478 | const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize }); |
| 444 | 479 | ||
| 445 | /// TODO Look into making a table to speed this up. | 480 | /// TODO Look into making a table to speed this up. |
| 446 | pub fn findDecl(self: Module, name: []const u8) ?*Inst { | 481 | pub fn findDecl(self: Module, name: []const u8) ?*Inst { |
| ... | @@ -462,17 +497,17 @@ pub const Module = struct { | ... | @@ -462,17 +497,17 @@ pub const Module = struct { |
| 462 | try inst_table.ensureCapacity(self.decls.len); | 497 | try inst_table.ensureCapacity(self.decls.len); |
| 463 | 498 | ||
| 464 | for (self.decls) |decl, decl_i| { | 499 | for (self.decls) |decl, decl_i| { |
| 465 | try inst_table.putNoClobber(decl, .{ .index = decl_i, .fn_body = null }); | 500 | try inst_table.putNoClobber(decl, .{ .inst = decl, .index = null }); |
| 466 | 501 | ||
| 467 | if (decl.cast(Inst.Fn)) |fn_inst| { | 502 | if (decl.cast(Inst.Fn)) |fn_inst| { |
| 468 | for (fn_inst.positionals.body.instructions) |inst, inst_i| { | 503 | for (fn_inst.positionals.body.instructions) |inst, inst_i| { |
| 469 | try inst_table.putNoClobber(inst, .{ .index = inst_i, .fn_body = &fn_inst.positionals.body }); | 504 | try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i }); |
| 470 | } | 505 | } |
| 471 | } | 506 | } |
| 472 | } | 507 | } |
| 473 | 508 | ||
| 474 | for (self.decls) |decl, i| { | 509 | for (self.decls) |decl, i| { |
| 475 | try stream.print("@{} ", .{i}); | 510 | try stream.print("@{} ", .{decl.name}); |
| 476 | try self.writeInstToStream(stream, decl, &inst_table); | 511 | try self.writeInstToStream(stream, decl, &inst_table); |
| 477 | try stream.writeByte('\n'); | 512 | try stream.writeByte('\n'); |
| 478 | } | 513 | } |
| ... | @@ -489,6 +524,8 @@ pub const Module = struct { | ... | @@ -489,6 +524,8 @@ pub const Module = struct { |
| 489 | .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table), | 524 | .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table), |
| 490 | .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table), | 525 | .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table), |
| 491 | .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table), | 526 | .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table), |
| 527 | .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table), | ||
| 528 | .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table), | ||
| 492 | .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table), | 529 | .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table), |
| 493 | .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table), | 530 | .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table), |
| 494 | .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table), | 531 | .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table), |
| ... | @@ -587,9 +624,18 @@ pub const Module = struct { | ... | @@ -587,9 +624,18 @@ pub const Module = struct { |
| 587 | } | 624 | } |
| 588 | 625 | ||
| 589 | fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void { | 626 | fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void { |
| 590 | const info = inst_table.getValue(inst).?; | 627 | if (inst_table.getValue(inst)) |info| { |
| 591 | const prefix = if (info.fn_body == null) "@" else "%"; | 628 | if (info.index) |i| { |
| 592 | try stream.print("{}{}", .{ prefix, info.index }); | 629 | try stream.print("%{}", .{info.index}); |
| 630 | } else { | ||
| 631 | try stream.print("@{}", .{info.inst.name}); | ||
| 632 | } | ||
| 633 | } else if (inst.cast(Inst.DeclVal)) |decl_val| { | ||
| 634 | try stream.print("@{}", .{decl_val.positionals.name}); | ||
| 635 | } else { | ||
| 636 | //try stream.print("?", .{}); | ||
| 637 | unreachable; | ||
| 638 | } | ||
| 593 | } | 639 | } |
| 594 | }; | 640 | }; |
| 595 | 641 | ||
| ... | @@ -884,6 +930,7 @@ const Parser = struct { | ... | @@ -884,6 +930,7 @@ const Parser = struct { |
| 884 | try requireEatBytes(self, ")"); | 930 | try requireEatBytes(self, ")"); |
| 885 | 931 | ||
| 886 | inst_specific.base.contents = self.source[contents_start..self.i]; | 932 | inst_specific.base.contents = self.source[contents_start..self.i]; |
| 933 | //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents }); | ||
| 887 | 934 | ||
| 888 | return &inst_specific.base; | 935 | return &inst_specific.base; |
| 889 | } | 936 | } |
| ... | @@ -964,47 +1011,17 @@ const Parser = struct { | ... | @@ -964,47 +1011,17 @@ const Parser = struct { |
| 964 | self.i = src; | 1011 | self.i = src; |
| 965 | return self.fail("unrecognized identifier: {}", .{bad_name}); | 1012 | return self.fail("unrecognized identifier: {}", .{bad_name}); |
| 966 | } else { | 1013 | } else { |
| 967 | const name_array = try self.arena.allocator.create(Inst.Str); | 1014 | const declval = try self.arena.allocator.create(Inst.DeclVal); |
| 968 | name_array.* = .{ | 1015 | declval.* = .{ |
| 969 | .base = .{ | ||
| 970 | .name = try self.generateName(), | ||
| 971 | .src = src, | ||
| 972 | .tag = Inst.Str.base_tag, | ||
| 973 | }, | ||
| 974 | .positionals = .{ .bytes = ident }, | ||
| 975 | .kw_args = .{}, | ||
| 976 | }; | ||
| 977 | const name = try self.arena.allocator.create(Inst.Ref); | ||
| 978 | name.* = .{ | ||
| 979 | .base = .{ | ||
| 980 | .name = try self.generateName(), | ||
| 981 | .src = src, | ||
| 982 | .tag = Inst.Ref.base_tag, | ||
| 983 | }, | ||
| 984 | .positionals = .{ .operand = &name_array.base }, | ||
| 985 | .kw_args = .{}, | ||
| 986 | }; | ||
| 987 | const declref = try self.arena.allocator.create(Inst.DeclRef); | ||
| 988 | declref.* = .{ | ||
| 989 | .base = .{ | ||
| 990 | .name = try self.generateName(), | ||
| 991 | .src = src, | ||
| 992 | .tag = Inst.DeclRef.base_tag, | ||
| 993 | }, | ||
| 994 | .positionals = .{ .name = &name.base }, | ||
| 995 | .kw_args = .{}, | ||
| 996 | }; | ||
| 997 | const deref = try self.arena.allocator.create(Inst.Deref); | ||
| 998 | deref.* = .{ | ||
| 999 | .base = .{ | 1016 | .base = .{ |
| 1000 | .name = try self.generateName(), | 1017 | .name = try self.generateName(), |
| 1001 | .src = src, | 1018 | .src = src, |
| 1002 | .tag = Inst.Deref.base_tag, | 1019 | .tag = Inst.DeclVal.base_tag, |
| 1003 | }, | 1020 | }, |
| 1004 | .positionals = .{ .ptr = &declref.base }, | 1021 | .positionals = .{ .name = ident }, |
| 1005 | .kw_args = .{}, | 1022 | .kw_args = .{}, |
| 1006 | }; | 1023 | }; |
| 1007 | return &deref.base; | 1024 | return &declval.base; |
| 1008 | } | 1025 | } |
| 1009 | }; | 1026 | }; |
| 1010 | if (local_ref) { | 1027 | if (local_ref) { |
| ... | @@ -1025,12 +1042,15 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module { | ... | @@ -1025,12 +1042,15 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module { |
| 1025 | var ctx: EmitZIR = .{ | 1042 | var ctx: EmitZIR = .{ |
| 1026 | .allocator = allocator, | 1043 | .allocator = allocator, |
| 1027 | .decls = .{}, | 1044 | .decls = .{}, |
| 1028 | .decl_table = std.AutoHashMap(*ir.Inst, *Inst).init(allocator), | ||
| 1029 | .arena = std.heap.ArenaAllocator.init(allocator), | 1045 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 1030 | .old_module = &old_module, | 1046 | .old_module = &old_module, |
| 1047 | .next_auto_name = 0, | ||
| 1048 | .names = std.StringHashMap(void).init(allocator), | ||
| 1049 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Inst).init(allocator), | ||
| 1031 | }; | 1050 | }; |
| 1032 | defer ctx.decls.deinit(allocator); | 1051 | defer ctx.decls.deinit(allocator); |
| 1033 | defer ctx.decl_table.deinit(); | 1052 | defer ctx.names.deinit(); |
| 1053 | defer ctx.primitive_table.deinit(); | ||
| 1034 | errdefer ctx.arena.deinit(); | 1054 | errdefer ctx.arena.deinit(); |
| 1035 | 1055 | ||
| 1036 | try ctx.emit(); | 1056 | try ctx.emit(); |
| ... | @@ -1046,47 +1066,90 @@ const EmitZIR = struct { | ... | @@ -1046,47 +1066,90 @@ const EmitZIR = struct { |
| 1046 | arena: std.heap.ArenaAllocator, | 1066 | arena: std.heap.ArenaAllocator, |
| 1047 | old_module: *const IrModule, | 1067 | old_module: *const IrModule, |
| 1048 | decls: std.ArrayListUnmanaged(*Inst), | 1068 | decls: std.ArrayListUnmanaged(*Inst), |
| 1049 | decl_table: std.AutoHashMap(*ir.Inst, *Inst), | 1069 | names: std.StringHashMap(void), |
| 1070 | next_auto_name: usize, | ||
| 1071 | primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Inst), | ||
| 1050 | 1072 | ||
| 1051 | fn emit(self: *EmitZIR) !void { | 1073 | fn emit(self: *EmitZIR) !void { |
| 1052 | var it = self.old_module.decl_exports.iterator(); | 1074 | // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced |
| 1053 | while (it.next()) |kv| { | 1075 | // by the hash table. |
| 1054 | const decl = kv.key; | 1076 | var src_decls = std.ArrayList(*IrModule.Decl).init(self.allocator); |
| 1055 | const exports = kv.value; | 1077 | defer src_decls.deinit(); |
| 1056 | const export_value = try self.emitTypedValue(decl.src, decl.typed_value.most_recent.typed_value); | 1078 | try src_decls.ensureCapacity(self.old_module.decl_table.size); |
| 1057 | for (exports) |module_export| { | 1079 | try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.size); |
| 1058 | const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name); | 1080 | try self.names.ensureCapacity(self.old_module.decl_table.size); |
| 1059 | const export_inst = try self.arena.allocator.create(Inst.Export); | 1081 | |
| 1060 | export_inst.* = .{ | 1082 | var decl_it = self.old_module.decl_table.iterator(); |
| 1061 | .base = .{ | 1083 | while (decl_it.next()) |kv| { |
| 1062 | .name = try self.autoName(), | 1084 | const decl = kv.value; |
| 1063 | .src = module_export.src, | 1085 | src_decls.appendAssumeCapacity(decl); |
| 1064 | .tag = Inst.Export.base_tag, | 1086 | self.names.putAssumeCapacityNoClobber(mem.spanZ(decl.name), {}); |
| 1065 | }, | 1087 | } |
| 1066 | .positionals = .{ | 1088 | std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct { |
| 1067 | .symbol_name = symbol_name, | 1089 | fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool { |
| 1068 | .value = export_value, | 1090 | return a.src < b.src; |
| 1069 | }, | 1091 | } |
| 1070 | .kw_args = .{}, | 1092 | }).lessThan); |
| 1071 | }; | 1093 | |
| 1072 | try self.decls.append(self.allocator, &export_inst.base); | 1094 | // Emit all the decls. |
| 1095 | for (src_decls.items) |ir_decl| { | ||
| 1096 | if (self.old_module.export_owners.getValue(ir_decl)) |exports| { | ||
| 1097 | for (exports) |module_export| { | ||
| 1098 | const declval = try self.emitDeclVal(ir_decl.src, mem.spanZ(module_export.exported_decl.name)); | ||
| 1099 | const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name); | ||
| 1100 | const export_inst = try self.arena.allocator.create(Inst.Export); | ||
| 1101 | export_inst.* = .{ | ||
| 1102 | .base = .{ | ||
| 1103 | .name = try self.autoName(), | ||
| 1104 | .src = module_export.src, | ||
| 1105 | .tag = Inst.Export.base_tag, | ||
| 1106 | }, | ||
| 1107 | .positionals = .{ | ||
| 1108 | .symbol_name = symbol_name, | ||
| 1109 | .value = declval, | ||
| 1110 | }, | ||
| 1111 | .kw_args = .{}, | ||
| 1112 | }; | ||
| 1113 | try self.decls.append(self.allocator, &export_inst.base); | ||
| 1114 | } | ||
| 1115 | } else { | ||
| 1116 | const new_decl = try self.emitTypedValue(ir_decl.src, ir_decl.typed_value.most_recent.typed_value); | ||
| 1117 | new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name)); | ||
| 1073 | } | 1118 | } |
| 1074 | } | 1119 | } |
| 1075 | } | 1120 | } |
| 1076 | 1121 | ||
| 1077 | fn resolveInst(self: *EmitZIR, inst_table: *const std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst { | 1122 | fn resolveInst(self: *EmitZIR, inst_table: *std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst { |
| 1078 | if (inst.cast(ir.Inst.Constant)) |const_inst| { | 1123 | if (inst.cast(ir.Inst.Constant)) |const_inst| { |
| 1079 | if (self.decl_table.getValue(inst)) |decl| { | 1124 | const new_decl = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: { |
| 1080 | return decl; | 1125 | const owner_decl = func_pl.func.owner_decl; |
| 1081 | } | 1126 | break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); |
| 1082 | const new_decl = try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val }); | 1127 | } else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: { |
| 1083 | try self.decl_table.putNoClobber(inst, new_decl); | 1128 | break :blk try self.emitDeclRef(inst.src, declref.decl); |
| 1129 | } else blk: { | ||
| 1130 | break :blk try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val }); | ||
| 1131 | }; | ||
| 1132 | try inst_table.putNoClobber(inst, new_decl); | ||
| 1084 | return new_decl; | 1133 | return new_decl; |
| 1085 | } else { | 1134 | } else { |
| 1086 | return inst_table.getValue(inst).?; | 1135 | return inst_table.getValue(inst).?; |
| 1087 | } | 1136 | } |
| 1088 | } | 1137 | } |
| 1089 | 1138 | ||
| 1139 | fn emitDeclVal(self: *EmitZIR, src: usize, decl_name: []const u8) !*Inst { | ||
| 1140 | const declval = try self.arena.allocator.create(Inst.DeclVal); | ||
| 1141 | declval.* = .{ | ||
| 1142 | .base = .{ | ||
| 1143 | .name = try self.autoName(), | ||
| 1144 | .src = src, | ||
| 1145 | .tag = Inst.DeclVal.base_tag, | ||
| 1146 | }, | ||
| 1147 | .positionals = .{ .name = try self.arena.allocator.dupe(u8, decl_name) }, | ||
| 1148 | .kw_args = .{}, | ||
| 1149 | }; | ||
| 1150 | return &declval.base; | ||
| 1151 | } | ||
| 1152 | |||
| 1090 | fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst { | 1153 | fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst { |
| 1091 | const big_int_space = try self.arena.allocator.create(Value.BigIntSpace); | 1154 | const big_int_space = try self.arena.allocator.create(Value.BigIntSpace); |
| 1092 | const int_inst = try self.arena.allocator.create(Inst.Int); | 1155 | const int_inst = try self.arena.allocator.create(Inst.Int); |
| ... | @@ -1105,8 +1168,31 @@ const EmitZIR = struct { | ... | @@ -1105,8 +1168,31 @@ const EmitZIR = struct { |
| 1105 | return &int_inst.base; | 1168 | return &int_inst.base; |
| 1106 | } | 1169 | } |
| 1107 | 1170 | ||
| 1171 | fn emitDeclRef(self: *EmitZIR, src: usize, decl: *IrModule.Decl) !*Inst { | ||
| 1172 | const declval = try self.emitDeclVal(src, mem.spanZ(decl.name)); | ||
| 1173 | const ref_inst = try self.arena.allocator.create(Inst.Ref); | ||
| 1174 | ref_inst.* = .{ | ||
| 1175 | .base = .{ | ||
| 1176 | .name = try self.autoName(), | ||
| 1177 | .src = src, | ||
| 1178 | .tag = Inst.Ref.base_tag, | ||
| 1179 | }, | ||
| 1180 | .positionals = .{ | ||
| 1181 | .operand = declval, | ||
| 1182 | }, | ||
| 1183 | .kw_args = .{}, | ||
| 1184 | }; | ||
| 1185 | try self.decls.append(self.allocator, &ref_inst.base); | ||
| 1186 | |||
| 1187 | return &ref_inst.base; | ||
| 1188 | } | ||
| 1189 | |||
| 1108 | fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst { | 1190 | fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst { |
| 1109 | const allocator = &self.arena.allocator; | 1191 | const allocator = &self.arena.allocator; |
| 1192 | if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { | ||
| 1193 | const decl = decl_ref.decl; | ||
| 1194 | return self.emitDeclRef(src, decl); | ||
| 1195 | } | ||
| 1110 | switch (typed_value.ty.zigTypeTag()) { | 1196 | switch (typed_value.ty.zigTypeTag()) { |
| 1111 | .Pointer => { | 1197 | .Pointer => { |
| 1112 | const ptr_elem_type = typed_value.ty.elemType(); | 1198 | const ptr_elem_type = typed_value.ty.elemType(); |
| ... | @@ -1142,7 +1228,6 @@ const EmitZIR = struct { | ... | @@ -1142,7 +1228,6 @@ const EmitZIR = struct { |
| 1142 | }, | 1228 | }, |
| 1143 | .kw_args = .{}, | 1229 | .kw_args = .{}, |
| 1144 | }; | 1230 | }; |
| 1145 | try self.decls.append(self.allocator, &as_inst.base); | ||
| 1146 | 1231 | ||
| 1147 | return &as_inst.base; | 1232 | return &as_inst.base; |
| 1148 | }, | 1233 | }, |
| ... | @@ -1159,7 +1244,44 @@ const EmitZIR = struct { | ... | @@ -1159,7 +1244,44 @@ const EmitZIR = struct { |
| 1159 | var instructions = std.ArrayList(*Inst).init(self.allocator); | 1244 | var instructions = std.ArrayList(*Inst).init(self.allocator); |
| 1160 | defer instructions.deinit(); | 1245 | defer instructions.deinit(); |
| 1161 | 1246 | ||
| 1162 | try self.emitBody(module_fn.analysis.success, &inst_table, &instructions); | 1247 | switch (module_fn.analysis) { |
| 1248 | .queued => unreachable, | ||
| 1249 | .in_progress => unreachable, | ||
| 1250 | .success => |body| { | ||
| 1251 | try self.emitBody(body, &inst_table, &instructions); | ||
| 1252 | }, | ||
| 1253 | .sema_failure => { | ||
| 1254 | const err_msg = self.old_module.failed_decls.getValue(module_fn.owner_decl).?; | ||
| 1255 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); | ||
| 1256 | fail_inst.* = .{ | ||
| 1257 | .base = .{ | ||
| 1258 | .name = try self.autoName(), | ||
| 1259 | .src = src, | ||
| 1260 | .tag = Inst.CompileError.base_tag, | ||
| 1261 | }, | ||
| 1262 | .positionals = .{ | ||
| 1263 | .msg = try self.arena.allocator.dupe(u8, err_msg.msg), | ||
| 1264 | }, | ||
| 1265 | .kw_args = .{}, | ||
| 1266 | }; | ||
| 1267 | try instructions.append(&fail_inst.base); | ||
| 1268 | }, | ||
| 1269 | .dependency_failure => { | ||
| 1270 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); | ||
| 1271 | fail_inst.* = .{ | ||
| 1272 | .base = .{ | ||
| 1273 | .name = try self.autoName(), | ||
| 1274 | .src = src, | ||
| 1275 | .tag = Inst.CompileError.base_tag, | ||
| 1276 | }, | ||
| 1277 | .positionals = .{ | ||
| 1278 | .msg = try self.arena.allocator.dupe(u8, "depends on another failed Decl"), | ||
| 1279 | }, | ||
| 1280 | .kw_args = .{}, | ||
| 1281 | }; | ||
| 1282 | try instructions.append(&fail_inst.base); | ||
| 1283 | }, | ||
| 1284 | } | ||
| 1163 | 1285 | ||
| 1164 | const fn_type = try self.emitType(src, module_fn.fn_type); | 1286 | const fn_type = try self.emitType(src, module_fn.fn_type); |
| 1165 | 1287 | ||
| ... | @@ -1182,6 +1304,33 @@ const EmitZIR = struct { | ... | @@ -1182,6 +1304,33 @@ const EmitZIR = struct { |
| 1182 | try self.decls.append(self.allocator, &fn_inst.base); | 1304 | try self.decls.append(self.allocator, &fn_inst.base); |
| 1183 | return &fn_inst.base; | 1305 | return &fn_inst.base; |
| 1184 | }, | 1306 | }, |
| 1307 | .Array => { | ||
| 1308 | // TODO more checks to make sure this can be emitted as a string literal | ||
| 1309 | //const array_elem_type = ptr_elem_type.elemType(); | ||
| 1310 | //if (array_elem_type.eql(Type.initTag(.u8)) and | ||
| 1311 | // ptr_elem_type.hasSentinel(Value.initTag(.zero))) | ||
| 1312 | //{ | ||
| 1313 | //} | ||
| 1314 | const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) { | ||
| 1315 | error.AnalysisFail => unreachable, | ||
| 1316 | else => |e| return e, | ||
| 1317 | }; | ||
| 1318 | const str_inst = try self.arena.allocator.create(Inst.Str); | ||
| 1319 | str_inst.* = .{ | ||
| 1320 | .base = .{ | ||
| 1321 | .name = try self.autoName(), | ||
| 1322 | .src = src, | ||
| 1323 | .tag = Inst.Str.base_tag, | ||
| 1324 | }, | ||
| 1325 | .positionals = .{ | ||
| 1326 | .bytes = bytes, | ||
| 1327 | }, | ||
| 1328 | .kw_args = .{}, | ||
| 1329 | }; | ||
| 1330 | try self.decls.append(self.allocator, &str_inst.base); | ||
| 1331 | return &str_inst.base; | ||
| 1332 | }, | ||
| 1333 | .Void => return self.emitPrimitive(src, .void_value), | ||
| 1185 | else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), | 1334 | else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), |
| 1186 | } | 1335 | } |
| 1187 | } | 1336 | } |
| ... | @@ -1395,30 +1544,30 @@ const EmitZIR = struct { | ... | @@ -1395,30 +1544,30 @@ const EmitZIR = struct { |
| 1395 | 1544 | ||
| 1396 | fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst { | 1545 | fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst { |
| 1397 | switch (ty.tag()) { | 1546 | switch (ty.tag()) { |
| 1398 | .isize => return self.emitPrimitiveType(src, .isize), | 1547 | .isize => return self.emitPrimitive(src, .isize), |
| 1399 | .usize => return self.emitPrimitiveType(src, .usize), | 1548 | .usize => return self.emitPrimitive(src, .usize), |
| 1400 | .c_short => return self.emitPrimitiveType(src, .c_short), | 1549 | .c_short => return self.emitPrimitive(src, .c_short), |
| 1401 | .c_ushort => return self.emitPrimitiveType(src, .c_ushort), | 1550 | .c_ushort => return self.emitPrimitive(src, .c_ushort), |
| 1402 | .c_int => return self.emitPrimitiveType(src, .c_int), | 1551 | .c_int => return self.emitPrimitive(src, .c_int), |
| 1403 | .c_uint => return self.emitPrimitiveType(src, .c_uint), | 1552 | .c_uint => return self.emitPrimitive(src, .c_uint), |
| 1404 | .c_long => return self.emitPrimitiveType(src, .c_long), | 1553 | .c_long => return self.emitPrimitive(src, .c_long), |
| 1405 | .c_ulong => return self.emitPrimitiveType(src, .c_ulong), | 1554 | .c_ulong => return self.emitPrimitive(src, .c_ulong), |
| 1406 | .c_longlong => return self.emitPrimitiveType(src, .c_longlong), | 1555 | .c_longlong => return self.emitPrimitive(src, .c_longlong), |
| 1407 | .c_ulonglong => return self.emitPrimitiveType(src, .c_ulonglong), | 1556 | .c_ulonglong => return self.emitPrimitive(src, .c_ulonglong), |
| 1408 | .c_longdouble => return self.emitPrimitiveType(src, .c_longdouble), | 1557 | .c_longdouble => return self.emitPrimitive(src, .c_longdouble), |
| 1409 | .c_void => return self.emitPrimitiveType(src, .c_void), | 1558 | .c_void => return self.emitPrimitive(src, .c_void), |
| 1410 | .f16 => return self.emitPrimitiveType(src, .f16), | 1559 | .f16 => return self.emitPrimitive(src, .f16), |
| 1411 | .f32 => return self.emitPrimitiveType(src, .f32), | 1560 | .f32 => return self.emitPrimitive(src, .f32), |
| 1412 | .f64 => return self.emitPrimitiveType(src, .f64), | 1561 | .f64 => return self.emitPrimitive(src, .f64), |
| 1413 | .f128 => return self.emitPrimitiveType(src, .f128), | 1562 | .f128 => return self.emitPrimitive(src, .f128), |
| 1414 | .anyerror => return self.emitPrimitiveType(src, .anyerror), | 1563 | .anyerror => return self.emitPrimitive(src, .anyerror), |
| 1415 | else => switch (ty.zigTypeTag()) { | 1564 | else => switch (ty.zigTypeTag()) { |
| 1416 | .Bool => return self.emitPrimitiveType(src, .bool), | 1565 | .Bool => return self.emitPrimitive(src, .bool), |
| 1417 | .Void => return self.emitPrimitiveType(src, .void), | 1566 | .Void => return self.emitPrimitive(src, .void), |
| 1418 | .NoReturn => return self.emitPrimitiveType(src, .noreturn), | 1567 | .NoReturn => return self.emitPrimitive(src, .noreturn), |
| 1419 | .Type => return self.emitPrimitiveType(src, .type), | 1568 | .Type => return self.emitPrimitive(src, .type), |
| 1420 | .ComptimeInt => return self.emitPrimitiveType(src, .comptime_int), | 1569 | .ComptimeInt => return self.emitPrimitive(src, .comptime_int), |
| 1421 | .ComptimeFloat => return self.emitPrimitiveType(src, .comptime_float), | 1570 | .ComptimeFloat => return self.emitPrimitive(src, .comptime_float), |
| 1422 | .Fn => { | 1571 | .Fn => { |
| 1423 | const param_types = try self.allocator.alloc(Type, ty.fnParamLen()); | 1572 | const param_types = try self.allocator.alloc(Type, ty.fnParamLen()); |
| 1424 | defer self.allocator.free(param_types); | 1573 | defer self.allocator.free(param_types); |
| ... | @@ -1453,24 +1602,36 @@ const EmitZIR = struct { | ... | @@ -1453,24 +1602,36 @@ const EmitZIR = struct { |
| 1453 | } | 1602 | } |
| 1454 | 1603 | ||
| 1455 | fn autoName(self: *EmitZIR) ![]u8 { | 1604 | fn autoName(self: *EmitZIR) ![]u8 { |
| 1456 | return std.fmt.allocPrint(&self.arena.allocator, "{}", .{self.decls.items.len}); | 1605 | while (true) { |
| 1606 | const proposed_name = try std.fmt.allocPrint(&self.arena.allocator, "unnamed${}", .{self.next_auto_name}); | ||
| 1607 | self.next_auto_name += 1; | ||
| 1608 | const gop = try self.names.getOrPut(proposed_name); | ||
| 1609 | if (!gop.found_existing) { | ||
| 1610 | gop.kv.value = {}; | ||
| 1611 | return proposed_name; | ||
| 1612 | } | ||
| 1613 | } | ||
| 1457 | } | 1614 | } |
| 1458 | 1615 | ||
| 1459 | fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst { | 1616 | fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Inst { |
| 1460 | const primitive_inst = try self.arena.allocator.create(Inst.Primitive); | 1617 | const gop = try self.primitive_table.getOrPut(tag); |
| 1461 | primitive_inst.* = .{ | 1618 | if (!gop.found_existing) { |
| 1462 | .base = .{ | 1619 | const primitive_inst = try self.arena.allocator.create(Inst.Primitive); |
| 1463 | .name = try self.autoName(), | 1620 | primitive_inst.* = .{ |
| 1464 | .src = src, | 1621 | .base = .{ |
| 1465 | .tag = Inst.Primitive.base_tag, | 1622 | .name = try self.autoName(), |
| 1466 | }, | 1623 | .src = src, |
| 1467 | .positionals = .{ | 1624 | .tag = Inst.Primitive.base_tag, |
| 1468 | .tag = tag, | 1625 | }, |
| 1469 | }, | 1626 | .positionals = .{ |
| 1470 | .kw_args = .{}, | 1627 | .tag = tag, |
| 1471 | }; | 1628 | }, |
| 1472 | try self.decls.append(self.allocator, &primitive_inst.base); | 1629 | .kw_args = .{}, |
| 1473 | return &primitive_inst.base; | 1630 | }; |
| 1631 | try self.decls.append(self.allocator, &primitive_inst.base); | ||
| 1632 | gop.kv.value = &primitive_inst.base; | ||
| 1633 | } | ||
| 1634 | return gop.kv.value; | ||
| 1474 | } | 1635 | } |
| 1475 | 1636 | ||
| 1476 | fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst { | 1637 | fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst { |
test/stage2/zir.zig+142-12| ... | @@ -21,14 +21,17 @@ pub fn addCases(ctx: *TestContext) void { | ... | @@ -21,14 +21,17 @@ pub fn addCases(ctx: *TestContext) void { |
| 21 | \\ %11 = return() | 21 | \\ %11 = return() |
| 22 | \\}) | 22 | \\}) |
| 23 | , | 23 | , |
| 24 | \\@0 = primitive(void) | 24 | \\@void = primitive(void) |
| 25 | \\@1 = fntype([], @0, cc=C) | 25 | \\@fnty = fntype([], @void, cc=C) |
| 26 | \\@2 = fn(@1, { | 26 | \\@9 = str("entry") |
| 27 | \\@10 = ref(@9) | ||
| 28 | \\@unnamed$6 = str("entry") | ||
| 29 | \\@unnamed$7 = ref(@unnamed$6) | ||
| 30 | \\@unnamed$8 = export(@unnamed$7, @entry) | ||
| 31 | \\@unnamed$10 = fntype([], @void, cc=C) | ||
| 32 | \\@entry = fn(@unnamed$10, { | ||
| 27 | \\ %0 = return() | 33 | \\ %0 = return() |
| 28 | \\}) | 34 | \\}) |
| 29 | \\@3 = str("entry") | ||
| 30 | \\@4 = ref(@3) | ||
| 31 | \\@5 = export(@4, @2) | ||
| 32 | \\ | 35 | \\ |
| 33 | ); | 36 | ); |
| 34 | ctx.addZIRTransform("elemptr, add, cmp, condbr, return, breakpoint", linux_x64, | 37 | ctx.addZIRTransform("elemptr, add, cmp, condbr, return, breakpoint", linux_x64, |
| ... | @@ -68,17 +71,144 @@ pub fn addCases(ctx: *TestContext) void { | ... | @@ -68,17 +71,144 @@ pub fn addCases(ctx: *TestContext) void { |
| 68 | \\@10 = ref(@9) | 71 | \\@10 = ref(@9) |
| 69 | \\@11 = export(@10, @entry) | 72 | \\@11 = export(@10, @entry) |
| 70 | , | 73 | , |
| 71 | \\@0 = primitive(void) | 74 | \\@void = primitive(void) |
| 72 | \\@1 = fntype([], @0, cc=C) | 75 | \\@fnty = fntype([], @void, cc=C) |
| 73 | \\@2 = fn(@1, { | 76 | \\@0 = int(0) |
| 77 | \\@1 = int(1) | ||
| 78 | \\@2 = int(2) | ||
| 79 | \\@3 = int(3) | ||
| 80 | \\@unnamed$7 = fntype([], @void, cc=C) | ||
| 81 | \\@entry = fn(@unnamed$7, { | ||
| 74 | \\ %0 = return() | 82 | \\ %0 = return() |
| 75 | \\}) | 83 | \\}) |
| 76 | \\@3 = str("entry") | 84 | \\@a = str("2\x08\x01\n") |
| 77 | \\@4 = ref(@3) | 85 | \\@9 = str("entry") |
| 78 | \\@5 = export(@4, @2) | 86 | \\@10 = ref(@9) |
| 87 | \\@unnamed$14 = str("entry") | ||
| 88 | \\@unnamed$15 = ref(@unnamed$14) | ||
| 89 | \\@unnamed$16 = export(@unnamed$15, @entry) | ||
| 79 | \\ | 90 | \\ |
| 80 | ); | 91 | ); |
| 81 | 92 | ||
| 93 | { | ||
| 94 | var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64); | ||
| 95 | case.addZIR( | ||
| 96 | \\@void = primitive(void) | ||
| 97 | \\@fnty = fntype([], @void, cc=C) | ||
| 98 | \\ | ||
| 99 | \\@9 = str("entry") | ||
| 100 | \\@10 = ref(@9) | ||
| 101 | \\@11 = export(@10, @entry) | ||
| 102 | \\ | ||
| 103 | \\@entry = fn(@fnty, { | ||
| 104 | \\ %0 = call(@a, []) | ||
| 105 | \\ %1 = return() | ||
| 106 | \\}) | ||
| 107 | \\ | ||
| 108 | \\@a = fn(@fnty, { | ||
| 109 | \\ %0 = call(@b, []) | ||
| 110 | \\ %1 = return() | ||
| 111 | \\}) | ||
| 112 | \\ | ||
| 113 | \\@b = fn(@fnty, { | ||
| 114 | \\ %0 = call(@a, []) | ||
| 115 | \\ %1 = return() | ||
| 116 | \\}) | ||
| 117 | , | ||
| 118 | \\@void = primitive(void) | ||
| 119 | \\@fnty = fntype([], @void, cc=C) | ||
| 120 | \\@9 = str("entry") | ||
| 121 | \\@10 = ref(@9) | ||
| 122 | \\@unnamed$6 = str("entry") | ||
| 123 | \\@unnamed$7 = ref(@unnamed$6) | ||
| 124 | \\@unnamed$8 = export(@unnamed$7, @entry) | ||
| 125 | \\@unnamed$12 = fntype([], @void, cc=C) | ||
| 126 | \\@entry = fn(@unnamed$12, { | ||
| 127 | \\ %0 = call(@a, [], modifier=auto) | ||
| 128 | \\ %1 = return() | ||
| 129 | \\}) | ||
| 130 | \\@unnamed$17 = fntype([], @void, cc=C) | ||
| 131 | \\@a = fn(@unnamed$17, { | ||
| 132 | \\ %0 = call(@b, [], modifier=auto) | ||
| 133 | \\ %1 = return() | ||
| 134 | \\}) | ||
| 135 | \\@unnamed$22 = fntype([], @void, cc=C) | ||
| 136 | \\@b = fn(@unnamed$22, { | ||
| 137 | \\ %0 = call(@a, [], modifier=auto) | ||
| 138 | \\ %1 = return() | ||
| 139 | \\}) | ||
| 140 | \\ | ||
| 141 | ); | ||
| 142 | // Now we introduce a compile error | ||
| 143 | case.addError( | ||
| 144 | \\@void = primitive(void) | ||
| 145 | \\@fnty = fntype([], @void, cc=C) | ||
| 146 | \\ | ||
| 147 | \\@9 = str("entry") | ||
| 148 | \\@10 = ref(@9) | ||
| 149 | \\@11 = export(@10, @entry) | ||
| 150 | \\ | ||
| 151 | \\@entry = fn(@fnty, { | ||
| 152 | \\ %0 = call(@a, []) | ||
| 153 | \\ %1 = return() | ||
| 154 | \\}) | ||
| 155 | \\ | ||
| 156 | \\@a = fn(@fnty, { | ||
| 157 | \\ %0 = call(@b, []) | ||
| 158 | \\ %1 = return() | ||
| 159 | \\}) | ||
| 160 | \\ | ||
| 161 | \\@b = fn(@fnty, { | ||
| 162 | \\ %9 = compileerror("message") | ||
| 163 | \\ %0 = call(@a, []) | ||
| 164 | \\ %1 = return() | ||
| 165 | \\}) | ||
| 166 | , | ||
| 167 | &[_][]const u8{ | ||
| 168 | ":19:21: error: message", | ||
| 169 | }, | ||
| 170 | ); | ||
| 171 | // Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are | ||
| 172 | // referencing either of them. This tests that the cycle is detected, and the error | ||
| 173 | // goes away. | ||
| 174 | case.addZIR( | ||
| 175 | \\@void = primitive(void) | ||
| 176 | \\@fnty = fntype([], @void, cc=C) | ||
| 177 | \\ | ||
| 178 | \\@9 = str("entry") | ||
| 179 | \\@10 = ref(@9) | ||
| 180 | \\@11 = export(@10, @entry) | ||
| 181 | \\ | ||
| 182 | \\@entry = fn(@fnty, { | ||
| 183 | \\ %1 = return() | ||
| 184 | \\}) | ||
| 185 | \\ | ||
| 186 | \\@a = fn(@fnty, { | ||
| 187 | \\ %0 = call(@b, []) | ||
| 188 | \\ %1 = return() | ||
| 189 | \\}) | ||
| 190 | \\ | ||
| 191 | \\@b = fn(@fnty, { | ||
| 192 | \\ %9 = compileerror("message") | ||
| 193 | \\ %0 = call(@a, []) | ||
| 194 | \\ %1 = return() | ||
| 195 | \\}) | ||
| 196 | , | ||
| 197 | \\@void = primitive(void) | ||
| 198 | \\@fnty = fntype([], @void, cc=C) | ||
| 199 | \\@9 = str("entry") | ||
| 200 | \\@10 = ref(@9) | ||
| 201 | \\@unnamed$6 = str("entry") | ||
| 202 | \\@unnamed$7 = ref(@unnamed$6) | ||
| 203 | \\@unnamed$8 = export(@unnamed$7, @entry) | ||
| 204 | \\@unnamed$10 = fntype([], @void, cc=C) | ||
| 205 | \\@entry = fn(@unnamed$10, { | ||
| 206 | \\ %0 = return() | ||
| 207 | \\}) | ||
| 208 | \\ | ||
| 209 | ); | ||
| 210 | } | ||
| 211 | |||
| 82 | if (std.Target.current.os.tag != .linux or | 212 | if (std.Target.current.os.tag != .linux or |
| 83 | std.Target.current.cpu.arch != .x86_64) | 213 | std.Target.current.cpu.arch != .x86_64) |
| 84 | { | 214 | { |