authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-02 18:23:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-03 20:05:32-07:00
logf90ba235d04165e654af0787e1e381159cbc5202
tree2d5777ffc398377a6cae8976b65ebd8f8ac4de01
parent73b96ac114c74a2167fdc0ae0332a5087eab5c74

zig reduce proof of concept


1 files changed, 69 insertions(+), 14 deletions(-)

src/reduce.zig+69-14
...@@ -3,20 +3,38 @@ const Allocator = std.mem.Allocator;...@@ -3,20 +3,38 @@ const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;3const assert = std.debug.assert;
44
5const usage =5const usage =
6 \\zig reduce [source_file] [transformation]6 \\zig reduce [source_file] [interestingness]
7 \\7 \\
8;8;
99
10const Interestingness = enum { interesting, boring, unknown };
11
10// Roadmap:12// Roadmap:
11// - add the main loop that checks for interestingness
12// - add transformations
13// - add thread pool13// - add thread pool
14// - add support for `@import` detection and other files14// - add support for `@import` detection and other files
15// - more fancy transformations
15// - reduce flags sent to the compiler16// - reduce flags sent to the compiler
17// - @import inlining
18// - deleting unused functions and other globals
19// - removing statements or blocks of code
20// - replacing operands of `and` and `or` with `true` and `false`
21// - replacing if conditions with `true` and `false`
22// - integrate the build system?
1623
17pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {24pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
18 const file_path = args[2];25 const file_path = args[2];
19 const transformation_index = try std.fmt.parseInt(u32, args[3], 0);26 const interestingness_argv_template = args[3..];
27
28 var interestingness_argv: std.ArrayListUnmanaged([]const u8) = .{};
29 try interestingness_argv.ensureUnusedCapacity(arena, interestingness_argv_template.len + 1);
30 interestingness_argv.appendSliceAssumeCapacity(interestingness_argv_template);
31 interestingness_argv.appendAssumeCapacity(file_path);
32
33 var rendered = std.ArrayList(u8).init(gpa);
34 defer rendered.deinit();
35
36 var prev_rendered = std.ArrayList(u8).init(gpa);
37 defer prev_rendered.deinit();
2038
21 const source_code = try std.fs.cwd().readFileAllocOptions(39 const source_code = try std.fs.cwd().readFileAllocOptions(
22 arena,40 arena,
...@@ -33,19 +51,56 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -33,19 +51,56 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
33 if (tree.errors.len != 0) {51 if (tree.errors.len != 0) {
34 @panic("syntax errors occurred");52 @panic("syntax errors occurred");
35 }53 }
36 var rendered = std.ArrayList(u8).init(gpa);
37 defer rendered.deinit();
38 rendered.clearRetainingCapacity();
3954
40 var gut_functions: std.AutoHashMapUnmanaged(u32, void) = .{};55 var next_gut_fn_index: u32 = 0;
41 try gut_functions.put(arena, transformation_index, {});56 var fixups: std.zig.Ast.Fixups = .{};
57
58 while (true) {
59 try fixups.gut_functions.put(arena, next_gut_fn_index, {});
4260
43 try tree.renderToArrayList(&rendered, .{61 rendered.clearRetainingCapacity();
44 .gut_functions = gut_functions,62 try tree.renderToArrayList(&rendered, fixups);
45 });
4663
47 const stdout = std.io.getStdOut();64 if (std.mem.eql(u8, rendered.items, prev_rendered.items)) {
48 try stdout.writeAll(rendered.items);65 std.debug.print("no remaining transformations\n", .{});
66 break;
67 }
68 prev_rendered.clearRetainingCapacity();
69 try prev_rendered.appendSlice(rendered.items);
4970
71 try std.fs.cwd().writeFile(file_path, rendered.items);
72
73 const result = try std.process.Child.run(.{
74 .allocator = arena,
75 .argv = interestingness_argv.items,
76 });
77 if (result.stderr.len != 0)
78 std.debug.print("{s}", .{result.stderr});
79 const interestingness: Interestingness = switch (result.term) {
80 .Exited => |code| switch (code) {
81 0 => .interesting,
82 1 => .unknown,
83 else => .boring,
84 },
85 else => b: {
86 std.debug.print("interestingness check aborted unexpectedly\n", .{});
87 break :b .boring;
88 },
89 };
90 std.debug.print("{s}\n", .{@tagName(interestingness)});
91 switch (interestingness) {
92 .interesting => {
93 next_gut_fn_index += 1;
94 },
95 .unknown, .boring => {
96 // revert the change and try the next transformation
97 assert(fixups.gut_functions.remove(next_gut_fn_index));
98 next_gut_fn_index += 1;
99
100 rendered.clearRetainingCapacity();
101 try tree.renderToArrayList(&rendered, fixups);
102 },
103 }
104 }
50 return std.process.cleanExit();105 return std.process.cleanExit();
51}106}