go-vise

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

commit f76b61018ff96e5d2ce5971752eb3f3cc69176a8
parent d1f6647211ac99bd619dcbafd04491ff40270241
Author: lash <dev@holbrook.no>
Date:   Sat, 15 Mar 2025 02:10:06 +0000

Add load error sym to debug output

Diffstat:
MCHANGELOG | 3+++
Mengine/config.go | 2--
Mengine/db.go | 5+++--
Mengine/db_test.go | 26--------------------------
Mstate/state.go | 4++--
Mvm/runner.go | 12+++++++++++-
Mvm/runner_test.go | 35+++++++++++++++++++++++++++++++++++
7 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,6 @@ +- 0.4.0 + * Add state debug output on loadfail. + * Store last failed symbol in vm for debug. - 0.3.0 * Remove db prefix from data dumper results. * Add transactional interface for db. diff --git a/engine/config.go b/engine/config.go @@ -20,8 +20,6 @@ type Config struct { Language string // StateDebug activates string translations of flags in output logs if set StateDebug bool - // EngineDebug activates the engine debug output - EngineDebug bool // MenuSeparator sets the string to use for separating menu selectors and menu descriptors in the renderer MenuSeparator string // ResetOnEmptyInput purges cache and restart state execution at root on empty input diff --git a/engine/db.go b/engine/db.go @@ -524,13 +524,14 @@ func (en *DefaultEngine) exec(ctx context.Context, input []byte) (bool, error) { return false, fmt.Errorf("no code to execute") } - logg.Debugf("start new VM run", "code", code) + logg.Debugf("start VM run", "code", code) code, err = en.vm.Run(ctx, code) if err != nil { + logg.ErrorCtxf(ctx, "fail VM run with state", "code", en.st.Code, "state", en.st.String(), "vm", en.vm) return false, err } en.execd = true - logg.Debugf("end new VM run", "code", code) + logg.Debugf("end VM run", "code", code, "state", en.st.String(), "vm", en.vm) v := en.st.MatchFlag(state.FLAG_TERMINATE, true) if v { diff --git a/engine/db_test.go b/engine/db_test.go @@ -1,7 +1,6 @@ package engine import ( - "bytes" "context" "fmt" "io" @@ -263,31 +262,6 @@ func TestDbEnginePersist(t *testing.T) { } } -func TestDbEngineDebug(t *testing.T) { - w := bytes.NewBuffer(nil) - ctx := context.Background() - cfg := Config{ - Root: "tinkywinky", - FlagCount: 1, - } - rs := resource.NewMenuResource() - rs = rs.WithCodeGetter(codeGet) - rs.AddLocalFunc("foo", flagSet) - dbg := NewSimpleDebug(w) - en := NewEngine(cfg, rs).WithDebug(dbg) - //c, err := en.Init(ctx) - c, err := en.Exec(ctx, []byte{}) - if err != nil { - t.Fatal(err) - } - if !c { - t.Fatal("expected true") - } - if len(w.Bytes()) == 0 { - t.Fatal("expected non-empty debug") - } -} - func TestDbConfigString(t *testing.T) { cfg := Config{ Root: "tinkywinky", diff --git a/state/state.go b/state/state.go @@ -41,8 +41,8 @@ type State struct { Language *lang.Language // Language selector for rendering input []byte // Last input debug bool // Make string representation more human friendly - invalid bool - lastMove uint8 + invalid bool // True if state is corrupted and should not be persisted. + lastMove uint8 // Last menu move direction } // number of bytes necessary to represent a bitfield of the given size. diff --git a/vm/runner.go b/vm/runner.go @@ -47,6 +47,7 @@ type Vm struct { sizer *render.Sizer // Apply size constraints to output. pg *render.Page // Render outputs with menues to size constraints menuSeparator string // Passed to Menu.WithSeparator if not empty + last string // Last failed LOAD/RELOAD attempt } // NewVm creates a new Vm. @@ -63,6 +64,14 @@ func NewVm(st *state.State, rs resource.Resource, ca cache.Memory, sizer *render return vmi } +func (vmi *Vm) String() string { + s, _ := vmi.st.Where() + if s != "_catch" { + return fmt.Sprintf("vm (%p) ok", vmi) + } + return fmt.Sprintf("vm (%p) error load: %s", vmi, vmi.last) +} + // WithMenuSeparator is a chainable function that sets the separator string to use // in the menu renderer. func (vmi *Vm) WithMenuSeparator(sep string) *Vm { @@ -110,6 +119,7 @@ func Rewind(sym string, st *state.State, ca cache.Memory) (string, error) { func (vm *Vm) Run(ctx context.Context, b []byte) ([]byte, error) { logg.Tracef("new vm run") running := true + vm.last = "" for running { r := vm.st.MatchFlag(state.FLAG_TERMINATE, true) if r { @@ -507,7 +517,7 @@ func (vm *Vm) Render(ctx context.Context) (string, error) { // retrieve and cache data for key func (vm *Vm) refresh(key string, rs resource.Resource, ctx context.Context) (string, error) { var err error - + vm.last = key fn, err := rs.FuncFor(ctx, key) if err != nil { return "", err diff --git a/vm/runner_test.go b/vm/runner_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "log" + "strings" "testing" "git.defalsify.org/vise.git/cache" @@ -833,3 +834,37 @@ func TestBatchRun(t *testing.T) { t.Fatal(err) } } + +func TestErrorOut(t *testing.T) { + var err error + ctx := context.Background() + st := state.NewState(0) + ca := cache.NewCache() + rs := newTestResource(st) + rs.AddLocalFunc("foo", getTwo) + rs.AddLocalFunc("aiee", uhOh) + rs.Lock() + b := NewLine(nil, LOAD, []string{"two"}, []byte{0x01, 0x10}, nil) + vm := NewVm(st, rs, ca, nil) + b, err = vm.Run(ctx, b) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(vm.String(), " ok") { + t.Fatalf("expected ok, got %s", vm.String()) + } + + st = state.NewState(0) + ca = cache.NewCache() + b = NewLine(nil, LOAD, []string{"aiee"}, []byte{0x01, 0x10}, nil) + b = NewLine(b, HALT, nil, nil, nil) + vm = NewVm(st, rs, ca, nil) + b, err = vm.Run(ctx, b) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(vm.String(), ") error load: aiee") { + t.Fatalf("expected load fail aiee in vm string, got %s", vm.String()) + } + +}