Factor out instruction parse from runner in vm

This commit is contained in:
lash 2023-04-02 13:59:40 +01:00
parent 8bd0c44a61
commit aec0564cea
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
4 changed files with 259 additions and 158 deletions

View File

@ -1,7 +1,6 @@
package vm package vm
import ( import (
"encoding/binary"
"context" "context"
"fmt" "fmt"
"log" "log"
@ -17,176 +16,183 @@ import (
// Each step may update the state. // Each step may update the state.
// //
// On error, the remaining instructions will be returned. State will not be rolled back. // On error, the remaining instructions will be returned. State will not be rolled back.
func Run(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
var err error running := true
for len(instruction) > 0 { for running {
log.Printf("instruction is now 0x%x", instruction) log.Printf("code before 0x%x", b)
op := binary.BigEndian.Uint16(instruction[:2]) op, bb, err := opSplit(b)
if op > _MAX { if err != nil {
return instruction, fmt.Errorf("opcode value %v out of range (%v)", op, _MAX) return b, err
} }
b = bb
log.Printf("code after 0x%x", b)
switch op { switch op {
case CATCH: case CATCH:
instruction, err = RunCatch(instruction[2:], st, rs, ctx) b, err = RunCatch(b, st, rs, ctx)
case CROAK: case CROAK:
instruction, err = RunCroak(instruction[2:], st, rs, ctx) b, err = RunCroak(b, st, rs, ctx)
case LOAD: case LOAD:
instruction, err = RunLoad(instruction[2:], st, rs, ctx) b, err = RunLoad(b, st, rs, ctx)
case RELOAD: case RELOAD:
instruction, err = RunReload(instruction[2:], st, rs, ctx) b, err = RunReload(b, st, rs, ctx)
case MAP: case MAP:
instruction, err = RunMap(instruction[2:], st, rs, ctx) b, err = RunMap(b, st, rs, ctx)
case MOVE: case MOVE:
instruction, err = RunMove(instruction[2:], st, rs, ctx) b, err = RunMove(b, st, rs, ctx)
case INCMP: case INCMP:
instruction, err = RunIncmp(instruction[2:], st, rs, ctx) b, err = RunInCmp(b, st, rs, ctx)
log.Printf("bb %v", b)
case HALT: case HALT:
return RunHalt(instruction[2:], st, rs, ctx) b, err = RunHalt(b, st, rs, ctx)
return b, err
default: default:
err = fmt.Errorf("Unhandled state: %v", op) err = fmt.Errorf("Unhandled state: %v", op)
} }
if err != nil { if err != nil {
return instruction, err return b, err
}
log.Printf("aa %v", b)
if len(b) == 0 {
return []byte{}, nil
} }
} }
return instruction, nil return b, nil
} }
// RunMap executes the MAP opcode // RunMap executes the MAP opcode
func RunMap(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunMap(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) sym, b, err := ParseMap(b)
if err != nil { err = st.Map(sym)
return instruction, err return b, err
}
err = st.Map(head)
return tail, err
} }
// RunMap executes the CATCH opcode // RunMap executes the CATCH opcode
func RunCatch(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunCatch(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) sym, sig, mode, b, err := ParseCatch(b)
if err != nil { if err != nil {
return instruction, err return b, err
} }
bitFieldSize := tail[0] r, err := matchFlag(st, sig, mode)
bitField := tail[1:1+bitFieldSize] if err != nil {
tail = tail[1+bitFieldSize:] return b, err
matchMode := tail[0] // matchmode 1 is match NOT set bit
tail = tail[1:]
match := false
if matchMode > 0 {
if !st.GetIndex(bitField) {
match = true
} }
} else if st.GetIndex(bitField) { if r {
match = true log.Printf("catch at flag %v, moving to %v", sig, sym) //bitField, d)
st.Down(sym)
b = []byte{}
} }
return b, nil
if match {
log.Printf("catch at flag %v, moving to %v", bitField, head)
st.Down(head)
tail = []byte{}
}
return tail, nil
} }
// RunMap executes the CROAK opcode // RunMap executes the CROAK opcode
func RunCroak(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunCroak(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) sig, mode, b, err := ParseCroak(b)
if err != nil { if err != nil {
return instruction, err return b, err
} }
_ = head r, err := matchFlag(st, sig, mode)
_ = tail if err != nil {
return b, err
}
if r {
log.Printf("croak at flag %v, purging and moving to top", sig)
st.Reset() st.Reset()
b = []byte{}
}
return []byte{}, nil return []byte{}, nil
} }
// RunLoad executes the LOAD opcode // RunLoad executes the LOAD opcode
func RunLoad(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunLoad(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) // head, tail, err := instructionSplit(b)
// if err != nil {
// return b, err
// }
// if !st.Check(head) {
// return b, fmt.Errorf("key %v already loaded", head)
// }
// sz := uint16(tail[0])
// tail = tail[1:]
sym, sz, b, err := ParseLoad(b)
if err != nil { if err != nil {
return instruction, err return b, err
} }
if !st.Check(head) {
return instruction, fmt.Errorf("key %v already loaded", head)
}
sz := uint16(tail[0])
tail = tail[1:]
r, err := refresh(head, rs, ctx) r, err := refresh(sym, rs, ctx)
if err != nil { if err != nil {
return tail, err return b, err
} }
err = st.Add(head, r, sz) err = st.Add(sym, r, uint16(sz))
return tail, err return b, err
} }
// RunLoad executes the RELOAD opcode // RunLoad executes the RELOAD opcode
func RunReload(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunReload(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) // head, tail, err := instructionSplit(b)
// if err != nil {
// return b, err
// }
sym, b, err := ParseReload(b)
if err != nil { if err != nil {
return instruction, err return b, err
} }
r, err := refresh(head, rs, ctx)
r, err := refresh(sym, rs, ctx)
if err != nil { if err != nil {
return tail, err return b, err
} }
st.Update(head, r) st.Update(sym, r)
return tail, nil return b, nil
} }
// RunLoad executes the MOVE opcode // RunLoad executes the MOVE opcode
func RunMove(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunMove(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) sym, b, err := ParseMove(b)
// head, tail, err := instructionSplit(b)
if err != nil { if err != nil {
return instruction, err return b, err
} }
st.Down(head) st.Down(sym)
return tail, nil return b, nil
}
// RunLoad executes the BACK opcode
func RunBack(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
st.Up()
return instruction, nil
} }
// RunIncmp executes the INCMP opcode // RunIncmp executes the INCMP opcode
func RunIncmp(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunInCmp(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
head, tail, err := instructionSplit(instruction) //head, tail, err := instructionSplit(b)
sym, target, b, err := ParseInCmp(b)
if err != nil { if err != nil {
return instruction, err return b, err
}
sym, tail, err := instructionSplit(tail)
if err != nil {
return instruction, err
} }
v, err := st.GetFlag(state.FLAG_INMATCH) v, err := st.GetFlag(state.FLAG_INMATCH)
if err != nil { if err != nil {
return tail, err return b, err
} }
if v { if v {
return tail, nil return b, nil
} }
input, err := st.GetInput() input, err := st.GetInput()
if err != nil { if err != nil {
return tail, err return b, err
} }
log.Printf("checking input %v %v", input, head) if sym == string(input) {
if head == string(input) {
log.Printf("input match for '%s'", input) log.Printf("input match for '%s'", input)
_, err = st.SetFlag(state.FLAG_INMATCH) _, err = st.SetFlag(state.FLAG_INMATCH)
st.Down(sym) st.Down(target)
} }
return tail, err log.Printf("b last %v", b)
return b, err
} }
// RunHalt executes the HALT opcode // RunHalt executes the HALT opcode
func RunHalt(instruction []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) { func RunHalt(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
var err error
b, err = ParseHalt(b)
if err != nil {
return b, err
}
log.Printf("found HALT, stopping") log.Printf("found HALT, stopping")
_, err := st.ResetFlag(state.FLAG_INMATCH) _, err = st.ResetFlag(state.FLAG_INMATCH)
return instruction, err return b, err
} }

