vm: implement REVERSE* opcodes

Use new opcodes in the compiler instead of XSWAP/ROLL.
This commit is contained in:
Evgenii Stratonikov 2020-05-06 12:12:29 +03:00
parent c8a1188ee1
commit d18199ce42
6 changed files with 161 additions and 81 deletions

View file

@ -1049,22 +1049,32 @@ func runWithArgs(t *testing.T, prog []byte, result interface{}, args ...interfac
getTestFuncForVM(prog, result, args...)(t)
}
func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) {
func getCustomTestFuncForVM(prog []byte, check func(t *testing.T, v *VM), args ...interface{}) func(t *testing.T) {
return func(t *testing.T) {
v := load(prog)
for i := range args {
v.estack.PushVal(args[i])
}
if result == nil {
if check == nil {
checkVMFailed(t, v)
return
}
runVM(t, v)
require.Equal(t, 1, v.estack.Len())
require.Equal(t, makeStackItem(result), v.estack.Pop().value)
check(t, v)
}
}
func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) {
var f func(t *testing.T, v *VM)
if result != nil {
f = func(t *testing.T, v *VM) {
require.Equal(t, 1, v.estack.Len())
require.Equal(t, makeStackItem(result), v.estack.Pop().value)
}
}
return getCustomTestFuncForVM(prog, f, args...)
}
func TestNOTEQUALByteArray(t *testing.T) {
prog := makeProgram(opcode.NOTEQUAL)
t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2}))
@ -1568,6 +1578,37 @@ func TestROLLGood(t *testing.T) {
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
}
func getCheckEStackFunc(items ...interface{}) func(t *testing.T, v *VM) {
return func(t *testing.T, v *VM) {
require.Equal(t, len(items), v.estack.Len())
for i := 0; i < len(items); i++ {
assert.Equal(t, makeStackItem(items[i]), v.estack.Peek(i).Item())
}
}
}
func TestREVERSE3(t *testing.T) {
prog := makeProgram(opcode.REVERSE3)
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2))
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3), 1, 2, 3))
}
func TestREVERSE4(t *testing.T) {
prog := makeProgram(opcode.REVERSE4)
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4), 1, 2, 3, 4))
}
func TestREVERSEN(t *testing.T) {
prog := makeProgram(opcode.REVERSEN)
t.Run("NoArgument", getTestFuncForVM(prog, nil))
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
t.Run("NegativeArgument", getTestFuncForVM(prog, nil, 1, 2, -1))
t.Run("Zero", getCustomTestFuncForVM(prog, getCheckEStackFunc(3, 2, 1), 1, 2, 3, 0))
t.Run("OneItem", getCustomTestFuncForVM(prog, getCheckEStackFunc(42), 42, 1))
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4, 5), 1, 2, 3, 4, 5, 5))
}
func TestXTUCK(t *testing.T) {
prog := makeProgram(opcode.XTUCK)
t.Run("NoItem", getTestFuncForVM(prog, nil, 1))