Add stateful render method to vm

This commit is contained in:
lash 2023-04-09 15:35:26 +01:00
parent 45de1f5c7a
commit 95bee7f8e0
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
7 changed files with 87 additions and 118 deletions

View File

@ -7,7 +7,6 @@ import (
"log"
"git.defalsify.org/festive/cache"
"git.defalsify.org/festive/render"
"git.defalsify.org/festive/resource"
"git.defalsify.org/festive/state"
"git.defalsify.org/festive/vm"
@ -23,7 +22,7 @@ type Engine struct {
st *state.State
rs resource.Resource
ca cache.Memory
pg render.Renderer
vm *vm.Vm
}
// NewEngine creates a new Engine
@ -32,6 +31,7 @@ func NewEngine(st *state.State, rs resource.Resource, ca cache.Memory) Engine {
st: st,
rs: rs,
ca: ca,
vm: vm.NewVm(st, rs, ca, nil),
}
return engine
}
@ -40,15 +40,12 @@ func NewEngine(st *state.State, rs resource.Resource, ca cache.Memory) Engine {
//
// It loads and executes code for the start node.
func(en *Engine) Init(sym string, ctx context.Context) error {
mn := render.NewMenu()
en.pg = render.NewPage(en.ca, en.rs).WithMenu(mn)
vmi := vm.NewVm(en.st, en.rs, en.ca, mn, nil)
err := en.st.SetInput([]byte{})
if err != nil {
return err
}
b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil)
b, err = vmi.Run(b, ctx)
b, err = en.vm.Run(b, ctx)
if err != nil {
return err
}
@ -75,9 +72,6 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
if err != nil {
return false, err
}
mn := render.NewMenu()
en.pg = render.NewPage(en.ca, en.rs).WithMenu(mn)
vmi := vm.NewVm(en.st, en.rs, en.ca, mn, en.pg)
log.Printf("new execution with input '%s' (0x%x)", input, input)
code, err := en.st.GetCode()
@ -87,7 +81,7 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
if len(code) == 0 {
return false, fmt.Errorf("no code to execute")
}
code, err = vmi.Run(code, ctx)
code, err = en.vm.Run(code, ctx)
if err != nil {
return false, err
}
@ -120,27 +114,11 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
// - the supplied writer fails to process the writes.
func(en *Engine) WriteResult(w io.Writer) error {
location, idx := en.st.Where()
v, err := en.ca.Get()
if err != nil {
return err
}
// r, err := en.rs.RenderTemplate(location, v, idx, nil)
// if err != nil {
// return err
// }
// m, err := en.rs.RenderMenu(idx)
// if err != nil {
// return err
// }
// if len(m) > 0 {
// r += "\n" + m
// }
r, err := en.pg.Render(location, v, idx)
r, err := en.vm.Render()
if err != nil {
return err
}
c, err := io.WriteString(w, r)
log.Printf("%v bytes written as result for %v", c, location)
en.pg = nil
log.Printf("%v bytes written as result for %v idx %v", c, location, idx)
return err
}

View File

@ -257,7 +257,9 @@ func(pg *Page) render(sym string, values map[string]string, idx uint16) (string,
return "", err
}
log.Printf("rendered %v bytes for menu", len(s))
r += "\n" + s
if len(s) > 0 {
r += "\n" + s
}
if pg.sizer != nil {
_, ok = pg.sizer.Check(r)
if !ok {
@ -267,9 +269,14 @@ func(pg *Page) render(sym string, values map[string]string, idx uint16) (string,
return r, nil
}
func(pg *Page) Render(sym string, values map[string]string, idx uint16) (string, error) {
func(pg *Page) Render(sym string, idx uint16) (string, error) {
var err error
values, err := pg.cache.Get()
if err != nil {
return "", err
}
values, err = pg.prepare(sym, values, idx)
if err != nil {
return "", err

View File

@ -1,7 +1 @@
package render
type Renderer interface {
Map(key string) error
Render(sym string, values map[string]string, idx uint16) (string, error)
Reset()
}

View File

@ -29,11 +29,6 @@ func(szr *Sizer) WithMenuSize(menuSize uint16) *Sizer {
}
func(szr *Sizer) Set(key string, size uint16) error {
var ok bool
_, ok = szr.memberSizes[key]
if ok {
return fmt.Errorf("already have key %s", key)
}
szr.memberSizes[key] = size
if size == 0 {
szr.sink = key

View File

@ -98,20 +98,13 @@ func TestSizeLimit(t *testing.T) {
mn.Put("1", "foo the foo")
mn.Put("2", "go to bar")
vals, err := ca.Get()
var err error
_, err = pg.Render("small", 0)
if err != nil {
t.Fatal(err)
}
_, err = pg.Render("small", vals, 0)
if err != nil {
t.Fatal(err)
}
mn.Put("1", "foo the foo")
mn.Put("2", "go to bar")
_, err = pg.Render("toobig", vals, 0)
_, err = pg.Render("toobig", 0)
if err == nil {
t.Fatalf("expected size exceeded")
}
@ -138,15 +131,10 @@ func TestSizePages(t *testing.T) {
pg.Map("baz")
pg.Map("xyzzy")
vals, err := ca.Get()
if err != nil {
t.Fatal(err)
}
mn.Put("1", "foo the foo")
mn.Put("2", "go to bar")
r, err := pg.Render("pages", vals, 0)
r, err := pg.Render("pages", 0)
if err != nil {
t.Fatal(err)
}
@ -163,7 +151,7 @@ lala poo
if r != expect {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, r)
}
r, err = pg.Render("pages", vals, 1)
r, err = pg.Render("pages", 1)
if err != nil {
t.Fatal(err)
}

View File

@ -14,19 +14,29 @@ import (
type Vm struct {
st *state.State
rs resource.Resource
pg render.Renderer
pg *render.Page
ca cache.Memory
mn *render.Menu
sizer *render.Sizer
}
func NewVm(st *state.State, rs resource.Resource, ca cache.Memory, mn *render.Menu, pg render.Renderer) *Vm {
return &Vm{
func NewVm(st *state.State, rs resource.Resource, ca cache.Memory, sizer *render.Sizer) *Vm {
vmi := &Vm{
st: st,
rs: rs,
pg: pg,
ca: ca,
mn: mn,
sizer: sizer,
}
vmi.Reset()
return vmi
}
func(vmi *Vm) Reset() {
vmi.mn = render.NewMenu()
vmi.pg = render.NewPage(vmi.ca, vmi.rs).WithMenu(vmi.mn)
if vmi.sizer != nil {
vmi.pg = vmi.pg.WithSizer(vmi.sizer)
}
}
@ -316,6 +326,16 @@ func(vm *Vm) RunMPrev(b []byte, ctx context.Context) ([]byte, error) {
return b, nil
}
func(vm *Vm) Render() (string, error) {
sym, idx := vm.st.Where()
r, err := vm.pg.Render(sym, idx)
if err != nil {
return "", err
}
vm.Reset()
return r, nil
}
// retrieve data for key
func refresh(key string, rs resource.Resource, ctx context.Context) (string, error) {
fn, err := rs.FuncFor(key)
@ -327,3 +347,4 @@ func refresh(key string, rs resource.Resource, ctx context.Context) (string, err
}
return fn(ctx)
}

View File

@ -46,6 +46,8 @@ func (r TestResource) GetTemplate(sym string) (string, error) {
return "inky pinky {{.baz}} blinky clyde", nil
case "three":
return "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}", nil
case "root":
return "root", nil
case "_catch":
return "aiee", nil
}
@ -85,7 +87,7 @@ func TestRun(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
vm := NewVm(&st, &rs, ca, nil, nil)
vm := NewVm(&st, &rs, ca, nil)
b := NewLine(nil, MOVE, []string{"foo"}, nil, nil)
b = NewLine(b, HALT, nil, nil, nil)
@ -105,59 +107,46 @@ func TestRunLoadRender(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
pg := render.NewPage(ca, rs)
vm := NewVm(&st, &rs, ca, nil, pg)
vm := NewVm(&st, &rs, ca, nil)
st.Down("barbarbar")
st.Down("bar")
var err error
b := NewLine(nil, LOAD, []string{"one"}, []byte{0x0a}, nil)
b = NewLine(b, LOAD, []string{"two"}, []byte{0x0a}, nil)
b = NewLine(b, HALT, nil, nil, nil)
b, err = vm.Run(b, context.TODO())
if err != nil {
t.Error(err)
t.Fatal(err)
}
m, err := ca.Get()
r, err := vm.Render()
if err != nil {
t.Error(err)
t.Fatal(err)
}
r, err := pg.RenderTemplate("foo", m, 0)
if err != nil {
t.Error(err)
}
expect := "inky pinky blinky clyde"
expect := "inky pinky one blinky two clyde"
if r != expect {
t.Errorf("Expected %v, got %v", []byte(expect), []byte(r))
}
r, err = pg.RenderTemplate("bar", m, 0)
if err == nil {
t.Errorf("expected error for render of bar: %v" ,err)
t.Fatalf("Expected\n\t%s\ngot\n\t%s\n", expect, r)
}
b = NewLine(nil, LOAD, []string{"two"}, []byte{0x0a}, nil)
b = NewLine(b, HALT, nil, nil, nil)
b, err = vm.Run(b, context.TODO())
if err != nil {
t.Error(err)
t.Fatal(err)
}
b = NewLine(nil, MAP, []string{"one"}, nil, nil)
b = NewLine(b, HALT, nil, nil, nil)
_, err = vm.Run(b, context.TODO())
if err != nil {
t.Error(err)
t.Fatal(err)
}
m, err = ca.Get()
r, err = vm.Render()
if err != nil {
t.Error(err)
}
r, err = pg.RenderTemplate("bar", m, 0)
if err != nil {
t.Error(err)
t.Fatal(err)
}
expect = "inky pinky one blinky two clyde"
if r != expect {
t.Errorf("Expected %v, got %v", expect, r)
t.Fatalf("Expected %v, got %v", expect, r)
}
}
@ -165,7 +154,7 @@ func TestRunMultiple(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
vm := NewVm(&st, &rs, ca, nil, nil)
vm := NewVm(&st, &rs, ca, nil)
b := NewLine(nil, MOVE, []string{"test"}, nil, nil)
b = NewLine(b, LOAD, []string{"one"}, []byte{0x00}, nil)
@ -184,8 +173,8 @@ func TestRunReload(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
pg := render.NewPage(ca, rs)
vm := NewVm(&st, &rs, ca, nil, pg)
szr := render.NewSizer(128)
vm := NewVm(&st, &rs, ca, szr)
b := NewLine(nil, MOVE, []string{"root"}, nil, nil)
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
@ -195,12 +184,13 @@ func TestRunReload(t *testing.T) {
if err != nil {
t.Fatal(err)
}
r, err := pg.Val("dyn")
r, err := vm.Render()
// r, err := pg.Val("dyn")
if err != nil {
t.Fatal(err)
}
if r != "three" {
t.Fatalf("expected result 'three', got %v", r)
if r != "root" {
t.Fatalf("expected result 'root', got %v", r)
}
dynVal = "baz"
b = NewLine(nil, RELOAD, []string{"dyn"}, nil, nil)
@ -209,21 +199,21 @@ func TestRunReload(t *testing.T) {
if err != nil {
t.Fatal(err)
}
r, err = pg.Val("dyn")
if err != nil {
t.Fatal(err)
}
log.Printf("dun now %s", r)
if r != "baz" {
t.Fatalf("expected result 'baz', got %v", r)
}
// r, err = pg.Val("dyn")
// if err != nil {
// t.Fatal(err)
// }
// log.Printf("dun now %s", r)
// if r != "baz" {
// t.Fatalf("expected result 'baz', got %v", r)
// }
}
func TestHalt(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
vm := NewVm(&st, &rs, ca, nil, nil)
vm := NewVm(&st, &rs, ca, nil)
b := NewLine(nil, MOVE, []string{"root"}, nil, nil)
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
@ -247,7 +237,7 @@ func TestRunArg(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
vm := NewVm(&st, &rs, ca, nil, nil)
vm := NewVm(&st, &rs, ca, nil)
input := []byte("bar")
_ = st.SetInput(input)
@ -272,8 +262,7 @@ func TestRunInputHandler(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
pg := render.NewPage(ca, rs)
vm := NewVm(&st, &rs, ca, nil, pg)
vm := NewVm(&st, &rs, ca, nil)
_ = st.SetInput([]byte("baz"))
@ -300,8 +289,7 @@ func TestRunArgInvalid(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
mn := render.NewMenu()
vm := NewVm(&st, &rs, ca, mn, nil)
vm := NewVm(&st, &rs, ca, nil)
_ = st.SetInput([]byte("foo"))
@ -324,8 +312,7 @@ func TestRunMenu(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
mn := render.NewMenu()
vm := NewVm(&st, &rs, ca, mn, nil)
vm := NewVm(&st, &rs, ca, nil)
var err error
@ -343,11 +330,11 @@ func TestRunMenu(t *testing.T) {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
r, err := mn.Render(0)
r, err := vm.Render()
if err != nil {
t.Fatal(err)
}
expect := "0:one\n1:two"
expect := "inky pinky blinky clyde\n0:one\n1:two"
if r != expect {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, r)
}
@ -358,8 +345,7 @@ func TestRunMenuBrowse(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
ca := cache.NewCache()
mn := render.NewMenu()
vm := NewVm(&st, &rs, ca, mn, nil)
vm := NewVm(&st, &rs, ca, nil)
var err error
@ -377,11 +363,11 @@ func TestRunMenuBrowse(t *testing.T) {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
r, err := mn.Render(0)
r, err := vm.Render()
if err != nil {
t.Fatal(err)
}
expect := "0:one\n1:two"
expect := "inky pinky blinky clyde\n0:one\n1:two"
if r != expect {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, r)
}