Skip to content

Commit 1463144

Browse files
committed
Compilation: point caret in error message at the main token
1 parent b5a8382 commit 1463144

File tree

5 files changed

+72
-56
lines changed

5 files changed

+72
-56
lines changed

src/Compilation.zig

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {

0 commit comments

Comments
 (0)