Add HALT opcode
This commit is contained in:
parent
3febf0a6e2
commit
4181fe0576
@ -16,6 +16,7 @@ The VM defines the following opcode symbols:
|
|||||||
* `RELOAD <symbol>` - Execute a code symbol already loaded by `LOAD` and cache the data, constrained to the previously given `size` for the same symbol.
|
* `RELOAD <symbol>` - Execute a code symbol already loaded by `LOAD` and cache the data, constrained to the previously given `size` for the same symbol.
|
||||||
* `MAP <symbol>` - Expose a code symbol previously loaded by `LOAD` to the rendering client. Roughly corresponds to the `global` directive in Python.
|
* `MAP <symbol>` - Expose a code symbol previously loaded by `LOAD` to the rendering client. Roughly corresponds to the `global` directive in Python.
|
||||||
* `MOVE <symbol>` - Create a new execution frame, invalidating all previous `MAP` calls. More detailed: After a `MOVE` call, a `BACK` call will return to the same execution frame, with the same symbols available, but all `MAP` calls will have to be repeated.
|
* `MOVE <symbol>` - Create a new execution frame, invalidating all previous `MAP` calls. More detailed: After a `MOVE` call, a `BACK` call will return to the same execution frame, with the same symbols available, but all `MAP` calls will have to be repeated.
|
||||||
|
* 'HALT' - Stop execution. The remaining bytecode (typicaly, the routing code for the node) is returned to the invoking function.
|
||||||
|
|
||||||
|
|
||||||
### External code
|
### External code
|
||||||
|
@ -6,14 +6,15 @@ import (
|
|||||||
const VERSION = 0
|
const VERSION = 0
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BACK = iota
|
BACK = 0
|
||||||
CATCH
|
CATCH = 1
|
||||||
CROAK
|
CROAK = 2
|
||||||
LOAD
|
LOAD = 3
|
||||||
RELOAD
|
RELOAD = 4
|
||||||
MAP
|
MAP = 5
|
||||||
MOVE
|
MOVE = 6
|
||||||
_MAX
|
HALT = 7
|
||||||
|
_MAX = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLine(instructionList []byte, instruction uint16, args []string, post []byte, szPost []uint8) []byte {
|
func NewLine(instructionList []byte, instruction uint16, args []string, post []byte, szPost []uint8) []byte {
|
||||||
|
@ -96,6 +96,9 @@ func Run(instruction []byte, st *state.State, rs resource.Resource, ctx context.
|
|||||||
instruction, err = RunMove(instruction[2:], st, rs, ctx)
|
instruction, err = RunMove(instruction[2:], st, rs, ctx)
|
||||||
case BACK:
|
case BACK:
|
||||||
instruction, err = RunBack(instruction[2:], st, rs, ctx)
|
instruction, err = RunBack(instruction[2:], st, rs, ctx)
|
||||||
|
case HALT:
|
||||||
|
log.Printf("found HALT, stopping")
|
||||||
|
return instruction[2:], err
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Unhandled state: %v", op)
|
err = fmt.Errorf("Unhandled state: %v", op)
|
||||||
}
|
}
|
||||||
|
227
go/vm/vm_test.go
227
go/vm/vm_test.go
@ -50,6 +50,8 @@ func (r *TestResource) GetTemplate(sym string) (string, error) {
|
|||||||
return "inky pinky {{.baz}} blinky clyde", nil
|
return "inky pinky {{.baz}} blinky clyde", nil
|
||||||
case "three":
|
case "three":
|
||||||
return "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}", nil
|
return "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}", nil
|
||||||
|
case "_catch":
|
||||||
|
return "aiee", nil
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("unknown symbol %s", sym))
|
panic(fmt.Sprintf("unknown symbol %s", sym))
|
||||||
return "", fmt.Errorf("unknown symbol %s", sym)
|
return "", fmt.Errorf("unknown symbol %s", sym)
|
||||||
@ -253,108 +255,112 @@ func TestRunArgInvalid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//func TestRunArgInstructions(t *testing.T) {
|
func TestRunArgInstructions(t *testing.T) {
|
||||||
// st := state.NewState(5)
|
t.Skip("pending fix for separating router code from executing code")
|
||||||
// rs := TestResource{}
|
st := state.NewState(5)
|
||||||
//
|
rs := TestResource{}
|
||||||
// rt := router.NewRouter()
|
|
||||||
// rt.Add("foo", "bar")
|
rt := router.NewRouter()
|
||||||
// b := []byte{0x03}
|
rt.Add("foo", "bar")
|
||||||
// b = append(b, []byte("foo")...)
|
b := []byte{0x03}
|
||||||
|
b = append(b, []byte("foo")...)
|
||||||
|
|
||||||
|
bi := NewLine(rt.ToBytes(), LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
|
bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
|
||||||
|
bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
|
||||||
|
bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
|
||||||
|
var err error
|
||||||
|
b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
l := len(b)
|
||||||
|
if l != 0 {
|
||||||
|
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
|
}
|
||||||
|
loc := st.Where()
|
||||||
|
if loc != "bar" {
|
||||||
|
t.Errorf("expected where-state bar, got %v", loc)
|
||||||
|
}
|
||||||
|
m, err := st.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
r, err := rs.RenderTemplate(loc, m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err) //f("expected error to generate template")
|
||||||
|
}
|
||||||
|
if r != "aiee" {
|
||||||
|
t.Fatalf("expected result 'aiee', got '%v'", r)
|
||||||
|
}
|
||||||
|
_, err = Run(bi, &st, &rs, context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
m, err = st.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = rs.RenderTemplate(loc, m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunMoveAndBack(t *testing.T) {
|
||||||
|
t.Skip("pending fix for separating router code from executing code")
|
||||||
|
st := state.NewState(5)
|
||||||
|
rs := TestResource{}
|
||||||
|
rt := router.NewRouter()
|
||||||
|
rt.Add("foo", "bar")
|
||||||
|
b := []byte{0x03}
|
||||||
|
b = append(b, []byte("foo")...)
|
||||||
//b = append(b, rt.ToBytes()...)
|
//b = append(b, rt.ToBytes()...)
|
||||||
//
|
bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
|
||||||
// bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
|
var err error
|
||||||
// bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
|
b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
// bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
|
if err != nil {
|
||||||
// var err error
|
t.Error(err)
|
||||||
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
}
|
||||||
// if err != nil {
|
l := len(b)
|
||||||
// t.Error(err)
|
if l != 0 {
|
||||||
// }
|
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
// l := len(b)
|
}
|
||||||
// if l != 0 {
|
|
||||||
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
rt = router.NewRouter()
|
||||||
// }
|
rt.Add("foo", "baz")
|
||||||
// loc := st.Where()
|
b = []byte{0x03}
|
||||||
// if loc != "bar" {
|
b = append(b, []byte("foo")...)
|
||||||
// t.Errorf("expected where-state bar, got %v", loc)
|
b = append(b, rt.ToBytes()...)
|
||||||
// }
|
bi = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
||||||
// m, err := st.Get()
|
b, err = Apply(b, bi, &st, &rs, context.TODO())
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// t.Fatal(err)
|
t.Error(err)
|
||||||
// }
|
}
|
||||||
// _, err = rs.RenderTemplate(loc, m)
|
l = len(b)
|
||||||
// if err == nil {
|
if l != 0 {
|
||||||
// t.Fatalf("expected error to generate template")
|
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
// }
|
}
|
||||||
// _, err = Run(bi, &st, &rs, context.TODO())
|
|
||||||
// if err != nil {
|
rt = router.NewRouter()
|
||||||
// t.Error(err)
|
rt.Add("foo", "_")
|
||||||
// }
|
b = []byte{0x03}
|
||||||
// m, err = st.Get()
|
b = append(b, []byte("foo")...)
|
||||||
// if err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// }
|
|
||||||
// _, err = rs.RenderTemplate(loc, m)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func TestRunMoveAndBack(t *testing.T) {
|
|
||||||
// st := state.NewState(5)
|
|
||||||
// rs := TestResource{}
|
|
||||||
// rt := router.NewRouter()
|
|
||||||
// rt.Add("foo", "bar")
|
|
||||||
// b := []byte{0x03}
|
|
||||||
// b = append(b, []byte("foo")...)
|
|
||||||
// //b = append(b, rt.ToBytes()...)
|
|
||||||
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
|
||||||
//
|
|
||||||
// var err error
|
|
||||||
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error(err)
|
|
||||||
// }
|
|
||||||
// l := len(b)
|
|
||||||
// if l != 0 {
|
|
||||||
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// rt = router.NewRouter()
|
|
||||||
// rt.Add("foo", "baz")
|
|
||||||
// b = []byte{0x03}
|
|
||||||
// b = append(b, []byte("foo")...)
|
|
||||||
//b = append(b, rt.ToBytes()...)
|
//b = append(b, rt.ToBytes()...)
|
||||||
// bi = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
||||||
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
if err != nil {
|
||||||
// if err != nil {
|
t.Error(err)
|
||||||
// t.Error(err)
|
}
|
||||||
// }
|
l = len(b)
|
||||||
// l = len(b)
|
if l != 0 {
|
||||||
// if l != 0 {
|
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
||||||
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
}
|
||||||
// }
|
loc := st.Where()
|
||||||
//
|
if loc != "bar" {
|
||||||
// rt = router.NewRouter()
|
t.Errorf("expected where-string 'bar', got %v", loc)
|
||||||
// rt.Add("foo", "_")
|
}
|
||||||
// b = []byte{0x03}
|
}
|
||||||
// b = append(b, []byte("foo")...)
|
|
||||||
// //b = append(b, rt.ToBytes()...)
|
|
||||||
// b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error(err)
|
|
||||||
// }
|
|
||||||
// l = len(b)
|
|
||||||
// if l != 0 {
|
|
||||||
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
||||||
// }
|
|
||||||
// loc := st.Where()
|
|
||||||
// if loc != "bar" {
|
|
||||||
// t.Errorf("expected where-string 'bar', got %v", loc)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func TestCatchAndBack(t *testing.T) {
|
func TestCatchAndBack(t *testing.T) {
|
||||||
st := state.NewState(5)
|
st := state.NewState(5)
|
||||||
@ -396,3 +402,24 @@ func TestCatchAndBack(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestHalt(t *testing.T) {
|
||||||
|
st := state.NewState(5)
|
||||||
|
rs := TestResource{}
|
||||||
|
b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
||||||
|
b = NewLine(b, HALT, nil, nil, nil)
|
||||||
|
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
||||||
|
var err error
|
||||||
|
b, err = Run(b, &st, &rs, context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
r := st.Where()
|
||||||
|
if r == "foo" {
|
||||||
|
t.Fatalf("Expected where-symbol not to be 'foo'")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(b[:2], []byte{0x00, MOVE}) {
|
||||||
|
t.Fatalf("Expected MOVE instruction, found '%v'", b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user