authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-15 11:38:16+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-15 15:11:43+03:00
log1463144fc88550ba1dca3888acdcdd4903781222
tree19aa9a5f957b04d095afc7d6009eaf26877d19a4
parentb5a838247bd7d66037ba48378c34ba4460747deb

Compilation: point caret in error message at the main token


5 files changed, 72 insertions(+), 56 deletions(-)

src/Compilation.zig+18-14
...@@ -427,11 +427,15 @@ pub const AllErrors = struct {...@@ -427,11 +427,15 @@ pub const AllErrors = struct {
427 else => try stderr.writeByte(b),427 else => try stderr.writeByte(b),
428 };428 };
429 try stderr.writeByte('\n');429 try stderr.writeByte('\n');
430 try stderr.writeByteNTimes(' ', src.column);430 // TODO basic unicode code point monospace width
431 const before_caret = src.span.main - src.span.start;
432 // -1 since span.main includes the caret
433 const after_caret = src.span.end - src.span.main -| 1;
434 try stderr.writeByteNTimes(' ', src.column - before_caret);
431 ttyconf.setColor(stderr, .Green);435 ttyconf.setColor(stderr, .Green);
436 try stderr.writeByteNTimes('~', before_caret);
432 try stderr.writeByte('^');437 try stderr.writeByte('^');
433 // TODO basic unicode code point monospace width438 try stderr.writeByteNTimes('~', after_caret);
434 try stderr.writeByteNTimes('~', src.span.end - src.span.start - 1);
435 try stderr.writeByte('\n');439 try stderr.writeByte('\n');
436 ttyconf.setColor(stderr, .Reset);440 ttyconf.setColor(stderr, .Reset);
437 }441 }
...@@ -472,8 +476,7 @@ pub const AllErrors = struct {...@@ -472,8 +476,7 @@ pub const AllErrors = struct {
472 hasher.update(src.src_path);476 hasher.update(src.src_path);
473 std.hash.autoHash(&hasher, src.line);477 std.hash.autoHash(&hasher, src.line);
474 std.hash.autoHash(&hasher, src.column);478 std.hash.autoHash(&hasher, src.column);
475 std.hash.autoHash(&hasher, src.span.start);479 std.hash.autoHash(&hasher, src.span.main);
476 std.hash.autoHash(&hasher, src.span.end);
477 },480 },
478 .plain => |plain| {481 .plain => |plain| {
479 hasher.update(plain.msg);482 hasher.update(plain.msg);
...@@ -492,8 +495,7 @@ pub const AllErrors = struct {...@@ -492,8 +495,7 @@ pub const AllErrors = struct {
492 mem.eql(u8, a_src.src_path, b_src.src_path) and495 mem.eql(u8, a_src.src_path, b_src.src_path) and
493 a_src.line == b_src.line and496 a_src.line == b_src.line and
494 a_src.column == b_src.column and497 a_src.column == b_src.column and
495 a_src.span.start == b_src.span.start and498 a_src.span.main == b_src.span.main;
496 a_src.span.end == b_src.span.end;
497 },499 },
498 .plain => return false,500 .plain => return false,
499 },501 },
...@@ -533,12 +535,12 @@ pub const AllErrors = struct {...@@ -533,12 +535,12 @@ pub const AllErrors = struct {
533 ).init(allocator);535 ).init(allocator);
534 const err_source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);536 const err_source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
535 const err_span = try module_err_msg.src_loc.span(module.gpa);537 const err_span = try module_err_msg.src_loc.span(module.gpa);
536 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.start);538 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
537539
538 for (module_err_msg.notes) |module_note| {540 for (module_err_msg.notes) |module_note| {
539 const source = try module_note.src_loc.file_scope.getSource(module.gpa);541 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
540 const span = try module_note.src_loc.span(module.gpa);542 const span = try module_note.src_loc.span(module.gpa);
541 const loc = std.zig.findLineColumn(source.bytes, span.start);543 const loc = std.zig.findLineColumn(source.bytes, span.main);
542 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);544 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);
543 const note = &notes_buf[note_i];545 const note = &notes_buf[note_i];
544 note.* = .{546 note.* = .{
...@@ -604,9 +606,10 @@ pub const AllErrors = struct {...@@ -604,9 +606,10 @@ pub const AllErrors = struct {
604 }606 }
605 const token_starts = file.tree.tokens.items(.start);607 const token_starts = file.tree.tokens.items(.start);
606 const start = token_starts[item.data.token] + item.data.byte_offset;608 const start = token_starts[item.data.token] + item.data.byte_offset;
607 break :blk Module.SrcLoc.Span{ .start = start, .end = start + 1 };609 const end = start + @intCast(u32, file.tree.tokenSlice(item.data.token).len);
610 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
608 };611 };
609 const err_loc = std.zig.findLineColumn(file.source, err_span.start);612 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
610613
611 var notes: []Message = &[0]Message{};614 var notes: []Message = &[0]Message{};
612 if (item.data.notes != 0) {615 if (item.data.notes != 0) {
...@@ -622,9 +625,10 @@ pub const AllErrors = struct {...@@ -622,9 +625,10 @@ pub const AllErrors = struct {
622 }625 }
623 const token_starts = file.tree.tokens.items(.start);626 const token_starts = file.tree.tokens.items(.start);
624 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;627 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
625 break :blk Module.SrcLoc.Span{ .start = start, .end = start + 1 };628 const end = start + @intCast(u32, file.tree.tokenSlice(note_item.data.token).len);
629 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
626 };630 };
627 const loc = std.zig.findLineColumn(file.source, span.start);631 const loc = std.zig.findLineColumn(file.source, span.main);
628632
629 note.* = .{633 note.* = .{
630 .src = .{634 .src = .{
...@@ -2665,7 +2669,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -2665,7 +2669,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
2665 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{2669 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{
2666 err_msg.msg,2670 err_msg.msg,
2667 }),2671 }),
2668 .span = .{ .start = 0, .end = 1 },2672 .span = .{ .start = 0, .end = 1, .main = 0 },
2669 .line = err_msg.line,2673 .line = err_msg.line,
2670 .column = err_msg.column,2674 .column = err_msg.column,
2671 .source_line = null, // TODO2675 .source_line = null, // TODO
src/Module.zig+33-38
...@@ -2085,20 +2085,21 @@ pub const SrcLoc = struct {...@@ -2085,20 +2085,21 @@ pub const SrcLoc = struct {
2085 pub const Span = struct {2085 pub const Span = struct {
2086 start: u32,2086 start: u32,
2087 end: u32,2087 end: u32,
2088 main: u32,
2088 };2089 };
20892090
2090 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {2091 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
2091 switch (src_loc.lazy) {2092 switch (src_loc.lazy) {
2092 .unneeded => unreachable,2093 .unneeded => unreachable,
2093 .entire_file => return Span{ .start = 0, .end = 1 },2094 .entire_file => return Span{ .start = 0, .end = 1, .main = 0 },
20942095
2095 .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1 },2096 .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index },
20962097
2097 .token_abs => |tok_index| {2098 .token_abs => |tok_index| {
2098 const tree = try src_loc.file_scope.getTree(gpa);2099 const tree = try src_loc.file_scope.getTree(gpa);
2099 const start = tree.tokens.items(.start)[tok_index];2100 const start = tree.tokens.items(.start)[tok_index];
2100 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2101 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2101 return Span{ .start = start, .end = end };2102 return Span{ .start = start, .end = end, .main = start };
2102 },2103 },
2103 .node_abs => |node| {2104 .node_abs => |node| {
2104 const tree = try src_loc.file_scope.getTree(gpa);2105 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -2109,14 +2110,14 @@ pub const SrcLoc = struct {...@@ -2109,14 +2110,14 @@ pub const SrcLoc = struct {
2109 const tok_index = src_loc.declSrcToken();2110 const tok_index = src_loc.declSrcToken();
2110 const start = tree.tokens.items(.start)[tok_index] + byte_off;2111 const start = tree.tokens.items(.start)[tok_index] + byte_off;
2111 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2112 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2112 return Span{ .start = start, .end = end };2113 return Span{ .start = start, .end = end, .main = start };
2113 },2114 },
2114 .token_offset => |tok_off| {2115 .token_offset => |tok_off| {
2115 const tree = try src_loc.file_scope.getTree(gpa);2116 const tree = try src_loc.file_scope.getTree(gpa);
2116 const tok_index = src_loc.declSrcToken() + tok_off;2117 const tok_index = src_loc.declSrcToken() + tok_off;
2117 const start = tree.tokens.items(.start)[tok_index];2118 const start = tree.tokens.items(.start)[tok_index];
2118 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2119 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2119 return Span{ .start = start, .end = end };2120 return Span{ .start = start, .end = end, .main = start };
2120 },2121 },
2121 .node_offset => |traced_off| {2122 .node_offset => |traced_off| {
2122 const node_off = traced_off.x;2123 const node_off = traced_off.x;
...@@ -2137,7 +2138,7 @@ pub const SrcLoc = struct {...@@ -2137,7 +2138,7 @@ pub const SrcLoc = struct {
2137 const tok_index = tree.firstToken(node) - 2;2138 const tok_index = tree.firstToken(node) - 2;
2138 const start = tree.tokens.items(.start)[tok_index];2139 const start = tree.tokens.items(.start)[tok_index];
2139 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2140 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2140 return Span{ .start = start, .end = end };2141 return Span{ .start = start, .end = end, .main = start };
2141 },2142 },
2142 .node_offset_var_decl_ty => |node_off| {2143 .node_offset_var_decl_ty => |node_off| {
2143 const tree = try src_loc.file_scope.getTree(gpa);2144 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -2158,7 +2159,7 @@ pub const SrcLoc = struct {...@@ -2158,7 +2159,7 @@ pub const SrcLoc = struct {
2158 };2159 };
2159 const start = tree.tokens.items(.start)[tok_index];2160 const start = tree.tokens.items(.start)[tok_index];
2160 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2161 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2161 return Span{ .start = start, .end = end };2162 return Span{ .start = start, .end = end, .main = start };
2162 },2163 },
2163 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),2164 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
2164 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),2165 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
...@@ -2186,16 +2187,13 @@ pub const SrcLoc = struct {...@@ -2186,16 +2187,13 @@ pub const SrcLoc = struct {
2186 .slice_sentinel => tree.sliceSentinel(node),2187 .slice_sentinel => tree.sliceSentinel(node),
2187 else => unreachable,2188 else => unreachable,
2188 };2189 };
2189 const main_tokens = tree.nodes.items(.main_token);2190 const part_node = switch (src_loc.lazy) {
2190 const part_node = main_tokens[2191 .node_offset_slice_ptr => full.ast.sliced,
2191 switch (src_loc.lazy) {2192 .node_offset_slice_start => full.ast.start,
2192 .node_offset_slice_ptr => full.ast.sliced,2193 .node_offset_slice_end => full.ast.end,
2193 .node_offset_slice_start => full.ast.start,2194 .node_offset_slice_sentinel => full.ast.sentinel,
2194 .node_offset_slice_end => full.ast.end,2195 else => unreachable,
2195 .node_offset_slice_sentinel => full.ast.sentinel,2196 };
2196 else => unreachable,
2197 }
2198 ];
2199 return nodeToSpan(tree, part_node);2197 return nodeToSpan(tree, part_node);
2200 },2198 },
2201 .node_offset_call_func => |node_off| {2199 .node_offset_call_func => |node_off| {
...@@ -2231,7 +2229,7 @@ pub const SrcLoc = struct {...@@ -2231,7 +2229,7 @@ pub const SrcLoc = struct {
2231 };2229 };
2232 const start = tree.tokens.items(.start)[tok_index];2230 const start = tree.tokens.items(.start)[tok_index];
2233 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2231 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2234 return Span{ .start = start, .end = end };2232 return Span{ .start = start, .end = end, .main = start };
2235 },2233 },
2236 .node_offset_deref_ptr => |node_off| {2234 .node_offset_deref_ptr => |node_off| {
2237 const tree = try src_loc.file_scope.getTree(gpa);2235 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -2422,7 +2420,7 @@ pub const SrcLoc = struct {...@@ -2422,7 +2420,7 @@ pub const SrcLoc = struct {
2422 const tok_index = full.lib_name.?;2420 const tok_index = full.lib_name.?;
2423 const start = tree.tokens.items(.start)[tok_index];2421 const start = tree.tokens.items(.start)[tok_index];
2424 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);2422 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
2425 return Span{ .start = start, .end = end };2423 return Span{ .start = start, .end = end, .main = start };
2426 },2424 },
24272425
2428 .node_offset_array_type_len => |node_off| {2426 .node_offset_array_type_len => |node_off| {
...@@ -2495,28 +2493,25 @@ pub const SrcLoc = struct {...@@ -2495,28 +2493,25 @@ pub const SrcLoc = struct {
24952493
2496 pub fn nodeToSpan(tree: *const Ast, node: u32) Span {2494 pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
2497 const token_starts = tree.tokens.items(.start);2495 const token_starts = tree.tokens.items(.start);
2496 const main_token = tree.nodes.items(.main_token)[node];
2498 const start = tree.firstToken(node);2497 const start = tree.firstToken(node);
2499 const end = tree.lastToken(node);2498 const end = tree.lastToken(node);
2500 if (tree.tokensOnSameLine(start, end)) {2499 var start_tok = start;
2501 const start_off = token_starts[start];2500 var end_tok = end;
2502 const end_off = token_starts[end] + @intCast(u32, tree.tokenSlice(end).len);
2503 return Span{ .start = start_off, .end = end_off };
2504 }
25052501
2506 const main_token = tree.nodes.items(.main_token)[node];2502 if (tree.tokensOnSameLine(start, end)) {
2507 if (tree.tokensOnSameLine(start, main_token)) {2503 // do nothing
2508 const start_off = token_starts[start];2504 } else if (tree.tokensOnSameLine(start, main_token)) {
2509 const end_off = token_starts[main_token] + @intCast(u32, tree.tokenSlice(main_token).len);2505 end_tok = main_token;
2510 return Span{ .start = start_off, .end = end_off };2506 } else if (tree.tokensOnSameLine(main_token, end)) {
2511 }2507 start_tok = main_token;
2512 if (tree.tokensOnSameLine(main_token, end)) {2508 } else {
2513 const start_off = token_starts[main_token];2509 start_tok = main_token;
2514 const end_off = token_starts[end] + @intCast(u32, tree.tokenSlice(end).len);2510 end_tok = main_token;
2515 return Span{ .start = start_off, .end = end_off };
2516 }2511 }
2517 const start_off = token_starts[main_token];2512 const start_off = token_starts[start_tok];
2518 const end_off = token_starts[main_token] + @intCast(u32, tree.tokenSlice(main_token).len);2513 const end_off = token_starts[end_tok] + @intCast(u32, tree.tokenSlice(end_tok).len);
2519 return Span{ .start = start_off, .end = end_off };2514 return Span{ .start = start_off, .end = end_off, .main = token_starts[main_token] };
2520 }2515 }
2521};2516};
25222517
...@@ -3283,7 +3278,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3283,7 +3278,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3283 .lazy = if (extra_offset == 0) .{3278 .lazy = if (extra_offset == 0) .{
3284 .token_abs = parse_err.token,3279 .token_abs = parse_err.token,
3285 } else .{3280 } else .{
3286 .byte_abs = token_starts[parse_err.token],3281 .byte_abs = token_starts[parse_err.token] + extra_offset,
3287 },3282 },
3288 },3283 },
3289 .msg = msg.toOwnedSlice(),3284 .msg = msg.toOwnedSlice(),
src/main.zig+11-3
...@@ -4381,7 +4381,7 @@ fn printErrsMsgToStdErr(...@@ -4381,7 +4381,7 @@ fn printErrsMsgToStdErr(
4381 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{4381 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
4382 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),4382 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
4383 }),4383 }),
4384 .span = .{ .start = byte_offset, .end = byte_offset + 1 },4384 .span = .{ .start = byte_offset, .end = byte_offset + 1, .main = byte_offset },
4385 .line = @intCast(u32, start_loc.line),4385 .line = @intCast(u32, start_loc.line),
4386 .column = @intCast(u32, start_loc.column) + bad_off,4386 .column = @intCast(u32, start_loc.column) + bad_off,
4387 .source_line = source_line,4387 .source_line = source_line,
...@@ -4401,7 +4401,11 @@ fn printErrsMsgToStdErr(...@@ -4401,7 +4401,11 @@ fn printErrsMsgToStdErr(
4401 .src = .{4401 .src = .{
4402 .src_path = path,4402 .src_path = path,
4403 .msg = try arena.dupe(u8, text_buf.items),4403 .msg = try arena.dupe(u8, text_buf.items),
4404 .span = .{ .start = byte_offset, .end = byte_offset + @intCast(u32, tree.tokenSlice(note.token).len) },4404 .span = .{
4405 .start = byte_offset,
4406 .end = byte_offset + @intCast(u32, tree.tokenSlice(note.token).len),
4407 .main = byte_offset,
4408 },
4405 .line = @intCast(u32, note_loc.line),4409 .line = @intCast(u32, note_loc.line),
4406 .column = @intCast(u32, note_loc.column),4410 .column = @intCast(u32, note_loc.column),
4407 .source_line = tree.source[note_loc.line_start..note_loc.line_end],4411 .source_line = tree.source[note_loc.line_start..note_loc.line_end],
...@@ -4417,7 +4421,11 @@ fn printErrsMsgToStdErr(...@@ -4417,7 +4421,11 @@ fn printErrsMsgToStdErr(
4417 .src = .{4421 .src = .{
4418 .src_path = path,4422 .src_path = path,
4419 .msg = text,4423 .msg = text,
4420 .span = .{ .start = byte_offset, .end = byte_offset + @intCast(u32, tree.tokenSlice(lok_token).len) },4424 .span = .{
4425 .start = byte_offset,
4426 .end = byte_offset + @intCast(u32, tree.tokenSlice(lok_token).len),
4427 .main = byte_offset,
4428 },
4421 .line = @intCast(u32, start_loc.line),4429 .line = @intCast(u32, start_loc.line),
4422 .column = @intCast(u32, start_loc.column) + extra_offset,4430 .column = @intCast(u32, start_loc.column) + extra_offset,
4423 .source_line = source_line,4431 .source_line = source_line,
src/print_zir.zig+1-1
...@@ -2386,7 +2386,7 @@ const Writer = struct {...@@ -2386,7 +2386,7 @@ const Writer = struct {
2386 const end = std.zig.findLineColumn(tree.source, src_span.end);2386 const end = std.zig.findLineColumn(tree.source, src_span.end);
2387 try stream.print("{s}:{d}:{d} to :{d}:{d}", .{2387 try stream.print("{s}:{d}:{d} to :{d}:{d}", .{
2388 @tagName(src), start.line + 1, start.column + 1,2388 @tagName(src), start.line + 1, start.column + 1,
2389 end.line + 1, end.column + 1,2389 end.line + 1, end.column + 1,
2390 });2390 });
2391 }2391 }
2392 }2392 }
test/compile_errors.zig+9
...@@ -174,6 +174,15 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -174,6 +174,15 @@ pub fn addCases(ctx: *TestContext) !void {
174 });174 });
175 }175 }
176176
177 {
178 const case = ctx.obj("missing semicolon at EOF", .{});
179 case.addError(
180 \\const foo = 1
181 , &[_][]const u8{
182 \\:1:14: error: expected ';' after declaration
183 });
184 }
185
177 // TODO test this in stage2, but we won't even try in stage1186 // TODO test this in stage2, but we won't even try in stage1
178 //ctx.objErrStage1("inline fn calls itself indirectly",187 //ctx.objErrStage1("inline fn calls itself indirectly",
179 // \\export fn foo() void {188 // \\export fn foo() void {