| author | |
| committer | |
| log | ddd6de86f7eb71814d3605d3e0ea9ed01d075613 |
| tree | 4d6373402a99ed70eba6aa66dbcc3624036dbe30 |
| parent | 0b7347fd18eee7dd829cd9aaed3683123d84859b |
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 | 64 | return @import("./render.zig").renderTree(buffer, tree); |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | /// Returns an extra offset for column and byte offset of errors that | |
| 68 | /// should point after the token in the error message. | |
| 69 | pub 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 | ||
| 67 | 78 | pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location { |
| 68 | 79 | var loc = Location{ |
| 69 | 80 | .line = 0, |
| ... | ... | @@ -306,6 +317,13 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 306 | 317 | return stream.writeAll("function prototype has parameter after varargs"); |
| 307 | 318 | }, |
| 308 | 319 | |
| 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 | 327 | .expected_token => { |
| 310 | 328 | const found_tag = token_tags[parse_error.token]; |
| 311 | 329 | const expected_symbol = parse_error.extra.expected_tag.symbol(); |
| ... | ... | @@ -2495,6 +2513,10 @@ pub const Error = struct { |
| 2495 | 2513 | unattached_doc_comment, |
| 2496 | 2514 | varargs_nonfinal, |
| 2497 | 2515 | |
| 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 | 2520 | /// `expected_tag` is populated. |
| 2499 | 2521 | expected_token, |
| 2500 | 2522 | }; |
lib/std/zig/parse.zig+14-5| ... | ... | @@ -586,7 +586,7 @@ const Parser = struct { |
| 586 | 586 | const thread_local_token = p.eatToken(.keyword_threadlocal); |
| 587 | 587 | const var_decl = try p.parseVarDecl(); |
| 588 | 588 | if (var_decl != 0) { |
| 589 | _ = try p.expectToken(.semicolon); | |
| 589 | try p.expectSemicolon(.expected_semi_after_decl, false); | |
| 590 | 590 | return var_decl; |
| 591 | 591 | } |
| 592 | 592 | if (thread_local_token != null) { |
| ... | ... | @@ -614,7 +614,7 @@ const Parser = struct { |
| 614 | 614 | fn expectUsingNamespace(p: *Parser) !Node.Index { |
| 615 | 615 | const usingnamespace_token = p.assertToken(.keyword_usingnamespace); |
| 616 | 616 | const expr = try p.expectExpr(); |
| 617 | _ = try p.expectToken(.semicolon); | |
| 617 | try p.expectSemicolon(.expected_semi_after_decl, false); | |
| 618 | 618 | return p.addNode(.{ |
| 619 | 619 | .tag = .@"usingnamespace", |
| 620 | 620 | .main_token = usingnamespace_token, |
| ... | ... | @@ -851,7 +851,7 @@ const Parser = struct { |
| 851 | 851 | |
| 852 | 852 | const var_decl = try p.parseVarDecl(); |
| 853 | 853 | if (var_decl != 0) { |
| 854 | _ = try p.expectTokenRecoverable(.semicolon); | |
| 854 | try p.expectSemicolon(.expected_semi_after_decl, true); | |
| 855 | 855 | return var_decl; |
| 856 | 856 | } |
| 857 | 857 | |
| ... | ... | @@ -915,7 +915,7 @@ const Parser = struct { |
| 915 | 915 | |
| 916 | 916 | const assign_expr = try p.parseAssignExpr(); |
| 917 | 917 | if (assign_expr != 0) { |
| 918 | _ = try p.expectTokenRecoverable(.semicolon); | |
| 918 | try p.expectSemicolon(.expected_semi_after_stmt, true); | |
| 919 | 919 | return assign_expr; |
| 920 | 920 | } |
| 921 | 921 | |
| ... | ... | @@ -1205,7 +1205,7 @@ const Parser = struct { |
| 1205 | 1205 | } |
| 1206 | 1206 | const assign_expr = try p.parseAssignExpr(); |
| 1207 | 1207 | if (assign_expr != 0) { |
| 1208 | _ = try p.expectTokenRecoverable(.semicolon); | |
| 1208 | try p.expectSemicolon(.expected_semi_after_stmt, true); | |
| 1209 | 1209 | return assign_expr; |
| 1210 | 1210 | } |
| 1211 | 1211 | return null_node; |
| ... | ... | @@ -3664,6 +3664,15 @@ const Parser = struct { |
| 3664 | 3664 | } |
| 3665 | 3665 | } |
| 3666 | 3666 | |
| 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 | 3676 | fn nextToken(p: *Parser) TokenIndex { |
| 3668 | 3677 | const result = p.tok_i; |
| 3669 | 3678 | p.tok_i += 1; |
src/Module.zig+2-1| ... | ... | @@ -2995,13 +2995,14 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2995 | 2995 | const token_starts = file.tree.tokens.items(.start); |
| 2996 | 2996 | const token_tags = file.tree.tokens.items(.tag); |
| 2997 | 2997 | |
| 2998 | const extra_offset = file.tree.errorOffset(parse_err.tag, parse_err.token); | |
| 2998 | 2999 | try file.tree.renderError(parse_err, msg.writer()); |
| 2999 | 3000 | const err_msg = try gpa.create(ErrorMsg); |
| 3000 | 3001 | err_msg.* = .{ |
| 3001 | 3002 | .src_loc = .{ |
| 3002 | 3003 | .file_scope = file, |
| 3003 | 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 | 3007 | .msg = msg.toOwnedSlice(), |
| 3007 | 3008 | }; |
src/main.zig+3-2| ... | ... | @@ -4040,13 +4040,14 @@ fn printErrMsgToStdErr( |
| 4040 | 4040 | notes_len += 1; |
| 4041 | 4041 | } |
| 4042 | 4042 | |
| 4043 | const extra_offset = tree.errorOffset(parse_error.tag, parse_error.token); | |
| 4043 | 4044 | const message: Compilation.AllErrors.Message = .{ |
| 4044 | 4045 | .src = .{ |
| 4045 | 4046 | .src_path = path, |
| 4046 | 4047 | .msg = text, |
| 4047 | .byte_offset = @intCast(u32, start_loc.line_start), | |
| 4048 | .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset, | |
| 4048 | 4049 | .line = @intCast(u32, start_loc.line), |
| 4049 | .column = @intCast(u32, start_loc.column), | |
| 4050 | .column = @intCast(u32, start_loc.column) + extra_offset, | |
| 4050 | 4051 | .source_line = source_line, |
| 4051 | 4052 | .notes = notes_buffer[0..notes_len], |
| 4052 | 4053 | }, |