Split out the loader from the VM
This commit is contained in:
54
load/load.go
Normal file
54
load/load.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package load
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
|
import "github.com/firestuff/subcoding/vm"
|
||||||
|
import "github.com/lunixbochs/struc"
|
||||||
|
import "github.com/pkg/errors"
|
||||||
|
|
||||||
|
const instructionBytes = 32
|
||||||
|
|
||||||
|
func Load(byteCodes [][]byte) ([][]*vm.Instruction, error) {
|
||||||
|
fncs := [][]*vm.Instruction{}
|
||||||
|
|
||||||
|
for i, byteCode := range byteCodes {
|
||||||
|
instrs, err := loadFunction(byteCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "At function index %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fncs = append(fncs, instrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fncs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFunction(byteCode []byte) ([]*vm.Instruction, error) {
|
||||||
|
instrs := []*vm.Instruction{}
|
||||||
|
|
||||||
|
for start := 0; start < len(byteCode); start += instructionBytes {
|
||||||
|
chunk := byteCode[start : start+instructionBytes]
|
||||||
|
|
||||||
|
instr, err := loadInstruction(chunk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "At byte offset %d", start)
|
||||||
|
}
|
||||||
|
|
||||||
|
instrs = append(instrs, instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return instrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadInstruction(byteCode []byte) (*vm.Instruction, error) {
|
||||||
|
instr := &vm.Instruction{}
|
||||||
|
|
||||||
|
reader := bytes.NewReader(byteCode)
|
||||||
|
|
||||||
|
err := struc.Unpack(reader, instr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error decoding instruction")
|
||||||
|
}
|
||||||
|
|
||||||
|
return instr, nil
|
||||||
|
}
|
||||||
12
test/load_test.go
Normal file
12
test/load_test.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
import "github.com/firestuff/subcoding/load"
|
||||||
|
|
||||||
|
func TestLoad(t *testing.T) {
|
||||||
|
_, err := load.Load(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import "bytes"
|
|
||||||
|
|
||||||
import "github.com/lunixbochs/struc"
|
|
||||||
import "github.com/pkg/errors"
|
|
||||||
|
|
||||||
type Instruction struct {
|
type Instruction struct {
|
||||||
OpCode OpCodeType
|
OpCode OpCodeType
|
||||||
Reserved [4]byte
|
Reserved [4]byte
|
||||||
@@ -13,33 +8,3 @@ type Instruction struct {
|
|||||||
|
|
||||||
opHandler opHandler `struc:"skip"`
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
return instrs, nil
|
|
||||||
}
|
|
||||||
|
|||||||
17
vm/state.go
17
vm/state.go
@@ -2,8 +2,6 @@ package vm
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
import "github.com/pkg/errors"
|
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
running bool
|
running bool
|
||||||
err error
|
err error
|
||||||
@@ -24,21 +22,6 @@ func NewState(functions [][]*Instruction) (*State, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateFromByteCode(byteCodes [][]byte) (*State, error) {
|
|
||||||
functions := [][]*Instruction{}
|
|
||||||
|
|
||||||
for i, byteCode := range byteCodes {
|
|
||||||
instrs, err := NewInstructionsFromByteCode(byteCode)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "At function index %d", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
functions = append(functions, instrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewState(functions)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (state *State) Execute() error {
|
func (state *State) Execute() error {
|
||||||
state.setHandlers()
|
state.setHandlers()
|
||||||
state.call(0)
|
state.call(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user