Machine is now a generic type
This commit is contained in:
parent
810ecdb3ac
commit
635aced0d4
80
creature.go
80
creature.go
@ -1,24 +1,31 @@
|
|||||||
package creature
|
package creature
|
||||||
|
|
||||||
|
// Word is a type constraint defining possible word types for the Machine.
|
||||||
|
type Word interface {
|
||||||
|
int8 | int16 | int32 | int64 |
|
||||||
|
uint8 | uint16 | uint32 | uint64 |
|
||||||
|
int | uint
|
||||||
|
}
|
||||||
|
|
||||||
// Machine is a stack machine. It contains an array of integers as its program
|
// Machine is a stack machine. It contains an array of integers as its program
|
||||||
// data, and provides methods to run this program data, as well as interact with
|
// data, and provides methods to run this program data, as well as interact with
|
||||||
// it.
|
// it.
|
||||||
type Machine struct {
|
type Machine [WORD Word] struct {
|
||||||
// Program is not modified by the machine, and can be freely set before
|
// Program is not modified by the machine, and can be freely set before
|
||||||
// the machine is started.
|
// the machine is started.
|
||||||
Program []int
|
Program []WORD
|
||||||
|
|
||||||
stack []int
|
stack []WORD
|
||||||
block []int
|
block []WORD
|
||||||
counter int
|
counter WORD
|
||||||
pointer int
|
pointer WORD
|
||||||
functions map[int]MachineFunction
|
functions map[WORD]MachineFunction[WORD]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MachineFunction is a function that can extend the functionality of the stack
|
// MachineFunction is a function that can extend the functionality of the stack
|
||||||
// machine. It is passed a pointer to the machine that is calling it, and the
|
// machine. It is passed a pointer to the machine that is calling it, and the
|
||||||
// machine will halt execution if true is returned.
|
// machine will halt execution if true is returned.
|
||||||
type MachineFunction func(machine *Machine) (stop bool)
|
type MachineFunction [WORD Word] func(machine *Machine[WORD]) (stop bool)
|
||||||
|
|
||||||
// All supported opcodes
|
// All supported opcodes
|
||||||
const (
|
const (
|
||||||
@ -68,7 +75,7 @@ func (err Error) Error() (description string) {
|
|||||||
|
|
||||||
// Reset resets the stack of the machine. This should be called before Execute,
|
// Reset resets the stack of the machine. This should be called before Execute,
|
||||||
// since Execute does not reset the stack.
|
// since Execute does not reset the stack.
|
||||||
func (machine *Machine) Reset() {
|
func (machine *Machine[WORD]) Reset() {
|
||||||
machine.stack = nil
|
machine.stack = nil
|
||||||
machine.pointer = 0
|
machine.pointer = 0
|
||||||
}
|
}
|
||||||
@ -77,10 +84,10 @@ func (machine *Machine) Reset() {
|
|||||||
// run until a HALT instruction is encountered, or the end of program memory is
|
// run until a HALT instruction is encountered, or the end of program memory is
|
||||||
// reached. If an unknown instruction is encountered, the machine halts and
|
// reached. If an unknown instruction is encountered, the machine halts and
|
||||||
// returns an error.
|
// returns an error.
|
||||||
func (machine *Machine) Execute(offset int) (err error) {
|
func (machine *Machine[WORD]) Execute(offset WORD) (err error) {
|
||||||
machine.counter = offset
|
machine.counter = offset
|
||||||
|
|
||||||
for machine.counter < len(machine.Program) {
|
for int(machine.counter) < len(machine.Program) {
|
||||||
switch machine.instruction() {
|
switch machine.instruction() {
|
||||||
case PUSH:
|
case PUSH:
|
||||||
// push the next word in program memory onto the stack
|
// push the next word in program memory onto the stack
|
||||||
@ -131,7 +138,7 @@ func (machine *Machine) Execute(offset int) (err error) {
|
|||||||
if machine.Pop() == machine.Pop() {
|
if machine.Pop() == machine.Pop() {
|
||||||
equal = 1
|
equal = 1
|
||||||
}
|
}
|
||||||
machine.Push(equal)
|
machine.Push(WORD(equal))
|
||||||
|
|
||||||
case GT:
|
case GT:
|
||||||
// checks if the last word on the stack is greater than
|
// checks if the last word on the stack is greater than
|
||||||
@ -140,7 +147,7 @@ func (machine *Machine) Execute(offset int) (err error) {
|
|||||||
if machine.Pop() > machine.Pop() {
|
if machine.Pop() > machine.Pop() {
|
||||||
greater = 1
|
greater = 1
|
||||||
}
|
}
|
||||||
machine.Push(greater)
|
machine.Push(WORD(greater))
|
||||||
|
|
||||||
case LT:
|
case LT:
|
||||||
// checks if the last word on the stack is less than the
|
// checks if the last word on the stack is less than the
|
||||||
@ -149,7 +156,7 @@ func (machine *Machine) Execute(offset int) (err error) {
|
|||||||
if machine.Pop() < machine.Pop() {
|
if machine.Pop() < machine.Pop() {
|
||||||
less = 1
|
less = 1
|
||||||
}
|
}
|
||||||
machine.Push(less)
|
machine.Push(WORD(less))
|
||||||
|
|
||||||
case NEQ:
|
case NEQ:
|
||||||
// checks if the last two words on the stack are not
|
// checks if the last two words on the stack are not
|
||||||
@ -158,7 +165,7 @@ func (machine *Machine) Execute(offset int) (err error) {
|
|||||||
if machine.Pop() != machine.Pop() {
|
if machine.Pop() != machine.Pop() {
|
||||||
notEqual = 1
|
notEqual = 1
|
||||||
}
|
}
|
||||||
machine.Push(notEqual)
|
machine.Push(WORD(notEqual))
|
||||||
|
|
||||||
case MOD:
|
case MOD:
|
||||||
// performs a modulo operation of the second to last
|
// performs a modulo operation of the second to last
|
||||||
@ -204,7 +211,7 @@ func (machine *Machine) Execute(offset int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instruction returns the current instruction in program memory.
|
// Instruction returns the current instruction in program memory.
|
||||||
func (machine *Machine) instruction() (instruction int) {
|
func (machine *Machine[WORD]) instruction() (instruction WORD) {
|
||||||
instruction = machine.Program[machine.counter]
|
instruction = machine.Program[machine.counter]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -212,17 +219,17 @@ func (machine *Machine) instruction() (instruction int) {
|
|||||||
// reallocateStack changes the size of the stack to something reasonable. This
|
// reallocateStack changes the size of the stack to something reasonable. This
|
||||||
// should be called then the stack pointer is really small compared to the
|
// should be called then the stack pointer is really small compared to the
|
||||||
// actual stack size, or the stack pointer is bigger than the stack.
|
// actual stack size, or the stack pointer is bigger than the stack.
|
||||||
func (machine *Machine) reallocateStack() {
|
func (machine *Machine[WORD]) reallocateStack() {
|
||||||
reallocatedStack := make([]int, machine.pointer*2)
|
reallocatedStack := make([]WORD, machine.pointer*2)
|
||||||
copy(reallocatedStack, machine.stack)
|
copy(reallocatedStack, machine.stack)
|
||||||
machine.stack = reallocatedStack
|
machine.stack = reallocatedStack
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push pushes a word onto the stack, increasing the stack pointer and
|
// Push pushes a word onto the stack, increasing the stack pointer and
|
||||||
// reallocating the stack if necessary.
|
// reallocating the stack if necessary.
|
||||||
func (machine *Machine) Push(word int) {
|
func (machine *Machine[WORD]) Push(word WORD) {
|
||||||
machine.pointer++
|
machine.pointer++
|
||||||
if len(machine.stack) <= machine.pointer {
|
if len(machine.stack) <= int(machine.pointer) {
|
||||||
machine.reallocateStack()
|
machine.reallocateStack()
|
||||||
}
|
}
|
||||||
machine.stack[machine.pointer] = word
|
machine.stack[machine.pointer] = word
|
||||||
@ -230,15 +237,15 @@ func (machine *Machine) Push(word int) {
|
|||||||
|
|
||||||
// Pop pops the last word off of the stack, and returns it, decreasing the stack
|
// Pop pops the last word off of the stack, and returns it, decreasing the stack
|
||||||
// pointer and reallocating the stack if necessary.
|
// pointer and reallocating the stack if necessary.
|
||||||
func (machine *Machine) Pop() (word int) {
|
func (machine *Machine[WORD]) Pop() (word WORD) {
|
||||||
if machine.pointer <= 0 || machine.pointer >= len(machine.stack) {
|
if int(machine.pointer) <= 0 || int(machine.pointer) >= len(machine.stack) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
word = machine.stack[machine.pointer]
|
word = machine.stack[machine.pointer]
|
||||||
machine.pointer--
|
machine.pointer--
|
||||||
|
|
||||||
if machine.pointer < len(machine.stack)/3 {
|
if int(machine.pointer) < len(machine.stack)/3 {
|
||||||
machine.reallocateStack()
|
machine.reallocateStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,17 +253,17 @@ func (machine *Machine) Pop() (word int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Peek returns the word at address in the block.
|
// Peek returns the word at address in the block.
|
||||||
func (machine *Machine) Peek(address int) (word int) {
|
func (machine *Machine[WORD]) Peek(address WORD) (word WORD) {
|
||||||
if address < len(machine.block) {
|
if int(address) < len(machine.block) {
|
||||||
word = machine.block[address]
|
word = machine.block[address]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poke sets the value at address in the block to word.
|
// Poke sets the value at address in the block to word.
|
||||||
func (machine *Machine) Poke(address int, word int) {
|
func (machine *Machine[WORD]) Poke(address WORD, word WORD) {
|
||||||
if address >= len(machine.block) {
|
if int(address) >= len(machine.block) {
|
||||||
reallocatedBlock := make([]int, address*3/2)
|
reallocatedBlock := make([]WORD, address*3/2)
|
||||||
copy(reallocatedBlock, machine.block)
|
copy(reallocatedBlock, machine.block)
|
||||||
machine.block = reallocatedBlock
|
machine.block = reallocatedBlock
|
||||||
}
|
}
|
||||||
@ -265,9 +272,14 @@ func (machine *Machine) Poke(address int, word int) {
|
|||||||
|
|
||||||
// Register registers a function at the specified ID. If there is already a
|
// Register registers a function at the specified ID. If there is already a
|
||||||
// function registered at that ID, this method will return an error.
|
// function registered at that ID, this method will return an error.
|
||||||
func (machine *Machine) Register(id int, function MachineFunction) (err error) {
|
func (machine *Machine[WORD]) Register (
|
||||||
|
id WORD,
|
||||||
|
function MachineFunction[WORD],
|
||||||
|
) (
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
if machine.functions == nil {
|
if machine.functions == nil {
|
||||||
machine.functions = make(map[int]MachineFunction)
|
machine.functions = make(map[WORD]MachineFunction[WORD])
|
||||||
}
|
}
|
||||||
|
|
||||||
_, exists := machine.functions[id]
|
_, exists := machine.functions[id]
|
||||||
@ -282,7 +294,7 @@ func (machine *Machine) Register(id int, function MachineFunction) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unregister removes a function that is registered at the specified ID.
|
// Unregister removes a function that is registered at the specified ID.
|
||||||
func (machine *Machine) Unregister(id int) {
|
func (machine *Machine[WORD]) Unregister(id WORD) {
|
||||||
if machine.functions == nil {
|
if machine.functions == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -290,10 +302,10 @@ func (machine *Machine) Unregister(id int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadMemory loads the contents of block into the machine's memory.
|
// LoadMemory loads the contents of block into the machine's memory.
|
||||||
func (machine *Machine) LoadMemory(block []int) {
|
func (machine *Machine[WORD]) LoadMemory(block []WORD) {
|
||||||
machine.block = make([]int, len(block))
|
machine.block = make([]WORD, len(block))
|
||||||
copy(machine.block, block)
|
copy(machine.block, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Milk milks the stack machine.
|
// Milk milks the stack machine.
|
||||||
func (machine *Machine) Milk() {}
|
func (machine *Machine[WORD]) Milk() {}
|
||||||
|
@ -7,9 +7,9 @@ func runMachineTest (
|
|||||||
memory []int,
|
memory []int,
|
||||||
test *testing.T,
|
test *testing.T,
|
||||||
) (
|
) (
|
||||||
machine *Machine,
|
machine *Machine[int],
|
||||||
) {
|
) {
|
||||||
machine = &Machine { Program: program }
|
machine = &Machine[int] { Program: program }
|
||||||
if memory != nil {
|
if memory != nil {
|
||||||
machine.LoadMemory(memory)
|
machine.LoadMemory(memory)
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ func TestJump(test *testing.T) {
|
|||||||
|
|
||||||
func TestRegister(test *testing.T) {
|
func TestRegister(test *testing.T) {
|
||||||
output := ""
|
output := ""
|
||||||
machine := &Machine { Program: []int {
|
machine := &Machine[int] { Program: []int {
|
||||||
PUSH, int('h'),
|
PUSH, int('h'),
|
||||||
PUSH, 4,
|
PUSH, 4,
|
||||||
CAL,
|
CAL,
|
||||||
@ -259,7 +259,7 @@ func TestRegister(test *testing.T) {
|
|||||||
PUSH, 4,
|
PUSH, 4,
|
||||||
CAL,
|
CAL,
|
||||||
}}
|
}}
|
||||||
machine.Register(4, func(machine *Machine) (stop bool) {
|
machine.Register(4, func(machine *Machine[int]) (stop bool) {
|
||||||
output += string(rune(machine.Pop()))
|
output += string(rune(machine.Pop()))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
@ -9,7 +9,7 @@ func main () {
|
|||||||
// this is a simple echo program. it will take in input indefinetly and
|
// this is a simple echo program. it will take in input indefinetly and
|
||||||
// repeat it. due to line buffering in the terminal however, it will
|
// repeat it. due to line buffering in the terminal however, it will
|
||||||
// only print output once you have pressed enter.
|
// only print output once you have pressed enter.
|
||||||
machine := cre.Machine { Program: []int {
|
machine := cre.Machine[int] { Program: []int {
|
||||||
cre.PUSH, 0,
|
cre.PUSH, 0,
|
||||||
cre.CAL,
|
cre.CAL,
|
||||||
|
|
||||||
@ -27,14 +27,14 @@ func main () {
|
|||||||
if err != nil { panic(err.Error()) }
|
if err != nil { panic(err.Error()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func read (machine *cre.Machine) (stop bool) {
|
func read (machine *cre.Machine[int]) (stop bool) {
|
||||||
ch := []byte { 0 }
|
ch := []byte { 0 }
|
||||||
os.Stdin.Read(ch)
|
os.Stdin.Read(ch)
|
||||||
machine.Push(int(ch[0]))
|
machine.Push(int(ch[0]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func write (machine *cre.Machine) (stop bool) {
|
func write (machine *cre.Machine[int]) (stop bool) {
|
||||||
print(string(rune(machine.Pop())))
|
print(string(rune(machine.Pop())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func main () {
|
|||||||
responseStart := 71
|
responseStart := 71
|
||||||
responseLoopStart := 50
|
responseLoopStart := 50
|
||||||
|
|
||||||
machine := cre.Machine { Program: []int {
|
machine := cre.Machine[int] { Program: []int {
|
||||||
// reset x
|
// reset x
|
||||||
cre.PUSH, introStart,
|
cre.PUSH, introStart,
|
||||||
cre.PUSH, x,
|
cre.PUSH, x,
|
||||||
@ -129,14 +129,14 @@ func main () {
|
|||||||
if err != nil { panic(err.Error()) }
|
if err != nil { panic(err.Error()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func read (machine *cre.Machine) (stop bool) {
|
func read (machine *cre.Machine[int]) (stop bool) {
|
||||||
ch := []byte { 0 }
|
ch := []byte { 0 }
|
||||||
os.Stdin.Read(ch)
|
os.Stdin.Read(ch)
|
||||||
machine.Push(int(ch[0]))
|
machine.Push(int(ch[0]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func write (machine *cre.Machine) (stop bool) {
|
func write (machine *cre.Machine[int]) (stop bool) {
|
||||||
print(string(rune(machine.Pop())))
|
print(string(rune(machine.Pop())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user