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:
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())
+ }
+
+}