diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 6011f768f6a681da686c46eaeb585e6ddcf6970e..d48e1be0391dec49e5483a8303ae5011914a00c7 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -94,8 +94,12 @@ pub const Error = struct { /// Errors encountered while parsing ZON. See `log` and `fatal` for reporting errors to the user. pub const Errors = struct { items: []const Error, + oom: bool, - pub const empty: Errors = .{ .items = &.{} }; + pub const empty: Errors = .{ + .items = &.{}, + .oom = false, + }; /// Log the failure with `std.log.err`. pub fn log(self: *const Errors, path: []const u8) void { @@ -119,12 +123,9 @@ pub const Errors = struct { .arena = arena, .source = ".{ .foo = 1, .bar = 2 }", .errors = &errors, - }) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseZon => b: { - errors.log("input.zon"); - break :b .{ .foo = 0, .bar = 0 }; - }, + }) catch b: { + errors.log("input.zon"); + break :b .{ .foo = 0, .bar = 0 }; }; _ = parsed; } @@ -151,16 +152,14 @@ pub const Errors = struct { .arena = arena, .source = ".{ .foo = 1, .bar = 2 }", .errors = &errors, - }) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseZon => errors.fatal("input.zon"), - }; + }) catch errors.fatal("input.zon"); _ = parsed; } pub fn fmt(self: *const Errors, path: []const u8) Formatter { return .{ .items = self.items, + .oom = self.oom, .path = path, }; } @@ -168,8 +167,12 @@ pub const Errors = struct { pub const Formatter = struct { path: []const u8, items: []const Error, + oom: bool, pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { + if (self.oom) { + try w.print("{s}: out of memory", .{self.path}); + } for (self.items) |e| { try w.print("{s}:", .{self.path}); try w.print("{d}:{d}: error: {s}\n", .{ @@ -189,6 +192,11 @@ pub const Errors = struct { } } }; + + fn checkOom(self: *Errors, result: anytype) @TypeOf(result) { + self.oom |= result == error.OutOfMemory; + return result; + } }; pub const Options = struct { @@ -238,12 +246,9 @@ test fromSlice { .arena = arena, .source = source, .errors = &errors, - }) catch |err| switch (err) { - error.OutOfMemory => return err, - error.ParseZon => { - errors.log("texture_options.zon"); - return err; - }, + }) catch |err| { + errors.log("texture_options.zon"); + return err; }; try std.testing.expectEqualDeep(TextureOptions{ @@ -313,24 +318,18 @@ test updateFromSlice { .arena = arena, .source = global_config, .errors = &errors, - }) catch |err| switch (err) { - error.OutOfMemory => return err, - error.ParseZon => { - errors.log("global_config.zon"); - return err; - }, + }) catch |err| { + errors.log("global_config.zon"); + return err; }; updateFromSlice(MyTextEditorConfig, &config, .{ .gpa = gpa, .arena = arena, .source = project_config, .errors = &errors, - }) catch |err| switch (err) { - error.OutOfMemory => return err, - error.ParseZon => { - errors.log("project_config.zon"); - return err; - }, + }) catch |err| { + errors.log("project_config.zon"); + return err; }; try std.testing.expectEqualDeep(MyTextEditorConfig{ @@ -358,23 +357,32 @@ fn fromSliceInner( initialized: bool, options: Options, ) error{ OutOfMemory, ParseZon }!void { + options.errors.oom = false; var errors: std.ArrayList(Error) = .empty; defer options.errors.items = errors.items; - var ast = try std.zig.Ast.parse(options.gpa, options.source, .{ .mode = .zon }); + var ast = try options.errors.checkOom(std.zig.Ast.parse( + options.gpa, + options.source, + .{ .mode = .zon }, + )); defer ast.deinit(options.gpa); - var zoir = try ZonGen.generate(options.gpa, ast, .{ .parse_str_lits = false }); + var zoir = try options.errors.checkOom(ZonGen.generate( + options.gpa, + ast, + .{ .parse_str_lits = false }, + )); defer zoir.deinit(options.gpa); - try inner(T, value, initialized, .{ + try options.errors.checkOom(inner(T, value, initialized, .{ .arena = options.arena, .ast = &ast, .zoir = &zoir, .node = .root, .errors = &errors, .ignore_unknown_fields = options.ignore_unknown_fields, - }); + })); } pub const FromZoirOptions = struct { @@ -431,15 +439,16 @@ fn fromZoirInner( initialized: bool, options: FromZoirOptions, ) error{ OutOfMemory, ParseZon }!void { + options.errors.oom = false; var errors: std.ArrayList(Error) = .empty; defer options.errors.items = errors.items; - return inner(T, value, initialized, .{ + return options.errors.checkOom(inner(T, value, initialized, .{ .arena = options.arena, .ast = options.ast, .zoir = options.zoir, .errors = &errors, .ignore_unknown_fields = options.ignore_unknown_fields, - }); + })); } const InnerOptions = struct { @@ -1441,17 +1450,38 @@ test "std.zon failure/oom formatting" { var arena_allocator: ArenaAllocator = .init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - var errors: Errors = .empty; - - try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{ - .gpa = .failing, - .arena = arena, - .source = "\"foo\"", - .errors = &errors, - })); - try std.testing.expectFmt( - \\ - , "{f}", .{errors.fmt("input.zon")}); + + { + var errors: Errors = .empty; + try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{ + .gpa = .failing, + .arena = arena, + .source = "\"foo\"", + .errors = &errors, + })); + try std.testing.expectFmt( + \\input.zon: out of memory + , "{f}", .{errors.fmt("input.zon")}); + } + + { + var ast = try std.zig.Ast.parse(gpa, "\"foo\"", .{ .mode = .zon }); + defer ast.deinit(gpa); + + var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); + defer zoir.deinit(gpa); + + var errors: Errors = .empty; + try std.testing.expectError(error.OutOfMemory, fromZoir([]const u8, .{ + .arena = .failing, + .ast = &ast, + .zoir = &zoir, + .errors = &errors, + })); + try std.testing.expectFmt( + \\input.zon: out of memory + , "{f}", .{errors.fmt("input.zon")}); + } } test "std.zon fromSlice syntax error" {