Catch range errors, add implicit return

This commit is contained in:
Ian Gulliver
2021-11-14 20:54:53 -10:00
parent b6d7f66def
commit 3e07a3f99d

67
main.go
View File

@@ -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",
},
}