From 2da64267b028527d6abd27101e2a28dc7fad067e Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 24 Sep 2019 15:41:39 +0300 Subject: [PATCH] vm: implement KEYS opcode --- pkg/vm/stack_item.go | 8 ++++++++ pkg/vm/vm.go | 19 ++++++++++++++++++- pkg/vm/vm_test.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/pkg/vm/stack_item.go b/pkg/vm/stack_item.go index 26b758e60..9389178f8 100644 --- a/pkg/vm/stack_item.go +++ b/pkg/vm/stack_item.go @@ -19,10 +19,18 @@ func makeStackItem(v interface{}) StackItem { return &BigIntegerItem{ value: big.NewInt(int64(val)), } + case int64: + return &BigIntegerItem{ + value: big.NewInt(val), + } case []byte: return &ByteArrayItem{ value: val, } + case string: + return &ByteArrayItem{ + value: []byte(val), + } case bool: return &BoolItem{ value: val, diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index b713fd712..69df69fb4 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -912,12 +912,29 @@ func (v *VM) execute(ctx *Context, op Instruction) { } v.estack.PushVal(sigok) - case KEYS, VALUES: + case VALUES: panic("unimplemented") case NEWMAP: 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: key := v.estack.Pop() validateMapKey(key) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 79b2694ac..815a2f9b6 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -673,6 +673,40 @@ func TestSIZEBool(t *testing.T) { 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) { prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY) vm := load(prog)