Add input to entryfuncs, return flag delta from entryfunc

This commit is contained in:
lash 2023-04-13 09:16:17 +01:00
parent 46288b240b
commit 1844415ae9
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
9 changed files with 228 additions and 38 deletions

View File

@ -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) { func(fs FsWrapper) one(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "one", nil return resource.Result{
Content: "one",
}, nil
} }
func(fs FsWrapper) inky(sym string, input []byte, ctx context.Context) (string, error) { func(fs FsWrapper) inky(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "tinkywinky", nil return resource.Result{
Content: "tinkywinky",
}, nil
} }
func(fs FsWrapper) pinky(sym string, input []byte, ctx context.Context) (string, error) { func(fs FsWrapper) pinky(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return fmt.Sprintf("xyzzy: %x", input), nil r := fmt.Sprintf("xyzzy: %x", input)
return resource.Result{
Content: r,
}, nil
} }
func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) { func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) {

View File

@ -41,20 +41,28 @@ func funcFor(sym string) (resource.EntryFunc, error) {
return nil, fmt.Errorf("unknown func: %s", sym) return nil, fmt.Errorf("unknown func: %s", sym)
} }
func getFoo(sym string, input []byte, ctx context.Context) (string, error) { func getFoo(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "inky", nil return resource.Result{
Content: "inky",
}, nil
} }
func getBar(sym string, input []byte, ctx context.Context) (string, error) { func getBar(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "pinky", nil return resource.Result{
Content: "pinky",
}, nil
} }
func getBaz(sym string, input []byte, ctx context.Context) (string, error) { func getBaz(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "blinky", nil return resource.Result{
Content: "blinky",
}, nil
} }
func getXyzzy(sym string, input []byte, ctx context.Context) (string, error) { func getXyzzy(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve", nil 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) { func TestSizeCheck(t *testing.T) {

View File

@ -55,18 +55,20 @@ func(fs FsResource) String() string {
return fmt.Sprintf("fs resource at path: %s", fs.Path) 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) 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" fb := sym + ".txt"
fp := path.Join(fs.Path, fb) fp := path.Join(fs.Path, fb)
log.Printf("getfunc search dir %s %s for %s", fs.Path, fp, sym) log.Printf("getfunc search dir %s %s for %s", fs.Path, fp, sym)
r, err := ioutil.ReadFile(fp) r, err := ioutil.ReadFile(fp)
if err != nil { 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) s := string(r)
return strings.TrimSpace(s), nil return Result{
Content: strings.TrimSpace(s),
}, nil
} }

View File

@ -4,8 +4,14 @@ import (
"context" "context"
) )
type Result struct {
Content string
FlagSet []uint32
FlagReset []uint32
}
// EntryFunc is a function signature for retrieving value for a key // 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 CodeFunc func(sym string) ([]byte, error)
type TemplateFunc func(sym string) (string, error) type TemplateFunc func(sym string) (string, error)
type FuncForFunc func(sym string) (EntryFunc, error) type FuncForFunc func(sym string) (EntryFunc, error)

View File

@ -37,18 +37,27 @@ func funcFor(sym string) (EntryFunc, error) {
return nil, fmt.Errorf("unknown func: %s", sym) 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 { switch sym {
case "foo": case "foo":
return "inky", nil return Result{
Content: "inky",
}, nil
case "bar": case "bar":
return "pinky", nil return Result{
Content: "pinky",
}, nil
case "baz": 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) { func getXyzzy(sym string, input []byte, ctx context.Context) (Result, error) {
return "inky pinky\nblinky clyde sue\ntinkywinky dipsy\nlala poo\none two three four five six seven\neight nine ten\neleven twelve", nil 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
} }

View File

@ -5,4 +5,16 @@ const (
FLAG_INMATCH = 2 FLAG_INMATCH = 2
FLAG_TERMINATE = 3 FLAG_TERMINATE = 3
FLAG_DIRTY = 4 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
}

View File

@ -112,6 +112,11 @@ func(st *State) ResetFlag(bitIndex uint32) (bool, error) {
return true, nil 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. // GetFlag returns the state of the flag at the given bit field index.
// //
// Fails if bit field index is out of range. // Fails if bit field index is out of range.

View File

@ -60,6 +60,7 @@ func(vm *Vm) Run(b []byte, ctx context.Context) ([]byte, error) {
log.Printf("terminate set! bailing!") log.Printf("terminate set! bailing!")
return []byte{}, nil return []byte{}, nil
} }
vm.st.ResetBaseFlags()
_, err = vm.st.SetFlag(state.FLAG_DIRTY) _, err = vm.st.SetFlag(state.FLAG_DIRTY)
if err != nil { if err != nil {
panic(err) 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) log.Printf("catch at flag %v, moving to %v", sig, sym) //bitField, d)
vm.st.Down(sym) vm.st.Down(sym)
vm.Reset() vm.Reset()
b = []byte{} bh := NewLine(nil, HALT, nil, nil, nil)
b = append(bh, b...)
} }
return b, nil 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) return "", fmt.Errorf("no retrieve function for external symbol %v", key)
} }
input, _ := vm.st.GetInput() 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
}

View File

@ -20,16 +20,45 @@ type TestResource struct {
state *state.State state *state.State
} }
func getOne(sym string, input []byte, ctx context.Context) (string, error) { func getOne(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "one", nil return resource.Result{
Content: "one",
}, nil
} }
func getTwo(sym string, input []byte, ctx context.Context) (string, error) { func getTwo(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return "two", nil return resource.Result{
Content: "two",
}, nil
} }
func getDyn(sym string, input []byte, ctx context.Context) (string, error) { func getDyn(sym string, input []byte, ctx context.Context) (resource.Result, error) {
return dynVal, nil 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 { type TestStatefulResolver struct {
@ -50,6 +79,8 @@ func (r TestResource) GetTemplate(sym string) (string, error) {
return "root", nil return "root", nil
case "_catch": case "_catch":
return "aiee", nil return "aiee", nil
case "flagCatch":
return "flagiee", nil
} }
panic(fmt.Sprintf("unknown symbol %s", sym)) panic(fmt.Sprintf("unknown symbol %s", sym))
return "", fmt.Errorf("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 return getDyn, nil
case "arg": case "arg":
return r.getInput, nil return r.getInput, nil
case "echo":
return getEcho, nil
case "setFlagOne":
return setFlag, nil
} }
return nil, fmt.Errorf("invalid function: '%s'", sym) 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() v, err := r.state.GetInput()
return string(v), err return resource.Result{
Content: string(v),
}, err
} }
func(r TestResource) GetCode(sym string) ([]byte, error) { func(r TestResource) GetCode(sym string) ([]byte, error) {
var b []byte 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, MOUT, []string{"0", "repent"}, nil, nil)
b = NewLine(b, HALT, nil, nil, nil) b = NewLine(b, HALT, nil, nil, nil)
} }
return b, nil return b, nil
} }
@ -409,3 +451,73 @@ func TestRunReturn(t *testing.T) {
t.Fatalf("expected location 'root', got '%s'", location) 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)
}
}