vm: implement VALUES opcode
This commit is contained in:
parent
2da64267b0
commit
d7bb50c609
2 changed files with 78 additions and 3 deletions
37
pkg/vm/vm.go
37
pkg/vm/vm.go
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue