WIP implement engine object
This commit is contained in:
parent
39eafc8ff2
commit
4f473c12f0
@ -2,6 +2,7 @@ package engine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
@ -16,11 +17,11 @@ import (
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
st state.State
|
st *state.State
|
||||||
rs resource.Resource
|
rs resource.Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine(st state.State, rs resource.Resource) Engine {
|
func NewEngine(st *state.State, rs resource.Resource) Engine {
|
||||||
engine := Engine{st, rs}
|
engine := Engine{st, rs}
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
@ -28,7 +29,33 @@ func NewEngine(st state.State, rs resource.Resource) Engine {
|
|||||||
func(en *Engine) Init(ctx context.Context) error {
|
func(en *Engine) Init(ctx context.Context) error {
|
||||||
b := vm.NewLine([]byte{}, vm.MOVE, []string{"root"}, nil, nil)
|
b := vm.NewLine([]byte{}, vm.MOVE, []string{"root"}, nil, nil)
|
||||||
var err error
|
var err error
|
||||||
en.st, _, err = vm.Run(b, en.st, en.rs, ctx)
|
_, err = vm.Run(b, en.st, en.rs, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
location := en.st.Where()
|
||||||
|
code, err := en.rs.GetCode(location)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return en.st.AppendCode(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (en *Engine) Exec(input []byte, ctx context.Context) error {
|
||||||
|
l := uint8(len(input))
|
||||||
|
if l > 255 {
|
||||||
|
return fmt.Errorf("input too long (%v)", l)
|
||||||
|
}
|
||||||
|
input = append([]byte{l}, input...)
|
||||||
|
code, err := en.st.GetCode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(code) == 0 {
|
||||||
|
return fmt.Errorf("no code to execute")
|
||||||
|
}
|
||||||
|
code, err = vm.Apply(input, code, en.st, en.rs, ctx)
|
||||||
|
en.st.SetCode(code)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"text/template"
|
"text/template"
|
||||||
@ -16,10 +18,10 @@ import (
|
|||||||
|
|
||||||
type FsWrapper struct {
|
type FsWrapper struct {
|
||||||
*resource.FsResource
|
*resource.FsResource
|
||||||
st state.State
|
st *state.State
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFsWrapper(path string, st state.State, ctx context.Context) FsWrapper {
|
func NewFsWrapper(path string, st *state.State, ctx context.Context) FsWrapper {
|
||||||
rs := resource.NewFsResource(path, ctx)
|
rs := resource.NewFsResource(path, ctx)
|
||||||
return FsWrapper {
|
return FsWrapper {
|
||||||
&rs,
|
&rs,
|
||||||
@ -42,12 +44,27 @@ func (r FsWrapper) RenderTemplate(sym string, values map[string]string) (string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
log.Printf("template is %v render is %v", v, b)
|
|
||||||
return b.String(), err
|
return b.String(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func(fs FsWrapper) one(ctx context.Context) (string, error) {
|
||||||
|
return "one", nil
|
||||||
|
}
|
||||||
|
|
||||||
func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) {
|
func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) {
|
||||||
return nil, nil
|
switch sym {
|
||||||
|
case "one":
|
||||||
|
return fs.one, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("function for %v not found", sym)
|
||||||
|
}
|
||||||
|
|
||||||
|
func(fs FsWrapper) GetCode(sym string) ([]byte, error) {
|
||||||
|
sym += ".bin"
|
||||||
|
fp := path.Join(fs.Path, sym)
|
||||||
|
r, err := ioutil.ReadFile(fp)
|
||||||
|
log.Printf("getcode for %v %v", fp, r)
|
||||||
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEngineInit(t *testing.T) {
|
func TestEngineInit(t *testing.T) {
|
||||||
@ -62,8 +79,8 @@ func TestEngineInit(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
dir := path.Join(testdataloader.GetBasePath(), "testdata")
|
dir := path.Join(testdataloader.GetBasePath(), "testdata")
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
rs := NewFsWrapper(dir, st, ctx)
|
rs := NewFsWrapper(dir, &st, ctx)
|
||||||
en := NewEngine(st, rs)
|
en := NewEngine(&st, &rs)
|
||||||
err := en.Init(ctx)
|
err := en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -78,4 +95,13 @@ func TestEngineInit(t *testing.T) {
|
|||||||
if !bytes.Equal(b, []byte("hello world")) {
|
if !bytes.Equal(b, []byte("hello world")) {
|
||||||
t.Fatalf("expected result 'hello world', got %v", b)
|
t.Fatalf("expected result 'hello world', got %v", b)
|
||||||
}
|
}
|
||||||
|
input := []byte("foo")
|
||||||
|
err = en.Exec(input, ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
r := st.Where()
|
||||||
|
if r != "bar" {
|
||||||
|
t.Fatalf("expected where-string 'bar', got %v", r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FsResource struct {
|
type FsResource struct {
|
||||||
path string
|
Path string
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFsResource(path string, ctx context.Context) (FsResource) {
|
func NewFsResource(path string, ctx context.Context) (FsResource) {
|
||||||
return FsResource{
|
return FsResource{
|
||||||
path: path,
|
Path: path,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func(fs FsResource) GetTemplate(sym string) (string, error) {
|
func(fs FsResource) GetTemplate(sym string) (string, error) {
|
||||||
fp := path.Join(fs.path, sym)
|
fp := path.Join(fs.Path, sym)
|
||||||
r, err := ioutil.ReadFile(fp)
|
r, err := ioutil.ReadFile(fp)
|
||||||
s := string(r)
|
s := string(r)
|
||||||
return strings.TrimSpace(s), err
|
return strings.TrimSpace(s), err
|
||||||
|
@ -26,7 +26,7 @@ type State struct {
|
|||||||
CacheUseSize uint32 // Currently used bytes by all values in cache
|
CacheUseSize uint32 // Currently used bytes by all values in cache
|
||||||
Cache []map[string]string // All loaded cache items
|
Cache []map[string]string // All loaded cache items
|
||||||
CacheMap map[string]string // Mapped
|
CacheMap map[string]string // Mapped
|
||||||
Code []byte // Pending bytecode to execute
|
code []byte // Pending bytecode to execute
|
||||||
execPath []string // Command symbols stack
|
execPath []string // Command symbols stack
|
||||||
arg *string // Optional argument. Nil if not set.
|
arg *string // Optional argument. Nil if not set.
|
||||||
sizes map[string]uint16 // Size limits for all loaded symbols.
|
sizes map[string]uint16 // Size limits for all loaded symbols.
|
||||||
@ -366,7 +366,7 @@ func(st *State) Check(key string) bool {
|
|||||||
return st.frameOf(key) == -1
|
return st.frameOf(key) == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns size used by values, and remaining size available
|
// Size returns size used by values, and remaining size available
|
||||||
func(st *State) Size() (uint32, uint32) {
|
func(st *State) Size() (uint32, uint32) {
|
||||||
var l int
|
var l int
|
||||||
var c uint16
|
var c uint16
|
||||||
@ -378,6 +378,25 @@ func(st *State) Size() (uint32, uint32) {
|
|||||||
return r, uint32(c)-r
|
return r, uint32(c)-r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Appendcode adds the given bytecode to the end of the existing code.
|
||||||
|
func(st *State) AppendCode(b []byte) error {
|
||||||
|
st.code = append(st.code, b...)
|
||||||
|
log.Printf("code changed to %v", b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCode replaces the current bytecode with the given bytecode.
|
||||||
|
func(st *State) SetCode(b []byte) {
|
||||||
|
log.Printf("code set to %v", b)
|
||||||
|
st.code = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func(st *State) GetCode() ([]byte, error) {
|
||||||
|
b := st.code
|
||||||
|
st.code = []byte{}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
// return 0-indexed frame number where key is defined. -1 if not defined
|
// return 0-indexed frame number where key is defined. -1 if not defined
|
||||||
func(st *State) frameOf(key string) int {
|
func(st *State) frameOf(key string) int {
|
||||||
for i, m := range st.Cache {
|
for i, m := range st.Cache {
|
||||||
@ -408,4 +427,3 @@ func(st *State) resetCurrent() {
|
|||||||
st.sink = nil
|
st.sink = nil
|
||||||
st.CacheMap = make(map[string]string)
|
st.CacheMap = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
105
go/vm/vm.go
105
go/vm/vm.go
@ -29,34 +29,43 @@ func argFromBytes(input []byte) (string, []byte, error) {
|
|||||||
// If the router indicates an argument input, the optional argument is set on the state.
|
// If the router indicates an argument input, the optional argument is set on the state.
|
||||||
//
|
//
|
||||||
// TODO: the bytecode load is a separate step so Run should be run separately.
|
// TODO: the bytecode load is a separate step so Run should be run separately.
|
||||||
func Apply(input []byte, instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func Apply(input []byte, instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
log.Printf("running input %v against instruction %v", input, instruction)
|
||||||
arg, input, err := argFromBytes(input)
|
arg, input, err := argFromBytes(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, input, err
|
return input, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rt := router.FromBytes(input)
|
rt := router.FromBytes(instruction)
|
||||||
sym := rt.Get(arg)
|
sym := rt.Get(arg)
|
||||||
if sym == "" {
|
if sym == "" {
|
||||||
sym = rt.Default()
|
sym = rt.Default()
|
||||||
st.PutArg(arg)
|
st.PutArg(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sym == "" {
|
if sym == "" {
|
||||||
instruction = NewLine([]byte{}, MOVE, []string{"_catch"}, nil, nil)
|
instruction = NewLine([]byte{}, MOVE, []string{"_catch"}, nil, nil)
|
||||||
} else if sym == "_" {
|
} else {
|
||||||
|
instruction, err = rs.GetCode(sym)
|
||||||
|
if err != nil {
|
||||||
|
return instruction, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sym == "_" {
|
||||||
instruction = NewLine([]byte{}, BACK, nil, nil, nil)
|
instruction = NewLine([]byte{}, BACK, nil, nil, nil)
|
||||||
} else {
|
} else {
|
||||||
new_instruction := NewLine([]byte{}, MOVE, []string{sym}, nil, nil)
|
new_instruction := NewLine([]byte{}, MOVE, []string{sym}, nil, nil)
|
||||||
instruction = append(new_instruction, instruction...)
|
instruction = append(new_instruction, instruction...)
|
||||||
}
|
}
|
||||||
|
|
||||||
st, instruction, err = Run(instruction, st, rs, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return st, instruction, err
|
|
||||||
}
|
}
|
||||||
return st, instruction, nil
|
|
||||||
|
instruction, err = Run(instruction, st, rs, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return instruction, err
|
||||||
|
}
|
||||||
|
return instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run extracts individual op codes and arguments and executes them.
|
// Run extracts individual op codes and arguments and executes them.
|
||||||
@ -64,61 +73,54 @@ func Apply(input []byte, instruction []byte, st state.State, rs resource.Resourc
|
|||||||
// Each step may update the state.
|
// Each step may update the state.
|
||||||
//
|
//
|
||||||
// On error, the remaining instructions will be returned. State will not be rolled back.
|
// On error, the remaining instructions will be returned. State will not be rolled back.
|
||||||
func Run(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func Run(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
for len(instruction) > 0 {
|
for len(instruction) > 0 {
|
||||||
log.Printf("instruction is now %v", instruction)
|
log.Printf("instruction is now %v", instruction)
|
||||||
op := binary.BigEndian.Uint16(instruction[:2])
|
op := binary.BigEndian.Uint16(instruction[:2])
|
||||||
if op > _MAX {
|
if op > _MAX {
|
||||||
return st, instruction, fmt.Errorf("opcode value %v out of range (%v)", op, _MAX)
|
return instruction, fmt.Errorf("opcode value %v out of range (%v)", op, _MAX)
|
||||||
}
|
}
|
||||||
switch op {
|
switch op {
|
||||||
case CATCH:
|
case CATCH:
|
||||||
st, instruction, err = RunCatch(instruction[2:], st, rs, ctx)
|
instruction, err = RunCatch(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case CROAK:
|
case CROAK:
|
||||||
st, instruction, err = RunCroak(instruction[2:], st, rs, ctx)
|
instruction, err = RunCroak(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case LOAD:
|
case LOAD:
|
||||||
st, instruction, err = RunLoad(instruction[2:], st, rs, ctx)
|
instruction, err = RunLoad(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case RELOAD:
|
case RELOAD:
|
||||||
st, instruction, err = RunReload(instruction[2:], st, rs, ctx)
|
instruction, err = RunReload(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case MAP:
|
case MAP:
|
||||||
st, instruction, err = RunMap(instruction[2:], st, rs, ctx)
|
instruction, err = RunMap(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case MOVE:
|
case MOVE:
|
||||||
st, instruction, err = RunMove(instruction[2:], st, rs, ctx)
|
instruction, err = RunMove(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
case BACK:
|
case BACK:
|
||||||
st, instruction, err = RunBack(instruction[2:], st, rs, ctx)
|
instruction, err = RunBack(instruction[2:], st, rs, ctx)
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Unhandled state: %v", op)
|
err = fmt.Errorf("Unhandled state: %v", op)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return st, instruction, nil
|
return instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunMap executes the MAP opcode
|
// RunMap executes the MAP opcode
|
||||||
func RunMap(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunMap(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
err = st.Map(head)
|
err = st.Map(head)
|
||||||
return st, tail, err
|
return tail, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunMap executes the CATCH opcode
|
// RunMap executes the CATCH opcode
|
||||||
func RunCatch(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunCatch(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
bitFieldSize := tail[0]
|
bitFieldSize := tail[0]
|
||||||
bitField := tail[1:1+bitFieldSize]
|
bitField := tail[1:1+bitFieldSize]
|
||||||
@ -128,69 +130,69 @@ func RunCatch(instruction []byte, st state.State, rs resource.Resource, ctx cont
|
|||||||
st.Down(head)
|
st.Down(head)
|
||||||
tail = []byte{}
|
tail = []byte{}
|
||||||
}
|
}
|
||||||
return st, tail, nil
|
return tail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunMap executes the CROAK opcode
|
// RunMap executes the CROAK opcode
|
||||||
func RunCroak(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunCroak(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
_ = head
|
_ = head
|
||||||
_ = tail
|
_ = tail
|
||||||
st.Reset()
|
st.Reset()
|
||||||
return st, []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunLoad executes the LOAD opcode
|
// RunLoad executes the LOAD opcode
|
||||||
func RunLoad(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunLoad(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
if !st.Check(head) {
|
if !st.Check(head) {
|
||||||
return st, instruction, fmt.Errorf("key %v already loaded", head)
|
return instruction, fmt.Errorf("key %v already loaded", head)
|
||||||
}
|
}
|
||||||
sz := uint16(tail[0])
|
sz := uint16(tail[0])
|
||||||
tail = tail[1:]
|
tail = tail[1:]
|
||||||
|
|
||||||
r, err := refresh(head, rs, ctx)
|
r, err := refresh(head, rs, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, tail, err
|
return tail, err
|
||||||
}
|
}
|
||||||
err = st.Add(head, r, sz)
|
err = st.Add(head, r, sz)
|
||||||
return st, tail, err
|
return tail, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunLoad executes the RELOAD opcode
|
// RunLoad executes the RELOAD opcode
|
||||||
func RunReload(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunReload(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
r, err := refresh(head, rs, ctx)
|
r, err := refresh(head, rs, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, tail, err
|
return tail, err
|
||||||
}
|
}
|
||||||
st.Update(head, r)
|
st.Update(head, r)
|
||||||
return st, tail, nil
|
return tail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunLoad executes the MOVE opcode
|
// RunLoad executes the MOVE opcode
|
||||||
func RunMove(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunMove(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return instruction, err
|
||||||
}
|
}
|
||||||
st.Down(head)
|
st.Down(head)
|
||||||
return st, tail, nil
|
return tail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunLoad executes the BACK opcode
|
// RunLoad executes the BACK opcode
|
||||||
func RunBack(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
func RunBack(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
st.Up()
|
st.Up()
|
||||||
return st, instruction, nil
|
return instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve data for key
|
// retrieve data for key
|
||||||
@ -199,6 +201,9 @@ func refresh(key string, rs resource.Resource, ctx context.Context) (string, err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if fn == nil {
|
||||||
|
return "", fmt.Errorf("no retrieve function for external symbol %v", key)
|
||||||
|
}
|
||||||
return fn(ctx)
|
return fn(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
221
go/vm/vm_test.go
221
go/vm/vm_test.go
@ -96,17 +96,16 @@ func TestRun(t *testing.T) {
|
|||||||
rs := TestResource{}
|
rs := TestResource{}
|
||||||
b := []byte{0x00, MOVE, 0x03}
|
b := []byte{0x00, MOVE, 0x03}
|
||||||
b = append(b, []byte("foo")...)
|
b = append(b, []byte("foo")...)
|
||||||
r, _, err := Run(b, st, &rs, context.TODO())
|
_, err := Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error on valid opcode: %v", err)
|
t.Errorf("error on valid opcode: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b = []byte{0x01, 0x02}
|
b = []byte{0x01, 0x02}
|
||||||
r, _, err = Run(b, st, &rs, context.TODO())
|
_, err = Run(b, &st, &rs, context.TODO())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("no error on invalid opcode")
|
t.Errorf("no error on invalid opcode")
|
||||||
}
|
}
|
||||||
_ = r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunLoadRender(t *testing.T) {
|
func TestRunLoadRender(t *testing.T) {
|
||||||
@ -117,7 +116,7 @@ func TestRunLoadRender(t *testing.T) {
|
|||||||
ins := append([]byte{uint8(len(sym))}, []byte(sym)...)
|
ins := append([]byte{uint8(len(sym))}, []byte(sym)...)
|
||||||
ins = append(ins, 0x0a)
|
ins = append(ins, 0x0a)
|
||||||
var err error
|
var err error
|
||||||
st, _, err = RunLoad(ins, st, &rs, context.TODO())
|
_, err = RunLoad(ins, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -142,7 +141,7 @@ func TestRunLoadRender(t *testing.T) {
|
|||||||
sym = "two"
|
sym = "two"
|
||||||
ins = append([]byte{uint8(len(sym))}, []byte(sym)...)
|
ins = append([]byte{uint8(len(sym))}, []byte(sym)...)
|
||||||
ins = append(ins, 0)
|
ins = append(ins, 0)
|
||||||
st, _, err = RunLoad(ins, st, &rs, context.TODO())
|
_, err = RunLoad(ins, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -166,7 +165,7 @@ func TestRunMultiple(t *testing.T) {
|
|||||||
b := []byte{}
|
b := []byte{}
|
||||||
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
|
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
b = NewLine(b, LOAD, []string{"two"}, nil, []uint8{42})
|
b = NewLine(b, LOAD, []string{"two"}, nil, []uint8{42})
|
||||||
st, _, err := Run(b, st, &rs, context.TODO())
|
_, err := Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -178,7 +177,7 @@ func TestRunReload(t *testing.T) {
|
|||||||
b := []byte{}
|
b := []byte{}
|
||||||
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
|
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
|
||||||
b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
|
b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
|
||||||
st, _, err := Run(b, st, &rs, context.TODO())
|
_, err := Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -192,7 +191,7 @@ func TestRunReload(t *testing.T) {
|
|||||||
dynVal = "baz"
|
dynVal = "baz"
|
||||||
b = []byte{}
|
b = []byte{}
|
||||||
b = NewLine(b, RELOAD, []string{"dyn"}, nil, nil)
|
b = NewLine(b, RELOAD, []string{"dyn"}, nil, nil)
|
||||||
st, _, err = Run(b, st, &rs, context.TODO())
|
_, err = Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -209,14 +208,15 @@ func TestRunReload(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunArg(t *testing.T) {
|
func TestRunArg(t *testing.T) {
|
||||||
st := state.NewState(5)
|
st := state.NewState(5)
|
||||||
|
rs := TestResource{}
|
||||||
rt := router.NewRouter()
|
rt := router.NewRouter()
|
||||||
rt.Add("foo", "bar")
|
rt.Add("foo", "bar")
|
||||||
rt.Add("baz", "xyzzy")
|
rt.Add("baz", "xyzzy")
|
||||||
b := []byte{0x03}
|
b := []byte{0x03}
|
||||||
b = append(b, []byte("baz")...)
|
b = append(b, []byte("baz")...)
|
||||||
b = append(b, rt.ToBytes()...)
|
//b = append(b, rt.ToBytes()...)
|
||||||
var err error
|
var err error
|
||||||
st, b, err = Apply(b, []byte{}, st, nil, context.TODO())
|
b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -237,9 +237,9 @@ func TestRunArgInvalid(t *testing.T) {
|
|||||||
rt.Add("baz", "xyzzy")
|
rt.Add("baz", "xyzzy")
|
||||||
b := []byte{0x03}
|
b := []byte{0x03}
|
||||||
b = append(b, []byte("bar")...)
|
b = append(b, []byte("bar")...)
|
||||||
b = append(b, rt.ToBytes()...)
|
//b = append(b, rt.ToBytes()...)
|
||||||
var err error
|
var err error
|
||||||
st, b, err = Apply(b, []byte{}, st, nil, context.TODO())
|
b, err = Apply(b, rt.ToBytes(), &st, nil, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -253,97 +253,108 @@ func TestRunArgInvalid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunArgInstructions(t *testing.T) {
|
//func TestRunArgInstructions(t *testing.T) {
|
||||||
st := state.NewState(5)
|
// st := state.NewState(5)
|
||||||
rs := TestResource{}
|
// rs := TestResource{}
|
||||||
|
//
|
||||||
rt := router.NewRouter()
|
// rt := router.NewRouter()
|
||||||
rt.Add("foo", "bar")
|
// rt.Add("foo", "bar")
|
||||||
b := []byte{0x03}
|
// b := []byte{0x03}
|
||||||
b = append(b, []byte("foo")...)
|
// b = append(b, []byte("foo")...)
|
||||||
b = append(b, rt.ToBytes()...)
|
// b = append(b, rt.ToBytes()...)
|
||||||
|
//
|
||||||
bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
|
// bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
|
||||||
bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
|
// bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
|
||||||
bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
|
// bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
|
||||||
var err error
|
// var err error
|
||||||
st, b, err = Apply(b, bi, st, &rs, context.TODO())
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
t.Error(err)
|
// t.Error(err)
|
||||||
}
|
// }
|
||||||
l := len(b)
|
// l := len(b)
|
||||||
if l != 0 {
|
// if l != 0 {
|
||||||
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
}
|
// }
|
||||||
loc := st.Where()
|
// loc := st.Where()
|
||||||
if loc != "bar" {
|
// if loc != "bar" {
|
||||||
t.Errorf("expected where-state _catch, got %v", loc)
|
// t.Errorf("expected where-state bar, got %v", loc)
|
||||||
}
|
// }
|
||||||
m, err := st.Get()
|
// m, err := st.Get()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
t.Error(err)
|
// t.Fatal(err)
|
||||||
}
|
// }
|
||||||
r, err := rs.RenderTemplate(loc, m)
|
// _, err = rs.RenderTemplate(loc, m)
|
||||||
if err != nil {
|
// if err == nil {
|
||||||
t.Error(err)
|
// t.Fatalf("expected error to generate template")
|
||||||
}
|
// }
|
||||||
_ = r
|
// _, err = Run(bi, &st, &rs, context.TODO())
|
||||||
}
|
// if err != nil {
|
||||||
|
// t.Error(err)
|
||||||
func TestRunMoveAndBack(t *testing.T) {
|
// }
|
||||||
st := state.NewState(5)
|
// m, err = st.Get()
|
||||||
rs := TestResource{}
|
// if err != nil {
|
||||||
rt := router.NewRouter()
|
// t.Fatal(err)
|
||||||
rt.Add("foo", "bar")
|
// }
|
||||||
b := []byte{0x03}
|
// _, err = rs.RenderTemplate(loc, m)
|
||||||
b = append(b, []byte("foo")...)
|
// if err != nil {
|
||||||
b = append(b, rt.ToBytes()...)
|
// t.Fatal(err)
|
||||||
bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
// }
|
||||||
|
//}
|
||||||
var err error
|
//
|
||||||
st, b, err = Apply(b, bi, st, &rs, context.TODO())
|
//func TestRunMoveAndBack(t *testing.T) {
|
||||||
if err != nil {
|
// st := state.NewState(5)
|
||||||
t.Error(err)
|
// rs := TestResource{}
|
||||||
}
|
// rt := router.NewRouter()
|
||||||
l := len(b)
|
// rt.Add("foo", "bar")
|
||||||
if l != 0 {
|
// b := []byte{0x03}
|
||||||
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
// b = append(b, []byte("foo")...)
|
||||||
}
|
// //b = append(b, rt.ToBytes()...)
|
||||||
|
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
rt = router.NewRouter()
|
//
|
||||||
rt.Add("foo", "baz")
|
// var err error
|
||||||
b = []byte{0x03}
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
b = append(b, []byte("foo")...)
|
// if err != nil {
|
||||||
b = append(b, rt.ToBytes()...)
|
// t.Error(err)
|
||||||
bi = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
// }
|
||||||
st, b, err = Apply(b, bi, st, &rs, context.TODO())
|
// l := len(b)
|
||||||
if err != nil {
|
// if l != 0 {
|
||||||
t.Error(err)
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
}
|
// }
|
||||||
l = len(b)
|
//
|
||||||
if l != 0 {
|
// rt = router.NewRouter()
|
||||||
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
// rt.Add("foo", "baz")
|
||||||
}
|
// b = []byte{0x03}
|
||||||
|
// b = append(b, []byte("foo")...)
|
||||||
rt = router.NewRouter()
|
// b = append(b, rt.ToBytes()...)
|
||||||
rt.Add("foo", "_")
|
// bi = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
||||||
b = []byte{0x03}
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
b = append(b, []byte("foo")...)
|
// if err != nil {
|
||||||
b = append(b, rt.ToBytes()...)
|
// t.Error(err)
|
||||||
st, b, err = Apply(b, []byte{}, st, &rs, context.TODO())
|
// }
|
||||||
if err != nil {
|
// l = len(b)
|
||||||
t.Error(err)
|
// if l != 0 {
|
||||||
}
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
l = len(b)
|
// }
|
||||||
if l != 0 {
|
//
|
||||||
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
// rt = router.NewRouter()
|
||||||
}
|
// rt.Add("foo", "_")
|
||||||
loc := st.Where()
|
// b = []byte{0x03}
|
||||||
if loc != "bar" {
|
// b = append(b, []byte("foo")...)
|
||||||
t.Errorf("expected where-string 'bar', got %v", loc)
|
// //b = append(b, rt.ToBytes()...)
|
||||||
}
|
// b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
||||||
}
|
// if err != nil {
|
||||||
|
// t.Error(err)
|
||||||
|
// }
|
||||||
|
// l = len(b)
|
||||||
|
// if l != 0 {
|
||||||
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
|
// }
|
||||||
|
// loc := st.Where()
|
||||||
|
// if loc != "bar" {
|
||||||
|
// t.Errorf("expected where-string 'bar', got %v", loc)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
func TestCatchAndBack(t *testing.T) {
|
func TestCatchAndBack(t *testing.T) {
|
||||||
st := state.NewState(5)
|
st := state.NewState(5)
|
||||||
@ -353,7 +364,7 @@ func TestCatchAndBack(t *testing.T) {
|
|||||||
b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
||||||
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
||||||
st, _, err := Run(b, st, &rs, context.TODO())
|
_, err := Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -366,7 +377,7 @@ func TestCatchAndBack(t *testing.T) {
|
|||||||
b = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
b = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
||||||
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
||||||
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
||||||
st, _, err = Run(b, st, &rs, context.TODO())
|
_, err = Run(b, &st, &rs, context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user