From 9df2a6a5027be17cba7f11ac9d7c106c3497647b Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 29 Mar 2018 13:43:17 +0200 Subject: [PATCH] std.zig.parser can now parse top level test declarations --- std/zig/ast.zig | 29 +++++++++++++++++++++++++ std/zig/parser.zig | 53 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 903dc051e2..180a0a9308 100644 --- a/std/zig/ast.zig +++ b/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(); + } +}; + diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 533ad754ac..06b7d35a48 100644 --- a/std/zig/parser.zig +++ b/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; + \\} + \\ + ); }