Commit 1d06915f27

Andrew Kelley <superjoe30@gmail.com>
2018-05-01 00:20:27
zig fmt: support union(enum(tag)) and enum init values
1 parent 7dc8d43
Changed files (3)
std/zig/ast.zig
@@ -261,7 +261,7 @@ pub const Node = struct {
 
         const InitArg = union(enum) {
             None,
-            Enum,
+            Enum: ?&Node,
             Type: &Node,
         };
 
@@ -321,6 +321,7 @@ pub const Node = struct {
         base: Node,
         name_token: Token,
         type_expr: ?&Node,
+        value_expr: ?&Node,
 
         pub fn iterate(self: &UnionTag, index: usize) ?&Node {
             var i = index;
@@ -330,6 +331,11 @@ pub const Node = struct {
                 i -= 1;
             }
 
+            if (self.value_expr) |value_expr| {
+                if (i < 1) return value_expr;
+                i -= 1;
+            }
+
             return null;
         }
 
@@ -338,6 +344,9 @@ pub const Node = struct {
         }
 
         pub fn lastToken(self: &UnionTag) Token {
+            if (self.value_expr) |value_expr| {
+                return value_expr.lastToken();
+            }
             if (self.type_expr) |type_expr| {
                 return type_expr.lastToken();
             }
std/zig/parser.zig
@@ -242,6 +242,7 @@ pub const Parser = struct {
         FieldInitListItemOrEnd: ListSave(&ast.Node.FieldInitializer),
         FieldInitListCommaOrEnd: ListSave(&ast.Node.FieldInitializer),
         FieldListCommaOrEnd: &ast.Node.ContainerDecl,
+        FieldInitValue: OptionalCtx,
         IdentifierListItemOrEnd: ListSave(&ast.Node),
         IdentifierListCommaOrEnd: ListSave(&ast.Node),
         SwitchCaseOrEnd: ListSave(&ast.Node),
@@ -653,6 +654,15 @@ pub const Parser = struct {
                     continue;
                 },
 
+                State.FieldInitValue => |ctx| {
+                    const eq_tok = self.getNextToken();
+                    if (eq_tok.id != Token.Id.Equal) {
+                        self.putBackToken(eq_tok);
+                        continue;
+                    }
+                    stack.append(State { .Expression = ctx }) catch unreachable;
+                    continue;
+                },
 
                 State.ContainerKind => |ctx| {
                     const token = self.getNextToken();
@@ -699,7 +709,16 @@ pub const Parser = struct {
                     const init_arg_token = self.getNextToken();
                     switch (init_arg_token.id) {
                         Token.Id.Keyword_enum => {
-                            container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg.Enum;
+                            container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
+                            const lparen_tok = self.getNextToken();
+                            if (lparen_tok.id == Token.Id.LParen) {
+                                try stack.append(State { .ExpectToken = Token.Id.RParen } );
+                                try stack.append(State { .Expression = OptionalCtx {
+                                    .RequiredNull = &container_decl.init_arg_expr.Enum,
+                                } });
+                            } else {
+                                self.putBackToken(lparen_tok);
+                            }
                         },
                         else => {
                             self.putBackToken(init_arg_token);
@@ -709,6 +728,7 @@ pub const Parser = struct {
                     }
                     continue;
                 },
+
                 State.ContainerDecl => |container_decl| {
                     while (try self.eatLineComment(arena)) |line_comment| {
                         try container_decl.fields_and_decls.append(&line_comment.base);
@@ -744,10 +764,12 @@ pub const Parser = struct {
                                             .base = undefined,
                                             .name_token = token,
                                             .type_expr = null,
+                                            .value_expr = null,
                                         }
                                     );
 
                                     stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
+                                    try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
                                     try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
                                     try stack.append(State { .IfToken = Token.Id.Colon });
                                     continue;
@@ -3515,6 +3537,12 @@ pub const Parser = struct {
                             try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
 
                             try stack.append(RenderState { .Text = "," });
+
+                            if (tag.value_expr) |value_expr| {
+                                try stack.append(RenderState { .Expression = value_expr });
+                                try stack.append(RenderState { .Text = " = " });
+                            }
+
                             if (tag.type_expr) |type_expr| {
                                 try stream.print(": ");
                                 try stack.append(RenderState { .Expression = type_expr});
@@ -4055,7 +4083,15 @@ pub const Parser = struct {
 
                         switch (container_decl.init_arg_expr) {
                             ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
-                            ast.Node.ContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
+                            ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
+                                if (enum_tag_type) |expr| {
+                                    try stack.append(RenderState { .Text = ")) "});
+                                    try stack.append(RenderState { .Expression = expr});
+                                    try stack.append(RenderState { .Text = "(enum("});
+                                } else {
+                                    try stack.append(RenderState { .Text = "(enum) "});
+                                }
+                            },
                             ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
                                 try stack.append(RenderState { .Text = ") "});
                                 try stack.append(RenderState { .Expression = type_expr});
std/zig/parser_test.zig
@@ -1,3 +1,15 @@
+test "zig fmt: union(enum(u32)) with assigned enum values" {
+      try testCanonical(
+        \\const MultipleChoice = union(enum(u32)) {
+        \\    A = 20,
+        \\    B = 40,
+        \\    C = 60,
+        \\    D = 1000,
+        \\};
+        \\
+    );
+}
+
 test "zig fmt: labeled suspend" {
     try testCanonical(
         \\fn foo() void {