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) {
|
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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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.
|
||||||
|
33
vm/runner.go
33
vm/runner.go
@ -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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user