WIP apply map command
This commit is contained in:
parent
c0d38513d3
commit
767321fa2c
@ -1,7 +1,13 @@
|
|||||||
package resource
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntryFunc func(input []byte, ctx context.Context) (string, error)
|
||||||
|
|
||||||
type Fetcher interface {
|
type Fetcher interface {
|
||||||
Get(symbol string) (string, error)
|
Get(sym string) (string, error)
|
||||||
Render(symbol string, values map[string]string) (string, error)
|
Render(sym string, values map[string]string) (string, error)
|
||||||
|
FuncFor(sym string) (EntryFunc, error)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
@ -9,7 +8,8 @@ type State struct {
|
|||||||
OutputSize uint16
|
OutputSize uint16
|
||||||
CacheSize uint32
|
CacheSize uint32
|
||||||
CacheUseSize uint32
|
CacheUseSize uint32
|
||||||
Cache io.ReadWriteSeeker
|
Cache []map[string]string
|
||||||
|
ExecPath []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(bitSize uint64, outputSize uint16) State {
|
func NewState(bitSize uint64, outputSize uint16) State {
|
||||||
@ -26,7 +26,6 @@ func NewState(bitSize uint64, outputSize uint16) State {
|
|||||||
OutputSize: outputSize,
|
OutputSize: outputSize,
|
||||||
CacheSize: 0,
|
CacheSize: 0,
|
||||||
CacheUseSize: 0,
|
CacheUseSize: 0,
|
||||||
Cache: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,3 +33,17 @@ func(st State) WithCacheSize(cacheSize uint32) State {
|
|||||||
st.CacheSize = cacheSize
|
st.CacheSize = cacheSize
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func(st *State) Enter(input string) {
|
||||||
|
m := make(map[string]string)
|
||||||
|
st.Cache = append(st.Cache, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func(st *State) Add(k string, v string) error {
|
||||||
|
st.Cache[len(st.Cache)-1][k] = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func(st *State) Get() (map[string]string, error) {
|
||||||
|
return st.Cache[len(st.Cache)-1], nil
|
||||||
|
}
|
||||||
|
@ -31,3 +31,9 @@ func TestNewStateCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateCacheUse(t *testing.T) {
|
||||||
|
st := NewState(17, 0)
|
||||||
|
st.Enter("foo")
|
||||||
|
st.Add("bar", "baz")
|
||||||
|
}
|
||||||
|
@ -7,5 +7,7 @@ const (
|
|||||||
CROAK
|
CROAK
|
||||||
LOAD
|
LOAD
|
||||||
RELOAD
|
RELOAD
|
||||||
|
MAP
|
||||||
|
SINK
|
||||||
_MAX
|
_MAX
|
||||||
)
|
)
|
||||||
|
35
go/vm/vm.go
35
go/vm/vm.go
@ -25,6 +25,10 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
|
|||||||
RunLoad(instruction[2:], st, rs, ctx)
|
RunLoad(instruction[2:], st, rs, ctx)
|
||||||
case RELOAD:
|
case RELOAD:
|
||||||
RunReload(instruction[2:], st, rs, ctx)
|
RunReload(instruction[2:], st, rs, ctx)
|
||||||
|
case MAP:
|
||||||
|
RunMap(instruction[2:], st, rs, ctx)
|
||||||
|
case SINK:
|
||||||
|
RunSink(instruction[2:], st, rs, ctx)
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("Unhandled state: %v", op)
|
err := fmt.Errorf("Unhandled state: %v", op)
|
||||||
return st, err
|
return st, err
|
||||||
@ -32,10 +36,37 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
|
|||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
func instructionSplit(b []byte) (string, []byte, error) {
|
||||||
|
sz := uint8(b[0])
|
||||||
|
tailSz := uint8(len(b))
|
||||||
|
if tailSz - 1 < sz {
|
||||||
|
return "", nil, fmt.Errorf("corrupt instruction, len %v less than symbol length: %v", tailSz, sz)
|
||||||
|
}
|
||||||
|
r := string(b[1:1+sz])
|
||||||
|
return r, b[1+sz:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunMap(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
||||||
|
head, tail, err := instructionSplit(instruction)
|
||||||
|
fn, err := rs.FuncFor(head)
|
||||||
|
if err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
r, err := fn(tail, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
st.Add(head, r)
|
||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunSink(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
||||||
|
return st, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
||||||
|
return st, nil
|
||||||
|
}
|
||||||
|
|
||||||
func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
||||||
return st, nil
|
return st, nil
|
||||||
@ -48,3 +79,5 @@ func RunLoad(instruction []byte, st state.State, rs resource.Fetcher, ctx contex
|
|||||||
func RunReload(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
func RunReload(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, error) {
|
||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,26 +4,60 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"git.defalsify.org/festive/resource"
|
||||||
"git.defalsify.org/festive/state"
|
"git.defalsify.org/festive/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestResource struct {
|
type TestResource struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOne(input []byte, ctx context.Context) (string, error) {
|
||||||
|
return "one", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTwo(input []byte, ctx context.Context) (string, error) {
|
||||||
|
return "two", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *TestResource) Get(sym string) (string, error) {
|
func (r *TestResource) Get(sym string) (string, error) {
|
||||||
switch sym {
|
switch sym {
|
||||||
case "foo":
|
case "foo":
|
||||||
return "inky pinky blinky clyde", nil
|
return "inky pinky blinky clyde", nil
|
||||||
case "bar":
|
case "bar":
|
||||||
return "inky pinky {.one} blinky {.two} clyde", nil
|
return "inky pinky {{.one}} blinky {{.two}} clyde", nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("unknown symbol %s", sym)
|
return "", fmt.Errorf("unknown symbol %s", sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TestResource) Render(sym string, values map[string]string) (string, error) {
|
func (r *TestResource) Render(sym string, values map[string]string) (string, error) {
|
||||||
v, err := r.Get(sym)
|
v, err := r.Get(sym)
|
||||||
return v, err
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
t, err := template.New("tester").Option("missingkey=error").Parse(v)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := bytes.NewBuffer([]byte{})
|
||||||
|
err = t.Execute(b, values)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return b.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *TestResource) FuncFor(sym string) (resource.EntryFunc, error) {
|
||||||
|
switch sym {
|
||||||
|
case "one":
|
||||||
|
return getOne, nil
|
||||||
|
case "two":
|
||||||
|
return getTwo, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("invalid function: '%s'", sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRun(t *testing.T) {
|
func TestRun(t *testing.T) {
|
||||||
@ -42,3 +76,54 @@ func TestRun(t *testing.T) {
|
|||||||
}
|
}
|
||||||
_ = r
|
_ = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunMap(t *testing.T) {
|
||||||
|
st := state.NewState(5, 255)
|
||||||
|
st.Enter("barbarbar")
|
||||||
|
rs := TestResource{}
|
||||||
|
sym := "one"
|
||||||
|
ins := append([]byte{uint8(len(sym))}, []byte(sym)...)
|
||||||
|
var err error
|
||||||
|
st, err = RunMap(ins, st, &rs, context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
m, err := st.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
r, err := rs.Render("foo", m)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
expect := "inky pinky blinky clyde"
|
||||||
|
if r != expect {
|
||||||
|
t.Errorf("Expected %v, got %v", []byte(expect), []byte(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err = rs.Render("bar", m)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error for render of bar: %v" ,err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = "two"
|
||||||
|
ins = append([]byte{uint8(len(sym))}, []byte(sym)...)
|
||||||
|
st, err = RunMap(ins, st, &rs, context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
m, err = st.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
r, err = rs.Render("bar", m)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
expect = "inky pinky one blinky two clyde"
|
||||||
|
if r != expect {
|
||||||
|
t.Errorf("Expected %v, got %v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user