mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 13:41:37 +00:00
compiler: refactor argument handling for builtins
It is more convenient to have all unusual logic in one place.
This commit is contained in:
parent
d2326a8b96
commit
b6629fb6bd
2 changed files with 32 additions and 31 deletions
|
@ -187,16 +187,6 @@ func isBuiltin(expr ast.Expr) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func isAppCall(expr ast.Expr) bool {
|
||||
t, ok := expr.(*ast.SelectorExpr)
|
||||
return ok && t.Sel.Name == "AppCall"
|
||||
}
|
||||
|
||||
func isFromAddress(expr ast.Expr) bool {
|
||||
t, ok := expr.(*ast.SelectorExpr)
|
||||
return ok && t.Sel.Name == "FromAddress"
|
||||
}
|
||||
|
||||
func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool {
|
||||
if len(lit.Elts) == 0 {
|
||||
return false
|
||||
|
|
|
@ -523,17 +523,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
return nil
|
||||
}
|
||||
|
||||
args := n.Args
|
||||
isAppCall := isAppCall(n.Fun)
|
||||
isFromAddress := isFromAddress(n.Fun)
|
||||
// There are 2 special cases:
|
||||
// 1. When using APPCALL, script hash is a part of the instruction so
|
||||
// script hash should be emitted after APPCALL.
|
||||
// 2. With FromAddress, parameter conversion is happening at compile-time
|
||||
// so there is no need to push parameters on stack and perform an actual call
|
||||
if isAppCall || isFromAddress {
|
||||
args = n.Args[1:]
|
||||
}
|
||||
args := transformArgs(n.Fun, n.Args)
|
||||
|
||||
// Handle the arguments
|
||||
for _, arg := range args {
|
||||
|
@ -560,16 +550,6 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// Use the ident to check, builtins are not in func scopes.
|
||||
// We can be sure builtins are of type *ast.Ident.
|
||||
c.convertBuiltin(n)
|
||||
|
||||
if isAppCall {
|
||||
buf := c.getByteArray(n.Args[0])
|
||||
if len(buf) != 20 {
|
||||
c.prog.Err = errors.New("invalid script hash")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.prog.WriteBytes(buf)
|
||||
}
|
||||
case isSyscall(f):
|
||||
c.convertSyscall(f.selector.Name, f.name)
|
||||
default:
|
||||
|
@ -776,6 +756,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
emitOpcode(c.prog.BinWriter, opcode.DROP)
|
||||
emitOpcode(c.prog.BinWriter, opcode.THROW)
|
||||
} else if isStringType(c.typeInfo.Types[arg].Type) {
|
||||
ast.Walk(c, arg)
|
||||
emitSyscall(c.prog.BinWriter, "Neo.Runtime.Log")
|
||||
emitOpcode(c.prog.BinWriter, opcode.THROW)
|
||||
} else {
|
||||
|
@ -793,6 +774,12 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
emitOpcode(c.prog.BinWriter, opcode.VERIFY)
|
||||
case "AppCall":
|
||||
emitOpcode(c.prog.BinWriter, opcode.APPCALL)
|
||||
buf := c.getByteArray(expr.Args[0])
|
||||
if len(buf) != 20 {
|
||||
c.prog.Err = errors.New("invalid script hash")
|
||||
}
|
||||
|
||||
c.prog.WriteBytes(buf)
|
||||
case "Equals":
|
||||
emitOpcode(c.prog.BinWriter, opcode.EQUAL)
|
||||
case "FromAddress":
|
||||
|
@ -811,6 +798,30 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
|
||||
// transformArgs returns a list of function arguments
|
||||
// which should be put on stack.
|
||||
// There are special cases for builtins:
|
||||
// 1. When using AppCall, script hash is a part of the instruction so
|
||||
// it should be emitted after APPCALL.
|
||||
// 2. With FromAddress, parameter conversion is happening at compile-time
|
||||
// so there is no need to push parameters on stack and perform an actual call
|
||||
// 3. With panic, generated code depends on if argument was nil or a string so
|
||||
// it should be handled accordingly.
|
||||
func transformArgs(fun ast.Expr, args []ast.Expr) []ast.Expr {
|
||||
switch f := fun.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
if f.Sel.Name == "AppCall" || f.Sel.Name == "FromAddress" {
|
||||
return args[1:]
|
||||
}
|
||||
case *ast.Ident:
|
||||
if f.Name == "panic" {
|
||||
return args[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func (c *codegen) convertByteArray(lit *ast.CompositeLit) {
|
||||
buf := make([]byte, len(lit.Elts))
|
||||
for i := 0; i < len(lit.Elts); i++ {
|
||||
|
|
Loading…
Reference in a new issue