authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-13 12:34:41+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-13 13:45:35+02:00
logddd6de86f7eb71814d3605d3e0ea9ed01d075613
tree4d6373402a99ed70eba6aa66dbcc3624036dbe30
parent0b7347fd18eee7dd829cd9aaed3683123d84859b

parser: make missing semicolon error point to the end of the previous token


4 files changed, 41 insertions(+), 8 deletions(-)

lib/std/zig/Ast.zig+22
...@@ -64,6 +64,17 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void...@@ -64,6 +64,17 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void
64 return @import("./render.zig").renderTree(buffer, tree);64 return @import("./render.zig").renderTree(buffer, tree);
65}65}
6666
67/// Returns an extra offset for column and byte offset of errors that
68/// should point after the token in the error message.
69pub fn errorOffset(tree:Ast, error_tag: Error.Tag, token: TokenIndex) u32 {
70 return switch (error_tag) {
71 .expected_semi_after_decl,
72 .expected_semi_after_stmt,
73 => @intCast(u32, tree.tokenSlice(token).len),
74 else => 0,
75 };
76}
77
67pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {78pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {
68 var loc = Location{79 var loc = Location{
69 .line = 0,80 .line = 0,
...@@ -306,6 +317,13 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -306,6 +317,13 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
306 return stream.writeAll("function prototype has parameter after varargs");317 return stream.writeAll("function prototype has parameter after varargs");
307 },318 },
308319
320 .expected_semi_after_decl => {
321 return stream.writeAll("expected ';' after declaration");
322 },
323 .expected_semi_after_stmt => {
324 return stream.writeAll("expected ';' after statement");
325 },
326
309 .expected_token => {327 .expected_token => {
310 const found_tag = token_tags[parse_error.token];328 const found_tag = token_tags[parse_error.token];
311 const expected_symbol = parse_error.extra.expected_tag.symbol();329 const expected_symbol = parse_error.extra.expected_tag.symbol();
...@@ -2495,6 +2513,10 @@ pub const Error = struct {...@@ -2495,6 +2513,10 @@ pub const Error = struct {
2495 unattached_doc_comment,2513 unattached_doc_comment,
2496 varargs_nonfinal,2514 varargs_nonfinal,
24972515
2516 // these have `token` set to token after which a semicolon was expected
2517 expected_semi_after_decl,
2518 expected_semi_after_stmt,
2519
2498 /// `expected_tag` is populated.2520 /// `expected_tag` is populated.
2499 expected_token,2521 expected_token,
2500 };2522 };
lib/std/zig/parse.zig+14-5
...@@ -586,7 +586,7 @@ const Parser = struct {...@@ -586,7 +586,7 @@ const Parser = struct {
586 const thread_local_token = p.eatToken(.keyword_threadlocal);586 const thread_local_token = p.eatToken(.keyword_threadlocal);
587 const var_decl = try p.parseVarDecl();587 const var_decl = try p.parseVarDecl();
588 if (var_decl != 0) {588 if (var_decl != 0) {
589 _ = try p.expectToken(.semicolon);589 try p.expectSemicolon(.expected_semi_after_decl, false);
590 return var_decl;590 return var_decl;
591 }591 }
592 if (thread_local_token != null) {592 if (thread_local_token != null) {
...@@ -614,7 +614,7 @@ const Parser = struct {...@@ -614,7 +614,7 @@ const Parser = struct {
614 fn expectUsingNamespace(p: *Parser) !Node.Index {614 fn expectUsingNamespace(p: *Parser) !Node.Index {
615 const usingnamespace_token = p.assertToken(.keyword_usingnamespace);615 const usingnamespace_token = p.assertToken(.keyword_usingnamespace);
616 const expr = try p.expectExpr();616 const expr = try p.expectExpr();
617 _ = try p.expectToken(.semicolon);617 try p.expectSemicolon(.expected_semi_after_decl, false);
618 return p.addNode(.{618 return p.addNode(.{
619 .tag = .@"usingnamespace",619 .tag = .@"usingnamespace",
620 .main_token = usingnamespace_token,620 .main_token = usingnamespace_token,
...@@ -851,7 +851,7 @@ const Parser = struct {...@@ -851,7 +851,7 @@ const Parser = struct {
851851
852 const var_decl = try p.parseVarDecl();852 const var_decl = try p.parseVarDecl();
853 if (var_decl != 0) {853 if (var_decl != 0) {
854 _ = try p.expectTokenRecoverable(.semicolon);854 try p.expectSemicolon(.expected_semi_after_decl, true);
855 return var_decl;855 return var_decl;
856 }856 }
857857
...@@ -915,7 +915,7 @@ const Parser = struct {...@@ -915,7 +915,7 @@ const Parser = struct {
915915
916 const assign_expr = try p.parseAssignExpr();916 const assign_expr = try p.parseAssignExpr();
917 if (assign_expr != 0) {917 if (assign_expr != 0) {
918 _ = try p.expectTokenRecoverable(.semicolon);918 try p.expectSemicolon(.expected_semi_after_stmt, true);
919 return assign_expr;919 return assign_expr;
920 }920 }
921921
...@@ -1205,7 +1205,7 @@ const Parser = struct {...@@ -1205,7 +1205,7 @@ const Parser = struct {
1205 }1205 }
1206 const assign_expr = try p.parseAssignExpr();1206 const assign_expr = try p.parseAssignExpr();
1207 if (assign_expr != 0) {1207 if (assign_expr != 0) {
1208 _ = try p.expectTokenRecoverable(.semicolon);1208 try p.expectSemicolon(.expected_semi_after_stmt, true);
1209 return assign_expr;1209 return assign_expr;
1210 }1210 }
1211 return null_node;1211 return null_node;
...@@ -3664,6 +3664,15 @@ const Parser = struct {...@@ -3664,6 +3664,15 @@ const Parser = struct {
3664 }3664 }
3665 }3665 }
36663666
3667 fn expectSemicolon(p: *Parser, tag: AstError.Tag, recoverable: bool) Error!void {
3668 if (p.token_tags[p.tok_i] == .semicolon) {
3669 _ = p.nextToken();
3670 return;
3671 }
3672 try p.warnMsg(.{ .tag = tag, .token = p.tok_i - 1 });
3673 if (!recoverable) return error.ParseError;
3674 }
3675
3667 fn nextToken(p: *Parser) TokenIndex {3676 fn nextToken(p: *Parser) TokenIndex {
3668 const result = p.tok_i;3677 const result = p.tok_i;
3669 p.tok_i += 1;3678 p.tok_i += 1;
src/Module.zig+2-1
...@@ -2995,13 +2995,14 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2995,13 +2995,14 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2995 const token_starts = file.tree.tokens.items(.start);2995 const token_starts = file.tree.tokens.items(.start);
2996 const token_tags = file.tree.tokens.items(.tag);2996 const token_tags = file.tree.tokens.items(.tag);
29972997
2998 const extra_offset = file.tree.errorOffset(parse_err.tag, parse_err.token);
2998 try file.tree.renderError(parse_err, msg.writer());2999 try file.tree.renderError(parse_err, msg.writer());
2999 const err_msg = try gpa.create(ErrorMsg);3000 const err_msg = try gpa.create(ErrorMsg);
3000 err_msg.* = .{3001 err_msg.* = .{
3001 .src_loc = .{3002 .src_loc = .{
3002 .file_scope = file,3003 .file_scope = file,
3003 .parent_decl_node = 0,3004 .parent_decl_node = 0,
3004 .lazy = .{ .byte_abs = token_starts[parse_err.token] },3005 .lazy = .{ .byte_abs = token_starts[parse_err.token] + extra_offset },
3005 },3006 },
3006 .msg = msg.toOwnedSlice(),3007 .msg = msg.toOwnedSlice(),
3007 };3008 };
src/main.zig+3-2
...@@ -4040,13 +4040,14 @@ fn printErrMsgToStdErr(...@@ -4040,13 +4040,14 @@ fn printErrMsgToStdErr(
4040 notes_len += 1;4040 notes_len += 1;
4041 }4041 }
40424042
4043 const extra_offset = tree.errorOffset(parse_error.tag, parse_error.token);
4043 const message: Compilation.AllErrors.Message = .{4044 const message: Compilation.AllErrors.Message = .{
4044 .src = .{4045 .src = .{
4045 .src_path = path,4046 .src_path = path,
4046 .msg = text,4047 .msg = text,
4047 .byte_offset = @intCast(u32, start_loc.line_start),4048 .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
4048 .line = @intCast(u32, start_loc.line),4049 .line = @intCast(u32, start_loc.line),
4049 .column = @intCast(u32, start_loc.column),4050 .column = @intCast(u32, start_loc.column) + extra_offset,
4050 .source_line = source_line,4051 .source_line = source_line,
4051 .notes = notes_buffer[0..notes_len],4052 .notes = notes_buffer[0..notes_len],
4052 },4053 },