Commit 440189a04a

Vexu <git@vexu.eu>
2020-05-15 10:06:34
cleanup* remove unecessary error* properly handle ReturnTypeInvalid in ast.zig functions* assert that the tree is clean in render.zig* simplify parser recovery with top level decls
1 parent c77fee0
Changed files (4)
lib/std/zig/ast.zig
@@ -166,7 +166,6 @@ pub const Error = union(enum) {
     ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
     ExpectedSuffixOp: ExpectedSuffixOp,
     DeclBetweenFields: DeclBetweenFields,
-    MissingComma: MissingComma,
     InvalidAnd: InvalidAnd,
 
     pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
@@ -217,7 +216,6 @@ 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),
             .InvalidAnd => |*x| return x.render(tokens, stream),
         }
     }
@@ -270,7 +268,6 @@ 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,
             .InvalidAnd => |x| return x.token,
         }
     }
@@ -318,7 +315,6 @@ 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 InvalidAnd = SimpleError("`&&` is invalid. Note that `and` is boolean AND.");
 
     pub const ExpectedCall = struct {
@@ -926,7 +922,7 @@ pub const Node = struct {
                     if (i < 1) return node;
                     i -= 1;
                 },
-                .Invalid => unreachable,
+                .Invalid => {},
             }
 
             if (self.body_node) |body_node| {
@@ -948,7 +944,7 @@ pub const Node = struct {
             if (self.body_node) |body_node| return body_node.lastToken();
             switch (self.return_type) {
                 .Explicit, .InferErrorSet => |node| return node.lastToken(),
-                .Invalid => unreachable,
+                .Invalid => |tok| return tok,
             }
         }
     };
lib/std/zig/parse.zig
@@ -78,7 +78,7 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error
 ///      / KEYWORD_pub? ContainerField COMMA ContainerMembers
 ///      / KEYWORD_pub? ContainerField
 ///      /
-fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!Node.Root.DeclList {
+fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList {
     var list = Node.Root.DeclList.init(arena);
 
     var field_state: union(enum) {
@@ -136,7 +136,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All
         if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {
             error.OutOfMemory => return error.OutOfMemory,
             error.ParseError => {
-                // try again
+                findNextContainerMember(it);
                 continue;
             },
         }) |node| {
@@ -324,7 +324,7 @@ fn findNextStmt(it: *TokenIterator) void {
 }
 
 /// Eat a multiline container doc comment
-fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!?*Node {
+fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     var lines = Node.DocComment.LineList.init(arena);
     while (eatToken(it, .ContainerDocComment)) |line| {
         try lines.push(line);
@@ -384,7 +384,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) Error!?*Node {
+fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     var lib_name: ?*Node = null;
     const extern_export_inline_token = blk: {
         if (eatToken(it, .Keyword_export)) |token| break :blk token;
@@ -397,13 +397,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?
         break :blk null;
     };
 
-    if (parseFnProto(arena, it, tree) catch |err| switch (err) {
-        error.OutOfMemory => return error.OutOfMemory,
-        error.ParseError => {
-            findNextContainerMember(it);
-            return error.ParseError;
-        },
-    }) |node| {
+    if (try parseFnProto(arena, it, tree)) |node| {
         const fn_node = node.cast(Node.FnProto).?;
         fn_node.*.extern_export_inline_token = extern_export_inline_token;
         fn_node.*.lib_name = lib_name;
@@ -413,7 +407,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?
             // since parseBlock only return error.ParseError on
             // a missing '}' we can assume this function was
             // supposed to end here.
-            error.ParseError => null,
+            error.ParseError => return node,
         }) |body_node| {
             fn_node.body_node = body_node;
             return node;
@@ -437,14 +431,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?
 
     const thread_local_token = eatToken(it, .Keyword_threadlocal);
 
-    if (parseVarDecl(arena, it, tree) catch |err| switch (err) {
-        error.OutOfMemory => return error.OutOfMemory,
-        error.ParseError => {
-            // try to skip to next decl
-            findNextContainerMember(it);
-            return error.ParseError;
-        },
-    }) |node| {
+    if (try parseVarDecl(arena, it, tree)) |node| {
         var var_decl = node.cast(Node.VarDecl).?;
         var_decl.*.thread_local_token = thread_local_token;
         var_decl.*.comptime_token = null;
@@ -469,14 +456,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?
         return error.ParseError;
     }
 
-    return parseUse(arena, it, tree) catch |err| switch (err) {
-        error.OutOfMemory => return error.OutOfMemory,
-        error.ParseError => {
-            // try to skip to next decl
-            findNextContainerMember(it);
-            return error.ParseError;
-        },
-    };
+    return try parseUse(arena, it, tree);
 }
 
 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
@@ -2926,7 +2906,7 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
                         // this is likely just a missing comma,
                         // continue parsing this list and give an error
                         try tree.errors.push(.{
-                            .MissingComma = .{ .token = it.index },
+                            .ExpectedToken = .{ .token = it.index, .expected_id = .Comma },
                         });
                     },
                 }
lib/std/zig/parser_test.zig
@@ -32,8 +32,8 @@ test "recovery: missing comma" {
         \\    }
         \\}
     , &[_]Error{
-        .MissingComma,
-        .MissingComma,
+        .ExpectedToken,
+        .ExpectedToken,
         .InvalidAnd,
         .InvalidToken,
     });
@@ -2983,7 +2983,6 @@ test "zig fmt: extern without container keyword returns error" {
     , &[_]Error{
         .ExpectedExpr,
         .ExpectedVarDeclOrFn,
-        .ExpectedContainerMembers,
     });
 }
 
lib/std/zig/render.zig
@@ -13,6 +13,9 @@ pub const Error = error{
 
 /// Returns whether anything changed
 pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
+    // cannot render an invalid tree
+    std.debug.assert(tree.errors.len == 0);
+
     // make a passthrough stream that checks whether something changed
     const MyStream = struct {
         const MyStream = @This();