vm: implement VALUES opcode

This commit is contained in:
Evgenii Stratonikov 2019-09-24 15:53:55 +03:00
parent 2da64267b0
commit d7bb50c609
2 changed files with 78 additions and 3 deletions

View file

@ -912,9 +912,6 @@ func (v *VM) execute(ctx *Context, op Instruction) {
}
v.estack.PushVal(sigok)
case VALUES:
panic("unimplemented")
case NEWMAP:
v.estack.Push(&Element{value: NewMapItem()})
@ -935,6 +932,31 @@ func (v *VM) execute(ctx *Context, op Instruction) {
}
v.estack.PushVal(arr)
case VALUES:
item := v.estack.Pop()
if item == nil {
panic("no argument")
}
var arr []StackItem
switch t := item.value.(type) {
case *ArrayItem, *StructItem:
src := t.Value().([]StackItem)
arr = make([]StackItem, len(src))
for i := range src {
arr[i] = cloneIfStruct(src[i])
}
case *MapItem:
arr = make([]StackItem, 0, len(t.value))
for k := range t.value {
arr = append(arr, cloneIfStruct(t.value[k]))
}
default:
panic("not a Map, Array or Struct")
}
v.estack.PushVal(arr)
case HASKEY:
key := v.estack.Pop()
validateMapKey(key)
@ -991,6 +1013,15 @@ func (v *VM) execute(ctx *Context, op Instruction) {
}
}
func cloneIfStruct(item StackItem) StackItem {
switch it := item.(type) {
case *StructItem:
return it.Clone()
default:
return it
}
}
func makeArrayOfFalses(n int) []StackItem {
items := make([]StackItem, n)
for i := range items {

View file

@ -707,6 +707,50 @@ func TestKEYSWrongType(t *testing.T) {
assert.Equal(t, true, vm.HasFailed())
}
func TestVALUESMap(t *testing.T) {
prog := makeProgram(VALUES)
vm := load(prog)
m := NewMapItem()
m.Add(makeStackItem(5), makeStackItem([]byte{2, 3}))
m.Add(makeStackItem([]byte{0, 1}), makeStackItem([]StackItem{}))
vm.estack.Push(&Element{value: m})
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
top := vm.estack.Pop().value.(*ArrayItem)
assert.Equal(t, 2, len(top.value))
assert.Contains(t, top.value, makeStackItem([]byte{2, 3}))
assert.Contains(t, top.value, makeStackItem([]StackItem{}))
}
func TestVALUESArray(t *testing.T) {
prog := makeProgram(VALUES)
vm := load(prog)
vm.estack.PushVal([]StackItem{makeStackItem(4)})
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(4)}}, vm.estack.Pop().value)
}
func TestVALUESNoArgument(t *testing.T) {
prog := makeProgram(VALUES)
vm := load(prog)
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestVALUESWrongType(t *testing.T) {
prog := makeProgram(VALUES)
vm := load(prog)
vm.estack.PushVal(5)
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestHASKEYArrayTrue(t *testing.T) {
prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY)
vm := load(prog)