2019-12-23 14:05:34 +00:00
|
|
|
package compiler_test
|
2018-04-02 15:04:42 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"math/big"
|
2019-08-20 17:37:06 +00:00
|
|
|
"testing"
|
2018-04-02 15:04:42 +00:00
|
|
|
|
2020-06-03 12:55:06 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2018-04-02 15:04:42 +00:00
|
|
|
)
|
2018-02-19 09:24:28 +00:00
|
|
|
|
|
|
|
var structTestCases = []testCase{
|
|
|
|
{
|
|
|
|
"struct field assign",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
|
|
|
|
age := t.x
|
|
|
|
return age
|
|
|
|
}
|
2018-02-24 09:06:48 +00:00
|
|
|
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
2018-02-19 09:24:28 +00:00
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(2),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
2020-09-24 17:29:52 +00:00
|
|
|
{
|
|
|
|
"struct field from func result",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type S struct { x int }
|
|
|
|
func fn() int { return 2 }
|
|
|
|
func Main() int {
|
|
|
|
t := S{x: fn()}
|
|
|
|
return t.x
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
2018-02-19 09:24:28 +00:00
|
|
|
{
|
|
|
|
"struct field return",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
|
|
|
|
return t.x
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(2),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"struct field assign",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
t.x = 10
|
|
|
|
return t.x
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(10),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"complex struct",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
x := 10
|
|
|
|
|
|
|
|
t := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
|
|
|
|
y := x + t.x
|
|
|
|
|
|
|
|
return y
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(12),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
2020-02-11 08:10:51 +00:00
|
|
|
{
|
|
|
|
"initialize struct field from variable",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
x := 10
|
|
|
|
t := token {
|
|
|
|
x: x,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
y := t.x + t.y
|
|
|
|
return y
|
|
|
|
}`,
|
|
|
|
big.NewInt(14),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"assign a variable to a struct field",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
ten := 10
|
|
|
|
t := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
t.x = ten
|
|
|
|
y := t.y + t.x
|
|
|
|
return y
|
|
|
|
}`,
|
|
|
|
big.NewInt(14),
|
|
|
|
},
|
2020-05-18 08:45:20 +00:00
|
|
|
{
|
|
|
|
"increase struct field with +=",
|
|
|
|
`package foo
|
|
|
|
type token struct { x int }
|
|
|
|
func Main() int {
|
|
|
|
t := token{x: 2}
|
|
|
|
t.x += 3
|
|
|
|
return t.x
|
|
|
|
}`,
|
|
|
|
big.NewInt(5),
|
|
|
|
},
|
2020-02-11 08:10:51 +00:00
|
|
|
{
|
|
|
|
"assign a struct field to a struct field",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t1 := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
t2 := token {
|
|
|
|
x: 3,
|
|
|
|
y: 5,
|
|
|
|
}
|
|
|
|
t1.x = t2.y
|
|
|
|
y := t1.x + t2.x
|
|
|
|
return y
|
|
|
|
}`,
|
|
|
|
big.NewInt(8),
|
|
|
|
},
|
2018-02-19 09:24:28 +00:00
|
|
|
{
|
|
|
|
"initialize same struct twice",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t1 := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
t2 := token {
|
|
|
|
x: 2,
|
|
|
|
y: 4,
|
|
|
|
}
|
|
|
|
return t1.x + t2.y
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(6),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"struct methods",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
}
|
|
|
|
|
|
|
|
func(t token) getInteger() int {
|
|
|
|
return t.x
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 4,
|
|
|
|
}
|
|
|
|
someInt := t.getInteger()
|
|
|
|
return someInt
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(4),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"struct methods with arguments",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Also tests if x conflicts with t.x
|
|
|
|
func(t token) addIntegers(x int, y int) int {
|
|
|
|
return t.x + x + y
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 4,
|
|
|
|
}
|
|
|
|
someInt := t.addIntegers(2, 4)
|
|
|
|
return someInt
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(10),
|
2018-02-19 09:24:28 +00:00
|
|
|
},
|
2018-02-24 09:06:48 +00:00
|
|
|
{
|
|
|
|
"initialize struct partially",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
z string
|
|
|
|
b bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
t := token {
|
|
|
|
x: 4,
|
|
|
|
}
|
|
|
|
return t.y
|
|
|
|
}
|
|
|
|
`,
|
2020-05-20 13:31:10 +00:00
|
|
|
big.NewInt(0),
|
2018-02-24 09:06:48 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"test return struct from func",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
type token struct {
|
|
|
|
x int
|
|
|
|
y int
|
|
|
|
z string
|
|
|
|
b bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newToken() token {
|
|
|
|
return token{
|
|
|
|
x: 1,
|
|
|
|
y: 2,
|
|
|
|
z: "hello",
|
|
|
|
b: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() token {
|
|
|
|
return newToken()
|
|
|
|
}
|
|
|
|
`,
|
2020-06-03 12:55:06 +00:00
|
|
|
[]stackitem.Item{
|
|
|
|
stackitem.NewBigInteger(big.NewInt(1)),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(2)),
|
|
|
|
stackitem.NewByteArray([]byte("hello")),
|
|
|
|
stackitem.NewBool(false),
|
2018-04-02 15:04:42 +00:00
|
|
|
},
|
2018-02-24 09:06:48 +00:00
|
|
|
},
|
2018-02-27 09:04:24 +00:00
|
|
|
{
|
|
|
|
"pass struct as argument",
|
|
|
|
`
|
|
|
|
package foo
|
|
|
|
|
|
|
|
type Bar struct {
|
|
|
|
amount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func addToAmount(x int, bar Bar) int {
|
|
|
|
bar.amount = bar.amount + x
|
|
|
|
return bar.amount
|
|
|
|
}
|
|
|
|
|
|
|
|
func Main() int {
|
|
|
|
b := Bar{
|
|
|
|
amount: 10,
|
|
|
|
}
|
|
|
|
|
|
|
|
x := addToAmount(4, b)
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
`,
|
2018-04-02 15:04:42 +00:00
|
|
|
big.NewInt(14),
|
2018-02-27 09:04:24 +00:00
|
|
|
},
|
2020-03-26 12:35:15 +00:00
|
|
|
{
|
|
|
|
"declare struct literal",
|
|
|
|
`package foo
|
|
|
|
func Main() int {
|
|
|
|
var x struct {
|
|
|
|
a int
|
|
|
|
}
|
|
|
|
x.a = 2
|
|
|
|
return x.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"declare struct type",
|
|
|
|
`package foo
|
|
|
|
type withA struct {
|
|
|
|
a int
|
|
|
|
}
|
|
|
|
func Main() int {
|
|
|
|
var x withA
|
|
|
|
x.a = 2
|
|
|
|
return x.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
2020-05-20 08:05:01 +00:00
|
|
|
{
|
|
|
|
"nested selectors (simple read)",
|
|
|
|
`package foo
|
|
|
|
type S1 struct { x, y S2 }
|
|
|
|
type S2 struct { a, b int }
|
|
|
|
func Main() int {
|
|
|
|
var s1 S1
|
|
|
|
var s2 S2
|
|
|
|
s2.a = 3
|
|
|
|
s1.y = s2
|
|
|
|
return s1.y.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(3),
|
|
|
|
},
|
2020-05-20 08:08:59 +00:00
|
|
|
{
|
|
|
|
"nested selectors (simple write)",
|
|
|
|
`package foo
|
|
|
|
type S1 struct { x S2 }
|
|
|
|
type S2 struct { a int }
|
|
|
|
func Main() int {
|
|
|
|
s1 := S1{
|
|
|
|
x: S2 {
|
|
|
|
a: 3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
s1.x.a = 11
|
|
|
|
return s1.x.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(11),
|
|
|
|
},
|
2020-05-20 08:32:52 +00:00
|
|
|
{
|
|
|
|
"complex struct default value",
|
|
|
|
`package foo
|
|
|
|
type S1 struct { x S2 }
|
|
|
|
type S2 struct { y S3 }
|
|
|
|
type S3 struct { a int }
|
|
|
|
func Main() int {
|
|
|
|
var s1 S1
|
|
|
|
s1.x.y.a = 11
|
|
|
|
return s1.x.y.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(11),
|
|
|
|
},
|
2021-11-12 13:35:30 +00:00
|
|
|
{
|
|
|
|
"lengthy struct default value",
|
|
|
|
`package foo
|
|
|
|
type S struct { x int; y []byte; z bool }
|
|
|
|
func Main() int {
|
|
|
|
var s S
|
|
|
|
return s.x
|
|
|
|
}`,
|
|
|
|
big.NewInt(0),
|
|
|
|
},
|
2020-05-20 08:32:52 +00:00
|
|
|
{
|
|
|
|
"nested selectors (complex write)",
|
|
|
|
`package foo
|
|
|
|
type S1 struct { x S2 }
|
|
|
|
type S2 struct { y, z S3 }
|
|
|
|
type S3 struct { a int }
|
|
|
|
func Main() int {
|
|
|
|
var s1 S1
|
|
|
|
s1.x.y.a, s1.x.z.a = 11, 31
|
|
|
|
return s1.x.y.a + s1.x.z.a
|
|
|
|
}`,
|
|
|
|
big.NewInt(42),
|
|
|
|
},
|
2020-06-24 16:33:58 +00:00
|
|
|
{
|
|
|
|
"omit field names",
|
|
|
|
`package foo
|
|
|
|
type pair struct { a, b int }
|
|
|
|
func Main() int {
|
|
|
|
p := pair{1, 2}
|
|
|
|
x := p.a * 10
|
|
|
|
return x + p.b
|
|
|
|
}`,
|
|
|
|
big.NewInt(12),
|
|
|
|
},
|
2020-07-09 09:26:16 +00:00
|
|
|
{
|
|
|
|
"uninitialized struct fields",
|
|
|
|
`package foo
|
|
|
|
type Foo struct {
|
|
|
|
i int
|
|
|
|
m map[string]int
|
|
|
|
b []byte
|
|
|
|
a []int
|
|
|
|
s struct { ii int }
|
|
|
|
}
|
|
|
|
func NewFoo() Foo { return Foo{} }
|
|
|
|
func Main() int {
|
|
|
|
foo := NewFoo()
|
|
|
|
if foo.i != 0 { return 1 }
|
|
|
|
if len(foo.m) != 0 { return 1 }
|
|
|
|
if len(foo.b) != 0 { return 1 }
|
|
|
|
if len(foo.a) != 0 { return 1 }
|
|
|
|
s := foo.s
|
|
|
|
if s.ii != 0 { return 1 }
|
|
|
|
return 2
|
|
|
|
}`,
|
|
|
|
big.NewInt(2),
|
|
|
|
},
|
2018-02-19 09:24:28 +00:00
|
|
|
}
|
2019-08-20 17:37:06 +00:00
|
|
|
|
|
|
|
func TestStructs(t *testing.T) {
|
2019-10-18 15:36:54 +00:00
|
|
|
runTestCases(t, structTestCases)
|
2019-08-20 17:37:06 +00:00
|
|
|
}
|