commit afb3ff3a36ef84b343b4a4c8e92dc8287386b302
parent 100f7f3b48193f432bb18a6058b6414f78355939
Author: lash <dev@holbrook.no>
Date: Mon, 17 Apr 2023 06:35:36 +0100
Add hello world example
Diffstat:
11 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/Makefile b/Makefile
@@ -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
diff --git a/README.md b/README.md
@@ -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
diff --git a/dev/interactive/main.go b/dev/interactive/main.go
@@ -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)
diff --git a/engine/engine.go b/engine/engine.go
@@ -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()
}
diff --git a/engine/engine_test.go b/engine/engine_test.go
@@ -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)
}
diff --git a/engine/loop_test.go b/engine/loop_test.go
@@ -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)
}
diff --git a/examples/helloworld/que.txt.orig b/examples/helloworld/que.txt.orig
@@ -0,0 +1 @@
+world
+\ No newline at end of file
diff --git a/examples/helloworld/root b/examples/helloworld/root
@@ -0,0 +1 @@
+hello, {{.que}}!
diff --git a/examples/helloworld/root.vis b/examples/helloworld/root.vis
@@ -0,0 +1,2 @@
+LOAD que 5
+MAP que
diff --git a/examples/profile/main.go b/examples/profile/main.go
@@ -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)
diff --git a/examples/session/main.go b/examples/session/main.go
@@ -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)