From d16ef536530c8881d3662acffc1943a3bb5217d5 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Tue, 16 Feb 2021 16:45:06 +0300 Subject: [PATCH] compiler: support ellipsis for append of non-byte slices NeoVM lacks opcode for array append, thus some kind of loop is needed for this. --- pkg/compiler/codegen.go | 30 ++++++++++++++++++++++++++---- pkg/compiler/slice_test.go | 17 +++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 53b0cd1d9..0d4f59a17 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -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": diff --git a/pkg/compiler/slice_test.go b/pkg/compiler/slice_test.go index 4e3e9b82c..37f163b38 100644 --- a/pkg/compiler/slice_test.go +++ b/pkg/compiler/slice_test.go @@ -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