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 {
427427 else => try stderr.writeByte(b),
428428 };
429429 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);
431435 ttyconf.setColor(stderr, .Green);
436 try stderr.writeByteNTimes('~', before_caret);
432437 try stderr.writeByte('^');
433 // TODO basic unicode code point monospace width
434 try stderr.writeByteNTimes('~', src.span.end - src.span.start - 1);
438 try stderr.writeByteNTimes('~', after_caret);
435439 try stderr.writeByte('\n');
436440 ttyconf.setColor(stderr, .Reset);
437441 }
......@@ -472,8 +476,7 @@ pub const AllErrors = struct {
472476 hasher.update(src.src_path);
473477 std.hash.autoHash(&hasher, src.line);
474478 std.hash.autoHash(&hasher, src.column);
475 std.hash.autoHash(&hasher, src.span.start);
476 std.hash.autoHash(&hasher, src.span.end);
479 std.hash.autoHash(&hasher, src.span.main);
477480 },
478481 .plain => |plain| {
479482 hasher.update(plain.msg);
......@@ -492,8 +495,7 @@ pub const AllErrors = struct {
492495 mem.eql(u8, a_src.src_path, b_src.src_path) and
493496 a_src.line == b_src.line and
494497 a_src.column == b_src.column and
495 a_src.span.start == b_src.span.start and
496 a_src.span.end == b_src.span.end;
498 a_src.span.main == b_src.span.main;
497499 },
498500 .plain => return false,
499501 },
......@@ -533,12 +535,12 @@ pub const AllErrors = struct {
533535 ).init(allocator);
534536 const err_source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
535537 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
538540 for (module_err_msg.notes) |module_note| {
539541 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
540542 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);
542544 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);
543545 const note = &notes_buf[note_i];
544546 note.* = .{
......@@ -604,9 +606,10 @@ pub const AllErrors = struct {
604606 }
605607 const token_starts = file.tree.tokens.items(.start);
606608 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 };
608611 };
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
611614 var notes: []Message = &[0]Message{};
612615 if (item.data.notes != 0) {
......@@ -622,9 +625,10 @@ pub const AllErrors = struct {
622625 }
623626 const token_starts = file.tree.tokens.items(.start);
624627 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 };
626630 };
627 const loc = std.zig.findLineColumn(file.source, span.start);
631 const loc = std.zig.findLineColumn(file.source, span.main);
628632
629633 note.* = .{
630634 .src = .{
......@@ -2665,7 +2669,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
26652669 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{
26662670 err_msg.msg,
26672671 }),
2668 .span = .{ .start = 0, .end = 1 },
2672 .span = .{ .start = 0, .end = 1, .main = 0 },
26692673 .line = err_msg.line,
26702674 .column = err_msg.column,
26712675 .source_line = null, // TODO
src/Module.zig+33-38
......@@ -2085,20 +2085,21 @@ pub const SrcLoc = struct {
20852085 pub const Span = struct {
20862086 start: u32,
20872087 end: u32,
2088 main: u32,
20882089 };
20892090
20902091 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
20912092 switch (src_loc.lazy) {
20922093 .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
20972098 .token_abs => |tok_index| {
20982099 const tree = try src_loc.file_scope.getTree(gpa);
20992100 const start = tree.tokens.items(.start)[tok_index];
21002101 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 };
21022103 },
21032104 .node_abs => |node| {
21042105 const tree = try src_loc.file_scope.getTree(gpa);
......@@ -2109,14 +2110,14 @@ pub const SrcLoc = struct {
21092110 const tok_index = src_loc.declSrcToken();
21102111 const start = tree.tokens.items(.start)[tok_index] + byte_off;
21112112 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 };
21132114 },
21142115 .token_offset => |tok_off| {
21152116 const tree = try src_loc.file_scope.getTree(gpa);
21162117 const tok_index = src_loc.declSrcToken() + tok_off;
21172118 const start = tree.tokens.items(.start)[tok_index];
21182119 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 };
21202121 },
21212122 .node_offset => |traced_off| {
21222123 const node_off = traced_off.x;
......@@ -2137,7 +2138,7 @@ pub const SrcLoc = struct {
21372138 const tok_index = tree.firstToken(node) - 2;
21382139 const start = tree.tokens.items(.start)[tok_index];
21392140 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 };
21412142 },
21422143 .node_offset_var_decl_ty => |node_off| {
21432144 const tree = try src_loc.file_scope.getTree(gpa);
......@@ -2158,7 +2159,7 @@ pub const SrcLoc = struct {
21582159 };
21592160 const start = tree.tokens.items(.start)[tok_index];
21602161 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 };
21622163 },
21632164 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
21642165 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
......@@ -2186,16 +2187,13 @@ pub const SrcLoc = struct {
21862187 .slice_sentinel => tree.sliceSentinel(node),
21872188 else => unreachable,
21882189 };
2189 const main_tokens = tree.nodes.items(.main_token);
2190 const part_node = main_tokens[
2191 switch (src_loc.lazy) {
2192 .node_offset_slice_ptr => full.ast.sliced,
2193 .node_offset_slice_start => full.ast.start,
2194 .node_offset_slice_end => full.ast.end,
2195 .node_offset_slice_sentinel => full.ast.sentinel,
2196 else => unreachable,
2197 }
2198 ];
2190 const part_node = switch (src_loc.lazy) {
2191 .node_offset_slice_ptr => full.ast.sliced,
2192 .node_offset_slice_start => full.ast.start,
2193 .node_offset_slice_end => full.ast.end,
2194 .node_offset_slice_sentinel => full.ast.sentinel,
2195 else => unreachable,
2196 };
21992197 return nodeToSpan(tree, part_node);
22002198 },
22012199 .node_offset_call_func => |node_off| {
......@@ -2231,7 +2229,7 @@ pub const SrcLoc = struct {
22312229 };
22322230 const start = tree.tokens.items(.start)[tok_index];
22332231 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 };
22352233 },
22362234 .node_offset_deref_ptr => |node_off| {
22372235 const tree = try src_loc.file_scope.getTree(gpa);
......@@ -2422,7 +2420,7 @@ pub const SrcLoc = struct {
24222420 const tok_index = full.lib_name.?;
24232421 const start = tree.tokens.items(.start)[tok_index];
24242422 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 };
24262424 },
24272425
24282426 .node_offset_array_type_len => |node_off| {
......@@ -2495,28 +2493,25 @@ pub const SrcLoc = struct {
24952493
24962494 pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
24972495 const token_starts = tree.tokens.items(.start);
2496 const main_token = tree.nodes.items(.main_token)[node];
24982497 const start = tree.firstToken(node);
24992498 const end = tree.lastToken(node);
2500 if (tree.tokensOnSameLine(start, end)) {
2501 const start_off = token_starts[start];
2502 const end_off = token_starts[end] + @intCast(u32, tree.tokenSlice(end).len);
2503 return Span{ .start = start_off, .end = end_off };
2504 }
2499 var start_tok = start;
2500 var end_tok = end;
25052501
2506 const main_token = tree.nodes.items(.main_token)[node];
2507 if (tree.tokensOnSameLine(start, main_token)) {
2508 const start_off = token_starts[start];
2509 const end_off = token_starts[main_token] + @intCast(u32, tree.tokenSlice(main_token).len);
2510 return Span{ .start = start_off, .end = end_off };
2511 }
2512 if (tree.tokensOnSameLine(main_token, end)) {
2513 const start_off = token_starts[main_token];
2514 const end_off = token_starts[end] + @intCast(u32, tree.tokenSlice(end).len);
2515 return Span{ .start = start_off, .end = end_off };
2502 if (tree.tokensOnSameLine(start, end)) {
2503 // do nothing
2504 } else if (tree.tokensOnSameLine(start, main_token)) {
2505 end_tok = main_token;
2506 } else if (tree.tokensOnSameLine(main_token, end)) {
2507 start_tok = main_token;
2508 } else {
2509 start_tok = main_token;
2510 end_tok = main_token;
25162511 }
2517 const start_off = token_starts[main_token];
2518 const end_off = token_starts[main_token] + @intCast(u32, tree.tokenSlice(main_token).len);
2519 return Span{ .start = start_off, .end = end_off };
2512 const start_off = token_starts[start_tok];
2513 const end_off = token_starts[end_tok] + @intCast(u32, tree.tokenSlice(end_tok).len);
2514 return Span{ .start = start_off, .end = end_off, .main = token_starts[main_token] };
25202515 }
25212516};
25222517
......@@ -3283,7 +3278,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
32833278 .lazy = if (extra_offset == 0) .{
32843279 .token_abs = parse_err.token,
32853280 } else .{
3286 .byte_abs = token_starts[parse_err.token],
3281 .byte_abs = token_starts[parse_err.token] + extra_offset,
32873282 },
32883283 },
32893284 .msg = msg.toOwnedSlice(),
src/main.zig+11-3
......@@ -4381,7 +4381,7 @@ fn printErrsMsgToStdErr(
43814381 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
43824382 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
43834383 }),
4384 .span = .{ .start = byte_offset, .end = byte_offset + 1 },
4384 .span = .{ .start = byte_offset, .end = byte_offset + 1, .main = byte_offset },
43854385 .line = @intCast(u32, start_loc.line),
43864386 .column = @intCast(u32, start_loc.column) + bad_off,
43874387 .source_line = source_line,
......@@ -4401,7 +4401,11 @@ fn printErrsMsgToStdErr(
44014401 .src = .{
44024402 .src_path = path,
44034403 .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 },
44054409 .line = @intCast(u32, note_loc.line),
44064410 .column = @intCast(u32, note_loc.column),
44074411 .source_line = tree.source[note_loc.line_start..note_loc.line_end],
......@@ -4417,7 +4421,11 @@ fn printErrsMsgToStdErr(
44174421 .src = .{
44184422 .src_path = path,
44194423 .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 },
44214429 .line = @intCast(u32, start_loc.line),
44224430 .column = @intCast(u32, start_loc.column) + extra_offset,
44234431 .source_line = source_line,
src/print_zir.zig+1-1
......@@ -2386,7 +2386,7 @@ const Writer = struct {
23862386 const end = std.zig.findLineColumn(tree.source, src_span.end);
23872387 try stream.print("{s}:{d}:{d} to :{d}:{d}", .{
23882388 @tagName(src), start.line + 1, start.column + 1,
2389 end.line + 1, end.column + 1,
2389 end.line + 1, end.column + 1,
23902390 });
23912391 }
23922392 }
test/compile_errors.zig+9
......@@ -174,6 +174,15 @@ pub fn addCases(ctx: *TestContext) !void {
174174 });
175175 }
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
177186 // TODO test this in stage2, but we won't even try in stage1
178187 //ctx.objErrStage1("inline fn calls itself indirectly",
179188 // \\export fn foo() void {