From afb3ff3a36ef84b343b4a4c8e92dc8287386b302 Mon Sep 17 00:00:00 2001 From: lash Date: Mon, 17 Apr 2023 06:35:36 +0100 Subject: [PATCH] Add hello world example --- Makefile | 5 ++++- README.md | 1 + dev/interactive/main.go | 11 ++++++++++- engine/engine.go | 33 ++++++++++++++------------------ engine/engine_test.go | 8 +++++--- engine/loop_test.go | 9 ++++++--- examples/helloworld/que.txt.orig | 1 + examples/helloworld/root | 1 + examples/helloworld/root.vis | 2 ++ examples/profile/main.go | 3 ++- examples/session/main.go | 3 ++- 11 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 examples/helloworld/que.txt.orig create mode 100644 examples/helloworld/root create mode 100644 examples/helloworld/root.vis diff --git a/Makefile b/Makefile index 156bf52..ad93bda 100644 --- 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 index 336d3ab..f5cc9d5 100644 --- 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 index 0a0ae8c..274a188 100644 --- 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 index 25a7245..643d569 100644 --- 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 index 5d6c186..e6a9d70 100644 --- 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 index d55b94c..308882d 100644 --- 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 new file mode 100644 index 0000000..04fea06 --- /dev/null +++ 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 new file mode 100644 index 0000000..f37f25b --- /dev/null +++ b/examples/helloworld/root @@ -0,0 +1 @@ +hello, {{.que}}! diff --git a/examples/helloworld/root.vis b/examples/helloworld/root.vis new file mode 100644 index 0000000..e352321 --- /dev/null +++ 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 index efbd619..f11a508 100644 --- 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 index 9bd9289..61b8699 100644 --- 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)