Commit be392777b7

Vexu <git@vexu.eu>
2020-05-13 16:21:27
continue parsing after missing commas and invalid statements
1 parent 91358f3
Changed files (3)
lib/std/zig/ast.zig
@@ -165,6 +165,7 @@ pub const Error = union(enum) {
     ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
     ExpectedSuffixOp: ExpectedSuffixOp,
     DeclBetweenFields: DeclBetweenFields,
+    MissingComma: MissingComma,
 
     pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
         switch (self.*) {
@@ -213,6 +214,7 @@ pub const Error = union(enum) {
             .ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
             .ExpectedSuffixOp => |*x| return x.render(tokens, stream),
             .DeclBetweenFields => |*x| return x.render(tokens, stream),
+            .MissingComma => |*x| return x.render(tokens, stream),
         }
     }
 
@@ -263,6 +265,7 @@ pub const Error = union(enum) {
             .ExpectedDerefOrUnwrap => |x| return x.token,
             .ExpectedSuffixOp => |x| return x.token,
             .DeclBetweenFields => |x| return x.token,
+            .MissingComma => |x| return x.token,
         }
     }
 
@@ -308,6 +311,7 @@ pub const Error = union(enum) {
     pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
     pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
     pub const DeclBetweenFields = SimpleError("Declarations are not allowed between container fields");
+    pub const MissingComma = SimpleError("Expected comma between items");
 
     pub const ExpectedCall = struct {
         node: *Node,
lib/std/zig/parse.zig
@@ -1083,7 +1083,14 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 
     var statements = Node.Block.StatementList.init(arena);
     while (true) {
-        const statement = (try parseStatement(arena, it, tree)) orelse break;
+        const statement = (parseStatement(arena, it, tree) catch |err| switch (err) {
+            error.OutOfMemory => return error.OutOfMemory,
+            error.ParseError => {
+                // try to skip to the next statement
+                findToken(it, .Semicolon);
+                continue;
+            },
+        }) orelse break;
         try statements.push(statement);
     }
 
@@ -2816,7 +2823,24 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
             var list = L.init(arena);
             while (try nodeParseFn(arena, it, tree)) |node| {
                 try list.push(node);
-                if (eatToken(it, .Comma) == null) break;
+
+                const token = nextToken(it);
+                switch (token.ptr.id) {
+                    .Comma => {},
+                    // all possible delimiters
+                    .Colon, .RParen, .RBrace, .RBracket => {
+                        putBackToken(it, token.index);
+                        break;
+                    },
+                    else => {
+                        // this is likely just a missing comma,
+                        // continue parsing this list and give an error
+                        try tree.errors.push(.{
+                            .MissingComma = .{ .token = token.index },
+                        });
+                        putBackToken(it, token.index);
+                    },
+                }
             }
             return list;
         }
lib/std/zig/parser_test.zig
@@ -6,6 +6,30 @@ test "zig fmt: fault tolerant parsing" {
         .ExpectedInlinable,
         .ExpectedInlinable,
     });
+    try testError(
+        \\test "" {
+        \\    foo + +;
+        \\    inline;
+        \\}
+    , &[_]Error{
+        .InvalidToken,
+        .ExpectedInlinable,
+    });
+    try testError(
+        \\test "" {
+        \\    switch (foo) {
+        \\        2 => {}
+        \\        3 => {}
+        \\        else => {
+        \\            inline;
+        \\        }
+        \\    }
+        \\}
+    , &[_]Error{
+        .MissingComma,
+        .MissingComma,
+        .ExpectedInlinable,
+    });
 }
 
 test "zig fmt: top-level fields" {