diff --git a/go/state/flag.go b/go/state/flag.go index 611ed6d..2634c8e 100644 --- a/go/state/flag.go +++ b/go/state/flag.go @@ -3,4 +3,5 @@ package state const ( FLAG_INMATCH = 1 FLAG_TERMINATE = 2 + FLAG_DIRTY = 4 ) diff --git a/go/state/state.go b/go/state/state.go index 5f21436..73e0aa6 100644 --- a/go/state/state.go +++ b/go/state/state.go @@ -3,6 +3,7 @@ package state import ( "fmt" "log" + "strings" ) // State holds the command stack, error condition of a unique execution session. @@ -261,12 +262,14 @@ func(st *State) Up() (string, error) { if l == 0 { return "", fmt.Errorf("exit called beyond top frame") } + log.Printf("execpath before %v", st.execPath) st.execPath = st.execPath[:l-1] sym := "" if len(st.execPath) > 0 { sym = st.execPath[len(st.execPath)-1] } st.sizeIdx = 0 + log.Printf("execpath after %v", st.execPath) return sym, nil } @@ -316,3 +319,7 @@ func(st *State) SetInput(input []byte) error { // Reset to initial state (start navigation over). func(st *State) Reset() { } + +func(st State) String() string { + return fmt.Sprintf("path: %s", strings.Join(st.execPath, "/")) +} diff --git a/go/testdata/testdata.go b/go/testdata/testdata.go index 2905572..d7a7154 100644 --- a/go/testdata/testdata.go +++ b/go/testdata/testdata.go @@ -70,7 +70,7 @@ func foo() error { b = vm.NewLine(b, vm.HALT, nil, nil, nil) b = vm.NewLine(b, vm.INCMP, []string{"0", "_"}, nil, nil) b = vm.NewLine(b, vm.INCMP, []string{"1", "baz"}, nil, nil) - b = vm.NewLine(b, vm.CATCH, []string{"_catch"}, []byte{1}, []uint8{1}) + //b = vm.NewLine(b, vm.CATCH, []string{"_catch"}, []byte{1}, []uint8{1}) data := make(map[string]string) data["inky"] = "one" @@ -86,7 +86,7 @@ func bar() error { b := []byte{} b = vm.NewLine(b, vm.LOAD, []string{"pinky"}, []byte{0}, nil) b = vm.NewLine(b, vm.HALT, nil, nil, nil) - b = vm.NewLine(b, vm.INCMP, []string{"0", "_home"}, nil, nil) + b = vm.NewLine(b, vm.INCMP, []string{"*", "^"}, nil, nil) tpl := "this is bar - an end node" @@ -110,7 +110,7 @@ func defaultCatch() error { b := []byte{} b = vm.NewLine(b, vm.MOUT, []string{"0", "back"}, nil, nil) b = vm.NewLine(b, vm.HALT, nil, nil, nil) - b = vm.NewLine(b, vm.MOVE, []string{"_"}, nil, nil) + b = vm.NewLine(b, vm.INCMP, []string{"*", "_"}, nil, nil) tpl := "invalid input" diff --git a/go/vm/input.go b/go/vm/input.go index 9245bdf..a927d5d 100644 --- a/go/vm/input.go +++ b/go/vm/input.go @@ -5,13 +5,14 @@ import ( "fmt" "regexp" + "git.defalsify.org/festive/cache" "git.defalsify.org/festive/state" ) var ( inputRegexStr = "^[a-zA-Z0-9].*$" inputRegex = regexp.MustCompile(inputRegexStr) - ctrlRegexStr = "^[><_]$" + ctrlRegexStr = "^[><_^]$" ctrlRegex = regexp.MustCompile(ctrlRegexStr) symRegexStr = "^[a-zA-Z0-9][a-zA-Z0-9_]+$" symRegex = regexp.MustCompile(symRegexStr) @@ -90,7 +91,7 @@ func CheckTarget(target []byte, st *state.State) (bool, error) { } // route parsed target symbol to navigation state change method, -func applyTarget(target []byte, st *state.State, ctx context.Context) (string, uint16, error) { +func applyTarget(target []byte, st *state.State, ca cache.Memory, ctx context.Context) (string, uint16, error) { var err error sym, idx := st.Where() @@ -102,6 +103,7 @@ func applyTarget(target []byte, st *state.State, ctx context.Context) (string, u switch target[0] { case '_': sym, err = st.Up() + ca.Pop() if err != nil { return sym, idx, err } @@ -115,9 +117,15 @@ func applyTarget(target []byte, st *state.State, ctx context.Context) (string, u if err != nil { return sym, idx, err } + case '^': + _, err := st.SetFlag(state.FLAG_TERMINATE) + if err != nil { + return sym, idx, err + } default: sym = string(target) st.Down(sym) + ca.Push() idx = 0 } return sym, idx, nil diff --git a/go/vm/runner.go b/go/vm/runner.go index e58a69f..4d7f07c 100644 --- a/go/vm/runner.go +++ b/go/vm/runner.go @@ -50,12 +50,25 @@ func(vmi *Vm) Reset() { func(vm *Vm) Run(b []byte, ctx context.Context) ([]byte, error) { running := true for running { + r, err := vm.st.MatchFlag(state.FLAG_TERMINATE, false) + if err != nil { + panic(err) + } + if r { + log.Printf("terminate set! bailing!") + return []byte{}, nil + } + _, err = vm.st.SetFlag(state.FLAG_DIRTY) + if err != nil { + panic(err) + } op, bb, err := opSplit(b) if err != nil { return b, err } b = bb log.Printf("execute code %x (%s) %x", op, OpcodeString[op], b) + log.Printf("state: %v", vm.st) switch op { case CATCH: b, err = vm.RunCatch(b, ctx) @@ -112,20 +125,20 @@ func(vm *Vm) RunDeadCheck(b []byte, ctx context.Context) ([]byte, error) { if len(b) > 0 { return b, nil } - log.Printf("no code remaining, let's check if we terminate") r, err := vm.st.MatchFlag(state.FLAG_TERMINATE, false) if err != nil { panic(err) } if r { + log.Printf("Terminate found!!") return b, nil } + log.Printf("no code remaining but not terminating") location, _ := vm.st.Where() if location == "" { return b, fmt.Errorf("dead runner with no current location") } b = NewLine(nil, MOVE, []string{"_catch"}, nil, nil) - log.Printf("code is now %x", b) return b, nil } @@ -138,7 +151,6 @@ func(vm *Vm) RunMap(b []byte, ctx context.Context) ([]byte, error) { // RunMap executes the CATCH opcode func(vm *Vm) RunCatch(b []byte, ctx context.Context) ([]byte, error) { - log.Printf("zzz %x", b) sym, sig, mode, b, err := ParseCatch(b) if err != nil { return b, err @@ -251,14 +263,22 @@ func(vm *Vm) RunInCmp(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - if sym != string(input) { - return b, nil + log.Printf("sym is %s", sym) + if sym == "*" { + log.Printf("input wildcard match ('%s'), target '%s'", input, target) + } else { + if sym != string(input) { + return b, nil + } + log.Printf("input match for '%s', target '%s'", input, target) } - log.Printf("input match for '%s', target '%s'", input, target) _, err = vm.st.SetFlag(state.FLAG_INMATCH) + if err != nil { + return b, err + } - target, _, err = applyTarget([]byte(target), vm.st, ctx) + target, _, err = applyTarget([]byte(target), vm.st, vm.ca, ctx) if err != nil { return b, err } @@ -330,6 +350,13 @@ func(vm *Vm) RunMPrev(b []byte, ctx context.Context) ([]byte, error) { } func(vm *Vm) Render() (string, error) { + changed, err := vm.st.ResetFlag(state.FLAG_DIRTY) + if err != nil { + panic(err) + } + if !changed { + log.Printf("Render called when not dirty, please investigate.") + } sym, idx := vm.st.Where() r, err := vm.pg.Render(sym, idx) if err != nil {