forked from TrueCloudLab/neoneo-go
compiler: implement Remove builtin
Support removing items from collections via REMOVE opcode.
This commit is contained in:
parent
9a0d7d3254
commit
9f7f94a6fb
4 changed files with 70 additions and 0 deletions
|
@ -17,6 +17,7 @@ var (
|
||||||
"VerifySignature", "AppCall",
|
"VerifySignature", "AppCall",
|
||||||
"FromAddress", "Equals",
|
"FromAddress", "Equals",
|
||||||
"panic", "DynAppCall",
|
"panic", "DynAppCall",
|
||||||
|
"delete", "Remove",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1075,6 +1075,19 @@ 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 "delete", "Remove":
|
||||||
|
arg := expr.Args[0]
|
||||||
|
errNotSupported := errors.New("only maps and non-byte slices are supported in `Remove`")
|
||||||
|
switch typ := c.typeInfo.Types[arg].Type.Underlying().(type) {
|
||||||
|
case *types.Map:
|
||||||
|
case *types.Slice:
|
||||||
|
if isByte(typ.Elem()) {
|
||||||
|
c.prog.Err = errNotSupported
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
c.prog.Err = errNotSupported
|
||||||
|
}
|
||||||
|
emit.Opcode(c.prog.BinWriter, opcode.REMOVE)
|
||||||
case "SHA256":
|
case "SHA256":
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
||||||
case "SHA1":
|
case "SHA1":
|
||||||
|
|
|
@ -2,6 +2,7 @@ package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -13,6 +14,56 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestRemove(t *testing.T) {
|
||||||
|
srcTmpl := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||||
|
func Main() int {
|
||||||
|
a := %s
|
||||||
|
util.Remove(a, %d)
|
||||||
|
return len(a) * a[%d]
|
||||||
|
}`
|
||||||
|
testRemove := func(item string, key, index, result int64) func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
src := fmt.Sprintf(srcTmpl, item, key, index)
|
||||||
|
if result > 0 {
|
||||||
|
eval(t, src, big.NewInt(result))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := vmAndCompile(t, src)
|
||||||
|
require.Error(t, v.Run())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Run("Map", func(t *testing.T) {
|
||||||
|
item := "map[int]int{1: 2, 5: 7, 11: 13}"
|
||||||
|
t.Run("RemovedKey", testRemove(item, 5, 5, -1))
|
||||||
|
t.Run("AnotherKey", testRemove(item, 5, 11, 26))
|
||||||
|
})
|
||||||
|
t.Run("Slice", func(t *testing.T) {
|
||||||
|
item := "[]int{5, 7, 11, 13}"
|
||||||
|
t.Run("RemovedKey", testRemove(item, 2, 2, 39))
|
||||||
|
t.Run("AnotherKey", testRemove(item, 2, 1, 21))
|
||||||
|
t.Run("LastKey", testRemove(item, 2, 3, -1))
|
||||||
|
})
|
||||||
|
t.Run("Invalid", func(t *testing.T) {
|
||||||
|
srcTmpl := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||||
|
func Main() int {
|
||||||
|
util.Remove(%s, 2)
|
||||||
|
return 1
|
||||||
|
}`
|
||||||
|
t.Run("BasicType", func(t *testing.T) {
|
||||||
|
src := fmt.Sprintf(srcTmpl, "1")
|
||||||
|
_, err := compiler.Compile(strings.NewReader(src))
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("ByteSlice", func(t *testing.T) {
|
||||||
|
src := fmt.Sprintf(srcTmpl, "[]byte{1, 2}")
|
||||||
|
_, err := compiler.Compile(strings.NewReader(src))
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromAddress(t *testing.T) {
|
func TestFromAddress(t *testing.T) {
|
||||||
as1 := "Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz"
|
as1 := "Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz"
|
||||||
addr1, err := address.StringToUint160(as1)
|
addr1, err := address.StringToUint160(as1)
|
||||||
|
|
|
@ -17,3 +17,8 @@ func FromAddress(address string) []byte {
|
||||||
func Equals(a, b interface{}) bool {
|
func Equals(a, b interface{}) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove removes item with the specified key from slice or map.
|
||||||
|
// For maps it is similar to `delete`.
|
||||||
|
// For slices it performs mutable update as if slice was provided by pointer.
|
||||||
|
func Remove(sliceOrMap, key interface{}) {}
|
||||||
|
|
Loading…
Reference in a new issue