From a88ac441472d0b1233f481761f094f9a9f0c45dd Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 26 Jun 2020 13:30:48 +0300 Subject: [PATCH] compiler: support variadic function definitions Pack variadic arguments into a slice. This currently doen't work with byte slices though. --- pkg/compiler/codegen.go | 14 +++++++------ pkg/compiler/function_call_test.go | 32 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) 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/function_call_test.go b/pkg/compiler/function_call_test.go index 446ac0b9a..072542f58 100644 --- a/pkg/compiler/function_call_test.go +++ b/pkg/compiler/function_call_test.go @@ -184,3 +184,35 @@ func TestLocalsCount(t *testing.T) { }` 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)) +}