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:
Anthony De Meulemeester 2018-04-04 21:41:19 +02:00 committed by GitHub
parent 83e467e527
commit 941bd7e728
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 475 additions and 292 deletions

View file

@ -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 := `
_ ____________ __________ _ ____ ___