diff --git a/go/asm/menu.go b/go/asm/menu.go index 13a2c2d..cf34dc4 100644 --- a/go/asm/menu.go +++ b/go/asm/menu.go @@ -71,9 +71,9 @@ func (mp *MenuProcessor) ToLines() []byte { case MENU_UP: postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, "_"}, nil, nil) case MENU_NEXT: - _ = postLines + postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, ">"}, nil, nil) case MENU_PREVIOUS: - _ = postLines + postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, "<"}, nil, nil) default: postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, v.target}, nil, nil) } @@ -82,5 +82,3 @@ func (mp *MenuProcessor) ToLines() []byte { preLines = vm.NewLine(preLines, vm.HALT, nil, nil, nil) return append(preLines, postLines...) } - - diff --git a/go/asm/menu_test.go b/go/asm/menu_test.go index 8f0d7e7..46e070a 100644 --- a/go/asm/menu_test.go +++ b/go/asm/menu_test.go @@ -40,6 +40,8 @@ MOUT 2 "blinky clyde" MOUT 99 "tinky-winky" HALT INCMP 0 foo +INCMP 1 > +INCMP 2 < INCMP 99 _ ` if r != expect { diff --git a/go/engine/engine.go b/go/engine/engine.go index 7c55520..5e0aa98 100644 --- a/go/engine/engine.go +++ b/go/engine/engine.go @@ -5,18 +5,12 @@ import ( "fmt" "io" "log" - "regexp" "git.defalsify.org/festive/resource" "git.defalsify.org/festive/state" "git.defalsify.org/festive/vm" ) -var ( - inputRegexStr = "^[a-zA-Z0-9].*$" - inputRegex = regexp.MustCompile(inputRegexStr) -) - //type Config struct { // FlagCount uint32 // CacheSize uint32 @@ -51,14 +45,6 @@ func(en *Engine) Init(sym string, ctx context.Context) error { return nil } -// return descriptive error if client input is invalid -func checkInput(input []byte) error { - if !inputRegex.Match(input) { - return fmt.Errorf("Input '%s' does not match format /%s/", input, inputRegexStr) - } - return nil -} - // Exec 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. @@ -70,7 +56,7 @@ func checkInput(input []byte) error { // - no current bytecode is available // - input processing against bytcode failed func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) { - err := checkInput(input) + err := vm.CheckInput(input) if err != nil { return true, err } diff --git a/go/resource/size_test.go b/go/resource/size_test.go index fd1eca0..d39bb39 100644 --- a/go/resource/size_test.go +++ b/go/resource/size_test.go @@ -61,6 +61,7 @@ func TestSizeLimit(t *testing.T) { rs := TestSizeResource{ mrs, } + st.Down("test") st.Add("foo", "inky", 4) st.Add("bar", "pinky", 10) st.Add("baz", "blinky", 0) @@ -107,6 +108,7 @@ func TestSizePages(t *testing.T) { rs := TestSizeResource{ mrs, } + st.Down("test") st.Add("foo", "inky", 4) st.Add("bar", "pinky", 10) st.Add("baz", "blinky", 20) diff --git a/go/state/state.go b/go/state/state.go index d593ea9..6d7f525 100644 --- a/go/state/state.go +++ b/go/state/state.go @@ -72,7 +72,7 @@ func NewState(bitSize uint32) State { } else { st.Flags = []byte{} } - st.Down("") + //st.Down("") return st } @@ -223,7 +223,6 @@ func(st *State) Down(input string) { st.resetCurrent() } - // Up removes the latest symbol to the command stack, and make the previous symbol current. // // Frees all symbols and associated values loaded at the previous stack level. Cache capacity is increased by the corresponding amount. @@ -231,10 +230,10 @@ func(st *State) Down(input string) { // Clears mapping and sink. // // Fails if called at top frame. -func(st *State) Up() error { +func(st *State) Up() (string, error) { l := len(st.Cache) if l == 0 { - return fmt.Errorf("exit called beyond top frame") + return "", fmt.Errorf("exit called beyond top frame") } l -= 1 m := st.Cache[l] @@ -245,8 +244,12 @@ func(st *State) Up() error { } st.Cache = st.Cache[:l] st.execPath = st.execPath[:l] + sym := "" + if len(st.execPath) > 0 { + sym = st.execPath[len(st.execPath)-1] + } st.resetCurrent() - return nil + return sym, nil } // Add adds a cache value under a cache symbol key. diff --git a/go/state/state_test.go b/go/state/state_test.go index 7ed746d..254195f 100644 --- a/go/state/state_test.go +++ b/go/state/state_test.go @@ -168,6 +168,7 @@ func TestStateCacheUse(t *testing.T) { func TestStateDownUp(t *testing.T) { st := NewState(17) st.Down("one") + st.Down("two") err := st.Add("foo", "bar", 0) if err != nil { t.Error(err) @@ -179,15 +180,21 @@ func TestStateDownUp(t *testing.T) { if st.CacheUseSize != 8 { t.Errorf("expected cache use size 8 got %v", st.CacheUseSize) } - err = st.Up() + s, err := st.Up() if err != nil { t.Error(err) } - err = st.Up() + if s != "one" { + t.Errorf("expected sym 'one', got '%s'", s) + } + s, err = st.Up() if err != nil { t.Error(err) } - err = st.Up() + if s != "" { + t.Errorf("expected sym '', got '%s'", s) + } + s, err = st.Up() if err == nil { t.Errorf("expected out of top frame error") } diff --git a/go/vm/debug.go b/go/vm/debug.go index 6b912a8..2e885bd 100644 --- a/go/vm/debug.go +++ b/go/vm/debug.go @@ -129,22 +129,6 @@ func ParseAll(b []byte, w io.Writer) (int, error) { rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v) } } - case MNEXT: - r, v, bb, err := ParseMNext(b) - b = bb - if err == nil { - if w != nil { - rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v) - } - } - case MPREV: - r, v, bb, err := ParseMPrev(b) - b = bb - if err == nil { - if w != nil { - rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v) - } - } } if err != nil { return rn, err diff --git a/go/vm/debug_test.go b/go/vm/debug_test.go index 7afd303..3605b10 100644 --- a/go/vm/debug_test.go +++ b/go/vm/debug_test.go @@ -91,26 +91,6 @@ func TestToString(t *testing.T) { t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r) } - b = NewLine(nil, MNEXT, []string{"11", "nextmenu"}, nil, nil) - r, err = ToString(b) - if err != nil { - t.Fatal(err) - } - expect = "MNEXT 11 \"nextmenu\"\n" - if r != expect { - t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r) - } - - b = NewLine(nil, MPREV, []string{"222", "previous menu item"}, nil, nil) - r, err = ToString(b) - if err != nil { - t.Fatal(err) - } - expect = "MPREV 222 \"previous menu item\"\n" - if r != expect { - t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r) - } - b = NewLine(nil, MOUT, []string{"1", "foo"}, nil, nil) r, err = ToString(b) if err != nil { diff --git a/go/vm/input.go b/go/vm/input.go new file mode 100644 index 0000000..78b4369 --- /dev/null +++ b/go/vm/input.go @@ -0,0 +1,52 @@ +package vm + +import ( + "context" + "fmt" + "regexp" + + "git.defalsify.org/festive/state" +) + +var ( + inputRegexStr = "^[a-zA-Z0-9].*$" + inputRegex = regexp.MustCompile(inputRegexStr) + ctrlInputRegexStr = "^[<>_]$" + ctrlInputRegex = regexp.MustCompile(inputRegexStr) +) + + +func CheckInput(input []byte) error { + if !inputRegex.Match(input) { + return fmt.Errorf("Input '%s' does not match format /%s/", input, inputRegexStr) + } + return nil +} + +func applyControlInput(input []byte, st *state.State, ctx context.Context) (string, error) { + var err error + sym, idx := st.Where() + switch input[0] { + case '_': + sym, err = st.Up() + if err != nil { + return sym, err + } + } + _ = idx + return sym, nil +} + +func ApplyInput(inputString string, st *state.State, ctx context.Context) (string, error) { + input := []byte(inputString) + if ctrlInputRegex.Match(input) { + return applyControlInput(input, st, ctx) + } + + err := CheckInput(input) + if err != nil { + return "", err + } + st.Down(inputString) + return inputString, nil +} diff --git a/go/vm/opcodes.go b/go/vm/opcodes.go index 77855b8..9072b1a 100644 --- a/go/vm/opcodes.go +++ b/go/vm/opcodes.go @@ -17,9 +17,7 @@ const ( INCMP = 8 MSIZE = 9 MOUT = 10 - MNEXT = 11 - MPREV = 12 - _MAX = 12 + _MAX = 10 ) var ( @@ -35,8 +33,6 @@ var ( INCMP: "INCMP", MSIZE: "MSIZE", MOUT: "MOUT", - MNEXT: "MNEXT", - MPREV: "MPREV", } OpcodeIndex = map[string]Opcode { @@ -51,8 +47,6 @@ var ( "INCMP": INCMP, "MSIZE": MSIZE, "MOUT": MOUT, - "MNEXT": MNEXT, - "MPREV": MPREV, } ) diff --git a/go/vm/runner.go b/go/vm/runner.go index 4ae2468..c8b7ae8 100644 --- a/go/vm/runner.go +++ b/go/vm/runner.go @@ -44,10 +44,6 @@ func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ( b, err = RunMSize(b, st, rs, ctx) case MOUT: b, err = RunMOut(b, st, rs, ctx) - case MNEXT: - b, err = RunMNext(b, st, rs, ctx) - case MPREV: - b, err = RunMPrev(b, st, rs, ctx) case HALT: b, err = RunHalt(b, st, rs, ctx) return b, err @@ -245,26 +241,6 @@ func RunMSize(b []byte, st *state.State, rs resource.Resource, ctx context.Conte return b, err } -// RunMNext executes the MNEXT opcode -func RunMNext(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { - selector, display, b, err := ParseMNext(b) - if err != nil { - return b, err - } - err = rs.SetMenuBrowse(selector, display, false) - return b, err -} - -// RunMPrev executes the MPREV opcode -func RunMPrev(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { - selector, display, b, err := ParseMPrev(b) - if err != nil { - return b, err - } - err = rs.SetMenuBrowse(selector, display, false) - return b, err -} - // RunMOut executes the MOUT opcode func RunMOut(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { choice, title, b, err := ParseMOut(b) diff --git a/go/vm/runner_test.go b/go/vm/runner_test.go index 5be3bd7..ecbbf01 100644 --- a/go/vm/runner_test.go +++ b/go/vm/runner_test.go @@ -160,7 +160,8 @@ func TestRunLoadRender(t *testing.T) { func TestRunMultiple(t *testing.T) { st := state.NewState(5) rs := TestResource{} - b := NewLine(nil, LOAD, []string{"one"}, []byte{0x00}, nil) + 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 := Run(b, &st, &rs, context.TODO()) @@ -211,7 +212,8 @@ func TestRunReload(t *testing.T) { func TestHalt(t *testing.T) { st := state.NewState(5) rs := TestResource{} - b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0}) + b := NewLine(nil, MOVE, []string{"root"}, nil, nil) + b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0}) b = NewLine(b, HALT, nil, nil, nil) b = NewLine(b, MOVE, []string{"foo"}, nil, nil) var err error @@ -336,8 +338,6 @@ func TestRunMenuBrowse(t *testing.T) { var err error b := NewLine(nil, MOVE, []string{"foo"}, nil, nil) - b = NewLine(b, MNEXT, []string{"11", "two"}, nil, nil) - b = NewLine(b, MPREV, []string{"22", "two"}, 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)