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
signaturelock-open 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...@@ -232,6 +232,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top
232 switch (next) {232 switch (next) {
233 .Eof => break,233 .Eof => break,
234 else => {234 else => {
235 const index = it.index;
235 if (next == .RBrace) {236 if (next == .RBrace) {
236 if (!top_level) break;237 if (!top_level) break;
237 _ = nextToken(it);238 _ = nextToken(it);
...@@ -239,7 +240,6 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top...@@ -239,7 +240,6 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top
239240
240 // this was likely not supposed to end yet,241 // this was likely not supposed to end yet,
241 // try to find the next declaration242 // try to find the next declaration
242 const index = it.index;
243 findNextContainerMember(it);243 findNextContainerMember(it);
244 try tree.errors.push(.{244 try tree.errors.push(.{
245 .ExpectedContainerMembers = .{ .token = index },245 .ExpectedContainerMembers = .{ .token = index },
...@@ -411,20 +411,16 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -411,20 +411,16 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
411 fn_node.*.extern_export_inline_token = extern_export_inline_token;411 fn_node.*.extern_export_inline_token = extern_export_inline_token;
412 fn_node.*.lib_name = lib_name;412 fn_node.*.lib_name = lib_name;
413 if (eatToken(it, .Semicolon)) |_| return node;413 if (eatToken(it, .Semicolon)) |_| return node;
414 if (parseBlock(arena, it, tree) catch |err| switch (err) {414
415 error.OutOfMemory => return error.OutOfMemory,415 if (try expectNodeRecoverable(arena, it, tree, parseBlock, .{
416 // since parseBlock only return error.ParseError on416 // since parseBlock only return error.ParseError on
417 // a missing '}' we can assume this function was417 // a missing '}' we can assume this function was
418 // supposed to end here.418 // supposed to end here.
419 error.ParseError => return node,419 .ExpectedSemiOrLBrace = .{ .token = it.index },
420 }) |body_node| {420 })) |body_node| {
421 fn_node.body_node = body_node;421 fn_node.body_node = body_node;
422 return node;
423 }422 }
424 try tree.errors.push(.{423 return node;
425 .ExpectedSemiOrLBrace = .{ .token = it.index },
426 });
427 return error.ParseError;
428 }424 }
429425
430 if (extern_export_inline_token) |token| {426 if (extern_export_inline_token) |token| {
...@@ -499,14 +495,11 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -499,14 +495,11 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
499 const exclamation_token = eatToken(it, .Bang);495 const exclamation_token = eatToken(it, .Bang);
500496
501 const return_type_expr = (try parseVarType(arena, it, tree)) orelse497 const return_type_expr = (try parseVarType(arena, it, tree)) orelse
502 (try parseTypeExpr(arena, it, tree)) orelse blk: {498 try expectNodeRecoverable(arena, it, tree, parseTypeExpr, .{
503 try tree.errors.push(.{
504 .ExpectedReturnType = .{ .token = it.index },
505 });
506 // most likely the user forgot to specify the return type.499 // most likely the user forgot to specify the return type.
507 // Mark return type as invalid and try to continue.500 // Mark return type as invalid and try to continue.
508 break :blk null;501 .ExpectedReturnType = .{ .token = it.index },
509 };502 });
510503
511 // TODO https://github.com/ziglang/zig/issues/3750504 // TODO https://github.com/ziglang/zig/issues/3750
512 const R = Node.FnProto.ReturnType;505 const R = Node.FnProto.ReturnType;
...@@ -716,12 +709,7 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No...@@ -716,12 +709,7 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
716 if (try parseLabeledStatement(arena, it, tree)) |node| return node;709 if (try parseLabeledStatement(arena, it, tree)) |node| return node;
717 if (try parseSwitchExpr(arena, it, tree)) |node| return node;710 if (try parseSwitchExpr(arena, it, tree)) |node| return node;
718 if (try parseAssignExpr(arena, it, tree)) |node| {711 if (try parseAssignExpr(arena, it, tree)) |node| {
719 _ = eatToken(it, .Semicolon) orelse {712 _ = try expectTokenRecoverable(it, tree, .Semicolon);
720 try tree.errors.push(.{
721 .ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
722 });
723 // pretend we saw a semicolon and continue parsing
724 };
725 return node;713 return node;
726 }714 }
727715
...@@ -965,12 +953,7 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -965,12 +953,7 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
965fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {953fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
966 if (try parseBlockExpr(arena, it, tree)) |node| return node;954 if (try parseBlockExpr(arena, it, tree)) |node| return node;
967 if (try parseAssignExpr(arena, it, tree)) |node| {955 if (try parseAssignExpr(arena, it, tree)) |node| {
968 _ = eatToken(it, .Semicolon) orelse {956 _ = try expectTokenRecoverable(it, tree, .Semicolon);
969 try tree.errors.push(.{
970 .ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
971 });
972 // pretend we saw a semicolon and continue parsing
973 };
974 return node;957 return node;
975 }958 }
976 return null;959 return null;
...@@ -1487,17 +1470,19 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N...@@ -1487,17 +1470,19 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1487 return &node.base;1470 return &node.base;
1488 }1471 }
1489 if (eatToken(it, .Keyword_error)) |token| {1472 if (eatToken(it, .Keyword_error)) |token| {
1490 const period = try expectToken(it, tree, .Period);1473 const period = try expectTokenRecoverable(it, tree, .Period);
1491 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{1474 const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{
1492 .ExpectedIdentifier = .{ .token = it.index },1475 .ExpectedIdentifier = .{ .token = it.index },
1493 });1476 });
1494 const global_error_set = try createLiteral(arena, Node.ErrorType, token);1477 const global_error_set = try createLiteral(arena, Node.ErrorType, token);
1478 if (period == null or identifier == null) return global_error_set;
1479
1495 const node = try arena.create(Node.InfixOp);1480 const node = try arena.create(Node.InfixOp);
1496 node.* = .{1481 node.* = .{
1497 .op_token = period,1482 .op_token = period.?,
1498 .lhs = global_error_set,1483 .lhs = global_error_set,
1499 .op = .Period,1484 .op = .Period,
1500 .rhs = identifier,1485 .rhs = identifier.?,
1501 };1486 };
1502 return &node.base;1487 return &node.base;
1503 }1488 }
...@@ -3259,6 +3244,11 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {...@@ -3259,6 +3244,11 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {
3259}3244}
32603245
3261fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {3246fn 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 {
3262 const token = nextToken(it);3252 const token = nextToken(it);
3263 if (token.ptr.id != id) {3253 if (token.ptr.id != id) {
3264 try tree.errors.push(.{3254 try tree.errors.push(.{
...@@ -3266,7 +3256,7 @@ fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {...@@ -3266,7 +3256,7 @@ fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
3266 });3256 });
3267 // go back so that we can recover properly3257 // go back so that we can recover properly
3268 putBackToken(it, token.index);3258 putBackToken(it, token.index);
3269 return error.ParseError;3259 return null;
3270 }3260 }
3271 return token.index;3261 return token.index;
3272}3262}
...@@ -3306,9 +3296,20 @@ fn expectNode(...@@ -3306,9 +3296,20 @@ fn expectNode(
3306 parseFn: NodeParseFn,3296 parseFn: NodeParseFn,
3307 err: AstError, // if parsing fails3297 err: AstError, // if parsing fails
3308) Error!*Node {3298) 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 {
3309 return (try parseFn(arena, it, tree)) orelse {3310 return (try parseFn(arena, it, tree)) orelse {
3310 try tree.errors.push(err);3311 try tree.errors.push(err);
3311 return error.ParseError;3312 return null;
3312 };3313 };
3313}3314}
33143315
lib/std/zig/parser_test.zig+12
...@@ -172,6 +172,18 @@ test "recovery: mismatched bracket at top level" {...@@ -172,6 +172,18 @@ test "recovery: mismatched bracket at top level" {
172 });172 });
173}173}
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
175test "zig fmt: top-level fields" {187test "zig fmt: top-level fields" {
176 try testCanonical(188 try testCanonical(
177 \\a: did_you_know,189 \\a: did_you_know,