VM and compiler update (#63)
* renamed test folders and fixed bug where wrong jump labels would be exectuted for rewrite. * Added support for Osize (len(string)) and factored out the array tests * Added current instruction number to VM prompt if program is loaded. * added support for unary expressions. * updated README of and sorted the help commands * updated readme of the compiler * bumped version -> 0.39.0
This commit is contained in:
parent
83e467e527
commit
941bd7e728
19 changed files with 475 additions and 292 deletions
|
@ -2,40 +2,45 @@ package cli
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||
"github.com/CityOfZion/neo-go/pkg/vm/compiler"
|
||||
)
|
||||
|
||||
// command describes a VM command.
|
||||
type command struct {
|
||||
// number of minimun arguments the command needs.
|
||||
args int
|
||||
|
||||
// description of the command.
|
||||
usage string
|
||||
|
||||
// whether the VM needs to be "ready" to execute this command.
|
||||
ready bool
|
||||
}
|
||||
|
||||
var commands = map[string]command{
|
||||
"help": {0, "show available commands", false},
|
||||
"exit": {0, "exit the VM prompt", false},
|
||||
"ip": {0, "show the current instruction", true},
|
||||
"break": {1, "place a breakpoint (> break 1)", true},
|
||||
"estack": {0, "show evaluation stack details", false},
|
||||
"astack": {0, "show alt stack details", false},
|
||||
"istack": {0, "show invocation stack details", false},
|
||||
"load": {1, "load a script into the VM (> load /path/to/script.avm)", false},
|
||||
"run": {0, "execute the current loaded script", true},
|
||||
"cont": {0, "continue execution of the current loaded script", true},
|
||||
"step": {0, "step (n) instruction in the program (> step 10)", true},
|
||||
"ops": {0, "show the opcodes of the current loaded program", true},
|
||||
"help": {0, "show available commands", false},
|
||||
"exit": {0, "exit the VM prompt", false},
|
||||
"ip": {0, "show the current instruction", true},
|
||||
"break": {1, "place a breakpoint (> break 1)", true},
|
||||
"estack": {0, "show evaluation stack details", false},
|
||||
"astack": {0, "show alt stack details", false},
|
||||
"istack": {0, "show invocation stack details", false},
|
||||
"loadavm": {1, "load an avm script into the VM (> load /path/to/script.avm)", false},
|
||||
"loadhex": {1, "load a hex string into the VM (> loadhex 006166 )", false},
|
||||
"loadgo": {1, "compile and load a .go file into the VM (> load /path/to/file.go)", false},
|
||||
"run": {0, "execute the current loaded script", true},
|
||||
"cont": {0, "continue execution of the current loaded script", true},
|
||||
"step": {0, "step (n) instruction in the program (> step 10)", true},
|
||||
"ops": {0, "show the opcodes of the current loaded program", true},
|
||||
}
|
||||
|
||||
// VMCLI object for interacting with the VM.
|
||||
|
@ -67,14 +72,7 @@ func (c *VMCLI) handleCommand(cmd string, args ...string) {
|
|||
|
||||
switch cmd {
|
||||
case "help":
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "COMMAND\tUSAGE")
|
||||
for name, details := range commands {
|
||||
fmt.Fprintf(w, "%s\t%s\n", name, details.usage)
|
||||
}
|
||||
w.Flush()
|
||||
fmt.Println()
|
||||
printHelp()
|
||||
|
||||
case "exit":
|
||||
fmt.Println("Bye!")
|
||||
|
@ -97,13 +95,36 @@ func (c *VMCLI) handleCommand(cmd string, args ...string) {
|
|||
case "estack", "istack", "astack":
|
||||
fmt.Println(c.vm.Stack(cmd))
|
||||
|
||||
case "load":
|
||||
case "loadavm":
|
||||
if err := c.vm.LoadFile(args[0]); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Printf("READY: loaded %d instructions\n", c.vm.Context().LenInstr())
|
||||
}
|
||||
|
||||
case "loadhex":
|
||||
b, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
c.vm.Load(b)
|
||||
fmt.Printf("READY: loaded %d instructions\n", c.vm.Context().LenInstr())
|
||||
|
||||
case "loadgo":
|
||||
fb, err := ioutil.ReadFile(args[0])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
b, err := compiler.Compile(bytes.NewReader(fb), &compiler.Options{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
c.vm.Load(b)
|
||||
fmt.Printf("READY: loaded %d instructions\n", c.vm.Context().LenInstr())
|
||||
|
||||
case "run", "cont":
|
||||
c.vm.Run()
|
||||
|
||||
|
@ -132,7 +153,11 @@ func (c *VMCLI) Run() error {
|
|||
printLogo()
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
fmt.Print("NEO-GO-VM > ")
|
||||
if c.vm.Ready() && c.vm.Context().IP()-1 >= 0 {
|
||||
fmt.Printf("NEO-GO-VM %d > ", c.vm.Context().IP()-1)
|
||||
} else {
|
||||
fmt.Print("NEO-GO-VM > ")
|
||||
}
|
||||
input, _ := reader.ReadString('\n')
|
||||
input = strings.Trim(input, "\n")
|
||||
if len(input) != 0 {
|
||||
|
@ -147,6 +172,25 @@ func (c *VMCLI) Run() error {
|
|||
}
|
||||
}
|
||||
|
||||
func printHelp() {
|
||||
names := make([]string, len(commands))
|
||||
i := 0
|
||||
for name, _ := range commands {
|
||||
names[i] = name
|
||||
i++
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "COMMAND\tUSAGE")
|
||||
for _, name := range names {
|
||||
fmt.Fprintf(w, "%s\t%s\n", name, commands[name].usage)
|
||||
}
|
||||
w.Flush()
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func printLogo() {
|
||||
logo := `
|
||||
_ ____________ __________ _ ____ ___
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue