Merge pull request #1401 from nspcc-dev/compiler/subslice

Support removing elements from slice.
This commit is contained in:
Roman Khimov 2020-09-15 18:42:08 +03:00 committed by GitHub
commit bfe3b3d05d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 1 deletions

View file

@ -32,6 +32,9 @@ pkg.go.dev](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/interop)
for full API documentation. In general it provides the same level of for full API documentation. In general it provides the same level of
functionality as Neo .net Framework library. functionality as Neo .net Framework library.
Compiler provides some helpful builtins in `util` and `convert` packages.
Refer to them for detailed documentation.
## Quick start ## Quick start
### Compiling ### Compiling

View file

@ -17,7 +17,7 @@ var (
goBuiltins = []string{"len", "append", "panic", "make", "copy", "recover", "delete"} goBuiltins = []string{"len", "append", "panic", "make", "copy", "recover", "delete"}
// Custom builtin utility functions. // Custom builtin utility functions.
customBuiltins = []string{ customBuiltins = []string{
"FromAddress", "Equals", "FromAddress", "Equals", "Remove",
"ToBool", "ToByteArray", "ToInteger", "ToBool", "ToByteArray", "ToInteger",
} }
) )

View file

@ -517,6 +517,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil return nil
case *ast.SliceExpr: case *ast.SliceExpr:
if isCompoundSlice(c.typeOf(n.X.(*ast.Ident)).Underlying()) {
c.prog.Err = errors.New("subslices are supported only for []byte")
return nil
}
name := n.X.(*ast.Ident).Name name := n.X.(*ast.Ident).Name
c.emitLoadVar("", name) c.emitLoadVar("", name)
@ -1538,6 +1542,12 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
typ = stackitem.BooleanT typ = stackitem.BooleanT
} }
c.emitConvert(typ) c.emitConvert(typ)
case "Remove":
if !isCompoundSlice(c.typeOf(expr.Args[0])) {
c.prog.Err = errors.New("`Remove` supports only non-byte slices")
return
}
emit.Opcode(c.prog.BinWriter, opcode.REMOVE)
case "Equals": case "Equals":
emit.Opcode(c.prog.BinWriter, opcode.EQUAL) emit.Opcode(c.prog.BinWriter, opcode.EQUAL)
case "FromAddress": case "FromAddress":

View file

@ -316,6 +316,41 @@ func TestSliceOperations(t *testing.T) {
runTestCases(t, sliceTestCases) runTestCases(t, sliceTestCases)
} }
func TestSubsliceCompound(t *testing.T) {
src := `package foo
func Main() []int {
a := []int{0, 1, 2, 3}
b := a[1:3]
return b
}`
_, err := compiler.Compile("", strings.NewReader(src))
require.Error(t, err)
}
func TestRemove(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
func Main() int {
a := []int{11, 22, 33}
util.Remove(a, 1)
return len(a) + a[0] + a[1]
}`
eval(t, src, big.NewInt(46))
})
t.Run("ByteSlice", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
func Main() int {
a := []byte{11, 22, 33}
util.Remove(a, 1)
return len(a)
}`
_, err := compiler.Compile("", strings.NewReader(src))
require.Error(t, err)
})
}
func TestJumps(t *testing.T) { func TestJumps(t *testing.T) {
src := ` src := `
package foo package foo

View file

@ -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 element with index i from slice.
// This is done in place and slice must have type other than `[]byte`.
func Remove(slice interface{}, i int) {
}