std.zig.parser now parses asm expressions

* We cannot render asm expressions yet
master
Jimmi Holst Christensen 2018-04-09 15:40:16 +02:00
parent aa552633cc
commit a09bb408a2
2 changed files with 178 additions and 1 deletions

View File

@ -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,

View File

@ -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,