authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 22:26:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 22:26:19-07:00
logd661f0f35ba5c5600c3547b52e6fbca34991702b
tree76d76dbd62943e749a73936631e62159784e2a02
parentb116063e02bf2bb1975f5ae862fcd25f8fbeda09

compiler: JIT zig fmt

See #19063

9 files changed, 778 insertions(+), 670 deletions(-)

lib/build_runner.zig+1-1
...@@ -13,7 +13,7 @@ const Step = std.Build.Step;...@@ -13,7 +13,7 @@ const Step = std.Build.Step;
13pub const dependencies = @import("@dependencies");13pub const dependencies = @import("@dependencies");
1414
15pub fn main() !void {15pub fn main() !void {
16 // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,16 // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
17 // one shot program. We don't need to waste time freeing memory and finding places to squish17 // one shot program. We don't need to waste time freeing memory and finding places to squish
18 // bytes into. So we free everything all at once at the very end.18 // bytes into. So we free everything all at once at the very end.
19 var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);19 var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
lib/std/zig.zig+106-4
...@@ -1,6 +1,3 @@...@@ -1,6 +1,3 @@
1/// Implementation of `zig fmt`.
2pub const fmt = @import("zig/fmt.zig");
3
4pub const ErrorBundle = @import("zig/ErrorBundle.zig");1pub const ErrorBundle = @import("zig/ErrorBundle.zig");
5pub const Server = @import("zig/Server.zig");2pub const Server = @import("zig/Server.zig");
6pub const Client = @import("zig/Client.zig");3pub const Client = @import("zig/Client.zig");
...@@ -30,6 +27,36 @@ pub const c_translation = @import("zig/c_translation.zig");...@@ -30,6 +27,36 @@ pub const c_translation = @import("zig/c_translation.zig");
30pub const SrcHasher = std.crypto.hash.Blake3;27pub const SrcHasher = std.crypto.hash.Blake3;
31pub const SrcHash = [16]u8;28pub const SrcHash = [16]u8;
3229
30pub const Color = enum {
31 /// Determine whether stderr is a terminal or not automatically.
32 auto,
33 /// Assume stderr is not a terminal.
34 off,
35 /// Assume stderr is a terminal.
36 on,
37
38 pub fn get_tty_conf(color: Color) std.io.tty.Config {
39 return switch (color) {
40 .auto => std.io.tty.detectConfig(std.io.getStdErr()),
41 .on => .escape_codes,
42 .off => .no_color,
43 };
44 }
45
46 pub fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
47 const ttyconf = get_tty_conf(color);
48 return .{
49 .ttyconf = ttyconf,
50 .include_source_line = ttyconf != .no_color,
51 .include_reference_trace = ttyconf != .no_color,
52 };
53 }
54};
55
56/// There are many assumptions in the entire codebase that Zig source files can
57/// be byte-indexed with a u32 integer.
58pub const max_src_size = std.math.maxInt(u32);
59
33pub fn hashSrc(src: []const u8) SrcHash {60pub fn hashSrc(src: []const u8) SrcHash {
34 var out: SrcHash = undefined;61 var out: SrcHash = undefined;
35 SrcHasher.hash(src, &out, .{});62 SrcHasher.hash(src, &out, .{});
...@@ -801,6 +828,78 @@ test isValidId {...@@ -801,6 +828,78 @@ test isValidId {
801 try std.testing.expect(isValidId("i386"));828 try std.testing.expect(isValidId("i386"));
802}829}
803830
831pub fn readSourceFileToEndAlloc(
832 allocator: Allocator,
833 input: std.fs.File,
834 size_hint: ?usize,
835) ![:0]u8 {
836 const source_code = input.readToEndAllocOptions(
837 allocator,
838 max_src_size,
839 size_hint,
840 @alignOf(u16),
841 0,
842 ) catch |err| switch (err) {
843 error.ConnectionResetByPeer => unreachable,
844 error.ConnectionTimedOut => unreachable,
845 error.NotOpenForReading => unreachable,
846 else => |e| return e,
847 };
848 errdefer allocator.free(source_code);
849
850 // Detect unsupported file types with their Byte Order Mark
851 const unsupported_boms = [_][]const u8{
852 "\xff\xfe\x00\x00", // UTF-32 little endian
853 "\xfe\xff\x00\x00", // UTF-32 big endian
854 "\xfe\xff", // UTF-16 big endian
855 };
856 for (unsupported_boms) |bom| {
857 if (std.mem.startsWith(u8, source_code, bom)) {
858 return error.UnsupportedEncoding;
859 }
860 }
861
862 // If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
863 if (std.mem.startsWith(u8, source_code, "\xff\xfe")) {
864 const source_code_utf16_le = std.mem.bytesAsSlice(u16, source_code);
865 const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
866 error.DanglingSurrogateHalf => error.UnsupportedEncoding,
867 error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
868 error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
869 else => |e| return e,
870 };
871
872 allocator.free(source_code);
873 return source_code_utf8;
874 }
875
876 return source_code;
877}
878
879pub fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
880 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
881 try wip_errors.init(gpa);
882 defer wip_errors.deinit();
883
884 try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
885
886 var error_bundle = try wip_errors.toOwnedBundle("");
887 defer error_bundle.deinit(gpa);
888 error_bundle.renderToStdErr(color.renderOptions());
889}
890
891pub fn putAstErrorsIntoBundle(
892 gpa: Allocator,
893 tree: Ast,
894 path: []const u8,
895 wip_errors: *std.zig.ErrorBundle.Wip,
896) Allocator.Error!void {
897 var zir = try AstGen.generate(gpa, tree);
898 defer zir.deinit(gpa);
899
900 try wip_errors.addZirErrorMessages(zir, tree, tree.source, path);
901}
902
804test {903test {
805 _ = Ast;904 _ = Ast;
806 _ = AstRlAnnotate;905 _ = AstRlAnnotate;
...@@ -808,9 +907,12 @@ test {...@@ -808,9 +907,12 @@ test {
808 _ = Client;907 _ = Client;
809 _ = ErrorBundle;908 _ = ErrorBundle;
810 _ = Server;909 _ = Server;
811 _ = fmt;
812 _ = number_literal;910 _ = number_literal;
813 _ = primitives;911 _ = primitives;
814 _ = string_literal;912 _ = string_literal;
815 _ = system;913 _ = system;
914
915 // This is not standard library API; it is the standalone executable
916 // implementation of `zig fmt`.
917 _ = @import("zig/fmt.zig");
816}918}
lib/std/zig/Ast.zig+41-1
...@@ -32,6 +32,12 @@ pub const Location = struct {...@@ -32,6 +32,12 @@ pub const Location = struct {
32 line_end: usize,32 line_end: usize,
33};33};
3434
35pub const Span = struct {
36 start: u32,
37 end: u32,
38 main: u32,
39};
40
35pub fn deinit(tree: *Ast, gpa: Allocator) void {41pub fn deinit(tree: *Ast, gpa: Allocator) void {
36 tree.tokens.deinit(gpa);42 tree.tokens.deinit(gpa);
37 tree.nodes.deinit(gpa);43 tree.nodes.deinit(gpa);
...@@ -3533,6 +3539,39 @@ pub const Node = struct {...@@ -3533,6 +3539,39 @@ pub const Node = struct {
3533 };3539 };
3534};3540};
35353541
3542pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
3543 return tokensToSpan(
3544 tree,
3545 tree.firstToken(node),
3546 tree.lastToken(node),
3547 tree.nodes.items(.main_token)[node],
3548 );
3549}
3550
3551pub fn tokenToSpan(tree: *const Ast, token: Ast.TokenIndex) Span {
3552 return tokensToSpan(tree, token, token, token);
3553}
3554
3555pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
3556 const token_starts = tree.tokens.items(.start);
3557 var start_tok = start;
3558 var end_tok = end;
3559
3560 if (tree.tokensOnSameLine(start, end)) {
3561 // do nothing
3562 } else if (tree.tokensOnSameLine(start, main)) {
3563 end_tok = main;
3564 } else if (tree.tokensOnSameLine(main, end)) {
3565 start_tok = main;
3566 } else {
3567 start_tok = main;
3568 end_tok = main;
3569 }
3570 const start_off = token_starts[start_tok];
3571 const end_off = token_starts[end_tok] + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
3572 return Span{ .start = start_off, .end = end_off, .main = token_starts[main] };
3573}
3574
3536const std = @import("../std.zig");3575const std = @import("../std.zig");
3537const assert = std.debug.assert;3576const assert = std.debug.assert;
3538const testing = std.testing;3577const testing = std.testing;
...@@ -3544,5 +3583,6 @@ const Parse = @import("Parse.zig");...@@ -3544,5 +3583,6 @@ const Parse = @import("Parse.zig");
3544const private_render = @import("./render.zig");3583const private_render = @import("./render.zig");
35453584
3546test {3585test {
3547 testing.refAllDecls(@This());3586 _ = Parse;
3587 _ = private_render;
3548}3588}
lib/std/zig/ErrorBundle.zig+84
...@@ -459,6 +459,90 @@ pub const Wip = struct {...@@ -459,6 +459,90 @@ pub const Wip = struct {
459 return @intCast(wip.extra.items.len - notes_len);459 return @intCast(wip.extra.items.len - notes_len);
460 }460 }
461461
462 pub fn addZirErrorMessages(
463 eb: *ErrorBundle.Wip,
464 zir: std.zig.Zir,
465 tree: std.zig.Ast,
466 source: [:0]const u8,
467 src_path: []const u8,
468 ) !void {
469 const Zir = std.zig.Zir;
470 const payload_index = zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
471 assert(payload_index != 0);
472
473 const header = zir.extraData(Zir.Inst.CompileErrors, payload_index);
474 const items_len = header.data.items_len;
475 var extra_index = header.end;
476 for (0..items_len) |_| {
477 const item = zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
478 extra_index = item.end;
479 const err_span = blk: {
480 if (item.data.node != 0) {
481 break :blk tree.nodeToSpan(item.data.node);
482 }
483 const token_starts = tree.tokens.items(.start);
484 const start = token_starts[item.data.token] + item.data.byte_offset;
485 const end = start + @as(u32, @intCast(tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
486 break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
487 };
488 const err_loc = std.zig.findLineColumn(source, err_span.main);
489
490 {
491 const msg = zir.nullTerminatedString(item.data.msg);
492 try eb.addRootErrorMessage(.{
493 .msg = try eb.addString(msg),
494 .src_loc = try eb.addSourceLocation(.{
495 .src_path = try eb.addString(src_path),
496 .span_start = err_span.start,
497 .span_main = err_span.main,
498 .span_end = err_span.end,
499 .line = @intCast(err_loc.line),
500 .column = @intCast(err_loc.column),
501 .source_line = try eb.addString(err_loc.source_line),
502 }),
503 .notes_len = item.data.notesLen(zir),
504 });
505 }
506
507 if (item.data.notes != 0) {
508 const notes_start = try eb.reserveNotes(item.data.notes);
509 const block = zir.extraData(Zir.Inst.Block, item.data.notes);
510 const body = zir.extra[block.end..][0..block.data.body_len];
511 for (notes_start.., body) |note_i, body_elem| {
512 const note_item = zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
513 const msg = zir.nullTerminatedString(note_item.data.msg);
514 const span = blk: {
515 if (note_item.data.node != 0) {
516 break :blk tree.nodeToSpan(note_item.data.node);
517 }
518 const token_starts = tree.tokens.items(.start);
519 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
520 const end = start + @as(u32, @intCast(tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
521 break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
522 };
523 const loc = std.zig.findLineColumn(source, span.main);
524
525 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
526 .msg = try eb.addString(msg),
527 .src_loc = try eb.addSourceLocation(.{
528 .src_path = try eb.addString(src_path),
529 .span_start = span.start,
530 .span_main = span.main,
531 .span_end = span.end,
532 .line = @intCast(loc.line),
533 .column = @intCast(loc.column),
534 .source_line = if (loc.eql(err_loc))
535 0
536 else
537 try eb.addString(loc.source_line),
538 }),
539 .notes_len = 0, // TODO rework this function to be recursive
540 }));
541 }
542 }
543 }
544 }
545
462 fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {546 fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
463 const other_msg = other.getErrorMessage(msg_index);547 const other_msg = other.getErrorMessage(msg_index);
464 const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);548 const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);
lib/std/zig/fmt.zig+342-1
...@@ -1 +1,342 @@...@@ -1 +1,342 @@
1const std = @import("../std.zig");1const std = @import("std");
2const mem = std.mem;
3const fs = std.fs;
4const process = std.process;
5const Allocator = std.mem.Allocator;
6const warn = std.log.warn;
7const Color = std.zig.Color;
8
9const usage_fmt =
10 \\Usage: zig fmt [file]...
11 \\
12 \\ Formats the input files and modifies them in-place.
13 \\ Arguments can be files or directories, which are searched
14 \\ recursively.
15 \\
16 \\Options:
17 \\ -h, --help Print this help and exit
18 \\ --color [auto|off|on] Enable or disable colored error messages
19 \\ --stdin Format code from stdin; output to stdout
20 \\ --check List non-conforming files and exit with an error
21 \\ if the list is non-empty
22 \\ --ast-check Run zig ast-check on every file
23 \\ --exclude [file] Exclude file or directory from formatting
24 \\
25 \\
26;
27
28const Fmt = struct {
29 seen: SeenMap,
30 any_error: bool,
31 check_ast: bool,
32 color: Color,
33 gpa: Allocator,
34 arena: Allocator,
35 out_buffer: std.ArrayList(u8),
36
37 const SeenMap = std.AutoHashMap(fs.File.INode, void);
38};
39
40pub fn main() !void {
41 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
42 defer arena_instance.deinit();
43 const arena = arena_instance.allocator();
44 const gpa = arena;
45
46 const args = try process.argsAlloc(arena);
47
48 var color: Color = .auto;
49 var stdin_flag: bool = false;
50 var check_flag: bool = false;
51 var check_ast_flag: bool = false;
52 var input_files = std.ArrayList([]const u8).init(gpa);
53 defer input_files.deinit();
54 var excluded_files = std.ArrayList([]const u8).init(gpa);
55 defer excluded_files.deinit();
56
57 {
58 var i: usize = 1;
59 while (i < args.len) : (i += 1) {
60 const arg = args[i];
61 if (mem.startsWith(u8, arg, "-")) {
62 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
63 const stdout = std.io.getStdOut().writer();
64 try stdout.writeAll(usage_fmt);
65 return process.cleanExit();
66 } else if (mem.eql(u8, arg, "--color")) {
67 if (i + 1 >= args.len) {
68 fatal("expected [auto|on|off] after --color", .{});
69 }
70 i += 1;
71 const next_arg = args[i];
72 color = std.meta.stringToEnum(Color, next_arg) orelse {
73 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
74 };
75 } else if (mem.eql(u8, arg, "--stdin")) {
76 stdin_flag = true;
77 } else if (mem.eql(u8, arg, "--check")) {
78 check_flag = true;
79 } else if (mem.eql(u8, arg, "--ast-check")) {
80 check_ast_flag = true;
81 } else if (mem.eql(u8, arg, "--exclude")) {
82 if (i + 1 >= args.len) {
83 fatal("expected parameter after --exclude", .{});
84 }
85 i += 1;
86 const next_arg = args[i];
87 try excluded_files.append(next_arg);
88 } else {
89 fatal("unrecognized parameter: '{s}'", .{arg});
90 }
91 } else {
92 try input_files.append(arg);
93 }
94 }
95 }
96
97 if (stdin_flag) {
98 if (input_files.items.len != 0) {
99 fatal("cannot use --stdin with positional arguments", .{});
100 }
101
102 const stdin = std.io.getStdIn();
103 const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
104 fatal("unable to read stdin: {}", .{err});
105 };
106 defer gpa.free(source_code);
107
108 var tree = std.zig.Ast.parse(gpa, source_code, .zig) catch |err| {
109 fatal("error parsing stdin: {}", .{err});
110 };
111 defer tree.deinit(gpa);
112
113 if (check_ast_flag) {
114 var zir = try std.zig.AstGen.generate(gpa, tree);
115
116 if (zir.hasCompileErrors()) {
117 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
118 try wip_errors.init(gpa);
119 defer wip_errors.deinit();
120 try wip_errors.addZirErrorMessages(zir, tree, source_code, "<stdin>");
121 var error_bundle = try wip_errors.toOwnedBundle("");
122 defer error_bundle.deinit(gpa);
123 error_bundle.renderToStdErr(color.renderOptions());
124 process.exit(2);
125 }
126 } else if (tree.errors.len != 0) {
127 try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
128 process.exit(2);
129 }
130 const formatted = try tree.render(gpa);
131 defer gpa.free(formatted);
132
133 if (check_flag) {
134 const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
135 process.exit(code);
136 }
137
138 return std.io.getStdOut().writeAll(formatted);
139 }
140
141 if (input_files.items.len == 0) {
142 fatal("expected at least one source file argument", .{});
143 }
144
145 var fmt = Fmt{
146 .gpa = gpa,
147 .arena = arena,
148 .seen = Fmt.SeenMap.init(gpa),
149 .any_error = false,
150 .check_ast = check_ast_flag,
151 .color = color,
152 .out_buffer = std.ArrayList(u8).init(gpa),
153 };
154 defer fmt.seen.deinit();
155 defer fmt.out_buffer.deinit();
156
157 // Mark any excluded files/directories as already seen,
158 // so that they are skipped later during actual processing
159 for (excluded_files.items) |file_path| {
160 const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
161 error.FileNotFound => continue,
162 // On Windows, statFile does not work for directories
163 error.IsDir => dir: {
164 var dir = try fs.cwd().openDir(file_path, .{});
165 defer dir.close();
166 break :dir try dir.stat();
167 },
168 else => |e| return e,
169 };
170 try fmt.seen.put(stat.inode, {});
171 }
172
173 for (input_files.items) |file_path| {
174 try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
175 }
176 if (fmt.any_error) {
177 process.exit(1);
178 }
179}
180
181const FmtError = error{
182 SystemResources,
183 OperationAborted,
184 IoPending,
185 BrokenPipe,
186 Unexpected,
187 WouldBlock,
188 FileClosed,
189 DestinationAddressRequired,
190 DiskQuota,
191 FileTooBig,
192 InputOutput,
193 NoSpaceLeft,
194 AccessDenied,
195 OutOfMemory,
196 RenameAcrossMountPoints,
197 ReadOnlyFileSystem,
198 LinkQuotaExceeded,
199 FileBusy,
200 EndOfStream,
201 Unseekable,
202 NotOpenForWriting,
203 UnsupportedEncoding,
204 ConnectionResetByPeer,
205 SocketNotConnected,
206 LockViolation,
207 NetNameDeleted,
208 InvalidArgument,
209} || fs.File.OpenError;
210
211fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
212 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
213 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
214 else => {
215 warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
216 fmt.any_error = true;
217 return;
218 },
219 };
220}
221
222fn fmtPathDir(
223 fmt: *Fmt,
224 file_path: []const u8,
225 check_mode: bool,
226 parent_dir: fs.Dir,
227 parent_sub_path: []const u8,
228) FmtError!void {
229 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
230 defer dir.close();
231
232 const stat = try dir.stat();
233 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
234
235 var dir_it = dir.iterate();
236 while (try dir_it.next()) |entry| {
237 const is_dir = entry.kind == .directory;
238
239 if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
240
241 if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
242 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
243 defer fmt.gpa.free(full_path);
244
245 if (is_dir) {
246 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
247 } else {
248 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
249 warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
250 fmt.any_error = true;
251 return;
252 };
253 }
254 }
255 }
256}
257
258fn fmtPathFile(
259 fmt: *Fmt,
260 file_path: []const u8,
261 check_mode: bool,
262 dir: fs.Dir,
263 sub_path: []const u8,
264) FmtError!void {
265 const source_file = try dir.openFile(sub_path, .{});
266 var file_closed = false;
267 errdefer if (!file_closed) source_file.close();
268
269 const stat = try source_file.stat();
270
271 if (stat.kind == .directory)
272 return error.IsDir;
273
274 const gpa = fmt.gpa;
275 const source_code = try std.zig.readSourceFileToEndAlloc(
276 gpa,
277 source_file,
278 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
279 );
280 defer gpa.free(source_code);
281
282 source_file.close();
283 file_closed = true;
284
285 // Add to set after no longer possible to get error.IsDir.
286 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
287
288 var tree = try std.zig.Ast.parse(gpa, source_code, .zig);
289 defer tree.deinit(gpa);
290
291 if (tree.errors.len != 0) {
292 try std.zig.printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
293 fmt.any_error = true;
294 return;
295 }
296
297 if (fmt.check_ast) {
298 if (stat.size > std.zig.max_src_size)
299 return error.FileTooBig;
300
301 var zir = try std.zig.AstGen.generate(gpa, tree);
302 defer zir.deinit(gpa);
303
304 if (zir.hasCompileErrors()) {
305 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
306 try wip_errors.init(gpa);
307 defer wip_errors.deinit();
308 try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path);
309 var error_bundle = try wip_errors.toOwnedBundle("");
310 defer error_bundle.deinit(gpa);
311 error_bundle.renderToStdErr(fmt.color.renderOptions());
312 fmt.any_error = true;
313 }
314 }
315
316 // As a heuristic, we make enough capacity for the same as the input source.
317 fmt.out_buffer.shrinkRetainingCapacity(0);
318 try fmt.out_buffer.ensureTotalCapacity(source_code.len);
319
320 try tree.renderToArrayList(&fmt.out_buffer, .{});
321 if (mem.eql(u8, fmt.out_buffer.items, source_code))
322 return;
323
324 if (check_mode) {
325 const stdout = std.io.getStdOut().writer();
326 try stdout.print("{s}\n", .{file_path});
327 fmt.any_error = true;
328 } else {
329 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
330 defer af.deinit();
331
332 try af.file.writeAll(fmt.out_buffer.items);
333 try af.finish();
334 const stdout = std.io.getStdOut().writer();
335 try stdout.print("{s}\n", .{file_path});
336 }
337}
338
339fn fatal(comptime format: []const u8, args: anytype) noreturn {
340 std.log.err(format, args);
341 process.exit(1);
342}
src/Compilation.zig+3-78
...@@ -3322,85 +3322,10 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {...@@ -3322,85 +3322,10 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
3322 assert(file.zir_loaded);3322 assert(file.zir_loaded);
3323 assert(file.tree_loaded);3323 assert(file.tree_loaded);
3324 assert(file.source_loaded);3324 assert(file.source_loaded);
3325 const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
3326 assert(payload_index != 0);
3327 const gpa = eb.gpa;3325 const gpa = eb.gpa;
33283326 const src_path = try file.fullPath(gpa);
3329 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);3327 defer gpa.free(src_path);
3330 const items_len = header.data.items_len;3328 return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
3331 var extra_index = header.end;
3332 for (0..items_len) |_| {
3333 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
3334 extra_index = item.end;
3335 const err_span = blk: {
3336 if (item.data.node != 0) {
3337 break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
3338 }
3339 const token_starts = file.tree.tokens.items(.start);
3340 const start = token_starts[item.data.token] + item.data.byte_offset;
3341 const end = start + @as(u32, @intCast(file.tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
3342 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
3343 };
3344 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
3345
3346 {
3347 const msg = file.zir.nullTerminatedString(item.data.msg);
3348 const src_path = try file.fullPath(gpa);
3349 defer gpa.free(src_path);
3350 try eb.addRootErrorMessage(.{
3351 .msg = try eb.addString(msg),
3352 .src_loc = try eb.addSourceLocation(.{
3353 .src_path = try eb.addString(src_path),
3354 .span_start = err_span.start,
3355 .span_main = err_span.main,
3356 .span_end = err_span.end,
3357 .line = @as(u32, @intCast(err_loc.line)),
3358 .column = @as(u32, @intCast(err_loc.column)),
3359 .source_line = try eb.addString(err_loc.source_line),
3360 }),
3361 .notes_len = item.data.notesLen(file.zir),
3362 });
3363 }
3364
3365 if (item.data.notes != 0) {
3366 const notes_start = try eb.reserveNotes(item.data.notes);
3367 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
3368 const body = file.zir.extra[block.end..][0..block.data.body_len];
3369 for (notes_start.., body) |note_i, body_elem| {
3370 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
3371 const msg = file.zir.nullTerminatedString(note_item.data.msg);
3372 const span = blk: {
3373 if (note_item.data.node != 0) {
3374 break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
3375 }
3376 const token_starts = file.tree.tokens.items(.start);
3377 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
3378 const end = start + @as(u32, @intCast(file.tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
3379 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
3380 };
3381 const loc = std.zig.findLineColumn(file.source, span.main);
3382 const src_path = try file.fullPath(gpa);
3383 defer gpa.free(src_path);
3384
3385 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
3386 .msg = try eb.addString(msg),
3387 .src_loc = try eb.addSourceLocation(.{
3388 .src_path = try eb.addString(src_path),
3389 .span_start = span.start,
3390 .span_main = span.main,
3391 .span_end = span.end,
3392 .line = @as(u32, @intCast(loc.line)),
3393 .column = @as(u32, @intCast(loc.column)),
3394 .source_line = if (loc.eql(err_loc))
3395 0
3396 else
3397 try eb.addString(loc.source_line),
3398 }),
3399 .notes_len = 0, // TODO rework this function to be recursive
3400 }));
3401 }
3402 }
3403 }
3404}3329}
34053330
3406pub fn performAllTheWork(3331pub fn performAllTheWork(
src/Module.zig+66-108
...@@ -1255,11 +1255,7 @@ pub const SrcLoc = struct {...@@ -1255,11 +1255,7 @@ pub const SrcLoc = struct {
1255 return @bitCast(offset + @as(i32, @bitCast(src_loc.parent_decl_node)));1255 return @bitCast(offset + @as(i32, @bitCast(src_loc.parent_decl_node)));
1256 }1256 }
12571257
1258 pub const Span = struct {1258 pub const Span = Ast.Span;
1259 start: u32,
1260 end: u32,
1261 main: u32,
1262 };
12631259
1264 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {1260 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
1265 switch (src_loc.lazy) {1261 switch (src_loc.lazy) {
...@@ -1276,7 +1272,7 @@ pub const SrcLoc = struct {...@@ -1276,7 +1272,7 @@ pub const SrcLoc = struct {
1276 },1272 },
1277 .node_abs => |node| {1273 .node_abs => |node| {
1278 const tree = try src_loc.file_scope.getTree(gpa);1274 const tree = try src_loc.file_scope.getTree(gpa);
1279 return nodeToSpan(tree, node);1275 return tree.nodeToSpan(node);
1280 },1276 },
1281 .byte_offset => |byte_off| {1277 .byte_offset => |byte_off| {
1282 const tree = try src_loc.file_scope.getTree(gpa);1278 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1297,25 +1293,24 @@ pub const SrcLoc = struct {...@@ -1297,25 +1293,24 @@ pub const SrcLoc = struct {
1297 const tree = try src_loc.file_scope.getTree(gpa);1293 const tree = try src_loc.file_scope.getTree(gpa);
1298 const node = src_loc.declRelativeToNodeIndex(node_off);1294 const node = src_loc.declRelativeToNodeIndex(node_off);
1299 assert(src_loc.file_scope.tree_loaded);1295 assert(src_loc.file_scope.tree_loaded);
1300 return nodeToSpan(tree, node);1296 return tree.nodeToSpan(node);
1301 },1297 },
1302 .node_offset_main_token => |node_off| {1298 .node_offset_main_token => |node_off| {
1303 const tree = try src_loc.file_scope.getTree(gpa);1299 const tree = try src_loc.file_scope.getTree(gpa);
1304 const node = src_loc.declRelativeToNodeIndex(node_off);1300 const node = src_loc.declRelativeToNodeIndex(node_off);
1305 const main_token = tree.nodes.items(.main_token)[node];1301 const main_token = tree.nodes.items(.main_token)[node];
1306 return tokensToSpan(tree, main_token, main_token, main_token);1302 return tree.tokensToSpan(main_token, main_token, main_token);
1307 },1303 },
1308 .node_offset_bin_op => |node_off| {1304 .node_offset_bin_op => |node_off| {
1309 const tree = try src_loc.file_scope.getTree(gpa);1305 const tree = try src_loc.file_scope.getTree(gpa);
1310 const node = src_loc.declRelativeToNodeIndex(node_off);1306 const node = src_loc.declRelativeToNodeIndex(node_off);
1311 assert(src_loc.file_scope.tree_loaded);1307 assert(src_loc.file_scope.tree_loaded);
1312 return nodeToSpan(tree, node);1308 return tree.nodeToSpan(node);
1313 },1309 },
1314 .node_offset_initializer => |node_off| {1310 .node_offset_initializer => |node_off| {
1315 const tree = try src_loc.file_scope.getTree(gpa);1311 const tree = try src_loc.file_scope.getTree(gpa);
1316 const node = src_loc.declRelativeToNodeIndex(node_off);1312 const node = src_loc.declRelativeToNodeIndex(node_off);
1317 return tokensToSpan(1313 return tree.tokensToSpan(
1318 tree,
1319 tree.firstToken(node) - 3,1314 tree.firstToken(node) - 3,
1320 tree.lastToken(node),1315 tree.lastToken(node),
1321 tree.nodes.items(.main_token)[node] - 2,1316 tree.nodes.items(.main_token)[node] - 2,
...@@ -1333,12 +1328,12 @@ pub const SrcLoc = struct {...@@ -1333,12 +1328,12 @@ pub const SrcLoc = struct {
1333 => tree.fullVarDecl(node).?,1328 => tree.fullVarDecl(node).?,
1334 .@"usingnamespace" => {1329 .@"usingnamespace" => {
1335 const node_data = tree.nodes.items(.data);1330 const node_data = tree.nodes.items(.data);
1336 return nodeToSpan(tree, node_data[node].lhs);1331 return tree.nodeToSpan(node_data[node].lhs);
1337 },1332 },
1338 else => unreachable,1333 else => unreachable,
1339 };1334 };
1340 if (full.ast.type_node != 0) {1335 if (full.ast.type_node != 0) {
1341 return nodeToSpan(tree, full.ast.type_node);1336 return tree.nodeToSpan(full.ast.type_node);
1342 }1337 }
1343 const tok_index = full.ast.mut_token + 1; // the name token1338 const tok_index = full.ast.mut_token + 1; // the name token
1344 const start = tree.tokens.items(.start)[tok_index];1339 const start = tree.tokens.items(.start)[tok_index];
...@@ -1349,25 +1344,25 @@ pub const SrcLoc = struct {...@@ -1349,25 +1344,25 @@ pub const SrcLoc = struct {
1349 const tree = try src_loc.file_scope.getTree(gpa);1344 const tree = try src_loc.file_scope.getTree(gpa);
1350 const node = src_loc.declRelativeToNodeIndex(node_off);1345 const node = src_loc.declRelativeToNodeIndex(node_off);
1351 const full = tree.fullVarDecl(node).?;1346 const full = tree.fullVarDecl(node).?;
1352 return nodeToSpan(tree, full.ast.align_node);1347 return tree.nodeToSpan(full.ast.align_node);
1353 },1348 },
1354 .node_offset_var_decl_section => |node_off| {1349 .node_offset_var_decl_section => |node_off| {
1355 const tree = try src_loc.file_scope.getTree(gpa);1350 const tree = try src_loc.file_scope.getTree(gpa);
1356 const node = src_loc.declRelativeToNodeIndex(node_off);1351 const node = src_loc.declRelativeToNodeIndex(node_off);
1357 const full = tree.fullVarDecl(node).?;1352 const full = tree.fullVarDecl(node).?;
1358 return nodeToSpan(tree, full.ast.section_node);1353 return tree.nodeToSpan(full.ast.section_node);
1359 },1354 },
1360 .node_offset_var_decl_addrspace => |node_off| {1355 .node_offset_var_decl_addrspace => |node_off| {
1361 const tree = try src_loc.file_scope.getTree(gpa);1356 const tree = try src_loc.file_scope.getTree(gpa);
1362 const node = src_loc.declRelativeToNodeIndex(node_off);1357 const node = src_loc.declRelativeToNodeIndex(node_off);
1363 const full = tree.fullVarDecl(node).?;1358 const full = tree.fullVarDecl(node).?;
1364 return nodeToSpan(tree, full.ast.addrspace_node);1359 return tree.nodeToSpan(full.ast.addrspace_node);
1365 },1360 },
1366 .node_offset_var_decl_init => |node_off| {1361 .node_offset_var_decl_init => |node_off| {
1367 const tree = try src_loc.file_scope.getTree(gpa);1362 const tree = try src_loc.file_scope.getTree(gpa);
1368 const node = src_loc.declRelativeToNodeIndex(node_off);1363 const node = src_loc.declRelativeToNodeIndex(node_off);
1369 const full = tree.fullVarDecl(node).?;1364 const full = tree.fullVarDecl(node).?;
1370 return nodeToSpan(tree, full.ast.init_node);1365 return tree.nodeToSpan(full.ast.init_node);
1371 },1366 },
1372 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),1367 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
1373 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),1368 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
...@@ -1408,13 +1403,13 @@ pub const SrcLoc = struct {...@@ -1408,13 +1403,13 @@ pub const SrcLoc = struct {
1408 node = node_datas[node].lhs;1403 node = node_datas[node].lhs;
1409 }1404 }
14101405
1411 return nodeToSpan(tree, node);1406 return tree.nodeToSpan(node);
1412 },1407 },
1413 .node_offset_array_access_index => |node_off| {1408 .node_offset_array_access_index => |node_off| {
1414 const tree = try src_loc.file_scope.getTree(gpa);1409 const tree = try src_loc.file_scope.getTree(gpa);
1415 const node_datas = tree.nodes.items(.data);1410 const node_datas = tree.nodes.items(.data);
1416 const node = src_loc.declRelativeToNodeIndex(node_off);1411 const node = src_loc.declRelativeToNodeIndex(node_off);
1417 return nodeToSpan(tree, node_datas[node].rhs);1412 return tree.nodeToSpan(node_datas[node].rhs);
1418 },1413 },
1419 .node_offset_slice_ptr,1414 .node_offset_slice_ptr,
1420 .node_offset_slice_start,1415 .node_offset_slice_start,
...@@ -1431,14 +1426,14 @@ pub const SrcLoc = struct {...@@ -1431,14 +1426,14 @@ pub const SrcLoc = struct {
1431 .node_offset_slice_sentinel => full.ast.sentinel,1426 .node_offset_slice_sentinel => full.ast.sentinel,
1432 else => unreachable,1427 else => unreachable,
1433 };1428 };
1434 return nodeToSpan(tree, part_node);1429 return tree.nodeToSpan(part_node);
1435 },1430 },
1436 .node_offset_call_func => |node_off| {1431 .node_offset_call_func => |node_off| {
1437 const tree = try src_loc.file_scope.getTree(gpa);1432 const tree = try src_loc.file_scope.getTree(gpa);
1438 const node = src_loc.declRelativeToNodeIndex(node_off);1433 const node = src_loc.declRelativeToNodeIndex(node_off);
1439 var buf: [1]Ast.Node.Index = undefined;1434 var buf: [1]Ast.Node.Index = undefined;
1440 const full = tree.fullCall(&buf, node).?;1435 const full = tree.fullCall(&buf, node).?;
1441 return nodeToSpan(tree, full.ast.fn_expr);1436 return tree.nodeToSpan(full.ast.fn_expr);
1442 },1437 },
1443 .node_offset_field_name => |node_off| {1438 .node_offset_field_name => |node_off| {
1444 const tree = try src_loc.file_scope.getTree(gpa);1439 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1477,13 +1472,13 @@ pub const SrcLoc = struct {...@@ -1477,13 +1472,13 @@ pub const SrcLoc = struct {
1477 .node_offset_deref_ptr => |node_off| {1472 .node_offset_deref_ptr => |node_off| {
1478 const tree = try src_loc.file_scope.getTree(gpa);1473 const tree = try src_loc.file_scope.getTree(gpa);
1479 const node = src_loc.declRelativeToNodeIndex(node_off);1474 const node = src_loc.declRelativeToNodeIndex(node_off);
1480 return nodeToSpan(tree, node);1475 return tree.nodeToSpan(node);
1481 },1476 },
1482 .node_offset_asm_source => |node_off| {1477 .node_offset_asm_source => |node_off| {
1483 const tree = try src_loc.file_scope.getTree(gpa);1478 const tree = try src_loc.file_scope.getTree(gpa);
1484 const node = src_loc.declRelativeToNodeIndex(node_off);1479 const node = src_loc.declRelativeToNodeIndex(node_off);
1485 const full = tree.fullAsm(node).?;1480 const full = tree.fullAsm(node).?;
1486 return nodeToSpan(tree, full.ast.template);1481 return tree.nodeToSpan(full.ast.template);
1487 },1482 },
1488 .node_offset_asm_ret_ty => |node_off| {1483 .node_offset_asm_ret_ty => |node_off| {
1489 const tree = try src_loc.file_scope.getTree(gpa);1484 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1491,7 +1486,7 @@ pub const SrcLoc = struct {...@@ -1491,7 +1486,7 @@ pub const SrcLoc = struct {
1491 const full = tree.fullAsm(node).?;1486 const full = tree.fullAsm(node).?;
1492 const asm_output = full.outputs[0];1487 const asm_output = full.outputs[0];
1493 const node_datas = tree.nodes.items(.data);1488 const node_datas = tree.nodes.items(.data);
1494 return nodeToSpan(tree, node_datas[asm_output].lhs);1489 return tree.nodeToSpan(node_datas[asm_output].lhs);
1495 },1490 },
14961491
1497 .node_offset_if_cond => |node_off| {1492 .node_offset_if_cond => |node_off| {
...@@ -1514,21 +1509,21 @@ pub const SrcLoc = struct {...@@ -1514,21 +1509,21 @@ pub const SrcLoc = struct {
1514 const inputs = tree.fullFor(node).?.ast.inputs;1509 const inputs = tree.fullFor(node).?.ast.inputs;
1515 const start = tree.firstToken(inputs[0]);1510 const start = tree.firstToken(inputs[0]);
1516 const end = tree.lastToken(inputs[inputs.len - 1]);1511 const end = tree.lastToken(inputs[inputs.len - 1]);
1517 return tokensToSpan(tree, start, end, start);1512 return tree.tokensToSpan(start, end, start);
1518 },1513 },
15191514
1520 .@"orelse" => node,1515 .@"orelse" => node,
1521 .@"catch" => node,1516 .@"catch" => node,
1522 else => unreachable,1517 else => unreachable,
1523 };1518 };
1524 return nodeToSpan(tree, src_node);1519 return tree.nodeToSpan(src_node);
1525 },1520 },
1526 .for_input => |for_input| {1521 .for_input => |for_input| {
1527 const tree = try src_loc.file_scope.getTree(gpa);1522 const tree = try src_loc.file_scope.getTree(gpa);
1528 const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);1523 const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);
1529 const for_full = tree.fullFor(node).?;1524 const for_full = tree.fullFor(node).?;
1530 const src_node = for_full.ast.inputs[for_input.input_index];1525 const src_node = for_full.ast.inputs[for_input.input_index];
1531 return nodeToSpan(tree, src_node);1526 return tree.nodeToSpan(src_node);
1532 },1527 },
1533 .for_capture_from_input => |node_off| {1528 .for_capture_from_input => |node_off| {
1534 const tree = try src_loc.file_scope.getTree(gpa);1529 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1554,12 +1549,12 @@ pub const SrcLoc = struct {...@@ -1554,12 +1549,12 @@ pub const SrcLoc = struct {
1554 },1549 },
1555 .identifier => {1550 .identifier => {
1556 if (count == 0)1551 if (count == 0)
1557 return tokensToSpan(tree, tok, tok + 1, tok);1552 return tree.tokensToSpan(tok, tok + 1, tok);
1558 tok += 1;1553 tok += 1;
1559 },1554 },
1560 .asterisk => {1555 .asterisk => {
1561 if (count == 0)1556 if (count == 0)
1562 return tokensToSpan(tree, tok, tok + 2, tok);1557 return tree.tokensToSpan(tok, tok + 2, tok);
1563 tok += 1;1558 tok += 1;
1564 },1559 },
1565 else => unreachable,1560 else => unreachable,
...@@ -1591,7 +1586,7 @@ pub const SrcLoc = struct {...@@ -1591,7 +1586,7 @@ pub const SrcLoc = struct {
1591 .array_init_comma,1586 .array_init_comma,
1592 => {1587 => {
1593 const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements;1588 const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements;
1594 return nodeToSpan(tree, full[call_arg.arg_index]);1589 return tree.nodeToSpan(full[call_arg.arg_index]);
1595 },1590 },
1596 .struct_init_one,1591 .struct_init_one,
1597 .struct_init_one_comma,1592 .struct_init_one_comma,
...@@ -1603,12 +1598,12 @@ pub const SrcLoc = struct {...@@ -1603,12 +1598,12 @@ pub const SrcLoc = struct {
1603 .struct_init_comma,1598 .struct_init_comma,
1604 => {1599 => {
1605 const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields;1600 const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields;
1606 return nodeToSpan(tree, full[call_arg.arg_index]);1601 return tree.nodeToSpan(full[call_arg.arg_index]);
1607 },1602 },
1608 else => return nodeToSpan(tree, call_args_node),1603 else => return tree.nodeToSpan(call_args_node),
1609 }1604 }
1610 };1605 };
1611 return nodeToSpan(tree, call_full.ast.params[call_arg.arg_index]);1606 return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
1612 },1607 },
1613 .fn_proto_param => |fn_proto_param| {1608 .fn_proto_param => |fn_proto_param| {
1614 const tree = try src_loc.file_scope.getTree(gpa);1609 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1619,12 +1614,11 @@ pub const SrcLoc = struct {...@@ -1619,12 +1614,11 @@ pub const SrcLoc = struct {
1619 var i: usize = 0;1614 var i: usize = 0;
1620 while (it.next()) |param| : (i += 1) {1615 while (it.next()) |param| : (i += 1) {
1621 if (i == fn_proto_param.param_index) {1616 if (i == fn_proto_param.param_index) {
1622 if (param.anytype_ellipsis3) |token| return tokenToSpan(tree, token);1617 if (param.anytype_ellipsis3) |token| return tree.tokenToSpan(token);
1623 const first_token = param.comptime_noalias orelse1618 const first_token = param.comptime_noalias orelse
1624 param.name_token orelse1619 param.name_token orelse
1625 tree.firstToken(param.type_expr);1620 tree.firstToken(param.type_expr);
1626 return tokensToSpan(1621 return tree.tokensToSpan(
1627 tree,
1628 first_token,1622 first_token,
1629 tree.lastToken(param.type_expr),1623 tree.lastToken(param.type_expr),
1630 first_token,1624 first_token,
...@@ -1637,13 +1631,13 @@ pub const SrcLoc = struct {...@@ -1637,13 +1631,13 @@ pub const SrcLoc = struct {
1637 const tree = try src_loc.file_scope.getTree(gpa);1631 const tree = try src_loc.file_scope.getTree(gpa);
1638 const node = src_loc.declRelativeToNodeIndex(node_off);1632 const node = src_loc.declRelativeToNodeIndex(node_off);
1639 const node_datas = tree.nodes.items(.data);1633 const node_datas = tree.nodes.items(.data);
1640 return nodeToSpan(tree, node_datas[node].lhs);1634 return tree.nodeToSpan(node_datas[node].lhs);
1641 },1635 },
1642 .node_offset_bin_rhs => |node_off| {1636 .node_offset_bin_rhs => |node_off| {
1643 const tree = try src_loc.file_scope.getTree(gpa);1637 const tree = try src_loc.file_scope.getTree(gpa);
1644 const node = src_loc.declRelativeToNodeIndex(node_off);1638 const node = src_loc.declRelativeToNodeIndex(node_off);
1645 const node_datas = tree.nodes.items(.data);1639 const node_datas = tree.nodes.items(.data);
1646 return nodeToSpan(tree, node_datas[node].rhs);1640 return tree.nodeToSpan(node_datas[node].rhs);
1647 },1641 },
1648 .array_cat_lhs, .array_cat_rhs => |cat| {1642 .array_cat_lhs, .array_cat_rhs => |cat| {
1649 const tree = try src_loc.file_scope.getTree(gpa);1643 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1667,9 +1661,9 @@ pub const SrcLoc = struct {...@@ -1667,9 +1661,9 @@ pub const SrcLoc = struct {
1667 .array_init_comma,1661 .array_init_comma,
1668 => {1662 => {
1669 const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements;1663 const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements;
1670 return nodeToSpan(tree, full[cat.elem_index]);1664 return tree.nodeToSpan(full[cat.elem_index]);
1671 },1665 },
1672 else => return nodeToSpan(tree, arr_node),1666 else => return tree.nodeToSpan(arr_node),
1673 }1667 }
1674 },1668 },
16751669
...@@ -1677,7 +1671,7 @@ pub const SrcLoc = struct {...@@ -1677,7 +1671,7 @@ pub const SrcLoc = struct {
1677 const tree = try src_loc.file_scope.getTree(gpa);1671 const tree = try src_loc.file_scope.getTree(gpa);
1678 const node = src_loc.declRelativeToNodeIndex(node_off);1672 const node = src_loc.declRelativeToNodeIndex(node_off);
1679 const node_datas = tree.nodes.items(.data);1673 const node_datas = tree.nodes.items(.data);
1680 return nodeToSpan(tree, node_datas[node].lhs);1674 return tree.nodeToSpan(node_datas[node].lhs);
1681 },1675 },
16821676
1683 .node_offset_switch_special_prong => |node_off| {1677 .node_offset_switch_special_prong => |node_off| {
...@@ -1696,7 +1690,7 @@ pub const SrcLoc = struct {...@@ -1696,7 +1690,7 @@ pub const SrcLoc = struct {
1696 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));1690 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
1697 if (!is_special) continue;1691 if (!is_special) continue;
16981692
1699 return nodeToSpan(tree, case_node);1693 return tree.nodeToSpan(case_node);
1700 } else unreachable;1694 } else unreachable;
1701 },1695 },
17021696
...@@ -1718,7 +1712,7 @@ pub const SrcLoc = struct {...@@ -1718,7 +1712,7 @@ pub const SrcLoc = struct {
17181712
1719 for (case.ast.values) |item_node| {1713 for (case.ast.values) |item_node| {
1720 if (node_tags[item_node] == .switch_range) {1714 if (node_tags[item_node] == .switch_range) {
1721 return nodeToSpan(tree, item_node);1715 return tree.nodeToSpan(item_node);
1722 }1716 }
1723 }1717 }
1724 } else unreachable;1718 } else unreachable;
...@@ -1754,28 +1748,28 @@ pub const SrcLoc = struct {...@@ -1754,28 +1748,28 @@ pub const SrcLoc = struct {
1754 const node = src_loc.declRelativeToNodeIndex(node_off);1748 const node = src_loc.declRelativeToNodeIndex(node_off);
1755 var buf: [1]Ast.Node.Index = undefined;1749 var buf: [1]Ast.Node.Index = undefined;
1756 const full = tree.fullFnProto(&buf, node).?;1750 const full = tree.fullFnProto(&buf, node).?;
1757 return nodeToSpan(tree, full.ast.align_expr);1751 return tree.nodeToSpan(full.ast.align_expr);
1758 },1752 },
1759 .node_offset_fn_type_addrspace => |node_off| {1753 .node_offset_fn_type_addrspace => |node_off| {
1760 const tree = try src_loc.file_scope.getTree(gpa);1754 const tree = try src_loc.file_scope.getTree(gpa);
1761 const node = src_loc.declRelativeToNodeIndex(node_off);1755 const node = src_loc.declRelativeToNodeIndex(node_off);
1762 var buf: [1]Ast.Node.Index = undefined;1756 var buf: [1]Ast.Node.Index = undefined;
1763 const full = tree.fullFnProto(&buf, node).?;1757 const full = tree.fullFnProto(&buf, node).?;
1764 return nodeToSpan(tree, full.ast.addrspace_expr);1758 return tree.nodeToSpan(full.ast.addrspace_expr);
1765 },1759 },
1766 .node_offset_fn_type_section => |node_off| {1760 .node_offset_fn_type_section => |node_off| {
1767 const tree = try src_loc.file_scope.getTree(gpa);1761 const tree = try src_loc.file_scope.getTree(gpa);
1768 const node = src_loc.declRelativeToNodeIndex(node_off);1762 const node = src_loc.declRelativeToNodeIndex(node_off);
1769 var buf: [1]Ast.Node.Index = undefined;1763 var buf: [1]Ast.Node.Index = undefined;
1770 const full = tree.fullFnProto(&buf, node).?;1764 const full = tree.fullFnProto(&buf, node).?;
1771 return nodeToSpan(tree, full.ast.section_expr);1765 return tree.nodeToSpan(full.ast.section_expr);
1772 },1766 },
1773 .node_offset_fn_type_cc => |node_off| {1767 .node_offset_fn_type_cc => |node_off| {
1774 const tree = try src_loc.file_scope.getTree(gpa);1768 const tree = try src_loc.file_scope.getTree(gpa);
1775 const node = src_loc.declRelativeToNodeIndex(node_off);1769 const node = src_loc.declRelativeToNodeIndex(node_off);
1776 var buf: [1]Ast.Node.Index = undefined;1770 var buf: [1]Ast.Node.Index = undefined;
1777 const full = tree.fullFnProto(&buf, node).?;1771 const full = tree.fullFnProto(&buf, node).?;
1778 return nodeToSpan(tree, full.ast.callconv_expr);1772 return tree.nodeToSpan(full.ast.callconv_expr);
1779 },1773 },
17801774
1781 .node_offset_fn_type_ret_ty => |node_off| {1775 .node_offset_fn_type_ret_ty => |node_off| {
...@@ -1783,7 +1777,7 @@ pub const SrcLoc = struct {...@@ -1783,7 +1777,7 @@ pub const SrcLoc = struct {
1783 const node = src_loc.declRelativeToNodeIndex(node_off);1777 const node = src_loc.declRelativeToNodeIndex(node_off);
1784 var buf: [1]Ast.Node.Index = undefined;1778 var buf: [1]Ast.Node.Index = undefined;
1785 const full = tree.fullFnProto(&buf, node).?;1779 const full = tree.fullFnProto(&buf, node).?;
1786 return nodeToSpan(tree, full.ast.return_type);1780 return tree.nodeToSpan(full.ast.return_type);
1787 },1781 },
1788 .node_offset_param => |node_off| {1782 .node_offset_param => |node_off| {
1789 const tree = try src_loc.file_scope.getTree(gpa);1783 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1795,8 +1789,7 @@ pub const SrcLoc = struct {...@@ -1795,8 +1789,7 @@ pub const SrcLoc = struct {
1795 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,1789 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
1796 else => break,1790 else => break,
1797 };1791 };
1798 return tokensToSpan(1792 return tree.tokensToSpan(
1799 tree,
1800 first_tok,1793 first_tok,
1801 tree.lastToken(node),1794 tree.lastToken(node),
1802 first_tok,1795 first_tok,
...@@ -1813,8 +1806,7 @@ pub const SrcLoc = struct {...@@ -1813,8 +1806,7 @@ pub const SrcLoc = struct {
1813 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,1806 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
1814 else => break,1807 else => break,
1815 };1808 };
1816 return tokensToSpan(1809 return tree.tokensToSpan(
1817 tree,
1818 first_tok,1810 first_tok,
1819 tok_index,1811 tok_index,
1820 first_tok,1812 first_tok,
...@@ -1825,7 +1817,7 @@ pub const SrcLoc = struct {...@@ -1825,7 +1817,7 @@ pub const SrcLoc = struct {
1825 const tree = try src_loc.file_scope.getTree(gpa);1817 const tree = try src_loc.file_scope.getTree(gpa);
1826 const node_datas = tree.nodes.items(.data);1818 const node_datas = tree.nodes.items(.data);
1827 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1819 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
1828 return nodeToSpan(tree, node_datas[parent_node].rhs);1820 return tree.nodeToSpan(node_datas[parent_node].rhs);
1829 },1821 },
18301822
1831 .node_offset_lib_name => |node_off| {1823 .node_offset_lib_name => |node_off| {
...@@ -1844,70 +1836,70 @@ pub const SrcLoc = struct {...@@ -1844,70 +1836,70 @@ pub const SrcLoc = struct {
1844 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1836 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18451837
1846 const full = tree.fullArrayType(parent_node).?;1838 const full = tree.fullArrayType(parent_node).?;
1847 return nodeToSpan(tree, full.ast.elem_count);1839 return tree.nodeToSpan(full.ast.elem_count);
1848 },1840 },
1849 .node_offset_array_type_sentinel => |node_off| {1841 .node_offset_array_type_sentinel => |node_off| {
1850 const tree = try src_loc.file_scope.getTree(gpa);1842 const tree = try src_loc.file_scope.getTree(gpa);
1851 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1843 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18521844
1853 const full = tree.fullArrayType(parent_node).?;1845 const full = tree.fullArrayType(parent_node).?;
1854 return nodeToSpan(tree, full.ast.sentinel);1846 return tree.nodeToSpan(full.ast.sentinel);
1855 },1847 },
1856 .node_offset_array_type_elem => |node_off| {1848 .node_offset_array_type_elem => |node_off| {
1857 const tree = try src_loc.file_scope.getTree(gpa);1849 const tree = try src_loc.file_scope.getTree(gpa);
1858 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1850 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18591851
1860 const full = tree.fullArrayType(parent_node).?;1852 const full = tree.fullArrayType(parent_node).?;
1861 return nodeToSpan(tree, full.ast.elem_type);1853 return tree.nodeToSpan(full.ast.elem_type);
1862 },1854 },
1863 .node_offset_un_op => |node_off| {1855 .node_offset_un_op => |node_off| {
1864 const tree = try src_loc.file_scope.getTree(gpa);1856 const tree = try src_loc.file_scope.getTree(gpa);
1865 const node_datas = tree.nodes.items(.data);1857 const node_datas = tree.nodes.items(.data);
1866 const node = src_loc.declRelativeToNodeIndex(node_off);1858 const node = src_loc.declRelativeToNodeIndex(node_off);
18671859
1868 return nodeToSpan(tree, node_datas[node].lhs);1860 return tree.nodeToSpan(node_datas[node].lhs);
1869 },1861 },
1870 .node_offset_ptr_elem => |node_off| {1862 .node_offset_ptr_elem => |node_off| {
1871 const tree = try src_loc.file_scope.getTree(gpa);1863 const tree = try src_loc.file_scope.getTree(gpa);
1872 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1864 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18731865
1874 const full = tree.fullPtrType(parent_node).?;1866 const full = tree.fullPtrType(parent_node).?;
1875 return nodeToSpan(tree, full.ast.child_type);1867 return tree.nodeToSpan(full.ast.child_type);
1876 },1868 },
1877 .node_offset_ptr_sentinel => |node_off| {1869 .node_offset_ptr_sentinel => |node_off| {
1878 const tree = try src_loc.file_scope.getTree(gpa);1870 const tree = try src_loc.file_scope.getTree(gpa);
1879 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1871 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18801872
1881 const full = tree.fullPtrType(parent_node).?;1873 const full = tree.fullPtrType(parent_node).?;
1882 return nodeToSpan(tree, full.ast.sentinel);1874 return tree.nodeToSpan(full.ast.sentinel);
1883 },1875 },
1884 .node_offset_ptr_align => |node_off| {1876 .node_offset_ptr_align => |node_off| {
1885 const tree = try src_loc.file_scope.getTree(gpa);1877 const tree = try src_loc.file_scope.getTree(gpa);
1886 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1878 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18871879
1888 const full = tree.fullPtrType(parent_node).?;1880 const full = tree.fullPtrType(parent_node).?;
1889 return nodeToSpan(tree, full.ast.align_node);1881 return tree.nodeToSpan(full.ast.align_node);
1890 },1882 },
1891 .node_offset_ptr_addrspace => |node_off| {1883 .node_offset_ptr_addrspace => |node_off| {
1892 const tree = try src_loc.file_scope.getTree(gpa);1884 const tree = try src_loc.file_scope.getTree(gpa);
1893 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1885 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
18941886
1895 const full = tree.fullPtrType(parent_node).?;1887 const full = tree.fullPtrType(parent_node).?;
1896 return nodeToSpan(tree, full.ast.addrspace_node);1888 return tree.nodeToSpan(full.ast.addrspace_node);
1897 },1889 },
1898 .node_offset_ptr_bitoffset => |node_off| {1890 .node_offset_ptr_bitoffset => |node_off| {
1899 const tree = try src_loc.file_scope.getTree(gpa);1891 const tree = try src_loc.file_scope.getTree(gpa);
1900 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1892 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
19011893
1902 const full = tree.fullPtrType(parent_node).?;1894 const full = tree.fullPtrType(parent_node).?;
1903 return nodeToSpan(tree, full.ast.bit_range_start);1895 return tree.nodeToSpan(full.ast.bit_range_start);
1904 },1896 },
1905 .node_offset_ptr_hostsize => |node_off| {1897 .node_offset_ptr_hostsize => |node_off| {
1906 const tree = try src_loc.file_scope.getTree(gpa);1898 const tree = try src_loc.file_scope.getTree(gpa);
1907 const parent_node = src_loc.declRelativeToNodeIndex(node_off);1899 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
19081900
1909 const full = tree.fullPtrType(parent_node).?;1901 const full = tree.fullPtrType(parent_node).?;
1910 return nodeToSpan(tree, full.ast.bit_range_end);1902 return tree.nodeToSpan(full.ast.bit_range_end);
1911 },1903 },
1912 .node_offset_container_tag => |node_off| {1904 .node_offset_container_tag => |node_off| {
1913 const tree = try src_loc.file_scope.getTree(gpa);1905 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1917,13 +1909,12 @@ pub const SrcLoc = struct {...@@ -1917,13 +1909,12 @@ pub const SrcLoc = struct {
1917 switch (node_tags[parent_node]) {1909 switch (node_tags[parent_node]) {
1918 .container_decl_arg, .container_decl_arg_trailing => {1910 .container_decl_arg, .container_decl_arg_trailing => {
1919 const full = tree.containerDeclArg(parent_node);1911 const full = tree.containerDeclArg(parent_node);
1920 return nodeToSpan(tree, full.ast.arg);1912 return tree.nodeToSpan(full.ast.arg);
1921 },1913 },
1922 .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {1914 .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
1923 const full = tree.taggedUnionEnumTag(parent_node);1915 const full = tree.taggedUnionEnumTag(parent_node);
19241916
1925 return tokensToSpan(1917 return tree.tokensToSpan(
1926 tree,
1927 tree.firstToken(full.ast.arg) - 2,1918 tree.firstToken(full.ast.arg) - 2,
1928 tree.lastToken(full.ast.arg) + 1,1919 tree.lastToken(full.ast.arg) + 1,
1929 tree.nodes.items(.main_token)[full.ast.arg],1920 tree.nodes.items(.main_token)[full.ast.arg],
...@@ -1942,7 +1933,7 @@ pub const SrcLoc = struct {...@@ -1942,7 +1933,7 @@ pub const SrcLoc = struct {
1942 .container_field_init => tree.containerFieldInit(parent_node),1933 .container_field_init => tree.containerFieldInit(parent_node),
1943 else => unreachable,1934 else => unreachable,
1944 };1935 };
1945 return nodeToSpan(tree, full.ast.value_expr);1936 return tree.nodeToSpan(full.ast.value_expr);
1946 },1937 },
1947 .node_offset_init_ty => |node_off| {1938 .node_offset_init_ty => |node_off| {
1948 const tree = try src_loc.file_scope.getTree(gpa);1939 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1950,7 +1941,7 @@ pub const SrcLoc = struct {...@@ -1950,7 +1941,7 @@ pub const SrcLoc = struct {
19501941
1951 var buf: [2]Ast.Node.Index = undefined;1942 var buf: [2]Ast.Node.Index = undefined;
1952 const full = tree.fullArrayInit(&buf, parent_node).?;1943 const full = tree.fullArrayInit(&buf, parent_node).?;
1953 return nodeToSpan(tree, full.ast.type_expr);1944 return tree.nodeToSpan(full.ast.type_expr);
1954 },1945 },
1955 .node_offset_store_ptr => |node_off| {1946 .node_offset_store_ptr => |node_off| {
1956 const tree = try src_loc.file_scope.getTree(gpa);1947 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1960,9 +1951,9 @@ pub const SrcLoc = struct {...@@ -1960,9 +1951,9 @@ pub const SrcLoc = struct {
19601951
1961 switch (node_tags[node]) {1952 switch (node_tags[node]) {
1962 .assign => {1953 .assign => {
1963 return nodeToSpan(tree, node_datas[node].lhs);1954 return tree.nodeToSpan(node_datas[node].lhs);
1964 },1955 },
1965 else => return nodeToSpan(tree, node),1956 else => return tree.nodeToSpan(node),
1966 }1957 }
1967 },1958 },
1968 .node_offset_store_operand => |node_off| {1959 .node_offset_store_operand => |node_off| {
...@@ -1973,9 +1964,9 @@ pub const SrcLoc = struct {...@@ -1973,9 +1964,9 @@ pub const SrcLoc = struct {
19731964
1974 switch (node_tags[node]) {1965 switch (node_tags[node]) {
1975 .assign => {1966 .assign => {
1976 return nodeToSpan(tree, node_datas[node].rhs);1967 return tree.nodeToSpan(node_datas[node].rhs);
1977 },1968 },
1978 else => return nodeToSpan(tree, node),1969 else => return tree.nodeToSpan(node),
1979 }1970 }
1980 },1971 },
1981 .node_offset_return_operand => |node_off| {1972 .node_offset_return_operand => |node_off| {
...@@ -1984,9 +1975,9 @@ pub const SrcLoc = struct {...@@ -1984,9 +1975,9 @@ pub const SrcLoc = struct {
1984 const node_tags = tree.nodes.items(.tag);1975 const node_tags = tree.nodes.items(.tag);
1985 const node_datas = tree.nodes.items(.data);1976 const node_datas = tree.nodes.items(.data);
1986 if (node_tags[node] == .@"return" and node_datas[node].lhs != 0) {1977 if (node_tags[node] == .@"return" and node_datas[node].lhs != 0) {
1987 return nodeToSpan(tree, node_datas[node].lhs);1978 return tree.nodeToSpan(node_datas[node].lhs);
1988 }1979 }
1989 return nodeToSpan(tree, node);1980 return tree.nodeToSpan(node);
1990 },1981 },
1991 }1982 }
1992 }1983 }
...@@ -2010,40 +2001,7 @@ pub const SrcLoc = struct {...@@ -2010,40 +2001,7 @@ pub const SrcLoc = struct {
2010 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],2001 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],
2011 else => unreachable,2002 else => unreachable,
2012 };2003 };
2013 return nodeToSpan(tree, param);2004 return tree.nodeToSpan(param);
2014 }
2015
2016 pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
2017 return tokensToSpan(
2018 tree,
2019 tree.firstToken(node),
2020 tree.lastToken(node),
2021 tree.nodes.items(.main_token)[node],
2022 );
2023 }
2024
2025 fn tokenToSpan(tree: *const Ast, token: Ast.TokenIndex) Span {
2026 return tokensToSpan(tree, token, token, token);
2027 }
2028
2029 fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
2030 const token_starts = tree.tokens.items(.start);
2031 var start_tok = start;
2032 var end_tok = end;
2033
2034 if (tree.tokensOnSameLine(start, end)) {
2035 // do nothing
2036 } else if (tree.tokensOnSameLine(start, main)) {
2037 end_tok = main;
2038 } else if (tree.tokensOnSameLine(main, end)) {
2039 start_tok = main;
2040 } else {
2041 start_tok = main;
2042 end_tok = main;
2043 }
2044 const start_off = token_starts[start_tok];
2045 const end_off = token_starts[end_tok] + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
2046 return Span{ .start = start_off, .end = end_off, .main = token_starts[main] };
2047 }2005 }
2048};2006};
20492007
src/Package/Fetch.zig+1-2
...@@ -592,7 +592,7 @@ fn loadManifest(f: *Fetch, pkg_root: Package.Path) RunError!void {...@@ -592,7 +592,7 @@ fn loadManifest(f: *Fetch, pkg_root: Package.Path) RunError!void {
592592
593 if (ast.errors.len > 0) {593 if (ast.errors.len > 0) {
594 const file_path = try std.fmt.allocPrint(arena, "{}" ++ Manifest.basename, .{pkg_root});594 const file_path = try std.fmt.allocPrint(arena, "{}" ++ Manifest.basename, .{pkg_root});
595 try main.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);595 try std.zig.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
596 return error.FetchFailed;596 return error.FetchFailed;
597 }597 }
598598
...@@ -1690,7 +1690,6 @@ const Cache = std.Build.Cache;...@@ -1690,7 +1690,6 @@ const Cache = std.Build.Cache;
1690const ThreadPool = std.Thread.Pool;1690const ThreadPool = std.Thread.Pool;
1691const WaitGroup = std.Thread.WaitGroup;1691const WaitGroup = std.Thread.WaitGroup;
1692const Fetch = @This();1692const Fetch = @This();
1693const main = @import("../main.zig");
1694const git = @import("Fetch/git.zig");1693const git = @import("Fetch/git.zig");
1695const Package = @import("../Package.zig");1694const Package = @import("../Package.zig");
1696const Manifest = Package.Manifest;1695const Manifest = Package.Manifest;
src/main.zig+134-475
...@@ -8,6 +8,7 @@ const process = std.process;...@@ -8,6 +8,7 @@ const process = std.process;
8const Allocator = mem.Allocator;8const Allocator = mem.Allocator;
9const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
10const Ast = std.zig.Ast;10const Ast = std.zig.Ast;
11const Color = std.zig.Color;
11const warn = std.log.warn;12const warn = std.log.warn;
12const ThreadPool = std.Thread.Pool;13const ThreadPool = std.Thread.Pool;
13const cleanExit = std.process.cleanExit;14const cleanExit = std.process.cleanExit;
...@@ -66,18 +67,8 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {...@@ -66,18 +67,8 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
66 process.exit(1);67 process.exit(1);
67}68}
6869
69/// There are many assumptions in the entire codebase that Zig source files can
70/// be byte-indexed with a u32 integer.
71const max_src_size = std.math.maxInt(u32);
72
73const debug_extensions_enabled = builtin.mode == .Debug;70const debug_extensions_enabled = builtin.mode == .Debug;
7471
75const Color = enum {
76 auto,
77 off,
78 on,
79};
80
81const normal_usage =72const normal_usage =
82 \\Usage: zig [command] [options]73 \\Usage: zig [command] [options]
83 \\74 \\
...@@ -4501,7 +4492,7 @@ fn updateModule(comp: *Compilation, color: Color) !void {...@@ -4501,7 +4492,7 @@ fn updateModule(comp: *Compilation, color: Color) !void {
4501 defer errors.deinit(comp.gpa);4492 defer errors.deinit(comp.gpa);
45024493
4503 if (errors.errorMessageCount() > 0) {4494 if (errors.errorMessageCount() > 0) {
4504 errors.renderToStdErr(renderOptions(color));4495 errors.renderToStdErr(color.renderOptions());
4505 return error.SemanticAnalyzeFail;4496 return error.SemanticAnalyzeFail;
4506 }4497 }
4507}4498}
...@@ -4601,7 +4592,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati...@@ -4601,7 +4592,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
4601 p.errors = errors;4592 p.errors = errors;
4602 return;4593 return;
4603 } else {4594 } else {
4604 errors.renderToStdErr(renderOptions(color));4595 errors.renderToStdErr(color.renderOptions());
4605 process.exit(1);4596 process.exit(1);
4606 }4597 }
4607 },4598 },
...@@ -5528,7 +5519,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5528,7 +5519,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
55285519
5529 if (fetch.error_bundle.root_list.items.len > 0) {5520 if (fetch.error_bundle.root_list.items.len > 0) {
5530 var errors = try fetch.error_bundle.toOwnedBundle("");5521 var errors = try fetch.error_bundle.toOwnedBundle("");
5531 errors.renderToStdErr(renderOptions(color));5522 errors.renderToStdErr(color.renderOptions());
5532 process.exit(1);5523 process.exit(1);
5533 }5524 }
55345525
...@@ -5719,470 +5710,155 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5719,470 +5710,155 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5719 }5710 }
5720}5711}
57215712
5722fn readSourceFileToEndAlloc(5713fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5723 allocator: Allocator,5714 const color: Color = .auto;
5724 input: *const fs.File,
5725 size_hint: ?usize,
5726) ![:0]u8 {
5727 const source_code = input.readToEndAllocOptions(
5728 allocator,
5729 max_src_size,
5730 size_hint,
5731 @alignOf(u16),
5732 0,
5733 ) catch |err| switch (err) {
5734 error.ConnectionResetByPeer => unreachable,
5735 error.ConnectionTimedOut => unreachable,
5736 error.NotOpenForReading => unreachable,
5737 else => |e| return e,
5738 };
5739 errdefer allocator.free(source_code);
57405715
5741 // Detect unsupported file types with their Byte Order Mark5716 const target_query: std.Target.Query = .{};
5742 const unsupported_boms = [_][]const u8{5717 const resolved_target: Package.Module.ResolvedTarget = .{
5743 "\xff\xfe\x00\x00", // UTF-32 little endian5718 .result = resolveTargetQueryOrFatal(target_query),
5744 "\xfe\xff\x00\x00", // UTF-32 big endian5719 .is_native_os = true,
5745 "\xfe\xff", // UTF-16 big endian5720 .is_native_abi = true,
5746 };5721 };
5747 for (unsupported_boms) |bom| {
5748 if (mem.startsWith(u8, source_code, bom)) {
5749 return error.UnsupportedEncoding;
5750 }
5751 }
57525722
5753 // If the file starts with a UTF-16 little endian BOM, translate it to UTF-85723 const exe_basename = try std.zig.binNameAlloc(arena, .{
5754 if (mem.startsWith(u8, source_code, "\xff\xfe")) {5724 .root_name = "fmt",
5755 const source_code_utf16_le = mem.bytesAsSlice(u16, source_code);5725 .target = resolved_target.result,
5756 const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {5726 .output_mode = .Exe,
5757 error.DanglingSurrogateHalf => error.UnsupportedEncoding,5727 });
5758 error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,5728 const emit_bin: Compilation.EmitLoc = .{
5759 error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,5729 .directory = null, // Use the global zig-cache.
5760 else => |e| return e,5730 .basename = exe_basename,
5761 };5731 };
57625732
5763 allocator.free(source_code);5733 const self_exe_path = introspect.findZigExePath(arena) catch |err| {
5764 return source_code_utf8;5734 fatal("unable to find self exe path: {s}", .{@errorName(err)});
5765 }5735 };
57665736
5767 return source_code;5737 const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
5768}5738 const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
57695739
5770const usage_fmt =5740 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
5771 \\Usage: zig fmt [file]...5741 .path = lib_dir,
5772 \\5742 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5773 \\ Formats the input files and modifies them in-place.5743 fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
5774 \\ Arguments can be files or directories, which are searched5744 },
5775 \\ recursively.5745 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
5776 \\5746 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
5777 \\Options:5747 };
5778 \\ -h, --help Print this help and exit5748 defer zig_lib_directory.handle.close();
5779 \\ --color [auto|off|on] Enable or disable colored error messages
5780 \\ --stdin Format code from stdin; output to stdout
5781 \\ --check List non-conforming files and exit with an error
5782 \\ if the list is non-empty
5783 \\ --ast-check Run zig ast-check on every file
5784 \\ --exclude [file] Exclude file or directory from formatting
5785 \\
5786 \\
5787;
57885749
5789const Fmt = struct {5750 var global_cache_directory: Compilation.Directory = l: {
5790 seen: SeenMap,5751 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
5791 any_error: bool,5752 break :l .{
5792 check_ast: bool,5753 .handle = try fs.cwd().makeOpenPath(p, .{}),
5793 color: Color,5754 .path = p,
5794 gpa: Allocator,5755 };
5795 arena: Allocator,5756 };
5796 out_buffer: std.ArrayList(u8),5757 defer global_cache_directory.handle.close();
57975758
5798 const SeenMap = std.AutoHashMap(fs.File.INode, void);5759 var thread_pool: ThreadPool = undefined;
5799};5760 try thread_pool.init(.{ .allocator = gpa });
5761 defer thread_pool.deinit();
58005762
5801fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {5763 var child_argv: std.ArrayListUnmanaged([]const u8) = .{};
5802 var color: Color = .auto;5764 try child_argv.ensureUnusedCapacity(arena, args.len + 1);
5803 var stdin_flag: bool = false;
5804 var check_flag: bool = false;
5805 var check_ast_flag: bool = false;
5806 var input_files = ArrayList([]const u8).init(gpa);
5807 defer input_files.deinit();
5808 var excluded_files = ArrayList([]const u8).init(gpa);
5809 defer excluded_files.deinit();
58105765
5766 // We want to release all the locks before executing the child process, so we make a nice
5767 // big block here to ensure the cleanup gets run when we extract out our argv.
5811 {5768 {
5812 var i: usize = 0;5769 const main_mod_paths: Package.Module.CreateOptions.Paths = .{
5813 while (i < args.len) : (i += 1) {5770 .root = .{
5814 const arg = args[i];5771 .root_dir = zig_lib_directory,
5815 if (mem.startsWith(u8, arg, "-")) {5772 .sub_path = "std/zig",
5816 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {5773 },
5817 const stdout = io.getStdOut().writer();5774 .root_src_path = "fmt.zig",
5818 try stdout.writeAll(usage_fmt);
5819 return cleanExit();
5820 } else if (mem.eql(u8, arg, "--color")) {
5821 if (i + 1 >= args.len) {
5822 fatal("expected [auto|on|off] after --color", .{});
5823 }
5824 i += 1;
5825 const next_arg = args[i];
5826 color = std.meta.stringToEnum(Color, next_arg) orelse {
5827 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
5828 };
5829 } else if (mem.eql(u8, arg, "--stdin")) {
5830 stdin_flag = true;
5831 } else if (mem.eql(u8, arg, "--check")) {
5832 check_flag = true;
5833 } else if (mem.eql(u8, arg, "--ast-check")) {
5834 check_ast_flag = true;
5835 } else if (mem.eql(u8, arg, "--exclude")) {
5836 if (i + 1 >= args.len) {
5837 fatal("expected parameter after --exclude", .{});
5838 }
5839 i += 1;
5840 const next_arg = args[i];
5841 try excluded_files.append(next_arg);
5842 } else {
5843 fatal("unrecognized parameter: '{s}'", .{arg});
5844 }
5845 } else {
5846 try input_files.append(arg);
5847 }
5848 }
5849 }
5850
5851 if (stdin_flag) {
5852 if (input_files.items.len != 0) {
5853 fatal("cannot use --stdin with positional arguments", .{});
5854 }
5855
5856 const stdin = io.getStdIn();
5857 const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| {
5858 fatal("unable to read stdin: {}", .{err});
5859 };
5860 defer gpa.free(source_code);
5861
5862 var tree = Ast.parse(gpa, source_code, .zig) catch |err| {
5863 fatal("error parsing stdin: {}", .{err});
5864 };5775 };
5865 defer tree.deinit(gpa);
5866
5867 if (check_ast_flag) {
5868 var file: Module.File = .{
5869 .status = .never_loaded,
5870 .source_loaded = true,
5871 .zir_loaded = false,
5872 .sub_file_path = "<stdin>",
5873 .source = source_code,
5874 .stat = undefined,
5875 .tree = tree,
5876 .tree_loaded = true,
5877 .zir = undefined,
5878 .mod = undefined,
5879 .root_decl = .none,
5880 };
5881
5882 file.mod = try Package.Module.createLimited(arena, .{
5883 .root = Package.Path.cwd(),
5884 .root_src_path = file.sub_file_path,
5885 .fully_qualified_name = "root",
5886 });
5887
5888 file.zir = try AstGen.generate(gpa, file.tree);
5889 file.zir_loaded = true;
5890 defer file.zir.deinit(gpa);
5891
5892 if (file.zir.hasCompileErrors()) {
5893 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5894 try wip_errors.init(gpa);
5895 defer wip_errors.deinit();
5896 try Compilation.addZirErrorMessages(&wip_errors, &file);
5897 var error_bundle = try wip_errors.toOwnedBundle("");
5898 defer error_bundle.deinit(gpa);
5899 error_bundle.renderToStdErr(renderOptions(color));
5900 process.exit(2);
5901 }
5902 } else if (tree.errors.len != 0) {
5903 try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
5904 process.exit(2);
5905 }
5906 const formatted = try tree.render(gpa);
5907 defer gpa.free(formatted);
5908
5909 if (check_flag) {
5910 const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
5911 process.exit(code);
5912 }
59135776
5914 return io.getStdOut().writeAll(formatted);5777 const config = try Compilation.Config.resolve(.{
5915 }5778 .output_mode = .Exe,
5779 .root_optimize_mode = .ReleaseFast,
5780 .resolved_target = resolved_target,
5781 .have_zcu = true,
5782 .emit_bin = true,
5783 .is_test = false,
5784 });
59165785
5917 if (input_files.items.len == 0) {5786 const root_mod = try Package.Module.create(arena, .{
5918 fatal("expected at least one source file argument", .{});5787 .global_cache_directory = global_cache_directory,
5919 }5788 .paths = main_mod_paths,
5789 .fully_qualified_name = "root",
5790 .cc_argv = &.{},
5791 .inherited = .{
5792 .resolved_target = resolved_target,
5793 .optimize_mode = .ReleaseFast,
5794 },
5795 .global = config,
5796 .parent = null,
5797 .builtin_mod = null,
5798 });
59205799
5921 var fmt = Fmt{5800 const comp = Compilation.create(gpa, arena, .{
5922 .gpa = gpa,5801 .zig_lib_directory = zig_lib_directory,
5923 .arena = arena,5802 .local_cache_directory = global_cache_directory,
5924 .seen = Fmt.SeenMap.init(gpa),5803 .global_cache_directory = global_cache_directory,
5925 .any_error = false,5804 .root_name = "fmt",
5926 .check_ast = check_ast_flag,5805 .config = config,
5927 .color = color,5806 .root_mod = root_mod,
5928 .out_buffer = std.ArrayList(u8).init(gpa),5807 .main_mod = root_mod,
5929 };5808 .emit_bin = emit_bin,
5930 defer fmt.seen.deinit();5809 .emit_h = null,
5931 defer fmt.out_buffer.deinit();5810 .self_exe_path = self_exe_path,
5811 .thread_pool = &thread_pool,
5812 .cache_mode = .whole,
5813 }) catch |err| {
5814 fatal("unable to create compilation: {s}", .{@errorName(err)});
5815 };
5816 defer comp.destroy();
59325817
5933 // Mark any excluded files/directories as already seen,5818 updateModule(comp, color) catch |err| switch (err) {
5934 // so that they are skipped later during actual processing5819 error.SemanticAnalyzeFail => process.exit(2),
5935 for (excluded_files.items) |file_path| {
5936 const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
5937 error.FileNotFound => continue,
5938 // On Windows, statFile does not work for directories
5939 error.IsDir => dir: {
5940 var dir = try fs.cwd().openDir(file_path, .{});
5941 defer dir.close();
5942 break :dir try dir.stat();
5943 },
5944 else => |e| return e,5820 else => |e| return e,
5945 };5821 };
5946 try fmt.seen.put(stat.inode, {});
5947 }
5948
5949 for (input_files.items) |file_path| {
5950 try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
5951 }
5952 if (fmt.any_error) {
5953 process.exit(1);
5954 }
5955}
5956
5957const FmtError = error{
5958 SystemResources,
5959 OperationAborted,
5960 IoPending,
5961 BrokenPipe,
5962 Unexpected,
5963 WouldBlock,
5964 FileClosed,
5965 DestinationAddressRequired,
5966 DiskQuota,
5967 FileTooBig,
5968 InputOutput,
5969 NoSpaceLeft,
5970 AccessDenied,
5971 OutOfMemory,
5972 RenameAcrossMountPoints,
5973 ReadOnlyFileSystem,
5974 LinkQuotaExceeded,
5975 FileBusy,
5976 EndOfStream,
5977 Unseekable,
5978 NotOpenForWriting,
5979 UnsupportedEncoding,
5980 ConnectionResetByPeer,
5981 SocketNotConnected,
5982 LockViolation,
5983 NetNameDeleted,
5984 InvalidArgument,
5985} || fs.File.OpenError;
5986
5987fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
5988 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
5989 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
5990 else => {
5991 warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
5992 fmt.any_error = true;
5993 return;
5994 },
5995 };
5996}
5997
5998fn fmtPathDir(
5999 fmt: *Fmt,
6000 file_path: []const u8,
6001 check_mode: bool,
6002 parent_dir: fs.Dir,
6003 parent_sub_path: []const u8,
6004) FmtError!void {
6005 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
6006 defer dir.close();
6007
6008 const stat = try dir.stat();
6009 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
6010
6011 var dir_it = dir.iterate();
6012 while (try dir_it.next()) |entry| {
6013 const is_dir = entry.kind == .directory;
6014
6015 if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
6016
6017 if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
6018 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
6019 defer fmt.gpa.free(full_path);
6020
6021 if (is_dir) {
6022 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
6023 } else {
6024 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
6025 warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
6026 fmt.any_error = true;
6027 return;
6028 };
6029 }
6030 }
6031 }
6032}
6033
6034fn fmtPathFile(
6035 fmt: *Fmt,
6036 file_path: []const u8,
6037 check_mode: bool,
6038 dir: fs.Dir,
6039 sub_path: []const u8,
6040) FmtError!void {
6041 const source_file = try dir.openFile(sub_path, .{});
6042 var file_closed = false;
6043 errdefer if (!file_closed) source_file.close();
6044
6045 const stat = try source_file.stat();
6046
6047 if (stat.kind == .directory)
6048 return error.IsDir;
6049
6050 const gpa = fmt.gpa;
6051 const source_code = try readSourceFileToEndAlloc(
6052 gpa,
6053 &source_file,
6054 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
6055 );
6056 defer gpa.free(source_code);
6057
6058 source_file.close();
6059 file_closed = true;
6060
6061 // Add to set after no longer possible to get error.IsDir.
6062 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
6063
6064 var tree = try Ast.parse(gpa, source_code, .zig);
6065 defer tree.deinit(gpa);
60665822
6067 if (tree.errors.len != 0) {5823 const fmt_exe = try global_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
6068 try printAstErrorsToStderr(gpa, tree, file_path, fmt.color);5824 child_argv.appendAssumeCapacity(fmt_exe);
6069 fmt.any_error = true;
6070 return;
6071 }5825 }
60725826
6073 if (fmt.check_ast) {5827 child_argv.appendSliceAssumeCapacity(args);
6074 var file: Module.File = .{
6075 .status = .never_loaded,
6076 .source_loaded = true,
6077 .zir_loaded = false,
6078 .sub_file_path = file_path,
6079 .source = source_code,
6080 .stat = .{
6081 .size = stat.size,
6082 .inode = stat.inode,
6083 .mtime = stat.mtime,
6084 },
6085 .tree = tree,
6086 .tree_loaded = true,
6087 .zir = undefined,
6088 .mod = undefined,
6089 .root_decl = .none,
6090 };
60915828
6092 file.mod = try Package.Module.createLimited(fmt.arena, .{5829 if (process.can_execv) {
6093 .root = Package.Path.cwd(),5830 const err = process.execv(gpa, child_argv.items);
6094 .root_src_path = file.sub_file_path,5831 const cmd = try std.mem.join(arena, " ", child_argv.items);
6095 .fully_qualified_name = "root",5832 fatal("the following command failed to execve with '{s}':\n{s}", .{
5833 @errorName(err),
5834 cmd,
6096 });5835 });
6097
6098 if (stat.size > max_src_size)
6099 return error.FileTooBig;
6100
6101 file.zir = try AstGen.generate(gpa, file.tree);
6102 file.zir_loaded = true;
6103 defer file.zir.deinit(gpa);
6104
6105 if (file.zir.hasCompileErrors()) {
6106 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6107 try wip_errors.init(gpa);
6108 defer wip_errors.deinit();
6109 try Compilation.addZirErrorMessages(&wip_errors, &file);
6110 var error_bundle = try wip_errors.toOwnedBundle("");
6111 defer error_bundle.deinit(gpa);
6112 error_bundle.renderToStdErr(renderOptions(fmt.color));
6113 fmt.any_error = true;
6114 }
6115 }5836 }
61165837
6117 // As a heuristic, we make enough capacity for the same as the input source.5838 if (!process.can_spawn) {
6118 fmt.out_buffer.shrinkRetainingCapacity(0);5839 const cmd = try std.mem.join(arena, " ", child_argv.items);
6119 try fmt.out_buffer.ensureTotalCapacity(source_code.len);5840 fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
61205841 @tagName(builtin.os.tag), cmd,
6121 try tree.renderToArrayList(&fmt.out_buffer, .{});5842 });
6122 if (mem.eql(u8, fmt.out_buffer.items, source_code))
6123 return;
6124
6125 if (check_mode) {
6126 const stdout = io.getStdOut().writer();
6127 try stdout.print("{s}\n", .{file_path});
6128 fmt.any_error = true;
6129 } else {
6130 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
6131 defer af.deinit();
6132
6133 try af.file.writeAll(fmt.out_buffer.items);
6134 try af.finish();
6135 const stdout = io.getStdOut().writer();
6136 try stdout.print("{s}\n", .{file_path});
6137 }5843 }
6138}
6139
6140fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
6141 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6142 try wip_errors.init(gpa);
6143 defer wip_errors.deinit();
61445844
6145 try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);5845 var child = std.ChildProcess.init(child_argv.items, gpa);
5846 child.stdin_behavior = .Inherit;
5847 child.stdout_behavior = .Inherit;
5848 child.stderr_behavior = .Inherit;
61465849
6147 var error_bundle = try wip_errors.toOwnedBundle("");5850 const term = try child.spawnAndWait();
6148 defer error_bundle.deinit(gpa);5851 switch (term) {
6149 error_bundle.renderToStdErr(renderOptions(color));5852 .Exited => |code| {
6150}5853 if (code == 0) return cleanExit();
61515854 const cmd = try std.mem.join(arena, " ", child_argv.items);
6152pub fn putAstErrorsIntoBundle(5855 fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
6153 gpa: Allocator,
6154 tree: Ast,
6155 path: []const u8,
6156 wip_errors: *std.zig.ErrorBundle.Wip,
6157) Allocator.Error!void {
6158 var file: Module.File = .{
6159 .status = .never_loaded,
6160 .source_loaded = true,
6161 .zir_loaded = false,
6162 .sub_file_path = path,
6163 .source = tree.source,
6164 .stat = .{
6165 .size = 0,
6166 .inode = 0,
6167 .mtime = 0,
6168 },5856 },
6169 .tree = tree,5857 else => {
6170 .tree_loaded = true,5858 const cmd = try std.mem.join(arena, " ", child_argv.items);
6171 .zir = undefined,5859 fatal("the following build command crashed:\n{s}", .{cmd});
6172 .mod = try Package.Module.createLimited(gpa, .{5860 },
6173 .root = Package.Path.cwd(),5861 }
6174 .root_src_path = path,
6175 .fully_qualified_name = "root",
6176 }),
6177 .root_decl = .none,
6178 };
6179 defer gpa.destroy(file.mod);
6180
6181 file.zir = try AstGen.generate(gpa, file.tree);
6182 file.zir_loaded = true;
6183 defer file.zir.deinit(gpa);
6184
6185 try Compilation.addZirErrorMessages(wip_errors, &file);
6186}5862}
61875863
6188const info_zen =5864const info_zen =
...@@ -6710,7 +6386,7 @@ fn cmdAstCheck(...@@ -6710,7 +6386,7 @@ fn cmdAstCheck(
67106386
6711 const stat = try f.stat();6387 const stat = try f.stat();
67126388
6713 if (stat.size > max_src_size)6389 if (stat.size > std.zig.max_src_size)
6714 return error.FileTooBig;6390 return error.FileTooBig;
67156391
6716 const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);6392 const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
...@@ -6728,7 +6404,7 @@ fn cmdAstCheck(...@@ -6728,7 +6404,7 @@ fn cmdAstCheck(
6728 };6404 };
6729 } else {6405 } else {
6730 const stdin = io.getStdIn();6406 const stdin = io.getStdIn();
6731 const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| {6407 const source = std.zig.readSourceFileToEndAlloc(arena, stdin, null) catch |err| {
6732 fatal("unable to read stdin: {}", .{err});6408 fatal("unable to read stdin: {}", .{err});
6733 };6409 };
6734 file.sub_file_path = "<stdin>";6410 file.sub_file_path = "<stdin>";
...@@ -6758,7 +6434,7 @@ fn cmdAstCheck(...@@ -6758,7 +6434,7 @@ fn cmdAstCheck(
6758 try Compilation.addZirErrorMessages(&wip_errors, &file);6434 try Compilation.addZirErrorMessages(&wip_errors, &file);
6759 var error_bundle = try wip_errors.toOwnedBundle("");6435 var error_bundle = try wip_errors.toOwnedBundle("");
6760 defer error_bundle.deinit(gpa);6436 defer error_bundle.deinit(gpa);
6761 error_bundle.renderToStdErr(renderOptions(color));6437 error_bundle.renderToStdErr(color.renderOptions());
6762 process.exit(1);6438 process.exit(1);
6763 }6439 }
67646440
...@@ -6889,7 +6565,7 @@ fn cmdChangelist(...@@ -6889,7 +6565,7 @@ fn cmdChangelist(
68896565
6890 const stat = try f.stat();6566 const stat = try f.stat();
68916567
6892 if (stat.size > max_src_size)6568 if (stat.size > std.zig.max_src_size)
6893 return error.FileTooBig;6569 return error.FileTooBig;
68946570
6895 var file: Module.File = .{6571 var file: Module.File = .{
...@@ -6938,7 +6614,7 @@ fn cmdChangelist(...@@ -6938,7 +6614,7 @@ fn cmdChangelist(
6938 try Compilation.addZirErrorMessages(&wip_errors, &file);6614 try Compilation.addZirErrorMessages(&wip_errors, &file);
6939 var error_bundle = try wip_errors.toOwnedBundle("");6615 var error_bundle = try wip_errors.toOwnedBundle("");
6940 defer error_bundle.deinit(gpa);6616 defer error_bundle.deinit(gpa);
6941 error_bundle.renderToStdErr(renderOptions(color));6617 error_bundle.renderToStdErr(color.renderOptions());
6942 process.exit(1);6618 process.exit(1);
6943 }6619 }
69446620
...@@ -6949,7 +6625,7 @@ fn cmdChangelist(...@@ -6949,7 +6625,7 @@ fn cmdChangelist(
69496625
6950 const new_stat = try new_f.stat();6626 const new_stat = try new_f.stat();
69516627
6952 if (new_stat.size > max_src_size)6628 if (new_stat.size > std.zig.max_src_size)
6953 return error.FileTooBig;6629 return error.FileTooBig;
69546630
6955 const new_source = try arena.allocSentinel(u8, @as(usize, @intCast(new_stat.size)), 0);6631 const new_source = try arena.allocSentinel(u8, @as(usize, @intCast(new_stat.size)), 0);
...@@ -6973,7 +6649,7 @@ fn cmdChangelist(...@@ -6973,7 +6649,7 @@ fn cmdChangelist(
6973 try Compilation.addZirErrorMessages(&wip_errors, &file);6649 try Compilation.addZirErrorMessages(&wip_errors, &file);
6974 var error_bundle = try wip_errors.toOwnedBundle("");6650 var error_bundle = try wip_errors.toOwnedBundle("");
6975 defer error_bundle.deinit(gpa);6651 defer error_bundle.deinit(gpa);
6976 error_bundle.renderToStdErr(renderOptions(color));6652 error_bundle.renderToStdErr(color.renderOptions());
6977 process.exit(1);6653 process.exit(1);
6978 }6654 }
69796655
...@@ -7241,23 +6917,6 @@ const ClangSearchSanitizer = struct {...@@ -7241,23 +6917,6 @@ const ClangSearchSanitizer = struct {
7241 };6917 };
7242};6918};
72436919
7244fn get_tty_conf(color: Color) std.io.tty.Config {
7245 return switch (color) {
7246 .auto => std.io.tty.detectConfig(std.io.getStdErr()),
7247 .on => .escape_codes,
7248 .off => .no_color,
7249 };
7250}
7251
7252fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
7253 const ttyconf = get_tty_conf(color);
7254 return .{
7255 .ttyconf = ttyconf,
7256 .include_source_line = ttyconf != .no_color,
7257 .include_reference_trace = ttyconf != .no_color,
7258 };
7259}
7260
7261fn accessLibPath(6920fn accessLibPath(
7262 test_path: *std.ArrayList(u8),6921 test_path: *std.ArrayList(u8),
7263 checked_paths: *std.ArrayList(u8),6922 checked_paths: *std.ArrayList(u8),
...@@ -7498,7 +7157,7 @@ fn cmdFetch(...@@ -7498,7 +7157,7 @@ fn cmdFetch(
74987157
7499 if (fetch.error_bundle.root_list.items.len > 0) {7158 if (fetch.error_bundle.root_list.items.len > 0) {
7500 var errors = try fetch.error_bundle.toOwnedBundle("");7159 var errors = try fetch.error_bundle.toOwnedBundle("");
7501 errors.renderToStdErr(renderOptions(color));7160 errors.renderToStdErr(color.renderOptions());
7502 process.exit(1);7161 process.exit(1);
7503 }7162 }
75047163
...@@ -7790,7 +7449,7 @@ fn loadManifest(...@@ -7790,7 +7449,7 @@ fn loadManifest(
7790 errdefer ast.deinit(gpa);7449 errdefer ast.deinit(gpa);
77917450
7792 if (ast.errors.len > 0) {7451 if (ast.errors.len > 0) {
7793 try printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);7452 try std.zig.printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
7794 process.exit(2);7453 process.exit(2);
7795 }7454 }
77967455
...@@ -7807,7 +7466,7 @@ fn loadManifest(...@@ -7807,7 +7466,7 @@ fn loadManifest(
78077466
7808 var error_bundle = try wip_errors.toOwnedBundle("");7467 var error_bundle = try wip_errors.toOwnedBundle("");
7809 defer error_bundle.deinit(gpa);7468 defer error_bundle.deinit(gpa);
7810 error_bundle.renderToStdErr(renderOptions(options.color));7469 error_bundle.renderToStdErr(options.color.renderOptions());
78117470
7812 process.exit(2);7471 process.exit(2);
7813 }7472 }