| ... | ... | @@ -3,20 +3,38 @@ const Allocator = std.mem.Allocator; |
| 3 | 3 | const assert = std.debug.assert; |
| 4 | 4 | |
| 5 | 5 | const usage = |
| 6 | | \\zig reduce [source_file] [transformation] |
| 6 | \\zig reduce [source_file] [interestingness] |
| 7 | 7 | \\ |
| 8 | 8 | ; |
| 9 | 9 | |
| 10 | const Interestingness = enum { interesting, boring, unknown }; |
| 11 | |
| 10 | 12 | // Roadmap: |
| 11 | | // - add the main loop that checks for interestingness |
| 12 | | // - add transformations |
| 13 | 13 | // - add thread pool |
| 14 | 14 | // - add support for `@import` detection and other files |
| 15 | // - more fancy transformations |
| 15 | 16 | // - 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? |
| 16 | 23 | |
| 17 | 24 | pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 18 | 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(); |
| 20 | 38 | |
| 21 | 39 | const source_code = try std.fs.cwd().readFileAllocOptions( |
| 22 | 40 | arena, |
| ... | ... | @@ -33,19 +51,56 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 33 | 51 | if (tree.errors.len != 0) { |
| 34 | 52 | @panic("syntax errors occurred"); |
| 35 | 53 | } |
| 36 | | var rendered = std.ArrayList(u8).init(gpa); |
| 37 | | defer rendered.deinit(); |
| 38 | | rendered.clearRetainingCapacity(); |
| 39 | 54 | |
| 40 | | var gut_functions: std.AutoHashMapUnmanaged(u32, void) = .{}; |
| 41 | | try gut_functions.put(arena, transformation_index, {}); |
| 55 | var next_gut_fn_index: u32 = 0; |
| 56 | var fixups: std.zig.Ast.Fixups = .{}; |
| 57 | |
| 58 | while (true) { |
| 59 | try fixups.gut_functions.put(arena, next_gut_fn_index, {}); |
| 42 | 60 | |
| 43 | | try tree.renderToArrayList(&rendered, .{ |
| 44 | | .gut_functions = gut_functions, |
| 45 | | }); |
| 61 | rendered.clearRetainingCapacity(); |
| 62 | try tree.renderToArrayList(&rendered, fixups); |
| 46 | 63 | |
| 47 | | const stdout = std.io.getStdOut(); |
| 48 | | try stdout.writeAll(rendered.items); |
| 64 | if (std.mem.eql(u8, rendered.items, prev_rendered.items)) { |
| 65 | std.debug.print("no remaining transformations\n", .{}); |
| 66 | break; |
| 67 | } |
| 68 | prev_rendered.clearRetainingCapacity(); |
| 69 | try prev_rendered.appendSlice(rendered.items); |
| 49 | 70 | |
| 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 | 105 | return std.process.cleanExit(); |
| 51 | 106 | } |