View File

@ -80,11 +80,13 @@ func(r *TestResource) GetCode(sym string) ([]byte, error) {
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
st := state.NewState(5) st := state.NewState(5)
rs := TestResource{} rs := TestResource{}
b := []byte{0x00, MOVE, 0x03}
b = append(b, []byte("foo")...) b := NewLine(nil, MOVE, []string{"foo"}, nil, nil)
//b := []byte{0x00, MOVE, 0x03}
//b = append(b, []byte("foo")...)
_, err := Run(b, &st, &rs, context.TODO()) _, err := Run(b, &st, &rs, context.TODO())
if err != nil { if err != nil {
t.Errorf("error on valid opcode: %v", err) t.Errorf("run error: %v", err)
} }
b = []byte{0x01, 0x02} b = []byte{0x01, 0x02}
@ -98,11 +100,10 @@ func TestRunLoadRender(t *testing.T) {
st := state.NewState(5) st := state.NewState(5)
st.Down("barbarbar") st.Down("barbarbar")
rs := TestResource{} rs := TestResource{}
sym := "one"
ins := append([]byte{uint8(len(sym))}, []byte(sym)...)
ins = append(ins, 0x0a)
var err error var err error
_, err = RunLoad(ins, &st, &rs, context.TODO()) b := NewLine(nil, LOAD, []string{"one"}, []byte{0x0a}, nil)
b, err = Run(b, &st, &rs, context.TODO())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -124,10 +125,13 @@ func TestRunLoadRender(t *testing.T) {
t.Errorf("expected error for render of bar: %v" ,err) t.Errorf("expected error for render of bar: %v" ,err)
} }
sym = "two" b = NewLine(nil, LOAD, []string{"two"}, []byte{0x0a}, nil)
ins = append([]byte{uint8(len(sym))}, []byte(sym)...) b, err = Run(b, &st, &rs, context.TODO())
ins = append(ins, 0) if err != nil {
_, err = RunLoad(ins, &st, &rs, context.TODO()) t.Error(err)
}
b = NewLine(nil, MAP, []string{"one"}, nil, nil)
_, err = Run(b, &st, &rs, context.TODO())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -148,20 +152,21 @@ func TestRunLoadRender(t *testing.T) {
func TestRunMultiple(t *testing.T) { func TestRunMultiple(t *testing.T) {
st := state.NewState(5) st := state.NewState(5)
rs := TestResource{} rs := TestResource{}
b := []byte{} b := NewLine(nil, LOAD, []string{"one"}, []byte{0x00}, nil)
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0}) b = NewLine(b, LOAD, []string{"two"}, []byte{42}, nil)
b = NewLine(b, LOAD, []string{"two"}, nil, []uint8{42}) b, err := Run(b, &st, &rs, context.TODO())
_, err := Run(b, &st, &rs, context.TODO())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
if len(b) > 0 {
t.Errorf("expected empty code")
}
} }
func TestRunReload(t *testing.T) { func TestRunReload(t *testing.T) {
st := state.NewState(5) st := state.NewState(5)
rs := TestResource{} rs := TestResource{}
b := []byte{} b := NewLine(nil, LOAD, []string{"dyn"}, nil, []uint8{0})
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
b = NewLine(b, MAP, []string{"dyn"}, nil, nil) b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
_, err := Run(b, &st, &rs, context.TODO()) _, err := Run(b, &st, &rs, context.TODO())
if err != nil { if err != nil {
@ -242,8 +247,8 @@ func TestRunInputHandler(t *testing.T) {
bi := NewLine([]byte{}, INCMP, []string{"bar", "aiee"}, nil, nil) bi := NewLine([]byte{}, INCMP, []string{"bar", "aiee"}, nil, nil)
bi = NewLine(bi, INCMP, []string{"baz", "foo"}, nil, nil) bi = NewLine(bi, INCMP, []string{"baz", "foo"}, nil, nil)
bi = NewLine(bi, LOAD, []string{"one"}, nil, []uint8{0}) bi = NewLine(bi, LOAD, []string{"one"}, []byte{0x00}, nil)
bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3}) bi = NewLine(bi, LOAD, []string{"two"}, []byte{0x03}, nil)
bi = NewLine(bi, MAP, []string{"one"}, nil, nil) bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
bi = NewLine(bi, MAP, []string{"two"}, nil, nil) bi = NewLine(bi, MAP, []string{"two"}, nil, nil)

View File

@ -3,50 +3,55 @@ package vm
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"git.defalsify.org/festive/state"
) )
func Parse(b []byte) (Opcode, []byte, error) {
op, b, err := opSplit(b)
if err != nil {
return NOOP, b, err
}
return op, b, nil
}
func ParseLoad(b []byte) (string, uint32, []byte, error) { func ParseLoad(b []byte) (string, uint32, []byte, error) {
return parseSymLen(b, LOAD) return parseSymLen(b)
} }
func ParseReload(b []byte) (string, []byte, error) { func ParseReload(b []byte) (string, []byte, error) {
return parseSym(b, RELOAD) return parseSym(b)
} }
func ParseMap(b []byte) (string, []byte, error) { func ParseMap(b []byte) (string, []byte, error) {
return parseSym(b, MAP) return parseSym(b)
} }
func ParseMove(b []byte) (string, []byte, error) { func ParseMove(b []byte) (string, []byte, error) {
return parseSym(b, MOVE) return parseSym(b)
} }
func ParseHalt(b []byte) ([]byte, error) { func ParseHalt(b []byte) ([]byte, error) {
return parseNoArg(b, HALT) return parseNoArg(b)
} }
func ParseCatch(b []byte) (string, uint8, []byte, error) { func ParseCatch(b []byte) (string, uint32, bool, []byte, error) {
return parseSymSig(b, CATCH) return parseSymSig(b)
} }
func ParseCroak(b []byte) (string, uint8, []byte, error) { func ParseCroak(b []byte) (uint32, bool, []byte, error) {
return parseSymSig(b, CROAK) return parseSig(b)
} }
func ParseInCmp(b []byte) (string, string, []byte, error) { func ParseInCmp(b []byte) (string, string, []byte, error) {
return parseTwoSym(b, INCMP) return parseTwoSym(b)
} }
func parseNoArg(b []byte, op Opcode) ([]byte, error) { func parseNoArg(b []byte) ([]byte, error) {
return opCheck(b, op) return b, nil
} }
func parseSym(b []byte, op Opcode) (string, []byte, error) { func parseSym(b []byte) (string, []byte, error) {
b, err := opCheck(b, op)
if err != nil {
return "", b, err
}
sym, tail, err := instructionSplit(b) sym, tail, err := instructionSplit(b)
if err != nil { if err != nil {
return "", b, err return "", b, err
@ -54,11 +59,7 @@ func parseSym(b []byte, op Opcode) (string, []byte, error) {
return sym, tail, nil return sym, tail, nil
} }
func parseTwoSym(b []byte, op Opcode) (string, string, []byte, error) { func parseTwoSym(b []byte) (string, string, []byte, error) {
b, err := opCheck(b, op)
if err != nil {
return "", "", b, err
}
symOne, tail, err := instructionSplit(b) symOne, tail, err := instructionSplit(b)
if err != nil { if err != nil {
return "", "", b, err return "", "", b, err
@ -70,11 +71,7 @@ func parseTwoSym(b []byte, op Opcode) (string, string, []byte, error) {
return symOne, symTwo, tail, nil return symOne, symTwo, tail, nil
} }
func parseSymLen(b []byte, op Opcode) (string, uint32, []byte, error) { func parseSymLen(b []byte) (string, uint32, []byte, error) {
b, err := opCheck(b, op)
if err != nil {
return "", 0, b, err
}
sym, tail, err := instructionSplit(b) sym, tail, err := instructionSplit(b)
if err != nil { if err != nil {
return "", 0, b, err return "", 0, b, err
@ -86,21 +83,51 @@ func parseSymLen(b []byte, op Opcode) (string, uint32, []byte, error) {
return sym, sz, tail, nil return sym, sz, tail, nil
} }
func parseSymSig(b []byte, op Opcode) (string, uint8, []byte, error) { func parseSymSig(b []byte) (string, uint32, bool, []byte, error) {
b, err := opCheck(b, op)
if err != nil {
return "", 0, b, err
}
sym, tail, err := instructionSplit(b) sym, tail, err := instructionSplit(b)
if err != nil { if err != nil {
return "", 0, b, err return "", 0, false, b, err
}
sig, tail, err := intSplit(tail)
if err != nil {
return "", 0, false, b, err
} }
if len(tail) == 0 { if len(tail) == 0 {
return "", 0, b, fmt.Errorf("instruction too short") return "", 0, false, b, fmt.Errorf("instruction too short")
} }
n := tail[0] matchmode := tail[0] > 0
tail = tail[1:] tail = tail[1:]
return sym, n, tail, nil
return sym, sig, matchmode, tail, nil
}
func parseSig(b []byte) (uint32, bool, []byte, error) {
sig, b, err := intSplit(b)
if err != nil {
return 0, false, b, err
}
if len(b) == 0 {
return 0, false, b, fmt.Errorf("instruction too short")
}
matchmode := b[0] > 0
b = b[1:]
return sig, matchmode, b, nil
}
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
} }
// NewLine creates a new instruction line for the VM. // NewLine creates a new instruction line for the VM.
@ -124,6 +151,13 @@ func NewLine(instructionList []byte, instruction uint16, strargs []string, bytea
return append(instructionList, b...) return append(instructionList, b...)
} }
func byteSplit(b []byte) ([]byte, []byte, error) {
bitFieldSize := b[0]
bitField := b[1:1+bitFieldSize]
b = b[1+bitFieldSize:]
return bitField, b, nil
}
func intSplit(b []byte) (uint32, []byte, error) { func intSplit(b []byte) (uint32, []byte, error) {
l := uint8(b[0]) l := uint8(b[0])
sz := uint32(l) sz := uint32(l)
@ -163,10 +197,12 @@ func instructionSplit(b []byte) (string, []byte, error) {
} }
func opCheck(b []byte, opIn Opcode) ([]byte, error) { func opCheck(b []byte, opIn Opcode) ([]byte, error) {
op, b, err := opSplit(b) var bb []byte
op, bb, err := opSplit(b)
if err != nil { if err != nil {
return b, err return b, err
} }
b = bb
if op != opIn { if op != opIn {
return b, fmt.Errorf("not a %v instruction", op) return b, fmt.Errorf("not a %v instruction", op)
} }

View File

@ -6,14 +6,19 @@ import (
func TestParseNoArg(t *testing.T) { func TestParseNoArg(t *testing.T) {
b := NewLine(nil, HALT, nil, nil, nil) b := NewLine(nil, HALT, nil, nil, nil)
_, b, _ = opSplit(b)
b, err := ParseHalt(b) b, err := ParseHalt(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
} }
func TestParseSym(t *testing.T) { func TestParseSym(t *testing.T) {
b := NewLine(nil, MAP, []string{"baz"}, nil, nil) b := NewLine(nil, MAP, []string{"baz"}, nil, nil)
_, b, _ = opSplit(b)
sym, b, err := ParseMap(b) sym, b, err := ParseMap(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -21,8 +26,12 @@ func TestParseSym(t *testing.T) {
if sym != "baz" { if sym != "baz" {
t.Fatalf("expected sym baz, got %v", sym) t.Fatalf("expected sym baz, got %v", sym)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
b = NewLine(nil, RELOAD, []string{"xyzzy"}, nil, nil) b = NewLine(nil, RELOAD, []string{"xyzzy"}, nil, nil)
_, b, _ = opSplit(b)
sym, b, err = ParseReload(b) sym, b, err = ParseReload(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -30,8 +39,12 @@ func TestParseSym(t *testing.T) {
if sym != "xyzzy" { if sym != "xyzzy" {
t.Fatalf("expected sym xyzzy, got %v", sym) t.Fatalf("expected sym xyzzy, got %v", sym)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
b = NewLine(nil, MOVE, []string{"plugh"}, nil, nil) b = NewLine(nil, MOVE, []string{"plugh"}, nil, nil)
_, b, _ = opSplit(b)
sym, b, err = ParseMove(b) sym, b, err = ParseMove(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -39,10 +52,14 @@ func TestParseSym(t *testing.T) {
if sym != "plugh" { if sym != "plugh" {
t.Fatalf("expected sym plugh, got %v", sym) t.Fatalf("expected sym plugh, got %v", sym)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
} }
func TestParseTwoSym(t *testing.T) { func TestParseTwoSym(t *testing.T) {
b := NewLine(nil, INCMP, []string{"foo", "bar"}, nil, nil) b := NewLine(nil, INCMP, []string{"foo", "bar"}, nil, nil)
_, b, _ = opSplit(b)
one, two, b, err := ParseInCmp(b) one, two, b, err := ParseInCmp(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -53,24 +70,53 @@ func TestParseTwoSym(t *testing.T) {
if two != "bar" { if two != "bar" {
t.Fatalf("expected symtwo bar, got %v", two) t.Fatalf("expected symtwo bar, got %v", two)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
}
func TestParseSig(t *testing.T) {
b := NewLine(nil, CROAK, nil, []byte{0x0b, 0x13}, []uint8{0x04})
_, b, _ = opSplit(b)
n, m, b, err := ParseCroak(b)
if err != nil {
t.Fatal(err)
}
if n != 2835 {
t.Fatalf("expected n 13, got %v", n)
}
if !m {
t.Fatalf("expected m true")
}
if len(b) > 0 {
t.Fatalf("expected empty code")
}
} }
func TestParseSymSig(t *testing.T) { func TestParseSymSig(t *testing.T) {
b := NewLine(nil, CATCH, []string{"baz"}, nil, []uint8{0x0d}) b := NewLine(nil, CATCH, []string{"baz"}, []byte{0x0a, 0x13}, []uint8{0x01})
sym, n, b, err := ParseCatch(b) _, b, _ = opSplit(b)
sym, n, m, b, err := ParseCatch(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if sym != "baz" { if sym != "baz" {
t.Fatalf("expected sym baz, got %v", sym) t.Fatalf("expected sym baz, got %v", sym)
} }
if n != 13 { if n != 2579 {
t.Fatalf("expected n 13, got %v", n) t.Fatalf("expected n 13, got %v", n)
} }
if !m {
t.Fatalf("expected m true")
}
if len(b) > 0 {
t.Fatalf("expected empty code")
}
} }
func TestParseSymAndLen(t *testing.T) { func TestParseSymAndLen(t *testing.T) {
b := NewLine(nil, LOAD, []string{"foo"}, []byte{0x2a}, nil) b := NewLine(nil, LOAD, []string{"foo"}, []byte{0x2a}, nil)
_, b, _ = opSplit(b)
sym, n, b, err := ParseLoad(b) sym, n, b, err := ParseLoad(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -83,6 +129,7 @@ func TestParseSymAndLen(t *testing.T) {
} }
b = NewLine(nil, LOAD, []string{"bar"}, []byte{0x02, 0x9a}, nil) b = NewLine(nil, LOAD, []string{"bar"}, []byte{0x02, 0x9a}, nil)
_, b, _ = opSplit(b)
sym, n, b, err = ParseLoad(b) sym, n, b, err = ParseLoad(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -93,8 +140,12 @@ func TestParseSymAndLen(t *testing.T) {
if n != 666 { if n != 666 {
t.Fatalf("expected n 666, got %v", n) t.Fatalf("expected n 666, got %v", n)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
b = NewLine(nil, LOAD, []string{"baz"}, []byte{0x0}, nil) b = NewLine(nil, LOAD, []string{"baz"}, []byte{0x0}, nil)
_, b, _ = opSplit(b)
sym, n, b, err = ParseLoad(b) sym, n, b, err = ParseLoad(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -105,4 +156,7 @@ func TestParseSymAndLen(t *testing.T) {
if n != 0 { if n != 0 {
t.Fatalf("expected n 666, got %v", n) t.Fatalf("expected n 666, got %v", n)
} }
if len(b) > 0 {
t.Fatalf("expected empty code")
}
} }