diff --git a/pkg/vm/cli/cli.go b/pkg/vm/cli/cli.go index 2cef728fe..f056e10d8 100644 --- a/pkg/vm/cli/cli.go +++ b/pkg/vm/cli/cli.go @@ -87,6 +87,16 @@ var commands = []*ishell.Cmd{ > load /path/to/file.go`, Func: handleLoadGo, }, + { + Name: "push", + Help: "Push given item to the estack", + LongHelp: `Usage: push + is mandatory, example: +> push methodstring + +See run command help for parameter syntax.`, + Func: handlePush, + }, { Name: "run", Help: "Execute the current loaded script", @@ -270,6 +280,20 @@ func handleLoadGo(c *ishell.Context) { changePrompt(c, v) } +func handlePush(c *ishell.Context) { + v := getVMFromContext(c) + if len(c.Args) == 0 { + c.Err(errors.New("missing parameter")) + return + } + param, err := parseArg(c.Args[0]) + if err != nil { + c.Err(err) + return + } + v.Estack().PushVal(param) +} + func handleRun(c *ishell.Context) { v := getVMFromContext(c) if len(c.Args) != 0 { @@ -297,7 +321,13 @@ func runVMWithHandling(c *ishell.Context, v *vm.VM) { c.Err(err) return } + checkAndPrintVMState(c, v) +} +// checkAndPrintVMState checks VM state and outputs it to the user if it's +// failed, halted or at breakpoint. No message is printed if VM is running +// normally. +func checkAndPrintVMState(c *ishell.Context, v *vm.VM) { var message string switch { case v.HasFailed(): @@ -340,8 +370,17 @@ func handleStep(c *ishell.Context) { return } } - v.AddBreakPointRel(n) - runVMWithHandling(c, v) + for i := 0; i < n; i++ { + err := v.Step() + if err != nil { + c.Err(err) + return + } + checkAndPrintVMState(c, v) + } + ctx := v.Context() + i, op := ctx.CurrInstr() + c.Printf("at %d (%s)\n", i, op.String()) changePrompt(c, v) } @@ -408,43 +447,53 @@ func isMethodArg(s string) bool { func parseArgs(args []string) ([]vm.StackItem, error) { items := make([]vm.StackItem, len(args)) for i, arg := range args { - var typ, value string - typeAndVal := strings.Split(arg, ":") - if len(typeAndVal) < 2 { - if typeAndVal[0] == boolFalse || typeAndVal[0] == boolTrue { - typ = boolType - } else if _, err := strconv.Atoi(typeAndVal[0]); err == nil { - typ = intType - } else { - typ = stringType - } - value = typeAndVal[0] - } else { - typ = typeAndVal[0] - value = typeAndVal[1] + item, err := parseArg(arg) + if err != nil { + return nil, err } + items[i] = item + } + return items, nil +} - switch typ { - case boolType: - if value == boolFalse { - items[i] = vm.NewBoolItem(false) - } else if value == boolTrue { - items[i] = vm.NewBoolItem(true) - } else { - return nil, errors.New("failed to parse bool parameter") - } - case intType: - val, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, err - } - items[i] = vm.NewBigIntegerItem(val) - case stringType: - items[i] = vm.NewByteArrayItem([]byte(value)) +func parseArg(arg string) (vm.StackItem, error) { + var typ, value string + var item vm.StackItem + + typeAndVal := strings.Split(arg, ":") + if len(typeAndVal) < 2 { + if typeAndVal[0] == boolFalse || typeAndVal[0] == boolTrue { + typ = boolType + } else if _, err := strconv.Atoi(typeAndVal[0]); err == nil { + typ = intType + } else { + typ = stringType } + value = typeAndVal[0] + } else { + typ = typeAndVal[0] + value = typeAndVal[1] } - return items, nil + switch typ { + case boolType: + if value == boolFalse { + item = vm.NewBoolItem(false) + } else if value == boolTrue { + item = vm.NewBoolItem(true) + } else { + return nil, errors.New("failed to parse bool parameter") + } + case intType: + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return nil, err + } + item = vm.NewBigIntegerItem(val) + case stringType: + item = vm.NewByteArrayItem([]byte(value)) + } + return item, nil } func printLogo(c *ishell.Shell) { diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index aeb8b0180..9a022e75a 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1029,12 +1029,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } v.estack.Push(&Element{value: t.value[index].Value.Dup()}) default: - arr := obj.Bytes() - if index < 0 || index >= len(arr) { - panic("PICKITEM: invalid index") - } - item := arr[index] - v.estack.PushVal(int(item)) + panic("PICKITEM: unknown type") } case opcode.SETITEM: diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index aab31a408..34c5ddab2 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -1367,9 +1367,7 @@ func TestPICKITEMByteArray(t *testing.T) { vm := load(prog) vm.estack.PushVal([]byte{1, 2}) vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) + checkVMFailed(t, vm) } func TestPICKITEMDupArray(t *testing.T) {