From 39eafc8ff272cb0c0b59cf789ee21bba51df4b5a Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 1 Apr 2023 10:58:02 +0100 Subject: [PATCH] Add engine object --- go/engine/engine.go | 48 ++++++++++++++++++++++++ go/engine/engine_test.go | 81 ++++++++++++++++++++++++++++++++++++++++ go/go.mod | 2 + go/resource/fs.go | 21 +++++++++-- go/resource/resource.go | 7 ++-- go/state/state.go | 1 + go/testdata/root | 1 + go/vm/vm.go | 7 ---- go/vm/vm_test.go | 18 +++++---- 9 files changed, 166 insertions(+), 20 deletions(-) create mode 100644 go/engine/engine.go create mode 100644 go/engine/engine_test.go create mode 100644 go/testdata/root diff --git a/go/engine/engine.go b/go/engine/engine.go new file mode 100644 index 0000000..2f18b9b --- /dev/null +++ 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 new file mode 100644 index 0000000..6da7e0a --- /dev/null +++ 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 index c38aca7..77af5ba 100644 --- 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 index d54f14c..e31a853 100644 --- 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) { +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) RenderTemplate(sym string, values map[string]string) (string, error) { return "", nil } -func(fs *FsResource) Render(sym string, values []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 index 2c27084..1aea752 100644 --- 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 index 8404cc4..dfe535c 100644 --- 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 new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/go/testdata/root @@ -0,0 +1 @@ +hello world diff --git a/go/vm/vm.go b/go/vm/vm.go index 3ade799..4f62374 100644 --- 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 index 0848a69..568268c 100644 --- 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) }