commit a3073f6189b34da5d4e8bc71cb7f1b3882dde154
parent 6325ef4afda403c1b4db5f6d6ee3f13e8813078a
Author: lash <dev@holbrook.no>
Date: Thu, 6 Apr 2023 10:08:40 +0100
WIP Add termination handler in engine
Diffstat:
7 files changed, 47 insertions(+), 28 deletions(-)
diff --git a/go/asm/asm.go b/go/asm/asm.go
@@ -321,7 +321,6 @@ func(bt *Batcher) MenuExit(w io.Writer) (int, error) {
}
bt.inMenu = false
b := bt.menuProcessor.ToLines()
- log.Printf("tolines %v", b)
return w.Write(b)
}
diff --git a/go/dev/interactive.go b/go/dev/interactive.go
@@ -41,7 +41,7 @@ func main() {
os.Exit(1)
}
in = strings.TrimSpace(in)
- err = en.Exec([]byte(in), ctx)
+ running, err = en.Exec([]byte(in), ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "execution terminated: %v\n", err)
os.Exit(1)
@@ -50,4 +50,5 @@ func main() {
en.WriteResult(b)
fmt.Println(b.String())
}
+
}
diff --git a/go/engine/engine.go b/go/engine/engine.go
@@ -59,22 +59,38 @@ func(en *Engine) Init(sym string, ctx context.Context) error {
// - input is objectively invalid (too long etc)
// - no current bytecode is available
// - input processing against bytcode failed
-func (en *Engine) Exec(input []byte, ctx context.Context) error {
+func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) {
err := en.st.SetInput(input)
if err != nil {
- return err
+ return false, err
}
log.Printf("new execution with input '%s' (0x%x)", input, input)
code, err := en.st.GetCode()
if err != nil {
- return err
+ return false, err
}
if len(code) == 0 {
- return fmt.Errorf("no code to execute")
+ return false, fmt.Errorf("no code to execute")
}
code, err = vm.Run(code, en.st, en.rs, ctx)
+ if err != nil {
+ return false, err
+ }
+
+ v, err := en.st.MatchFlag(state.FLAG_TERMINATE, false)
+ if err != nil {
+ return false, err
+ }
+ if v {
+ if len(code) > 0 {
+ log.Printf("terminated with code remaining: %x", code)
+ }
+ return false, nil
+ }
+
en.st.SetCode(code)
- return err
+
+ return true, nil
}
// WriteResult writes the output of the last vm execution to the given writer.
diff --git a/go/engine/engine_test.go b/go/engine/engine_test.go
@@ -97,7 +97,7 @@ func TestEngineInit(t *testing.T) {
}
input := []byte("1")
- err = en.Exec(input, ctx)
+ _, err = en.Exec(input, ctx)
if err != nil {
t.Fatal(err)
}
diff --git a/go/state/state.go b/go/state/state.go
@@ -135,6 +135,26 @@ func(st *State) FlagByteSize() uint8 {
return uint8(len(st.Flags))
}
+// MatchFlag matches the current state of the given flag.
+//
+// The flag is specified given its bit index in the bit field.
+//
+// If invertMatch is set, a positive result will be returned if the flag is not set.
+func(st *State) MatchFlag(sig uint32, invertMatch bool) (bool, error) {
+ r, err := st.GetFlag(sig)
+ if err != nil {
+ return false, err
+ }
+ if invertMatch {
+ if !r {
+ return true, nil
+ }
+ } else if r {
+ return true, nil
+ }
+ return false, nil
+}
+
// GetIndex scans a byte slice in same order as in storage, and returns the index of the first set bit.
//
// If the given byte slice is too small for the bit field bitsize, the check will terminate at end-of-data without error.
diff --git a/go/vm/runner.go b/go/vm/runner.go
@@ -82,7 +82,7 @@ func RunDeadCheck(b []byte, st *state.State, rs resource.Resource, ctx context.C
return b, nil
}
log.Printf("no code remaining, let's check if we terminate")
- r, err := matchFlag(st, state.FLAG_TERMINATE, false)
+ r, err := st.MatchFlag(state.FLAG_TERMINATE, false)
if err != nil {
panic(err)
}
@@ -114,7 +114,7 @@ func RunCatch(b []byte, st *state.State, rs resource.Resource, ctx context.Conte
if err != nil {
return b, err
}
- r, err := matchFlag(st, sig, mode)
+ r, err := st.MatchFlag(sig, mode)
if err != nil {
return b, err
}
@@ -132,7 +132,7 @@ func RunCroak(b []byte, st *state.State, rs resource.Resource, ctx context.Conte
if err != nil {
return b, err
}
- r, err := matchFlag(st, sig, mode)
+ r, err := st.MatchFlag(sig, mode)
if err != nil {
return b, err
}
diff --git a/go/vm/vm.go b/go/vm/vm.go
@@ -3,8 +3,6 @@ package vm
import (
"encoding/binary"
"fmt"
-
- "git.defalsify.org/festive/state"
)
// NewLine creates a new instruction line for the VM.
@@ -177,21 +175,6 @@ func parseSig(b []byte) (uint32, bool, []byte, error) {
return sig, matchmode, b, nil
}
-// TODO: move to state
-func matchFlag(st *state.State, sig uint32, invertMatch bool) (bool, error) {
- r, err := st.GetFlag(sig)
- if err != nil {
- return false, err
- }
- if invertMatch {
- if !r {
- return true, nil
- }
- } else if r {
- return true, nil
- }
- return false, nil
-}
// split bytecode into head and b using length-prefixed bitfield
func byteSplit(b []byte) ([]byte, []byte, error) {