go-vise

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

commit 3dce006779c07ca77e3f9d44de93c4a550f799b6
parent bc0d9312f1a1489aff93d1aca5a0bd50b58e3388
Author: lash <dev@holbrook.no>
Date:   Wed, 18 Sep 2024 16:36:59 +0100

Add engine execution state to object, rehabilitate db example

Diffstat:
Mengine/db.go | 52+++++++++++++++++++++++++++++++++++++++++-----------
Mengine/db_test.go | 7+------
Mengine/engine.go | 7++++---
Mengine/engine_test.go | 24+++++++++++++++---------
Mengine/loop.go | 4++--
Mexamples/db/main.go | 2++
6 files changed, 65 insertions(+), 31 deletions(-)

diff --git a/engine/db.go b/engine/db.go @@ -1,6 +1,7 @@ package engine import ( + "bytes" "context" "errors" "fmt" @@ -27,6 +28,7 @@ type DefaultEngine struct { initd bool exit string exiting bool + execd bool regexCount int } @@ -260,8 +262,27 @@ func(en *DefaultEngine) setupVm() { en.vm = vm.NewVm(en.st, en.rs, en.ca, szr) } +func(en *DefaultEngine) empty(ctx context.Context) error { + var err error + b := bytes.NewBuffer(nil) + _, err = en.Flush(ctx, b) + if err != nil { + return err + } + logg.WarnCtxf(ctx, "discarding rendered output") + logg.DebugCtxf(ctx, "discard", "output", b.Bytes()) + return nil +} + // prepare engine for Init run. -func(en *DefaultEngine) prepare() error { +func(en *DefaultEngine) prepare(ctx context.Context) error { + if en.execd { + err := en.empty(ctx) + if err != nil { + return err + } + } + en.execd = false en.exit = "" en.exiting = false if en.initd { @@ -307,6 +328,7 @@ func(en *DefaultEngine) runFirst(ctx context.Context) (bool, error) { err = fmt.Errorf("Pre-VM code cannot have remaining bytecode after execution, had: %x", b) } else { if en.st.MatchFlag(state.FLAG_TERMINATE, true) { + en.execd = true en.exit = en.ca.Last() logg.InfoCtxf(ctx, "Pre-VM check says not to continue execution", "state", en.st) } else { @@ -366,8 +388,10 @@ func(en *DefaultEngine) restore() { } } -func(en *DefaultEngine) setCode(ctx context.Context, code []byte) error { +func(en *DefaultEngine) setCode(ctx context.Context, code []byte) (bool, error) { var err error + + cont := true en.st.SetCode(code) if len(code) == 0 { logg.Infof("runner finished with no remaining code", "state", en.st) @@ -376,15 +400,16 @@ func(en *DefaultEngine) setCode(ctx context.Context, code []byte) error { en.exiting = true en.exit = en.ca.Last() } + cont = false } - return err + return cont, err } // Init implements the Engine interface. // // It loads and executes code for the start node. func(en *DefaultEngine) init(ctx context.Context, input []byte) (bool, error) { - err := en.prepare() + err := en.prepare(ctx) if err != nil { return false, err } @@ -425,11 +450,12 @@ func(en *DefaultEngine) init(ctx context.Context, input []byte) (bool, error) { if err != nil { return false, err } + en.execd = true if en.dbg != nil { en.dbg.Break(en.st, en.ca) } logg.DebugCtxf(ctx, "end new init VM run", "code", b) - err = en.setCode(ctx, b) + cont, err := en.setCode(ctx, b) if err != nil { return false, err } @@ -439,14 +465,14 @@ func(en *DefaultEngine) init(ctx context.Context, input []byte) (bool, error) { return false, err } en.initd = true - return len(b) > 0, nil + return cont, nil } // Exec implements the Engine interface. // // It processes user input against the current state of the virtual machine environment. // -// If successfully executed, output of the last execution is available using the WriteResult call. +// If successfully executed, output of the last execution is available using the Flush call. // // A bool return valus of false indicates that execution should be terminated. Calling Exec again has undefined effects. // @@ -502,6 +528,7 @@ func(en *DefaultEngine) exec(ctx context.Context, input []byte) (bool, error) { if err != nil { return false, err } + en.execd = true logg.Debugf("end new VM run", "code", code) v := en.st.MatchFlag(state.FLAG_TERMINATE, true) @@ -511,15 +538,15 @@ func(en *DefaultEngine) exec(ctx context.Context, input []byte) (bool, error) { } return false, err } - err = en.setCode(ctx, code) + cont, err := en.setCode(ctx, code) if en.dbg != nil { en.dbg.Break(en.st, en.ca) } - return true, err + return cont, err } -// WriteResult implements the Engine interface. +// Flush implements the Engine interface. // // The method writes the output of the last vm execution to the given writer. // @@ -527,8 +554,11 @@ func(en *DefaultEngine) exec(ctx context.Context, input []byte) (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 *DefaultEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) { +func(en *DefaultEngine) Flush(ctx context.Context, w io.Writer) (int, error) { var l int + if !en.execd { + return 0, errors.New("Attempted flush on unexecuted engine") + } if en.st.Language != nil { ctx = context.WithValue(ctx, "Language", *en.st.Language) } diff --git a/engine/db_test.go b/engine/db_test.go @@ -201,11 +201,6 @@ func TestDbEngineRoot(t *testing.T) { t.Fatalf("expected loadfail") } - _, err = en.WriteResult(ctx, nul) - if err != nil { - t.Fatal(err) - } - cont, err = en.Exec(ctx, []byte{0x30}) if err == nil { t.Fatalf("expected nocode") @@ -246,7 +241,7 @@ func TestDbEnginePersist(t *testing.T) { t.Fatal(err) } - _, err = en.WriteResult(ctx, nul) + _, err = en.Flush(ctx, nul) if err != nil { t.Fatal(err) } diff --git a/engine/engine.go b/engine/engine.go @@ -11,9 +11,10 @@ type Engine interface { //Init(ctx context.Context) (bool, error) // Exec executes the pending bytecode. Exec(ctx context.Context, input []byte) (bool, error) - // WriteResult renders output according to the state of VM execution - // to the given io.Writer. - WriteResult(ctx context.Context, w io.Writer) (int, error) + // Flush renders output according to the state of VM execution + // to the given io.Writer, and prepares the engine for another + // VM execution. + Flush(ctx context.Context, w io.Writer) (int, error) // Finish must be called after the last call to Exec. Finish() error } diff --git a/engine/engine_test.go b/engine/engine_test.go @@ -141,7 +141,7 @@ func TestEngineInit(t *testing.T) { t.Fatal(err) } w := bytes.NewBuffer(nil) - _, err = en.WriteResult(ctx, w) + _, err = en.Flush(ctx, w) if err != nil { t.Fatal(err) } @@ -165,7 +165,7 @@ func TestEngineInit(t *testing.T) { t.Fatalf("expected where-string 'foo', got %s", r) } w = bytes.NewBuffer(nil) - _, err = en.WriteResult(ctx, w) + _, err = en.Flush(ctx, w) if err != nil { t.Fatal(err) } @@ -333,7 +333,7 @@ func TestLanguageRender(t *testing.T) { } br := bytes.NewBuffer(nil) - _, err = en.WriteResult(ctx, br) + _, err = en.Flush(ctx, br) if err != nil { t.Fatal(err) } @@ -376,7 +376,7 @@ func TestConfigLanguageRender(t *testing.T) { t.Fatal(err) } br := bytes.NewBuffer(nil) - _, err = en.WriteResult(ctx, br) + _, err = en.Flush(ctx, br) if err != nil { t.Fatal(err) } @@ -428,7 +428,7 @@ func TestPreVm(t *testing.T) { t.Fatalf("expected init to return 'not continue'") } out = bytes.NewBuffer(b) - _, err = en.WriteResult(ctx, out) + _, err = en.Flush(ctx, out) if err != nil { t.Fatal(err) } @@ -475,7 +475,10 @@ func TestManyQuits(t *testing.T) { if r { t.Fatalf("expected init to return 'not continue'") } - en.WriteResult(ctx, b) + _, err = en.Flush(ctx, b) + if err != nil { + t.Fatal(err) + } en = NewEngine(cfg, rs) en = en.WithState(st) @@ -487,7 +490,10 @@ func TestManyQuits(t *testing.T) { if r { t.Fatalf("expected init to return 'not continue'") } - en.WriteResult(ctx, b) + _, err = en.Flush(ctx, b) + if err != nil { + t.Fatal(err) + } en = NewEngine(cfg, rs) en = en.WithState(st) @@ -501,7 +507,7 @@ func TestManyQuits(t *testing.T) { } b = bytes.NewBuffer(nil) - _, err = en.WriteResult(ctx, b) + _, err = en.Flush(ctx, b) if err != nil { t.Fatal(err) } @@ -535,7 +541,7 @@ func TestOutEmpty(t *testing.T) { } v := bytes.NewBuffer(nil) - en.WriteResult(ctx, v) + en.Flush(ctx, v) x := "mmmm, something..." if !bytes.Equal(v.Bytes(), []byte(x)) { t.Fatalf("expected '%s', got '%s'", x, v.Bytes()) diff --git a/engine/loop.go b/engine/loop.go @@ -19,7 +19,7 @@ import ( // Rendered output is written to the provided writer. func Loop(ctx context.Context, en Engine, reader io.Reader, writer io.Writer) error { defer en.Finish() - l, err := en.WriteResult(ctx, writer) + l, err := en.Flush(ctx, writer) if err != nil { return err } @@ -43,7 +43,7 @@ func Loop(ctx context.Context, en Engine, reader io.Reader, writer io.Writer) er if err != nil { return fmt.Errorf("unexpected termination: %v\n", err) } - l, err := en.WriteResult(ctx, writer) + l, err := en.Flush(ctx, writer) if err != nil { return err } diff --git a/examples/db/main.go b/examples/db/main.go @@ -1,4 +1,6 @@ // Example: Use db.Db provider for all local data. +// +// BUG: This will be stuck on _catch if quit before first write. package main import (