Add input to entryfuncs, return flag delta from entryfunc
This commit is contained in:
parent
46288b240b
commit
1844415ae9
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
35
vm/runner.go
35
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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user