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:
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 (