Commit 09cf823619

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-04 09:57:37
std.zig.parser now parses container decls
1 parent ec611bf
Changed files (2)
std/zig/ast.zig
@@ -214,12 +214,19 @@ pub const NodeVarDecl = struct {
 
 pub const NodeContainerDecl = struct {
     base: Node,
-    kind_token: Token,
+    ltoken: Token,
+    layout: Layout,
     kind: Kind,
     init_arg_expr: InitArg,
     fields_and_decls: ArrayList(&Node),
     rbrace_token: Token,
 
+    const Layout = enum {
+        Auto,
+        Extern,
+        Packed,
+    };
+
     const Kind = enum {
         Struct,
         Enum,
@@ -266,7 +273,7 @@ pub const NodeContainerDecl = struct {
     }
 
     pub fn firstToken(self: &NodeContainerDecl) Token {
-        return self.kind_token;
+        return self.ltoken;
     }
 
     pub fn lastToken(self: &NodeContainerDecl) Token {
std/zig/parser.zig
@@ -59,6 +59,11 @@ pub const Parser = struct {
         lib_name: ?&ast.Node,
     };
 
+    const ContainerExternCtx = struct {
+        ltoken: Token,
+        layout: ast.NodeContainerDecl.Layout,
+    };
+
     const DestPtr = union(enum) {
         Field: &&ast.Node,
         NullableField: &?&ast.Node,
@@ -90,6 +95,7 @@ pub const Parser = struct {
         TopLevel,
         TopLevelExtern: TopLevelDeclCtx,
         TopLevelDecl: TopLevelDeclCtx,
+        ContainerExtern: ContainerExternCtx,
         ContainerDecl: &ast.NodeContainerDecl,
         Expression: DestPtr,
         ExpectOperand,
@@ -338,6 +344,63 @@ pub const Parser = struct {
                     return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
                 },
 
+                State.ContainerExtern => |ctx| {
+                    const token = self.getNextToken();
+
+                    const node = try arena.create(ast.NodeContainerDecl);
+                    *node = ast.NodeContainerDecl {
+                        .base = self.initNode(ast.Node.Id.ContainerDecl),
+                        .ltoken = ctx.ltoken,
+                        .layout = ctx.layout,
+                        .kind = switch (token.id) {
+                            Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
+                            Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
+                            Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
+                            else => {
+                                return self.parseError(token, "expected {}, {} or {}, found {}",
+                                    @tagName(Token.Id.Keyword_struct),
+                                    @tagName(Token.Id.Keyword_union),
+                                    @tagName(Token.Id.Keyword_enum),
+                                    @tagName(token.id));
+                            },
+                        },
+                        .init_arg_expr = undefined,
+                        .fields_and_decls = ArrayList(&ast.Node).init(arena),
+                        .rbrace_token = undefined,
+                    };
+
+                    try stack.append(State { .Operand = &node.base });
+                    try stack.append(State.AfterOperand);
+                    try stack.append(State { .ContainerDecl = node });
+                    try stack.append(State { .ExpectToken = Token.Id.LBrace });
+
+                    const lparen = self.getNextToken();
+                    if (lparen.id != Token.Id.LParen) {
+                        self.putBackToken(lparen);
+                        node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
+                        continue;
+                    }
+
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+
+                    const init_arg_token = self.getNextToken();
+                    switch (init_arg_token.id) {
+                        Token.Id.Keyword_enum => {
+                            node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
+                        },
+                        else => {
+                            self.putBackToken(init_arg_token);
+                            node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
+                            try stack.append(State {
+                                .Expression = DestPtr {
+                                    .Field = &node.init_arg_expr.Type
+                                }
+                            });
+                        },
+                    }
+                    continue;
+                },
+
                 State.ContainerDecl => |container_decl| {
                     const token = self.getNextToken();
 
@@ -633,52 +696,30 @@ pub const Parser = struct {
                             try stack.append(State.AfterOperand);
                             continue;
                         },
-                        Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
-                            const node = try arena.create(ast.NodeContainerDecl);
-                            *node = ast.NodeContainerDecl {
-                                .base = self.initNode(ast.Node.Id.ContainerDecl),
-                                .kind_token = token,
-                                .kind = switch (token.id) {
-                                    Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
-                                    Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
-                                    Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
-                                    else => unreachable,
+                        Token.Id.Keyword_packed => {
+                            try stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Packed,
                                 },
-                                .init_arg_expr = undefined,
-                                .fields_and_decls = ArrayList(&ast.Node).init(arena),
-                                .rbrace_token = undefined,
-                            };
-
-                            try stack.append(State { .Operand = &node.base });
-                            try stack.append(State.AfterOperand);
-                            try stack.append(State { .ContainerDecl = node });
-                            try stack.append(State { .ExpectToken = Token.Id.LBrace });
-
-                            const lparen = self.getNextToken();
-                            if (lparen.id != Token.Id.LParen) {
-                                self.putBackToken(lparen);
-                                node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
-                                continue;
-                            }
-
-                            try stack.append(State { .ExpectToken = Token.Id.RParen });
-
-                            const init_arg_token = self.getNextToken();
-                            switch (init_arg_token.id) {
-                                Token.Id.Keyword_enum => {
-                                    node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
+                            });
+                        },
+                        Token.Id.Keyword_extern => {
+                            try stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Extern,
                                 },
-                                else => {
-                                    self.putBackToken(lparen);
-                                    node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
-                                    try stack.append(State {
-                                        .Expression = DestPtr {
-                                            .Field = &node.init_arg_expr.Type
-                                        }
-                                    });
+                            });
+                        },
+                        Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
+                            self.putBackToken(token);
+                            try stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Auto,
                                 },
-                            }
-                            continue;
+                            });
                         },
                         Token.Id.Builtin => {
                             const node = try arena.create(ast.NodeBuiltinCall);
@@ -1706,6 +1747,29 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Text = " " });
                             try stack.append(RenderState { .Expression = test_decl.name });
                         },
