2019-12-23 14:05:34 +00:00
|
|
|
package compiler_test
|
2019-12-19 07:48:06 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"math/big"
|
2020-08-24 08:58:29 +00:00
|
|
|
"strings"
|
2019-12-19 07:48:06 +00:00
|
|
|
"testing"
|
2020-03-26 12:29:49 +00:00
|
|
|
|
2020-08-24 08:58:29 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
2020-06-03 12:55:06 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2020-08-24 08:58:29 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-12-19 07:48:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var sliceTestCases = []testCase{
|
|
|
|
{
|
|
|
|
"constant index",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
a := []int{0,0}
|
|
|
|
a[1] = 42
|
|
|
|
return a[1]+0
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"variable index",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
a := []int{0,0}
|
|
|
|
i := 1
|
|
|
|
a[i] = 42
|
|
|
|
return a[1]+0
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
2020-05-18 08:45:20 +00:00
|
|
|
{
|
|
|
|
"increase slice element with +=",
|
|
|
|
`package foo
|
|
|
|
func Main() int {
|
|
|
|
a := []int{1, 2, 3}
|
|
|
|
a[1] += 40
|
|
|
|
return a[1]
|
|
|
|
}`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
2019-12-19 07:48:06 +00:00
|
|
|
{
|
|
|
|
"complex test",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
a := []int{1,2,3}
|
|
|
|
x := a[0]
|
|
|
|
a[x] = a[x] + 4
|
|
|
|
a[x] = a[x] + a[2]
|
|
|
|
return a[1]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(9),
|
|
|
|
},
|
2020-01-23 12:42:50 +00:00
|
|
|
{
|
|
|
|
"slice literals with variables",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
elem := 7
|
|
|
|
a := []int{6, elem, 8}
|
|
|
|
return a[1]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(7),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"slice literals with expressions",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
elem := []int{3, 7}
|
|
|
|
a := []int{6, elem[1]*2+1, 24}
|
|
|
|
return a[1]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(15),
|
|
|
|
},
|
2020-02-10 15:14:34 +00:00
|
|
|
{
|
|
|
|
"sub-slice with literal bounds",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2, 3}
|
|
|
|
b := a[1:3]
|
|
|
|
return b
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sub-slice with constant bounds",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
const x = 1
|
|
|
|
const y = 3
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2, 3}
|
|
|
|
b := a[x:y]
|
|
|
|
return b
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sub-slice with variable bounds",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2, 3}
|
|
|
|
x := 1
|
|
|
|
y := 3
|
|
|
|
b := a[x:y]
|
|
|
|
return b
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sub-slice with no lower bound",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2, 3}
|
|
|
|
b := a[:3]
|
|
|
|
return b
|
|
|
|
}`,
|
|
|
|
[]byte{0, 1, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sub-slice with no upper bound",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2, 3}
|
|
|
|
b := a[2:]
|
|
|
|
return b
|
|
|
|
}`,
|
|
|
|
[]byte{2, 3},
|
|
|
|
},
|
2020-05-19 14:02:26 +00:00
|
|
|
{
|
|
|
|
"declare byte slice",
|
|
|
|
`package foo
|
|
|
|
func Main() []byte {
|
|
|
|
var a []byte
|
|
|
|
a = append(a, 1)
|
|
|
|
a = append(a, 2)
|
|
|
|
return a
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
2020-07-09 10:51:49 +00:00
|
|
|
{
|
|
|
|
"append multiple bytes to a slice",
|
|
|
|
`package foo
|
|
|
|
func Main() []byte {
|
|
|
|
var a []byte
|
|
|
|
a = append(a, 1, 2)
|
|
|
|
return a
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"append multiple ints to a slice",
|
|
|
|
`package foo
|
|
|
|
func Main() []int {
|
|
|
|
var a []int
|
|
|
|
a = append(a, 1, 2, 3)
|
|
|
|
a = append(a, 4, 5)
|
|
|
|
return a
|
|
|
|
}`,
|
|
|
|
[]stackitem.Item{
|
|
|
|
stackitem.NewBigInteger(big.NewInt(1)),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(2)),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(3)),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(4)),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(5)),
|
|
|
|
},
|
|
|
|
},
|
2020-03-26 12:29:49 +00:00
|
|
|
{
|
|
|
|
"declare compound slice",
|
|
|
|
`package foo
|
|
|
|
func Main() []string {
|
|
|
|
var a []string
|
|
|
|
a = append(a, "a")
|
|
|
|
a = append(a, "b")
|
|
|
|
return a
|
|
|
|
}`,
|
2020-06-03 12:55:06 +00:00
|
|
|
[]stackitem.Item{
|
|
|
|
stackitem.NewByteArray([]byte("a")),
|
|
|
|
stackitem.NewByteArray([]byte("b")),
|
2020-03-26 12:29:49 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"declare compound slice alias",
|
|
|
|
`package foo
|
|
|
|
type strs []string
|
|
|
|
func Main() []string {
|
|
|
|
var a strs
|
|
|
|
a = append(a, "a")
|
|
|
|
a = append(a, "b")
|
|
|
|
return a
|
|
|
|
}`,
|
2020-06-03 12:55:06 +00:00
|
|
|
[]stackitem.Item{
|
|
|
|
stackitem.NewByteArray([]byte("a")),
|
|
|
|
stackitem.NewByteArray([]byte("b")),
|
2020-03-26 12:29:49 +00:00
|
|
|
},
|
|
|
|
},
|
2020-05-13 08:06:12 +00:00
|
|
|
{
|
|
|
|
"byte-slice assignment",
|
|
|
|
`package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := []byte{0, 1, 2}
|
|
|
|
a[1] = 42
|
|
|
|
return a
|
|
|
|
}`,
|
|
|
|
[]byte{0, 42, 2},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"byte-slice assignment after string conversion",
|
|
|
|
`package foo
|
|
|
|
func Main() []byte {
|
|
|
|
a := "abc"
|
|
|
|
b := []byte(a)
|
|
|
|
b[1] = 42
|
|
|
|
return []byte(a)
|
|
|
|
}`,
|
|
|
|
[]byte{0x61, 0x62, 0x63},
|
|
|
|
},
|
2020-05-13 10:24:49 +00:00
|
|
|
{
|
|
|
|
"declare and append byte-slice",
|
|
|
|
`package foo
|
|
|
|
func Main() []byte {
|
|
|
|
var a []byte
|
|
|
|
a = append(a, 1)
|
|
|
|
a = append(a, 2)
|
|
|
|
return a
|
|
|
|
}`,
|
|
|
|
[]byte{1, 2},
|
|
|
|
},
|
2020-05-20 14:53:01 +00:00
|
|
|
{
|
|
|
|
"nested slice assignment",
|
|
|
|
`package foo
|
|
|
|
func Main() int {
|
|
|
|
a := [][]int{[]int{1, 2}, []int{3, 4}}
|
|
|
|
a[1][0] = 42
|
|
|
|
return a[1][0]
|
|
|
|
}`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
2020-06-24 16:25:08 +00:00
|
|
|
{
|
|
|
|
"nested slice omitted type (slice)",
|
|
|
|
`package foo
|
|
|
|
func Main() int {
|
|
|
|
a := [][]int{{1, 2}, {3, 4}}
|
|
|
|
a[1][0] = 42
|
|
|
|
return a[1][0]
|
|
|
|
}`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"nested slice omitted type (struct)",
|
|
|
|
`package foo
|
|
|
|
type pair struct { a, b int }
|
|
|
|
func Main() int {
|
|
|
|
a := []pair{{a: 1, b: 2}, {a: 3, b: 4}}
|
|
|
|
a[1].a = 42
|
|
|
|
return a[1].a
|
|
|
|
}`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
2020-07-09 10:06:49 +00:00
|
|
|
{
|
|
|
|
"defaults to nil for byte slice",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
var a []byte
|
|
|
|
if a != nil { return 1}
|
|
|
|
return 2
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"defaults to nil for int slice",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
var a []int
|
|
|
|
if a != nil { return 1}
|
|
|
|
return 2
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"defaults to nil for struct slice",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type pair struct { a, b int }
|
|
|
|
func Main() int {
|
|
|
|
var a []pair
|
|
|
|
if a != nil { return 1}
|
|
|
|
return 2
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
2020-09-24 17:20:34 +00:00
|
|
|
{
|
|
|
|
"literal byte-slice with variable values",
|
|
|
|
`package foo
|
|
|
|
const sym1 = 's'
|
|
|
|
func Main() []byte {
|
|
|
|
sym2 := byte('t')
|
|
|
|
sym4 := byte('i')
|
|
|
|
return []byte{sym1, sym2, 'r', sym4, 'n', 'g'}
|
|
|
|
}`,
|
|
|
|
[]byte("string"),
|
|
|
|
},
|
2020-09-24 17:29:52 +00:00
|
|
|
{
|
|
|
|
"literal slice with function call",
|
|
|
|
`package foo
|
|
|
|
func fn() byte { return 't' }
|
|
|
|
func Main() []byte {
|
|
|
|
return []byte{'s', fn(), 'r'}
|
|
|
|
}`,
|
|
|
|
[]byte("str"),
|
|
|
|
},
|
2019-12-19 07:48:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSliceOperations(t *testing.T) {
|
|
|
|
runTestCases(t, sliceTestCases)
|
|
|
|
}
|
2020-02-03 09:10:07 +00:00
|
|
|
|
2020-09-15 06:52:56 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-09-15 07:05:41 +00:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-03 09:10:07 +00:00
|
|
|
func TestJumps(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
|
|
|
func Main() []byte {
|
|
|
|
buf := []byte{0x62, 0x01, 0x00}
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, []byte{0x62, 0x01, 0x00})
|
|
|
|
}
|
2020-08-24 08:58:29 +00:00
|
|
|
|
|
|
|
func TestMake(t *testing.T) {
|
|
|
|
t.Run("Map", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
a := make(map[int]int)
|
|
|
|
a[1] = 10
|
|
|
|
a[2] = 20
|
|
|
|
return a[1]
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(10))
|
|
|
|
})
|
|
|
|
t.Run("IntSlice", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
a := make([]int, 10)
|
|
|
|
return len(a) + a[0]
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(10))
|
|
|
|
})
|
|
|
|
t.Run("ByteSlice", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
a := make([]byte, 10)
|
|
|
|
return len(a) + int(a[0])
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(10))
|
|
|
|
})
|
|
|
|
t.Run("CapacityError", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
a := make([]int, 1, 2)
|
|
|
|
return a[0]
|
|
|
|
}`
|
|
|
|
_, err := compiler.Compile("foo.go", strings.NewReader(src))
|
|
|
|
require.Error(t, err)
|
|
|
|
})
|
|
|
|
}
|
2020-08-24 09:54:01 +00:00
|
|
|
|
|
|
|
func TestCopy(t *testing.T) {
|
|
|
|
t.Run("Invalid", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []int {
|
|
|
|
src := []int{3, 2, 1}
|
|
|
|
dst := make([]int, 2)
|
|
|
|
copy(dst, src)
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
_, err := compiler.Compile("foo.go", strings.NewReader(src))
|
|
|
|
require.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("Simple", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []byte {
|
|
|
|
src := []byte{3, 2, 1}
|
|
|
|
dst := make([]byte, 2)
|
|
|
|
copy(dst, src)
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
eval(t, src, []byte{3, 2})
|
|
|
|
})
|
|
|
|
t.Run("LowSrcIndex", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []byte {
|
|
|
|
src := []byte{3, 2, 1}
|
|
|
|
dst := make([]byte, 2)
|
|
|
|
copy(dst, src[1:])
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
eval(t, src, []byte{2, 1})
|
|
|
|
})
|
|
|
|
t.Run("LowDstIndex", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []byte {
|
|
|
|
src := []byte{3, 2, 1}
|
|
|
|
dst := make([]byte, 2)
|
|
|
|
copy(dst[1:], src[1:])
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
eval(t, src, []byte{0, 2})
|
|
|
|
})
|
|
|
|
t.Run("BothIndices", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []byte {
|
|
|
|
src := []byte{4, 3, 2, 1}
|
|
|
|
dst := make([]byte, 4)
|
|
|
|
copy(dst[1:], src[1:3])
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
eval(t, src, []byte{0, 3, 2, 0})
|
|
|
|
})
|
|
|
|
t.Run("EmptySliceExpr", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() []byte {
|
|
|
|
src := []byte{3, 2, 1}
|
|
|
|
dst := make([]byte, 2)
|
|
|
|
copy(dst[1:], src[:])
|
|
|
|
return dst
|
|
|
|
}`
|
|
|
|
eval(t, src, []byte{0, 3})
|
|
|
|
})
|
2020-09-02 12:29:59 +00:00
|
|
|
t.Run("AssignToVariable", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
src := []byte{3, 2, 1}
|
|
|
|
dst := make([]byte, 2)
|
|
|
|
n := copy(dst, src)
|
|
|
|
return n
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(2))
|
|
|
|
})
|
2020-08-24 09:54:01 +00:00
|
|
|
}
|