commit 39eafc8ff272cb0c0b59cf789ee21bba51df4b5a
parent 832228ba11f612037d119750397c7552af8ea15d
Author: lash <dev@holbrook.no>
Date: Sat, 1 Apr 2023 10:58:02 +0100
Add engine object
Diffstat:
9 files changed, 166 insertions(+), 20 deletions(-)
diff --git a/go/engine/engine.go b/go/engine/engine.go
@@ -0,0 +1,48 @@
+package engine
+
+import (
+ "context"
+ "io"
+ "log"
+
+ "git.defalsify.org/festive/resource"
+ "git.defalsify.org/festive/state"
+ "git.defalsify.org/festive/vm"
+)
+//
+//type Config struct {
+// FlagCount uint32
+// CacheSize uint32
+//}
+
+type Engine struct {
+ st state.State
+ rs resource.Resource
+}
+
+func NewEngine(st state.State, rs resource.Resource) Engine {
+ engine := Engine{st, rs}
+ return engine
+}
+
+func(en *Engine) Init(ctx context.Context) error {
+ b := vm.NewLine([]byte{}, vm.MOVE, []string{"root"}, nil, nil)
+ var err error
+ en.st, _, err = vm.Run(b, en.st, en.rs, ctx)
+ return err
+}
+
+func(en *Engine) WriteResult(w io.Writer) error {
+ location := en.st.Where()
+ v, err := en.st.Get()
+ if err != nil {
+ return err
+ }
+ r, err := en.rs.RenderTemplate(location, v)
+ if err != nil {
+ return err
+ }
+ c, err := io.WriteString(w, r)
+ log.Printf("%v bytes written as result for %v", c, location)
+ return err
+}
diff --git a/go/engine/engine_test.go b/go/engine/engine_test.go
@@ -0,0 +1,81 @@
+package engine
+
+import (
+ "bytes"
+ "context"
+ "log"
+ "path"
+ "text/template"
+ "testing"
+
+ testdataloader "github.com/peteole/testdata-loader"
+
+ "git.defalsify.org/festive/state"
+ "git.defalsify.org/festive/resource"
+)
+
+type FsWrapper struct {
+ *resource.FsResource
+ st state.State
+}
+
+func NewFsWrapper(path string, st state.State, ctx context.Context) FsWrapper {
+ rs := resource.NewFsResource(path, ctx)
+ return FsWrapper {
+ &rs,
+ st,
+ }
+}
+
+func (r FsWrapper) RenderTemplate(sym string, values map[string]string) (string, error) {
+ v, err := r.GetTemplate(sym)
+ if err != nil {
+ return "", err
+ }
+ tp, err := template.New("tester").Option("missingkey=error").Parse(v)
+ if err != nil {
+ return "", err
+ }
+
+ b := bytes.NewBuffer([]byte{})
+ err = tp.Execute(b, values)
+ if err != nil {
+ return "", err
+ }
+ log.Printf("template is %v render is %v", v, b)
+ return b.String(), err
+}
+
+func(fs FsWrapper) FuncFor(sym string) (resource.EntryFunc, error) {
+ return nil, nil
+}
+
+func TestEngineInit(t *testing.T) {
+// cfg := Config{
+// FlagCount: 12,
+// CacheSize: 1024,
+// }
+ st := state.NewState(17).WithCacheSize(1024)
+// dir, err := ioutil.TempDir("", "festive_test_")
+// if err != nil {
+// t.Fatal(err)
+// }
+ dir := path.Join(testdataloader.GetBasePath(), "testdata")
+ ctx := context.TODO()
+ rs := NewFsWrapper(dir, st, ctx)
+ en := NewEngine(st, rs)
+ err := en.Init(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ w := bytes.NewBuffer(nil)
+ err = en.WriteResult(w)
+ if err != nil {
+ t.Fatal(err)
+ }
+ b := w.Bytes()
+ if !bytes.Equal(b, []byte("hello world")) {
+ t.Fatalf("expected result 'hello world', got %v", b)
+ }
+}
diff --git a/go/go.mod b/go/go.mod
@@ -1,3 +1,5 @@
module git.defalsify.org/festive
go 1.20
+
+require github.com/peteole/testdata-loader v0.3.0
diff --git a/go/resource/fs.go b/go/resource/fs.go
@@ -2,6 +2,10 @@ package resource
import (
"context"
+ "fmt"
+ "io/ioutil"
+ "path"
+ "strings"
)
type FsResource struct {
@@ -16,10 +20,21 @@ func NewFsResource(path string, ctx context.Context) (FsResource) {
}
}
-func(fs *FsResource) Get(sym string) (string, error) {
- return "", nil
+func(fs FsResource) GetTemplate(sym string) (string, error) {
+ fp := path.Join(fs.path, sym)
+ r, err := ioutil.ReadFile(fp)
+ s := string(r)
+ return strings.TrimSpace(s), err
}
-func(fs *FsResource) Render(sym string, values []string) (string, error) {
+func(fs FsResource) RenderTemplate(sym string, values map[string]string) (string, error) {
return "", nil
}
+
+func(fs FsResource) GetCode(sym string) ([]byte, error) {
+ return []byte{}, nil
+}
+
+func(fs FsResource) FuncFor(sym string) (EntryFunc, error) {
+ return nil, fmt.Errorf("not implemented")
+}
diff --git a/go/resource/resource.go b/go/resource/resource.go
@@ -9,7 +9,8 @@ type EntryFunc func(ctx context.Context) (string, error)
// 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)
- Render(sym string, values map[string]string) (string, error)
- FuncFor(sym string) (EntryFunc, error)
+ GetTemplate(sym string) (string, error) // Get the template for a given symbol.
+ GetCode(sym string) ([]byte, error) // Get the bytecode for the given symbol.
+ RenderTemplate(sym string, values map[string]string) (string, error) // Render the given data map using the template of the symbol.
+ FuncFor(sym string) (EntryFunc, error) // Resolve symbol code point for.
}
diff --git a/go/state/state.go b/go/state/state.go
@@ -26,6 +26,7 @@ type State struct {
CacheUseSize uint32 // Currently used bytes by all values in cache
Cache []map[string]string // All loaded cache items
CacheMap map[string]string // Mapped
+ Code []byte // Pending bytecode to execute
execPath []string // Command symbols stack
arg *string // Optional argument. Nil if not set.
sizes map[string]uint16 // Size limits for all loaded symbols.
diff --git a/go/testdata/root b/go/testdata/root
@@ -0,0 +1 @@
+hello world
diff --git a/go/vm/vm.go b/go/vm/vm.go
@@ -120,18 +120,11 @@ func RunCatch(instruction []byte, st state.State, rs resource.Resource, ctx cont
if err != nil {
return st, instruction, err
}
- // TODO: perhaps check against the registered byte size
- //l := st.FlagByteSize()
bitFieldSize := tail[0]
bitField := tail[1:1+bitFieldSize]
tail = tail[1+bitFieldSize:]
if st.GetIndex(bitField) {
log.Printf("catch at flag %v, moving to %v", bitField, head)
-// r, err := rs.Get(head)
-// if err != nil {
-// return st, instruction, err
-// }
- //st.Add(head, r, 0)
st.Down(head)
tail = []byte{}
}
diff --git a/go/vm/vm_test.go b/go/vm/vm_test.go
@@ -40,7 +40,7 @@ func (r *TestResource) getEachArg(ctx context.Context) (string, error) {
return r.state.PopArg()
}
-func (r *TestResource) Get(sym string) (string, error) {
+func (r *TestResource) GetTemplate(sym string) (string, error) {
switch sym {
case "foo":
return "inky pinky blinky clyde", nil
@@ -55,8 +55,8 @@ func (r *TestResource) Get(sym string) (string, error) {
return "", fmt.Errorf("unknown symbol %s", sym)
}
-func (r *TestResource) Render(sym string, values map[string]string) (string, error) {
- v, err := r.Get(sym)
+func (r *TestResource) RenderTemplate(sym string, values map[string]string) (string, error) {
+ v, err := r.GetTemplate(sym)
if err != nil {
return "", err
}
@@ -87,6 +87,10 @@ func (r *TestResource) FuncFor(sym string) (resource.EntryFunc, error) {
return nil, fmt.Errorf("invalid function: '%s'", sym)
}
+func (r *TestResource) GetCode(sym string) ([]byte, error) {
+ return []byte{}, nil
+}
+
func TestRun(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
@@ -121,7 +125,7 @@ func TestRunLoadRender(t *testing.T) {
if err != nil {
t.Error(err)
}
- r, err := rs.Render("foo", m)
+ r, err := rs.RenderTemplate("foo", m)
if err != nil {
t.Error(err)
}
@@ -130,7 +134,7 @@ func TestRunLoadRender(t *testing.T) {
t.Errorf("Expected %v, got %v", []byte(expect), []byte(r))
}
- r, err = rs.Render("bar", m)
+ r, err = rs.RenderTemplate("bar", m)
if err == nil {
t.Errorf("expected error for render of bar: %v" ,err)
}
@@ -146,7 +150,7 @@ func TestRunLoadRender(t *testing.T) {
if err != nil {
t.Error(err)
}
- r, err = rs.Render("bar", m)
+ r, err = rs.RenderTemplate("bar", m)
if err != nil {
t.Error(err)
}
@@ -280,7 +284,7 @@ func TestRunArgInstructions(t *testing.T) {
if err != nil {
t.Error(err)
}
- r, err := rs.Render(loc, m)
+ r, err := rs.RenderTemplate(loc, m)
if err != nil {
t.Error(err)
}