Commit 7dd55a8007

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-09 11:48:25
std.zig.parser now parses for loops
1 parent e24409e
Changed files (2)
std/zig/ast.zig
@@ -20,12 +20,15 @@ pub const Node = struct {
         FnProto,
         ParamDecl,
         Block,
-        Payload,
+        ErrorPayload,
+        ValuePayload,
+        ValueIndexPayload,
         Else,
         Switch,
         SwitchCase,
         SwitchElse,
         While,
+        For,
         InfixOp,
         PrefixOp,
         SuffixOp,
@@ -61,12 +64,15 @@ pub const Node = struct {
             Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
             Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
             Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
-            Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index),
+            Id.ErrorPayload => @fieldParentPtr(NodeErrorPayload, "base", base).iterate(index),
+            Id.ValuePayload => @fieldParentPtr(NodeValuePayload, "base", base).iterate(index),
+            Id.ValueIndexPayload => @fieldParentPtr(NodeValueIndexPayload, "base", base).iterate(index),
             Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
             Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
             Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
             Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
             Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index),
+            Id.For => @fieldParentPtr(NodeFor, "base", base).iterate(index),
             Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
             Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
             Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
@@ -103,12 +109,15 @@ pub const Node = struct {
             Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
             Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
             Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
-            Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(),
+            Id.ErrorPayload => @fieldParentPtr(NodeErrorPayload, "base", base).firstToken(),
+            Id.ValuePayload => @fieldParentPtr(NodeValuePayload, "base", base).firstToken(),
+            Id.ValueIndexPayload => @fieldParentPtr(NodeValueIndexPayload, "base", base).firstToken(),
             Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
             Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
             Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
             Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
             Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(),
+            Id.For => @fieldParentPtr(NodeFor, "base", base).firstToken(),
             Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
             Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
             Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
@@ -145,12 +154,15 @@ pub const Node = struct {
             Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
             Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
             Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
-            Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(),
+            Id.ErrorPayload => @fieldParentPtr(NodeErrorPayload, "base", base).lastToken(),
+            Id.ValuePayload => @fieldParentPtr(NodeValuePayload, "base", base).lastToken(),
+            Id.ValueIndexPayload => @fieldParentPtr(NodeValueIndexPayload, "base", base).lastToken(),
             Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(),
             Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
             Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
             Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(),
             Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(),
+            Id.For => @fieldParentPtr(NodeFor, "base", base).lastToken(),
             Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
             Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
             Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
@@ -557,27 +569,82 @@ pub const NodeBlock = struct {
     }
 };
 
-pub const NodePayload = struct {
+pub const NodeErrorPayload = struct {
+    base: Node,
+    lpipe: Token,
+    error_symbol: &NodeIdentifier,
+    rpipe: Token,
+
+    pub fn iterate(self: &NodeErrorPayload, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return &self.error_symbol.base;
+        i -= 1;
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeErrorPayload) Token {
+        return self.lpipe;
+    }
+
+    pub fn lastToken(self: &NodeErrorPayload) Token {
+        return self.rpipe;
+    }
+};
+
+pub const NodeValuePayload = struct {
+    base: Node,
+    lpipe: Token,
+    is_ptr: bool,
+    value_symbol: &NodeIdentifier,
+    rpipe: Token,
+
+    pub fn iterate(self: &NodeValuePayload, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return &self.value_symbol.base;
+        i -= 1;
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeValuePayload) Token {
+        return self.lpipe;
+    }
+
+    pub fn lastToken(self: &NodeValuePayload) Token {
+        return self.rpipe;
+    }
+};
+
+pub const NodeValueIndexPayload = struct {
     base: Node,
     lpipe: Token,
     is_ptr: bool,
-    symbol: &NodeIdentifier,
+    value_symbol: &NodeIdentifier,
+    index_symbol: ?&NodeIdentifier,
     rpipe: Token,
 
-    pub fn iterate(self: &NodePayload, index: usize) ?&Node {
+    pub fn iterate(self: &NodeValueIndexPayload, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.symbol.base;
+        if (i < 1) return &self.value_symbol.base;
         i -= 1;
 
+        if (self.index_symbol) |index_symbol| {
+            if (i < 1) return &index_symbol.base;
+            i -= 1;
+        }
+
         return null;
     }
 
-    pub fn firstToken(self: &NodePayload) Token {
+    pub fn firstToken(self: &NodeValueIndexPayload) Token {
         return self.lpipe;
     }
 
-    pub fn lastToken(self: &NodePayload) Token {
+    pub fn lastToken(self: &NodeValueIndexPayload) Token {
         return self.rpipe;
     }
 };
@@ -585,7 +652,7 @@ pub const NodePayload = struct {
 pub const NodeElse = struct {
     base: Node,
     else_token: Token,
-    payload: ?&NodePayload,
+    payload: ?&NodeErrorPayload,
     body: &Node,
 
     pub fn iterate(self: &NodeElse, index: usize) ?&Node {
@@ -642,7 +709,7 @@ pub const NodeSwitch = struct {
 pub const NodeSwitchCase = struct {
     base: Node,
     items: ArrayList(&Node),
-    payload: ?&NodePayload,
+    payload: ?&NodeValuePayload,
     expr: &Node,
 
     pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
@@ -694,7 +761,7 @@ pub const NodeWhile = struct {
     inline_token: ?Token,
     while_token: Token,
     condition: &Node,
-    payload: ?&NodePayload,
+    payload: ?&NodeValuePayload,
     continue_expr: ?&Node,
     body: &Node,
     @"else": ?&NodeElse,
@@ -747,6 +814,59 @@ pub const NodeWhile = struct {
     }
 };
 
+pub const NodeFor = struct {
+    base: Node,
+    label: ?Token,
+    inline_token: ?Token,
+    for_token: Token,
+    array_expr: &Node,
+    payload: ?&NodeValueIndexPayload,
+    body: &Node,
+    @"else": ?&NodeElse,
+
+    pub fn iterate(self: &NodeFor, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return self.array_expr;
+        i -= 1;
+
+        if (self.payload) |payload| {
+            if (i < 1) return &payload.base;
+            i -= 1;
+        }
+
+        if (i < 1) return self.body;
+        i -= 1;
+
+        if (self.@"else") |@"else"| {
+            if (i < 1) return &@"else".base;
+            i -= 1;
+        }
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeFor) Token {
+        if (self.label) |label| {
+            return label;
+        }
+
+        if (self.inline_token) |inline_token| {
+            return inline_token;
+        }
+
+        return self.for_token;
+    }
+
+    pub fn lastToken(self: &NodeFor) Token {
+        if (self.@"else") |@"else"| {
+            return @"else".body.lastToken();
+        }
+
+        return self.body.lastToken();
+    }
+};
+
 pub const NodeInfixOp = struct {
     base: Node,
     op_token: Token,
@@ -781,7 +901,7 @@ pub const NodeInfixOp = struct {
         BitXor,
         BoolAnd,
         BoolOr,
-        Catch: ?&NodePayload,
+        Catch: ?&NodeErrorPayload,
         Div,
         EqualEqual,
         ErrorUnion,
std/zig/parser.zig
@@ -170,7 +170,9 @@ pub const Parser = struct {
         FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
         FieldListCommaOrEnd: &ast.NodeContainerDecl,
         SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
-        Payload: &?&ast.NodePayload,
+        ErrorPayload: &?&ast.NodeErrorPayload,
+        ValuePayload: &?&ast.NodeValuePayload,
+        ValueIndexPayload: &?&ast.NodeValueIndexPayload,
         SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
         SwitchCaseItem: &ArrayList(&ast.Node),
         SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
@@ -769,7 +771,7 @@ pub const Parser = struct {
 
                             stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
                             try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
-                            try stack.append(State { .Payload = &node.op.Catch });
+                            try stack.append(State { .ErrorPayload = &node.op.Catch });
                             continue;
                         },
                         Token.Id.QuestionMarkQuestionMark => {
@@ -1471,7 +1473,15 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_for => {
-                            @panic("TODO: inline for");
+                            stack.append(State {
+                                .For = LoopCtx {
+                                    .label = null,
+                                    .inline_token = null,
+                                    .loop_token = token,
+                                    .dest_ptr = dest_ptr,
+                                }
+                            }) catch unreachable;
+                            continue;
                         },
                         Token.Id.Keyword_switch => {
                             const node = try arena.create(ast.NodeSwitch);
@@ -1614,7 +1624,7 @@ pub const Parser = struct {
                     try list_state.list.append(node);
                     stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
                     try stack.append(State { .Expression = DestPtr{ .Field = &node.expr  } });
-                    try stack.append(State { .Payload = &node.payload });
+                    try stack.append(State { .ValuePayload = &node.payload });
 
                     const maybe_else = self.getNextToken();
                     if (maybe_else.id == Token.Id.Keyword_else) {
@@ -1681,7 +1691,7 @@ pub const Parser = struct {
                     *dest = node;
 
                     stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
-                    try stack.append(State { .Payload = &node.payload });
+                    try stack.append(State { .ErrorPayload = &node.payload });
                 },
 
                 State.WhileContinueExpr => |dest| {
@@ -1696,7 +1706,26 @@ pub const Parser = struct {
                     try stack.append(State { .Expression = DestPtr { .NullableField = dest } });
                 },
 
-                State.Payload => |dest| {
+                State.ErrorPayload => |dest| {
+                    const lpipe = self.getNextToken();
+                    if (lpipe.id != Token.Id.Pipe) {
+                        self.putBackToken(lpipe);
+                        continue;
+                    }
+
+                    const error_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                    const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
+                    const node = try arena.create(ast.NodeErrorPayload);
+                    *node = ast.NodeErrorPayload {
+                        .base = self.initNode(ast.Node.Id.ErrorPayload),
+                        .lpipe = lpipe,
+                        .error_symbol = try self.createIdentifier(arena, error_symbol),
+                        .rpipe = rpipe
+                    };
+                    *dest = node;
+                },
+
+                State.ValuePayload => |dest| {
                     const lpipe = self.getNextToken();
                     if (lpipe.id != Token.Id.Pipe) {
                         self.putBackToken(lpipe);
@@ -1713,14 +1742,56 @@ pub const Parser = struct {
                         }
                     };
 
-                    const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                    const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
                     const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
-                    const node = try arena.create(ast.NodePayload);
-                    *node = ast.NodePayload {
-                        .base = self.initNode(ast.Node.Id.Payload),
+                    const node = try arena.create(ast.NodeValuePayload);
+                    *node = ast.NodeValuePayload {
+                        .base = self.initNode(ast.Node.Id.ValuePayload),
                         .lpipe = lpipe,
                         .is_ptr = is_ptr,
-                        .symbol = try self.createIdentifier(arena, ident),
+                        .value_symbol = try self.createIdentifier(arena, value_symbol),
+                        .rpipe = rpipe
+                    };
+                    *dest = node;
+                },
+
+                State.ValueIndexPayload => |dest| {
+                    const lpipe = self.getNextToken();
+                    if (lpipe.id != Token.Id.Pipe) {
+                        self.putBackToken(lpipe);
+                        continue;
+                    }
+
+                    const is_ptr = blk: {
+                        const asterik = self.getNextToken();
+                        if (asterik.id == Token.Id.Asterisk) {
+                            break :blk true;
+                        } else {
+                            self.putBackToken(asterik);
+                            break :blk false;
+                        }
+                    };
+
+                    const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                    const index_symbol = blk: {
+                        const comma = self.getNextToken();
+                        if (comma.id != Token.Id.Comma) {
+                            self.putBackToken(comma);
+                            break :blk null;
+                        }
+
+                        const symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                        break :blk try self.createIdentifier(arena, symbol);
+                    };
+
+                    const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
+                    const node = try arena.create(ast.NodeValueIndexPayload);
+                    *node = ast.NodeValueIndexPayload {
+                        .base = self.initNode(ast.Node.Id.ValueIndexPayload),
+                        .lpipe = lpipe,
+                        .is_ptr = is_ptr,
+                        .value_symbol = try self.createIdentifier(arena, value_symbol),
+                        .index_symbol = index_symbol,
                         .rpipe = rpipe
                     };
                     *dest = node;
@@ -1986,13 +2057,32 @@ pub const Parser = struct {
                     stack.append(State { .Else = &node.@"else" }) catch unreachable;
                     try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
                     try stack.append(State { .WhileContinueExpr = &node.continue_expr });
-                    try stack.append(State { .Payload = &node.payload });
+                    try stack.append(State { .ValuePayload = &node.payload });
                     try stack.append(State { .ExpectToken = Token.Id.RParen });
                     try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
                     try stack.append(State { .ExpectToken = Token.Id.LParen });
                 },
 
                 State.For => |ctx| {
+                    const node = try arena.create(ast.NodeFor);
+                    *node = ast.NodeFor {
+                        .base = self.initNode(ast.Node.Id.For),
+                        .label = ctx.label,
+                        .inline_token = ctx.inline_token,
+                        .for_token = ctx.loop_token,
+                        .array_expr = undefined,
+                        .payload = null,
+                        .body = undefined,
+                        .@"else" = null,
+                    };
+                    ctx.dest_ptr.store(&node.base);
+
+                    stack.append(State { .Else = &node.@"else" }) catch unreachable;
+                    try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
+                    try stack.append(State { .ValueIndexPayload = &node.payload });
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
                 },
 
                 State.Block => |block| {
@@ -2071,7 +2161,9 @@ pub const Parser = struct {
                 ast.Node.Id.EnumTag,
                 ast.Node.Id.ParamDecl,
                 ast.Node.Id.Block,
-                ast.Node.Id.Payload,
+                ast.Node.Id.ErrorPayload,
+                ast.Node.Id.ValuePayload,
+                ast.Node.Id.ValueIndexPayload,
                 ast.Node.Id.Switch,
                 ast.Node.Id.SwitchCase,
                 ast.Node.Id.SwitchElse,
@@ -2087,6 +2179,15 @@ pub const Parser = struct {
 
                     n = while_node.body;
                 },
+                ast.Node.Id.For => {
+                    const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
+                    if (for_node.@"else") |@"else"| {
+                        n = @"else".base;
+                        continue;
+                    }
+
+                    n = for_node.body;
+                },
                 ast.Node.Id.Else => {
                     const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
                     n = else_node.body;
@@ -2982,10 +3083,33 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Expression = rhs });
                         }
                     },
-                    ast.Node.Id.Payload => {
-                        const payload = @fieldParentPtr(ast.NodePayload, "base", base);
+                    ast.Node.Id.ErrorPayload => {
+                        const payload = @fieldParentPtr(ast.NodeErrorPayload, "base", base);
+                        try stack.append(RenderState { .Text = "|"});
+                        try stack.append(RenderState { .Expression = &payload.error_symbol.base });
+                        try stack.append(RenderState { .Text = "|"});
+                    },
+                    ast.Node.Id.ValuePayload => {
+                        const payload = @fieldParentPtr(ast.NodeValuePayload, "base", base);
+                        try stack.append(RenderState { .Text = "|"});
+                        try stack.append(RenderState { .Expression = &payload.value_symbol.base });
+
+                        if (payload.is_ptr) {
+                            try stack.append(RenderState { .Text = "*"});
+                        }
+
+                        try stack.append(RenderState { .Text = "|"});
+                    },
+                    ast.Node.Id.ValueIndexPayload => {
+                        const payload = @fieldParentPtr(ast.NodeValueIndexPayload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
-                        try stack.append(RenderState { .Expression = &payload.symbol.base });
+
+                        if (payload.index_symbol) |index_symbol| {
+                            try stack.append(RenderState { .Expression = &index_symbol.base });
+                            try stack.append(RenderState { .Text = ", "});
+                        }
+
+                        try stack.append(RenderState { .Expression = &payload.value_symbol.base });
 
                         if (payload.is_ptr) {
                             try stack.append(RenderState { .Text = "*"});
@@ -3303,6 +3427,48 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Expression = while_node.condition });
                         try stack.append(RenderState { .Text = "(" });
                     },
+                    ast.Node.Id.For => {
+                        const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
+                        if (for_node.label) |label| {
+                            try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
+                        }
+
+                        if (for_node.inline_token) |inline_token| {
+                            try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
+                        }
+
+                        try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
+
+                        if (for_node.@"else") |@"else"| {
+                            try stack.append(RenderState { .Expression = &@"else".base });
+
+                            if (for_node.body.id == ast.Node.Id.Block) {
+                                try stack.append(RenderState { .Text = " " });
+                            } else {
+                                try stack.append(RenderState { .Text = "\n" });
+                            }
+                        }
+
+                        if (for_node.body.id == ast.Node.Id.Block) {
+                            try stack.append(RenderState { .Expression = for_node.body });
+                            try stack.append(RenderState { .Text = " " });
+                        } else {
+                            try stack.append(RenderState { .Indent = indent });
+                            try stack.append(RenderState { .Expression = for_node.body });
+                            try stack.append(RenderState.PrintIndent);
+                            try stack.append(RenderState { .Indent = indent + indent_delta });
+                            try stack.append(RenderState { .Text = "\n" });
+                        }
+
+                        if (for_node.payload) |payload| {
+                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Text = " " });
+                        }
+
+                        try stack.append(RenderState { .Text = ")" });
+                        try stack.append(RenderState { .Expression = for_node.array_expr });
+                        try stack.append(RenderState { .Text = "(" });
+                    },
 
                     ast.Node.Id.StructField,
                     ast.Node.Id.UnionTag,
@@ -4022,10 +4188,10 @@ test "zig fmt: for" {
         \\        continue;
         \\
         \\    const res = for (a) |v, i| {
-        \\        breal v;
+        \\        break v;
         \\    } else {
         \\        unreachable;
-        \\    }
+        \\    };
         \\
         \\    var num: usize = 0;
         \\    inline for (a) |v, i| {