+                        ast.Node.Id.StructField => {
+                            const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
+                            try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
+                            try stack.append(RenderState { .Expression = field.type_expr});
+                        },
+                        ast.Node.Id.UnionTag => {
+                            const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
+                            try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
+
+                            if (tag.type_expr) |type_expr| {
+                                try stream.print(": ");
+                                try stack.append(RenderState { .Expression = type_expr});
+                            }
+                        },
+                        ast.Node.Id.EnumTag => {
+                            const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
+                            try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
+
+                            if (tag.value) |value| {
+                                try stream.print(" = ");
+                                try stack.append(RenderState { .Expression = value});
+                            }
+                        },
                         else => unreachable,
                     }
                 },
@@ -1990,27 +2054,30 @@ pub const Parser = struct {
                     },
                     ast.Node.Id.ContainerDecl => {
                         const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
-                        try stream.print("{} {{", self.tokenizer.getTokenSlice(container_decl.kind_token));
+
+                        switch (container_decl.layout) {
+                            ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
+                            ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
+                            ast.NodeContainerDecl.Layout.Auto => { },
+                        }
+
+                        switch (container_decl.kind) {
+                            ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
+                            ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
+                            ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
+                        }
+
                         try stack.append(RenderState { .Text = "}"});
                         try stack.append(RenderState.PrintIndent);
                         try stack.append(RenderState { .Indent = indent });
+                        try stack.append(RenderState { .Text = "\n"});
 
                         const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
                         var i = fields_and_decls.len;
                         while (i != 0) {
                             i -= 1;
                             const node = fields_and_decls[i];
-                            if (i != 0) {
-                                switch (node.id) {
-                                    ast.Node.Id.StructField,
-                                    ast.Node.Id.UnionTag,
-                                    ast.Node.Id.EnumTag => {
-                                        try stack.append(RenderState { .Text = "," });
-                                    },
-                                    else => { }
-                                }
-                            }
-                            try stack.append(RenderState { .Expression = node});
+                            try stack.append(RenderState { .TopLevelDecl = node});
                             try stack.append(RenderState.PrintIndent);
                             try stack.append(RenderState {
                                 .Text = blk: {
@@ -2025,22 +2092,43 @@ pub const Parser = struct {
                                     break :blk "\n";
                                 },
                             });
+
+                            if (i != 0) {
+                                const prev_node = fields_and_decls[i - 1];
+                                switch (prev_node.id) {
+                                    ast.Node.Id.StructField,
+                                    ast.Node.Id.UnionTag,
+                                    ast.Node.Id.EnumTag => {
+                                        try stack.append(RenderState { .Text = "," });
+                                    },
+                                    else => { }
+                                }
+                            }
                         }
                         try stack.append(RenderState { .Indent = indent + indent_delta});
+                        try stack.append(RenderState { .Text = "{"});
+
+                        switch (container_decl.init_arg_expr) {
+                            ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
+                            ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
+                            ast.NodeContainerDecl.InitArg.Type => |type_expr| {
+                                try stack.append(RenderState { .Text = ") "});
+                                try stack.append(RenderState { .Expression = type_expr});
+                                try stack.append(RenderState { .Text = "("});
+                            },
+                        }
                     },
                     ast.Node.Id.MultilineStringLiteral => {
                         const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
                         try stream.print("\n");
 
                         var i : usize = 0;
-                        indent += 4;
                         while (i < multiline_str_literal.tokens.len) : (i += 1) {
                             const t = multiline_str_literal.tokens.at(i);
-                            try stream.writeByteNTimes(' ', indent);
+                            try stream.writeByteNTimes(' ', indent + indent_delta);
                             try stream.print("{}", self.tokenizer.getTokenSlice(t));
                         }
-                        try stream.writeByteNTimes(' ', indent);
-                        indent -= 4;
+                        try stream.writeByteNTimes(' ', indent + indent_delta);
                     },
                     ast.Node.Id.UndefinedLiteral => {
                         const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
@@ -2060,31 +2148,12 @@ pub const Parser = struct {
                             }
                         }
                     },
-                    ast.Node.Id.StructField => {
-                        const field = @fieldParentPtr(ast.NodeStructField, "base", base);
-                        try stream.print("{}:", self.tokenizer.getTokenSlice(field.name_token));
-                    },
-                    ast.Node.Id.UnionTag => {
-                        const tag = @fieldParentPtr(ast.NodeUnionTag, "base", base);
-                        try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
-
-                        if (tag.type_expr) |type_expr| {
-                            try stream.print(": ");
-                            try stack.append(RenderState { .Expression = type_expr});
-                        }
-                    },
-                    ast.Node.Id.EnumTag => {
-                        const tag = @fieldParentPtr(ast.NodeEnumTag, "base", base);
-                        try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
-
-                        if (tag.value) |value| {
-                            try stream.print(" = ");
-                            try stack.append(RenderState { .Expression = value});
-                        }
-                    },
                     ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
                     ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
 
+                    ast.Node.Id.StructField,
+                    ast.Node.Id.UnionTag,
+                    ast.Node.Id.EnumTag,
                     ast.Node.Id.Root,
                     ast.Node.Id.VarDecl,
                     ast.Node.Id.TestDecl,
@@ -2489,21 +2558,21 @@ test "zig fmt: struct declaration" {
         \\        return *self;
         \\    }
         \\
-        \\    f2: u8,
+        \\    f2: u8
         \\};
         \\
         \\const Ps = packed struct {
         \\    a: u8,
         \\    b: u8,
         \\
-        \\    c: u8,
+        \\    c: u8
         \\};
         \\
         \\const Es = extern struct {
         \\    a: u8,
         \\    b: u8,
         \\
-        \\    c: u8,
+        \\    c: u8
         \\};
         \\
     );
@@ -2513,25 +2582,25 @@ test "zig fmt: enum declaration" {
       try testCanonical(
         \\const E = enum {
         \\    Ok,
-        \\    SomethingElse = 0,
+        \\    SomethingElse = 0
         \\};
         \\
         \\const E2 = enum(u8) {
         \\    Ok,
         \\    SomethingElse = 255,
-        \\    SomethingThird,
+        \\    SomethingThird
         \\};
         \\
         \\const Ee = extern enum {
         \\    Ok,
         \\    SomethingElse,
-        \\    SomethingThird,
+        \\    SomethingThird
         \\};
         \\
         \\const Ep = packed enum {
         \\    Ok,
         \\    SomethingElse,
-        \\    SomethingThird,
+        \\    SomethingThird
         \\};
         \\
     );
@@ -2542,31 +2611,36 @@ test "zig fmt: union declaration" {
         \\const U = union {
         \\    Int: u8,
         \\    Float: f32,
-        \\    Bool: bool,
+        \\    None,
+        \\    Bool: bool
         \\};
         \\
         \\const Ue = union(enum) {
         \\    Int: u8,
         \\    Float: f32,
-        \\    Bool: bool,
+        \\    None,
+        \\    Bool: bool
         \\};
         \\
         \\const E = enum {
         \\    Int,
         \\    Float,
-        \\    Bool,
+        \\    None,
+        \\    Bool
         \\};
         \\
         \\const Ue2 = union(E) {
         \\    Int: u8,
         \\    Float: f32,
-        \\    Bool: bool,
+        \\    None,
+        \\    Bool: bool
         \\};
         \\
         \\const Eu = extern union {
         \\    Int: u8,
         \\    Float: f32,
-        \\    Bool: bool,
+        \\    None,
+        \\    Bool: bool
         \\};
         \\
     );