Add hello world example
This commit is contained in:
parent
100f7f3b48
commit
afb3ff3a36
5
Makefile
5
Makefile
@ -1,4 +1,4 @@
|
|||||||
examples: profile session
|
examples: profile session helloworld
|
||||||
|
|
||||||
.PHONY: examples
|
.PHONY: examples
|
||||||
|
|
||||||
@ -7,3 +7,6 @@ profile:
|
|||||||
|
|
||||||
session:
|
session:
|
||||||
bash examples/compile.bash examples/session
|
bash examples/compile.bash examples/session
|
||||||
|
|
||||||
|
helloworld:
|
||||||
|
bash examples/compile.bash examples/helloworld
|
||||||
|
@ -38,6 +38,7 @@ Original motivation was to create a simple templating renderer for USSD clients,
|
|||||||
|
|
||||||
* Breakpoints.
|
* Breakpoints.
|
||||||
* Key/value database reference example.
|
* Key/value database reference example.
|
||||||
|
* Same-page catch with dedicated error string to prepend to template
|
||||||
|
|
||||||
|
|
||||||
## Opcodes
|
## Opcodes
|
||||||
|
@ -23,11 +23,20 @@ func main() {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
en := engine.NewSizedEngine(dir, uint32(size))
|
en := engine.NewSizedEngine(dir, uint32(size))
|
||||||
err := en.Init(ctx)
|
cont, err := en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
|
||||||
os.Exit(1)
|
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)
|
err = engine.Loop(&en, os.Stdin, os.Stdout, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)
|
||||||
|
@ -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.
|
// Init must be explicitly called before using the Engine instance.
|
||||||
//
|
//
|
||||||
// It loads and executes code for the start node.
|
// 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 {
|
if en.initd {
|
||||||
log.Printf("already initialized")
|
log.Printf("already initialized")
|
||||||
return nil
|
return true, nil
|
||||||
}
|
}
|
||||||
sym := en.root
|
sym := en.root
|
||||||
if sym == "" {
|
if sym == "" {
|
||||||
return fmt.Errorf("start sym empty")
|
return false, fmt.Errorf("start sym empty")
|
||||||
}
|
}
|
||||||
inSave, _ := en.st.GetInput()
|
inSave, _ := en.st.GetInput()
|
||||||
err := en.st.SetInput([]byte{})
|
err := en.st.SetInput([]byte{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil)
|
b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil)
|
||||||
log.Printf("start new init VM run with code %x", b)
|
log.Printf("start new init VM run with code %x", b)
|
||||||
b, err = en.vm.Run(b, ctx)
|
b, err = en.vm.Run(b, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
|
||||||
if len(b) == 0 {
|
|
||||||
return fmt.Errorf("no code left after init, that's just useless and sad")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("ended init VM run with code %x", b)
|
log.Printf("ended init VM run with code %x", b)
|
||||||
en.st.SetCode(b)
|
en.st.SetCode(b)
|
||||||
err = en.st.SetInput(inSave)
|
err = en.st.SetInput(inSave)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
en.initd = true
|
return len(b) > 0, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec processes user input against the current state of the virtual machine environment.
|
// 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) {
|
func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
|
||||||
var err error
|
var err error
|
||||||
if en.st.Moves == 0 {
|
if en.st.Moves == 0 {
|
||||||
err = en.Init(ctx)
|
cont, err := en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if len(input) == 0 {
|
return cont, nil
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err = vm.ValidInput(input)
|
err = vm.ValidInput(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -146,7 +141,7 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
|
|||||||
en.st.SetCode(code)
|
en.st.SetCode(code)
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
log.Printf("runner finished with no remaining code")
|
log.Printf("runner finished with no remaining code")
|
||||||
err = en.reset(ctx)
|
_, err = en.reset(ctx)
|
||||||
return false, err
|
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.
|
// 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 err error
|
||||||
var isTop bool
|
var isTop bool
|
||||||
for !isTop {
|
for !isTop {
|
||||||
isTop, err = en.st.Top()
|
isTop, err = en.st.Top()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
_, err = en.st.Up()
|
_, err = en.st.Up()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
en.ca.Pop()
|
en.ca.Pop()
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ func TestEngineInit(t *testing.T) {
|
|||||||
Root: "root",
|
Root: "root",
|
||||||
}, &st, &rs, ca, ctx)
|
}, &st, &rs, ca, ctx)
|
||||||
|
|
||||||
err = en.Init(ctx)
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -141,7 +141,8 @@ func TestEngineExecInvalidInput(t *testing.T) {
|
|||||||
en := NewEngine(Config{
|
en := NewEngine(Config{
|
||||||
Root: "root",
|
Root: "root",
|
||||||
}, &st, &rs, ca, ctx)
|
}, &st, &rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -161,7 +162,8 @@ func TestEngineResumeTerminated(t *testing.T) {
|
|||||||
en := NewEngine(Config{
|
en := NewEngine(Config{
|
||||||
Root: "root",
|
Root: "root",
|
||||||
}, &st, &rs, ca, ctx)
|
}, &st, &rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ func TestLoopTop(t *testing.T) {
|
|||||||
Root: "root",
|
Root: "root",
|
||||||
}
|
}
|
||||||
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -60,7 +61,8 @@ func TestLoopBackForth(t *testing.T) {
|
|||||||
Root: "root",
|
Root: "root",
|
||||||
}
|
}
|
||||||
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -94,7 +96,8 @@ func TestLoopBrowse(t *testing.T) {
|
|||||||
Root: "root",
|
Root: "root",
|
||||||
}
|
}
|
||||||
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
en := NewEngine(cfg, &st, &rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
1
examples/helloworld/que.txt.orig
Normal file
1
examples/helloworld/que.txt.orig
Normal file
@ -0,0 +1 @@
|
|||||||
|
world
|
1
examples/helloworld/root
Normal file
1
examples/helloworld/root
Normal file
@ -0,0 +1 @@
|
|||||||
|
hello, {{.que}}!
|
2
examples/helloworld/root.vis
Normal file
2
examples/helloworld/root.vis
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
LOAD que 5
|
||||||
|
MAP que
|
@ -124,7 +124,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
|
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
|
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -72,7 +72,8 @@ func main() {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
|
en := engine.NewEngine(cfg, &st, rs, ca, ctx)
|
||||||
err := en.Init(ctx)
|
var err error
|
||||||
|
_, err = en.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
|
fmt.Fprintf(os.Stderr, "engine init fail: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
Loading…
Reference in New Issue
Block a user