Commit 2d6520d5d4
Changed files (6)
src/main.cpp
@@ -588,37 +588,7 @@ int main(int argc, char **argv) {
}
return (term.how == TerminationIdClean) ? term.code : -1;
} else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
- init_all_targets();
- ZigTarget target;
- get_native_target(&target);
- Buf *zig_lib_dir = (override_lib_dir == nullptr) ? get_zig_lib_dir() : override_lib_dir;
- Buf *fmt_runner_path = buf_alloc();
- os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
- Buf *cache_dir_buf = buf_create_from_str(cache_dir ? cache_dir : default_zig_cache_name);
- CodeGen *g = codegen_create(main_pkg_path, fmt_runner_path, &target, OutTypeExe,
- BuildModeDebug, zig_lib_dir, nullptr, nullptr, cache_dir_buf);
- g->valgrind_support = valgrind_support;
- g->want_single_threaded = true;
- codegen_set_out_name(g, buf_create_from_str("fmt"));
- g->enable_cache = true;
-
- codegen_build_and_link(g);
-
- // TODO standardize os.cpp so that the args are supposed to have the exe
- ZigList<const char*> args_with_exe = {0};
- ZigList<const char*> args_without_exe = {0};
- const char *exec_path = buf_ptr(&g->output_file_path);
- args_with_exe.append(exec_path);
- for (int i = 2; i < argc; i += 1) {
- args_with_exe.append(argv[i]);
- args_without_exe.append(argv[i]);
- }
- args_with_exe.append(nullptr);
- os_execv(exec_path, args_with_exe.items);
-
- Termination term;
- os_spawn_process(exec_path, args_without_exe, &term);
- return term.code;
+ return stage2_fmt(argc, argv);
}
for (int i = 1; i < argc; i += 1) {
src/userland.cpp
@@ -37,3 +37,8 @@ void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) {
const char *msg = "stage0 called stage2_render_ast";
stage2_panic(msg, strlen(msg));
}
+
+int stage2_fmt(int argc, char **argv) {
+ const char *msg = "stage0 called stage2_fmt";
+ stage2_panic(msg, strlen(msg));
+}
src/userland.h
@@ -114,4 +114,7 @@ ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
// ABI warning
ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len);
+// ABI warning
+ZIG_EXTERN_C int stage2_fmt(int argc, char **argv);
+
#endif
src-self-hosted/stage1.zig
@@ -2,6 +2,7 @@
// The prototypes in src/userland.h must match these definitions.
const std = @import("std");
+const builtin = @import("builtin");
// ABI warning
export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
@@ -119,3 +120,277 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
};
return Error.None;
}
+
+// TODO: just use the actual self-hosted zig fmt. Until the coroutine rewrite, we use a blocking implementation.
+export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
+ if (std.debug.runtime_safety) {
+ fmtMain(argc, argv) catch unreachable;
+ } else {
+ fmtMain(argc, argv) catch |e| {
+ std.debug.warn("{}\n", @errorName(e));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
+ const allocator = std.heap.c_allocator;
+ var args_list = std.ArrayList([]const u8).init(allocator);
+ const argc_usize = @intCast(usize, argc);
+ var arg_i: usize = 0;
+ while (arg_i < argc_usize) : (arg_i += 1) {
+ try args_list.append(std.mem.toSliceConst(u8, argv[arg_i]));
+ }
+
+ 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 = args_list.toSliceConst();
+ var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[2..]);
+ 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 {
+ 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");
+}
+
+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 arg = @import("arg.zig");
+const self_hosted_main = @import("main.zig");
+const Args = arg.Args;
+const Flag = arg.Flag;
+const errmsg = @import("errmsg.zig");
+
+var stderr_file: os.File = undefined;
+var stderr: *io.OutStream(os.File.WriteError) = undefined;
+var stdout: *io.OutStream(os.File.WriteError) = undefined;
std/special/fmt_runner.zig
@@ -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");
-}
CMakeLists.txt
@@ -685,7 +685,6 @@ set(ZIG_STD_FILES
"special/compiler_rt/udivmodti4.zig"
"special/compiler_rt/udivti3.zig"
"special/compiler_rt/umodti3.zig"
- "special/fmt_runner.zig"
"special/init-exe/build.zig"
"special/init-exe/src/main.zig"
"special/init-lib/build.zig"
@@ -6744,7 +6743,3 @@ foreach(file ${ZIG_LIBCXX_FILES})
get_filename_component(file_dir "${LIBCXX_FILES_DEST}/${file}" DIRECTORY)
install(FILES "${CMAKE_SOURCE_DIR}/libcxx/${file}" DESTINATION "${file_dir}")
endforeach()
-
-install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
-install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
-install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")