commit 767321fa2c064b1c6e6ca1df3ea107cefda6a250
parent c0d38513d3619675cd7f614c41bbbd58f0cf368d
Author: lash <dev@holbrook.no>
Date: Fri, 31 Mar 2023 10:59:55 +0100
WIP apply map command
Diffstat:
6 files changed, 153 insertions(+), 8 deletions(-)
diff --git a/go/resource/resource.go b/go/resource/resource.go
@@ -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)
}
diff --git a/go/state/state.go b/go/state/state.go
@@ -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
+}
diff --git a/go/state/state_test.go b/go/state/state_test.go
@@ -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")
+}
diff --git a/go/vm/opcodes.go b/go/vm/opcodes.go
@@ -7,5 +7,7 @@ const (
CROAK
LOAD
RELOAD
+ MAP
+ SINK
_MAX
)
diff --git a/go/vm/vm.go b/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
}
+
+
diff --git a/go/vm/vm_test.go b/go/vm/vm_test.go
@@ -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)
+ }
+
+
+}