Skip to content

Commit 1216bca

Browse files
committed
improve error message for unterminated string and character literals
1 parent 1a1389c commit 1216bca

File tree

5 files changed

+56
-8
lines changed

5 files changed

+56
-8
lines changed

lib/std/zig/Ast.zig

+12
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,17 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
458458
return stream.writeAll("for input is not captured");
459459
},
460460

461+
.unterminated_literal => {
462+
const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..];
463+
return stream.print("unterminated '{s} literal'", .{
464+
switch (tok_slice[0]) {
465+
'\'' => "character",
466+
'"', '\\' => "string",
467+
else => unreachable,
468+
},
469+
});
470+
},
471+
461472
.invalid_byte => {
462473
const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..];
463474
return stream.print("{s} contains invalid byte: '{'}'", .{
@@ -3003,6 +3014,7 @@ pub const Error = struct {
30033014
var_const_decl,
30043015
extra_for_capture,
30053016
for_input_not_captured,
3017+
unterminated_literal,
30063018

30073019
zig_style_container,
30083020
previous_field,

lib/std/zig/AstGen.zig

+19-7
Original file line numberDiff line numberDiff line change
@@ -14039,15 +14039,27 @@ fn lowerAstErrors(astgen: *AstGen) !void {
1403914039
}
1404014040
break :blk idx - tok_start;
1404114041
};
14042-
14043-
const err: Ast.Error = .{
14044-
.tag = Ast.Error.Tag.invalid_byte,
14045-
.token = tok,
14046-
.extra = .{ .offset = bad_off },
14047-
};
14042+
const err: Ast.Error =
14043+
if ((start_char == '\"' or start_char == '\'') and (bad_off == tok_len or tree.source[tok_start + bad_off] == '\n'))
14044+
.{
14045+
.tag = Ast.Error.Tag.unterminated_literal,
14046+
.token = tok,
14047+
}
14048+
else
14049+
.{
14050+
.tag = Ast.Error.Tag.invalid_byte,
14051+
.token = tok,
14052+
.extra = .{ .offset = bad_off },
14053+
};
1404814054
msg.clearRetainingCapacity();
1404914055
try tree.renderError(err, msg.writer(gpa));
14050-
return try astgen.appendErrorTokNotesOff(tok, bad_off, "{s}", .{msg.items}, notes.items);
14056+
return try astgen.appendErrorTokNotesOff(
14057+
tok,
14058+
if (err.tag == .invalid_byte) bad_off else 0,
14059+
"{s}",
14060+
.{msg.items},
14061+
notes.items,
14062+
);
1405114063
}
1405214064

1405314065
var cur_err = tree.errors[0];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const foo = 'a
2+
';
3+
4+
// error
5+
// backend=stage2
6+
// target=native
7+
//
8+
// :1:13: error: unterminated 'character literal'

test/cases/compile_errors/normal_string_with_newline.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ b";
55
// backend=stage2
66
// target=native
77
//
8-
// :1:15: error: string literal contains invalid byte: '\n'
8+
// :1:13: error: unterminated 'string literal'

test/compile_errors.zig

+16
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,22 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
237237
});
238238
}
239239

240+
{
241+
const case = ctx.obj("unterminated character literal eof", b.graph.host);
242+
243+
case.addError("const c = '", &[_][]const u8{
244+
":1:11: error: unterminated 'character literal'",
245+
});
246+
}
247+
248+
{
249+
const case = ctx.obj("unterminated string literal eof", b.graph.host);
250+
251+
case.addError("const s = \"hello, ", &[_][]const u8{
252+
":1:11: error: unterminated 'string literal'",
253+
});
254+
}
255+
240256
{
241257
const case = ctx.obj("invalid byte at start of token", b.graph.host);
242258

0 commit comments

Comments
 (0)