compiler: support CONVERT interops

When result is needed to have certain type, we should have ability
to convert it, with the help of CONVERT opcode.
This commit is contained in:
Evgenii Stratonikov 2020-04-28 15:46:03 +03:00
parent bfcb1a409f
commit 2fd63387c0
4 changed files with 89 additions and 0 deletions

View file

@ -17,6 +17,7 @@ var (
"AppCall", "AppCall",
"FromAddress", "Equals", "FromAddress", "Equals",
"panic", "panic",
"ToBool", "ToByteArray", "ToInteger",
} }
) )

View file

@ -1055,6 +1055,15 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
} else { } else {
c.prog.Err = errors.New("panic should have string or nil argument") c.prog.Err = errors.New("panic should have string or nil argument")
} }
case "ToInteger", "ToByteArray", "ToBool":
typ := vm.IntegerT
switch name {
case "ToByteArray":
typ = vm.ByteArrayT
case "ToBool":
typ = vm.BooleanT
}
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
case "SHA256": case "SHA256":
emit.Opcode(c.prog.BinWriter, opcode.SHA256) emit.Opcode(c.prog.BinWriter, opcode.SHA256)
case "SHA1": case "SHA1":

View file

@ -0,0 +1,62 @@
package compiler_test
import (
"fmt"
"math/big"
"testing"
)
type convertTestCase struct {
returnType string
argValue string
result interface{}
}
func getFunctionName(typ string) string {
switch typ {
case "bool":
return "Bool"
case "[]byte":
return "ByteArray"
case "int64":
return "Integer"
}
panic("invalid type")
}
func TestConvert(t *testing.T) {
srcTmpl := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/convert"
func Main() %s {
arg := %s
return convert.To%s(arg)
}`
convertTestCases := []convertTestCase{
{"bool", "true", true},
{"bool", "false", false},
{"bool", "12", true},
{"bool", "0", false},
{"bool", "[]byte{0, 1, 0}", true},
{"bool", "[]byte{0}", false},
{"int64", "true", big.NewInt(1)},
{"int64", "false", big.NewInt(0)},
{"int64", "12", big.NewInt(12)},
{"int64", "0", big.NewInt(0)},
{"int64", "[]byte{0, 1, 0}", big.NewInt(256)},
{"int64", "[]byte{0}", big.NewInt(0)},
{"[]byte", "true", []byte{1}},
{"[]byte", "false", []byte{}},
{"[]byte", "12", []byte{0x0C}},
{"[]byte", "0", []byte{}},
{"[]byte", "[]byte{0, 1, 0}", []byte{0, 1, 0}},
}
for _, tc := range convertTestCases {
name := getFunctionName(tc.returnType)
t.Run(tc.argValue+"->"+name, func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, tc.returnType, tc.argValue, name)
eval(t, src, tc.result)
})
}
}

View file

@ -0,0 +1,17 @@
// Package convert provides functions for type conversion.
package convert
// ToInteger converts it's argument to an Integer.
func ToInteger(v interface{}) int64 {
return 0
}
// ToByteArray converts it's argument to a ByteArray.
func ToByteArray(v interface{}) []byte {
return nil
}
// ToBool converts it's argument to a Boolean.
func ToBool(v interface{}) bool {
return false
}