2019-12-23 14:05:34 +00:00
|
|
|
package compiler_test
|
2018-04-10 09:45:31 +00:00
|
|
|
|
|
|
|
import (
|
2020-05-06 12:39:25 +00:00
|
|
|
"fmt"
|
2018-04-10 09:45:31 +00:00
|
|
|
"math/big"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSimpleFunctionCall(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := 10
|
|
|
|
y := getSomeInteger()
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeInteger() int {
|
|
|
|
x := 10
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, big.NewInt(20))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNotAssignedFunctionCall(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
getSomeInteger()
|
|
|
|
getSomeInteger()
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeInteger() int {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
`
|
2020-03-06 12:11:14 +00:00
|
|
|
// disable stack checks because it is hard right now
|
|
|
|
// to distinguish between simple function call traversal
|
|
|
|
// and the same traversal inside an assignment.
|
2020-05-20 13:31:10 +00:00
|
|
|
evalWithoutStackChecks(t, src, big.NewInt(0))
|
2018-04-10 09:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestMultipleFunctionCalls(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := 10
|
|
|
|
y := getSomeInteger()
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeInteger() int {
|
|
|
|
x := 10
|
|
|
|
y := getSomeOtherInt()
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeOtherInt() int {
|
|
|
|
x := 8
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, big.NewInt(28))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFunctionCallWithArgs(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := 10
|
|
|
|
y := getSomeInteger(x)
|
|
|
|
return y
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeInteger(x int) int {
|
|
|
|
y := 8
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, big.NewInt(18))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFunctionCallWithInterfaceType(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() interface{} {
|
|
|
|
x := getSomeInteger(10)
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSomeInteger(x interface{}) interface{} {
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, big.NewInt(10))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFunctionCallMultiArg(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := addIntegers(2, 4)
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
|
|
|
func addIntegers(x int, y int) int {
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
`
|
|
|
|
eval(t, src, big.NewInt(6))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFunctionWithVoidReturn(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := 2
|
|
|
|
getSomeInteger()
|
|
|
|
y := 4
|
|
|
|
return x + y
|
|
|
|
}
|
|
|
|
|
2020-05-06 12:24:12 +00:00
|
|
|
func getSomeInteger() { %s }
|
2018-04-10 09:45:31 +00:00
|
|
|
`
|
2020-05-06 12:24:12 +00:00
|
|
|
t.Run("EmptyBody", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(src, "")
|
|
|
|
eval(t, src, big.NewInt(6))
|
|
|
|
})
|
|
|
|
t.Run("SingleReturn", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(src, "return")
|
|
|
|
eval(t, src, big.NewInt(6))
|
|
|
|
})
|
2018-04-10 09:45:31 +00:00
|
|
|
}
|
2020-05-06 12:39:25 +00:00
|
|
|
|
|
|
|
func TestFunctionWithVoidReturnBranch(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package testcase
|
|
|
|
func Main() int {
|
|
|
|
x := %t
|
|
|
|
f(x)
|
|
|
|
return 2
|
|
|
|
}
|
|
|
|
|
|
|
|
func f(x bool) {
|
|
|
|
if x {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
|
|
|
t.Run("ReturnBranch", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(src, true)
|
|
|
|
eval(t, src, big.NewInt(2))
|
|
|
|
})
|
|
|
|
t.Run("NoReturn", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(src, false)
|
|
|
|
eval(t, src, big.NewInt(2))
|
|
|
|
})
|
|
|
|
}
|
2020-05-06 15:20:12 +00:00
|
|
|
|
|
|
|
func TestFunctionWithMultipleArgumentNames(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func Main() int {
|
|
|
|
return add(1, 2)
|
|
|
|
}
|
|
|
|
func add(a, b int) int {
|
|
|
|
return a + b
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(3))
|
|
|
|
}
|
2020-06-26 10:24:17 +00:00
|
|
|
|
|
|
|
func TestLocalsCount(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
func f(a, b, c int) int {
|
|
|
|
sum := a
|
|
|
|
for i := 0; i < c; i++ {
|
|
|
|
sum += b
|
|
|
|
}
|
|
|
|
return sum
|
|
|
|
}
|
|
|
|
func Main() int {
|
|
|
|
return f(1, 2, 3)
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(7))
|
|
|
|
}
|
2020-06-26 10:30:48 +00:00
|
|
|
|
|
|
|
func TestVariadic(t *testing.T) {
|
2020-06-27 07:39:30 +00:00
|
|
|
srcTmpl := `package foo
|
2020-06-26 10:30:48 +00:00
|
|
|
func someFunc(a int, b ...int) int {
|
|
|
|
sum := a
|
|
|
|
for i := range b {
|
|
|
|
sum = sum - b[i]
|
|
|
|
}
|
|
|
|
return sum
|
|
|
|
}
|
|
|
|
func Main() int {
|
2020-06-27 07:39:30 +00:00
|
|
|
%s
|
|
|
|
return someFunc(10, %s)
|
2020-06-26 10:30:48 +00:00
|
|
|
}`
|
2020-06-27 07:39:30 +00:00
|
|
|
t.Run("Elements", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(srcTmpl, "", "1, 2, 3")
|
|
|
|
eval(t, src, big.NewInt(4))
|
|
|
|
})
|
|
|
|
t.Run("Slice", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(srcTmpl, "a := []int{1, 2, 3}", "a...")
|
|
|
|
eval(t, src, big.NewInt(4))
|
|
|
|
})
|
|
|
|
t.Run("Literal", func(t *testing.T) {
|
|
|
|
src := fmt.Sprintf(srcTmpl, "", "[]int{1, 2, 3}...")
|
|
|
|
eval(t, src, big.NewInt(4))
|
|
|
|
})
|
2020-06-26 10:30:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestVariadicMethod(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
type myInt int
|
|
|
|
func (x myInt) someFunc(a int, b ...int) int {
|
|
|
|
sum := int(x) + a
|
|
|
|
for i := range b {
|
|
|
|
sum = sum - b[i]
|
|
|
|
}
|
|
|
|
return sum
|
|
|
|
}
|
|
|
|
func Main() int {
|
|
|
|
x := myInt(38)
|
|
|
|
return x.someFunc(10, 1, 2, 3)
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(42))
|
|
|
|
}
|