From 3e45baa60adbb041bf75af4cde380abb3b05abfb Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 8 Jul 2026 10:54:42 +0200 Subject: [PATCH] std.zig.Ast.parse: introduce options struct This is a much cleaner way to expose the new option to disable recovery added in 62720ad9f9e65dd8c625. It also makes it possible to add further options in the future without further breaking changes. --- lib/compiler/Maker.zig | 2 +- lib/compiler/Maker/Package/Manifest.zig | 8 ++++---- lib/compiler/reduce.zig | 4 ++-- lib/docs/wasm/Walk.zig | 6 +++--- lib/std/zig/Ast.zig | 16 ++++++++-------- lib/std/zig/parser_fuzz.zig | 2 +- lib/std/zig/parser_test.zig | 8 ++++---- lib/std/zig/perf_test.zig | 2 +- lib/std/zon/parse.zig | 6 +++--- src/Builtin.zig | 2 +- src/Zcu.zig | 2 +- src/Zcu/PerThread.zig | 2 +- src/fmt.zig | 4 ++-- src/main.zig | 6 +++--- tools/gen_parser_oracle.zig | 2 +- tools/gen_spirv_spec.zig | 2 +- 16 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index ad73ac16272d6848bbe4234f88ba833bb4bbaa7e..7a16501777c835283b394664453fb2d214aeb0d8 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -3536,7 +3536,7 @@ fn loadManifest( else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }), }; }; - var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon); + var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon, .{}); errdefer ast.deinit(gpa); if (ast.errors.len > 0) { diff --git a/lib/compiler/Maker/Package/Manifest.zig b/lib/compiler/Maker/Package/Manifest.zig index 849fc742ec5c7b5be02a2895f54f99fece02b2ff..cabcb9852549a3600919df36e5cbc7693bfeed3e 100644 --- a/lib/compiler/Maker/Package/Manifest.zig +++ b/lib/compiler/Maker/Package/Manifest.zig @@ -597,7 +597,7 @@ pub fn load( 0, ); - ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon); + ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon, .{}); if (ast.errors.len > 0) { const file_path = try manifest_path.joinString(arena, ""); @@ -636,7 +636,7 @@ test "basic" { \\} ; - var ast = try Ast.parse(gpa, example, .zon); + var ast = try Ast.parse(gpa, example, .zon, .{}); defer ast.deinit(gpa); try testing.expect(ast.errors.len == 0); @@ -682,7 +682,7 @@ test "minimum_zig_version" { \\} ; - var ast = try Ast.parse(gpa, example, .zon); + var ast = try Ast.parse(gpa, example, .zon, .{}); defer ast.deinit(gpa); try testing.expect(ast.errors.len == 0); @@ -717,7 +717,7 @@ test "minimum_zig_version - invalid version" { \\} ; - var ast = try Ast.parse(gpa, example, .zon); + var ast = try Ast.parse(gpa, example, .zon, .{}); defer ast.deinit(gpa); try testing.expect(ast.errors.len == 0); diff --git a/lib/compiler/reduce.zig b/lib/compiler/reduce.zig index 8d4f270a7946ca32ae04aa996df91a1decc22743..df4675ff47bdf42812c026a1f61cd1edc47b544b 100644 --- a/lib/compiler/reduce.zig +++ b/lib/compiler/reduce.zig @@ -188,7 +188,7 @@ pub fn main(init: std.process.Init) !void { try astgen_input.writer.writeAll(rendered.written()); try astgen_input.writer.writeByte(0); const source_with_null = astgen_input.written()[0..(astgen_input.written().len - 1) :0]; - var astgen_tree = try Ast.parse(gpa, source_with_null, .zig); + var astgen_tree = try Ast.parse(gpa, source_with_null, .zig, .{}); defer astgen_tree.deinit(gpa); if (astgen_tree.errors.len != 0) { @panic("syntax errors occurred"); @@ -407,7 +407,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast { }; errdefer gpa.free(source_code); - var tree = try Ast.parse(gpa, source_code, .zig); + var tree = try Ast.parse(gpa, source_code, .zig, .{}); errdefer tree.deinit(gpa); if (tree.errors.len != 0) { diff --git a/lib/docs/wasm/Walk.zig b/lib/docs/wasm/Walk.zig index 2d5a45d72f739abb1d763bea3d6804b3ee53859d..779ed163485a147338b5c1e4a44b252ee3071064 100644 --- a/lib/docs/wasm/Walk.zig +++ b/lib/docs/wasm/Walk.zig @@ -428,7 +428,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { break :s source[0 .. source.len - 1 :0]; }; - var ast = try Ast.parse(gpa, adjusted_source, .zig); + var ast = try Ast.parse(gpa, adjusted_source, .zig, .{}); if (ast.errors.len > 0) { defer ast.deinit(gpa); @@ -446,7 +446,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.written(), }); } - return Ast.parse(gpa, "", .zig); + return Ast.parse(gpa, "", .zig, .{}); } return ast; } @@ -1085,7 +1085,7 @@ pub fn isPrimitiveNonType(name: []const u8) bool { // // // example test command: // // zig test --dep input.zig -Mroot=src/Walk.zig -Minput.zig=/home/andy/dev/zig/lib/std/fs/File/zig -// var ast = try Ast.parse(gpa, @embedFile("input.zig"), .zig); +// var ast = try Ast.parse(gpa, @embedFile("input.zig"), .zig, .{}); // defer ast.deinit(gpa); // // var w: Walk = .{ diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index f2af6c9f173e280b3ad7135431ed7251b313cc7a..9a09f027d91f70d077cde861148bb951d06877b8 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -138,11 +138,14 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { tree.* = undefined; } -pub const Mode = enum { zig, zon, zig_no_recover }; +pub const Mode = enum { zig, zon }; +pub const ParseOptions = struct { + recover: bool = true, +}; /// Result should be freed with tree.deinit() when there are /// no more references to any of the tokens or nodes. -pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!Ast { +pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode, options: ParseOptions) Allocator.Error!Ast { var tokens = Ast.TokenList{}; defer tokens.deinit(gpa); @@ -162,7 +165,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A var tokens_slice = tokens.toOwnedSlice(); errdefer tokens_slice.deinit(gpa); - return parseTokens(gpa, source, tokens_slice, mode); + return parseTokens(gpa, source, tokens_slice, mode, options); } pub fn parseTokens( @@ -170,6 +173,7 @@ pub fn parseTokens( source: [:0]const u8, tokens: Ast.TokenList.Slice, mode: Mode, + options: ParseOptions, ) Allocator.Error!Ast { var parser: Parse = .{ .source = source, @@ -180,7 +184,7 @@ pub fn parseTokens( .extra_data = .empty, .scratch = .empty, .tok_i = 0, - .recover = true, + .recover = options.recover, }; defer parser.errors.deinit(gpa); defer parser.nodes.deinit(gpa); @@ -194,10 +198,6 @@ pub fn parseTokens( switch (mode) { .zig => try parser.parseRoot(), - .zig_no_recover => { - parser.recover = false; - try parser.parseRoot(); - }, .zon => try parser.parseZon(), } diff --git a/lib/std/zig/parser_fuzz.zig b/lib/std/zig/parser_fuzz.zig index 298b1dea8536a095567fb6931659c3ca3c038ba1..48823191202f822ba38be1d7d68530a458877a69 100644 --- a/lib/std/zig/parser_fuzz.zig +++ b/lib/std/zig/parser_fuzz.zig @@ -171,7 +171,7 @@ fn checkAgainstOracle(source: [:0]const u8) !void { // error right away and does no recovery. However, std.zig.Ast.parse() does recovery // by default and will hit a stack overflow rather than returning after the parser error. // Stack overflows are not interesting and we do not want the fuzzer to be able to find them. - const ast = try std.zig.Ast.parse(fba.allocator(), source, .zig_no_recover); + const ast = try std.zig.Ast.parse(fba.allocator(), source, .zig, .{ .recover = false }); errdefer logBadSource(source, ast); try std.testing.expectEqual(expected, ast.errors.len == 0); diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index f5ba5b6bed49453e5137ad838579278f33626ceb..cc4e1bca11d3b0f17fcb16564f364e060fff18d5 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -7231,7 +7231,7 @@ test "ampersand" { test "Ast: pointer types with subexprs containing qualifiers" { var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); const allocator = fixed_allocator.allocator(); - var tree = try std.zig.Ast.parse(allocator, "**addrspace(*align(1)T)T", .zon); + var tree = try std.zig.Ast.parse(allocator, "**addrspace(*align(1)T)T", .zon, .{}); defer tree.deinit(allocator); const regular_ptr_node = tree.nodeData(.root).node; @@ -7253,7 +7253,7 @@ fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_change defer io.unlockStderr(); const writer = &stderr.file_writer.interface; - var tree = try std.zig.Ast.parse(allocator, source, .zig); + var tree = try std.zig.Ast.parse(allocator, source, .zig, .{}); defer tree.deinit(allocator); for (tree.errors) |parse_error| { @@ -7313,7 +7313,7 @@ fn testCanonical(source: [:0]const u8) !void { const Error = std.zig.Ast.Error.Tag; fn testError(source: [:0]const u8, expected_errors: []const Error) !void { - var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig); + var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig, .{}); defer tree.deinit(std.testing.allocator); std.testing.expectEqual(expected_errors.len, tree.errors.len) catch |err| { @@ -7333,5 +7333,5 @@ fn fuzzTestOneParse(_: void, smith: *std.testing.Smith) !void { const mode = smith.value(std.zig.Ast.Mode); var tokens: std.zig.TokenSmith = .gen(smith); var fba: std.heap.FixedBufferAllocator = .init(&fixed_buffer_mem); - _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode) catch return; + _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode, .{ .recover = false }) catch return; } diff --git a/lib/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig index da3dd42f15fc3feb4f2c2347119e32b145d4430d..e04fa562c3a31d6e423eb772326af54a6679f3a6 100644 --- a/lib/std/zig/perf_test.zig +++ b/lib/std/zig/perf_test.zig @@ -32,6 +32,6 @@ pub fn main() !void { fn testOnce() usize { var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem); const allocator = fixed_buf_alloc.allocator(); - _ = std.zig.Ast.parse(allocator, source, .zig) catch @panic("parse failure"); + _ = std.zig.Ast.parse(allocator, source, .zig, .{}) catch @panic("parse failure"); return fixed_buf_alloc.end_index; } diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 249dc9b644ce80553568bfd5dfb77291ec6bf60c..d074a2198e798e3e191a9788f0c53626ca8fa7a5 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -294,7 +294,7 @@ pub fn fromSliceAlloc( ) error{ OutOfMemory, ParseZon }!T { if (diag) |s| s.assertEmpty(); - var ast = try std.zig.Ast.parse(gpa, source, .zon); + var ast = try std.zig.Ast.parse(gpa, source, .zon, .{}); defer if (diag == null) ast.deinit(gpa); if (diag) |s| s.ast = ast; @@ -2140,7 +2140,7 @@ test "std.zon string literal" { // Passing string literal to a array { { - var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon); + var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon, .{}); defer ast.deinit(gpa); var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); defer zoir.deinit(gpa); @@ -3534,7 +3534,7 @@ test "std.zon no alloc" { const Nested = struct { u8, u8, struct { u8, u8 } }; - var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon); + var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon, .{}); defer ast.deinit(gpa); var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); diff --git a/src/Builtin.zig b/src/Builtin.zig index 2117aae11b1ef834cfdb594dfc1f7ea2711e5406..05329d77a21709c96445f48e8bac0e123d24ac1b 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -296,7 +296,7 @@ pub fn populateFile(opts: @This(), gpa: Allocator, file: *File) Allocator.Error! log.debug("parsing and generating 'builtin.zig'", .{}); - file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig); + file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig, .{}); assert(file.tree.?.errors.len == 0); // builtin.zig must parse file.zir = try AstGen.generate(gpa, file.tree.?); diff --git a/src/Zcu.zig b/src/Zcu.zig index d36c96c07dab3f38df7abfff2a67003529a80201..b6d17eb624e01a416f78ab3677a74a23f77318a5 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -1145,7 +1145,7 @@ pub const File = struct { if (file.tree) |*tree| return tree; const source = try file.getSource(zcu); - file.tree = try .parse(zcu.gpa, source, file.getMode()); + file.tree = try .parse(zcu.gpa, source, file.getMode(), .{}); return &file.tree.?; } diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index c6c665655cf1ae7a792fabb44b5433efa6664bef..a1c5d400b0e6fcda22716196b6ca60ddb7c3ba45 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -642,7 +642,7 @@ pub fn updateFile( var timer = comp.startTimer(); // Any potential AST errors are converted to ZIR errors when we run AstGen/ZonGen. - file.tree = try Ast.parse(gpa, source, file.getMode()); + file.tree = try Ast.parse(gpa, source, file.getMode(), .{}); if (timer.finish(io)) |ns_parse| { comp.mutex.lockUncancelable(io); defer comp.mutex.unlock(io); diff --git a/src/fmt.zig b/src/fmt.zig index 73d8a1c162328f720e9687d17cf7e2129b431da2..247f9fb7affea661954faf6da84de95eabc89188 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -117,7 +117,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! }; defer gpa.free(source_code); - var tree = std.zig.Ast.parse(gpa, source_code, if (force_zon) .zon else .zig) catch |err| { + var tree = std.zig.Ast.parse(gpa, source_code, if (force_zon) .zon else .zig, .{}) catch |err| { fatal("error parsing stdin: {}", .{err}); }; defer tree.deinit(gpa); @@ -312,7 +312,7 @@ fn fmtPathFile( break :mode .zig; }; - var tree = try std.zig.Ast.parse(gpa, source_code, mode); + var tree = try std.zig.Ast.parse(gpa, source_code, mode, .{}); defer tree.deinit(gpa); if (tree.errors.len != 0) { diff --git a/src/main.zig b/src/main.zig index 8f569d2a856e039466416c5bd3e810a1a0d15610..11801d65ef000e6581e4a9361e54aed8846d4839 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5529,7 +5529,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: break :mode .zig; }; - const tree = try Ast.parse(arena, source, mode); + const tree = try Ast.parse(arena, source, mode, .{}); var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); const stdout_bw = &stdout_writer.interface; @@ -5699,7 +5699,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map fatal("unable to read new source file {q}: {t}", .{ new_source_path, err }); }; - const old_tree = try Ast.parse(arena, old_source, .zig); + const old_tree = try Ast.parse(arena, old_source, .zig, .{}); const old_zir = try AstGen.generate(arena, old_tree); if (old_zir.loweringFailed()) { @@ -5711,7 +5711,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map process.exit(1); } - const new_tree = try Ast.parse(arena, new_source, .zig); + const new_tree = try Ast.parse(arena, new_source, .zig, .{}); const new_zir = try AstGen.generate(arena, new_tree); if (new_zir.loweringFailed()) { diff --git a/tools/gen_parser_oracle.zig b/tools/gen_parser_oracle.zig index 96db98aa3894c11c9f2edc3b0cd256adf0e9a168..26e550fef1adcde2e8eb01356dd5fdef63b84c2e 100644 --- a/tools/gen_parser_oracle.zig +++ b/tools/gen_parser_oracle.zig @@ -43,7 +43,7 @@ pub fn main(init: std.process.Init) !void { defer gpa.free(generated); // Parse the generated Zig code and render it in the canonical format - var tree = try std.zig.Ast.parse(gpa, generated, .zig); + var tree = try std.zig.Ast.parse(gpa, generated, .zig, .{}); defer tree.deinit(gpa); if (tree.errors.len != 0) { diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig index fbf8fa167ae6fc0ae5dcba040a87046b66d34c5c..8258c0c464af12be489b099d7ad0105ab2c0d1c2 100644 --- a/tools/gen_spirv_spec.zig +++ b/tools/gen_spirv_spec.zig @@ -116,7 +116,7 @@ pub fn main(init: std.process.Init) !void { try allocating.writer.writeByte(0); const output = allocating.written()[0 .. allocating.written().len - 1 :0]; - var tree = try std.zig.Ast.parse(arena, output, .zig); + var tree = try std.zig.Ast.parse(arena, output, .zig, .{}); if (tree.errors.len != 0) { try std.zig.printAstErrorsToStderr(arena, io, tree, "", .auto); -- 2.54.0