| ... | @@ -235,9 +235,9 @@ const TestManifest = struct { | ... | @@ -235,9 +235,9 @@ const TestManifest = struct { |
| 235 | inner: std.mem.SplitIterator(u8), | 235 | inner: std.mem.SplitIterator(u8), |
| 236 | parse_fn: ParseFn(T), | 236 | parse_fn: ParseFn(T), |
| 237 | | 237 | |
| 238 | fn next(self: *@This()) ?T { | 238 | fn next(self: *@This()) !?T { |
| 239 | const next_raw = self.inner.next() orelse return null; | 239 | const next_raw = self.inner.next() orelse return null; |
| 240 | return self.parse_fn(next_raw); | 240 | return try self.parse_fn(next_raw); |
| 241 | } | 241 | } |
| 242 | }; | 242 | }; |
| 243 | } | 243 | } |
| ... | @@ -339,20 +339,20 @@ const TestManifest = struct { | ... | @@ -339,20 +339,20 @@ const TestManifest = struct { |
| 339 | allocator: Allocator, | 339 | allocator: Allocator, |
| 340 | key: []const u8, | 340 | key: []const u8, |
| 341 | comptime T: type, | 341 | comptime T: type, |
| 342 | ) error{OutOfMemory}![]const T { | 342 | ) ![]const T { |
| 343 | var out = std.ArrayList(T).init(allocator); | 343 | var out = std.ArrayList(T).init(allocator); |
| 344 | defer out.deinit(); | 344 | defer out.deinit(); |
| 345 | var it = self.getConfigForKey(key, T); | 345 | var it = self.getConfigForKey(key, T); |
| 346 | while (it.next()) |item| { | 346 | while (try it.next()) |item| { |
| 347 | try out.append(item); | 347 | try out.append(item); |
| 348 | } | 348 | } |
| 349 | return out.toOwnedSlice(); | 349 | return out.toOwnedSlice(); |
| 350 | } | 350 | } |
| 351 | | 351 | |
| 352 | fn getConfigForKeyAssertSingle(self: TestManifest, key: []const u8, comptime T: type) T { | 352 | fn getConfigForKeyAssertSingle(self: TestManifest, key: []const u8, comptime T: type) !T { |
| 353 | var it = self.getConfigForKey(key, T); | 353 | var it = self.getConfigForKey(key, T); |
| 354 | const res = it.next().?; | 354 | const res = (try it.next()) orelse unreachable; |
| 355 | assert(it.next() == null); | 355 | assert((try it.next()) == null); |
| 356 | return res; | 356 | return res; |
| 357 | } | 357 | } |
| 358 | | 358 | |
| ... | @@ -373,33 +373,36 @@ const TestManifest = struct { | ... | @@ -373,33 +373,36 @@ const TestManifest = struct { |
| 373 | } | 373 | } |
| 374 | | 374 | |
| 375 | fn ParseFn(comptime T: type) type { | 375 | fn ParseFn(comptime T: type) type { |
| 376 | return fn ([]const u8) ?T; | 376 | return fn ([]const u8) anyerror!T; |
| 377 | } | 377 | } |
| 378 | | 378 | |
| 379 | fn getDefaultParser(comptime T: type) ParseFn(T) { | 379 | fn getDefaultParser(comptime T: type) ParseFn(T) { |
| 380 | switch (@typeInfo(T)) { | 380 | switch (@typeInfo(T)) { |
| 381 | .Int => return struct { | 381 | .Int => return struct { |
| 382 | fn parse(str: []const u8) ?T { | 382 | fn parse(str: []const u8) anyerror!T { |
| 383 | return std.fmt.parseInt(T, str, 0) catch null; | 383 | return try std.fmt.parseInt(T, str, 0); |
| 384 | } | 384 | } |
| 385 | }.parse, | 385 | }.parse, |
| 386 | .Bool => return struct { | 386 | .Bool => return struct { |
| 387 | fn parse(str: []const u8) ?T { | 387 | fn parse(str: []const u8) anyerror!T { |
| 388 | const as_int = std.fmt.parseInt(u1, str, 0) catch return null; | 388 | const as_int = try std.fmt.parseInt(u1, str, 0); |
| 389 | return as_int > 0; | 389 | return as_int > 0; |
| 390 | } | 390 | } |
| 391 | }.parse, | 391 | }.parse, |
| 392 | .Enum => return struct { | 392 | .Enum => return struct { |
| 393 | fn parse(str: []const u8) ?T { | 393 | fn parse(str: []const u8) anyerror!T { |
| 394 | return std.meta.stringToEnum(T, str); | 394 | return std.meta.stringToEnum(T, str) orelse { |
| | 395 | std.log.err("unknown enum variant for {s}: {s}", .{ @typeName(T), str }); |
| | 396 | return error.UnknownEnumVariant; |
| | 397 | }; |
| 395 | } | 398 | } |
| 396 | }.parse, | 399 | }.parse, |
| 397 | .Struct => if (comptime std.mem.eql(u8, @typeName(T), "CrossTarget")) return struct { | 400 | .Struct => if (comptime std.mem.eql(u8, @typeName(T), "CrossTarget")) return struct { |
| 398 | fn parse(str: []const u8) ?T { | 401 | fn parse(str: []const u8) anyerror!T { |
| 399 | var opts = CrossTarget.ParseOptions{ | 402 | var opts = CrossTarget.ParseOptions{ |
| 400 | .arch_os_abi = str, | 403 | .arch_os_abi = str, |
| 401 | }; | 404 | }; |
| 402 | return CrossTarget.parse(opts) catch null; | 405 | return try CrossTarget.parse(opts); |
| 403 | } | 406 | } |
| 404 | }.parse else @compileError("no default parser for " ++ @typeName(T)), | 407 | }.parse else @compileError("no default parser for " ++ @typeName(T)), |
| 405 | else => @compileError("no default parser for " ++ @typeName(T)), | 408 | else => @compileError("no default parser for " ++ @typeName(T)), |
| ... | @@ -1128,8 +1131,8 @@ pub const TestContext = struct { | ... | @@ -1128,8 +1131,8 @@ pub const TestContext = struct { |
| 1128 | if (cases.items.len == 0) { | 1131 | if (cases.items.len == 0) { |
| 1129 | const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend); | 1132 | const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend); |
| 1130 | const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", CrossTarget); | 1133 | const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", CrossTarget); |
| 1131 | const is_test = manifest.getConfigForKeyAssertSingle("is_test", bool); | 1134 | const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool); |
| 1132 | const output_mode = manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode); | 1135 | const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode); |
| 1133 | | 1136 | |
| 1134 | const name_prefix = blk: { | 1137 | const name_prefix = blk: { |
| 1135 | const ext_index = std.mem.lastIndexOfScalar(u8, current_file.*, '.') orelse | 1138 | const ext_index = std.mem.lastIndexOfScalar(u8, current_file.*, '.') orelse |