go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

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:
Mgo/vm/runner.go | 7++++---
Mgo/vm/vm.go | 104+++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
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 {