From b9093185f748293064e7eeaaa07e7479099420ed Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Sun, 1 Apr 2018 22:02:51 +0200 Subject: [PATCH] std.zig.parser now parses slicing and array access --- std/zig/ast.zig | 66 +++++++++++++++++++++++++++++++ std/zig/parser.zig | 92 +++++++++++++++++++++++++++++++++++++++++++ std/zig/tokenizer.zig | 12 ++++++ 3 files changed, 170 insertions(+) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 8a9a072d67dfdd44ac8d8fdd8b712482329caf05..680e61796231d9336867bf7c4e76cf6dbe80be84 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -30,6 +30,8 @@ pub const Node = struct { ErrorType, BuiltinCall, Call, + ArrayAccess, + SliceExpression, LineComment, TestDecl, }; @@ -57,6 +59,8 @@ pub const Node = struct { Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index), Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index), Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index), + Id.ArrayAccess => @fieldParentPtr(NodeArrayAccess, "base", base).iterate(index), + Id.SliceExpression => @fieldParentPtr(NodeSliceExpression, "base", base).iterate(index), Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index), Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index), }; @@ -85,6 +89,8 @@ pub const Node = struct { Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(), Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(), Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(), + Id.ArrayAccess => @fieldParentPtr(NodeArrayAccess, "base", base).firstToken(), + Id.SliceExpression => @fieldParentPtr(NodeSliceExpression, "base", base).firstToken(), Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(), Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(), }; @@ -113,6 +119,8 @@ pub const Node = struct { Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(), Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(), Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(), + Id.ArrayAccess => @fieldParentPtr(NodeArrayAccess, "base", base).lastToken(), + Id.SliceExpression => @fieldParentPtr(NodeSliceExpression, "base", base).lastToken(), Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(), Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(), }; @@ -598,6 +606,64 @@ pub const NodeCall = struct { } }; +pub const NodeArrayAccess = struct { + base: Node, + expr: &Node, + index: &Node, + rbracket_token: Token, + + pub fn iterate(self: &NodeArrayAccess, index: usize) ?&Node { + var i = index; + + if (i < 1) return self.expr; + i -= 1; + + if (i < 1) return self.index; + i -= 1; + + return null; + } + + pub fn firstToken(self: &NodeArrayAccess) Token { + return self.expr.firstToken(); + } + + pub fn lastToken(self: &NodeArrayAccess) Token { + return self.rbracket_token; + } +}; + +pub const NodeSliceExpression = struct { + base: Node, + expr: &Node, + start: &Node, + end: ?&Node, + rbracket_token: Token, + + pub fn iterate(self: &NodeSliceExpression, index: usize) ?&Node { + var i = index; + + if (i < 1) return self.callee; + i -= 1; + + if (i < 1) return self.start; + i -= 1; + + if (i < 1) return self.end; + i -= 1; + + return null; + } + + pub fn firstToken(self: &NodeSliceExpression) Token { + return self.expr.firstToken(); + } + + pub fn lastToken(self: &NodeSliceExpression) Token { + return self.rbracket_token; + } +}; + pub const NodeStringLiteral = struct { base: Node, token: Token, diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 0b8a15d3ddc130e86f31f00ab97aa767e7b1723e..d0ab7e17d877d3c950487ecd66915113d13a4a23 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -88,6 +88,7 @@ pub const Parser = struct { InfixOp: &ast.NodeInfixOp, PrefixOp: &ast.NodePrefixOp, SuffixOp: &ast.Node, + SliceOrArrayAccess, AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo, TypeExpr: DestPtr, VarDecl: &ast.NodeVarDecl, @@ -590,6 +591,11 @@ pub const Parser = struct { }); continue; + } else if (token.id == Token.Id.LBracket) { + try stack.append(State.SliceOrArrayAccess); + try stack.append(State.ExpectOperand); + continue; + // TODO: Parse postfix operator } else { // no postfix/infix operator after this operand. @@ -603,6 +609,53 @@ pub const Parser = struct { try dest_ptr.store(expression); break; }, + State.SliceOrArrayAccess => { + var rbracket_or_ellipsis2_token = self.getNextToken(); + + switch (rbracket_or_ellipsis2_token.id) { + Token.Id.Ellipsis2 => { + const node = try arena.create(ast.NodeSliceExpression); + *node = ast.NodeSliceExpression { + .base = self.initNode(ast.Node.Id.SliceExpression), + .expr = undefined, + .start = expression, + .end = null, + .rbracket_token = undefined, + }; + + try stack.append(State { .SuffixOp = &node.base }); + try stack.append(State.AfterOperand); + + const rbracket_token = self.getNextToken(); + if (rbracket_token.id != Token.Id.RBracket) { + self.putBackToken(rbracket_token); + try stack.append(State { + .ExpectTokenSave = ExpectTokenSave { + .id = Token.Id.RBracket, + .ptr = &node.rbracket_token, + } + }); + try stack.append(State { .Expression = DestPtr { .NullableField = &node.end } }); + } else { + node.rbracket_token = rbracket_token; + } + break; + }, + Token.Id.RBracket => { + const node = try arena.create(ast.NodeArrayAccess); + *node = ast.NodeArrayAccess { + .base = self.initNode(ast.Node.Id.ArrayAccess), + .expr = undefined, + .index = expression, + .rbracket_token = token, + }; + try stack.append(State { .SuffixOp = &node.base }); + try stack.append(State.AfterOperand); + break; + }, + else => return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id)) + } + }, State.InfixOp => |infix_op| { infix_op.rhs = expression; infix_op.lhs = popSuffixOp(&stack); @@ -857,6 +910,7 @@ pub const Parser = struct { State.PrefixOp => unreachable, State.SuffixOp => unreachable, State.Operand => unreachable, + State.SliceOrArrayAccess => unreachable, } } } @@ -874,6 +928,18 @@ pub const Parser = struct { left_leaf_ptr = &call.callee; continue; }, + ast.Node.Id.ArrayAccess => { + const arr_access = @fieldParentPtr(ast.NodeArrayAccess, "base", suffix_op); + *left_leaf_ptr = &arr_access.base; + left_leaf_ptr = &arr_access.expr; + continue; + }, + ast.Node.Id.SliceExpression => { + const slice_expr = @fieldParentPtr(ast.NodeSliceExpression, "base", suffix_op); + *left_leaf_ptr = &slice_expr.base; + left_leaf_ptr = &slice_expr.expr; + continue; + }, else => unreachable, } }, @@ -1594,6 +1660,24 @@ pub const Parser = struct { try stack.append(RenderState { .Text = "("}); try stack.append(RenderState { .Expression = call.callee }); }, + ast.Node.Id.ArrayAccess => { + const arr_access = @fieldParentPtr(ast.NodeArrayAccess, "base", base); + try stack.append(RenderState { .Text = "]"}); + try stack.append(RenderState { .Expression = arr_access.index}); + try stack.append(RenderState { .Text = "["}); + try stack.append(RenderState { .Expression = arr_access.expr }); + }, + ast.Node.Id.SliceExpression => { + const slice_expr = @fieldParentPtr(ast.NodeSliceExpression, "base", base); + try stack.append(RenderState { .Text = "]"}); + if (slice_expr.end) |end| { + try stack.append(RenderState { .Expression = end}); + } + try stack.append(RenderState { .Text = ".."}); + try stack.append(RenderState { .Expression = slice_expr.start}); + try stack.append(RenderState { .Text = "["}); + try stack.append(RenderState { .Expression = slice_expr.expr}); + }, ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"), ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"), @@ -1978,6 +2062,14 @@ test "zig fmt: indexing" { \\ a[0 + 5]; \\ a[0..]; \\ a[0..5]; + \\ a[a[0]]; + \\ a[a[0..]]; + \\ a[a[0..5]]; + \\ a[a[0]..]; + \\ a[a[0..5]..]; + \\ a[a[0]..a[0]]; + \\ a[a[0..5]..a[0]]; + \\ a[a[0..5]..a[0..5]]; \\} \\ ); diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 64eb627590125931c1eba7b418287cc0a194cbd6..1014bacb30afb71a56f91c4d1c0b9f000ab2e323 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -91,6 +91,8 @@ pub const Token = struct { PercentEqual, LBrace, RBrace, + LBracket, + RBracket, Period, Ellipsis2, Ellipsis3, @@ -327,6 +329,16 @@ pub const Tokenizer = struct { self.index += 1; break; }, + '[' => { + result.id = Token.Id.LBracket; + self.index += 1; + break; + }, + ']' => { + result.id = Token.Id.RBracket; + self.index += 1; + break; + }, ';' => { result.id = Token.Id.Semicolon; self.index += 1; -- 2.54.0