authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-13 23:28:04+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-13 23:28:04+03:00
logad71d959d7d1b5f3a771dc2c1eaf37dbd7cd0852
tree6d039ebd3f9df24e0b2f9d7acc2b6bdd50e7859e
parent2296906e2ad54c387b4b19784148c47a26969cdc
signature Commit is signed but in an unrecognized format.

correctly recover from invalid top level declarations


2 files changed, 35 insertions(+), 7 deletions(-)

lib/std/zig/parse.zig+13-7
......@@ -130,7 +130,13 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All
130130
131131 const visib_token = eatToken(it, .Keyword_pub);
132132
133 if (try parseTopLevelDecl(arena, it, tree)) |node| {
133 if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {
134 error.OutOfMemory => return error.OutOfMemory,
135 error.ParseError => {
136 // try again
137 continue;
138 },
139 }) |node| {
134140 if (field_state == .seen) {
135141 field_state = .{ .end = visib_token orelse node.firstToken() };
136142 }
......@@ -315,7 +321,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*
315321/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
316322/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
317323/// / KEYWORD_usingnamespace Expr SEMICOLON
318fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!?*Node {
324fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
319325 var lib_name: ?*Node = null;
320326 const extern_export_inline_token = blk: {
321327 if (eatToken(it, .Keyword_export)) |token| break :blk token;
......@@ -334,7 +340,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat
334340 // this fn will likely have a body so we
335341 // use findEndOfBlock instead of findToken.
336342 findEndOfBlock(it);
337 return null;
343 return error.ParseError;
338344 },
339345 }) |node| {
340346 const fn_node = node.cast(Node.FnProto).?;
......@@ -373,7 +379,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat
373379 error.ParseError => {
374380 // try to skip to next decl
375381 findToken(it, .Semicolon);
376 return null;
382 return error.ParseError;
377383 },
378384 }) |node| {
379385 var var_decl = node.cast(Node.VarDecl).?;
......@@ -388,8 +394,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat
388394 try tree.errors.push(.{
389395 .ExpectedVarDecl = .{ .token = it.index },
390396 });
391 // ignore this, try to find next decl by skipping the next block
392 findEndOfBlock(it);
397 // ignore this and try again;
398 return error.ParseError;
393399 }
394400
395401 if (extern_export_inline_token) |token| {
......@@ -404,7 +410,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocat
404410 error.ParseError => {
405411 // try to skip to next decl
406412 findToken(it, .Semicolon);
407 return null;
413 return error.ParseError;
408414 },
409415 };
410416}
lib/std/zig/parser_test.zig+22
......@@ -62,6 +62,28 @@ test "recovery: missing return type" {
6262 });
6363}
6464
65test "recovery: continue after invalid decl" {
66 try testError(
67 \\fn foo {
68 \\ inline;
69 \\}
70 \\test "" {
71 \\ a && b;
72 \\}
73 , &[_]Error{
74 .ExpectedToken,
75 .InvalidAnd,
76 });
77 try testError(
78 \\threadlocal test "" {
79 \\ a && b;
80 \\}
81 , &[_]Error{
82 .ExpectedVarDecl,
83 .InvalidAnd,
84 });
85}
86
6587test "zig fmt: top-level fields" {
6688 try testCanonical(
6789 \\a: did_you_know,