53 lines
1.1 KiB
Go
53 lines
1.1 KiB
Go
package vm
|
|
|
|
import "bytes"
|
|
|
|
import "github.com/lunixbochs/struc"
|
|
import "github.com/pkg/errors"
|
|
|
|
type Instruction struct {
|
|
OpCode OpCodeType
|
|
Reserved [4]byte
|
|
Operand1 Operand
|
|
Operand2 Operand
|
|
|
|
opHandler opHandler `struc:"skip"`
|
|
}
|
|
|
|
const instructionBytes = 32
|
|
|
|
func NewInstructionFromByteCode(byteCode []byte) (*Instruction, error) {
|
|
instr := &Instruction{}
|
|
|
|
reader := bytes.NewReader(byteCode)
|
|
|
|
err := struc.Unpack(reader, instr)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Error decoding instruction")
|
|
}
|
|
|
|
return instr, nil
|
|
}
|
|
|
|
func NewInstructionsFromByteCode(byteCode []byte) ([]*Instruction, error) {
|
|
instrs := []*Instruction{}
|
|
|
|
for start := 0; start < len(byteCode); start += instructionBytes {
|
|
chunk := byteCode[start : start+instructionBytes]
|
|
instr, err := NewInstructionFromByteCode(chunk)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "At byte offset %d", start)
|
|
}
|
|
instrs = append(instrs, instr)
|
|
}
|
|
|
|
if len(instrs) == 0 || instrs[len(instrs)-1].OpCode != OpReturn {
|
|
// Add implicit return at the end of each function
|
|
instrs = append(instrs, &Instruction{
|
|
OpCode: OpReturn,
|
|
})
|
|
}
|
|
|
|
return instrs, nil
|
|
}
|