mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 20:43:19 +00:00
zig reduce: check once upfront to verify interestingness
This commit is contained in:
parent
b1aaf42134
commit
815b85d8a2
126
src/reduce.zig
126
src/reduce.zig
@ -1,13 +1,34 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const fatal = @import("./main.zig").fatal;
|
||||
|
||||
const usage =
|
||||
\\zig reduce [source_file] [interestingness]
|
||||
\\zig reduce [options] ./checker root_source_file.zig [-- [argv]]
|
||||
\\
|
||||
\\root_source_file.zig is relative to --main-mod-path.
|
||||
\\
|
||||
\\checker:
|
||||
\\ An executable that communicates interestingness by returning these exit codes:
|
||||
\\ exit(0): interesting
|
||||
\\ exit(1): unknown (infinite loop or other mishap)
|
||||
\\ exit(other): not interesting
|
||||
\\
|
||||
\\options:
|
||||
\\ --mod [name]:[deps]:[src] Make a module available for dependency under the given name
|
||||
\\ deps: [dep],[dep],...
|
||||
\\ dep: [[import=]name]
|
||||
\\ --deps [dep],[dep],... Set dependency names for the root package
|
||||
\\ dep: [[import=]name]
|
||||
\\ --main-mod-path Set the directory of the root module
|
||||
\\
|
||||
\\argv:
|
||||
\\ Forwarded directly to the interestingness script.
|
||||
\\
|
||||
;
|
||||
|
||||
const Interestingness = enum { interesting, boring, unknown };
|
||||
const Interestingness = enum { interesting, unknown, boring };
|
||||
|
||||
// Roadmap:
|
||||
// - add thread pool
|
||||
@ -22,13 +43,44 @@ const Interestingness = enum { interesting, boring, unknown };
|
||||
// - integrate the build system?
|
||||
|
||||
pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
const file_path = args[2];
|
||||
const interestingness_argv_template = args[3..];
|
||||
var opt_checker_path: ?[]const u8 = null;
|
||||
var opt_root_source_file_path: ?[]const u8 = null;
|
||||
var argv: []const []const u8 = &.{};
|
||||
|
||||
{
|
||||
var i: usize = 2; // skip over "zig" and "reduce"
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
try stdout.writeAll(usage);
|
||||
return std.process.cleanExit();
|
||||
} else if (mem.eql(u8, arg, "--")) {
|
||||
argv = args[i + 1 ..];
|
||||
break;
|
||||
} else {
|
||||
fatal("unrecognized parameter: '{s}'", .{arg});
|
||||
}
|
||||
} else if (opt_checker_path == null) {
|
||||
opt_checker_path = arg;
|
||||
} else if (opt_root_source_file_path == null) {
|
||||
opt_root_source_file_path = arg;
|
||||
} else {
|
||||
fatal("unexpected extra parameter: '{s}'", .{arg});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const checker_path = opt_checker_path orelse
|
||||
fatal("missing interestingness checker argument; see -h for usage", .{});
|
||||
const root_source_file_path = opt_root_source_file_path orelse
|
||||
fatal("missing root source file path argument; see -h for usage", .{});
|
||||
|
||||
var interestingness_argv: std.ArrayListUnmanaged([]const u8) = .{};
|
||||
try interestingness_argv.ensureUnusedCapacity(arena, interestingness_argv_template.len + 1);
|
||||
interestingness_argv.appendSliceAssumeCapacity(interestingness_argv_template);
|
||||
interestingness_argv.appendAssumeCapacity(file_path);
|
||||
try interestingness_argv.ensureUnusedCapacity(arena, argv.len + 1);
|
||||
interestingness_argv.appendAssumeCapacity(checker_path);
|
||||
interestingness_argv.appendSliceAssumeCapacity(argv);
|
||||
|
||||
var rendered = std.ArrayList(u8).init(gpa);
|
||||
defer rendered.deinit();
|
||||
@ -38,7 +90,7 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
|
||||
const source_code = try std.fs.cwd().readFileAllocOptions(
|
||||
arena,
|
||||
file_path,
|
||||
root_source_file_path,
|
||||
std.math.maxInt(u32),
|
||||
null,
|
||||
1,
|
||||
@ -55,38 +107,34 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
var next_gut_fn_index: u32 = 0;
|
||||
var fixups: std.zig.Ast.Fixups = .{};
|
||||
|
||||
{
|
||||
// smoke test the interestingness check
|
||||
switch (try runCheck(arena, interestingness_argv.items)) {
|
||||
.interesting => {},
|
||||
.boring, .unknown => |t| {
|
||||
fatal("interestingness check returned {s} for unmodified input\n", .{
|
||||
@tagName(t),
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try fixups.gut_functions.put(arena, next_gut_fn_index, {});
|
||||
|
||||
rendered.clearRetainingCapacity();
|
||||
try tree.renderToArrayList(&rendered, fixups);
|
||||
|
||||
if (std.mem.eql(u8, rendered.items, prev_rendered.items)) {
|
||||
if (mem.eql(u8, rendered.items, prev_rendered.items)) {
|
||||
std.debug.print("no remaining transformations\n", .{});
|
||||
break;
|
||||
}
|
||||
prev_rendered.clearRetainingCapacity();
|
||||
try prev_rendered.appendSlice(rendered.items);
|
||||
|
||||
try std.fs.cwd().writeFile(file_path, rendered.items);
|
||||
try std.fs.cwd().writeFile(root_source_file_path, rendered.items);
|
||||
|
||||
const result = try std.process.Child.run(.{
|
||||
.allocator = arena,
|
||||
.argv = interestingness_argv.items,
|
||||
});
|
||||
if (result.stderr.len != 0)
|
||||
std.debug.print("{s}", .{result.stderr});
|
||||
const interestingness: Interestingness = switch (result.term) {
|
||||
.Exited => |code| switch (code) {
|
||||
0 => .interesting,
|
||||
1 => .unknown,
|
||||
else => .boring,
|
||||
},
|
||||
else => b: {
|
||||
std.debug.print("interestingness check aborted unexpectedly\n", .{});
|
||||
break :b .boring;
|
||||
},
|
||||
};
|
||||
const interestingness = try runCheck(arena, interestingness_argv.items);
|
||||
std.debug.print("{s}\n", .{@tagName(interestingness)});
|
||||
switch (interestingness) {
|
||||
.interesting => {
|
||||
@ -104,3 +152,27 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
}
|
||||
return std.process.cleanExit();
|
||||
}
|
||||
|
||||
fn termToInteresting(term: std.process.Child.Term) Interestingness {
|
||||
return switch (term) {
|
||||
.Exited => |code| switch (code) {
|
||||
0 => .interesting,
|
||||
1 => .unknown,
|
||||
else => .boring,
|
||||
},
|
||||
else => b: {
|
||||
std.debug.print("interestingness check aborted unexpectedly\n", .{});
|
||||
break :b .boring;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn runCheck(arena: std.mem.Allocator, argv: []const []const u8) !Interestingness {
|
||||
const result = try std.process.Child.run(.{
|
||||
.allocator = arena,
|
||||
.argv = argv,
|
||||
});
|
||||
if (result.stderr.len != 0)
|
||||
std.debug.print("{s}", .{result.stderr});
|
||||
return termToInteresting(result.term);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user