WIP apply map command
This commit is contained in:
parent
c0d38513d3
commit
767321fa2c
@ -1,7 +1,13 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type EntryFunc func(input []byte, ctx context.Context) (string, error)
|
||||
|
||||
type Fetcher interface {
|
||||
Get(symbol string) (string, error)
|
||||
Render(symbol string, values map[string]string) (string, error)
|
||||
Get(sym string) (string, error)
|
||||
Render(sym string, values map[string]string) (string, error)
|
||||
FuncFor(sym string) (EntryFunc, error)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
@ -9,7 +8,8 @@ type State struct {
|
||||
OutputSize uint16
|
||||
CacheSize uint32
|
||||
CacheUseSize uint32
|
||||
Cache io.ReadWriteSeeker
|
||||
Cache []map[string]string
|
||||
ExecPath []string
|
||||
}
|
||||
|
||||
func NewState(bitSize uint64, outputSize uint16) State {
|
||||
@ -26,7 +26,6 @@ func NewState(bitSize uint64, outputSize uint16) State {
|
||||
OutputSize: outputSize,
|
||||
CacheSize: 0,
|
||||
CacheUseSize: 0,
|
||||
Cache: nil,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,3 +33,17 @@ func(st State) WithCacheSize(cacheSize uint32) State {
|
||||
st.CacheSize = cacheSize
|
||||
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
|
||||
LOAD
|
||||
RELOAD
|
||||
MAP
|
||||
SINK
|
||||
_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)
|
||||
case RELOAD:
|
||||
RunReload(instruction[2:], st, rs, ctx)
|
||||
case MAP:
|
||||
RunMap(instruction[2:], st, rs, ctx)
|
||||
case SINK:
|
||||
RunSink(instruction[2:], st, rs, ctx)
|
||||
default:
|
||||
err := fmt.Errorf("Unhandled state: %v", op)
|
||||
return st, err
|
||||
@ -32,10 +36,37 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return st, nil
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,26 +4,60 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"text/template"
|
||||
"bytes"
|
||||
|
||||
"git.defalsify.org/festive/resource"
|
||||
"git.defalsify.org/festive/state"
|
||||
)
|
||||
|
||||
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) {
|
||||
switch sym {
|
||||
case "foo":
|
||||
return "inky pinky blinky clyde", nil
|
||||
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)
|
||||
}
|
||||
|
||||
func (r *TestResource) Render(sym string, values map[string]string) (string, error) {
|
||||
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) {
|
||||
@ -42,3 +76,54 @@ func TestRun(t *testing.T) {
|
||||
}
|
||||
_ = 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