diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-04-26 20:41:37 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-04-26 20:46:28 -0400 |
| commit | 2d6520d5d4cd912cdd20db6cfa155e871efc6f59 (patch) | |
| tree | 583e47f4af61d3950b34333d48e738733b5e107a /std | |
| parent | ac3946620cebfc706255a86103a14c6cb08cff97 (diff) | |
| download | zig-2d6520d5d4cd912cdd20db6cfa155e871efc6f59.tar.gz zig-2d6520d5d4cd912cdd20db6cfa155e871efc6f59.zip | |
zig fmt is built directly into stage1 rather than child process
Previously, `zig fmt` on the stage1 compiler (which is what we currently
ship) would perform what equates to `zig run std/special/fmt_runner.zig`
Now, `zig fmt` is implemented with the hybrid zig/C++ strategy outlined
by #1964.
This means Zig no longer has to ship some of the stage2 .zig files, and
there is no longer a delay when running `zig fmt` for the first time.
Diffstat (limited to 'std')
| -rw-r--r-- | std/special/fmt_runner.zig | 265 |
1 files changed, 0 insertions, 265 deletions
diff --git a/std/special/fmt_runner.zig b/std/special/fmt_runner.zig deleted file mode 100644 index e63de4d014..0000000000 --- a/std/special/fmt_runner.zig +++ /dev/null @@ -1,265 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -const os = std.os; -const io = std.io; -const mem = std.mem; -const Allocator = mem.Allocator; -const ArrayList = std.ArrayList; -const Buffer = std.Buffer; -const ast = std.zig.ast; - -const arg = @import("fmt/arg.zig"); -const self_hosted_main = @import("fmt/main.zig"); -const Args = arg.Args; -const Flag = arg.Flag; -const errmsg = @import("fmt/errmsg.zig"); - -var stderr_file: os.File = undefined; -var stderr: *io.OutStream(os.File.WriteError) = undefined; -var stdout: *io.OutStream(os.File.WriteError) = undefined; - -// This brings `zig fmt` to stage 1. -pub fn main() !void { - // Here we use an ArenaAllocator backed by a DirectAllocator because `zig fmt` is a short-lived, - // one shot program. We don't need to waste time freeing memory and finding places to squish - // bytes into. So we free everything all at once at the very end. - var direct_allocator = std.heap.DirectAllocator.init(); - var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); - const allocator = &arena.allocator; - - var stdout_file = try std.io.getStdOut(); - var stdout_out_stream = stdout_file.outStream(); - stdout = &stdout_out_stream.stream; - - stderr_file = try std.io.getStdErr(); - var stderr_out_stream = stderr_file.outStream(); - stderr = &stderr_out_stream.stream; - const args = try std.os.argsAlloc(allocator); - - var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[1..]); - defer flags.deinit(); - - if (flags.present("help")) { - try stdout.write(self_hosted_main.usage_fmt); - os.exit(0); - } - - const color = blk: { - if (flags.single("color")) |color_flag| { - if (mem.eql(u8, color_flag, "auto")) { - break :blk errmsg.Color.Auto; - } else if (mem.eql(u8, color_flag, "on")) { - break :blk errmsg.Color.On; - } else if (mem.eql(u8, color_flag, "off")) { - break :blk errmsg.Color.Off; - } else unreachable; - } else { - break :blk errmsg.Color.Auto; - } - }; - - if (flags.present("stdin")) { - if (flags.positionals.len != 0) { - try stderr.write("cannot use --stdin with positional arguments\n"); - os.exit(1); - } - - var stdin_file = try io.getStdIn(); - var stdin = stdin_file.inStream(); - - const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size); - defer allocator.free(source_code); - - const tree = std.zig.parse(allocator, source_code) catch |err| { - try stderr.print("error parsing stdin: {}\n", err); - os.exit(1); - }; - defer tree.deinit(); - - var error_it = tree.errors.iterator(0); - while (error_it.next()) |parse_error| { - try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color); - } - if (tree.errors.len != 0) { - os.exit(1); - } - if (flags.present("check")) { - const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree); - const code = if (anything_changed) u8(1) else u8(0); - os.exit(code); - } - - _ = try std.zig.render(allocator, stdout, tree); - return; - } - - if (flags.positionals.len == 0) { - try stderr.write("expected at least one source file argument\n"); - os.exit(1); - } - - var fmt = Fmt{ - .seen = Fmt.SeenMap.init(allocator), - .any_error = false, - .color = color, - .allocator = allocator, - }; - - const check_mode = flags.present("check"); - - for (flags.positionals.toSliceConst()) |file_path| { - try fmtPath(&fmt, file_path, check_mode); - } - if (fmt.any_error) { - os.exit(1); - } -} - -const FmtError = error{ - SystemResources, - OperationAborted, - IoPending, - BrokenPipe, - Unexpected, - WouldBlock, - FileClosed, - DestinationAddressRequired, - DiskQuota, - FileTooBig, - InputOutput, - NoSpaceLeft, - AccessDenied, - OutOfMemory, - RenameAcrossMountPoints, - ReadOnlyFileSystem, - LinkQuotaExceeded, - FileBusy, -} || os.File.OpenError; - -fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { - const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); - defer fmt.allocator.free(file_path); - - if (try fmt.seen.put(file_path, {})) |_| return; - - const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { - error.IsDir, error.AccessDenied => { - // TODO make event based (and dir.next()) - var dir = try std.os.Dir.open(fmt.allocator, file_path); - defer dir.close(); - - while (try dir.next()) |entry| { - if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) { - const full_path = try os.path.join(fmt.allocator, [][]const u8{ file_path, entry.name }); - try fmtPath(fmt, full_path, check_mode); - } - } - return; - }, - else => { - // TODO lock stderr printing - try stderr.print("unable to open '{}': {}\n", file_path, err); - fmt.any_error = true; - return; - }, - }; - defer fmt.allocator.free(source_code); - - const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { - try stderr.print("error parsing file '{}': {}\n", file_path, err); - fmt.any_error = true; - return; - }; - defer tree.deinit(); - - var error_it = tree.errors.iterator(0); - while (error_it.next()) |parse_error| { - try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color); - } - if (tree.errors.len != 0) { - fmt.any_error = true; - return; - } - - if (check_mode) { - const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree); - if (anything_changed) { - try stderr.print("{}\n", file_path); - fmt.any_error = true; - } - } else { - // TODO make this evented - const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); - defer baf.destroy(); - - const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); - if (anything_changed) { - try stderr.print("{}\n", file_path); - try baf.finish(); - } - } -} - -const Fmt = struct { - seen: SeenMap, - any_error: bool, - color: errmsg.Color, - allocator: *mem.Allocator, - - const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); -}; - -fn printErrMsgToFile( - allocator: *mem.Allocator, - parse_error: *const ast.Error, - tree: *ast.Tree, - path: []const u8, - file: os.File, - color: errmsg.Color, -) !void { - const color_on = switch (color) { - errmsg.Color.Auto => file.isTty(), - errmsg.Color.On => true, - errmsg.Color.Off => false, - }; - const lok_token = parse_error.loc(); - const span = errmsg.Span{ - .first = lok_token, - .last = lok_token, - }; - - const first_token = tree.tokens.at(span.first); - const last_token = tree.tokens.at(span.last); - const start_loc = tree.tokenLocationPtr(0, first_token); - const end_loc = tree.tokenLocationPtr(first_token.end, last_token); - - var text_buf = try std.Buffer.initSize(allocator, 0); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree.tokens, out_stream); - const text = text_buf.toOwnedSlice(); - - const stream = &file.outStream().stream; - if (!color_on) { - try stream.print( - "{}:{}:{}: error: {}\n", - path, - start_loc.line + 1, - start_loc.column + 1, - text, - ); - return; - } - - try stream.print( - "{}:{}:{}: error: {}\n{}\n", - path, - start_loc.line + 1, - start_loc.column + 1, - text, - tree.source[start_loc.line_start..start_loc.line_end], - ); - try stream.writeByteNTimes(' ', start_loc.column); - try stream.writeByteNTimes('~', last_token.end - first_token.start); - try stream.write("\n"); -} |
