Commit 2c7996f400

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-10 09:27:11
std.zig.parser can now render asm expressions
1 parent a09bb40
Changed files (2)
std/zig/ast.zig
@@ -48,6 +48,8 @@ pub const Node = struct {
         UndefinedLiteral,
         ThisLiteral,
         Asm,
+        AsmInput,
+        AsmOutput,
         Unreachable,
         ErrorType,
         BuiltinCall,
@@ -96,6 +98,8 @@ pub const Node = struct {
             Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
             Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).iterate(index),
             Id.Asm => @fieldParentPtr(NodeAsm, "base", base).iterate(index),
+            Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).iterate(index),
+            Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).iterate(index),
             Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
@@ -146,6 +150,8 @@ pub const Node = struct {
             Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(),
             Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(),
             Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(),
+            Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).firstToken(),
+            Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).firstToken(),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
             Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
@@ -194,6 +200,8 @@ pub const Node = struct {
             Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
             Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(),
             Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(),
+            Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).lastToken(),
+            Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).lastToken(),
             Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
@@ -1516,31 +1524,105 @@ pub const NodeThisLiteral = struct {
     }
 };
 
+pub const NodeAsmOutput = struct {
+    base: Node,
+    symbolic_name: &NodeIdentifier,
+    constraint: &NodeStringLiteral,
+    kind: Kind,
+
+    const Kind = union(enum) {
+        Variable: &NodeIdentifier,
+        Return: &Node
+    };
+
+    pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return &self.symbolic_name.base;
+        i -= 1;
+
+        if (i < 1) return &self.constraint.base;
+        i -= 1;
+
+        switch (self.kind) {
+            Kind.Variable => |variable_name| {
+                if (i < 1) return &variable_name.base;
+                i -= 1;
+            },
+            Kind.Return => |return_type| {
+                if (i < 1) return return_type;
+                i -= 1;
+            }
+        }
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeAsmOutput) Token {
+        return self.symbolic_name.firstToken();
+    }
+
+    pub fn lastToken(self: &NodeAsmOutput) Token {
+        return switch (self.kind) {
+            Kind.Variable => |variable_name| variable_name.lastToken(),
+            Kind.Return => |return_type| return_type.lastToken(),
+        };
+    }
+};
+
+pub const NodeAsmInput = struct {
+    base: Node,
+    symbolic_name: &NodeIdentifier,
+    constraint: &NodeStringLiteral,
+    expr: &Node,
+
+    pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
+        var i = index;
+
+        if (i < 1) return &self.symbolic_name.base;
+        i -= 1;
+
+        if (i < 1) return &self.constraint.base;
+        i -= 1;
+
+        if (i < 1) return self.expr;
+        i -= 1;
+
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeAsmInput) Token {
+        return self.symbolic_name.firstToken();
+    }
+
+    pub fn lastToken(self: &NodeAsmInput) Token {
+        return self.expr.lastToken();
+    }
+};
+
 pub const NodeAsm = struct {
     base: Node,
     asm_token: Token,
     is_volatile: bool,
     template: Token,
     //tokens: ArrayList(AsmToken),
-    outputs: ArrayList(AsmOutput),
-    inputs: ArrayList(AsmInput),
+    outputs: ArrayList(&NodeAsmOutput),
+    inputs: ArrayList(&NodeAsmInput),
     cloppers: ArrayList(&NodeStringLiteral),
     rparen: Token,
 
-    const AsmOutput = struct {
-        symbolic_name: Token,
-        constraint: Token,
-        variable_name: ?Token,
-        return_type: ?&Node,
-    };
+    pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
+        var i = index;
 
-    const AsmInput = struct {
-        symbolic_name: Token,
-        constraint: Token,
-        expr: &Node,
-    };
+        if (i < self.outputs.len) return &self.outputs.at(index).base;
+        i -= self.outputs.len;
+
+        if (i < self.inputs.len) return &self.inputs.at(index).base;
+        i -= self.inputs.len;
+
+        if (i < self.cloppers.len) return &self.cloppers.at(index).base;
+        i -= self.cloppers.len;
 
-    pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
         return null;
     }
 
