commit 8d7e8de76bed4a06c122ca79269d460b9bb5dc99
parent 683015d4df80721a2f209979338f383ee3678db9
Author: lash <dev@holbrook.no>
Date: Wed, 18 Dec 2024 18:21:35 +0000
Prepare VM parser for pluggable handler functions
Diffstat:
A | debug/node.go | | | 34 | ++++++++++++++++++++++++++++++++++ |
A | dev/walk/main.go | | | 47 | +++++++++++++++++++++++++++++++++++++++++++++++ |
M | vm/debug.go | | | 245 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
3 files changed, 252 insertions(+), 74 deletions(-)
diff --git a/debug/node.go b/debug/node.go
@@ -0,0 +1,34 @@
+package debug
+
+type Node struct {
+ Name string
+ Description string
+ conn []string
+}
+
+var (
+ NodeIndex = make(map[string]Node)
+)
+
+func (n *Node) haveConn(peer string) bool {
+ var v string
+ for _, v = range(n.conn) {
+ if peer == v {
+ return true
+ }
+ }
+ return false
+}
+
+func (n *Node) Connect(peer Node) bool {
+ var ok bool
+ _, ok = NodeIndex[peer.Name]
+ if !ok {
+ NodeIndex[peer.Name] = peer
+ }
+ if n.haveConn(peer.Name) {
+ return false
+ }
+ n.conn = append(n.conn, peer.Name)
+ return true
+}
diff --git a/dev/walk/main.go b/dev/walk/main.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "git.defalsify.org/vise.git/vm"
+ "git.defalsify.org/vise.git/resource"
+ fsdb "git.defalsify.org/vise.git/db/fs"
+
+)
+
+func main() {
+ var dir string
+ var root string
+
+ flag.StringVar(&dir, "d", ".", "resource dir to read from")
+ flag.StringVar(&root, "root", "root", "entry point symbol")
+ flag.Parse()
+ fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
+
+ ctx := context.Background()
+ rsStore := fsdb.NewFsDb()
+ err := rsStore.Connect(ctx, dir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "resource db connect error: %v", err)
+ os.Exit(1)
+ }
+
+ rs := resource.NewDbResource(rsStore)
+ //rs = rs.With(db.DATATYPE_STATICLOAD)
+
+ ph := vm.NewParseHandler().WithDefaultHandlers().WithWriter(os.Stdout)
+
+ b, err := rs.GetCode(ctx, root)
+ if err != nil {
+ panic(err)
+ }
+
+ n, err := ph.ParseAll(b)
+ if err != nil {
+ panic(err)
+ }
+ _ = n
+}
diff --git a/vm/debug.go b/vm/debug.go
@@ -6,10 +6,141 @@ import (
"io"
)
+type ParseHandler struct {
+ Catch func(string, uint32, bool) error
+ Croak func(uint32, bool) error
+ Load func(string, uint32) error
+ Reload func(string) error
+ Map func(string) error
+ Move func(string) error
+ Halt func() error
+ InCmp func(string, string) error
+ MOut func(string, string) error
+ MSink func() error
+ MNext func(string, string) error
+ MPrev func(string, string) error
+ cur string
+ n int
+ w io.Writer
+}
+
+func NewParseHandler() *ParseHandler {
+ return &ParseHandler{}
+}
+
+func (ph *ParseHandler) Length() int {
+ return ph.n
+}
+
+func (ph *ParseHandler) WithDefaultHandlers() *ParseHandler {
+ ph.Catch = ph.catch
+ ph.Croak = ph.croak
+ ph.Load = ph.load
+ ph.Reload = ph.reload
+ ph.Map = ph.maph
+ ph.Move = ph.move
+ ph.Halt = ph.halt
+ ph.InCmp = ph.incmp
+ ph.MOut = ph.mout
+ ph.MSink = ph.msink
+// ph.MNext = ph.mnext
+// ph.MPrev = ph.mprev
+ return ph
+}
+
+func (ph *ParseHandler) WithWriter(w io.Writer) *ParseHandler {
+ ph.w = w
+ return ph
+}
+
+// TODO: output op sym
+func (ph *ParseHandler) flush() error {
+ if ph.w != nil {
+ n, err := io.WriteString(ph.w, ph.cur)
+ if err != nil {
+ return err
+ }
+ ph.n += n
+ ph.cur = ""
+ //logg.Tracef("instruction debug write", "bytes", n, "instruction", s)
+ logg.Tracef("instruction debug write", "bytes", n)
+ }
+ return nil
+}
+
+func (ph *ParseHandler) catch(sym string, flag uint32, inv bool) error {
+ s := OpcodeString[CATCH]
+ vv := 0
+ if inv {
+ vv = 1
+ }
+ ph.cur = fmt.Sprintf("%s %s %v %v\n", s, sym, flag, vv)
+ return nil
+}
+
+func (ph *ParseHandler) croak(flag uint32, inv bool) error {
+ s := OpcodeString[CROAK]
+ vv := 0
+ if inv {
+ vv = 1
+ }
+ ph.cur = fmt.Sprintf("%s %v %v\n", s, flag, vv)
+ return nil
+}
+
+func (ph *ParseHandler) load(sym string, length uint32) error {
+ s := OpcodeString[LOAD]
+ ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, length)
+ return nil
+}
+
+func (ph *ParseHandler) reload(sym string) error {
+ s := OpcodeString[RELOAD]
+ ph.cur = fmt.Sprintf("%s %s\n", s, sym)
+ return nil
+}
+
+func (ph *ParseHandler) maph(sym string) error {
+ s := OpcodeString[MAP]
+ ph.cur = fmt.Sprintf("%s %s\n", s, sym)
+ return nil
+}
+
+func (ph *ParseHandler) move(sym string) error {
+ s := OpcodeString[MOVE]
+ ph.cur = fmt.Sprintf("%s %s\n", s, sym)
+ return nil
+}
+
+func (ph *ParseHandler) incmp(sym string, sel string) error {
+ s := OpcodeString[INCMP]
+ ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, sel)
+ return nil
+}
+
+func (ph *ParseHandler) halt() error {
+ s := OpcodeString[HALT]
+ ph.cur = fmt.Sprintf("%s\n", s)
+ return nil
+}
+
+func (ph *ParseHandler) msink() error {
+ s := OpcodeString[MSINK]
+ ph.cur = fmt.Sprintf("%s\n", s)
+ return nil
+}
+
+func (ph *ParseHandler) mout(sym string, sel string) error {
+ s := OpcodeString[MOUT]
+ ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, sel)
+ return nil
+}
+
// ToString verifies all instructions in bytecode and returns an assmebly code instruction for it.
-func ToString(b []byte) (string, error) {
+func (ph *ParseHandler) ToString(b []byte) (string, error) {
buf := bytes.NewBuffer(nil)
- n, err := ParseAll(b, buf)
+ ph = ph.WithWriter(buf)
+ n, err := ph.ParseAll(b)
if err != nil {
return "", err
}
@@ -24,20 +155,18 @@ func ToString(b []byte) (string, error) {
// 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) {
+func (ph *ParseHandler) ParseAll(b []byte) (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
+ return ph.Length(), err
}
s = OpcodeString[op]
if s == "" {
- return rn, fmt.Errorf("unknown opcode: %v", op)
+ return ph.Length(), fmt.Errorf("unknown opcode: %v", op)
}
switch op {
@@ -45,120 +174,88 @@ func ParseAll(b []byte, w io.Writer) (int, error) {
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)
- }
- }
+ err = ph.Catch(r, n, m)
}
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)
- }
+ err = ph.Croak(n, m)
}
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)
- }
+ err = ph.Load(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)
- }
+ err = ph.Reload(r)
}
case MAP:
r, bb, err := ParseMap(b)
b = bb
if err == nil {
- if w != nil {
- rs = fmt.Sprintf("%s %s\n", s, r)
- }
+ err = ph.Map(r)
}
case MOVE:
r, bb, err := ParseMove(b)
b = bb
if err == nil {
- if w != nil {
- rs = fmt.Sprintf("%s %s\n", s, r)
- }
+ err = ph.Move(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)
- }
+ err = ph.InCmp(r, v)
}
case HALT:
b, err = ParseHalt(b)
- rs = "HALT\n"
+ if err != nil {
+ err = ph.Halt()
+ }
case MSINK:
b, err = ParseMSink(b)
- rs = "MSINK\n"
+ if err != nil {
+ err = ph.MSink()
+ }
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)
- 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)
- 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)
- rs = fmt.Sprintf("%s %s %s\n", s, r, v)
- }
+ err = ph.MOut(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)
+// 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)
+// 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
- logg.Tracef("instruction debug write", "bytes", n, "instruction", s)
+ return ph.Length(), err
}
+ ph.flush()
//rs += "\n"
if len(b) == 0 {
running = false
}
}
- return rn, nil
+ return ph.Length(), nil
}