authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-16 12:09:34+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-16 12:09:34+03:00
log6ca0def499a610c638c38cd79d8df91035493083
treec42000ab7cf63cbc0f1cfa9cfd7eac9991cd7573
parentb2f16d4484d2506d6a1e8a7d9f516f780d7fbd22
signature Commit is signed but in an unrecognized format.

recover from invalid global error set access


2 files changed, 47 insertions(+), 34 deletions(-)

lib/std/zig/parse.zig+35-34
......@@ -232,6 +232,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top
232232 switch (next) {
233233 .Eof => break,
234234 else => {
235 const index = it.index;
235236 if (next == .RBrace) {
236237 if (!top_level) break;
237238 _ = nextToken(it);
......@@ -239,7 +240,6 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top
239240
240241 // this was likely not supposed to end yet,
241242 // try to find the next declaration
242 const index = it.index;
243243 findNextContainerMember(it);
244244 try tree.errors.push(.{
245245 .ExpectedContainerMembers = .{ .token = index },
......@@ -411,20 +411,16 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
411411 fn_node.*.extern_export_inline_token = extern_export_inline_token;
412412 fn_node.*.lib_name = lib_name;
413413 if (eatToken(it, .Semicolon)) |_| return node;
414 if (parseBlock(arena, it, tree) catch |err| switch (err) {
415 error.OutOfMemory => return error.OutOfMemory,
414
415 if (try expectNodeRecoverable(arena, it, tree, parseBlock, .{
416416 // since parseBlock only return error.ParseError on
417417 // a missing '}' we can assume this function was
418418 // supposed to end here.
419 error.ParseError => return node,
420 }) |body_node| {
419 .ExpectedSemiOrLBrace = .{ .token = it.index },
420 })) |body_node| {
421421 fn_node.body_node = body_node;
422 return node;
423422 }
424 try tree.errors.push(.{
425 .ExpectedSemiOrLBrace = .{ .token = it.index },
426 });
427 return error.ParseError;
423 return node;
428424 }
429425
430426 if (extern_export_inline_token) |token| {
......@@ -499,14 +495,11 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
499495 const exclamation_token = eatToken(it, .Bang);
500496
501497 const return_type_expr = (try parseVarType(arena, it, tree)) orelse
502 (try parseTypeExpr(arena, it, tree)) orelse blk: {
503 try tree.errors.push(.{
504 .ExpectedReturnType = .{ .token = it.index },
505 });
498 try expectNodeRecoverable(arena, it, tree, parseTypeExpr, .{
506499 // most likely the user forgot to specify the return type.
507500 // Mark return type as invalid and try to continue.
508 break :blk null;
509 };
501 .ExpectedReturnType = .{ .token = it.index },
502 });
510503
511504 // TODO https://github.com/ziglang/zig/issues/3750
512505 const R = Node.FnProto.ReturnType;
......@@ -716,12 +709,7 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
716709 if (try parseLabeledStatement(arena, it, tree)) |node| return node;
717710 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
718711 if (try parseAssignExpr(arena, it, tree)) |node| {
719 _ = eatToken(it, .Semicolon) orelse {
720 try tree.errors.push(.{
721 .ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
722 });
723 // pretend we saw a semicolon and continue parsing
724 };
712 _ = try expectTokenRecoverable(it, tree, .Semicolon);
725713 return node;
726714 }
727715
......@@ -965,12 +953,7 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
965953fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
966954 if (try parseBlockExpr(arena, it, tree)) |node| return node;
967955 if (try parseAssignExpr(arena, it, tree)) |node| {
968 _ = eatToken(it, .Semicolon) orelse {
969 try tree.errors.push(.{
970 .ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
971 });
972 // pretend we saw a semicolon and continue parsing
973 };
956 _ = try expectTokenRecoverable(it, tree, .Semicolon);
974957 return node;
975958 }
976959 return null;
......@@ -1487,17 +1470,19 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
14871470 return &node.base;
14881471 }
14891472 if (eatToken(it, .Keyword_error)) |token| {
1490 const period = try expectToken(it, tree, .Period);
1491 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
1473 const period = try expectTokenRecoverable(it, tree, .Period);
1474 const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{
14921475 .ExpectedIdentifier = .{ .token = it.index },
14931476 });
14941477 const global_error_set = try createLiteral(arena, Node.ErrorType, token);
1478 if (period == null or identifier == null) return global_error_set;
1479
14951480 const node = try arena.create(Node.InfixOp);
14961481 node.* = .{
1497 .op_token = period,
1482 .op_token = period.?,
14981483 .lhs = global_error_set,
14991484 .op = .Period,
1500 .rhs = identifier,
1485 .rhs = identifier.?,
15011486 };
15021487 return &node.base;
15031488 }
......@@ -3259,6 +3244,11 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {
32593244}
32603245
32613246fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
3247 return (try expectTokenRecoverable(it, tree, id)) orelse
3248 error.ParseError;
3249}
3250
3251fn expectTokenRecoverable(it: *TokenIterator, tree: *Tree, id: Token.Id) !?TokenIndex {
32623252 const token = nextToken(it);
32633253 if (token.ptr.id != id) {
32643254 try tree.errors.push(.{
......@@ -3266,7 +3256,7 @@ fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
32663256 });
32673257 // go back so that we can recover properly
32683258 putBackToken(it, token.index);
3269 return error.ParseError;
3259 return null;
32703260 }
32713261 return token.index;
32723262}
......@@ -3306,9 +3296,20 @@ fn expectNode(
33063296 parseFn: NodeParseFn,
33073297 err: AstError, // if parsing fails
33083298) Error!*Node {
3299 return (try expectNodeRecoverable(arena, it, tree, parseFn, err)) orelse
3300 return error.ParseError;
3301}
3302
3303fn expectNodeRecoverable(
3304 arena: *Allocator,
3305 it: *TokenIterator,
3306 tree: *Tree,
3307 parseFn: NodeParseFn,
3308 err: AstError, // if parsing fails
3309) !?*Node {
33093310 return (try parseFn(arena, it, tree)) orelse {
33103311 try tree.errors.push(err);
3311 return error.ParseError;
3312 return null;
33123313 };
33133314}
33143315
lib/std/zig/parser_test.zig+12
......@@ -172,6 +172,18 @@ test "recovery: mismatched bracket at top level" {
172172 });
173173}
174174
175test "recovery: invalid global error set access" {
176 try testError(
177 \\test "" {
178 \\ error && foo;
179 \\}
180 , &[_]Error{
181 .ExpectedToken,
182 .ExpectedIdentifier,
183 .InvalidAnd,
184 });
185}
186
175187test "zig fmt: top-level fields" {
176188 try testCanonical(
177189 \\a: did_you_know,