Merge pull request #1118 from nspcc-dev/feature/variadic
Support variadic functions in compiler
This commit is contained in:
commit
b9171eda14
3 changed files with 61 additions and 10 deletions
|
@ -758,6 +758,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
}
|
}
|
||||||
// Do not swap for builtin functions.
|
// Do not swap for builtin functions.
|
||||||
if !isBuiltin {
|
if !isBuiltin {
|
||||||
|
if typ, ok := c.typeOf(n.Fun).(*types.Signature); ok && typ.Variadic() {
|
||||||
|
// pack variadic args into an array
|
||||||
|
varSize := len(n.Args) - typ.Params().Len() + 1
|
||||||
|
c.emitReverse(varSize)
|
||||||
|
emit.Int(c.prog.BinWriter, int64(varSize))
|
||||||
|
emit.Opcode(c.prog.BinWriter, opcode.PACK)
|
||||||
|
numArgs -= varSize - 1
|
||||||
|
}
|
||||||
c.emitReverse(numArgs)
|
c.emitReverse(numArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,12 +1124,6 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
|
||||||
c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name)
|
c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch name {
|
|
||||||
case "Notify":
|
|
||||||
numArgs := len(expr.Args)
|
|
||||||
emit.Int(c.prog.BinWriter, int64(numArgs))
|
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.PACK)
|
|
||||||
}
|
|
||||||
emit.Syscall(c.prog.BinWriter, api)
|
emit.Syscall(c.prog.BinWriter, api)
|
||||||
switch name {
|
switch name {
|
||||||
case "GetTransaction", "GetBlock":
|
case "GetTransaction", "GetBlock":
|
||||||
|
|
|
@ -139,16 +139,18 @@ func (c *funcScope) stackSize() int64 {
|
||||||
|
|
||||||
// newVariable creates a new local variable or argument in the scope of the function.
|
// newVariable creates a new local variable or argument in the scope of the function.
|
||||||
func (c *funcScope) newVariable(t varType, name string) int {
|
func (c *funcScope) newVariable(t varType, name string) int {
|
||||||
c.i++
|
var n int
|
||||||
switch t {
|
switch t {
|
||||||
case varLocal:
|
case varLocal:
|
||||||
c.locals[name] = c.i
|
n = len(c.locals)
|
||||||
|
c.locals[name] = n
|
||||||
case varArgument:
|
case varArgument:
|
||||||
c.arguments[name] = c.i
|
n = len(c.arguments)
|
||||||
|
c.arguments[name] = n
|
||||||
default:
|
default:
|
||||||
panic("invalid type")
|
panic("invalid type")
|
||||||
}
|
}
|
||||||
return c.i
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// newLocal creates a new local variable into the scope of the function.
|
// newLocal creates a new local variable into the scope of the function.
|
||||||
|
|
|
@ -169,3 +169,50 @@ func TestFunctionWithMultipleArgumentNames(t *testing.T) {
|
||||||
}`
|
}`
|
||||||
eval(t, src, big.NewInt(3))
|
eval(t, src, big.NewInt(3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVariadic(t *testing.T) {
|
||||||
|
src := `package foo
|
||||||
|
func someFunc(a int, b ...int) int {
|
||||||
|
sum := a
|
||||||
|
for i := range b {
|
||||||
|
sum = sum - b[i]
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
func Main() int {
|
||||||
|
return someFunc(10, 1, 2, 3)
|
||||||
|
}`
|
||||||
|
eval(t, src, big.NewInt(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue