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) {
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) {

View File

@ -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) {

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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.

View File

@ -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
}

View File

@ -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)
}
}