| ... | @@ -94,8 +94,12 @@ pub const Error = struct { | ... | @@ -94,8 +94,12 @@ pub const Error = struct { |
| 94 | /// Errors encountered while parsing ZON. See `log` and `fatal` for reporting errors to the user. | 94 | /// Errors encountered while parsing ZON. See `log` and `fatal` for reporting errors to the user. |
| 95 | pub const Errors = struct { | 95 | pub const Errors = struct { |
| 96 | items: []const Error, | 96 | items: []const Error, |
| | 97 | oom: bool, |
| 97 | | 98 | |
| 98 | pub const empty: Errors = .{ .items = &.{} }; | 99 | pub const empty: Errors = .{ |
| | 100 | .items = &.{}, |
| | 101 | .oom = false, |
| | 102 | }; |
| 99 | | 103 | |
| 100 | /// Log the failure with `std.log.err`. | 104 | /// Log the failure with `std.log.err`. |
| 101 | pub fn log(self: *const Errors, path: []const u8) void { | 105 | pub fn log(self: *const Errors, path: []const u8) void { |
| ... | @@ -119,12 +123,9 @@ pub const Errors = struct { | ... | @@ -119,12 +123,9 @@ pub const Errors = struct { |
| 119 | .arena = arena, | 123 | .arena = arena, |
| 120 | .source = ".{ .foo = 1, .bar = 2 }", | 124 | .source = ".{ .foo = 1, .bar = 2 }", |
| 121 | .errors = &errors, | 125 | .errors = &errors, |
| 122 | }) catch |err| switch (err) { | 126 | }) catch b: { |
| 123 | error.OutOfMemory => return error.OutOfMemory, | 127 | errors.log("input.zon"); |
| 124 | error.ParseZon => b: { | 128 | break :b .{ .foo = 0, .bar = 0 }; |
| 125 | errors.log("input.zon"); | | |
| 126 | break :b .{ .foo = 0, .bar = 0 }; | | |
| 127 | }, | | |
| 128 | }; | 129 | }; |
| 129 | _ = parsed; | 130 | _ = parsed; |
| 130 | } | 131 | } |
| ... | @@ -151,16 +152,14 @@ pub const Errors = struct { | ... | @@ -151,16 +152,14 @@ pub const Errors = struct { |
| 151 | .arena = arena, | 152 | .arena = arena, |
| 152 | .source = ".{ .foo = 1, .bar = 2 }", | 153 | .source = ".{ .foo = 1, .bar = 2 }", |
| 153 | .errors = &errors, | 154 | .errors = &errors, |
| 154 | }) catch |err| switch (err) { | 155 | }) catch errors.fatal("input.zon"); |
| 155 | error.OutOfMemory => return error.OutOfMemory, | | |
| 156 | error.ParseZon => errors.fatal("input.zon"), | | |
| 157 | }; | | |
| 158 | _ = parsed; | 156 | _ = parsed; |
| 159 | } | 157 | } |
| 160 | | 158 | |
| 161 | pub fn fmt(self: *const Errors, path: []const u8) Formatter { | 159 | pub fn fmt(self: *const Errors, path: []const u8) Formatter { |
| 162 | return .{ | 160 | return .{ |
| 163 | .items = self.items, | 161 | .items = self.items, |
| | 162 | .oom = self.oom, |
| 164 | .path = path, | 163 | .path = path, |
| 165 | }; | 164 | }; |
| 166 | } | 165 | } |
| ... | @@ -168,8 +167,12 @@ pub const Errors = struct { | ... | @@ -168,8 +167,12 @@ pub const Errors = struct { |
| 168 | pub const Formatter = struct { | 167 | pub const Formatter = struct { |
| 169 | path: []const u8, | 168 | path: []const u8, |
| 170 | items: []const Error, | 169 | items: []const Error, |
| | 170 | oom: bool, |
| 171 | | 171 | |
| 172 | pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { | 172 | pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { |
| | 173 | if (self.oom) { |
| | 174 | try w.print("{s}: out of memory", .{self.path}); |
| | 175 | } |
| 173 | for (self.items) |e| { | 176 | for (self.items) |e| { |
| 174 | try w.print("{s}:", .{self.path}); | 177 | try w.print("{s}:", .{self.path}); |
| 175 | try w.print("{d}:{d}: error: {s}\n", .{ | 178 | try w.print("{d}:{d}: error: {s}\n", .{ |
| ... | @@ -189,6 +192,11 @@ pub const Errors = struct { | ... | @@ -189,6 +192,11 @@ pub const Errors = struct { |
| 189 | } | 192 | } |
| 190 | } | 193 | } |
| 191 | }; | 194 | }; |
| | 195 | |
| | 196 | fn checkOom(self: *Errors, result: anytype) @TypeOf(result) { |
| | 197 | self.oom |= result == error.OutOfMemory; |
| | 198 | return result; |
| | 199 | } |
| 192 | }; | 200 | }; |
| 193 | | 201 | |
| 194 | pub const Options = struct { | 202 | pub const Options = struct { |
| ... | @@ -238,12 +246,9 @@ test fromSlice { | ... | @@ -238,12 +246,9 @@ test fromSlice { |
| 238 | .arena = arena, | 246 | .arena = arena, |
| 239 | .source = source, | 247 | .source = source, |
| 240 | .errors = &errors, | 248 | .errors = &errors, |
| 241 | }) catch |err| switch (err) { | 249 | }) catch |err| { |
| 242 | error.OutOfMemory => return err, | 250 | errors.log("texture_options.zon"); |
| 243 | error.ParseZon => { | 251 | return err; |
| 244 | errors.log("texture_options.zon"); | | |
| 245 | return err; | | |
| 246 | }, | | |
| 247 | }; | 252 | }; |
| 248 | | 253 | |
| 249 | try std.testing.expectEqualDeep(TextureOptions{ | 254 | try std.testing.expectEqualDeep(TextureOptions{ |
| ... | @@ -313,24 +318,18 @@ test updateFromSlice { | ... | @@ -313,24 +318,18 @@ test updateFromSlice { |
| 313 | .arena = arena, | 318 | .arena = arena, |
| 314 | .source = global_config, | 319 | .source = global_config, |
| 315 | .errors = &errors, | 320 | .errors = &errors, |
| 316 | }) catch |err| switch (err) { | 321 | }) catch |err| { |
| 317 | error.OutOfMemory => return err, | 322 | errors.log("global_config.zon"); |
| 318 | error.ParseZon => { | 323 | return err; |
| 319 | errors.log("global_config.zon"); | | |
| 320 | return err; | | |
| 321 | }, | | |
| 322 | }; | 324 | }; |
| 323 | updateFromSlice(MyTextEditorConfig, &config, .{ | 325 | updateFromSlice(MyTextEditorConfig, &config, .{ |
| 324 | .gpa = gpa, | 326 | .gpa = gpa, |
| 325 | .arena = arena, | 327 | .arena = arena, |
| 326 | .source = project_config, | 328 | .source = project_config, |
| 327 | .errors = &errors, | 329 | .errors = &errors, |
| 328 | }) catch |err| switch (err) { | 330 | }) catch |err| { |
| 329 | error.OutOfMemory => return err, | 331 | errors.log("project_config.zon"); |
| 330 | error.ParseZon => { | 332 | return err; |
| 331 | errors.log("project_config.zon"); | | |
| 332 | return err; | | |
| 333 | }, | | |
| 334 | }; | 333 | }; |
| 335 | | 334 | |
| 336 | try std.testing.expectEqualDeep(MyTextEditorConfig{ | 335 | try std.testing.expectEqualDeep(MyTextEditorConfig{ |
| ... | @@ -358,23 +357,32 @@ fn fromSliceInner( | ... | @@ -358,23 +357,32 @@ fn fromSliceInner( |
| 358 | initialized: bool, | 357 | initialized: bool, |
| 359 | options: Options, | 358 | options: Options, |
| 360 | ) error{ OutOfMemory, ParseZon }!void { | 359 | ) error{ OutOfMemory, ParseZon }!void { |
| | 360 | options.errors.oom = false; |
| 361 | var errors: std.ArrayList(Error) = .empty; | 361 | var errors: std.ArrayList(Error) = .empty; |
| 362 | defer options.errors.items = errors.items; | 362 | defer options.errors.items = errors.items; |
| 363 | | 363 | |
| 364 | var ast = try std.zig.Ast.parse(options.gpa, options.source, .{ .mode = .zon }); | 364 | var ast = try options.errors.checkOom(std.zig.Ast.parse( |
| | 365 | options.gpa, |
| | 366 | options.source, |
| | 367 | .{ .mode = .zon }, |
| | 368 | )); |
| 365 | defer ast.deinit(options.gpa); | 369 | defer ast.deinit(options.gpa); |
| 366 | | 370 | |
| 367 | var zoir = try ZonGen.generate(options.gpa, ast, .{ .parse_str_lits = false }); | 371 | var zoir = try options.errors.checkOom(ZonGen.generate( |
| | 372 | options.gpa, |
| | 373 | ast, |
| | 374 | .{ .parse_str_lits = false }, |
| | 375 | )); |
| 368 | defer zoir.deinit(options.gpa); | 376 | defer zoir.deinit(options.gpa); |
| 369 | | 377 | |
| 370 | try inner(T, value, initialized, .{ | 378 | try options.errors.checkOom(inner(T, value, initialized, .{ |
| 371 | .arena = options.arena, | 379 | .arena = options.arena, |
| 372 | .ast = &ast, | 380 | .ast = &ast, |
| 373 | .zoir = &zoir, | 381 | .zoir = &zoir, |
| 374 | .node = .root, | 382 | .node = .root, |
| 375 | .errors = &errors, | 383 | .errors = &errors, |
| 376 | .ignore_unknown_fields = options.ignore_unknown_fields, | 384 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 377 | }); | 385 | })); |
| 378 | } | 386 | } |
| 379 | | 387 | |
| 380 | pub const FromZoirOptions = struct { | 388 | pub const FromZoirOptions = struct { |
| ... | @@ -431,15 +439,16 @@ fn fromZoirInner( | ... | @@ -431,15 +439,16 @@ fn fromZoirInner( |
| 431 | initialized: bool, | 439 | initialized: bool, |
| 432 | options: FromZoirOptions, | 440 | options: FromZoirOptions, |
| 433 | ) error{ OutOfMemory, ParseZon }!void { | 441 | ) error{ OutOfMemory, ParseZon }!void { |
| | 442 | options.errors.oom = false; |
| 434 | var errors: std.ArrayList(Error) = .empty; | 443 | var errors: std.ArrayList(Error) = .empty; |
| 435 | defer options.errors.items = errors.items; | 444 | defer options.errors.items = errors.items; |
| 436 | return inner(T, value, initialized, .{ | 445 | return options.errors.checkOom(inner(T, value, initialized, .{ |
| 437 | .arena = options.arena, | 446 | .arena = options.arena, |
| 438 | .ast = options.ast, | 447 | .ast = options.ast, |
| 439 | .zoir = options.zoir, | 448 | .zoir = options.zoir, |
| 440 | .errors = &errors, | 449 | .errors = &errors, |
| 441 | .ignore_unknown_fields = options.ignore_unknown_fields, | 450 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 442 | }); | 451 | })); |
| 443 | } | 452 | } |
| 444 | | 453 | |
| 445 | const InnerOptions = struct { | 454 | const InnerOptions = struct { |
| ... | @@ -1441,17 +1450,38 @@ test "std.zon failure/oom formatting" { | ... | @@ -1441,17 +1450,38 @@ test "std.zon failure/oom formatting" { |
| 1441 | var arena_allocator: ArenaAllocator = .init(gpa); | 1450 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1442 | defer arena_allocator.deinit(); | 1451 | defer arena_allocator.deinit(); |
| 1443 | const arena = arena_allocator.allocator(); | 1452 | const arena = arena_allocator.allocator(); |
| 1444 | var errors: Errors = .empty; | | |
| 1445 | | 1453 | |
| 1446 | try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{ | 1454 | { |
| 1447 | .gpa = .failing, | 1455 | var errors: Errors = .empty; |
| 1448 | .arena = arena, | 1456 | try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{ |
| 1449 | .source = "\"foo\"", | 1457 | .gpa = .failing, |
| 1450 | .errors = &errors, | 1458 | .arena = arena, |
| 1451 | })); | 1459 | .source = "\"foo\"", |
| 1452 | try std.testing.expectFmt( | 1460 | .errors = &errors, |
| 1453 | \\ | 1461 | })); |
| 1454 | , "{f}", .{errors.fmt("input.zon")}); | 1462 | try std.testing.expectFmt( |
| | 1463 | \\input.zon: out of memory |
| | 1464 | , "{f}", .{errors.fmt("input.zon")}); |
| | 1465 | } |
| | 1466 | |
| | 1467 | { |
| | 1468 | var ast = try std.zig.Ast.parse(gpa, "\"foo\"", .{ .mode = .zon }); |
| | 1469 | defer ast.deinit(gpa); |
| | 1470 | |
| | 1471 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| | 1472 | defer zoir.deinit(gpa); |
| | 1473 | |
| | 1474 | var errors: Errors = .empty; |
| | 1475 | try std.testing.expectError(error.OutOfMemory, fromZoir([]const u8, .{ |
| | 1476 | .arena = .failing, |
| | 1477 | .ast = &ast, |
| | 1478 | .zoir = &zoir, |
| | 1479 | .errors = &errors, |
| | 1480 | })); |
| | 1481 | try std.testing.expectFmt( |
| | 1482 | \\input.zon: out of memory |
| | 1483 | , "{f}", .{errors.fmt("input.zon")}); |
| | 1484 | } |
| 1455 | } | 1485 | } |
| 1456 | | 1486 | |
| 1457 | test "std.zon fromSlice syntax error" { | 1487 | test "std.zon fromSlice syntax error" { |