WIP apply map command

This commit is contained in:
lash 2023-03-31 10:59:55 +01:00
parent c0d38513d3
commit 767321fa2c
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 153 additions and 8 deletions

View File

@ -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)
} }

View File

@ -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
}

View File

@ -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")
}

View File

@ -7,5 +7,7 @@ const (
CROAK CROAK
LOAD LOAD
RELOAD RELOAD
MAP
SINK
_MAX _MAX
) )

View File

@ -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
} }

View File

@ -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)
}
}