Commit d4e6a6d5e2

Andrew Kelley <andrew@ziglang.org>
2019-11-11 19:10:06
zig fmt: support anon struct and anon list init syntax
1 parent 725b6ee
Changed files (4)
lib/std/zig/ast.zig
@@ -1648,10 +1648,15 @@ pub const Node = struct {
 
     pub const SuffixOp = struct {
         base: Node,
-        lhs: *Node,
+        lhs: Lhs,
         op: Op,
         rtoken: TokenIndex,
 
+        pub const Lhs = union(enum) {
+            node: *Node,
+            dot: TokenIndex,
+        };
+
         pub const Op = union(enum) {
             Call: Call,
             ArrayAccess: *Node,
@@ -1679,8 +1684,13 @@ pub const Node = struct {
         pub fn iterate(self: *SuffixOp, index: usize) ?*Node {
             var i = index;
 
-            if (i < 1) return self.lhs;
-            i -= 1;
+            switch (self.lhs) {
+                .node => |node| {
+                    if (i == 0) return node;
+                    i -= 1;
+                },
+                .dot => {},
+            }
 
             switch (self.op) {
                 .Call => |*call_info| {
@@ -1721,7 +1731,10 @@ pub const Node = struct {
                 .Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
                 else => {},
             }
-            return self.lhs.firstToken();
+            switch (self.lhs) {
+                .node => |node| return node.firstToken(),
+                .dot => |dot| return dot,
+            }
         }
 
         pub fn lastToken(self: *const SuffixOp) TokenIndex {
lib/std/zig/parse.zig
@@ -1026,16 +1026,16 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 /// CurlySuffixExpr <- TypeExpr InitList?
 fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
-    const init_list = (try parseInitList(arena, it, tree)) orelse return type_expr;
-    init_list.cast(Node.SuffixOp).?.lhs = type_expr;
-    return init_list;
+    const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr;
+    suffix_op.lhs.node = type_expr;
+    return &suffix_op.base;
 }
 
 /// InitList
 ///     <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
 ///      / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
 ///      / LBRACE RBRACE
-fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
+fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp {
     const lbrace = eatToken(it, .LBrace) orelse return null;
     var init_list = Node.SuffixOp.Op.InitList.init(arena);
 
@@ -1064,11 +1064,11 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     const node = try arena.create(Node.SuffixOp);
     node.* = Node.SuffixOp{
         .base = Node{ .id = .SuffixOp },
-        .lhs = undefined, // set by caller
+        .lhs = .{.node = undefined}, // set by caller
         .op = op,
         .rtoken = try expectToken(it, tree, .RBrace),
     };
-    return &node.base;
+    return node;
 }
 
 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
@@ -1117,7 +1117,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 
         while (try parseSuffixOp(arena, it, tree)) |node| {
             switch (node.id) {
-                .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
+                .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
                 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
                 else => unreachable,
             }
@@ -1133,7 +1133,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
         const node = try arena.create(Node.SuffixOp);
         node.* = Node.SuffixOp{
             .base = Node{ .id = .SuffixOp },
-            .lhs = res,
+            .lhs = .{.node = res},
             .op = Node.SuffixOp.Op{
                 .Call = Node.SuffixOp.Op.Call{
                     .params = params.list,
@@ -1150,7 +1150,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
         while (true) {
             if (try parseSuffixOp(arena, it, tree)) |node| {
                 switch (node.id) {
-                    .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
+                    .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
                     .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
                     else => unreachable,
                 }
@@ -1161,7 +1161,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
                 const call = try arena.create(Node.SuffixOp);
                 call.* = Node.SuffixOp{
                     .base = Node{ .id = .SuffixOp },
-                    .lhs = res,
+                    .lhs = .{.node = res},
                     .op = Node.SuffixOp.Op{
                         .Call = Node.SuffixOp.Op.Call{
                             .params = params.list,
@@ -1215,7 +1215,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
         return &node.base;
     }
     if (try parseContainerDecl(arena, it, tree)) |node| return node;
-    if (try parseEnumLiteral(arena, it, tree)) |node| return node;
+    if (try parseAnonLiteral(arena, it, tree)) |node| return node;
     if (try parseErrorSetDecl(arena, it, tree)) |node| return node;
     if (try parseFloatLiteral(arena, it, tree)) |node| return node;
     if (try parseFnProto(arena, it, tree)) |node| return node;
@@ -1494,16 +1494,28 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 }
 
 /// DOT IDENTIFIER
-fn parseEnumLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
+fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     const dot = eatToken(it, .Period) orelse return null;
-    const name = try expectToken(it, tree, .Identifier);
-    const node = try arena.create(Node.EnumLiteral);
-    node.* = Node.EnumLiteral{
-        .base = Node{ .id = .EnumLiteral },
-        .dot = dot,
-        .name = name,
-    };
-    return &node.base;
+
+    // anon enum literal
+    if (eatToken(it, .Identifier)) |name| {
+        const node = try arena.create(Node.EnumLiteral);
+        node.* = Node.EnumLiteral{
+            .base = Node{ .id = .EnumLiteral },
+            .dot = dot,
+            .name = name,
+        };
+        return &node.base;
+    }
+
+    // anon container literal
+    if (try parseInitList(arena, it, tree)) |node| {
+        node.lhs = .{.dot = dot};
+        return &node.base;
+    }
+
+    putBackToken(it, dot);
+    return null;
 }
 
 /// AsmOutput <- COLON AsmOutputList AsmInput?
lib/std/zig/parser_test.zig
@@ -1,3 +1,20 @@
+test "zig fmt: anon struct literal syntax" {
+    try testCanonical(
+        \\const x = .{
+        \\    .a = b,
+        \\    .c = d,
+        \\};
+        \\
+    );
+}
+
+test "zig fmt: anon list literal syntax" {
+    try testCanonical(
+        \\const x = .{ a, b, c };
+        \\
+    );
+}
+
 test "zig fmt: async function" {
     try testCanonical(
         \\pub const Server = struct {
lib/std/zig/render.zig
@@ -538,9 +538,9 @@ fn renderExpression(
                         try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
                     }
 
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
 
-                    const lparen = tree.nextToken(suffix_op.lhs.lastToken());
+                    const lparen = tree.nextToken(suffix_op.lhs.node.lastToken());
 
                     if (call_info.params.len == 0) {
                         try renderToken(tree, stream, lparen, indent, start_col, Space.None);
@@ -598,7 +598,7 @@ fn renderExpression(
                     const lbracket = tree.prevToken(index_expr.firstToken());
                     const rbracket = tree.nextToken(index_expr.lastToken());
 
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
                     try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
 
                     const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;
@@ -616,18 +616,18 @@ fn renderExpression(
                 },
 
                 ast.Node.SuffixOp.Op.Deref => {
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
                     return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
                 },
 
                 ast.Node.SuffixOp.Op.UnwrapOptional => {
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
                     try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
                     return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
                 },
 
                 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None);
 
                     const lbracket = tree.prevToken(range.start.firstToken());
                     const dotdot = tree.nextToken(range.start.lastToken());
@@ -647,10 +647,16 @@ fn renderExpression(
                 },
 
                 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
-                    const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
+                    const lbrace = switch (suffix_op.lhs) {
+                        .dot => |dot| tree.nextToken(dot),
+                        .node => |node| tree.nextToken(node.lastToken()),
+                    };
 
                     if (field_inits.len == 0) {
-                        try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                        switch (suffix_op.lhs) {
+                            .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                            .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                        }
                         try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);
                         return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
                     }
@@ -691,7 +697,10 @@ fn renderExpression(
                             break :blk;
                         }
 
-                        try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                        switch (suffix_op.lhs) {
+                            .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                            .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                        }
                         try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
                         try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);
                         return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
@@ -699,7 +708,10 @@ fn renderExpression(
 
                     if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
                         // render all on one line, no trailing comma
-                        try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                        switch (suffix_op.lhs) {
+                            .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                            .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                        }
                         try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
 
                         var it = field_inits.iterator(0);
@@ -719,7 +731,10 @@ fn renderExpression(
 
                     const new_indent = indent + indent_delta;
 
-                    try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.lhs, Space.None);
+                    switch (suffix_op.lhs) {
+                        .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),
+                        .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None),
+                    }
                     try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
 
                     var it = field_inits.iterator(0);
@@ -743,23 +758,35 @@ fn renderExpression(
                 },
 
                 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
-                    const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
+                    const lbrace = switch (suffix_op.lhs) {
+                        .dot => |dot| tree.nextToken(dot),
+                        .node => |node| tree.nextToken(node.lastToken()),
+                    };
 
                     if (exprs.len == 0) {
-                        try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                        switch (suffix_op.lhs) {
+                            .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                            .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                        }
                         try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
                         return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
                     }
                     if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) {
                         const expr = exprs.at(0).*;
 
-                        try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                        switch (suffix_op.lhs) {
+                            .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                            .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                        }
                         try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
                         try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
                         return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
                     }
 
-                    try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
+                    switch (suffix_op.lhs) {
+                        .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
+                        .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
+                    }
 
                     // scan to find row size
                     const maybe_row_size: ?usize = blk: {