Commit cefc04348e

Vexu <git@vexu.eu>
2020-05-13 16:36:06
continue parsing on invalid and token
1 parent be39277
Changed files (3)
lib/std/zig/ast.zig
@@ -166,6 +166,7 @@ pub const Error = union(enum) {
     ExpectedSuffixOp: ExpectedSuffixOp,
     DeclBetweenFields: DeclBetweenFields,
     MissingComma: MissingComma,
+    InvalidAnd: InvalidAnd,
 
     pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
         switch (self.*) {
@@ -215,6 +216,7 @@ pub const Error = union(enum) {
             .ExpectedSuffixOp => |*x| return x.render(tokens, stream),
             .DeclBetweenFields => |*x| return x.render(tokens, stream),
             .MissingComma => |*x| return x.render(tokens, stream),
+            .InvalidAnd => |*x| return x.render(tokens, stream),
         }
     }
 
@@ -266,6 +268,7 @@ pub const Error = union(enum) {
             .ExpectedSuffixOp => |x| return x.token,
             .DeclBetweenFields => |x| return x.token,
             .MissingComma => |x| return x.token,
+            .InvalidAnd => |x| return x.token,
         }
     }
 
@@ -312,6 +315,7 @@ pub const Error = union(enum) {
     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 InvalidAnd = SimpleError("`&&` is invalid. Note that `and` is boolean AND.");
 
     pub const ExpectedCall = struct {
         node: *Node,
@@ -339,9 +343,6 @@ pub const Error = union(enum) {
         pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
             const found_token = tokens.at(self.token);
             switch (found_token.id) {
-                .Invalid_ampersands => {
-                    return stream.print("`&&` is invalid. Note that `and` is boolean AND.", .{});
-                },
                 .Invalid => {
                     return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
                 },
lib/std/zig/parse.zig
@@ -2824,21 +2824,16 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
             while (try nodeParseFn(arena, it, tree)) |node| {
                 try list.push(node);
 
-                const token = nextToken(it);
-                switch (token.ptr.id) {
-                    .Comma => {},
+                switch (it.peek().?.id) {
+                    .Comma => _ = nextToken(it),
                     // all possible delimiters
-                    .Colon, .RParen, .RBrace, .RBracket => {
-                        putBackToken(it, token.index);
-                        break;
-                    },
+                    .Colon, .RParen, .RBrace, .RBracket => 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 },
+                            .MissingComma = .{ .token = it.index },
                         });
-                        putBackToken(it, token.index);
                     },
                 }
             }
@@ -2850,7 +2845,17 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
     return struct {
         pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
-            const op_token = eatToken(it, token) orelse return null;
+            const op_token = if (token == .Keyword_and) switch (it.peek().?.id) {
+                .Keyword_and => nextToken(it).index,
+                .Invalid_ampersands => blk: {
+                    try tree.errors.push(.{
+                        .InvalidAnd = .{ .token = it.index },
+                    });
+                    break :blk nextToken(it).index;
+                },
+                else => return null,
+            } else eatToken(it, token) orelse return null;
+
             const node = try arena.create(Node.InfixOp);
             node.* = .{
                 .op_token = op_token,
lib/std/zig/parser_test.zig
@@ -21,14 +21,15 @@ test "zig fmt: fault tolerant parsing" {
         \\        2 => {}
         \\        3 => {}
         \\        else => {
-        \\            inline;
+        \\            foo && bar +;
         \\        }
         \\    }
         \\}
     , &[_]Error{
         .MissingComma,
         .MissingComma,
-        .ExpectedInlinable,
+        .InvalidAnd,
+        .InvalidToken,
     });
 }