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)
|
v.estack.PushVal(sigok)
|
||||||
|
|
||||||
case VALUES:
|
|
||||||
panic("unimplemented")
|
|
||||||
|
|
||||||
case NEWMAP:
|
case NEWMAP:
|
||||||
v.estack.Push(&Element{value: NewMapItem()})
|
v.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
|
||||||
|
@ -935,6 +932,31 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
v.estack.PushVal(arr)
|
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:
|
case HASKEY:
|
||||||
key := v.estack.Pop()
|
key := v.estack.Pop()
|
||||||
validateMapKey(key)
|
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 {
|
func makeArrayOfFalses(n int) []StackItem {
|
||||||
items := make([]StackItem, n)
|
items := make([]StackItem, n)
|
||||||
for i := range items {
|
for i := range items {
|
||||||
|
|
|
@ -707,6 +707,50 @@ func TestKEYSWrongType(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.HasFailed())
|
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) {
|
func TestHASKEYArrayTrue(t *testing.T) {
|
||||||
prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY)
|
prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue