Commit ca0085c46d

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-04 10:54:48
std.zig.parser now parses error set declarations
1 parent 020724c
Changed files (2)
std/zig/ast.zig
@@ -11,6 +11,7 @@ pub const Node = struct {
     pub const Id = enum {
         Root,
         VarDecl,
+        ErrorSetDecl,
         ContainerDecl,
         StructField,
         UnionTag,
@@ -44,6 +45,7 @@ pub const Node = struct {
         return switch (base.id) {
             Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),
             Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),
+            Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index),
             Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index),
             Id.StructField => @fieldParentPtr(NodeStructField, "base", base).iterate(index),
             Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).iterate(index),
@@ -78,6 +80,7 @@ pub const Node = struct {
         return switch (base.id) {
             Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),
             Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),
+            Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(),
             Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(),
             Id.StructField => @fieldParentPtr(NodeStructField, "base", base).firstToken(),
             Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).firstToken(),
@@ -112,6 +115,7 @@ pub const Node = struct {
         return switch (base.id) {
             Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),
             Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),
+            Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(),
             Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(),
             Id.StructField => @fieldParentPtr(NodeStructField, "base", base).lastToken(),
             Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).lastToken(),
@@ -212,6 +216,30 @@ pub const NodeVarDecl = struct {
     }
 };
 
+pub const NodeErrorSetDecl = struct {
+    base: Node,
+    error_token: Token,
+    decls: ArrayList(&NodeIdentifier),
+    rbrace_token: Token,
+
+    pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
+        var i = index;
+
+        if (i < self.decls.len) return self.decls.at(i);
+        i -= self.decls.len;
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeErrorSetDecl) Token {
+        return self.error_token;
+    }
+
+    pub fn lastToken(self: &NodeErrorSetDecl) Token {
+        return self.rbrace_token;
+    }
+};
+
 pub const NodeContainerDecl = struct {
     base: Node,
     ltoken: Token,
@@ -251,23 +279,8 @@ pub const NodeContainerDecl = struct {
             InitArg.Enum => { }
         }
 
-        if (i < self.decls.len) return self.decls.at(i);
-        i -= self.decls.len;
-
-        switch (self.kind) {
-            Kind.Struct => |fields| {
-                if (i < fields.len) return fields.at(i);
-                i -= fields.len;
-            },
-            Kind.Enum => |tags| {
-                if (i < tags.len) return tags.at(i);
-                i -= tags.len;
-            },
-            Kind.Union => |tags| {
-                if (i < tags.len) return tags.at(i);
-                i -= tags.len;
-            },
-        }
+        if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
+        i -= self.fields_and_decls.len;
 
         return null;
     }
std/zig/parser.zig
@@ -685,11 +685,66 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_error => {
-                            const node = try arena.create(ast.NodeErrorType);
-                            *node = ast.NodeErrorType {
-                                .base = self.initNode(ast.Node.Id.ErrorType),
-                                .token = token,
+                            const next = self.getNextToken();
+
+                            if (next.id != Token.Id.LBrace) {
+                                self.putBackToken(next);
+                                const node = try arena.create(ast.NodeErrorType);
+                                *node = ast.NodeErrorType {
+                                    .base = self.initNode(ast.Node.Id.ErrorType),
+                                    .token = token,
+                                };
+                                try stack.append(State {
+                                    .Operand = &node.base
+                                });
+                                try stack.append(State.AfterOperand);
+                                continue;
+                            }
+
+                            const node = try arena.create(ast.NodeErrorSetDecl);
+                            *node = ast.NodeErrorSetDecl {
+                                .base = self.initNode(ast.Node.Id.ErrorSetDecl),
+                                .error_token = token,
+                                .decls = ArrayList(&ast.NodeIdentifier).init(arena),
+                                .rbrace_token = undefined,
                             };
+
+                            while (true) {
+                                const t = self.getNextToken();
+                                switch (t.id) {
+                                    Token.Id.RBrace => {
+                                        node.rbrace_token = t;
+                                        break;
+                                    },
+                                    Token.Id.Identifier => {
+                                        try node.decls.append(
+                                            try self.createIdentifier(arena, t)
+                                        );
+                                    },
+                                    else => {
+                                        return self.parseError(token, "expected {} or {}, found {}",
+                                            @tagName(Token.Id.RBrace),
+                                            @tagName(Token.Id.Identifier),
+                                            @tagName(token.id));
+                                    }
+                                }
+
+                                const t2 = self.getNextToken();
+                                switch (t2.id) {
+                                    Token.Id.RBrace => {
+                                        node.rbrace_token = t;
+                                        break;
+                                    },
+                                    Token.Id.Comma => continue,
+                                    else => {
+                                        return self.parseError(token, "expected {} or {}, found {}",
+                                            @tagName(Token.Id.RBrace),
+                                            @tagName(Token.Id.Comma),
+                                            @tagName(token.id));
+                                    }
+                                }
+                            }
+
                             try stack.append(State {
                                 .Operand = &node.base
                             });
@@ -2115,6 +2170,42 @@ pub const Parser = struct {
                             },
                         }
                     },
+                    ast.Node.Id.ErrorSetDecl => {
+                        const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
+                        try stream.print("error ");
+
+                        try stack.append(RenderState { .Text = "}"});
+                        try stack.append(RenderState.PrintIndent);
+                        try stack.append(RenderState { .Indent = indent });
+                        try stack.append(RenderState { .Text = "\n"});
+
+                        const decls = err_set_decl.decls.toSliceConst();
+                        var i = decls.len;
+                        while (i != 0) {
+                            i -= 1;
+                            const node = decls[i];
+                            try stack.append(RenderState { .Expression = &node.base});
+                            try stack.append(RenderState.PrintIndent);
+                            try stack.append(RenderState {
+                                .Text = blk: {
+                                    if (i != 0) {
+                                        const prev_node = decls[i - 1];
+                                        const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
+                                        if (loc.line >= 2) {
+                                            break :blk "\n\n";
+                                        }
+                                    }
+                                    break :blk "\n";
+                                },
+                            });
+
+                            if (i != 0) {
+                                try stack.append(RenderState { .Text = "," });
+                            }
+                        }
+                        try stack.append(RenderState { .Indent = indent + indent_delta});
+                        try stack.append(RenderState { .Text = "{"});
+                    },
                     ast.Node.Id.MultilineStringLiteral => {
                         const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
                         try stream.print("\n");
@@ -2643,6 +2734,18 @@ test "zig fmt: union declaration" {
     );
 }
 
+test "zig fmt: error set declaration" {
+      try testCanonical(
+        \\const E = error {
+        \\    A,
+        \\    B,
+        \\
+        \\    C
+        \\};
+        \\
+    );
+}
+
 test "zig fmt: switch" {
     try testCanonical(
         \\test "switch" {