Commit 4b0556ebd4

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-11 13:38:06
std.zig.parser can now parse `std/heap.zig`: related: #909 * Struct fields can now be pub * Parsing of double deref now works * Block expressions now have the right precedence
1 parent 6fb5ab1
Changed files (2)
std/zig/ast.zig
@@ -360,6 +360,7 @@ pub const NodeContainerDecl = struct {
 
 pub const NodeStructField = struct {
     base: Node,
+    visib_token: ?Token,
     name_token: Token,
     type_expr: &Node,
 
@@ -373,6 +374,7 @@ pub const NodeStructField = struct {
     }
 
     pub fn firstToken(self: &NodeStructField) Token {
+        if (self.visib_token) |visib_token| return visib_token;
         return self.name_token;
     }
 
std/zig/parser.zig
@@ -669,6 +669,7 @@ pub const Parser = struct {
                                     const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
                                         ast.NodeStructField {
                                             .base = undefined,
+                                            .visib_token = null,
                                             .name_token = token,
                                             .type_expr = undefined,
                                         }
@@ -721,7 +722,42 @@ pub const Parser = struct {
                                 },
                             }
                         },
-                        Token.Id.Keyword_pub, Token.Id.Keyword_export => {
+                        Token.Id.Keyword_pub => {
+                            if (self.eatToken(Token.Id.Identifier)) |identifier| {
+                                switch (container_decl.kind) {
+                                    ast.NodeContainerDecl.Kind.Struct => {
+                                        const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
+                                            ast.NodeStructField {
+                                                .base = undefined,
+                                                .visib_token = token,
+                                                .name_token = identifier,
+                                                .type_expr = undefined,
+                                            }
+                                        );
+
+                                        stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
+                                        try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
+                                        try stack.append(State { .ExpectToken = Token.Id.Colon });
+                                        continue;
+                                    },
+                                    else => {
+                                        self.putBackToken(identifier);
+                                    }
+                                }
+                            }
+
+                            stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
+                            try stack.append(State {
+                                .TopLevelExtern = TopLevelDeclCtx {
+                                    .decls = &container_decl.fields_and_decls,
+                                    .visib_token = token,
+                                    .extern_token = null,
+                                    .lib_name = null,
+                                }
+                            });
+                            continue;
+                        },
+                        Token.Id.Keyword_export => {
                             stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
                             try stack.append(State {
                                 .TopLevelExtern = TopLevelDeclCtx {
@@ -864,111 +900,11 @@ pub const Parser = struct {
                             stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
                             continue;
                         },
-                        Token.Id.Keyword_suspend => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend,
-                                ast.NodeSuspend {
-                                    .base = undefined,
-                                    .suspend_token = token,
-                                    .payload = null,
-                                    .body = null,
-                                }
-                            );
-
-                            stack.append(State { .SuspendBody = node }) catch unreachable;
-                            try stack.append(State { .Payload = &node.payload });
-                            continue;
-                        },
-                        Token.Id.Keyword_if => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf,
-                                ast.NodeIf {
-                                    .base = undefined,
-                                    .if_token = token,
-                                    .condition = undefined,
-                                    .payload = null,
-                                    .body = undefined,
-                                    .@"else" = null,
-                                }
-                            );
-
-                            stack.append(State { .Else = &node.@"else" }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
-                            try stack.append(State { .PointerPayload = &node.payload });
-                            try stack.append(State { .ExpectToken = Token.Id.RParen });
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
-                            try stack.append(State { .ExpectToken = Token.Id.LParen });
-                            continue;
-                        },
-                        Token.Id.Keyword_while => {
-                            stack.append(State {
-                                .While = LoopCtx {
-                                    .label = null,
-                                    .inline_token = null,
-                                    .loop_token = token,
-                                    .dest_ptr = dest_ptr,
-                                }
-                            }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_for => {
-                            stack.append(State {
-                                .For = LoopCtx {
-                                    .label = null,
-                                    .inline_token = null,
-                                    .loop_token = token,
-                                    .dest_ptr = dest_ptr,
-                                }
-                            }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_switch => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch,
-                                ast.NodeSwitch {
-                                    .base = undefined,
-                                    .switch_token = token,
-                                    .expr = undefined,
-                                    .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
-                                    .rbrace = undefined,
-                                }
-                            );
-
-                            stack.append(State {
-                                .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
-                                    .list = &node.cases,
-                                    .ptr = &node.rbrace,
-                                },
-                            }) catch unreachable;
-                            try stack.append(State { .ExpectToken = Token.Id.LBrace });
-                            try stack.append(State { .ExpectToken = Token.Id.RParen });
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
-                            try stack.append(State { .ExpectToken = Token.Id.LParen });
-                        },
-                        Token.Id.Keyword_comptime => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime,
-                                ast.NodeComptime {
-                                    .base = undefined,
-                                    .comptime_token = token,
-                                    .expr = undefined,
-                                }
-                            );
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
-                            continue;
-                        },
-                        Token.Id.LBrace => {
-                            const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock,
-                                ast.NodeBlock {
-                                    .base = undefined,
-                                    .label = null,
-                                    .lbrace = token,
-                                    .statements = ArrayList(&ast.Node).init(arena),
-                                    .rbrace = undefined,
-                                }
-                            );
-                            stack.append(State { .Block = block }) catch unreachable;
-                            continue;
-                        },
                         else => {
-                            self.putBackToken(token);
-                            stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
+                            if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
+                                self.putBackToken(token);
+                                stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
+                            }
                             continue;
                         }
                     }
