authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-16 00:42:56-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-16 00:53:32-05:00
logba56f365c813440b79c1710c6a8b0fd591883e13
tree2b0594a07e88fbb401c10021cff11f3f18601229
parent77a4e7b37468ee7fb5dd3193972050808732f66c
signature Commit is signed but in an unrecognized format.

bring zig fmt to stage1


4 files changed, 305 insertions(+), 7 deletions(-)

CMakeLists.txt+5
...@@ -652,6 +652,7 @@ set(ZIG_STD_FILES...@@ -652,6 +652,7 @@ set(ZIG_STD_FILES
652 "special/compiler_rt/udivmodti4.zig"652 "special/compiler_rt/udivmodti4.zig"
653 "special/compiler_rt/udivti3.zig"653 "special/compiler_rt/udivti3.zig"
654 "special/compiler_rt/umodti3.zig"654 "special/compiler_rt/umodti3.zig"
655 "special/fmt_runner.zig"
655 "special/init-exe/build.zig"656 "special/init-exe/build.zig"
656 "special/init-exe/src/main.zig"657 "special/init-exe/src/main.zig"
657 "special/init-lib/build.zig"658 "special/init-lib/build.zig"
...@@ -905,3 +906,7 @@ foreach(file ${ZIG_STD_FILES})...@@ -905,3 +906,7 @@ foreach(file ${ZIG_STD_FILES})
905 get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY)906 get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY)
906 install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")907 install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")
907endforeach()908endforeach()
909
910install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
911install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
912install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
src-self-hosted/main.zig+3-3
...@@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;...@@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;
24var stderr: *io.OutStream(os.File.WriteError) = undefined;24var stderr: *io.OutStream(os.File.WriteError) = undefined;
25var stdout: *io.OutStream(os.File.WriteError) = undefined;25var stdout: *io.OutStream(os.File.WriteError) = undefined;
2626
27const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB27pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
2828
29const usage =29const usage =
30 \\usage: zig [command] [options]30 \\usage: zig [command] [options]
...@@ -510,7 +510,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {...@@ -510,7 +510,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
510 return buildOutputType(allocator, args, Compilation.Kind.Obj);510 return buildOutputType(allocator, args, Compilation.Kind.Obj);
511}511}
512512
513const usage_fmt =513pub const usage_fmt =
514 \\usage: zig fmt [file]...514 \\usage: zig fmt [file]...
515 \\515 \\
516 \\ Formats the input files and modifies them in-place.516 \\ Formats the input files and modifies them in-place.
...@@ -527,7 +527,7 @@ const usage_fmt =...@@ -527,7 +527,7 @@ const usage_fmt =
527 \\527 \\
528;528;
529529
530const args_fmt_spec = []Flag{530pub const args_fmt_spec = []Flag{
531 Flag.Bool("--help"),531 Flag.Bool("--help"),
532 Flag.Bool("--check"),532 Flag.Bool("--check"),
533 Flag.Option("--color", []const []const u8{533 Flag.Option("--color", []const []const u8{
src/main.cpp+32-4
...@@ -21,8 +21,8 @@ static int print_error_usage(const char *arg0) {...@@ -21,8 +21,8 @@ static int print_error_usage(const char *arg0) {
21 return EXIT_FAILURE;21 return EXIT_FAILURE;
22}22}
2323
24static int print_full_usage(const char *arg0) {24static int print_full_usage(const char *arg0, FILE *file, int return_code) {
25 fprintf(stdout,25 fprintf(file,
26 "Usage: %s [command] [options]\n"26 "Usage: %s [command] [options]\n"
27 "\n"27 "\n"
28 "Commands:\n"28 "Commands:\n"
...@@ -31,6 +31,7 @@ static int print_full_usage(const char *arg0) {...@@ -31,6 +31,7 @@ static int print_full_usage(const char *arg0) {
31 " build-lib [source] create library from source or object files\n"31 " build-lib [source] create library from source or object files\n"
32 " build-obj [source] create object from source or assembly\n"32 " build-obj [source] create object from source or assembly\n"
33 " builtin show the source code of that @import(\"builtin\")\n"33 " builtin show the source code of that @import(\"builtin\")\n"
34 " fmt parse files and render in canonical zig format\n"
34 " help show this usage information\n"35 " help show this usage information\n"
35 " id print the base64-encoded compiler id\n"36 " id print the base64-encoded compiler id\n"
36 " init-exe initialize a `zig build` application in the cwd\n"37 " init-exe initialize a `zig build` application in the cwd\n"
...@@ -106,7 +107,7 @@ static int print_full_usage(const char *arg0) {...@@ -106,7 +107,7 @@ static int print_full_usage(const char *arg0) {
106 " --test-cmd [arg] specify test execution command one arg at a time\n"107 " --test-cmd [arg] specify test execution command one arg at a time\n"
107 " --test-cmd-bin appends test binary path to test cmd args\n"108 " --test-cmd-bin appends test binary path to test cmd args\n"
108 , arg0);109 , arg0);
109 return EXIT_SUCCESS;110 return return_code;
110}111}
111112
112static const char *ZIG_ZEN = "\n"113static const char *ZIG_ZEN = "\n"
...@@ -515,6 +516,31 @@ int main(int argc, char **argv) {...@@ -515,6 +516,31 @@ int main(int argc, char **argv) {
515 fprintf(stderr, "\n");516 fprintf(stderr, "\n");
516 }517 }
517 return (term.how == TerminationIdClean) ? term.code : -1;518 return (term.how == TerminationIdClean) ? term.code : -1;
519 } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
520 init_all_targets();
521 Buf *fmt_runner_path = buf_alloc();
522 os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
523 CodeGen *g = codegen_create(fmt_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
524 nullptr);
525 g->is_single_threaded = true;
526 codegen_set_out_name(g, buf_create_from_str("fmt"));
527 g->enable_cache = true;
528
529 codegen_build_and_link(g);
530
531 ZigList<const char*> args = {0};
532 for (int i = 2; i < argc; i += 1) {
533 args.append(argv[i]);
534 }
535 args.append(nullptr);
536 const char *exec_path = buf_ptr(&g->output_file_path);
537
538 os_execv(exec_path, args.items);
539
540 args.pop();
541 Termination term;
542 os_spawn_process(exec_path, args, &term);
543 return term.code;
518 }544 }
519545
520 for (int i = 1; i < argc; i += 1) {546 for (int i = 1; i < argc; i += 1) {
...@@ -527,6 +553,8 @@ int main(int argc, char **argv) {...@@ -527,6 +553,8 @@ int main(int argc, char **argv) {
527 build_mode = BuildModeSafeRelease;553 build_mode = BuildModeSafeRelease;
528 } else if (strcmp(arg, "--release-small") == 0) {554 } else if (strcmp(arg, "--release-small") == 0) {
529 build_mode = BuildModeSmallRelease;555 build_mode = BuildModeSmallRelease;
556 } else if (strcmp(arg, "--help") == 0) {
557 return print_full_usage(arg0, stderr, EXIT_FAILURE);
530 } else if (strcmp(arg, "--strip") == 0) {558 } else if (strcmp(arg, "--strip") == 0) {
531 strip = true;559 strip = true;
532 } else if (strcmp(arg, "--static") == 0) {560 } else if (strcmp(arg, "--static") == 0) {
...@@ -1080,7 +1108,7 @@ int main(int argc, char **argv) {...@@ -1080,7 +1108,7 @@ int main(int argc, char **argv) {
1080 }1108 }
1081 }1109 }
1082 case CmdHelp:1110 case CmdHelp:
1083 return print_full_usage(arg0);1111 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
1084 case CmdVersion:1112 case CmdVersion:
1085 printf("%s\n", ZIG_VERSION_STRING);1113 printf("%s\n", ZIG_VERSION_STRING);
1086 return EXIT_SUCCESS;1114 return EXIT_SUCCESS;
std/special/fmt_runner.zig created+265
...@@ -0,0 +1,265 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4const os = std.os;
5const io = std.io;
6const mem = std.mem;
7const Allocator = mem.Allocator;
8const ArrayList = std.ArrayList;
9const Buffer = std.Buffer;
10const ast = std.zig.ast;
11
12const arg = @import("fmt/arg.zig");
13const self_hosted_main = @import("fmt/main.zig");
14const Args = arg.Args;
15const Flag = arg.Flag;
16const errmsg = @import("fmt/errmsg.zig");
17
18var stderr_file: os.File = undefined;
19var stderr: *io.OutStream(os.File.WriteError) = undefined;
20var stdout: *io.OutStream(os.File.WriteError) = undefined;
21
22// This brings `zig fmt` to stage 1.
23pub fn main() !void {
24 // Here we use an ArenaAllocator backed by a DirectAllocator because `zig fmt` is a short-lived,
25 // one shot program. We don't need to waste time freeing memory and finding places to squish
26 // bytes into. So we free everything all at once at the very end.
27 var direct_allocator = std.heap.DirectAllocator.init();
28 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
29 const allocator = &arena.allocator;
30
31 var stdout_file = try std.io.getStdOut();
32 var stdout_out_stream = stdout_file.outStream();
33 stdout = &stdout_out_stream.stream;
34
35 stderr_file = try std.io.getStdErr();
36 var stderr_out_stream = stderr_file.outStream();
37 stderr = &stderr_out_stream.stream;
38 const args = try std.os.argsAlloc(allocator);
39
40 var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args);
41 defer flags.deinit();
42
43 if (flags.present("help")) {
44 try stdout.write(self_hosted_main.usage_fmt);
45 os.exit(0);
46 }
47
48 const color = blk: {
49 if (flags.single("color")) |color_flag| {
50 if (mem.eql(u8, color_flag, "auto")) {
51 break :blk errmsg.Color.Auto;
52 } else if (mem.eql(u8, color_flag, "on")) {
53 break :blk errmsg.Color.On;
54 } else if (mem.eql(u8, color_flag, "off")) {
55 break :blk errmsg.Color.Off;
56 } else unreachable;
57 } else {
58 break :blk errmsg.Color.Auto;
59 }
60 };
61
62 if (flags.present("stdin")) {
63 if (flags.positionals.len != 0) {
64 try stderr.write("cannot use --stdin with positional arguments\n");
65 os.exit(1);
66 }
67
68 var stdin_file = try io.getStdIn();
69 var stdin = stdin_file.inStream();
70
71 const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
72 defer allocator.free(source_code);
73
74 var tree = std.zig.parse(allocator, source_code) catch |err| {
75 try stderr.print("error parsing stdin: {}\n", err);
76 os.exit(1);
77 };
78 defer tree.deinit();
79
80 var error_it = tree.errors.iterator(0);
81 while (error_it.next()) |parse_error| {
82 try printErrMsgToFile(allocator, parse_error, &tree, "<stdin>", stderr_file, color);
83 }
84 if (tree.errors.len != 0) {
85 os.exit(1);
86 }
87 if (flags.present("check")) {
88 const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree);
89 const code = if (anything_changed) u8(1) else u8(0);
90 os.exit(code);
91 }
92
93 _ = try std.zig.render(allocator, stdout, &tree);
94 return;
95 }
96
97 if (flags.positionals.len == 0) {
98 try stderr.write("expected at least one source file argument\n");
99 os.exit(1);
100 }
101
102 if (flags.positionals.len == 0) {
103 try stderr.write("expected at least one source file argument\n");
104 os.exit(1);
105 }
106
107 var fmt = Fmt{
108 .seen = Fmt.SeenMap.init(allocator),
109 .any_error = false,
110 .color = color,
111 .allocator = allocator,
112 };
113
114 const check_mode = flags.present("check");
115
116 for (flags.positionals.toSliceConst()) |file_path| {
117 try fmtPath(&fmt, file_path, check_mode);
118 }
119 if (fmt.any_error) {
120 os.exit(1);
121 }
122}
123
124const FmtError = error{
125 SystemResources,
126 OperationAborted,
127 IoPending,
128 BrokenPipe,
129 Unexpected,
130 WouldBlock,
131 FileClosed,
132 DestinationAddressRequired,
133 DiskQuota,
134 FileTooBig,
135 InputOutput,
136 NoSpaceLeft,
137 AccessDenied,
138 OutOfMemory,
139 RenameAcrossMountPoints,
140 ReadOnlyFileSystem,
141 LinkQuotaExceeded,
142 FileBusy,
143} || os.File.OpenError;
144
145fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
146 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
147 defer fmt.allocator.free(file_path);
148
149 if (try fmt.seen.put(file_path, {})) |_| return;
150
151 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
152 error.IsDir, error.AccessDenied => {
153 // TODO make event based (and dir.next())
154 var dir = try std.os.Dir.open(fmt.allocator, file_path);
155 defer dir.close();
156
157 while (try dir.next()) |entry| {
158 if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
159 const full_path = try os.path.join(fmt.allocator, [][]const u8{ file_path, entry.name });
160 try fmtPath(fmt, full_path, check_mode);
161 }
162 }
163 return;
164 },
165 else => {
166 // TODO lock stderr printing
167 try stderr.print("unable to open '{}': {}\n", file_path, err);
168 fmt.any_error = true;
169 return;
170 },
171 };
172 defer fmt.allocator.free(source_code);
173
174 var tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
175 try stderr.print("error parsing file '{}': {}\n", file_path, err);
176 fmt.any_error = true;
177 return;
178 };
179 defer tree.deinit();
180
181 var error_it = tree.errors.iterator(0);
182 while (error_it.next()) |parse_error| {
183 try printErrMsgToFile(fmt.allocator, parse_error, &tree, file_path, stderr_file, fmt.color);
184 }
185 if (tree.errors.len != 0) {
186 fmt.any_error = true;
187 return;
188 }
189
190 if (check_mode) {
191 const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, &tree);
192 if (anything_changed) {
193 try stderr.print("{}\n", file_path);
194 fmt.any_error = true;
195 }
196 } else {
197 // TODO make this evented
198 const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path);
199 defer baf.destroy();
200
201 const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), &tree);
202 if (anything_changed) {
203 try stderr.print("{}\n", file_path);
204 try baf.finish();
205 }
206 }
207}
208
209const Fmt = struct {
210 seen: SeenMap,
211 any_error: bool,
212 color: errmsg.Color,
213 allocator: *mem.Allocator,
214
215 const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
216};
217
218fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, tree: *ast.Tree,
219 path: []const u8, file: os.File, color: errmsg.Color,) !void
220{
221 const color_on = switch (color) {
222 errmsg.Color.Auto => file.isTty(),
223 errmsg.Color.On => true,
224 errmsg.Color.Off => false,
225 };
226 const lok_token = parse_error.loc();
227 const span = errmsg.Span{
228 .first = lok_token,
229 .last = lok_token,
230 };
231
232 const first_token = tree.tokens.at(span.first);
233 const last_token = tree.tokens.at(span.last);
234 const start_loc = tree.tokenLocationPtr(0, first_token);
235 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
236
237 var text_buf = try std.Buffer.initSize(allocator, 0);
238 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
239 try parse_error.render(&tree.tokens, out_stream);
240 const text = text_buf.toOwnedSlice();
241
242 const stream = &file.outStream().stream;
243 if (!color_on) {
244 try stream.print(
245 "{}:{}:{}: error: {}\n",
246 path,
247 start_loc.line + 1,
248 start_loc.column + 1,
249 text,
250 );
251 return;
252 }
253
254 try stream.print(
255 "{}:{}:{}: error: {}\n{}\n",
256 path,
257 start_loc.line + 1,
258 start_loc.column + 1,
259 text,
260 tree.source[start_loc.line_start..start_loc.line_end],
261 );
262 try stream.writeByteNTimes(' ', start_loc.column);
263 try stream.writeByteNTimes('~', last_token.end - first_token.start);
264 try stream.write("\n");
265}