Commit 9df2a6a502

Jimmi Holst Christensen <jimmiholstchristensen@gmail.com>
2018-03-29 13:43:17
std.zig.parser can now parse top level test declarations
1 parent 032fccf
Changed files (2)
std/zig/ast.zig
@@ -22,6 +22,7 @@ pub const Node = struct {
         StringLiteral,
         BuiltinCall,
         LineComment,
+        TestDecl,
     };
 
     pub fn iterate(base: &Node, index: usize) ?&Node {
@@ -39,6 +40,7 @@ pub const Node = struct {
             Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
             Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
+            Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
         };
     }
 
@@ -57,6 +59,7 @@ pub const Node = struct {
             Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
             Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
+            Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
         };
     }
 
@@ -75,6 +78,7 @@ pub const Node = struct {
             Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
             Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
+            Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
         };
     }
 };
@@ -476,3 +480,28 @@ pub const NodeLineComment = struct {
         return self.lines.at(self.lines.len - 1);
     }
 };
+
+pub const NodeTestDecl = struct {
+    base: Node,
+    test_token: Token,
+    name_token: Token,
+    body_node: &Node,
+
+    pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return self.body_node;
+        i -= 1;
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeTestDecl) Token {
+        return self.test_token;
+    }
+
+    pub fn lastToken(self: &NodeTestDecl) Token {
+        return self.body_node.lastToken();
+    }
+};
+
std/zig/parser.zig
@@ -171,6 +171,22 @@ pub const Parser = struct {
                             stack.append(State { .TopLevelExtern = token }) catch unreachable;
                             continue;
                         },
+                        Token.Id.Keyword_test => {
+                            stack.append(State.TopLevel) catch unreachable;
+
+                            const name_token = self.getNextToken();
+                            if (name_token.id != Token.Id.StringLiteral)
+                                return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.StringLiteral), @tagName(name_token.id));
+
+                            const lbrace = self.getNextToken();
+                            if (lbrace.id != Token.Id.LBrace)
+                                return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.LBrace), @tagName(name_token.id));
+
+                            const block = try self.createBlock(arena, token);
+                            const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, name_token, block);
+                            try stack.append(State { .Block = block });
+                            continue;
+                        },
                         Token.Id.Eof => {
                             root_node.eof_token = token;
                             return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
@@ -733,6 +749,20 @@ pub const Parser = struct {
         return node;
     }
 
+    fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name_token: &const Token,
+        block: &ast.NodeBlock) !&ast.NodeTestDecl
+    {
+        const node = try arena.create(ast.NodeTestDecl);
+
+        *node = ast.NodeTestDecl {
+            .base = self.initNode(ast.Node.Id.TestDecl),
+            .test_token = *test_token,
+            .name_token = *name_token,
+            .body_node = &block.base,
+        };
+        return node;
+    }
+
     fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
         cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
     {
@@ -867,6 +897,14 @@ pub const Parser = struct {
         return node;
     }
 
+    fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
+        test_token: &const Token, name_token: &const Token, block: &ast.NodeBlock) !&ast.NodeTestDecl
+    {
+        const node = try self.createTestDecl(arena, test_token, name_token, block);
+        try list.append(&node.base);
+        return node;
+    }
+
     fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
         const loc = self.tokenizer.getTokenLocation(token);
         warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args);
@@ -1032,7 +1070,11 @@ pub const Parser = struct {
                         ast.Node.Id.VarDecl => {
                             const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
                             try stack.append(RenderState { .VarDecl = var_decl});
-
+                        },
+                        ast.Node.Id.TestDecl => {
+                            const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
+                            try stream.print("test {} ", self.tokenizer.getTokenSlice(test_decl.name_token));
+                            try stack.append(RenderState { .Expression = test_decl.body_node });
                         },
                         else => unreachable,
                     }
@@ -1201,6 +1243,7 @@ pub const Parser = struct {
 
                     ast.Node.Id.Root,
                     ast.Node.Id.VarDecl,
+                    ast.Node.Id.TestDecl,
                     ast.Node.Id.ParamDecl => unreachable,
                 },
                 RenderState.FnProtoRParen => |fn_proto| {
@@ -1422,4 +1465,12 @@ test "zig fmt" {
         \\}
         \\
     );
+
+    try testCanonical(
+        \\test "test name" {
+        \\    const a = 1;
+        \\    var b = 1;
+        \\}
+        \\
+    );
 }