From 5c82ed2ea9360ea0931ba789a4ffb73d689b6a72 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 3 Apr 2018 14:53:27 +0200 Subject: [PATCH] std.zig.parser now parses initializers... Or, it would, if it worked --- std/zig/ast.zig | 4 +- std/zig/parser.zig | 149 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 125 insertions(+), 28 deletions(-) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 2ec305429c..c4b4ef983a 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -532,7 +532,7 @@ pub const NodePrefixOp = struct { pub const NodeFieldInitializer = struct { base: Node, - dot_token: Token, + period_token: Token, name_token: Token, expr: &Node, @@ -546,7 +546,7 @@ pub const NodeFieldInitializer = struct { } pub fn firstToken(self: &NodeFieldInitializer) Token { - return self.dot_token; + return self.period_token; } pub fn lastToken(self: &NodeFieldInitializer) Token { diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 43cc35fb6d..19ed4af4bf 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -75,13 +75,16 @@ pub const Parser = struct { const ExpectTokenSave = struct { id: Token.Id, ptr: &Token, + }; - const ExprListState = struct { - list: &ArrayList(&ast.Node), - end: Token.Id, - ptr: &Token, - }; + fn ListState(comptime T: type) type { + return struct { + list: &ArrayList(T), + end: Token.Id, + ptr: &Token, + }; + } const State = union(enum) { TopLevel, @@ -110,8 +113,10 @@ pub const Parser = struct { FnDef: &ast.NodeFnProto, Block: &ast.NodeBlock, Statement: &ast.NodeBlock, - ExprListItemOrEnd: ExprListState, - ExprListCommaOrEnd: ExprListState, + ExprListItemOrEnd: ListState(&ast.Node), + ExprListCommaOrEnd: ListState(&ast.Node), + FieldInitListItemOrEnd: ListState(&ast.NodeFieldInitializer), + FieldInitListCommaOrEnd: ListState(&ast.NodeFieldInitializer), }; /// Returns an AST tree, allocated with the parser's allocator. @@ -536,7 +541,7 @@ pub const Parser = struct { }); try stack.append(State.AfterOperand); try stack.append(State { - .ExprListItemOrEnd = ExprListState { + .ExprListItemOrEnd = ListState(&ast.Node) { .list = &node.params, .end = Token.Id.RParen, .ptr = &node.rparen_token, @@ -647,8 +652,6 @@ pub const Parser = struct { continue; } else if (token.id == Token.Id.LParen) { - self.putBackToken(token); - const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { .Call = ast.NodeSuffixOp.CallInfo { .params = ArrayList(&ast.Node).init(arena), @@ -658,18 +661,12 @@ pub const Parser = struct { try stack.append(State { .SuffixOp = node }); try stack.append(State.AfterOperand); try stack.append(State { - .ExprListItemOrEnd = ExprListState { + .ExprListItemOrEnd = ListState(&ast.Node) { .list = &node.op.Call.params, .end = Token.Id.RParen, .ptr = &node.rtoken, } }); - try stack.append(State { - .ExpectTokenSave = ExpectTokenSave { - .id = Token.Id.LParen, - .ptr = &node.rtoken, - }, - }); continue; } else if (token.id == Token.Id.LBracket) { @@ -686,6 +683,47 @@ pub const Parser = struct { try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }}); continue; + // TODO: This is the initializer parsing code. It doesn't work because of + // the ambiguity between function bodies and initializers: + // fn main() void {} or fn main() (void {}) + } else if (false) { //(token.id == Token.Id.LBrace) { + const next = self.getNextToken(); + + switch (next.id) { + Token.Id.Period => { + self.putBackToken(token); + + const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { + .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena), + }); + + try stack.append(State { + .FieldInitListItemOrEnd = ListState(&ast.NodeFieldInitializer) { + .list = &node.op.StructInitializer, + .end = Token.Id.RBrace, + .ptr = &node.rtoken, + } + }); + continue; + }, + else => { + self.putBackToken(token); + + const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { + .ArrayInitializer = ArrayList(&ast.Node).init(arena), + }); + + try stack.append(State { + .ExprListItemOrEnd = ListState(&ast.Node) { + .list = &node.op.ArrayInitializer, + .end = Token.Id.RBrace, + .ptr = &node.rtoken, + } + }); + continue; + }, + } + // TODO: Parse postfix operator } else { // no postfix/infix operator after this operand. @@ -717,30 +755,89 @@ pub const Parser = struct { } }, - State.ExprListItemOrEnd => |expr_list_state| { + State.ExprListItemOrEnd => |list_state| { + var token = self.getNextToken(); + + const IdTag = @TagType(Token.Id); + if (IdTag(list_state.end) == token.id) { + *list_state.ptr = token; + continue; + } + + self.putBackToken(token); + stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable; + try stack.append(State { .Expression = DestPtr{.List = list_state.list} }); + }, + + State.ExprListCommaOrEnd => |list_state| { var token = self.getNextToken(); switch (token.id) { - Token.Id.RParen => continue, + Token.Id.Comma => { + stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable; + }, else => { - self.putBackToken(token); - stack.append(State { .ExprListCommaOrEnd = expr_list_state }) catch unreachable; - try stack.append(State { .Expression = DestPtr{.List = expr_list_state.list} }); + const IdTag = @TagType(Token.Id); + if (IdTag(list_state.end) == token.id) { + *list_state.ptr = token; + continue; + } + + return self.parseError(token, "expected ',' or {}, found {}", @tagName(list_state.end), @tagName(token.id)); }, } }, - State.ExprListCommaOrEnd => |expr_list_state| { + State.FieldInitListItemOrEnd => |list_state| { + var token = self.getNextToken(); + + const IdTag = @TagType(Token.Id); + if (IdTag(list_state.end) == token.id){ + *list_state.ptr = token; + continue; + } + + self.putBackToken(token); + + const node = try arena.create(ast.NodeFieldInitializer); + *node = ast.NodeFieldInitializer { + .base = self.initNode(ast.Node.Id.FieldInitializer), + .period_token = undefined, + .name_token = undefined, + .expr = undefined, + }; + try list_state.list.append(node); + + stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable; + try stack.append(State { .Expression = DestPtr{.Field = &node.expr} }); + try stack.append(State { .ExpectToken = Token.Id.Equal }); + try stack.append(State { + .ExpectTokenSave = ExpectTokenSave { + .id = Token.Id.Identifier, + .ptr = &node.name_token, + } + }); + try stack.append(State { + .ExpectTokenSave = ExpectTokenSave { + .id = Token.Id.Period, + .ptr = &node.period_token, + } + }); + }, + + State.FieldInitListCommaOrEnd => |list_state| { var token = self.getNextToken(); switch (token.id) { Token.Id.Comma => { - stack.append(State { .ExprListItemOrEnd = expr_list_state }) catch unreachable; + stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable; }, else => { const IdTag = @TagType(Token.Id); - if (IdTag(expr_list_state.end) == token.id) + if (IdTag(list_state.end) == token.id) { + *list_state.ptr = token; continue; + } - return self.parseError(token, "expected ',' or {}, found {}", @tagName(expr_list_state.end), @tagName(token.id)); + return self.parseError(token, "expected ',' or {}, found {}", @tagName(list_state.end), @tagName(token.id)); }, } },