diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 2da819556c..d048f4ed43 100644 --- a/std/zig/ast.zig +++ b/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, diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 7bdff56b85..7f5427146a 100644 --- a/std/zig/parser.zig +++ b/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,