go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 59dcb7875db2a92718c8d049e8526e68012398f3
parent 28cbe308d430557c6d312d7ed481303ba2887944
Author: lash <dev@holbrook.no>
Date:   Thu, 13 Apr 2023 10:33:24 +0100

WIP correct entry point in persisted runner

Diffstat:
Mengine/engine.go | 14+++++++++-----
Mengine/engine_test.go | 33++++++++++++---------------------
Mengine/loop.go | 5+++--
Mengine/persist.go | 43++++++++++++++++++++++++++++++++++++-------
Mengine/persist_test.go | 48++++++++++++++++++++++++++++--------------------
Mpersist/fs.go | 4++--
Mresource/fs.go | 7+++++++
Mstate/state.go | 7++++++-
Mvm/runner.go | 5+++--
9 files changed, 106 insertions(+), 60 deletions(-)

diff --git a/engine/engine.go b/engine/engine.go @@ -43,7 +43,8 @@ func NewEngine(cfg Config, st *state.State, rs resource.Resource, ca cache.Memor ca: ca, vm: vm.NewVm(st, rs, ca, szr), } - if cfg.Root != "" { + //if cfg.Root != "" { + if st.Moves == 0 { engine.Init(cfg.Root, ctx) } return engine @@ -65,10 +66,12 @@ func(en *Engine) Init(sym string, ctx context.Context) error { return err } b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil) + log.Printf("start new init VM run with code %x", b) b, err = en.vm.Run(b, ctx) if err != nil { return err } + log.Printf("ended init VM run with code %x", b) en.st.SetCode(b) en.initd = true return nil @@ -102,10 +105,12 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) { if len(code) == 0 { return false, fmt.Errorf("no code to execute") } + log.Printf("start new VM run with code %x", code) code, err = en.vm.Run(code, ctx) if err != nil { return false, err } + log.Printf("ended VM run with code %x", code) v, err := en.st.MatchFlag(state.FLAG_TERMINATE, false) if err != nil { @@ -133,11 +138,10 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) { // - required data inputs to the template are not available. // - the template for the given node point is note available for retrieval using the resource.Resource implementer. // - the supplied writer fails to process the writes. -func(en *Engine) WriteResult(w io.Writer, ctx context.Context) error { +func(en *Engine) WriteResult(w io.Writer, ctx context.Context) (int, error) { r, err := en.vm.Render(ctx) if err != nil { - return err + return 0, err } - _, err = io.WriteString(w, r) - return err + return io.WriteString(w, r) } diff --git a/engine/engine_test.go b/engine/engine_test.go @@ -26,10 +26,14 @@ type FsWrapper struct { func NewFsWrapper(path string, st *state.State) FsWrapper { rs := resource.NewFsResource(path) - return FsWrapper { + wr := FsWrapper { &rs, st, } + wr.AddLocalFunc("one", wr.one) + wr.AddLocalFunc("inky", wr.inky) + wr.AddLocalFunc("pinky", wr.pinky) + return wr } func(fs FsWrapper) one(sym string, input []byte, ctx context.Context) (resource.Result, error) { @@ -51,18 +55,6 @@ func(fs FsWrapper) pinky(sym string, input []byte, ctx context.Context) (resourc }, nil } -func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) { - switch sym { - case "one": - return fs.one, nil - case "inky": - return fs.inky, nil - case "pinky": - return fs.pinky, nil - } - return nil, fmt.Errorf("function for %v not found", sym) -} - func(fs FsWrapper) GetCode(sym string) ([]byte, error) { sym += ".bin" fp := path.Join(fs.Path, sym) @@ -82,20 +74,19 @@ func generateTestData(t *testing.T) { } func TestEngineInit(t *testing.T) { + var err error generateTestData(t) ctx := context.TODO() st := state.NewState(17) rs := NewFsWrapper(dataDir, &st) ca := cache.NewCache().WithCacheSize(1024) - en := NewEngine(Config{}, &st, &rs, ca, ctx) - err := en.Init("root", ctx) - if err != nil { - t.Fatal(err) - } - + en := NewEngine(Config{ + Root: "root", + }, &st, &rs, ca, ctx) +// w := bytes.NewBuffer(nil) - err = en.WriteResult(w, ctx) + _, err = en.WriteResult(w, ctx) if err != nil { t.Fatal(err) } @@ -118,7 +109,7 @@ func TestEngineInit(t *testing.T) { t.Fatalf("expected where-string 'foo', got %s", r) } w = bytes.NewBuffer(nil) - err = en.WriteResult(w, ctx) + _, err = en.WriteResult(w, ctx) if err != nil { t.Fatal(err) } diff --git a/engine/loop.go b/engine/loop.go @@ -19,7 +19,8 @@ import ( // // Rendered output is written to the provided writer. func Loop(en *Engine, reader io.Reader, writer io.Writer, ctx context.Context) error { - err := en.WriteResult(writer, ctx) + var err error + _, err = en.WriteResult(writer, ctx) if err != nil { return err } @@ -41,7 +42,7 @@ func Loop(en *Engine, reader io.Reader, writer io.Writer, ctx context.Context) e if err != nil { return fmt.Errorf("unexpected termination: %v\n", err) } - err = en.WriteResult(writer, ctx) + _, err = en.WriteResult(writer, ctx) if err != nil { return err } diff --git a/engine/persist.go b/engine/persist.go @@ -25,14 +25,43 @@ func RunPersisted(cfg Config, rs resource.Resource, pr persist.Persister, input return err } st := pr.GetState() - log.Printf("st %v", st) + location, idx := st.Where() + if location != "" { + cfg.Root = location + } + + log.Printf("run persisted with state %v %x input %s", st, st.Code, input) en := NewEngine(cfg, pr.GetState(), rs, pr.GetMemory(), ctx) - if len(input) > 0 { - _, err = en.Exec(input, ctx) - if err != nil { - return err - } + log.Printf("location %s", location) + +// if len(input) == 0 { +// log.Printf("init") +// err = en.Init(location, ctx) +// if err != nil { +// return err +// } + c, err := en.WriteResult(w, ctx) + if err != nil { + return err + } + err = pr.Save(cfg.SessionId) + if err != nil { + return err + } + log.Printf("engine init write %v flags %v", c, st.Flags) + if c > 0 { + return err + } + _ = idx + + _, err = en.Exec(input, ctx) + if err != nil { + return err + } + _, err = en.WriteResult(w, ctx) + if err != nil { + return err } - return en.WriteResult(w, ctx) + return pr.Save(cfg.SessionId) } diff --git a/engine/persist_test.go b/engine/persist_test.go @@ -1,9 +1,9 @@ package engine import ( - "bytes" +// "bytes" "context" - "errors" +// "errors" "io/ioutil" "os" "testing" @@ -16,7 +16,7 @@ import ( func TestPersist(t *testing.T) { generateTestData(t) cfg := Config{ - OutputSize: 128, + OutputSize: 83, SessionId: "xyzzy", Root: "root", } @@ -31,27 +31,19 @@ func TestPersist(t *testing.T) { ca := cache.NewCache().WithCacheSize(1024) pr := persist.NewFsPersister(persistDir).WithContent(&st, ca) - w := bytes.NewBuffer(nil) + //w := bytes.NewBuffer(nil) + w := os.Stdout ctx := context.TODO() - - err = RunPersisted(cfg, rs, pr, []byte{}, w, ctx) + st = state.NewState(cfg.FlagCount) + ca = cache.NewCache() + ca = ca.WithCacheSize(cfg.CacheSize) + pr = persist.NewFsPersister(persistDir).WithContent(&st, ca) + err = pr.Save(cfg.SessionId) if err != nil { - if !errors.Is(err, os.ErrNotExist) { - t.Fatal(err) - } - st := state.NewState(cfg.FlagCount) - ca := cache.NewCache() - if cfg.CacheSize > 0 { - ca = ca.WithCacheSize(cfg.CacheSize) - } - pr = persist.NewFsPersister(persistDir).WithContent(&st, ca) - err = pr.Save(cfg.SessionId) - if err != nil { - t.Fatal(err) - } + t.Fatal(err) } - + pr = persist.NewFsPersister(persistDir) inputs := []string{ "", @@ -65,4 +57,20 @@ func TestPersist(t *testing.T) { t.Fatal(err) } } + + pr = persist.NewFsPersister(persistDir) + err = pr.Load(cfg.SessionId) + if err != nil { + t.Fatal(err) + } + + stAfter := pr.GetState() + location, idx := stAfter.Where() + if location != "long" { + t.Fatalf("expected 'long', got %s", location) + } + if idx != 1 { + t.Fatalf("expected '1', got %v", idx) + } + } diff --git a/persist/fs.go b/persist/fs.go @@ -68,7 +68,7 @@ func(p *FsPersister) Save(key string) error { return err } fp := path.Join(p.dir, key) - log.Printf("saved key %v", key) + log.Printf("saved key %v state %x", key, p.State.Code) return ioutil.WriteFile(fp, b, 0600) } @@ -80,6 +80,6 @@ func(p *FsPersister) Load(key string) error { return err } err = p.Deserialize(b) - log.Printf("loaded key %v", key) + log.Printf("loaded key %v state %x", key, p.State.Code) return err } diff --git a/resource/fs.go b/resource/fs.go @@ -39,6 +39,13 @@ func(fs FsResource) GetCode(sym string) ([]byte, error) { return ioutil.ReadFile(fp) } +func(fs *FsResource) AddLocalFunc(sym string, fn EntryFunc) { + if fs.fns == nil { + fs.fns = make(map[string]EntryFunc) + } + fs.fns[sym] = fn +} + func(fs FsResource) FuncFor(sym string) (EntryFunc, error) { fn, ok := fs.fns[sym] if ok { diff --git a/state/state.go b/state/state.go @@ -34,6 +34,7 @@ type State struct { BitSize uint32 // size of (32-bit capacity) bit flag byte array SizeIdx uint16 Flags []byte // Error state + Moves uint32 // Number of times navigation has been performed input []byte // Last input } @@ -208,6 +209,7 @@ func(st *State) Next() (uint16, error) { st.SizeIdx += 1 s, idx := st.Where() log.Printf("next page for %s: %v", s, idx) + st.Moves += 1 return st.SizeIdx, nil } @@ -224,6 +226,7 @@ func(st *State) Previous() (uint16, error) { st.SizeIdx -= 1 s, idx := st.Where() log.Printf("previous page for %s: %v", s, idx) + st.Moves += 1 return st.SizeIdx, nil } @@ -258,6 +261,7 @@ func(st *State) Top() (bool, error) { func(st *State) Down(input string) error { st.ExecPath = append(st.ExecPath, input) st.SizeIdx = 0 + st.Moves += 1 return nil } @@ -281,6 +285,7 @@ func(st *State) Up() (string, error) { } st.SizeIdx = 0 log.Printf("execpath after %v", st.ExecPath) + st.Moves += 1 return sym, nil } @@ -332,5 +337,5 @@ func(st *State) Reset() error { } func(st State) String() string { - return fmt.Sprintf("idx %v path: %s", st.SizeIdx, strings.Join(st.ExecPath, "/")) + return fmt.Sprintf("moves %v idx %v path: %s", st.Moves, st.SizeIdx, strings.Join(st.ExecPath, "/")) } diff --git a/vm/runner.go b/vm/runner.go @@ -182,10 +182,10 @@ func(vm *Vm) RunCatch(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } + b = append(bh, b...) vm.st.Down(sym) vm.ca.Push() vm.Reset() - b = append(bh, b...) } return b, nil } @@ -292,6 +292,7 @@ func(vm *Vm) RunInCmp(b []byte, ctx context.Context) ([]byte, error) { panic(err) } } else { + log.Printf("ignoring input %s, already have match", sym) return b, nil } } @@ -407,7 +408,7 @@ func(vm *Vm) Render(ctx context.Context) (string, error) { panic(err) } if !changed { - log.Printf("Render called when not dirty, please investigate.") + return "", nil } sym, idx := vm.st.Where() r, err := vm.pg.Render(sym, idx)