diff options
| -rw-r--r-- | src-self-hosted/main.zig | 12 | ||||
| -rw-r--r-- | src-self-hosted/module.zig | 2 | ||||
| -rw-r--r-- | std/zig/parser_test.zig | 10 | ||||
| -rw-r--r-- | std/zig/render.zig | 54 |
4 files changed, 68 insertions, 10 deletions
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index f54bdbdaf0..02e5bbf921 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -719,6 +719,9 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void { }; defer tree.deinit(); + var old_digest: [256]u8 = undefined; + std.crypto.Sha256.hash(source_code, old_digest[0..]); + var error_it = tree.errors.iterator(0); while (error_it.next()) |parse_error| { const token = tree.tokens.at(parse_error.loc()); @@ -745,13 +748,14 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void { continue; } - try stderr.print("{}\n", file_path); - const baf = try io.BufferedAtomicFile.create(allocator, file_path); defer baf.destroy(); - try std.zig.render(allocator, baf.stream(), &tree); - try baf.finish(); + const anything_changed = try std.zig.render(allocator, baf.stream(), &tree); + if (anything_changed) { + try stderr.print("{}\n", file_path); + try baf.finish(); + } } } diff --git a/src-self-hosted/module.zig b/src-self-hosted/module.zig index 375e2e840b..848ce95309 100644 --- a/src-self-hosted/module.zig +++ b/src-self-hosted/module.zig @@ -255,7 +255,7 @@ pub const Module = struct { const out_stream = &stderr_file_out_stream.stream; warn("====fmt:====\n"); - try std.zig.render(self.allocator, out_stream, &tree); + _ = try std.zig.render(self.allocator, out_stream, &tree); warn("====ir:====\n"); warn("TODO\n\n"); diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 75ba9e61d7..eee6b12767 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1792,7 +1792,7 @@ const io = std.io; var fixed_buffer_mem: [100 * 1024]u8 = undefined; -fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 { +fn testParse(source: []const u8, allocator: &mem.Allocator, changes_expected: bool) ![]u8 { var stderr_file = try io.getStdErr(); var stderr = &io.FileOutStream.init(&stderr_file).stream; @@ -1829,16 +1829,18 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 { errdefer buffer.deinit(); var buffer_out_stream = io.BufferOutStream.init(&buffer); - try std.zig.render(allocator, &buffer_out_stream.stream, &tree); + const anything_changed = try std.zig.render(allocator, &buffer_out_stream.stream, &tree); + std.debug.assert(anything_changed == changes_expected); return buffer.toOwnedSlice(); } fn testTransform(source: []const u8, expected_source: []const u8) !void { + const changes_expected = source.ptr != expected_source.ptr; const needed_alloc_count = x: { // Try it once with unlimited memory, make sure it works var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize)); - const result_source = try testParse(source, &failing_allocator.allocator); + const result_source = try testParse(source, &failing_allocator.allocator, changes_expected); if (!mem.eql(u8, result_source, expected_source)) { warn("\n====== expected this output: =========\n"); warn("{}", expected_source); @@ -1855,7 +1857,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { while (fail_index < needed_alloc_count) : (fail_index += 1) { var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); - if (testParse(source, &failing_allocator.allocator)) |_| { + if (testParse(source, &failing_allocator.allocator, changes_expected)) |_| { return error.NondeterministicMemoryUsage; } else |err| switch (err) { error.OutOfMemory => { diff --git a/std/zig/render.zig b/std/zig/render.zig index e3bf5fe38e..657fcae8bb 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -12,9 +12,61 @@ pub const Error = error{ OutOfMemory, }; -pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(stream).Child.Error || Error)!void { +/// Returns whether anything changed +pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(stream).Child.Error || Error)!bool { comptime assert(@typeId(@typeOf(stream)) == builtin.TypeId.Pointer); + var anything_changed: bool = false; + + // make a passthrough stream that checks whether something changed + const MyStream = struct { + const MyStream = this; + const StreamError = @typeOf(stream).Child.Error; + const Stream = std.io.OutStream(StreamError); + + anything_changed_ptr: &bool, + child_stream: @typeOf(stream), + stream: Stream, + source_index: usize, + source: []const u8, + + fn write(iface_stream: &Stream, bytes: []const u8) StreamError!void { + const self = @fieldParentPtr(MyStream, "stream", iface_stream); + + if (!self.anything_changed_ptr.*) { + const end = self.source_index + bytes.len; + if (end > self.source.len) { + self.anything_changed_ptr.* = true; + } else { + const src_slice = self.source[self.source_index..end]; + self.source_index += bytes.len; + if (!mem.eql(u8, bytes, src_slice)) { + self.anything_changed_ptr.* = true; + } + } + } + + try self.child_stream.write(bytes); + } + }; + var my_stream = MyStream{ + .stream = MyStream.Stream{ .writeFn = MyStream.write }, + .child_stream = stream, + .anything_changed_ptr = &anything_changed, + .source_index = 0, + .source = tree.source, + }; + + try renderRoot(allocator, &my_stream.stream, tree); + + return anything_changed; +} + +fn renderRoot( + allocator: &mem.Allocator, + stream: var, + tree: &ast.Tree, +) (@typeOf(stream).Child.Error || Error)!void { // render all the line comments at the beginning of the file var tok_it = tree.tokens.iterator(0); while (tok_it.next()) |token| { |
