authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-13 13:18:30+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-13 13:46:58+02:00
log6456af5a45cc12c0cd28d957dfedc72c369a157e
tree4a90d06dc7053134224bc6187cd06aee03efaa4b
parentddd6de86f7eb71814d3605d3e0ea9ed01d075613

parser: make missing comma errors point to the end of the previous token


2 files changed, 71 insertions(+), 52 deletions(-)

lib/std/zig/Ast.zig+29-6
...@@ -70,6 +70,13 @@ pub fn errorOffset(tree:Ast, error_tag: Error.Tag, token: TokenIndex) u32 {...@@ -70,6 +70,13 @@ pub fn errorOffset(tree:Ast, error_tag: Error.Tag, token: TokenIndex) u32 {
70 return switch (error_tag) {70 return switch (error_tag) {
71 .expected_semi_after_decl,71 .expected_semi_after_decl,
72 .expected_semi_after_stmt,72 .expected_semi_after_stmt,
73 .expected_comma_after_field,
74 .expected_comma_after_arg,
75 .expected_comma_after_param,
76 .expected_comma_after_initializer,
77 .expected_comma_after_switch_prong,
78 .expected_semi_or_else,
79 .expected_semi_or_lbrace,
73 => @intCast(u32, tree.tokenSlice(token).len),80 => @intCast(u32, tree.tokenSlice(token).len),
74 else => 0,81 else => 0,
75 };82 };
...@@ -227,14 +234,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -227,14 +234,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
227 });234 });
228 },235 },
229 .expected_semi_or_else => {236 .expected_semi_or_else => {
230 return stream.print("expected ';' or 'else', found '{s}'", .{237 return stream.writeAll("expected ';' or 'else' after statement");
231 token_tags[parse_error.token].symbol(),
232 });
233 },238 },
234 .expected_semi_or_lbrace => {239 .expected_semi_or_lbrace => {
235 return stream.print("expected ';' or '{{', found '{s}'", .{240 return stream.writeAll("expected ';' or block after function prototype");
236 token_tags[parse_error.token].symbol(),
237 });
238 },241 },
239 .expected_statement => {242 .expected_statement => {
240 return stream.print("expected statement, found '{s}'", .{243 return stream.print("expected statement, found '{s}'", .{
...@@ -323,6 +326,21 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -323,6 +326,21 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
323 .expected_semi_after_stmt => {326 .expected_semi_after_stmt => {
324 return stream.writeAll("expected ';' after statement");327 return stream.writeAll("expected ';' after statement");
325 },328 },
329 .expected_comma_after_field => {
330 return stream.writeAll("expected ',' after field");
331 },
332 .expected_comma_after_arg => {
333 return stream.writeAll("expected ',' after argument");
334 },
335 .expected_comma_after_param => {
336 return stream.writeAll("expected ',' after parameter");
337 },
338 .expected_comma_after_initializer => {
339 return stream.writeAll("expected ',' after initializer");
340 },
341 .expected_comma_after_switch_prong => {
342 return stream.writeAll("expected ',' after switch prong");
343 },
326344
327 .expected_token => {345 .expected_token => {
328 const found_tag = token_tags[parse_error.token];346 const found_tag = token_tags[parse_error.token];
...@@ -2516,6 +2534,11 @@ pub const Error = struct {...@@ -2516,6 +2534,11 @@ pub const Error = struct {
2516 // these have `token` set to token after which a semicolon was expected2534 // these have `token` set to token after which a semicolon was expected
2517 expected_semi_after_decl,2535 expected_semi_after_decl,
2518 expected_semi_after_stmt,2536 expected_semi_after_stmt,
2537 expected_comma_after_field,
2538 expected_comma_after_arg,
2539 expected_comma_after_param,
2540 expected_comma_after_initializer,
2541 expected_comma_after_switch_prong,
25192542
2520 /// `expected_tag` is populated.2543 /// `expected_tag` is populated.
2521 expected_token,2544 expected_token,
lib/std/zig/parse.zig+42-46
...@@ -160,6 +160,12 @@ const Parser = struct {...@@ -160,6 +160,12 @@ const Parser = struct {
160 .extra = .{ .expected_tag = expected_token },160 .extra = .{ .expected_tag = expected_token },
161 });161 });
162 }162 }
163
164 fn warnExpectedAfter(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {
165 @setCold(true);
166 try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i - 1 });
167 }
168
163 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {169 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {
164 @setCold(true);170 @setCold(true);
165 try p.errors.append(p.gpa, msg);171 try p.errors.append(p.gpa, msg);
...@@ -258,7 +264,7 @@ const Parser = struct {...@@ -258,7 +264,7 @@ const Parser = struct {
258 }264 }
259 // There is not allowed to be a decl after a field with no comma.265 // There is not allowed to be a decl after a field with no comma.
260 // Report error but recover parser.266 // Report error but recover parser.
261 try p.warnExpected(.comma);267 try p.warnExpectedAfter(.expected_comma_after_field);
262 p.findNextContainerMember();268 p.findNextContainerMember();
263 }269 }
264 },270 },
...@@ -361,7 +367,7 @@ const Parser = struct {...@@ -361,7 +367,7 @@ const Parser = struct {
361 }367 }
362 // There is not allowed to be a decl after a field with no comma.368 // There is not allowed to be a decl after a field with no comma.
363 // Report error but recover parser.369 // Report error but recover parser.
364 try p.warnExpected(.comma);370 try p.warnExpectedAfter(.expected_comma_after_field);
365 p.findNextContainerMember();371 p.findNextContainerMember();
366 }372 }
367 },373 },
...@@ -573,7 +579,7 @@ const Parser = struct {...@@ -573,7 +579,7 @@ const Parser = struct {
573 // Since parseBlock only return error.ParseError on579 // Since parseBlock only return error.ParseError on
574 // a missing '}' we can assume this function was580 // a missing '}' we can assume this function was
575 // supposed to end here.581 // supposed to end here.
576 try p.warn(.expected_semi_or_lbrace);582 try p.warnExpectedAfter(.expected_semi_or_lbrace);
577 return null_node;583 return null_node;
578 },584 },
579 }585 }
...@@ -984,7 +990,7 @@ const Parser = struct {...@@ -984,7 +990,7 @@ const Parser = struct {
984 };990 };
985 _ = p.eatToken(.keyword_else) orelse {991 _ = p.eatToken(.keyword_else) orelse {
986 if (else_required) {992 if (else_required) {
987 try p.warn(.expected_semi_or_else);993 try p.warnExpectedAfter(.expected_semi_or_else);
988 }994 }
989 return p.addNode(.{995 return p.addNode(.{
990 .tag = .if_simple,996 .tag = .if_simple,
...@@ -1079,7 +1085,7 @@ const Parser = struct {...@@ -1079,7 +1085,7 @@ const Parser = struct {
1079 };1085 };
1080 _ = p.eatToken(.keyword_else) orelse {1086 _ = p.eatToken(.keyword_else) orelse {
1081 if (else_required) {1087 if (else_required) {
1082 try p.warn(.expected_semi_or_else);1088 try p.warnExpectedAfter(.expected_semi_or_else);
1083 }1089 }
1084 return p.addNode(.{1090 return p.addNode(.{
1085 .tag = .for_simple,1091 .tag = .for_simple,
...@@ -1154,7 +1160,7 @@ const Parser = struct {...@@ -1154,7 +1160,7 @@ const Parser = struct {
1154 };1160 };
1155 _ = p.eatToken(.keyword_else) orelse {1161 _ = p.eatToken(.keyword_else) orelse {
1156 if (else_required) {1162 if (else_required) {
1157 try p.warn(.expected_semi_or_else);1163 try p.warnExpectedAfter(.expected_semi_or_else);
1158 }1164 }
1159 if (cont_expr == 0) {1165 if (cont_expr == 0) {
1160 return p.addNode(.{1166 return p.addNode(.{
...@@ -2038,7 +2044,7 @@ const Parser = struct {...@@ -2038,7 +2044,7 @@ const Parser = struct {
2038 },2044 },
2039 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2045 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2040 // Likely just a missing comma; give error but continue parsing.2046 // Likely just a missing comma; give error but continue parsing.
2041 else => try p.warnExpected(.comma),2047 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2042 }2048 }
2043 if (p.eatToken(.r_brace)) |_| break;2049 if (p.eatToken(.r_brace)) |_| break;
2044 const next = try p.expectFieldInit();2050 const next = try p.expectFieldInit();
...@@ -2079,7 +2085,7 @@ const Parser = struct {...@@ -2079,7 +2085,7 @@ const Parser = struct {
2079 },2085 },
2080 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2086 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2081 // Likely just a missing comma; give error but continue parsing.2087 // Likely just a missing comma; give error but continue parsing.
2082 else => try p.warnExpected(.comma),2088 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2083 }2089 }
2084 }2090 }
2085 const comma = (p.token_tags[p.tok_i - 2] == .comma);2091 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2158,7 +2164,7 @@ const Parser = struct {...@@ -2158,7 +2164,7 @@ const Parser = struct {
2158 },2164 },
2159 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2165 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2160 // Likely just a missing comma; give error but continue parsing.2166 // Likely just a missing comma; give error but continue parsing.
2161 else => try p.warnExpected(.comma),2167 else => try p.warnExpectedAfter(.expected_comma_after_arg),
2162 }2168 }
2163 }2169 }
2164 const comma = (p.token_tags[p.tok_i - 2] == .comma);2170 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2214,7 +2220,7 @@ const Parser = struct {...@@ -2214,7 +2220,7 @@ const Parser = struct {
2214 },2220 },
2215 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2221 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2216 // Likely just a missing comma; give error but continue parsing.2222 // Likely just a missing comma; give error but continue parsing.
2217 else => try p.warnExpected(.comma),2223 else => try p.warnExpectedAfter(.expected_comma_after_arg),
2218 }2224 }
2219 }2225 }
2220 const comma = (p.token_tags[p.tok_i - 2] == .comma);2226 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2455,7 +2461,7 @@ const Parser = struct {...@@ -2455,7 +2461,7 @@ const Parser = struct {
2455 },2461 },
2456 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2462 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2457 // Likely just a missing comma; give error but continue parsing.2463 // Likely just a missing comma; give error but continue parsing.
2458 else => try p.warnExpected(.comma),2464 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2459 }2465 }
2460 if (p.eatToken(.r_brace)) |_| break;2466 if (p.eatToken(.r_brace)) |_| break;
2461 const next = try p.expectFieldInit();2467 const next = try p.expectFieldInit();
...@@ -2507,7 +2513,7 @@ const Parser = struct {...@@ -2507,7 +2513,7 @@ const Parser = struct {
2507 },2513 },
2508 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2514 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2509 // Likely just a missing comma; give error but continue parsing.2515 // Likely just a missing comma; give error but continue parsing.
2510 else => try p.warnExpected(.comma),2516 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2511 }2517 }
2512 }2518 }
2513 const comma = (p.token_tags[p.tok_i - 2] == .comma);2519 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2568,7 +2574,7 @@ const Parser = struct {...@@ -2568,7 +2574,7 @@ const Parser = struct {
2568 },2574 },
2569 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2575 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2570 // Likely just a missing comma; give error but continue parsing.2576 // Likely just a missing comma; give error but continue parsing.
2571 else => try p.warnExpected(.comma),2577 else => try p.warnExpectedAfter(.expected_comma_after_field),
2572 }2578 }
2573 }2579 }
2574 return p.addNode(.{2580 return p.addNode(.{
...@@ -3383,7 +3389,24 @@ const Parser = struct {...@@ -3383,7 +3389,24 @@ const Parser = struct {
33833389
3384 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?3390 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
3385 fn parseSwitchProngList(p: *Parser) !Node.SubRange {3391 fn parseSwitchProngList(p: *Parser) !Node.SubRange {
3386 return ListParseFn(parseSwitchProng)(p);3392 const scratch_top = p.scratch.items.len;
3393 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3394
3395 while (true) {
3396 const item = try parseSwitchProng(p);
3397 if (item == 0) break;
3398
3399 try p.scratch.append(p.gpa, item);
3400
3401 switch (p.token_tags[p.tok_i]) {
3402 .comma => p.tok_i += 1,
3403 // All possible delimiters.
3404 .colon, .r_paren, .r_brace, .r_bracket => break,
3405 // Likely just a missing comma; give error but continue parsing.
3406 else => try p.warnExpectedAfter(.expected_comma_after_switch_prong),
3407 }
3408 }
3409 return p.listToSpan(p.scratch.items[scratch_top..]);
3387 }3410 }
33883411
3389 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?3412 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
...@@ -3409,7 +3432,7 @@ const Parser = struct {...@@ -3409,7 +3432,7 @@ const Parser = struct {
3409 },3432 },
3410 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),3433 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
3411 // Likely just a missing comma; give error but continue parsing.3434 // Likely just a missing comma; give error but continue parsing.
3412 else => try p.warnExpected(.comma),3435 else => try p.warnExpectedAfter(.expected_comma_after_param),
3413 }3436 }
3414 }3437 }
3415 if (varargs == .nonfinal) {3438 if (varargs == .nonfinal) {
...@@ -3423,33 +3446,6 @@ const Parser = struct {...@@ -3423,33 +3446,6 @@ const Parser = struct {
3423 };3446 };
3424 }3447 }
34253448
3426 const NodeParseFn = fn (p: *Parser) Error!Node.Index;
3427
3428 fn ListParseFn(comptime nodeParseFn: anytype) (fn (p: *Parser) Error!Node.SubRange) {
3429 return struct {
3430 pub fn parse(p: *Parser) Error!Node.SubRange {
3431 const scratch_top = p.scratch.items.len;
3432 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3433
3434 while (true) {
3435 const item = try nodeParseFn(p);
3436 if (item == 0) break;
3437
3438 try p.scratch.append(p.gpa, item);
3439
3440 switch (p.token_tags[p.tok_i]) {
3441 .comma => p.tok_i += 1,
3442 // All possible delimiters.
3443 .colon, .r_paren, .r_brace, .r_bracket => break,
3444 // Likely just a missing comma; give error but continue parsing.
3445 else => try p.warnExpected(.comma),
3446 }
3447 }
3448 return p.listToSpan(p.scratch.items[scratch_top..]);
3449 }
3450 }.parse;
3451 }
3452
3453 /// FnCallArguments <- LPAREN ExprList RPAREN3449 /// FnCallArguments <- LPAREN ExprList RPAREN
3454 /// ExprList <- (Expr COMMA)* Expr?3450 /// ExprList <- (Expr COMMA)* Expr?
3455 fn parseBuiltinCall(p: *Parser) !Node.Index {3451 fn parseBuiltinCall(p: *Parser) !Node.Index {
...@@ -3480,7 +3476,7 @@ const Parser = struct {...@@ -3480,7 +3476,7 @@ const Parser = struct {
3480 break;3476 break;
3481 },3477 },
3482 // Likely just a missing comma; give error but continue parsing.3478 // Likely just a missing comma; give error but continue parsing.
3483 else => try p.warnExpected(.comma),3479 else => try p.warnExpectedAfter(.expected_comma_after_arg),
3484 }3480 }
3485 }3481 }
3486 const comma = (p.token_tags[p.tok_i - 2] == .comma);3482 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -3576,7 +3572,7 @@ const Parser = struct {...@@ -3576,7 +3572,7 @@ const Parser = struct {
3576 }3572 }
35773573
3578 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3574 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
3579 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !Node.Index {3575 fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
3580 const if_token = p.eatToken(.keyword_if) orelse return null_node;3576 const if_token = p.eatToken(.keyword_if) orelse return null_node;
3581 _ = try p.expectToken(.l_paren);3577 _ = try p.expectToken(.l_paren);
3582 const condition = try p.expectExpr();3578 const condition = try p.expectExpr();
...@@ -3664,12 +3660,12 @@ const Parser = struct {...@@ -3664,12 +3660,12 @@ const Parser = struct {
3664 }3660 }
3665 }3661 }
36663662
3667 fn expectSemicolon(p: *Parser, tag: AstError.Tag, recoverable: bool) Error!void {3663 fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void {
3668 if (p.token_tags[p.tok_i] == .semicolon) {3664 if (p.token_tags[p.tok_i] == .semicolon) {
3669 _ = p.nextToken();3665 _ = p.nextToken();
3670 return;3666 return;
3671 }3667 }
3672 try p.warnMsg(.{ .tag = tag, .token = p.tok_i - 1 });3668 try p.warnExpectedAfter(error_tag);
3673 if (!recoverable) return error.ParseError;3669 if (!recoverable) return error.ParseError;
3674 }3670 }
36753671