@@ -1407,7 +1343,7 @@ pub const Parser = struct {
                 State.PrefixOpExpression => |dest_ptr| {
                     const token = self.getNextToken();
                     if (tokenIdToPrefixOp(token.id)) |prefix_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
+                        var node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
                             ast.NodePrefixOp {
                                 .base = undefined,
                                 .op_token = token,
@@ -1415,6 +1351,20 @@ pub const Parser = struct {
                                 .rhs = undefined,
                             }
                         );
+
+                        if (token.id == Token.Id.AsteriskAsterisk) {
+                            const child = try self.createNode(arena, ast.NodePrefixOp,
+                                ast.NodePrefixOp {
+                                    .base = undefined,
+                                    .op_token = token,
+                                    .op = prefix_id,
+                                    .rhs = undefined,
+                                }
+                            );
+                            node.rhs = &child.base;
+                            node = child;
+                        }
+
                         stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
                         if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
                             try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
@@ -1871,7 +1821,9 @@ pub const Parser = struct {
                             continue;
                         },
                         else => {
-                            try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
+                            if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
+                                try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
+                            }
                             continue;
                         }
                     }
@@ -2790,6 +2742,117 @@ pub const Parser = struct {
         }
     }
 
+    fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool {
+        switch (token.id) {
+            Token.Id.Keyword_suspend => {
+                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend,
+                    ast.NodeSuspend {
+                        .base = undefined,
+                        .suspend_token = *token,
+                        .payload = null,
+                        .body = null,
+                    }
+                );
+
+                stack.append(State { .SuspendBody = node }) catch unreachable;
+                try stack.append(State { .Payload = &node.payload });
+                return true;
+            },
+            Token.Id.Keyword_if => {
+                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf,
+                    ast.NodeIf {
+                        .base = undefined,
+                        .if_token = *token,
+                        .condition = undefined,
+                        .payload = null,
+                        .body = undefined,
+                        .@"else" = null,
+                    }
+                );
+
+                stack.append(State { .Else = &node.@"else" }) catch unreachable;
+                try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
+                try stack.append(State { .PointerPayload = &node.payload });
+                try stack.append(State { .ExpectToken = Token.Id.RParen });
+                try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
+                try stack.append(State { .ExpectToken = Token.Id.LParen });
+                return true;
+            },
+            Token.Id.Keyword_while => {
+                stack.append(State {
+                    .While = LoopCtx {
+                        .label = null,
+                        .inline_token = null,
+                        .loop_token = *token,
+                        .dest_ptr = *dest_ptr,
+                    }
+                }) catch unreachable;
+                return true;
+            },
+            Token.Id.Keyword_for => {
+                stack.append(State {
+                    .For = LoopCtx {
+                        .label = null,
+                        .inline_token = null,
+                        .loop_token = *token,
+                        .dest_ptr = *dest_ptr,
+                    }
+                }) catch unreachable;
+                return true;
+            },
+            Token.Id.Keyword_switch => {
+                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch,
+                    ast.NodeSwitch {
+                        .base = undefined,
+                        .switch_token = *token,
+                        .expr = undefined,
+                        .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
+                        .rbrace = undefined,
+                    }
+                );
+
+                stack.append(State {
+                    .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
+                        .list = &node.cases,
+                        .ptr = &node.rbrace,
+                    },
+                }) catch unreachable;
+                try stack.append(State { .ExpectToken = Token.Id.LBrace });
+                try stack.append(State { .ExpectToken = Token.Id.RParen });
+                try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                try stack.append(State { .ExpectToken = Token.Id.LParen });
+                return true;
+            },
+            Token.Id.Keyword_comptime => {
+                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime,
+                    ast.NodeComptime {
+                        .base = undefined,
+                        .comptime_token = *token,
+                        .expr = undefined,
+                    }
+                );
+                try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                return true;
+            },
+            Token.Id.LBrace => {
+                const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock,
+                    ast.NodeBlock {
+                        .base = undefined,
+                        .label = null,
+                        .lbrace = *token,
+                        .statements = ArrayList(&ast.Node).init(arena),
+                        .rbrace = undefined,
+                    }
+                );
+                stack.append(State { .Block = block }) catch unreachable;
+                return true;
+            },
+            else => {
+                return false;
+            }
+        }
+    }
+
     fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
         var token = self.getNextToken();
         switch (token.id) {
@@ -2881,7 +2944,7 @@ pub const Parser = struct {
             Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
             Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
             Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
-            Token.Id.Asterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
+            Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
             Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
                 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
                     .align_expr = null,
@@ -3126,6 +3189,9 @@ pub const Parser = struct {
                         },
                         ast.Node.Id.StructField => {
                             const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
+                            if (field.visib_token) |visib_token| {
+                                try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
+                            }
                             try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
                             try stack.append(RenderState { .Expression = field.type_expr});
                         },
@@ -4573,6 +4639,7 @@ test "zig fmt: struct declaration" {
         \\const S = struct {
         \\    const Self = this;
         \\    f1: u8,
+        \\    pub f3: u8,
         \\
         \\    fn method(self: &Self) Self {
         \\        return *self;
@@ -4583,14 +4650,14 @@ test "zig fmt: struct declaration" {
         \\
         \\const Ps = packed struct {
         \\    a: u8,
-        \\    b: u8,
+        \\    pub b: u8,
         \\
         \\    c: u8
         \\};
         \\
         \\const Es = extern struct {
         \\    a: u8,
-        \\    b: u8,
+        \\    pub b: u8,
         \\
         \\    c: u8
         \\};
@@ -4895,6 +4962,7 @@ test "zig fmt: if" {
         \\    }
         \\
         \\    const is_world_broken = if (10 < 0) true else false;
+        \\    const some_number = 1 + if (10 < 0) 2 else 3;
         \\
         \\    const a: ?u8 = 10;
         \\    const b: ?u8 = null;