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:
parent
bfcb1a409f
commit
2fd63387c0
4 changed files with 89 additions and 0 deletions
|
@ -17,6 +17,7 @@ var (
|
||||||
"AppCall",
|
"AppCall",
|
||||||
"FromAddress", "Equals",
|
"FromAddress", "Equals",
|
||||||
"panic",
|
"panic",
|
||||||
|
"ToBool", "ToByteArray", "ToInteger",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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":
|
||||||
|
|
62
pkg/compiler/convert_test.go
Normal file
62
pkg/compiler/convert_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
17
pkg/interop/convert/convert.go
Normal file
17
pkg/interop/convert/convert.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue