commit 6221e1dce2fb16c9518e452ab9d3ad027c8047eb
parent a8a6adbe6c268ec9c23d72cf213e32da6a913847
Author: lash <dev@holbrook.no>
Date: Sat, 8 Apr 2023 08:14:14 +0100
Use INCMP for lateral move, new input vm mod file
Diffstat:
12 files changed, 82 insertions(+), 98 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)