Class: Trith::Machine
- Inherits:
-
Object
- Object
- Trith::Machine
- Defined in:
- lib/trith/machine.rb
Overview
The Trith virtual machine.
Defined Under Namespace
Classes: InvalidOperandError, InvalidOperatorError, StackUnderflowError
Instance Attribute Summary (collapse)
- - (Proc) execute_hook
- - (Array) queue readonly
- - (Array) stack readonly
Class Method Summary (collapse)
-
+ (Object) run(code = [], &block)
Executes
codein a new virtual machine instance.
Instance Method Summary (collapse)
-
- (Array) capture_continuation(full = false)
protected
Captures the current contents of the code queue, returning them to the caller after first clearing the queue.
-
- (Machine) define!(name, code = [], options = {}, &block)
Defines a new operator
namethat will execute the givencode. -
- (Machine) execute(code = [], &block)
Executes the virtual machine until it halts.
-
- (Machine) import!(mod)
Imports operators from the given
moduleinto the virtual machine's current environment. -
- import_module!(mod)
protected
Imports operators from the given
moduleinto the virtual machine's current environment. -
- (Machine) initialize(stack = [], queue = [], env = {}) {|machine| ... }
constructor
Initializes a new virtual machine with the given initial
stack,queueand environment. -
- (String) inspect
Returns a developer-friendly representation of this machine.
-
- (Boolean) operand?(op)
protected
Returns
trueifopis an operand. -
- (Boolean) operator?(op)
protected
Returns
trueifopis an operator. -
- (Object) peek
Returns the operand at the top of the stack.
-
- (Object) pop(n = nil)
Pops and returns one or more operands off the top of the stack.
-
- (Machine) push(*ops)
Pushes the given operands onto the top of the stack.
-
- (Boolean) quotation?(op)
protected
Returns
trueifopis a quotation. -
- (Object) shift(n = nil)
Shifts and returns one or more operands off the front of the queue.
-
- (Array) to_a
Returns the concatenation of the stack and queue.
-
- (Machine) unshift(*ops)
Prepends the given operands onto the front of the queue.
-
- with_current_continuation { ... }
protected
Invokes the given block with an empty code queue, passing the previous queue contents as an argument.
-
- with_saved_continuation(name = nil) { ... }
protected
Invokes the given block with an empty code queue, restoring the queue contents after the block returns.
Constructor Details
- (Machine) initialize(stack = [], queue = [], env = {}) {|machine| ... }
Initializes a new virtual machine with the given initial stack,
queue and environment.
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/trith/machine.rb', line 44 def initialize(stack = [], queue = [], env = {}, &block) @stack, @queue, @env = stack, queue, {} import!(Trith::Core) env.each do |name, operator| if operator.is_a?(Proc) define!(name, &operator) else define!(name, operator) end end execute(&block) if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Object) method_missing(operator, *operands, &block) (protected)
278 279 280 281 282 283 284 |
# File 'lib/trith/machine.rb', line 278 def method_missing(operator, *operands, &block) begin super rescue NoMethodError => e raise InvalidOperatorError.new(operator) end end |
Instance Attribute Details
- (Proc) execute_hook
12 13 14 |
# File 'lib/trith/machine.rb', line 12 def execute_hook @execute_hook end |
- (Array) queue (readonly)
9 10 11 |
# File 'lib/trith/machine.rb', line 9 def queue @queue end |
- (Array) stack (readonly)
6 7 8 |
# File 'lib/trith/machine.rb', line 6 def stack @stack end |
Class Method Details
+ (Object) self.run(code) + (Object) self.run(code) {|machine| ... }
Executes code in a new virtual machine instance.
The machine will halt when the queue is exhausted, when encountering
a halt operator, or when encountering an error condition.
31 32 33 |
# File 'lib/trith/machine.rb', line 31 def self.run(code = [], &block) self.new([], code).execute(&block).peek end |
Instance Method Details
- (Array) capture_continuation(full = false) (protected)
Captures the current contents of the code queue, returning them to the caller after first clearing the queue.
347 348 349 350 351 |
# File 'lib/trith/machine.rb', line 347 def capture_continuation(full = false) continuation = @queue.dup @queue.clear continuation end |
- (Machine) define!(name, code = [], options = {}, &block)
Defines a new operator name that will execute the given code.
87 88 89 90 91 92 93 94 |
# File 'lib/trith/machine.rb', line 87 def define!(name, code = [], = {}, &block) @env[name = name.to_sym] = lambda { execute(code, &block) } unless [:method] == false this = class << self; self; end this.send(:define_method, name, &@env[name]) end self end |
- (Machine) execute(code) - (Machine) execute(code) {|machine| ... }
Executes the virtual machine until it halts.
The machine will halt when the queue is exhausted, when encountering
a halt operator, or when encountering an error condition.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/trith/machine.rb', line 213 def execute(code = [], &block) @queue.unshift(*code) unless code.empty? catch(:halt) do # thrown in `#shift` Kernel.loop do execute_hook.call if execute_hook && !@queue.empty? op = shift case when operator?(op) if fn = @env[op] fn.call else unshift(op) raise InvalidOperatorError.new(op) end when operand?(op) push(op) else raise InvalidOperandError.new(op) end end end if block_given? case block.arity when 1 then block.call(self) else instance_eval(&block) end end return self end |
- (Machine) import!(mod)
Imports operators from the given module into the virtual machine's
current environment.
71 72 73 74 75 76 77 78 |
# File 'lib/trith/machine.rb', line 71 def import!(mod) case mod when Module then import_module!(mod) when Function then # TODO else # TODO: error end self end |
- import_module!(mod) (protected)
This method returns an undefined value.
Imports operators from the given module into the virtual machine's
current environment.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/trith/machine.rb', line 292 def import_module!(mod) # Include all instance methods from the module into `self`: this = class << self; self; end this.send(:include, mod) # Create wrapper methods to support operators that need their # arguments and result marshalled from/to the virtual machine stack: mod.public_instance_methods(true).map(&:to_sym).each do |method| op = mod.instance_method(method).bind(self) case method when :stack_ # FIXME @env[:stack] = op else @env[method] = this.send(:define_method, method) do |*args| result = op.call(*(!args.empty? ? args : (op.arity > 0 ? pop(op.arity) : []))) push(result) unless result.equal?(self) return self end end end end |
- (String) inspect
Returns a developer-friendly representation of this machine.
61 62 63 |
# File 'lib/trith/machine.rb', line 61 def inspect sprintf("#<%s:%#0x(%s : %s)>", self.class.name, __id__, @stack.inspect, @queue.inspect) end |
- (Boolean) operand?(op) (protected)
Returns true if op is an operand.
263 264 265 |
# File 'lib/trith/machine.rb', line 263 def operand?(op) !operator?(op) end |
- (Boolean) operator?(op) (protected)
Returns true if op is an operator.
254 255 256 |
# File 'lib/trith/machine.rb', line 254 def operator?(op) op.is_a?(Symbol) end |
- (Object) peek
Returns the operand at the top of the stack.
If the stack is empty, returns nil.
110 111 112 |
# File 'lib/trith/machine.rb', line 110 def peek @stack.last end |
- (Object) pop - (Array) pop(n)
Pops and returns one or more operands off the top of the stack.
If the stack doesn't have sufficient operands, raises a stack underflow error.
129 130 131 132 133 134 135 |
# File 'lib/trith/machine.rb', line 129 def pop(n = nil) if @stack.size < (n || 1) raise StackUnderflowError.new else n ? @stack.pop(n) : @stack.pop end end |
- (Machine) push - (Machine) push(*ops)
Pushes the given operands onto the top of the stack.
If no operands were given, shifts an operand off the front of the queue.
151 152 153 154 |
# File 'lib/trith/machine.rb', line 151 def push(*ops) @stack.push(*(ops.empty? ? [shift] : ops)) self end |
- (Boolean) quotation?(op) (protected)
Returns true if op is a quotation.
272 273 274 |
# File 'lib/trith/machine.rb', line 272 def quotation?(op) op.is_a?(Array) end |
- (Object) shift - (Array) shift(n)
Shifts and returns one or more operands off the front of the queue.
If the queue doesn't have sufficient operands, throws a :halt
symbol.
170 171 172 173 174 175 176 |
# File 'lib/trith/machine.rb', line 170 def shift(n = nil) if @queue.size < (n || 1) throw(:halt) # caught in `#execute` else n ? @queue.shift(n) : @queue.shift end end |
- (Array) to_a
Returns the concatenation of the stack and queue.
100 101 102 |
# File 'lib/trith/machine.rb', line 100 def to_a (@stack + @queue).to_a end |
- (Machine) unshift - (Machine) unshift(*ops)
Prepends the given operands onto the front of the queue.
If no operands were given, pops an operand off the top of the stack.
191 192 193 194 |
# File 'lib/trith/machine.rb', line 191 def unshift(*ops) @queue.unshift(*(ops.empty? ? [pop] : ops)) self end |
- with_current_continuation { ... } (protected)
This method returns an undefined value.
Invokes the given block with an empty code queue, passing the previous queue contents as an argument.
337 338 339 340 |
# File 'lib/trith/machine.rb', line 337 def with_current_continuation(&block) block.call(capture_continuation) self end |
- with_saved_continuation(name = nil) { ... } (protected)
This method returns an undefined value.
Invokes the given block with an empty code queue, restoring the queue contents after the block returns.
321 322 323 324 325 326 327 328 329 |
# File 'lib/trith/machine.rb', line 321 def with_saved_continuation(name = nil, &block) cc = capture_continuation case block.arity when 1 then block.call(cc) else block.call end @queue.push(*cc) unless cc.empty? self end |