commit d95d27f8fe5fe87954278c604b0451a9553d7896
parent 684de95198725a3d636d0c5d3855a13174070243
Author: lash <dev@holbrook.no>
Date: Tue, 4 Apr 2023 08:10:25 +0100
Implement verifier as writer
Diffstat:
2 files changed, 110 insertions(+), 51 deletions(-)
diff --git a/go/vm/debug.go b/go/vm/debug.go
@@ -1,121 +1,165 @@
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 "", err
+ return rn, err
}
- opString := OpcodeString[op]
- if opString == "" {
- return "", fmt.Errorf("unknown opcode: %v", op)
+ s = OpcodeString[op]
+ if s == "" {
+ return rn, fmt.Errorf("unknown opcode: %v", op)
}
- s += opString
switch op {
case CATCH:
r, n, m, bb, err := ParseCatch(b)
b = bb
- if err != nil {
- return "", err
- }
- vv := 0
- if m {
- vv = 1
+ 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)
+ }
+ }
}
- s = fmt.Sprintf("%s %s %v %v # invertmatch=%v", s, r, n, vv, m)
case CROAK:
n, m, bb, err := ParseCroak(b)
b = bb
- if err != nil {
- return "", err
- }
- vv := 0
- if m {
- vv = 1
+ 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)
+ }
}
- s = fmt.Sprintf("%s %v %v # invertmatch=%v", s, n, vv, m)
case LOAD:
r, n, bb, err := ParseLoad(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s %v\n", s, r, n)
+ }
}
- s = fmt.Sprintf("%s %s %v", s, r, n)
case RELOAD:
r, bb, err := ParseReload(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s\n", s, r)
+ }
}
- s = fmt.Sprintf("%s %s", s, r)
case MAP:
r, bb, err := ParseMap(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s\n", s, r)
+ }
}
- s = fmt.Sprintf("%s %s", s, r)
case MOVE:
r, bb, err := ParseMove(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s\n", s, r)
+ }
}
- s = fmt.Sprintf("%s %s", s, r)
case INCMP:
r, v, bb, err := ParseInCmp(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s %s\n", s, r, v)
+ }
}
- s = fmt.Sprintf("%s %s %s", s, r, v)
case HALT:
b, err = ParseHalt(b)
- if err != nil {
- return "", err
- }
+ rs = "HALT\n"
case MSIZE:
r, v, bb, err := ParseMSize(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %v %v\n", s, r, v)
+ }
}
- s = fmt.Sprintf("%s %v %v", s, r, v)
case MOUT:
r, v, bb, err := ParseMOut(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
+ }
}
- s = fmt.Sprintf("%s %s \"%s\"", s, r, v)
case MNEXT:
r, v, bb, err := ParseMNext(b)
b = bb
- if err != nil {
- return "", err
+ if err == nil {
+ if w != nil {
+ rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
+ }
}
- s = fmt.Sprintf("%s %s \"%s\"", 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 "", err
+ return rn, err
}
- s = fmt.Sprintf("%s %s \"%s\"", s, r, v)
+ rn += n
+ log.Printf("wrote %v bytes from instruction %v", n, s)
}
- s += "\n"
+
+ //rs += "\n"
if len(b) == 0 {
running = false
}
}
- return s, nil
+ return rn, nil
}
diff --git a/go/vm/debug_test.go b/go/vm/debug_test.go
@@ -152,3 +152,18 @@ HALT
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
}
+
+func TestVerifyMultiple(t *testing.T) {
+ b := NewLine(nil, INCMP, []string{"1", "foo"}, nil, nil)
+ b = NewLine(b, INCMP, []string{"2", "bar"}, nil, nil)
+ b = NewLine(b, CATCH, []string{"aiee"}, []byte{0x02, 0x9a}, []uint8{0})
+ b = NewLine(b, LOAD, []string{"inky"}, []byte{0x2a}, nil)
+ b = NewLine(b, HALT, nil, nil, nil)
+ n, err := ParseAll(b, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 0 {
+ t.Fatalf("expected write count to be 0, was %v (how is that possible)", n)
+ }
+}