std.zig.parser can now render asm expressions

This commit is contained in:
Jimmi Holst Christensen 2018-04-10 09:27:11 +02:00
parent a09bb408a2
commit 2c7996f400
2 changed files with 228 additions and 40 deletions

View File

@ -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,
};
const AsmInput = struct {
symbolic_name: Token,
constraint: Token,
expr: &Node,
};
pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
var i = index;
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;
return null;
}

View File

@ -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");
\\}
\\