commit 1844415ae94840dbac2065b9e204f3737e093460
parent 46288b240b1d8feaed9dd416800a3a7cb83869e3
Author: lash <dev@holbrook.no>
Date: Thu, 13 Apr 2023 09:16:17 +0100
Add input to entryfuncs, return flag delta from entryfunc
Diffstat:
9 files changed, 228 insertions(+), 38 deletions(-)
diff --git a/engine/engine_test.go b/engine/engine_test.go
@@ -32,16 +32,23 @@ func NewFsWrapper(path string, st *state.State) FsWrapper {
}
}
-func(fs FsWrapper) one(sym string, input []byte, ctx context.Context) (string, error) {
- return "one", nil
+func(fs FsWrapper) one(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "one",
+ }, nil
}
-func(fs FsWrapper) inky(sym string, input []byte, ctx context.Context) (string, error) {
- return "tinkywinky", nil
+func(fs FsWrapper) inky(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "tinkywinky",
+ }, nil
}
-func(fs FsWrapper) pinky(sym string, input []byte, ctx context.Context) (string, error) {
- return fmt.Sprintf("xyzzy: %x", input), nil
+func(fs FsWrapper) pinky(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ r := fmt.Sprintf("xyzzy: %x", input)
+ return resource.Result{
+ Content: r,
+ }, nil
}
func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) {
diff --git a/render/size_test.go b/render/size_test.go
@@ -41,20 +41,28 @@ func funcFor(sym string) (resource.EntryFunc, error) {
return nil, fmt.Errorf("unknown func: %s", sym)
}
-func getFoo(sym string, input []byte, ctx context.Context) (string, error) {
- return "inky", nil
+func getFoo(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "inky",
+ }, nil
}
-func getBar(sym string, input []byte, ctx context.Context) (string, error) {
- return "pinky", nil
+func getBar(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "pinky",
+ }, nil
}
-func getBaz(sym string, input []byte, ctx context.Context) (string, error) {
- return "blinky", nil
+func getBaz(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "blinky",
+ }, nil
}
-func getXyzzy(sym string, input []byte, ctx context.Context) (string, error) {
- return "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve", nil
+func getXyzzy(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve",
+ }, nil
}
func TestSizeCheck(t *testing.T) {
diff --git a/resource/fs.go b/resource/fs.go
@@ -55,18 +55,20 @@ func(fs FsResource) String() string {
return fmt.Sprintf("fs resource at path: %s", fs.Path)
}
-func(fs FsResource) getFunc(sym string, input []byte, ctx context.Context) (string, error) {
+func(fs FsResource) getFunc(sym string, input []byte, ctx context.Context) (Result, error) {
return fs.getFuncNoCtx(sym, input)
}
-func(fs FsResource) getFuncNoCtx(sym string, input []byte) (string, error) {
+func(fs FsResource) getFuncNoCtx(sym string, input []byte) (Result, error) {
fb := sym + ".txt"
fp := path.Join(fs.Path, fb)
log.Printf("getfunc search dir %s %s for %s", fs.Path, fp, sym)
r, err := ioutil.ReadFile(fp)
if err != nil {
- return "", fmt.Errorf("failed getting data for sym '%s': %v", sym, err)
+ return Result{}, fmt.Errorf("failed getting data for sym '%s': %v", sym, err)
}
s := string(r)
- return strings.TrimSpace(s), nil
+ return Result{
+ Content: strings.TrimSpace(s),
+ }, nil
}
diff --git a/resource/resource.go b/resource/resource.go
@@ -4,8 +4,14 @@ import (
"context"
)
+type Result struct {
+ Content string
+ FlagSet []uint32
+ FlagReset []uint32
+}
+
// EntryFunc is a function signature for retrieving value for a key
-type EntryFunc func(sym string, input []byte, ctx context.Context) (string, error)
+type EntryFunc func(sym string, input []byte, ctx context.Context) (Result, error)
type CodeFunc func(sym string) ([]byte, error)
type TemplateFunc func(sym string) (string, error)
type FuncForFunc func(sym string) (EntryFunc, error)
diff --git a/resource/resource_test.go b/resource/resource_test.go
@@ -37,18 +37,27 @@ func funcFor(sym string) (EntryFunc, error) {
return nil, fmt.Errorf("unknown func: %s", sym)
}
-func get(sym string, input []byte, ctx context.Context) (string, error) {
+func get(sym string, input []byte, ctx context.Context) (Result, error) {
switch sym {
case "foo":
- return "inky", nil
+ return Result{
+ Content: "inky",
+ }, nil
case "bar":
- return "pinky", nil
+ return Result{
+ Content: "pinky",
+ }, nil
case "baz":
- return "blinky", nil
+ return Result{
+ Content: "blinky",
+ }, nil
}
- return "", fmt.Errorf("unknown sym: %s", sym)
+ return Result{}, fmt.Errorf("unknown sym: %s", sym)
}
-func getXyzzy(sym string, input []byte, ctx context.Context) (string, error) {
- return "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve", nil
+func getXyzzy(sym string, input []byte, ctx context.Context) (Result, error) {
+ r := "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve"
+ return Result{
+ Content: r,
+ }, nil
}
diff --git a/state/flag.go b/state/flag.go
@@ -5,4 +5,16 @@ const (
FLAG_INMATCH = 2
FLAG_TERMINATE = 3
FLAG_DIRTY = 4
+ FLAG_LOADFAIL = 5
+ //FLAG_WRITEABLE = FLAG_LOADFAIL
)
+
+func IsWriteableFlag(flag uint32) bool {
+ if flag > 7 {
+ return true
+ }
+ //if flag & FLAG_WRITEABLE > 0 {
+ // return true
+ //}
+ return false
+}
diff --git a/state/state.go b/state/state.go
@@ -112,6 +112,11 @@ func(st *State) ResetFlag(bitIndex uint32) (bool, error) {
return true, nil
}
+// ResetBaseFlags restes all builtin flags not writeable by client.
+func(st *State) ResetBaseFlags() {
+ st.Flags[0] = 0
+}
+
// GetFlag returns the state of the flag at the given bit field index.
//
// Fails if bit field index is out of range.
diff --git a/vm/runner.go b/vm/runner.go
@@ -60,6 +60,7 @@ func(vm *Vm) Run(b []byte, ctx context.Context) ([]byte, error) {
log.Printf("terminate set! bailing!")
return []byte{}, nil
}
+ vm.st.ResetBaseFlags()
_, err = vm.st.SetFlag(state.FLAG_DIRTY)
if err != nil {
panic(err)
@@ -179,7 +180,8 @@ func(vm *Vm) RunCatch(b []byte, ctx context.Context) ([]byte, error) {
log.Printf("catch at flag %v, moving to %v", sig, sym) //bitField, d)
vm.st.Down(sym)
vm.Reset()
- b = []byte{}
+ bh := NewLine(nil, HALT, nil, nil, nil)
+ b = append(bh, b...)
}
return b, nil
}
@@ -430,6 +432,33 @@ func(vm *Vm) refresh(key string, rs resource.Resource, ctx context.Context) (str
return "", fmt.Errorf("no retrieve function for external symbol %v", key)
}
input, _ := vm.st.GetInput()
- return fn(key, input, ctx)
-}
+ r, err := fn(key, input, ctx)
+ if err != nil {
+ var perr error
+ _, perr = vm.st.SetFlag(state.FLAG_LOADFAIL)
+ if perr != nil {
+ panic(err)
+ }
+ return "", err
+ }
+ for _, flag := range r.FlagSet {
+ if !state.IsWriteableFlag(flag) {
+ continue
+ }
+ _, err = vm.st.SetFlag(flag)
+ if err != nil {
+ panic(err)
+ }
+ }
+ for _, flag := range r.FlagReset {
+ if !state.IsWriteableFlag(flag) {
+ continue
+ }
+ _, err = vm.st.ResetFlag(flag)
+ if err != nil {
+ panic(err)
+ }
+ }
+ return r.Content, err
+}
diff --git a/vm/runner_test.go b/vm/runner_test.go
@@ -20,16 +20,45 @@ type TestResource struct {
state *state.State
}
-func getOne(sym string, input []byte, ctx context.Context) (string, error) {
- return "one", nil
+func getOne(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "one",
+ }, nil
}
-func getTwo(sym string, input []byte, ctx context.Context) (string, error) {
- return "two", nil
+func getTwo(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: "two",
+ }, nil
}
-func getDyn(sym string, input []byte, ctx context.Context) (string, error) {
- return dynVal, nil
+func getDyn(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ return resource.Result{
+ Content: dynVal,
+ }, nil
+}
+
+func getEcho(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ r := fmt.Sprintf("echo: %s", input)
+ return resource.Result{
+ Content: r,
+ }, nil
+}
+
+func setFlag(sym string, input []byte, ctx context.Context) (resource.Result, error) {
+ s := fmt.Sprintf("ping")
+ r := resource.Result{
+ Content: s,
+ }
+ if len(input) > 0 {
+ r.FlagSet = append(r.FlagSet, uint32(input[0]))
+ }
+ if len(input) > 1 {
+ r.FlagReset = append(r.FlagReset, uint32(input[1]))
+ }
+ log.Printf("setflag %v", r)
+ return r, nil
+
}
type TestStatefulResolver struct {
@@ -50,6 +79,8 @@ func (r TestResource) GetTemplate(sym string) (string, error) {
return "root", nil
case "_catch":
return "aiee", nil
+ case "flagCatch":
+ return "flagiee", nil
}
panic(fmt.Sprintf("unknown symbol %s", sym))
return "", fmt.Errorf("unknown symbol %s", sym)
@@ -65,21 +96,32 @@ func (r TestResource) FuncFor(sym string) (resource.EntryFunc, error) {
return getDyn, nil
case "arg":
return r.getInput, nil
+ case "echo":
+ return getEcho, nil
+ case "setFlagOne":
+ return setFlag, nil
}
return nil, fmt.Errorf("invalid function: '%s'", sym)
}
-func(r TestResource) getInput(sym string, input []byte, ctx context.Context) (string, error) {
+func(r TestResource) getInput(sym string, input []byte, ctx context.Context) (resource.Result, error) {
v, err := r.state.GetInput()
- return string(v), err
+ return resource.Result{
+ Content: string(v),
+ }, err
}
func(r TestResource) GetCode(sym string) ([]byte, error) {
var b []byte
- if sym == "_catch" {
+ switch sym {
+ case "_catch":
+ b = NewLine(b, MOUT, []string{"0", "repent"}, nil, nil)
+ b = NewLine(b, HALT, nil, nil, nil)
+ case "flagCatch":
b = NewLine(b, MOUT, []string{"0", "repent"}, nil, nil)
b = NewLine(b, HALT, nil, nil, nil)
}
+
return b, nil
}
@@ -409,3 +451,73 @@ func TestRunReturn(t *testing.T) {
t.Fatalf("expected location 'root', got '%s'", location)
}
}
+
+
+func TestRunLoadInput(t *testing.T) {
+ st := state.NewState(5)
+ rs := TestResource{}
+ ca := cache.NewCache()
+ vm := NewVm(&st, &rs, ca, nil)
+
+ var err error
+
+ st.Down("root")
+ st.SetInput([]byte("foobar"))
+
+ b := NewLine(nil, LOAD, []string{"echo"}, []byte{0x00}, nil)
+ b = NewLine(b, HALT, nil, nil, nil)
+
+ ctx := context.TODO()
+
+ b, err = vm.Run(b, ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r, err := ca.Get("echo")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if r != "echo: foobar" {
+ t.Fatalf("expected 'echo: foobar', got %s", r)
+ }
+}
+
+func TestInputBranch(t *testing.T) {
+ st := state.NewState(5)
+ rs := TestResource{}
+ ca := cache.NewCache()
+ vm := NewVm(&st, &rs, ca, nil)
+
+ var err error
+
+ st.Down("root")
+
+ b := NewLine(nil, LOAD, []string{"setFlagOne"}, []byte{0x00}, nil)
+ b = NewLine(b, CATCH, []string{"flagCatch"}, []byte{8}, []uint8{0})
+ b = NewLine(b, RELOAD, []string{"setFlagOne"}, nil, nil)
+ b = NewLine(b, CATCH, []string{"flagCatch"}, []byte{8}, []uint8{0})
+ b = NewLine(b, CATCH, []string{"one"}, []byte{9}, []uint8{0})
+
+ ctx := context.TODO()
+
+ st.SetInput([]byte{0x08})
+ b, err = vm.Run(b, ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ location, _ := st.Where()
+ if location != "flagCatch" {
+ t.Fatalf("expected 'flagCatch', got %s", location)
+ }
+
+ st.SetInput([]byte{0x09, 0x08})
+ b, err = vm.Run(b, ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ location, _ = st.Where()
+ if location != "one" {
+ t.Fatalf("expected 'one', got %s", location)
+ }
+}