From c57d4cfff251d6fc7bd8deaf79d714a765f70fe9 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 26 Jun 2020 13:24:17 +0300 Subject: [PATCH 1/2] compiler: count current amount of locals correctly --- pkg/compiler/func_scope.go | 10 ++++++---- pkg/compiler/function_call_test.go | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) 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..446ac0b9a 100644 --- a/pkg/compiler/function_call_test.go +++ b/pkg/compiler/function_call_test.go @@ -169,3 +169,18 @@ 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)) +} From a88ac441472d0b1233f481761f094f9a9f0c45dd Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 26 Jun 2020 13:30:48 +0300 Subject: [PATCH 2/2] 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)) +}