vise/vm/debug.go
2023-04-12 18:09:37 +01:00

168 lines
3.2 KiB
Go

package vm
import (
"bytes"
"fmt"
"io"
"log"
)
// ToString verifies all instructions in bytecode and returns an assmebly code instruction for it.
func ToString(b []byte) (string, error) {
buf := bytes.NewBuffer(nil)
n, err := ParseAll(b, buf)
if err != nil {
return "", err
}
log.Printf("Total %v bytes written to string buffer", n)
return buf.String(), nil
}
// ParseAll parses and verifies all instructions from bytecode.
//
// If writer is not nil, the parsed instruction as assembly code line string is written to it.
//
// Bytecode is consumed (and written) one instruction at a time.
//
// It fails on any parse error encountered before the bytecode EOF is reached.
func ParseAll(b []byte, w io.Writer) (int, error) {
var s string
var rs string
var rn int
running := true
for running {
op, bb, err := opSplit(b)
b = bb
if err != nil {
return rn, err
}
s = OpcodeString[op]
if s == "" {
return rn, fmt.Errorf("unknown opcode: %v", op)
}
switch op {
case CATCH:
r, n, m, bb, err := ParseCatch(b)
b = bb
if err == nil {
if w != nil {
vv := 0
if m {
vv = 1
}
if w != nil {
//rs = fmt.Sprintf("%s %s %v %v # invertmatch=%v\n", s, r, n, vv, m)
rs = fmt.Sprintf("%s %s %v %v\n", s, r, n, vv)
}
}
}
case CROAK:
n, m, bb, err := ParseCroak(b)
b = bb
if err == nil {
if w != nil {
vv := 0
if m {
vv = 1
}
//rs = fmt.Sprintf("%s %v %v # invertmatch=%v\n", s, n, vv, m)
rs = fmt.Sprintf("%s %v %v\n", s, n, vv)
}
}
case LOAD:
r, n, bb, err := ParseLoad(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s %v\n", s, r, n)
}
}
case RELOAD:
r, bb, err := ParseReload(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s\n", s, r)
}
}
case MAP:
r, bb, err := ParseMap(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s\n", s, r)
}
}
case MOVE:
r, bb, err := ParseMove(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s\n", s, r)
}
}
case INCMP:
r, v, bb, err := ParseInCmp(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s %s\n", s, r, v)
}
}
case HALT:
b, err = ParseHalt(b)
rs = "HALT\n"
case MSIZE:
r, v, bb, err := ParseMSize(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %v %v\n", s, r, v)
}
}
case MOUT:
r, v, bb, err := ParseMOut(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
}
}
case MNEXT:
r, v, bb, err := ParseMNext(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
}
}
case MPREV:
r, v, bb, err := ParseMPrev(b)
b = bb
if err == nil {
if w != nil {
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
}
}
}
if err != nil {
return rn, err
}
if w != nil {
n, err := io.WriteString(w, rs)
if err != nil {
return rn, err
}
rn += n
log.Printf("wrote %v bytes for instruction %v", n, s)
}
//rs += "\n"
if len(b) == 0 {
running = false
}
}
return rn, nil
}