Commit a09bb408a2

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-09 15:40:16
std.zig.parser now parses asm expressions * We cannot render asm expressions yet
1 parent aa55263
Changed files (2)
std/zig/ast.zig
@@ -47,6 +47,7 @@ pub const Node = struct {
         NullLiteral,
         UndefinedLiteral,
         ThisLiteral,
+        Asm,
         Unreachable,
         ErrorType,
         BuiltinCall,
@@ -94,6 +95,7 @@ pub const Node = struct {
             Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).iterate(index),
             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.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
@@ -143,6 +145,7 @@ pub const Node = struct {
             Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
             Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(),
             Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(),
+            Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
             Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
@@ -190,6 +193,7 @@ pub const Node = struct {
             Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).lastToken(),
             Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
             Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(),
+            Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(),
             Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(),
             Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(),
             Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
@@ -1512,6 +1516,43 @@ pub const NodeThisLiteral = struct {
     }
 };
 
+pub const NodeAsm = struct {
+    base: Node,
+    asm_token: Token,
+    is_volatile: bool,
+    template: Token,
+    //tokens: ArrayList(AsmToken),
+    outputs: ArrayList(AsmOutput),
+    inputs: ArrayList(AsmInput),
+    cloppers: ArrayList(&NodeStringLiteral),
+    rparen: Token,
+
+    const AsmOutput = struct {
+        symbolic_name: Token,
+        constraint: Token,
+        variable_name: ?Token,
+        return_type: ?&Node,
+    };
+
+    const AsmInput = struct {
+        symbolic_name: Token,
+        constraint: Token,
+        expr: &Node,
+    };
+
+    pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
+        return null;
+    }
+
+    pub fn firstToken(self: &NodeAsm) Token {
+        return self.asm_token;
+    }
+
+    pub fn lastToken(self: &NodeAsm) Token {
+        return self.rparen;
+    }
+};
+
 pub const NodeUnreachable = struct {
     base: Node,
     token: Token,
std/zig/parser.zig
@@ -164,6 +164,9 @@ 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),
+        AsmClopperItems: &ArrayList(&ast.NodeStringLiteral),
         ExprListItemOrEnd: ExprListCtx,
         ExprListCommaOrEnd: ExprListCtx,
         FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
@@ -1488,7 +1491,44 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_asm => {
-                            @panic("TODO: inline asm");
+                            const is_volatile = blk: {
+                                const volatile_token = self.getNextToken();
+                                if (volatile_token.id != Token.Id.Keyword_volatile) {
+                                    self.putBackToken(volatile_token);
+                                    break :blk false;
+                                }
+                                break :blk true;
+                            };
+                            _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
+                            const template = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
+                            // TODO parse template
+
+                            const node = try arena.create(ast.NodeAsm);
+                            *node = ast.NodeAsm {
+                                .base = self.initNode(ast.Node.Id.Asm),
+                                .asm_token = token,
+                                .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),
+                                .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena),
+                                .rparen = undefined,
+                            };
+                            dest_ptr.store(&node.base);
+
+                            stack.append(State {
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.RParen,
+                                    .ptr = &node.rparen,
+                                }
+                            }) catch unreachable;
+                            try stack.append(State { .AsmClopperItems = &node.cloppers });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
+                            try stack.append(State { .AsmInputItems = &node.inputs });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
+                            try stack.append(State { .AsmOutputItems = &node.outputs });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
                         },
                         Token.Id.Keyword_if => {
                             const node = try arena.create(ast.NodeIf);
@@ -1621,6 +1661,84 @@ pub const Parser = struct {
                     }
                 },
 
+
+                State.AsmOutputItems => |items| {
+                    const lbracket = self.getNextToken();
+                    if (lbracket.id != Token.Id.LBracket) {
+                        self.putBackToken(lbracket);
+                        continue;
+                    }
+
+                    stack.append(State { .AsmOutputItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+
+                    const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                    _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
+                    const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
+
+                    _ = (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 symbol_or_arrow = self.getNextToken();
+                    switch (symbol_or_arrow.id) {
+                        Token.Id.Identifier => res.variable_name = symbol_or_arrow,
+                        Token.Id.Arrow => {
+                            try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &res.return_type } });
+                        },
+                        else => {
+                            try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
+                                @tagName(Token.Id.Identifier),
+                                @tagName(symbol_or_arrow.id));
+                            continue;
+                        },
+                    }
+                },
+
+                State.AsmInputItems => |items| {
+                    const lbracket = self.getNextToken();
+                    if (lbracket.id != Token.Id.LBracket) {
+                        self.putBackToken(lbracket);
+                        continue;
+                    }
+
+                    stack.append(State { .AsmInputItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+
+                    const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
+                    _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
+                    const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
+
+                    _ = (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,
+                        .expr = undefined,
+                    };
+                    try stack.append(State { .Expression = DestPtr { .Field = &res.expr } });
+                },
+
+                State.AsmClopperItems => |items| {
+                    const string = self.getNextToken();
+                    if (string.id != Token.Id.StringLiteral) {
+                        self.putBackToken(string);
+                        continue;
+                    }
+
+                    try items.append(try self.createStringLiteral(arena, string));
+                    stack.append(State { .AsmClopperItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+                },
+
                 State.ExprListItemOrEnd => |list_state| {
                     var token = self.getNextToken();
 
@@ -3675,6 +3793,24 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Expression = if_node.condition });
                         try stack.append(RenderState { .Text = "(" });
                     },
+                    ast.Node.Id.Asm => {
+                        const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
+                        try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
+
+                        if (asm_node.is_volatile) {
+                            try stream.write("volatile ");
+                        }
+
+                        try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template));
+
+                        try stack.append(RenderState { .Text = ")" });
+                        @panic("TODO: Render asm");
+                        //\\    return asm volatile ("syscall"
+                        //\\        : [ret] "={rax}" (-> usize)
+                        //\\        : [number] "{rax}" (number),
+                        //\\            [arg1] "{rdi}" (arg1)
+                        //\\        : "rcx", "r11");
+                    },,
 
                     ast.Node.Id.StructField,
                     ast.Node.Id.UnionTag,