compiler: support ellipsis for append of non-byte slices

NeoVM lacks opcode for array append, thus some
kind of loop is needed for this.
This commit is contained in:
Evgeniy Stratonikov 2021-02-16 16:45:06 +03:00
parent fc3b840335
commit d16ef53653
2 changed files with 43 additions and 4 deletions

View file

@ -1635,10 +1635,32 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
} else {
emit.Instruction(c.prog.BinWriter, opcode.JMPIFNOT, []byte{2 + 2})
emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.NEWARRAY0)
for _, e := range expr.Args[1:] {
emit.Opcodes(c.prog.BinWriter, opcode.DUP)
ast.Walk(c, e)
emit.Opcodes(c.prog.BinWriter, opcode.APPEND)
if expr.Ellipsis.IsValid() {
ast.Walk(c, expr.Args[1]) // x y
emit.Opcodes(c.prog.BinWriter, opcode.PUSH0) // x y cnt=0
start := c.newLabel()
c.setLabel(start)
emit.Opcodes(c.prog.BinWriter, opcode.PUSH2, opcode.PICK) // x y cnt x
emit.Opcodes(c.prog.BinWriter, opcode.PUSH2, opcode.PICK) // x y cnt x y
emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.SIZE) // x y cnt x y len(y)
emit.Opcodes(c.prog.BinWriter, opcode.PUSH3, opcode.PICK) // x y cnt x y len(y) cnt
after := c.newLabel()
emit.Jmp(c.prog.BinWriter, opcode.JMPEQL, after) // x y cnt x y
emit.Opcodes(c.prog.BinWriter, opcode.PUSH2, opcode.PICK, // x y cnt x y cnt
opcode.PICKITEM, // x y cnt x y[cnt]
opcode.APPEND, // x=append(x, y[cnt]) y cnt
opcode.INC) // x y cnt+1
emit.Jmp(c.prog.BinWriter, opcode.JMPL, start)
c.setLabel(after)
for i := 0; i < 4; i++ { // leave x on stack
emit.Opcodes(c.prog.BinWriter, opcode.DROP)
}
} else {
for _, e := range expr.Args[1:] {
emit.Opcodes(c.prog.BinWriter, opcode.DUP)
ast.Walk(c, e)
emit.Opcodes(c.prog.BinWriter, opcode.APPEND)
}
}
}
case "panic":

View file

@ -181,6 +181,23 @@ var sliceTestCases = []testCase{
stackitem.NewBigInteger(big.NewInt(5)),
},
},
{
"int slice, append slice",
`package foo
func getByte() byte { return 0x80 }
func Main() []int {
x := []int{1}
y := []int{2, 3}
x = append(x, y...)
x = append(x, y...)
return x
}`,
[]stackitem.Item{
stackitem.Make(1),
stackitem.Make(2), stackitem.Make(3),
stackitem.Make(2), stackitem.Make(3),
},
},
{
"declare compound slice",
`package foo