Commit b9093185f7

Jimmi Holst Christensen <jimmiholstchristensen@gmail.com>
2018-04-01 22:02:51
std.zig.parser now parses slicing and array access
1 parent df09c01
Changed files (3)
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,
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]];
         \\}
         \\
     );
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;