authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-09 00:19:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-09 00:19:44-07:00
log9a2de796bd0eb047ca9bd23940004f3b25ab6625
tree473870b356590dc0631e9a809403e180190d23e1
parent0f105ea3249068441a94c0e783b3ca27a06a783b

stage2: clean up pretty printing compile errors


4 files changed, 73 insertions(+), 89 deletions(-)

lib/std/zig.zig+21-4
...@@ -31,21 +31,38 @@ pub fn hashSrc(src: []const u8) SrcHash {...@@ -31,21 +31,38 @@ pub fn hashSrc(src: []const u8) SrcHash {
31 return out;31 return out;
32}32}
3333
34pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {34pub const Loc = struct {
35 line: usize,
36 column: usize,
37 /// Does not include the trailing newline.
38 source_line: []const u8,
39};
40
41pub fn findLineColumn(source: []const u8, byte_offset: usize) Loc {
35 var line: usize = 0;42 var line: usize = 0;
36 var column: usize = 0;43 var column: usize = 0;
37 for (source[0..byte_offset]) |byte| {44 var line_start: usize = 0;
38 switch (byte) {45 var i: usize = 0;
46 while (i < byte_offset) : (i += 1) {
47 switch (source[i]) {
39 '\n' => {48 '\n' => {
40 line += 1;49 line += 1;
41 column = 0;50 column = 0;
51 line_start = i + 1;
42 },52 },
43 else => {53 else => {
44 column += 1;54 column += 1;
45 },55 },
46 }56 }
47 }57 }
48 return .{ .line = line, .column = column };58 while (i < source.len and source[i] != '\n') {
59 i += 1;
60 }
61 return .{
62 .line = line,
63 .column = column,
64 .source_line = source[line_start..i],
65 };
49}66}
5067
51pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {68pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {
src/Compilation.zig+44-84
...@@ -6,7 +6,6 @@ const Allocator = std.mem.Allocator;...@@ -6,7 +6,6 @@ const Allocator = std.mem.Allocator;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const log = std.log.scoped(.compilation);7const log = std.log.scoped(.compilation);
8const Target = std.Target;8const Target = std.Target;
9const debug = std.debug;
109
11const Value = @import("value.zig").Value;10const Value = @import("value.zig").Value;
12const Type = @import("type.zig").Type;11const Type = @import("type.zig").Type;
...@@ -267,103 +266,62 @@ pub const AllErrors = struct {...@@ -267,103 +266,62 @@ pub const AllErrors = struct {
267 list: []const Message,266 list: []const Message,
268267
269 pub const Message = union(enum) {268 pub const Message = union(enum) {
270 const MessageType = enum {
271 pub fn render(self: @This(), stderr: anytype, ttyconf: std.debug.TTY.Config) !void {
272 switch (self) {
273 .err => {
274 ttyconf.setColor(stderr, .Red);
275 try stderr.writeAll("error:");
276 },
277 .note => {
278 ttyconf.setColor(stderr, .Green);
279 try stderr.writeAll("note:");
280 },
281 }
282 ttyconf.setColor(stderr, .Reset);
283 }
284 err,
285 note
286 };
287
288 src: struct {269 src: struct {
289 msg: []const u8,270 msg: []const u8,
290 src_path: union(enum) {271 src_path: []const u8,
291 path: []const u8,
292 scope: *Module.Scope.File,
293 },
294 line: u32,272 line: u32,
295 column: u32,273 column: u32,
296 byte_offset: u32,274 byte_offset: u32,
275 /// Does not include the trailing newline.
276 source_line: ?[]const u8,
297 notes: []Message = &.{},277 notes: []Message = &.{},
298 },278 },
299 plain: struct {279 plain: struct {
300 msg: []const u8,280 msg: []const u8,
301 },281 },
302282
303 pub fn renderToStdErr(msg: Message, mod: ?*Module) !void {283 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
304 return msg.renderToStdErrInner(.err, mod);284 const stderr_mutex = std.debug.getStderrMutex();
285 const held = std.debug.getStderrMutex().acquire();
286 defer held.release();
287 const stderr = std.io.getStdErr();
288 return msg.renderToStdErrInner(ttyconf, stderr, "error", .Red) catch return;
305 }289 }
306290
307 fn renderToStdErrInner(msg: Message, kind: MessageType, mod: ?*Module) (std.fs.File.WriteError || @typeInfo(@typeInfo(@TypeOf(Module.Scope.File.getSource)).Fn.return_type.?).ErrorUnion.error_set)!void {291 fn renderToStdErrInner(
308 const ttyconf = debug.detectTTYConfig();292 msg: Message,
309 const stderr = std.io.getStdErr().writer();293 ttyconf: std.debug.TTY.Config,
294 stderr_file: std.fs.File,
295 kind: []const u8,
296 color: std.debug.TTY.Color,
297 ) anyerror!void {
298 const stderr = stderr_file.writer();
310 switch (msg) {299 switch (msg) {
311 .src => |src| {300 .src => |src| {
312 switch (src.src_path) {301 try stderr.print("{s}:{d}:{d}: ", .{
313 .path => |p| {302 src.src_path,
314 // TODO read the file and do pretty printing for c objects?303 src.line + 1,
315 try stderr.print("{s}:{d}:{d}: ", .{304 src.column + 1,
316 p,305 });
317 src.line + 1,306 ttyconf.setColor(stderr, color);
318 src.column + 1,307 try stderr.writeAll(kind);
319 });308 ttyconf.setColor(stderr, .Bold);
320 try kind.render(stderr, ttyconf);309 try stderr.print(" {s}\n", .{src.msg});
321 try stderr.print(" {s}\n", .{310 ttyconf.setColor(stderr, .Reset);
322 src.msg,311 if (src.source_line) |line| {
323 });312 try stderr.writeAll(line);
324 },313 try stderr.writeByte('\n');
325 .scope => |s| {314 try stderr.writeByteNTimes(' ', src.column);
326 const module = mod.?;315 ttyconf.setColor(stderr, .Green);
327 try stderr.print("{s}:{d}:{d}: ", .{316 try stderr.writeAll("^\n");
328 s.sub_file_path,317 ttyconf.setColor(stderr, .Reset);
329 src.line + 1,
330 src.column + 1,
331 });
332 try kind.render(stderr, ttyconf);
333 try stderr.print(" {s}\n", .{
334 src.msg,
335 });
336 const fsource = try s.getSource(module);
337 const end_pos = blk: for (fsource[src.byte_offset..]) |c, i| {
338 if (c == '\n')
339 break :blk src.byte_offset + i + 1;
340 if (c == 0)
341 break :blk fsource.len - 1;
342 } else unreachable;
343 const start_pos = blk: {
344 var i = src.byte_offset;
345 var c: u8 = fsource[i];
346 while (i > 0) : ({
347 i -= 1;
348 c = fsource[i];
349 }) {
350 if (c == '\n') break :blk i + 1;
351 }
352 break :blk 0;
353 };
354 try stderr.writeAll(fsource[start_pos..end_pos]);
355 try stderr.writeByteNTimes(' ', src.column);
356 ttyconf.setColor(stderr, .Cyan);
357 try stderr.writeAll("^\n");
358 ttyconf.setColor(stderr, .Reset);
359 },
360 }318 }
361 for (src.notes) |note| {319 for (src.notes) |note| {
362 try note.renderToStdErrInner(.note, mod);320 try note.renderToStdErrInner(ttyconf, stderr_file, "note", .Cyan);
363 }321 }
364 },322 },
365 .plain => |plain| {323 .plain => |plain| {
366 debug.print("{s}: {s}\n", .{ kind, plain.msg });324 std.debug.print("{s}: {s}\n", .{ kind, plain.msg });
367 },325 },
368 }326 }
369 }327 }
...@@ -385,30 +343,31 @@ pub const AllErrors = struct {...@@ -385,30 +343,31 @@ pub const AllErrors = struct {
385 const source = try module_note.src_loc.fileScope().getSource(module);343 const source = try module_note.src_loc.fileScope().getSource(module);
386 const byte_offset = try module_note.src_loc.byteOffset();344 const byte_offset = try module_note.src_loc.byteOffset();
387 const loc = std.zig.findLineColumn(source, byte_offset);345 const loc = std.zig.findLineColumn(source, byte_offset);
388 const fscope = module_note.src_loc.fileScope();346 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
389 note.* = .{347 note.* = .{
390 .src = .{348 .src = .{
391 // TODO this might be freed, might need to dupe the source349 .src_path = try arena.allocator.dupe(u8, sub_file_path),
392 .src_path = .{ .scope = fscope },
393 .msg = try arena.allocator.dupe(u8, module_note.msg),350 .msg = try arena.allocator.dupe(u8, module_note.msg),
394 .byte_offset = byte_offset,351 .byte_offset = byte_offset,
395 .line = @intCast(u32, loc.line),352 .line = @intCast(u32, loc.line),
396 .column = @intCast(u32, loc.column),353 .column = @intCast(u32, loc.column),
354 .source_line = try arena.allocator.dupe(u8, loc.source_line),
397 },355 },
398 };356 };
399 }357 }
400 const source = try module_err_msg.src_loc.fileScope().getSource(module);358 const source = try module_err_msg.src_loc.fileScope().getSource(module);
401 const byte_offset = try module_err_msg.src_loc.byteOffset();359 const byte_offset = try module_err_msg.src_loc.byteOffset();
402 const loc = std.zig.findLineColumn(source, byte_offset);360 const loc = std.zig.findLineColumn(source, byte_offset);
403 const fscope = module_err_msg.src_loc.fileScope();361 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
404 try errors.append(.{362 try errors.append(.{
405 .src = .{363 .src = .{
406 .src_path = .{ .scope = fscope },364 .src_path = try arena.allocator.dupe(u8, sub_file_path),
407 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),365 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
408 .byte_offset = byte_offset,366 .byte_offset = byte_offset,
409 .line = @intCast(u32, loc.line),367 .line = @intCast(u32, loc.line),
410 .column = @intCast(u32, loc.column),368 .column = @intCast(u32, loc.column),
411 .notes = notes,369 .notes = notes,
370 .source_line = try arena.allocator.dupe(u8, loc.source_line),
412 },371 },
413 });372 });
414 }373 }
...@@ -1549,13 +1508,14 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1549,13 +1508,14 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1549 // C error reporting bubbling up.1508 // C error reporting bubbling up.
1550 try errors.append(.{1509 try errors.append(.{
1551 .src = .{1510 .src = .{
1552 .src_path = .{ .path = try arena.allocator.dupe(u8, c_object.src.src_path) },1511 .src_path = try arena.allocator.dupe(u8, c_object.src.src_path),
1553 .msg = try std.fmt.allocPrint(&arena.allocator, "unable to build C object: {s}", .{1512 .msg = try std.fmt.allocPrint(&arena.allocator, "unable to build C object: {s}", .{
1554 err_msg.msg,1513 err_msg.msg,
1555 }),1514 }),
1556 .byte_offset = 0,1515 .byte_offset = 0,
1557 .line = err_msg.line,1516 .line = err_msg.line,
1558 .column = err_msg.column,1517 .column = err_msg.column,
1518 .source_line = null, // TODO
1559 },1519 },
1560 });1520 });
1561 }1521 }
src/Module.zig+3
...@@ -3219,7 +3219,9 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {...@@ -3219,7 +3219,9 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
32193219
3220 const source = try root_scope.getSource(mod);3220 const source = try root_scope.getSource(mod);
32213221
3222 var keep_tree = false;
3222 root_scope.tree = try std.zig.parse(mod.gpa, source);3223 root_scope.tree = try std.zig.parse(mod.gpa, source);
3224 defer if (!keep_tree) root_scope.tree.deinit(mod.gpa);
32233225
3224 const tree = &root_scope.tree;3226 const tree = &root_scope.tree;
32253227
...@@ -3247,6 +3249,7 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {...@@ -3247,6 +3249,7 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
3247 }3249 }
32483250
3249 root_scope.status = .loaded_success;3251 root_scope.status = .loaded_success;
3252 keep_tree = true;
32503253
3251 return tree;3254 return tree;
3252 },3255 },
src/main.zig+5-1
...@@ -2106,8 +2106,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2106,8 +2106,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
2106 defer errors.deinit(comp.gpa);2106 defer errors.deinit(comp.gpa);
21072107
2108 if (errors.list.len != 0) {2108 if (errors.list.len != 0) {
2109 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
2110 .auto, .on => std.debug.detectTTYConfig(),
2111 .off => .no_color,
2112 };
2109 for (errors.list) |full_err_msg| {2113 for (errors.list) |full_err_msg| {
2110 try full_err_msg.renderToStdErr(comp.bin_file.options.module);2114 full_err_msg.renderToStdErr(ttyconf);
2111 }2115 }
2112 const log_text = comp.getCompileLogOutput();2116 const log_text = comp.getCompileLogOutput();
2113 if (log_text.len != 0) {2117 if (log_text.len != 0) {