| ... | @@ -5,6 +5,8 @@ const assert = std.debug.assert; | ... | @@ -5,6 +5,8 @@ const assert = std.debug.assert; |
| 5 | const fatal = @import("./main.zig").fatal; | 5 | const fatal = @import("./main.zig").fatal; |
| 6 | const Ast = std.zig.Ast; | 6 | const Ast = std.zig.Ast; |
| 7 | const Walk = @import("reduce/Walk.zig"); | 7 | const Walk = @import("reduce/Walk.zig"); |
| | 8 | const AstGen = @import("AstGen.zig"); |
| | 9 | const Zir = @import("Zir.zig"); |
| 8 | | 10 | |
| 9 | const usage = | 11 | const usage = |
| 10 | \\zig reduce [options] ./checker root_source_file.zig [-- [argv]] | 12 | \\zig reduce [options] ./checker root_source_file.zig [-- [argv]] |
| ... | @@ -39,8 +41,6 @@ const Interestingness = enum { interesting, unknown, boring }; | ... | @@ -39,8 +41,6 @@ const Interestingness = enum { interesting, unknown, boring }; |
| 39 | // - add support for parsing the module flags | 41 | // - add support for parsing the module flags |
| 40 | // - more fancy transformations | 42 | // - more fancy transformations |
| 41 | // - @import inlining of modules | 43 | // - @import inlining of modules |
| 42 | // - @import inlining of files | | |
| 43 | // - deleting unused functions and other globals | | |
| 44 | // - removing statements or blocks of code | 44 | // - removing statements or blocks of code |
| 45 | // - replacing operands of `and` and `or` with `true` and `false` | 45 | // - replacing operands of `and` and `or` with `true` and `false` |
| 46 | // - replacing if conditions with `true` and `false` | 46 | // - replacing if conditions with `true` and `false` |
| ... | @@ -109,6 +109,9 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -109,6 +109,9 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 109 | var rendered = std.ArrayList(u8).init(gpa); | 109 | var rendered = std.ArrayList(u8).init(gpa); |
| 110 | defer rendered.deinit(); | 110 | defer rendered.deinit(); |
| 111 | | 111 | |
| | 112 | var astgen_input = std.ArrayList(u8).init(gpa); |
| | 113 | defer astgen_input.deinit(); |
| | 114 | |
| 112 | var tree = try parse(gpa, root_source_file_path); | 115 | var tree = try parse(gpa, root_source_file_path); |
| 113 | defer { | 116 | defer { |
| 114 | gpa.free(tree.source); | 117 | gpa.free(tree.source); |
| ... | @@ -129,6 +132,10 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -129,6 +132,10 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 129 | | 132 | |
| 130 | var fixups: Ast.Fixups = .{}; | 133 | var fixups: Ast.Fixups = .{}; |
| 131 | defer fixups.deinit(gpa); | 134 | defer fixups.deinit(gpa); |
| | 135 | |
| | 136 | var more_fixups: Ast.Fixups = .{}; |
| | 137 | defer more_fixups.deinit(gpa); |
| | 138 | |
| 132 | var rng = std.rand.DefaultPrng.init(seed); | 139 | var rng = std.rand.DefaultPrng.init(seed); |
| 133 | | 140 | |
| 134 | // 1. Walk the AST of the source file looking for independent | 141 | // 1. Walk the AST of the source file looking for independent |
| ... | @@ -171,8 +178,51 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -171,8 +178,51 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 171 | | 178 | |
| 172 | rendered.clearRetainingCapacity(); | 179 | rendered.clearRetainingCapacity(); |
| 173 | try tree.renderToArrayList(&rendered, fixups); | 180 | try tree.renderToArrayList(&rendered, fixups); |
| 174 | try std.fs.cwd().writeFile(root_source_file_path, rendered.items); | | |
| 175 | | 181 | |
| | 182 | // The transformations we applied may have resulted in unused locals, |
| | 183 | // in which case we would like to add the respective discards. |
| | 184 | { |
| | 185 | try astgen_input.resize(rendered.items.len); |
| | 186 | @memcpy(astgen_input.items, rendered.items); |
| | 187 | try astgen_input.append(0); |
| | 188 | const source_with_null = astgen_input.items[0 .. astgen_input.items.len - 1 :0]; |
| | 189 | var astgen_tree = try Ast.parse(gpa, source_with_null, .zig); |
| | 190 | defer astgen_tree.deinit(gpa); |
| | 191 | if (astgen_tree.errors.len != 0) { |
| | 192 | @panic("syntax errors occurred"); |
| | 193 | } |
| | 194 | var zir = try AstGen.generate(gpa, astgen_tree); |
| | 195 | defer zir.deinit(gpa); |
| | 196 | |
| | 197 | if (zir.hasCompileErrors()) { |
| | 198 | more_fixups.clearRetainingCapacity(); |
| | 199 | const payload_index = zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)]; |
| | 200 | assert(payload_index != 0); |
| | 201 | const header = zir.extraData(Zir.Inst.CompileErrors, payload_index); |
| | 202 | var extra_index = header.end; |
| | 203 | for (0..header.data.items_len) |_| { |
| | 204 | const item = zir.extraData(Zir.Inst.CompileErrors.Item, extra_index); |
| | 205 | extra_index = item.end; |
| | 206 | const msg = zir.nullTerminatedString(item.data.msg); |
| | 207 | if (mem.eql(u8, msg, "unused local constant") or |
| | 208 | mem.eql(u8, msg, "unused local variable") or |
| | 209 | mem.eql(u8, msg, "unused function parameter") or |
| | 210 | mem.eql(u8, msg, "unused capture")) |
| | 211 | { |
| | 212 | const ident_token = item.data.token; |
| | 213 | try more_fixups.unused_var_decls.put(gpa, ident_token, {}); |
| | 214 | } else { |
| | 215 | std.debug.print("found other ZIR error: '{s}'\n", .{msg}); |
| | 216 | } |
| | 217 | } |
| | 218 | if (more_fixups.count() != 0) { |
| | 219 | rendered.clearRetainingCapacity(); |
| | 220 | try astgen_tree.renderToArrayList(&rendered, more_fixups); |
| | 221 | } |
| | 222 | } |
| | 223 | } |
| | 224 | |
| | 225 | try std.fs.cwd().writeFile(root_source_file_path, rendered.items); |
| 176 | //std.debug.print("trying this code:\n{s}\n", .{rendered.items}); | 226 | //std.debug.print("trying this code:\n{s}\n", .{rendered.items}); |
| 177 | | 227 | |
| 178 | const interestingness = try runCheck(arena, interestingness_argv.items); | 228 | const interestingness = try runCheck(arena, interestingness_argv.items); |