Catch range errors, add implicit return
This commit is contained in:
67
main.go
67
main.go
@@ -17,6 +17,8 @@ const (
|
||||
)
|
||||
|
||||
const InstructionBytes = 32
|
||||
const GlobalMemoryEntries = 16
|
||||
const FunctionMemoryEntries = 16
|
||||
|
||||
type Operand struct {
|
||||
Type OperandType
|
||||
@@ -39,15 +41,14 @@ type State struct {
|
||||
InstructionIndex int64
|
||||
|
||||
ComparisonResult bool
|
||||
GlobalMemory [16]uint64
|
||||
GlobalMemory [GlobalMemoryEntries]uint64
|
||||
Stack []*StackFrame
|
||||
StackFrame *StackFrame
|
||||
}
|
||||
|
||||
type StackFrame struct {
|
||||
PreviousFunctionIndex int64
|
||||
PreviousInstructionIndex int64
|
||||
FunctionMemory [16]uint64
|
||||
FunctionMemory [FunctionMemoryEntries]uint64
|
||||
}
|
||||
|
||||
type OpHandler func(*State, *Instruction)
|
||||
@@ -86,15 +87,26 @@ func NewState(functionByteCode [][]byte) *State {
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) StackFrame() *StackFrame {
|
||||
return state.Stack[len(state.Stack) - 1]
|
||||
}
|
||||
|
||||
func (state *State) Function() []byte {
|
||||
return state.FunctionByteCode[state.FunctionIndex]
|
||||
}
|
||||
|
||||
func (state *State) Execute() {
|
||||
state.call(0)
|
||||
|
||||
for len(state.Stack) > 0 && state.Error == nil {
|
||||
fnc := state.FunctionByteCode[state.FunctionIndex]
|
||||
start := state.InstructionIndex * InstructionBytes
|
||||
chunk := fnc[start : start+InstructionBytes]
|
||||
chunk := state.Function()[start : start+InstructionBytes]
|
||||
state.InstructionIndex += 1
|
||||
state.ProcessInstruction(chunk)
|
||||
|
||||
if state.InstructionIndex >= int64(len(state.Function()) / InstructionBytes) {
|
||||
state.ret()
|
||||
}
|
||||
}
|
||||
|
||||
if state.Error != nil {
|
||||
@@ -128,10 +140,21 @@ func (state *State) ReadUnsigned(op *Operand) uint64 {
|
||||
switch op.Type {
|
||||
case Literal:
|
||||
return op.Value
|
||||
|
||||
case FunctionMemoryIndex:
|
||||
return state.StackFrame.FunctionMemory[op.Value]
|
||||
if op.Value >= FunctionMemoryEntries {
|
||||
state.Error = fmt.Errorf("Invalid function memory index: %016x", op.Value)
|
||||
return 0
|
||||
}
|
||||
return state.StackFrame().FunctionMemory[op.Value]
|
||||
|
||||
case GlobalMemoryIndex:
|
||||
if op.Value >= GlobalMemoryEntries {
|
||||
state.Error = fmt.Errorf("Invalid global memory index: %016x", op.Value)
|
||||
return 0
|
||||
}
|
||||
return state.GlobalMemory[op.Value]
|
||||
|
||||
default:
|
||||
state.Error = fmt.Errorf("Unknown operand type: 0x%02x", op.Type)
|
||||
return 0
|
||||
@@ -146,10 +169,21 @@ func (state *State) WriteUnsigned(op *Operand, value uint64) {
|
||||
switch op.Type {
|
||||
case Literal:
|
||||
state.Error = fmt.Errorf("Write to literal operand")
|
||||
|
||||
case FunctionMemoryIndex:
|
||||
state.StackFrame.FunctionMemory[op.Value] = value
|
||||
if op.Value >= FunctionMemoryEntries {
|
||||
state.Error = fmt.Errorf("Invalid function memory index: %016x", op.Value)
|
||||
return
|
||||
}
|
||||
state.StackFrame().FunctionMemory[op.Value] = value
|
||||
|
||||
case GlobalMemoryIndex:
|
||||
if op.Value >= GlobalMemoryEntries {
|
||||
state.Error = fmt.Errorf("Invalid global memory index: %016x", op.Value)
|
||||
return
|
||||
}
|
||||
state.GlobalMemory[op.Value] = value
|
||||
|
||||
default:
|
||||
state.Error = fmt.Errorf("Unknown operand type: 0x%02x", op.Type)
|
||||
}
|
||||
@@ -170,24 +204,29 @@ func (state *State) Call(instr *Instruction) {
|
||||
}
|
||||
|
||||
func (state *State) call(functionOffset int64) {
|
||||
if state.FunctionIndex + functionOffset >= int64(len(state.FunctionByteCode)) {
|
||||
state.Error = fmt.Errorf("Invalid function call index: %d + %d = %d", state.FunctionIndex, functionOffset, state.FunctionIndex + functionOffset)
|
||||
return
|
||||
}
|
||||
|
||||
stackFrame := &StackFrame{
|
||||
PreviousFunctionIndex: state.FunctionIndex,
|
||||
PreviousInstructionIndex: state.InstructionIndex,
|
||||
}
|
||||
state.Stack = append(state.Stack, stackFrame)
|
||||
state.StackFrame = stackFrame
|
||||
state.FunctionIndex += functionOffset
|
||||
state.InstructionIndex = 0
|
||||
}
|
||||
|
||||
func (state *State) Return(instr *Instruction) {
|
||||
fmt.Printf("Return\n")
|
||||
state.FunctionIndex = state.StackFrame.PreviousFunctionIndex
|
||||
state.InstructionIndex = state.StackFrame.PreviousInstructionIndex
|
||||
state.ret()
|
||||
}
|
||||
|
||||
func (state *State) ret() {
|
||||
state.FunctionIndex = state.StackFrame().PreviousFunctionIndex
|
||||
state.InstructionIndex = state.StackFrame().PreviousInstructionIndex
|
||||
state.Stack = state.Stack[:len(state.Stack)-1]
|
||||
if len(state.Stack) > 0 {
|
||||
state.StackFrame = state.Stack[len(state.Stack)-1]
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) Move(instr *Instruction) {
|
||||
@@ -321,11 +360,9 @@ func main() {
|
||||
"0000000100000000000000000000000000000001000000000000000000000000",
|
||||
"0000030100000000010000000000000000000000000000000000000000000003",
|
||||
"000004010000000000000000fffffffffffffffd000000000000000000000000",
|
||||
"0000000200000000000000000000000000000000000000000000000000000000",
|
||||
},
|
||||
[]string{
|
||||
"0000020000000000020000000000000000000000000000000000000000000001",
|
||||
"0000000200000000000000000000000000000000000000000000000000000000",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user