commit 684de95198725a3d636d0c5d3855a13174070243
parent 83fe049b1519a8ad52015d9d06498b95de868263
Author: lash <dev@holbrook.no>
Date: Tue, 4 Apr 2023 07:42:15 +0100
Add code comments, rename tail var to b
Diffstat:
2 files changed, 68 insertions(+), 43 deletions(-)
diff --git a/go/vm/runner.go b/go/vm/runner.go
@@ -196,14 +196,14 @@ func RunHalt(b []byte, st *state.State, rs resource.Resource, ctx context.Contex
return b, err
}
-// RunMSize
+// RunMSize executes the HALT opcode
func RunMSize(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
log.Printf("WARNING MSIZE not yet implemented")
_, _, b, err := ParseMSize(b)
return b, err
}
-// RunMSize
+// RunMNext executes the MNEXT opcode
func RunMNext(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
selector, display, b, err := ParseMNext(b)
if err != nil {
@@ -213,7 +213,7 @@ func RunMNext(b []byte, st *state.State, rs resource.Resource, ctx context.Conte
return b, err
}
-// RunMSize
+// RunMPrev executes the MPREV opcode
func RunMPrev(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
selector, display, b, err := ParseMPrev(b)
if err != nil {
@@ -223,6 +223,7 @@ func RunMPrev(b []byte, st *state.State, rs resource.Resource, ctx context.Conte
return b, err
}
+// RunMOut executes the MOUT opcode
func RunMOut(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
choice, title, b, err := ParseMOut(b)
if err != nil {
diff --git a/go/vm/vm.go b/go/vm/vm.go
@@ -7,6 +7,28 @@ import (
"git.defalsify.org/festive/state"
)
+// NewLine creates a new instruction line for the VM.
+func NewLine(instructionList []byte, instruction uint16, strargs []string, byteargs []byte, numargs []uint8) []byte {
+ if instructionList == nil {
+ instructionList = []byte{}
+ }
+ b := []byte{0x00, 0x00}
+ binary.BigEndian.PutUint16(b, instruction)
+ for _, arg := range strargs {
+ b = append(b, uint8(len(arg)))
+ b = append(b, []byte(arg)...)
+ }
+ if byteargs != nil {
+ b = append(b, uint8(len(byteargs)))
+ b = append(b, byteargs...)
+ }
+ if numargs != nil {
+ b = append(b, numargs...)
+ }
+ return append(instructionList, b...)
+}
+
+// ParseOp verifies and extracts the expected opcode portion of an instruction
func ParseOp(b []byte) (Opcode, []byte, error) {
op, b, err := opSplit(b)
if err != nil {
@@ -15,46 +37,57 @@ func ParseOp(b []byte) (Opcode, []byte, error) {
return op, b, nil
}
+// ParseLoad parses and extracts the expected argument portion of a LOAD instruction
func ParseLoad(b []byte) (string, uint32, []byte, error) {
return parseSymLen(b)
}
+// ParseReload parses and extracts the expected argument portion of a RELOAD instruction
func ParseReload(b []byte) (string, []byte, error) {
return parseSym(b)
}
+// ParseMap parses and extracts the expected argument portion of a MAP instruction
func ParseMap(b []byte) (string, []byte, error) {
return parseSym(b)
}
+// ParseMove parses and extracts the expected argument portion of a MOVE instruction
func ParseMove(b []byte) (string, []byte, error) {
return parseSym(b)
}
+// ParseHalt parses and extracts the expected argument portion of a HALT instruction
func ParseHalt(b []byte) ([]byte, error) {
return parseNoArg(b)
}
+// ParseCatch parses and extracts the expected argument portion of a CATCH instruction
func ParseCatch(b []byte) (string, uint32, bool, []byte, error) {
return parseSymSig(b)
}
+// ParseCroak parses and extracts the expected argument portion of a CROAK instruction
func ParseCroak(b []byte) (uint32, bool, []byte, error) {
return parseSig(b)
}
+// ParseInCmp parses and extracts the expected argument portion of a INCMP instruction
func ParseInCmp(b []byte) (string, string, []byte, error) {
return parseTwoSym(b)
}
+// ParseMPrev parses and extracts the expected argument portion of a MPREV instruction
func ParseMPrev(b []byte) (string, string, []byte, error) {
return parseTwoSym(b)
}
+// ParseMNext parses and extracts the expected argument portion of a MNEXT instruction
func ParseMNext(b []byte) (string, string, []byte, error) {
return parseTwoSym(b)
}
+// ParseMSize parses and extracts the expected argument portion of a MSIZE instruction
func ParseMSize(b []byte) (uint32, uint32, []byte, error) {
if len(b) < 2 {
return 0, 0, b, fmt.Errorf("argument too short")
@@ -65,64 +98,71 @@ func ParseMSize(b []byte) (uint32, uint32, []byte, error) {
return r, rr, b, nil
}
+// ParseMOut parses and extracts the expected argument portion of a MOUT instruction
func ParseMOut(b []byte) (string, string, []byte, error) {
return parseTwoSym(b)
}
+// noop
func parseNoArg(b []byte) ([]byte, error) {
return b, nil
}
+// parse and extract two length-prefixed string values
func parseSym(b []byte) (string, []byte, error) {
- sym, tail, err := instructionSplit(b)
+ sym, b, err := instructionSplit(b)
if err != nil {
return "", b, err
}
- return sym, tail, nil
+ return sym, b, nil
}
+// parse and extract two length-prefixed string values
func parseTwoSym(b []byte) (string, string, []byte, error) {
- symOne, tail, err := instructionSplit(b)
+ symOne, b, err := instructionSplit(b)
if err != nil {
return "", "", b, err
}
- symTwo, tail, err := instructionSplit(tail)
+ symTwo, b, err := instructionSplit(b)
if err != nil {
- return "", "", tail, err
+ return "", "", b, err
}
- return symOne, symTwo, tail, nil
+ return symOne, symTwo, b, nil
}
+// parse and extract one length-prefixed string value, and one length-prefixed integer value
func parseSymLen(b []byte) (string, uint32, []byte, error) {
- sym, tail, err := instructionSplit(b)
+ sym, b, err := instructionSplit(b)
if err != nil {
return "", 0, b, err
}
- sz, tail, err := intSplit(tail)
+ sz, b, err := intSplit(b)
if err != nil {
return "", 0, b, err
}
- return sym, sz, tail, nil
+ return sym, sz, b, nil
}
+// parse and extract one length-prefixed string value, and one single byte of integer
func parseSymSig(b []byte) (string, uint32, bool, []byte, error) {
- sym, tail, err := instructionSplit(b)
+ sym, b, err := instructionSplit(b)
if err != nil {
return "", 0, false, b, err
}
- sig, tail, err := intSplit(tail)
+ sig, b, err := intSplit(b)
if err != nil {
return "", 0, false, b, err
}
- if len(tail) == 0 {
+ if len(b) == 0 {
return "", 0, false, b, fmt.Errorf("instruction too short")
}
- matchmode := tail[0] > 0
- tail = tail[1:]
+ matchmode := b[0] > 0
+ b = b[1:]
- return sym, sig, matchmode, tail, nil
+ return sym, sig, matchmode, b, nil
}
+// parse and extract one single byte of integer
func parseSig(b []byte) (uint32, bool, []byte, error) {
sig, b, err := intSplit(b)
if err != nil {
@@ -137,6 +177,7 @@ 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 {
@@ -152,27 +193,7 @@ func matchFlag(st *state.State, sig uint32, invertMatch bool) (bool, error) {
return false, nil
}
-// NewLine creates a new instruction line for the VM.
-func NewLine(instructionList []byte, instruction uint16, strargs []string, byteargs []byte, numargs []uint8) []byte {
- if instructionList == nil {
- instructionList = []byte{}
- }
- b := []byte{0x00, 0x00}
- binary.BigEndian.PutUint16(b, instruction)
- for _, arg := range strargs {
- b = append(b, uint8(len(arg)))
- b = append(b, []byte(arg)...)
- }
- if byteargs != nil {
- b = append(b, uint8(len(byteargs)))
- b = append(b, byteargs...)
- }
- if numargs != nil {
- b = append(b, numargs...)
- }
- return append(instructionList, b...)
-}
-
+// split bytecode into head and b using length-prefixed bitfield
func byteSplit(b []byte) ([]byte, []byte, error) {
bitFieldSize := b[0]
bitField := b[1:1+bitFieldSize]
@@ -180,6 +201,7 @@ func byteSplit(b []byte) ([]byte, []byte, error) {
return bitField, b, nil
}
+// split bytecode into head and b using length-prefixed integer
func intSplit(b []byte) (uint32, []byte, error) {
l := uint8(b[0])
sz := uint32(l)
@@ -201,7 +223,7 @@ func intSplit(b []byte) (uint32, []byte, error) {
return sz, b, nil
}
-// split instruction into symbol and arguments
+// split bytecode into head and b using length-prefixed string
func instructionSplit(b []byte) (string, []byte, error) {
if len(b) == 0 {
return "", nil, fmt.Errorf("argument is empty")
@@ -210,14 +232,15 @@ func instructionSplit(b []byte) (string, []byte, error) {
if sz == 0 {
return "", nil, fmt.Errorf("zero-length argument")
}
- tailSz := uint8(len(b))
- if tailSz < sz {
- return "", nil, fmt.Errorf("corrupt instruction, len %v less than symbol length: %v", tailSz, sz)
+ bSz := uint8(len(b))
+ if bSz < sz {
+ return "", nil, fmt.Errorf("corrupt instruction, len %v less than symbol length: %v", bSz, sz)
}
r := string(b[1:1+sz])
return r, b[1+sz:], nil
}
+// check if the start of the given bytecode contains a valid opcode, extract and return it
func opCheck(b []byte, opIn Opcode) ([]byte, error) {
var bb []byte
op, bb, err := opSplit(b)
@@ -231,6 +254,7 @@ func opCheck(b []byte, opIn Opcode) ([]byte, error) {
return b, nil
}
+// split bytecode into head and b using opcode
func opSplit(b []byte) (Opcode, []byte, error) {
l := len(b)
if l < 2 {