diff options
| author | Vexu <git@vexu.eu> | 2020-05-13 23:28:04 +0300 |
|---|---|---|
| committer | Vexu <git@vexu.eu> | 2020-05-13 23:28:04 +0300 |
| commit | ad71d959d7d1b5f3a771dc2c1eaf37dbd7cd0852 (patch) | |
| tree | 6d039ebd3f9df24e0b2f9d7acc2b6bdd50e7859e /lib | |
| parent | 2296906e2ad54c387b4b19784148c47a26969cdc (diff) | |
| download | zig-ad71d959d7d1b5f3a771dc2c1eaf37dbd7cd0852.tar.gz zig-ad71d959d7d1b5f3a771dc2c1eaf37dbd7cd0852.zip | |
correctly recover from invalid top level declarations
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/zig/parse.zig | 20 | ||||
| -rw-r--r-- | lib/std/zig/parser_test.zig | 22 |
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 6052d92d6a..d8d1d4b427 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -130,7 +130,13 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All const visib_token = eatToken(it, .Keyword_pub); - if (try parseTopLevelDecl(arena, it, tree)) |node| { + if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + // try again + continue; + }, + }) |node| { if (field_state == .seen) { field_state = .{ .end = visib_token orelse node.firstToken() }; } @@ -315,7 +321,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl /// / KEYWORD_usingnamespace Expr SEMICOLON -fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!?*Node { +fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { var lib_name: ?*Node = null; const extern_export_inline_token = blk: { if (eatToken(it, .Keyword_export)) |token| break :blk token; @@ -334,7 +340,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat // this fn will likely have a body so we // use findEndOfBlock instead of findToken. findEndOfBlock(it); - return null; + return error.ParseError; }, }) |node| { const fn_node = node.cast(Node.FnProto).?; @@ -373,7 +379,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat error.ParseError => { // try to skip to next decl findToken(it, .Semicolon); - return null; + return error.ParseError; }, }) |node| { var var_decl = node.cast(Node.VarDecl).?; @@ -388,8 +394,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat try tree.errors.push(.{ .ExpectedVarDecl = .{ .token = it.index }, }); - // ignore this, try to find next decl by skipping the next block - findEndOfBlock(it); + // ignore this and try again; + return error.ParseError; } if (extern_export_inline_token) |token| { @@ -404,7 +410,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat error.ParseError => { // try to skip to next decl findToken(it, .Semicolon); - return null; + return error.ParseError; }, }; } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index e3bc20bd10..7ddf9cc9c8 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -62,6 +62,28 @@ test "recovery: missing return type" { }); } +test "recovery: continue after invalid decl" { + try testError( + \\fn foo { + \\ inline; + \\} + \\test "" { + \\ a && b; + \\} + , &[_]Error{ + .ExpectedToken, + .InvalidAnd, + }); + try testError( + \\threadlocal test "" { + \\ a && b; + \\} + , &[_]Error{ + .ExpectedVarDecl, + .InvalidAnd, + }); +} + test "zig fmt: top-level fields" { try testCanonical( \\a: did_you_know, |
