diff --git a/creature.go b/creature.go index a2c3ec0..9e53b02 100644 --- a/creature.go +++ b/creature.go @@ -1,11 +1,43 @@ package creature +// 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 +// it. type Machine struct { - Program []int - stack []int - block []int - counter int - pointer int + // Program is not modified by the machine, and can be freely set before + // the machine is started. + Program []int + + stack []int + block []int + counter int + pointer int + functions map[int] MachineFunction +} + +// 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 will halt execution if true is returned. +type MachineFunction func (machine *Machine) (stop bool) + +// Error is an error type that can be returned from the machine's methods if +// they experience problems. +type Error int + +const ( + // ErrorIDTaken is returned by Register when a new function is + // registered with the same ID as another one. + ErrorIDTaken Error = iota +) + +// Error returns a textual description of the error. +func (err Error) Error () (description string) { + switch err { + case ErrorIDTaken: + description = "this ID is taken by another function" + } + + return } // Execute starts execution at the address specified by offset. The machine will @@ -112,6 +144,16 @@ func (machine *Machine) Execute (offset int) { } case 0xf: + // CAL + // call an implementation-defined subroutine, with the + // id specified by the last word on the stack. this may + // push and pop various things from the stack + id := machine.Pop() + if machine.functions == nil { break } + function, exists := machine.functions[id] + if exists { + function(machine) + } } machine.counter ++ } @@ -171,5 +213,23 @@ func (machine *Machine) Poke (address int, word int) { } } +// Register registers a function at the specified ID. If there is already a +// function registered at that ID, this method will return an error. +func (machine *Machine) Register (id int, function MachineFunction) (err error) { + if machine.functions == nil { + machine.functions = make(map[int] MachineFunction) + } + + _, exists := machine.functions[id] + if exists { + err = ErrorIDTaken + return + } + + machine.functions[id] = function + + return +} + // Milk milks the stack machine func (machine *Machine) Milk () {}