Add engine object

This commit is contained in:
lash 2023-04-01 10:58:02 +01:00
parent 832228ba11
commit 39eafc8ff2
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
9 changed files with 166 additions and 20 deletions

48
go/engine/engine.go Normal file
View File

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

81
go/engine/engine_test.go Normal file
View File

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

View File

@ -1,3 +1,5 @@
module git.defalsify.org/festive module git.defalsify.org/festive
go 1.20 go 1.20
require github.com/peteole/testdata-loader v0.3.0

View File

@ -2,6 +2,10 @@ package resource
import ( import (
"context" "context"
"fmt"
"io/ioutil"
"path"
"strings"
) )
type FsResource struct { 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 return "", nil
} }
func(fs *FsResource) Render(sym string, values []string) (string, error) { func(fs FsResource) GetCode(sym string) ([]byte, error) {
return "", nil return []byte{}, nil
}
func(fs FsResource) FuncFor(sym string) (EntryFunc, error) {
return nil, fmt.Errorf("not implemented")
} }

View File

@ -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. // Resource implementation are responsible for retrieving values and templates for symbols, and can render templates from value dictionaries.
type Resource interface { type Resource interface {
Get(sym string) (string, error) GetTemplate(sym string) (string, error) // Get the template for a given symbol.
Render(sym string, values map[string]string) (string, error) GetCode(sym string) ([]byte, error) // Get the bytecode for the given symbol.
FuncFor(sym string) (EntryFunc, error) 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.
} }

View File

@ -26,6 +26,7 @@ type State struct {
CacheUseSize uint32 // Currently used bytes by all values in cache CacheUseSize uint32 // Currently used bytes by all values in cache
Cache []map[string]string // All loaded cache items Cache []map[string]string // All loaded cache items
CacheMap map[string]string // Mapped CacheMap map[string]string // Mapped
Code []byte // Pending bytecode to execute
execPath []string // Command symbols stack execPath []string // Command symbols stack
arg *string // Optional argument. Nil if not set. arg *string // Optional argument. Nil if not set.
sizes map[string]uint16 // Size limits for all loaded symbols. sizes map[string]uint16 // Size limits for all loaded symbols.

1
go/testdata/root vendored Normal file
View File

@ -0,0 +1 @@
hello world

View File

@ -120,18 +120,11 @@ func RunCatch(instruction []byte, st state.State, rs resource.Resource, ctx cont
if err != nil { if err != nil {
return st, instruction, err return st, instruction, err
} }
// TODO: perhaps check against the registered byte size
//l := st.FlagByteSize()
bitFieldSize := tail[0] bitFieldSize := tail[0]
bitField := tail[1:1+bitFieldSize] bitField := tail[1:1+bitFieldSize]
tail = tail[1+bitFieldSize:] tail = tail[1+bitFieldSize:]
if st.GetIndex(bitField) { if st.GetIndex(bitField) {
log.Printf("catch at flag %v, moving to %v", bitField, head) 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) st.Down(head)
tail = []byte{} tail = []byte{}
} }

View File

@ -40,7 +40,7 @@ func (r *TestResource) getEachArg(ctx context.Context) (string, error) {
return r.state.PopArg() return r.state.PopArg()
} }
func (r *TestResource) Get(sym string) (string, error) { func (r *TestResource) GetTemplate(sym string) (string, error) {
switch sym { switch sym {
case "foo": case "foo":
return "inky pinky blinky clyde", nil 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) return "", fmt.Errorf("unknown symbol %s", sym)
} }
func (r *TestResource) Render(sym string, values map[string]string) (string, error) { func (r *TestResource) RenderTemplate(sym string, values map[string]string) (string, error) {
v, err := r.Get(sym) v, err := r.GetTemplate(sym)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -87,6 +87,10 @@ func (r *TestResource) FuncFor(sym string) (resource.EntryFunc, error) {
return nil, fmt.Errorf("invalid function: '%s'", sym) return nil, fmt.Errorf("invalid function: '%s'", sym)
} }
func (r *TestResource) GetCode(sym string) ([]byte, error) {
return []byte{}, nil
}
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
st := state.NewState(5) st := state.NewState(5)
rs := TestResource{} rs := TestResource{}
@ -121,7 +125,7 @@ func TestRunLoadRender(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
r, err := rs.Render("foo", m) r, err := rs.RenderTemplate("foo", m)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -130,7 +134,7 @@ func TestRunLoadRender(t *testing.T) {
t.Errorf("Expected %v, got %v", []byte(expect), []byte(r)) 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 { if err == nil {
t.Errorf("expected error for render of bar: %v" ,err) t.Errorf("expected error for render of bar: %v" ,err)
} }
@ -146,7 +150,7 @@ func TestRunLoadRender(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
r, err = rs.Render("bar", m) r, err = rs.RenderTemplate("bar", m)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -280,7 +284,7 @@ func TestRunArgInstructions(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
r, err := rs.Render(loc, m) r, err := rs.RenderTemplate(loc, m)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }