diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index e566055da..a74d4b420 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -758,6 +758,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { } // Do not swap for builtin functions. 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) } @@ -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) 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) switch name { case "GetTransaction", "GetBlock": diff --git a/pkg/compiler/func_scope.go b/pkg/compiler/func_scope.go index 5c202c8aa..b66c8e1dd 100644 --- a/pkg/compiler/func_scope.go +++ b/pkg/compiler/func_scope.go @@ -139,16 +139,18 @@ func (c *funcScope) stackSize() int64 { // newVariable creates a new local variable or argument in the scope of the function. func (c *funcScope) newVariable(t varType, name string) int { - c.i++ + var n int switch t { case varLocal: - c.locals[name] = c.i + n = len(c.locals) + c.locals[name] = n case varArgument: - c.arguments[name] = c.i + n = len(c.arguments) + c.arguments[name] = n default: panic("invalid type") } - return c.i + return n } // newLocal creates a new local variable into the scope of the function. diff --git a/pkg/compiler/function_call_test.go b/pkg/compiler/function_call_test.go index c9d9ca04c..072542f58 100644 --- a/pkg/compiler/function_call_test.go +++ b/pkg/compiler/function_call_test.go @@ -169,3 +169,50 @@ func TestFunctionWithMultipleArgumentNames(t *testing.T) { }` 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)) +}