commit 856bbdeb6317e8c28b46b828f2357c50f5d0f785
parent 5a63b24ec1c59d83779daa3adf870de620e63f63
Author: lash <dev@holbrook.no>
Date:   Mon,  3 Apr 2023 08:22:01 +0100
Add menu interpreter
Diffstat:
2 files changed, 122 insertions(+), 0 deletions(-)
diff --git a/go/vm/interpreter.go b/go/vm/interpreter.go
@@ -0,0 +1,76 @@
+package vm
+
+import (
+	"fmt"
+)
+
+type BatchCode uint16
+
+const (
+	MENU_DOWN = 256
+	MENU_UP = 257
+	MENU_NEXT = 258
+	MENU_PREVIOUS = 259
+)
+
+var (
+	batchCode = map[string]BatchCode{
+		"DOWN": MENU_DOWN,
+		"UP": MENU_UP,
+		"NEXT": MENU_NEXT,
+		"PREVIOUS": MENU_PREVIOUS,
+	}
+)
+
+type menuItem struct {
+	code BatchCode
+	choice string
+	display string
+	target string
+}
+
+type MenuProcessor struct {
+	items []menuItem
+	size uint32
+}
+
+func NewMenuProcessor() MenuProcessor {
+	return MenuProcessor{}
+}
+
+func(mp *MenuProcessor) Add(bop string, choice string, display string, target string) error {
+	bopCode := batchCode[bop]
+	if bopCode == 0 {
+		return fmt.Errorf("unknown menu instruction: %v", bop)
+	}
+	m := menuItem{
+		code: bopCode,
+		choice: choice,
+		display: display,
+		target: target,
+	}
+	mp.items = append(mp.items, m)
+	return nil
+}
+
+func (mp *MenuProcessor) ToLines() []byte {
+	preLines := []byte{}
+	postLines := []byte{}
+
+	for _, v := range mp.items {
+		preLines = NewLine(preLines, MOUT, []string{v.choice, v.display}, nil, nil)
+		switch v.code {
+		case MENU_UP:
+			postLines = NewLine(postLines, INCMP, []string{v.choice, "_"}, nil, nil)
+		case MENU_NEXT:
+			_ = postLines
+		case MENU_PREVIOUS:
+			_ = postLines
+		default:
+			postLines = NewLine(postLines, INCMP, []string{v.choice, v.target}, nil, nil)
+		}
+	}
+
+	preLines = NewLine(preLines, HALT, nil, nil, nil)
+	return append(preLines, postLines...)
+}
diff --git a/go/vm/interpreter_test.go b/go/vm/interpreter_test.go
@@ -0,0 +1,46 @@
+package vm
+
+import (
+	"testing"
+)
+
+
+func TestMenuInterpreter(t *testing.T) {
+	m := NewMenuProcessor()
+	err := m.Add("DOWN", "0", "inky", "foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = m.Add("NEXT", "1", "pinky", "bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = m.Add("PREVIOUS", "2", "blinky clyde", "baz")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = m.Add("UP", "99", "tinky-winky", "xyzzy")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = m.Add("BOGUS", "42", "lala poo", "plugh")
+	if err == nil {
+		t.Errorf("expected error on invalid menu item 'BOGUS'")
+	}
+	b := m.ToLines()
+	r, err := ToString(b)
+	if err != nil {
+		t.Fatal(err)
+	}
+	expect := `MOUT 0 "inky"
+MOUT 1 "pinky"
+MOUT 2 "blinky clyde"
+MOUT 99 "tinky-winky"
+HALT
+INCMP 0 foo
+INCMP 99 _
+`
+	if r != expect {
+		t.Errorf("expected:\n\t%v\ngot:\n\t%v\n", expect, r)
+	}
+}