vm: implement KEYS opcode
This commit is contained in:
parent
0fb4bb05cf
commit
2da64267b0
3 changed files with 60 additions and 1 deletions
|
@ -19,10 +19,18 @@ func makeStackItem(v interface{}) StackItem {
|
||||||
return &BigIntegerItem{
|
return &BigIntegerItem{
|
||||||
value: big.NewInt(int64(val)),
|
value: big.NewInt(int64(val)),
|
||||||
}
|
}
|
||||||
|
case int64:
|
||||||
|
return &BigIntegerItem{
|
||||||
|
value: big.NewInt(val),
|
||||||
|
}
|
||||||
case []byte:
|
case []byte:
|
||||||
return &ByteArrayItem{
|
return &ByteArrayItem{
|
||||||
value: val,
|
value: val,
|
||||||
}
|
}
|
||||||
|
case string:
|
||||||
|
return &ByteArrayItem{
|
||||||
|
value: []byte(val),
|
||||||
|
}
|
||||||
case bool:
|
case bool:
|
||||||
return &BoolItem{
|
return &BoolItem{
|
||||||
value: val,
|
value: val,
|
||||||
|
|
19
pkg/vm/vm.go
19
pkg/vm/vm.go
|
@ -912,12 +912,29 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
v.estack.PushVal(sigok)
|
v.estack.PushVal(sigok)
|
||||||
|
|
||||||
case KEYS, VALUES:
|
case VALUES:
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
|
|
||||||
case NEWMAP:
|
case NEWMAP:
|
||||||
v.estack.Push(&Element{value: NewMapItem()})
|
v.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
|
||||||
|
case KEYS:
|
||||||
|
item := v.estack.Pop()
|
||||||
|
if item == nil {
|
||||||
|
panic("no argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
m, ok := item.value.(*MapItem)
|
||||||
|
if !ok {
|
||||||
|
panic("not a Map")
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := make([]StackItem, 0, len(m.value))
|
||||||
|
for k := range m.value {
|
||||||
|
arr = append(arr, makeStackItem(k))
|
||||||
|
}
|
||||||
|
v.estack.PushVal(arr)
|
||||||
|
|
||||||
case HASKEY:
|
case HASKEY:
|
||||||
key := v.estack.Pop()
|
key := v.estack.Pop()
|
||||||
validateMapKey(key)
|
validateMapKey(key)
|
||||||
|
|
|
@ -673,6 +673,40 @@ func TestSIZEBool(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKEYSMap(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(6))
|
||||||
|
m.Add(makeStackItem([]byte{0, 1}), makeStackItem(6))
|
||||||
|
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(5))
|
||||||
|
assert.Contains(t, top.value, makeStackItem([]byte{0, 1}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKEYSNoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKEYSWrongType(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
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