std/zig/parser.zig
@@ -164,8 +164,8 @@ pub const Parser = struct {
         WhileContinueExpr: &?&ast.Node,
         Statement: &ast.NodeBlock,
         Semicolon: &const &const ast.Node,
-        AsmOutputItems: &ArrayList(ast.NodeAsm.AsmOutput),
-        AsmInputItems: &ArrayList(ast.NodeAsm.AsmInput),
+        AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
+        AsmInputItems: &ArrayList(&ast.NodeAsmInput),
         AsmClopperItems: &ArrayList(&ast.NodeStringLiteral),
         ExprListItemOrEnd: ExprListCtx,
         ExprListCommaOrEnd: ExprListCtx,
@@ -1510,8 +1510,8 @@ pub const Parser = struct {
                                 .is_volatile = is_volatile,
                                 .template = template,
                                 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
-                                .outputs = ArrayList(ast.NodeAsm.AsmOutput).init(arena),
-                                .inputs = ArrayList(ast.NodeAsm.AsmInput).init(arena),
+                                .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
+                                .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
                                 .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena),
                                 .rparen = undefined,
                             };
@@ -1679,18 +1679,23 @@ pub const Parser = struct {
                     _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
                     try stack.append(State { .ExpectToken = Token.Id.RParen });
 
-                    const res = try items.addOne();
-                    *res = ast.NodeAsm.AsmOutput {
-                        .symbolic_name = symbolic_name,
-                        .constraint = constraint,
-                        .variable_name = null,
-                        .return_type = null,
+                    const node = try arena.create(ast.NodeAsmOutput);
+                    *node = ast.NodeAsmOutput {
+                        .base = self.initNode(ast.Node.Id.AsmOutput),
+                        .symbolic_name = try self.createIdentifier(arena, symbolic_name),
+                        .constraint = try self.createStringLiteral(arena, constraint),
+                        .kind = undefined,
                     };
+                    try items.append(node);
+
                     const symbol_or_arrow = self.getNextToken();
                     switch (symbol_or_arrow.id) {
-                        Token.Id.Identifier => res.variable_name = symbol_or_arrow,
+                        Token.Id.Identifier => {
+                            node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createIdentifier(arena, symbol_or_arrow) };
+                        },
                         Token.Id.Arrow => {
-                            try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &res.return_type } });
+                            node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
+                            try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
                         },
                         else => {
                             try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
@@ -1718,13 +1723,15 @@ pub const Parser = struct {
                     _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
                     try stack.append(State { .ExpectToken = Token.Id.RParen });
 
-                    const res = try items.addOne();
-                    *res = ast.NodeAsm.AsmInput {
-                        .symbolic_name = symbolic_name,
-                        .constraint = constraint,
+                    const node = try arena.create(ast.NodeAsmInput);
+                    *node = ast.NodeAsmInput {
+                        .base = self.initNode(ast.Node.Id.AsmInput),
+                        .symbolic_name = try self.createIdentifier(arena, symbolic_name),
+                        .constraint = try self.createStringLiteral(arena, constraint),
                         .expr = undefined,
                     };
-                    try stack.append(State { .Expression = DestPtr { .Field = &res.expr } });
+                    try items.append(node);
+                    try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
                 },
 
                 State.AsmClopperItems => |items| {
@@ -3803,14 +3810,113 @@ pub const Parser = struct {
 
                         try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template));
 
+                        try stack.append(RenderState { .Indent = indent });
                         try stack.append(RenderState { .Text = ")" });
-                        @panic("TODO: Render asm");
-                        //\\    return asm volatile ("syscall"
-                        //\\        : [ret] "={rax}" (-> usize)
-                        //\\        : [number] "{rax}" (number),
-                        //\\            [arg1] "{rdi}" (arg1)
-                        //\\        : "rcx", "r11");
-                    },,
+                        {
+                            const cloppers = asm_node.cloppers.toSliceConst();
+                            var i = cloppers.len;
+                            while (i != 0) {
+                                i -= 1;
+                                try stack.append(RenderState { .Expression = &cloppers[i].base });
+
+                                if (i != 0) {
+                                    try stack.append(RenderState { .Text = ", " });
+                                }
+                            }
+                        }
+                        try stack.append(RenderState { .Text = ": " });
+                        try stack.append(RenderState.PrintIndent);
+                        try stack.append(RenderState { .Indent = indent + indent_delta });
+                        try stack.append(RenderState { .Text = "\n" });
+                        {
+                            const inputs = asm_node.inputs.toSliceConst();
+                            var i = inputs.len;
+                            while (i != 0) {
+                                i -= 1;
+                                const node = inputs[i];
+                                try stack.append(RenderState { .Expression = &node.base});
+
+                                if (i != 0) {
+                                    try stack.append(RenderState.PrintIndent);
+                                    try stack.append(RenderState {
+                                        .Text = blk: {
+                                            const prev_node = inputs[i - 1];
+                                            const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
+                                            if (loc.line >= 2) {
+                                                break :blk "\n\n";
+                                            }
+                                            break :blk "\n";
+                                        },
+                                    });
+                                    try stack.append(RenderState { .Text = "," });
+                                }
+                            }
+                        }
+                        try stack.append(RenderState { .Indent = indent + indent_delta + 2});
+                        try stack.append(RenderState { .Text = ": "});
+                        try stack.append(RenderState.PrintIndent);
+                        try stack.append(RenderState { .Indent = indent + indent_delta});
+                        try stack.append(RenderState { .Text = "\n" });
+                        {
+                            const outputs = asm_node.outputs.toSliceConst();
+                            var i = outputs.len;
+                            while (i != 0) {
+                                i -= 1;
+                                const node = outputs[i];
+                                try stack.append(RenderState { .Expression = &node.base});
+
+                                if (i != 0) {
+                                    try stack.append(RenderState.PrintIndent);
+                                    try stack.append(RenderState {
+                                        .Text = blk: {
+                                            const prev_node = outputs[i - 1];
+                                            const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
+                                            if (loc.line >= 2) {
+                                                break :blk "\n\n";
+                                            }
+                                            break :blk "\n";
+                                        },
+                                    });
+                                    try stack.append(RenderState { .Text = "," });
+                                }
+                            }
+                        }
+                        try stack.append(RenderState { .Indent = indent + indent_delta + 2});
+                        try stack.append(RenderState { .Text = ": "});
+                        try stack.append(RenderState.PrintIndent);
+                        try stack.append(RenderState { .Indent = indent + indent_delta});
+                        try stack.append(RenderState { .Text = "\n" });
+                    },
+                    ast.Node.Id.AsmInput => {
+                        const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
+
+                        try stack.append(RenderState { .Text = ")"});
+                        try stack.append(RenderState { .Expression = asm_input.expr});
+                        try stack.append(RenderState { .Text = " ("});
+                        try stack.append(RenderState { .Expression = &asm_input.constraint.base});
+                        try stack.append(RenderState { .Text = "] "});
+                        try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
+                        try stack.append(RenderState { .Text = "["});
+                    },
+                    ast.Node.Id.AsmOutput => {
+                        const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
+
+                        try stack.append(RenderState { .Text = ")"});
+                        switch (asm_output.kind) {
+                            ast.NodeAsmOutput.Kind.Variable => |variable_name| {
+                                try stack.append(RenderState { .Expression = &variable_name.base});
+                            },
+                            ast.NodeAsmOutput.Kind.Return => |return_type| {
+                                try stack.append(RenderState { .Expression = return_type});
+                                try stack.append(RenderState { .Text = "-> "});
+                            },
+                        }
+                        try stack.append(RenderState { .Text = " ("});
+                        try stack.append(RenderState { .Expression = &asm_output.constraint.base});
+                        try stack.append(RenderState { .Text = "] "});
+                        try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
+                        try stack.append(RenderState { .Text = "["});
+                    },
 
                     ast.Node.Id.StructField,
                     ast.Node.Id.UnionTag,
@@ -4672,7 +4778,7 @@ test "zig fmt: inline asm" {
         \\    return asm volatile ("syscall"
         \\        : [ret] "={rax}" (-> usize)
         \\        : [number] "{rax}" (number),
-        \\            [arg1] "{rdi}" (arg1)
+        \\          [arg1] "{rdi}" (arg1)
         \\        : "rcx", "r11");
         \\}
         \\