Remove unused input from EntryFunc, add docs
This commit is contained in:
parent
b0a3324409
commit
f7bcf8896b
@ -4,9 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EntryFunc func(input []byte, ctx context.Context) (string, error)
|
// EntryFunc is a function signature for retrieving value for a key
|
||||||
|
type EntryFunc func(ctx context.Context) (string, error)
|
||||||
|
|
||||||
type Fetcher interface {
|
// Resource implementation are responsible for retrieving values and templates for symbols, and can render templates from value dictionaries.
|
||||||
|
type Resource interface {
|
||||||
Get(sym string) (string, error)
|
Get(sym string) (string, error)
|
||||||
Render(sym string, values map[string]string) (string, error)
|
Render(sym string, values map[string]string) (string, error)
|
||||||
FuncFor(sym string) (EntryFunc, error)
|
FuncFor(sym string) (EntryFunc, error)
|
||||||
|
@ -4,23 +4,33 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Router contains and parses the routing section of the bytecode for a node.
|
||||||
type Router struct {
|
type Router struct {
|
||||||
selectors []string
|
selectors []string
|
||||||
symbols map[string]string
|
symbols map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRouter creates a new Router object.
|
||||||
func NewRouter() Router {
|
func NewRouter() Router {
|
||||||
return Router{
|
return Router{
|
||||||
symbols: make(map[string]string),
|
symbols: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStaticRouter creates a new Router object with a single destination.
|
||||||
|
//
|
||||||
|
// Used for routes that consume input value instead of navigation choices.
|
||||||
func NewStaticRouter(symbol string) Router {
|
func NewStaticRouter(symbol string) Router {
|
||||||
return Router{
|
return Router{
|
||||||
symbols: map[string]string{"_": symbol},
|
symbols: map[string]string{"_": symbol},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add associates a selector with a destination symbol.
|
||||||
|
//
|
||||||
|
// Fails if:
|
||||||
|
// - selector or symbol value is invalid
|
||||||
|
// - selector already exists
|
||||||
func(r *Router) Add(selector string, symbol string) error {
|
func(r *Router) Add(selector string, symbol string) error {
|
||||||
if r.symbols[selector] != "" {
|
if r.symbols[selector] != "" {
|
||||||
return fmt.Errorf("selector %v already set to symbol %v", selector, symbol)
|
return fmt.Errorf("selector %v already set to symbol %v", selector, symbol)
|
||||||
@ -41,14 +51,27 @@ func(r *Router) Add(selector string, symbol string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get retrieve symbol for selector.
|
||||||
|
//
|
||||||
|
// Returns an empty string if selector does not exist.
|
||||||
|
//
|
||||||
|
// Will always return an empty string if the router is static.
|
||||||
func(r *Router) Get(selector string) string {
|
func(r *Router) Get(selector string) string {
|
||||||
return r.symbols[selector]
|
return r.symbols[selector]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the statically defined symbol destination.
|
||||||
|
//
|
||||||
|
// Returns an empty string if not a static router.
|
||||||
func(r *Router) Default() string {
|
func(r *Router) Default() string {
|
||||||
return r.symbols["_"]
|
return r.symbols["_"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next removes one selector from the list of registered selectors.
|
||||||
|
//
|
||||||
|
// It returns it together with it associated value in bytecode form.
|
||||||
|
//
|
||||||
|
// Returns an empty byte array if no more selectors remain.
|
||||||
func(r *Router) Next() []byte {
|
func(r *Router) Next() []byte {
|
||||||
if len(r.selectors) == 0 {
|
if len(r.selectors) == 0 {
|
||||||
return []byte{}
|
return []byte{}
|
||||||
@ -70,6 +93,9 @@ func(r *Router) Next() []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToBytes consume all selectors and values and returns them in sequence in bytecode form.
|
||||||
|
//
|
||||||
|
// This is identical to concatenating all returned values from non-empty Next() results.
|
||||||
func(r *Router) ToBytes() []byte {
|
func(r *Router) ToBytes() []byte {
|
||||||
b := []byte{}
|
b := []byte{}
|
||||||
for true {
|
for true {
|
||||||
@ -82,6 +108,9 @@ func(r *Router) ToBytes() []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore a Router from bytecode.
|
||||||
|
//
|
||||||
|
// FromBytes(ToBytes()) creates an identical object.
|
||||||
func FromBytes(b []byte) Router {
|
func FromBytes(b []byte) Router {
|
||||||
rb := NewRouter()
|
rb := NewRouter()
|
||||||
navigable := true
|
navigable := true
|
||||||
|
@ -5,19 +5,33 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// State holds the command stack, error condition of a unique execution session.
|
||||||
|
//
|
||||||
|
// It also holds cached values for all results of executed symbols.
|
||||||
|
//
|
||||||
|
// Cached values are linked to the command stack level it which they were loaded. When they go out of scope they are freed.
|
||||||
|
//
|
||||||
|
// Values must be mapped to a level in order to be available for retrieval and count towards size
|
||||||
|
//
|
||||||
|
// It can hold a single argument, which is freed once it is read
|
||||||
|
//
|
||||||
|
// Symbols are loaded with individual size limitations. The limitations apply if a load symbol is updated. Symbols may be added with a 0-value for limits, called a "sink." If mapped, the sink will consume all net remaining size allowance unused by other symbols. Only one sink may be mapped per level.
|
||||||
|
//
|
||||||
|
// Symbol keys do not count towards cache size limitations.
|
||||||
type State struct {
|
type State struct {
|
||||||
Flags []byte
|
Flags []byte // Error state
|
||||||
CacheSize uint32
|
CacheSize uint32 // Total allowed cumulative size of values in cache
|
||||||
CacheUseSize uint32
|
CacheUseSize uint32 // Currently used bytes by all values in cache
|
||||||
Cache []map[string]string
|
Cache []map[string]string // All loaded cache items
|
||||||
CacheMap map[string]string
|
CacheMap map[string]string // Mapped
|
||||||
ExecPath []string
|
execPath []string // Command symbols stack
|
||||||
Arg *string
|
arg *string // Optional argument. Nil if not set.
|
||||||
sizes map[string]uint16
|
sizes map[string]uint16 // Size limits for all loaded symbols.
|
||||||
sink *string
|
sink *string //
|
||||||
//sizeIdx uint16
|
//sizeIdx uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewState creates a new State object with bitSize number of error condition states.
|
||||||
func NewState(bitSize uint64) State {
|
func NewState(bitSize uint64) State {
|
||||||
if bitSize == 0 {
|
if bitSize == 0 {
|
||||||
panic("bitsize cannot be 0")
|
panic("bitsize cannot be 0")
|
||||||
@ -36,40 +50,61 @@ func NewState(bitSize uint64) State {
|
|||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
func(st State) Where() string {
|
// WithCacheSize applies a cumulative cache size limitation for all cached items.
|
||||||
if len(st.ExecPath) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
l := len(st.ExecPath)
|
|
||||||
return st.ExecPath[l-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func(st State) WithCacheSize(cacheSize uint32) State {
|
func(st State) WithCacheSize(cacheSize uint32) State {
|
||||||
st.CacheSize = cacheSize
|
st.CacheSize = cacheSize
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Where returns the current active rendering symbol.
|
||||||
|
func(st State) Where() string {
|
||||||
|
if len(st.execPath) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
l := len(st.execPath)
|
||||||
|
return st.execPath[l-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutArg adds the optional argument.
|
||||||
|
//
|
||||||
|
// Fails if arg already set.
|
||||||
func(st *State) PutArg(input string) error {
|
func(st *State) PutArg(input string) error {
|
||||||
st.Arg = &input
|
st.arg = &input
|
||||||
|
if st.arg != nil {
|
||||||
|
return fmt.Errorf("arg already set to %s", *st.arg)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PopArg retrieves the optional argument. Will be freed upon retrieval.
|
||||||
|
//
|
||||||
|
// Fails if arg not set (or already freed).
|
||||||
func(st *State) PopArg() (string, error) {
|
func(st *State) PopArg() (string, error) {
|
||||||
if st.Arg == nil {
|
if st.arg == nil {
|
||||||
return "", fmt.Errorf("arg is not set")
|
return "", fmt.Errorf("arg is not set")
|
||||||
}
|
}
|
||||||
return *st.Arg, nil
|
return *st.arg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Down adds the given symbol to the command stack.
|
||||||
|
//
|
||||||
|
// Clears mapping and sink.
|
||||||
func(st *State) Down(input string) {
|
func(st *State) Down(input string) {
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
st.Cache = append(st.Cache, m)
|
st.Cache = append(st.Cache, m)
|
||||||
st.sizes = make(map[string]uint16)
|
st.sizes = make(map[string]uint16)
|
||||||
st.ExecPath = append(st.ExecPath, input)
|
st.execPath = append(st.execPath, input)
|
||||||
st.resetCurrent()
|
st.resetCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Up removes the latest symbol to the command stack, and make the previous symbol current.
|
||||||
|
//
|
||||||
|
// Frees all symbols and associated values loaded at the previous stack level. Cache capacity is increased by the corresponding amount.
|
||||||
|
//
|
||||||
|
// Clears mapping and sink.
|
||||||
|
//
|
||||||
|
// Fails if called at top frame.
|
||||||
func(st *State) Up() error {
|
func(st *State) Up() error {
|
||||||
l := len(st.Cache)
|
l := len(st.Cache)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
@ -83,16 +118,24 @@ func(st *State) Up() error {
|
|||||||
log.Printf("free frame %v key %v value size %v", l, k, sz)
|
log.Printf("free frame %v key %v value size %v", l, k, sz)
|
||||||
}
|
}
|
||||||
st.Cache = st.Cache[:l]
|
st.Cache = st.Cache[:l]
|
||||||
st.ExecPath = st.ExecPath[:l]
|
st.execPath = st.execPath[:l]
|
||||||
st.resetCurrent()
|
st.resetCurrent()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func(st *State) Add(key string, value string, sizeHint uint16) error {
|
// Add adds a cache value under a cache symbol key.
|
||||||
if sizeHint > 0 {
|
//
|
||||||
|
// Also stores the size limitation of for key for later updates.
|
||||||
|
//
|
||||||
|
// Fails if:
|
||||||
|
// - key already defined
|
||||||
|
// - value is longer than size limit
|
||||||
|
// - adding value exceeds cumulative cache capacity
|
||||||
|
func(st *State) Add(key string, value string, sizeLimit uint16) error {
|
||||||
|
if sizeLimit > 0 {
|
||||||
l := uint16(len(value))
|
l := uint16(len(value))
|
||||||
if l > sizeHint {
|
if l > sizeLimit {
|
||||||
return fmt.Errorf("value length %v exceeds value size limit %v", l, sizeHint)
|
return fmt.Errorf("value length %v exceeds value size limit %v", l, sizeLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkFrame := st.frameOf(key)
|
checkFrame := st.frameOf(key)
|
||||||
@ -106,16 +149,24 @@ func(st *State) Add(key string, value string, sizeHint uint16) error {
|
|||||||
log.Printf("add key %s value size %v", key, sz)
|
log.Printf("add key %s value size %v", key, sz)
|
||||||
st.Cache[len(st.Cache)-1][key] = value
|
st.Cache[len(st.Cache)-1][key] = value
|
||||||
st.CacheUseSize += sz
|
st.CacheUseSize += sz
|
||||||
st.sizes[key] = sizeHint
|
st.sizes[key] = sizeLimit
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update sets a new value for an existing key.
|
||||||
|
//
|
||||||
|
// Uses the size limitation from when the key was added.
|
||||||
|
//
|
||||||
|
// Fails if:
|
||||||
|
// - key not defined
|
||||||
|
// - value is longer than size limit
|
||||||
|
// - replacing value exceeds cumulative cache capacity
|
||||||
func(st *State) Update(key string, value string) error {
|
func(st *State) Update(key string, value string) error {
|
||||||
sizeHint := st.sizes[key]
|
sizeLimit := st.sizes[key]
|
||||||
if st.sizes[key] > 0 {
|
if st.sizes[key] > 0 {
|
||||||
l := uint16(len(value))
|
l := uint16(len(value))
|
||||||
if l > sizeHint {
|
if l > sizeLimit {
|
||||||
return fmt.Errorf("update value length %v exceeds value size limit %v", l, sizeHint)
|
return fmt.Errorf("update value length %v exceeds value size limit %v", l, sizeLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkFrame := st.frameOf(key)
|
checkFrame := st.frameOf(key)
|
||||||
@ -139,6 +190,11 @@ func(st *State) Update(key string, value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map marks the given key for retrieval.
|
||||||
|
//
|
||||||
|
// After this, Val() will return the value for the key, and Size() will include the value size and limitations in its calculations.
|
||||||
|
//
|
||||||
|
// Only one symbol with no size limitation may be mapped at the current level.
|
||||||
func(st *State) Map(key string) error {
|
func(st *State) Map(key string) error {
|
||||||
m, err := st.Get()
|
m, err := st.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,10 +211,12 @@ func(st *State) Map(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Depth returns the current call stack depth.
|
||||||
func(st *State) Depth() uint8 {
|
func(st *State) Depth() uint8 {
|
||||||
return uint8(len(st.Cache))
|
return uint8(len(st.Cache))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the full key-value mapping for all mapped keys at the current cache level.
|
||||||
func(st *State) Get() (map[string]string, error) {
|
func(st *State) Get() (map[string]string, error) {
|
||||||
if len(st.Cache) == 0 {
|
if len(st.Cache) == 0 {
|
||||||
return nil, fmt.Errorf("get at top frame")
|
return nil, fmt.Errorf("get at top frame")
|
||||||
@ -166,6 +224,9 @@ func(st *State) Get() (map[string]string, error) {
|
|||||||
return st.Cache[len(st.Cache)-1], nil
|
return st.Cache[len(st.Cache)-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Val returns value for key
|
||||||
|
//
|
||||||
|
// Fails if key is not mapped.
|
||||||
func(st *State) Val(key string) (string, error) {
|
func(st *State) Val(key string) (string, error) {
|
||||||
r := st.CacheMap[key]
|
r := st.CacheMap[key]
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
@ -174,7 +235,7 @@ func(st *State) Val(key string) (string, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset flushes all state contents below the top level, and returns to the top level.
|
||||||
func(st *State) Reset() {
|
func(st *State) Reset() {
|
||||||
if len(st.Cache) == 0 {
|
if len(st.Cache) == 0 {
|
||||||
return
|
return
|
||||||
@ -184,6 +245,7 @@ func(st *State) Reset() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check returns true if a key already exists in the cache.
|
||||||
func(st *State) Check(key string) bool {
|
func(st *State) Check(key string) bool {
|
||||||
return st.frameOf(key) == -1
|
return st.frameOf(key) == -1
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Check creation and testing of state flags
|
||||||
func TestNewStateFlags(t *testing.T) {
|
func TestNewStateFlags(t *testing.T) {
|
||||||
st := NewState(5)
|
st := NewState(5)
|
||||||
if len(st.Flags) != 1 {
|
if len(st.Flags) != 1 {
|
||||||
@ -20,6 +21,7 @@ func TestNewStateFlags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
func TestNewStateCache(t *testing.T) {
|
func TestNewStateCache(t *testing.T) {
|
||||||
st := NewState(17)
|
st := NewState(17)
|
||||||
if st.CacheSize != 0 {
|
if st.CacheSize != 0 {
|
||||||
|
49
go/vm/vm.go
49
go/vm/vm.go
@ -11,7 +11,7 @@ import (
|
|||||||
"git.defalsify.org/festive/state"
|
"git.defalsify.org/festive/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
//type Runner func(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error)
|
//type Runner func(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error)
|
||||||
|
|
||||||
func argFromBytes(input []byte) (string, []byte, error) {
|
func argFromBytes(input []byte) (string, []byte, error) {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
@ -22,7 +22,14 @@ func argFromBytes(input []byte) (string, []byte, error) {
|
|||||||
return string(out), input[1+sz:], nil
|
return string(out), input[1+sz:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Apply(input []byte, instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// Apply applies input to router bytecode to resolve the node symbol to execute.
|
||||||
|
//
|
||||||
|
// The execution byte code is initialized with the appropriate MOVE
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
func Apply(input []byte, instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
arg, input, err := argFromBytes(input)
|
arg, input, err := argFromBytes(input)
|
||||||
@ -52,7 +59,12 @@ func Apply(input []byte, instruction []byte, st state.State, rs resource.Fetcher
|
|||||||
return st, instruction, nil
|
return st, instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// Run extracts individual op codes and arguments and executes them.
|
||||||
|
//
|
||||||
|
// Each step may update the state.
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
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)
|
||||||
@ -92,7 +104,8 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
|
|||||||
return st, instruction, nil
|
return st, instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMap(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunMap executes the MAP opcode
|
||||||
|
func RunMap(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
@ -101,7 +114,8 @@ func RunMap(instruction []byte, st state.State, rs resource.Fetcher, ctx context
|
|||||||
return st, tail, err
|
return st, tail, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunMap executes the CATCH opcode
|
||||||
|
func RunCatch(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
@ -115,7 +129,8 @@ func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx conte
|
|||||||
return st, []byte{}, nil
|
return st, []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunMap executes the CROAK opcode
|
||||||
|
func RunCroak(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
@ -126,7 +141,8 @@ func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx conte
|
|||||||
return st, []byte{}, nil
|
return st, []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunLoad(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunLoad executes the LOAD opcode
|
||||||
|
func RunLoad(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
@ -137,7 +153,7 @@ func RunLoad(instruction []byte, st state.State, rs resource.Fetcher, ctx contex
|
|||||||
sz := uint16(tail[0])
|
sz := uint16(tail[0])
|
||||||
tail = tail[1:]
|
tail = tail[1:]
|
||||||
|
|
||||||
r, err := refresh(head, tail, rs, ctx)
|
r, err := refresh(head, rs, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, tail, err
|
return st, tail, err
|
||||||
}
|
}
|
||||||
@ -145,12 +161,13 @@ func RunLoad(instruction []byte, st state.State, rs resource.Fetcher, ctx contex
|
|||||||
return st, tail, err
|
return st, tail, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunReload(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunLoad executes the RELOAD opcode
|
||||||
|
func RunReload(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
}
|
}
|
||||||
r, err := refresh(head, tail, rs, ctx)
|
r, err := refresh(head, rs, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, tail, err
|
return st, tail, err
|
||||||
}
|
}
|
||||||
@ -158,7 +175,8 @@ func RunReload(instruction []byte, st state.State, rs resource.Fetcher, ctx cont
|
|||||||
return st, tail, nil
|
return st, tail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMove(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunLoad executes the MOVE opcode
|
||||||
|
func RunMove(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
head, tail, err := instructionSplit(instruction)
|
head, tail, err := instructionSplit(instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, instruction, err
|
return st, instruction, err
|
||||||
@ -167,19 +185,22 @@ func RunMove(instruction []byte, st state.State, rs resource.Fetcher, ctx contex
|
|||||||
return st, tail, nil
|
return st, tail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunBack(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
// RunLoad executes the BACK opcode
|
||||||
|
func RunBack(instruction []byte, st state.State, rs resource.Resource, ctx context.Context) (state.State, []byte, error) {
|
||||||
st.Up()
|
st.Up()
|
||||||
return st, instruction, nil
|
return st, instruction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func refresh(key string, sym []byte, rs resource.Fetcher, ctx context.Context) (string, error) {
|
// retrieve data for key
|
||||||
|
func refresh(key string, rs resource.Resource, ctx context.Context) (string, error) {
|
||||||
fn, err := rs.FuncFor(key)
|
fn, err := rs.FuncFor(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return fn(sym, ctx)
|
return fn(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// split instruction into symbol and arguments
|
||||||
func instructionSplit(b []byte) (string, []byte, error) {
|
func instructionSplit(b []byte) (string, []byte, error) {
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return "", nil, fmt.Errorf("argument is empty")
|
return "", nil, fmt.Errorf("argument is empty")
|
||||||
|
@ -19,15 +19,15 @@ type TestResource struct {
|
|||||||
state *state.State
|
state *state.State
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOne(input []byte, ctx context.Context) (string, error) {
|
func getOne(ctx context.Context) (string, error) {
|
||||||
return "one", nil
|
return "one", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTwo(input []byte, ctx context.Context) (string, error) {
|
func getTwo(ctx context.Context) (string, error) {
|
||||||
return "two", nil
|
return "two", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDyn(input []byte, ctx context.Context) (string, error) {
|
func getDyn(ctx context.Context) (string, error) {
|
||||||
return dynVal, nil
|
return dynVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ type TestStatefulResolver struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (r *TestResource) getEachArg(input []byte, ctx context.Context) (string, error) {
|
func (r *TestResource) getEachArg(ctx context.Context) (string, error) {
|
||||||
return r.state.PopArg()
|
return r.state.PopArg()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user