Add hello world example

This commit is contained in:
lash 2023-04-17 06:35:36 +01:00
parent 100f7f3b48
commit afb3ff3a36
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
11 changed files with 48 additions and 29 deletions

View File

@ -1,4 +1,4 @@
examples: profile session
examples: profile session helloworld
.PHONY: examples
@ -7,3 +7,6 @@ profile:
session:
bash examples/compile.bash examples/session
helloworld:
bash examples/compile.bash examples/helloworld

View File

@ -38,6 +38,7 @@ Original motivation was to create a simple templating renderer for USSD clients,
* Breakpoints.
* Key/value database reference example.
* Same-page catch with dedicated error string to prepend to template
## Opcodes

View File

@ -23,11 +23,20 @@ func main() {
ctx := context.Background()
en := engine.NewSizedEngine(dir, uint32(size))
err := en.Init(ctx)
cont, err := en.Init(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
os.Exit(1)
}
if !cont {
_, err = en.WriteResult(os.Stdout, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "dead init write error: %v\n", err)
os.Exit(1)
}
os.Stdout.Write([]byte{0x0a})
os.Exit(0)
}
err = engine.Loop(&en, os.Stdin, os.Stdout, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)

View File

@ -53,37 +53,34 @@ func NewEngine(cfg Config, st *state.State, rs resource.Resource, ca cache.Memor
// Init must be explicitly called before using the Engine instance.
//
// It loads and executes code for the start node.
func(en *Engine) Init(ctx context.Context) error {
func(en *Engine) Init(ctx context.Context) (bool, error) {
if en.initd {
log.Printf("already initialized")
return nil
return true, nil
}
sym := en.root
if sym == "" {
return fmt.Errorf("start sym empty")
return false, fmt.Errorf("start sym empty")
}
inSave, _ := en.st.GetInput()
err := en.st.SetInput([]byte{})
if err != nil {
return err
return false, err
}
b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil)
log.Printf("start new init VM run with code %x", b)
b, err = en.vm.Run(b, ctx)
if err != nil {
return err
}
if len(b) == 0 {
return fmt.Errorf("no code left after init, that's just useless and sad")
return false, err
}
log.Printf("ended init VM run with code %x", b)
en.st.SetCode(b)
err = en.st.SetInput(inSave)
if err != nil {
return err
return false, err
}
en.initd = true
return nil
return len(b) > 0, nil
}
// Exec processes user input against the current state of the virtual machine environment.
@ -99,13 +96,11 @@ func(en *Engine) Init(ctx context.Context) error {
func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
var err error
if en.st.Moves == 0 {
err = en.Init(ctx)
cont, err := en.Init(ctx)
if err != nil {
return false, err
}
if len(input) == 0 {
return true, nil
}
return cont, nil
}
err = vm.ValidInput(input)
if err != nil {
@ -146,7 +141,7 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
en.st.SetCode(code)
if len(code) == 0 {
log.Printf("runner finished with no remaining code")
err = en.reset(ctx)
_, err = en.reset(ctx)
return false, err
}
@ -168,17 +163,17 @@ func(en *Engine) WriteResult(w io.Writer, ctx context.Context) (int, error) {
}
// start execution over at top node while keeping current state of client error flags.
func(en *Engine) reset(ctx context.Context) error {
func(en *Engine) reset(ctx context.Context) (bool, error) {
var err error
var isTop bool
for !isTop {
isTop, err = en.st.Top()
if err != nil {
return err
return false, err
}
_, err = en.st.Up()
if err != nil {
return err
return false, err
}
en.ca.Pop()
}

View File

@ -85,7 +85,7 @@ func TestEngineInit(t *testing.T) {
Root: "root",
}, &st, &rs, ca, ctx)
err = en.Init(ctx)
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}
@ -141,7 +141,8 @@ func TestEngineExecInvalidInput(t *testing.T) {
en := NewEngine(Config{
Root: "root",
}, &st, &rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}
@ -161,7 +162,8 @@ func TestEngineResumeTerminated(t *testing.T) {
en := NewEngine(Config{
Root: "root",
}, &st, &rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}

View File

@ -24,7 +24,8 @@ func TestLoopTop(t *testing.T) {
Root: "root",
}
en := NewEngine(cfg, &st, &rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}
@ -60,7 +61,8 @@ func TestLoopBackForth(t *testing.T) {
Root: "root",
}
en := NewEngine(cfg, &st, &rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}
@ -94,7 +96,8 @@ func TestLoopBrowse(t *testing.T) {
Root: "root",
}
en := NewEngine(cfg, &st, &rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
}

View File

@ -0,0 +1 @@
world

1
examples/helloworld/root Normal file
View File

@ -0,0 +1 @@
hello, {{.que}}!

View File

@ -0,0 +1,2 @@
LOAD que 5
MAP que

View File

@ -124,7 +124,8 @@ func main() {
}
ctx := context.Background()
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
os.Exit(1)

View File

@ -72,7 +72,8 @@ func main() {
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
err := en.Init(ctx)
var err error
_, err = en.Init(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
os.Exit(1)