Merge pull request #1118 from nspcc-dev/feature/variadic

Support variadic functions in compiler
This commit is contained in:
Roman Khimov 2020-06-26 23:14:54 +03:00 committed by GitHub
commit b9171eda14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 10 deletions

View file

@ -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":

View file

@ -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.

View file

@ -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))
}