Commit 1d71b19c0d

Isaac Freund <ifreund@ifreund.xyz>
2021-02-07 22:16:23
zig fmt: implement error set decls
1 parent bb7b5ee
Changed files (4)
lib/std/zig/ast.zig
@@ -498,6 +498,7 @@ pub const Tree = struct {
             .UnwrapOptional,
             .GroupedExpression,
             .StringLiteral,
+            .ErrorSetDecl,
             => return datas[n].rhs + end_offset,
 
             .AnyType,
@@ -724,7 +725,6 @@ pub const Tree = struct {
             .Switch => unreachable, // TODO
             .If => unreachable, // TODO
             .Continue => unreachable, // TODO
-            .ErrorSetDecl => unreachable, // TODO
             .AsmSimple => unreachable, // TODO
             .Asm => unreachable, // TODO
             .SwitchCaseOne => unreachable, // TODO
@@ -2061,7 +2061,7 @@ pub const Node = struct {
         /// Same as BuiltinCall but there is known to be a trailing comma before the rparen.
         BuiltinCallComma,
         /// `error{a, b}`.
-        /// lhs and rhs both unused.
+        /// rhs is the rbrace, lhs is unused.
         ErrorSetDecl,
         /// `struct {}`, `union {}`, `opaque {}`, `enum {}`. `extra_data[lhs..rhs]`.
         /// main_token is `struct`, `union`, `opaque`, `enum` keyword.
lib/std/zig/parse.zig
@@ -2714,13 +2714,13 @@ const Parser = struct {
                     const error_token = p.tok_i;
                     p.tok_i += 2;
 
-                    if (p.eatToken(.RBrace)) |_| {
+                    if (p.eatToken(.RBrace)) |rbrace| {
                         return p.addNode(.{
                             .tag = .ErrorSetDecl,
                             .main_token = error_token,
                             .data = .{
                                 .lhs = undefined,
-                                .rhs = undefined,
+                                .rhs = rbrace,
                             },
                         });
                     }
@@ -2758,7 +2758,7 @@ const Parser = struct {
                         .main_token = error_token,
                         .data = .{
                             .lhs = undefined,
-                            .rhs = undefined,
+                            .rhs = p.tok_i - 1, // rbrace
                         },
                     });
                 },
lib/std/zig/parser_test.zig
@@ -2015,7 +2015,36 @@ test "zig fmt: ptr deref operator and unwrap optional operator" {
 //        \\
 //    );
 //}
-//
+
+// TODO: replace this with the next test case when possible
+test "zig fmt: error set declaration" {
+    try testCanonical(
+        \\const E = error{
+        \\    A,
+        \\    B,
+        \\
+        \\    C,
+        \\};
+        \\const Error = error{
+        \\    /// no more memory
+        \\    OutOfMemory,
+        \\};
+        \\const Error = error{
+        \\    /// no more memory
+        \\    OutOfMemory,
+        \\
+        \\    /// another
+        \\    Another,
+        \\    /// and one more
+        \\    Another,
+        \\};
+        \\const Error = error{OutOfMemory};
+        \\const Error = error{};
+        \\const Error = error{ OutOfMemory, OutOfTime };
+        \\
+    );
+}
+
 //test "zig fmt: error set declaration" {
 //    try testCanonical(
 //        \\const E = error{
lib/std/zig/render.zig
@@ -563,7 +563,55 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
         .TaggedUnionEnumTagComma,
         => return renderContainerDecl(ais, tree, tree.taggedUnionEnumTag(node), space),
 
-        .ErrorSetDecl => unreachable, // TODO
+        // TODO: handle comments properly
+        .ErrorSetDecl => {
+            const error_token = main_tokens[node];
+            const lbrace = error_token + 1;
+            const rbrace = datas[node].rhs;
+
+            try renderToken(ais, tree, error_token, .None);
+
+            if (lbrace + 1 == rbrace) {
+                // There is nothing between the braces so render condensed: `error{}`
+                try renderToken(ais, tree, lbrace, .None);
+                try renderToken(ais, tree, rbrace, space);
+            } else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .Identifier) {
+                // There is exactly one member and no trailing comma or
+                // comments, so render without surrounding spaces: `error{Foo}`
+                try renderToken(ais, tree, lbrace, .None);
+                try renderToken(ais, tree, lbrace + 1, .None); // identifier
+                try renderToken(ais, tree, rbrace, space);
+            } else if (token_tags[rbrace - 1] == .Comma) {
+                // There is a trailing comma so render each member on a new line.
+                try renderToken(ais, tree, lbrace, .Newline);
+                ais.pushIndent();
+                var i = lbrace + 1;
+                while (i < rbrace) : (i += 1) {
+                    try renderExtraNewlineToken(ais, tree, i);
+                    switch (token_tags[i]) {
+                        .DocComment => try renderToken(ais, tree, i, .Newline),
+                        .Identifier => try renderToken(ais, tree, i, .Comma),
+                        .Comma => {},
+                        else => unreachable,
+                    }
+                }
+                ais.popIndent();
+                try renderToken(ais, tree, rbrace, space);
+            } else {
+                // There is no trailing comma so render everything on one line.
+                try renderToken(ais, tree, lbrace, .Space);
+                var i = lbrace + 1;
+                while (i < rbrace) : (i += 1) {
+                    switch (token_tags[i]) {
+                        .DocComment => unreachable, // TODO
+                        .Identifier => try renderToken(ais, tree, i, .CommaSpace),
+                        .Comma => {},
+                        else => unreachable,
+                    }
+                }
+                try renderToken(ais, tree, rbrace, space);
+            }
+        },
         //.ErrorSetDecl => {
         //    const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);