From 4da19b30479d145a469b61489277d88988cb547a Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 12 Apr 2023 08:30:35 +0100 Subject: [PATCH] Catch beyond index error in browse --- go/cache/cache.go | 1 - go/engine/engine.go | 4 ++-- go/engine/engine_test.go | 4 ++-- go/engine/loop.go | 4 ++-- go/render/menu.go | 12 +++++++++++- go/render/page.go | 17 +---------------- go/vm/runner.go | 11 ++++++++++- go/vm/runner_test.go | 33 ++++++++++++++++++++------------- 8 files changed, 48 insertions(+), 38 deletions(-) diff --git a/go/cache/cache.go b/go/cache/cache.go index 049605b..194f076 100644 --- a/go/cache/cache.go +++ b/go/cache/cache.go @@ -136,7 +136,6 @@ func(ca *Cache) Reset() { func (ca *Cache) Push() error { m := make(map[string]string) ca.Cache = append(ca.Cache, m) - //ca.resetCurrent() return nil } diff --git a/go/engine/engine.go b/go/engine/engine.go index 24399d4..27c2237 100644 --- a/go/engine/engine.go +++ b/go/engine/engine.go @@ -118,8 +118,8 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (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 *Engine) WriteResult(w io.Writer) error { - r, err := en.vm.Render() +func(en *Engine) WriteResult(w io.Writer, ctx context.Context) error { + r, err := en.vm.Render(ctx) if err != nil { return err } diff --git a/go/engine/engine_test.go b/go/engine/engine_test.go index 90e3c25..a1c72b3 100644 --- a/go/engine/engine_test.go +++ b/go/engine/engine_test.go @@ -82,7 +82,7 @@ func TestEngineInit(t *testing.T) { } w := bytes.NewBuffer(nil) - err = en.WriteResult(w) + err = en.WriteResult(w, ctx) if err != nil { t.Fatal(err) } @@ -105,7 +105,7 @@ func TestEngineInit(t *testing.T) { t.Fatalf("expected where-string 'foo', got %s", r) } w = bytes.NewBuffer(nil) - err = en.WriteResult(w) + err = en.WriteResult(w, ctx) if err != nil { t.Fatal(err) } diff --git a/go/engine/loop.go b/go/engine/loop.go index c509f12..88eb137 100644 --- a/go/engine/loop.go +++ b/go/engine/loop.go @@ -17,7 +17,7 @@ func Loop(en *Engine, startSym string, ctx context.Context, reader io.Reader, wr } b := bytes.NewBuffer(nil) - en.WriteResult(b) + en.WriteResult(b, ctx) fmt.Println(b.String()) running := true @@ -37,7 +37,7 @@ func Loop(en *Engine, startSym string, ctx context.Context, reader io.Reader, wr return fmt.Errorf("unexpected termination: %v\n", err) } //b := bytes.NewBuffer(nil) - err = en.WriteResult(writer) + err = en.WriteResult(writer, ctx) if err != nil { return err } diff --git a/go/render/menu.go b/go/render/menu.go index ce2686f..e6c5da9 100644 --- a/go/render/menu.go +++ b/go/render/menu.go @@ -4,6 +4,15 @@ import ( "fmt" ) +type BrowseError struct { + Idx uint16 + PageCount uint16 +} + +func(err *BrowseError) Error() string { + return fmt.Sprintf("index is out of bounds: %v", err.Idx) +} + // BrowseConfig defines the availability and display parameters for page browsing. type BrowseConfig struct { NextAvailable bool @@ -112,7 +121,8 @@ func(m *Menu) applyPage(idx uint16) error { } return nil } else if idx >= m.pageCount { - return fmt.Errorf("index %v out of bounds (%v)", idx, m.pageCount) + return &BrowseError{Idx: idx, PageCount: m.pageCount} + //return fmt.Errorf("index %v out of bounds (%v)", idx, m.pageCount) } m.reset() diff --git a/go/render/page.go b/go/render/page.go index e7ce682..9c0396a 100644 --- a/go/render/page.go +++ b/go/render/page.go @@ -307,20 +307,6 @@ func(pg *Page) render(sym string, values map[string]string, idx uint16) (string, return "", fmt.Errorf("limit exceeded: %v", pg.sizer) } } -// s, err = pg.menu.Render(idx) -// if err != nil { -// return "", err -// } -// log.Printf("rendered %v bytes for menu", len(s)) -// if len(s) > 0 { -// r += "\n" + s -// } -// if pg.sizer != nil { -// _, ok = pg.sizer.Check(r) -// if !ok { -// return "", fmt.Errorf("limit exceeded: %v", pg.sizer) -// } -// } return r, nil } @@ -332,12 +318,11 @@ func(pg *Page) Render(sym string, idx uint16) (string, error) { return "", err } - log.Printf("nosink %v", values) return pg.render(sym, values, idx) } func(pg *Page) Reset() { pg.sink = nil pg.sinkSize = 0 - //pg.cacheMap = make(map[string]string) + pg.cacheMap = make(map[string]string) } diff --git a/go/vm/runner.go b/go/vm/runner.go index 44bae55..17a3e44 100644 --- a/go/vm/runner.go +++ b/go/vm/runner.go @@ -383,7 +383,7 @@ func(vm *Vm) RunMPrev(b []byte, ctx context.Context) ([]byte, error) { return b, nil } -func(vm *Vm) Render() (string, error) { +func(vm *Vm) Render(ctx context.Context) (string, error) { changed, err := vm.st.ResetFlag(state.FLAG_DIRTY) if err != nil { panic(err) @@ -393,6 +393,15 @@ func(vm *Vm) Render() (string, error) { } sym, idx := vm.st.Where() r, err := vm.pg.Render(sym, idx) + var ok bool + _, ok = err.(*render.BrowseError) + if ok { + vm.Reset() + b := NewLine(nil, MOVE, []string{"_catch"}, nil, nil) + vm.Run(b, ctx) + sym, idx := vm.st.Where() + r, err = vm.pg.Render(sym, idx) + } if err != nil { return "", err } diff --git a/go/vm/runner_test.go b/go/vm/runner_test.go index 6d550b2..72677bf 100644 --- a/go/vm/runner_test.go +++ b/go/vm/runner_test.go @@ -112,16 +112,17 @@ func TestRunLoadRender(t *testing.T) { st.Down("bar") var err error + ctx := context.TODO() b := NewLine(nil, LOAD, []string{"one"}, []byte{0x0a}, nil) b = NewLine(b, MAP, []string{"one"}, nil, nil) b = NewLine(b, LOAD, []string{"two"}, []byte{0x0a}, nil) b = NewLine(b, MAP, []string{"two"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - b, err = vm.Run(b, context.TODO()) + b, err = vm.Run(b, ctx) if err != nil { t.Fatal(err) } - r, err := vm.Render() + r, err := vm.Render(ctx) if err != nil { t.Fatal(err) } @@ -133,17 +134,17 @@ func TestRunLoadRender(t *testing.T) { b = NewLine(nil, LOAD, []string{"two"}, []byte{0x0a}, nil) b = NewLine(b, MAP, []string{"two"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - b, err = vm.Run(b, context.TODO()) + b, err = vm.Run(b, ctx) if err != nil { t.Fatal(err) } b = NewLine(nil, MAP, []string{"one"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - _, err = vm.Run(b, context.TODO()) + _, err = vm.Run(b, ctx) if err != nil { t.Fatal(err) } - r, err = vm.Render() + r, err = vm.Render(ctx) if err != nil { t.Fatal(err) } @@ -159,11 +160,12 @@ func TestRunMultiple(t *testing.T) { ca := cache.NewCache() vm := NewVm(&st, &rs, ca, nil) + ctx := context.TODO() b := NewLine(nil, MOVE, []string{"test"}, nil, nil) b = NewLine(b, LOAD, []string{"one"}, []byte{0x00}, nil) b = NewLine(b, LOAD, []string{"two"}, []byte{42}, nil) b = NewLine(b, HALT, nil, nil, nil) - b, err := vm.Run(b, context.TODO()) + b, err := vm.Run(b, ctx) if err != nil { t.Error(err) } @@ -179,15 +181,16 @@ func TestRunReload(t *testing.T) { szr := render.NewSizer(128) vm := NewVm(&st, &rs, ca, szr) + ctx := context.TODO() b := NewLine(nil, MOVE, []string{"root"}, nil, nil) b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0}) b = NewLine(b, MAP, []string{"dyn"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - _, err := vm.Run(b, context.TODO()) + _, err := vm.Run(b, ctx) if err != nil { t.Fatal(err) } - r, err := vm.Render() + r, err := vm.Render(ctx) if err != nil { t.Fatal(err) } @@ -197,7 +200,7 @@ func TestRunReload(t *testing.T) { dynVal = "baz" b = NewLine(nil, RELOAD, []string{"dyn"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - _, err = vm.Run(b, context.TODO()) + _, err = vm.Run(b, ctx) if err != nil { t.Fatal(err) } @@ -310,12 +313,14 @@ func TestRunMenu(t *testing.T) { var err error + ctx := context.TODO() + b := NewLine(nil, MOVE, []string{"foo"}, nil, nil) b = NewLine(b, MOUT, []string{"0", "one"}, nil, nil) b = NewLine(b, MOUT, []string{"1", "two"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - b, err = vm.Run(b, context.TODO()) + b, err = vm.Run(b, ctx) if err != nil { t.Error(err) } @@ -324,7 +329,7 @@ func TestRunMenu(t *testing.T) { t.Errorf("expected empty remainder, got length %v: %v", l, b) } - r, err := vm.Render() + r, err := vm.Render(ctx) if err != nil { t.Fatal(err) } @@ -343,12 +348,14 @@ func TestRunMenuBrowse(t *testing.T) { var err error + ctx := context.TODO() + b := NewLine(nil, MOVE, []string{"foo"}, nil, nil) b = NewLine(b, MOUT, []string{"0", "one"}, nil, nil) b = NewLine(b, MOUT, []string{"1", "two"}, nil, nil) b = NewLine(b, HALT, nil, nil, nil) - b, err = vm.Run(b, context.TODO()) + b, err = vm.Run(b, ctx) if err != nil { t.Error(err) } @@ -357,7 +364,7 @@ func TestRunMenuBrowse(t *testing.T) { t.Errorf("expected empty remainder, got length %v: %v", l, b) } - r, err := vm.Render() + r, err := vm.Render(ctx) if err != nil { t.Fatal(err) }