Class: XfOOrth::VirtualMachine
- Defined in:
- lib/fOOrth.rb,
lib/fOOrth/compiler.rb,
lib/fOOrth/initialize.rb,
lib/fOOrth/interpreter.rb,
lib/fOOrth/compiler/cast.rb,
lib/fOOrth/compiler/modes.rb,
lib/fOOrth/debug/dbg_puts.rb,
lib/fOOrth/compiler/process.rb,
lib/fOOrth/interpreter/squash.rb,
lib/fOOrth/debug/display_abort.rb,
lib/fOOrth/interpreter/do_loop.rb,
lib/fOOrth/core/virtual_machine.rb,
lib/fOOrth/compiler/modes/nested.rb,
lib/fOOrth/compiler/modes/delayed.rb,
lib/fOOrth/compiler/modes/suspend.rb,
lib/fOOrth/interpreter/data_stack.rb,
lib/fOOrth/compiler/modes/compiled.rb,
lib/fOOrth/compiler/modes/deferred.rb,
lib/fOOrth/compiler/process/string.rb,
lib/fOOrth/interpreter/add_to_hash.rb,
lib/fOOrth/library/introspection/vm.rb,
lib/fOOrth/compiler/process/generate.rb,
lib/fOOrth/compiler/process/get_token.rb,
lib/fOOrth/compiler/process/procedure.rb
Overview
-
compiler/process/procedure.rb - Get an embedded procedure literal.
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
The current execution/compile context.
-
#data ⇒ Object
readonly
The thread data associated with this virtual machine.
-
#data_stack ⇒ Object
The fOOrth data stack.
-
#debug ⇒ Object
Set true for verbose compiler play-by-plays and detailed error reports.
-
#fiber ⇒ Object
The currently active fiber, if any.
-
#name ⇒ Object
readonly
The descriptive name of this virtual machine.
-
#parens ⇒ Object
The level of comment nesting.
-
#parser ⇒ Object
readonly
The current compiler parser.
-
#quotes ⇒ Object
The level of quote nesting.
-
#show_stack ⇒ Object
Set true to print out the data stack after every interactive line is processed.
-
#start_time ⇒ Object
The fOOrth timer anchor point.
Class Method Summary collapse
-
.create_foorth_subclass(_name) ⇒ Object
Create a new fOOrth subclass of this class.
-
.vm(name = '-') ⇒ Object
Get or create a virtual machine for this thread.
Instance Method Summary collapse
-
#<<(text) ⇒ Object
Append text to the compile buffer.
-
#add_to_hash ⇒ Object
Add the key and value to the hash being constructed.
-
#begin_compile_mode(ctrl, defs = {}, &action) ⇒ Object
Start compiling a fOOrth definition.
-
#buffer_valid? ⇒ Boolean
Is the buffer valid?.
-
#check_deferred_mode(text, ctrls) ⇒ Object
Verify the deferred execution state.
-
#clear_cast ⇒ Object
Clear the method cast.
-
#compiler_reset ⇒ Object
Return the compiler to a known state.
-
#connect_vm_to_thread ⇒ Object
Connect the vm to a thread variable.
-
#console ⇒ Object
The current system console object.
-
#dbg_puts(*args) ⇒ Object
Send out debug info to the fOOrth debug port if debug is enabled.
-
#delayed_compile_mode(start) ⇒ Object
Enter a delayed compile mode in which compilation is delayed till a later time.
-
#display_abort(exception) ⇒ Object
Display the diagnostic data required for a language abort error.
-
#do_delayed_compile_mode(start) ⇒ Object
The worker bee for delayed_compile_mode.
-
#end_compile_mode(ctrls) ⇒ Object
Finish compiling a fOOrth definition.
-
#execute_mode? ⇒ Boolean
Check to see if the virtual machine is in execute mode.
-
#foorth_copy(name) ⇒ Object
Create a copy of a donor vm instance.
-
#foorth_name ⇒ Object
The name of the virtual machine instance.
-
#generate_code(token, word) ⇒ Object
Finally generate some code!
Parameters: * token - The token to receive the generated code. -
#get_cast ⇒ Object
Get the method cast and clear it.
-
#get_info ⇒ Object
Get introspection info.
-
#get_token ⇒ Object
Get the next token structure from the source code or nil if none can be found.
-
#initialize(name = '-') ⇒ VirtualMachine
constructor
Create an new instance of a fOOrth virtual machine
Parameters: * name - An optional string that describes this virtual machine instance. -
#interpreter_reset ⇒ Object
Reset the state of the fOOrth inner interpreter.
-
#nest_mode(text, ctrl) ⇒ Object
Enter a nested context without altering the current mode.
-
#peek(index = 1) ⇒ Object
Read an entry from the data stack without modify that stack.
-
#peek?(index = 1) ⇒ Boolean
Read an entry from the data stack as a boolean without modify that stack.
-
#poke(datum) ⇒ Object
Overwrite the TOS with the supplied data.
-
#pop ⇒ Object
Remove the “top” entry from the data stack.
-
#pop? ⇒ Boolean
Remove the “top” entry from the data stack as a boolean.
-
#popm(count) ⇒ Object
Remove multiple entries from the “top” of the data stack.
-
#process_console ⇒ Object
Execute code from the interactive console.
-
#process_file(name) ⇒ Object
Execute a file of code.
-
#process_string(str) ⇒ Object
Execute a string of code.
-
#process_text(text) ⇒ Object
Depending on the mode, process the text source code.
-
#push(datum) ⇒ Object
Add an entry to the data stack.
-
#pushm(datum) ⇒ Object
Add some entries to the data stack.
-
#reinitialize(name) ⇒ Object
Get the vm ready for operation
Parameters: * name - A string that describes this virtual machine instance. -
#reset ⇒ Object
Reset the interpreter and the compiler.
-
#resume_buffered_mode(ctrls) ⇒ Object
While compiling and compiling is suspended, resume normal compiling.
-
#resume_execute_mode(text, ctrls) ⇒ Object
If execution was previously deferred, resume the previous mode.
-
#set_cast(spec) ⇒ Object
Set the method cast.
-
#squash ⇒ Object
Compress the entire data stack into a single entry.
-
#string_parms(token, word) ⇒ Object
Process optional string parameters.
-
#suspend_buffered_mode(ctrl) ⇒ Object
While compiling, suspend compiling so that some code may be executed.
-
#suspend_execute_mode(text, ctrl) ⇒ Object
Enter a mode where execution is deferred.
-
#swap_pop ⇒ Object
A special operation to support dyadic operators.
-
#unnest_mode(text, ctrls) ⇒ Object
Leave a nested context without altering the current mode.
-
#unsquash ⇒ Object
Compress all the added entries into a single entry and revive the previous contents of the data stack.
-
#verify_cast(allowed) ⇒ Object
Verify the method cast.
-
#verify_casts_cleared ⇒ Object
Make sure there are no dangling casts.
-
#version ⇒ Object
Get the version string for this virtual machine.
-
#vm_do(jloop = [0, 0, 0], &block) ⇒ Object
The runtime implementation of the “do” word.
-
#vm_do_increment ⇒ Object
The runtime implementation of the “+loop” word.
Constructor Details
#initialize(name = '-') ⇒ VirtualMachine
Create an new instance of a fOOrth virtual machine
Parameters:
-
name - An optional string that describes this virtual machine instance.
Note
-
A XfOOrthError will be raised if an attempt is made to create more than
one virtual machine on a thread.
38 39 40 41 42 43 |
# File 'lib/fOOrth/initialize.rb', line 38 def initialize(name='-') @name, @debug, @show_stack, @data = name, false, false, {} #Bring the major sub-systems to a known state. self.reset.connect_vm_to_thread end |
Instance Attribute Details
#context ⇒ Object (readonly)
The current execution/compile context.
30 31 32 |
# File 'lib/fOOrth/compiler.rb', line 30 def context @context end |
#data ⇒ Object (readonly)
The thread data associated with this virtual machine.
30 31 32 |
# File 'lib/fOOrth/initialize.rb', line 30 def data @data end |
#data_stack ⇒ Object
The fOOrth data stack. This is the primary means used to hold data for processing.
10 11 12 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 10 def data_stack @data_stack end |
#debug ⇒ Object
Set true for verbose compiler play-by-plays and detailed error reports.
21 22 23 |
# File 'lib/fOOrth/initialize.rb', line 21 def debug @debug end |
#fiber ⇒ Object
The currently active fiber, if any.
15 16 17 |
# File 'lib/fOOrth/core/virtual_machine.rb', line 15 def fiber @fiber end |
#name ⇒ Object (readonly)
The descriptive name of this virtual machine.
27 28 29 |
# File 'lib/fOOrth/initialize.rb', line 27 def name @name end |
#parens ⇒ Object
The level of comment nesting.
36 37 38 |
# File 'lib/fOOrth/compiler.rb', line 36 def parens @parens end |
#parser ⇒ Object (readonly)
The current compiler parser.
27 28 29 |
# File 'lib/fOOrth/compiler.rb', line 27 def parser @parser end |
#quotes ⇒ Object
The level of quote nesting.
33 34 35 |
# File 'lib/fOOrth/compiler.rb', line 33 def quotes @quotes end |
#show_stack ⇒ Object
Set true to print out the data stack after every interactive line is processed.
24 25 26 |
# File 'lib/fOOrth/initialize.rb', line 24 def show_stack @show_stack end |
#start_time ⇒ Object
The fOOrth timer anchor point. Used to assist in benchmarking etc.
15 16 17 |
# File 'lib/fOOrth/interpreter.rb', line 15 def start_time @start_time end |
Class Method Details
.create_foorth_subclass(_name) ⇒ Object
Create a new fOOrth subclass of this class. This is not allowed for the VirtualMachine class so this stub merely raises an exception.
21 22 23 |
# File 'lib/fOOrth/core/virtual_machine.rb', line 21 def create_foorth_subclass(_name) error "F13: Forbidden operation: VirtualMachine .class: " end |
.vm(name = '-') ⇒ Object
Get or create a virtual machine for this thread.
Paramters:
-
name - The name of the virtual machine, if one is created. If a virtual
machine already exists for this thread, this parameter is ignored.
Note: Non-intuitive code.
-
VitualMachine.new connects to the thread, setting up
\Thread.current[:vm] as a side-effect. Thus it is not done here.
16 17 18 |
# File 'lib/fOOrth/initialize.rb', line 16 def self.vm(name='-') Thread.current[:vm] || VirtualMachine.new(name) end |
Instance Method Details
#<<(text) ⇒ Object
Append text to the compile buffer.
48 49 50 51 52 53 |
# File 'lib/fOOrth/compiler.rb', line 48 def <<(text) dbg_puts " Append=#{text.inspect}" @buffer << text rescue NoMethodError error "F14: The current mode does not allow code to be appended." end |
#add_to_hash ⇒ Object
Add the key and value to the hash being constructed.
10 11 12 13 |
# File 'lib/fOOrth/interpreter/add_to_hash.rb', line 10 def add_to_hash key, value = popm(2) peek(1)[key] = value end |
#begin_compile_mode(ctrl, defs = {}, &action) ⇒ Object
Start compiling a fOOrth definition. This is used to get things going by the various compiling words like ‘:’, ‘::’, ‘:::’, etc.
Parameters:
-
ctrl - The control symbol that started the compilation.
-
action - A block to be executed when the compilation is done.
Note:
-
Adds a nested context level to be un-nested at a later point.
15 16 17 18 19 20 21 |
# File 'lib/fOOrth/compiler/modes/compiled.rb', line 15 def begin_compile_mode(ctrl, defs={}, &action) dbg_puts " begin_compile_mode" @context.check_set(:mode, [:execute]) @context = Context.new(@context, mode: :compile, ctrl: ctrl, action: action) @context.merge(defs) @buffer = '' end |
#buffer_valid? ⇒ Boolean
Is the buffer valid?
56 57 58 |
# File 'lib/fOOrth/compiler.rb', line 56 def buffer_valid? @buffer.is_a?(String) end |
#check_deferred_mode(text, ctrls) ⇒ Object
Verify the deferred execution state. This are used by words that work within a word grouping like else or while.
Parameters:
-
text - Some text to append to the buffer before bundling it up.
-
ctrls - An array of control symbols that could have started the deferral.
35 36 37 38 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 35 def check_deferred_mode(text, ctrls) @context.check_set(:ctrl, ctrls) self << text end |
#clear_cast ⇒ Object
Clear the method cast
16 17 18 |
# File 'lib/fOOrth/compiler/cast.rb', line 16 def clear_cast @cast = nil end |
#compiler_reset ⇒ Object
Return the compiler to a known state.
39 40 41 42 43 44 45 |
# File 'lib/fOOrth/compiler.rb', line 39 def compiler_reset @buffer = @parser = nil @quotes = @parens = 0 clear_cast @context = Context.new(nil, vm: self, mode: :execute) self end |
#connect_vm_to_thread ⇒ Object
Connect the vm to a thread variable.
70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/fOOrth/initialize.rb', line 70 def connect_vm_to_thread #Check for duplicates. current = Thread.current error "F91: Only one virtual machine allowed per thread" if current[:vm] #This virtual machine is associated with this thread. current[:vm] = self @start_time = Time.now self end |
#console ⇒ Object
The current system console object. Gets the current console object only creating one if somebody asks for one.
Note
-
This is to be the sole occurrence of @_private_console
22 23 24 |
# File 'lib/fOOrth/compiler.rb', line 22 def console @_private_console ||= Console.new end |
#dbg_puts(*args) ⇒ Object
Send out debug info to the fOOrth debug port if debug is enabled.
10 11 12 |
# File 'lib/fOOrth/debug/dbg_puts.rb', line 10 def dbg_puts(*args) $foorth_dbg.puts(*args) if debug end |
#delayed_compile_mode(start) ⇒ Object
Enter a delayed compile mode in which compilation is delayed till a later time.
10 11 12 13 14 15 16 17 18 |
# File 'lib/fOOrth/compiler/modes/delayed.rb', line 10 def delayed_compile_mode(start) dbg_puts " begin_delayed_compile_mode" buffer = do_delayed_compile_mode(start) dbg_puts " Append=#{buffer}" @buffer << buffer dbg_puts " end_delayed_compile_mode" end |
#display_abort(exception) ⇒ Object
Display the diagnostic data required for a language abort error.
Parameters:
-
exception - The exception object that required the system abort or a
string describing the error that was encountered.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/fOOrth/debug/display_abort.rb', line 13 def display_abort(exception) puts "\n#{exception.foorth_message}" if debug puts "Data Stack Contents: #{data_stack.inspect}" puts "\nInternal Backtrace Dump:" puts puts exception.backtrace puts end reset end |
#do_delayed_compile_mode(start) ⇒ Object
The worker bee for delayed_compile_mode.
Endemic Code Smells
-
:reek:FeatureEnvy – false positive
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/fOOrth/compiler/modes/delayed.rb', line 23 def do_delayed_compile_mode(start) buffer, depth = start + ' ', 1 while depth > 0 if (word = parser.get_word_or_string) buffer << word + ' ' depth += 1 if [':', '!:', '.:', '.::'].include?(word) depth -= 1 if word == ';' else error "F12: Error, Invalid compile nesting." end end "vm.process_string(#{buffer.foorth_embed}); " end |
#end_compile_mode(ctrls) ⇒ Object
Finish compiling a fOOrth definition. This is used to wrap things up, mostly by the semi-colon ‘;’ word.
Parameters:
-
ctrls - an array of the allowed set of control values.
Returns:
-
The value of the action block.
Note:
-
Un-nests a context level.
31 32 33 34 35 36 37 38 |
# File 'lib/fOOrth/compiler/modes/compiled.rb', line 31 def end_compile_mode(ctrls) @context.check_set(:ctrl, ctrls) source, @buffer = "lambda {|vm| #{@buffer} }", nil result = instance_exec(self, source, @context., &@context[:action]) @context = @context.previous dbg_puts " end_compile_mode" result end |
#execute_mode? ⇒ Boolean
Check to see if the virtual machine is in execute mode.
27 28 29 |
# File 'lib/fOOrth/compiler/modes.rb', line 27 def execute_mode? @context[:mode] == :execute end |
#foorth_copy(name) ⇒ Object
Create a copy of a donor vm instance.
Parameters:
-
name - An optional string that describes this virtual machine instance.
48 49 50 51 52 |
# File 'lib/fOOrth/initialize.rb', line 48 def foorth_copy(name) copy = self.clone copy.reinitialize(name) copy end |
#foorth_name ⇒ Object
The name of the virtual machine instance
10 11 12 |
# File 'lib/fOOrth/core/virtual_machine.rb', line 10 def foorth_name "#{self.class.foorth_name} instance <#{@name}>" end |
#generate_code(token, word) ⇒ Object
Finally generate some code!
Parameters:
-
token - The token to receive the generated code.
-
word - The text of the word.
13 14 15 16 17 18 19 20 21 |
# File 'lib/fOOrth/compiler/process/generate.rb', line 13 def generate_code(token, word) if (spec = @context.map(word)) token.add(spec.builds, spec.) elsif (value = word.to_foorth_n) token.add("vm.push(#{value.foorth_embed}); ", [:numeric]) else error "F10: ?#{word}?" end end |
#get_cast ⇒ Object
Get the method cast and clear it.
33 34 35 |
# File 'lib/fOOrth/compiler/cast.rb', line 33 def get_cast @cast end |
#get_info ⇒ Object
Get introspection info.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/fOOrth/library/introspection/vm.rb', line 10 def get_info results = [["Name", foorth_name], ["Ruby", self.to_s], ["Stack", @data_stack.inspect], ["Nesting", @context.depth], ["Quotes", @quotes], ["Debug", @debug], ["Show", @show_stack], ["Start", @start_time]] if (source = @parser && @parser.source) results << ["Source", source.source_name] results << ["Buffer", source.read_buffer.inspect] end names = instance_variables.map do |sym| if (name = XfOOrth::SymbolMap.unmap(sym.to_s[1..-1].to_sym)) [name, sym] end end names.compact! unless names.empty? results.concat([["", ""], ["Data", "Instance"], ["", ""]]) names.each do |name, sym| results << [name, instance_variable_get(sym)] end end unless @data.empty? results.concat([["", ""], ["Data", "Thread"], ["", ""]]) @data .keys .map{|symbol| [SymbolMap.unmap(symbol), symbol]} .sort{|a,b| a[0] <=> b[0]} .map{|name, symbol| [name, @data[symbol]]} .each do |name, value| results << [name, value.inspect] end end if foorth_has_exclusive? results.concat([["", ""], ["Methods", "Exclusive"]]) foorth_exclusive.extract_method_names(:all).sort.each do |name| symbol, info = SymbolMap.map_info(name) results.concat([["", ""], ["Name", name], info]) spec, info = map_foorth_exclusive_info(symbol, :shallow) results.concat(info).concat(spec.get_info) end end results end |
#get_token ⇒ Object
Get the next token structure from the source code or nil if none can be found.
Returns
-
A Token structure or nil.
13 14 15 16 17 18 19 20 |
# File 'lib/fOOrth/compiler/process/get_token.rb', line 13 def get_token return nil unless (word = parser.get_word) token = Token.new string_parms(token, word) || procedure_parms(token, word) generate_code(token, word) token end |
#interpreter_reset ⇒ Object
Reset the state of the fOOrth inner interpreter.
18 19 20 21 |
# File 'lib/fOOrth/interpreter.rb', line 18 def interpreter_reset @data_stack = Array.new self end |
#nest_mode(text, ctrl) ⇒ Object
Enter a nested context without altering the current mode.
Parameters:
-
text - Some text to append associated with the nested state.
-
ctrl - The control symbol that started the nested context.
Note:
-
Adds a nested context level to be un-nested at a later point.
14 15 16 17 18 |
# File 'lib/fOOrth/compiler/modes/nested.rb', line 14 def nest_mode(text, ctrl) dbg_puts " nest_context" @context = Context.new(@context, ctrl: ctrl) process_text(text) end |
#peek(index = 1) ⇒ Object
Read an entry from the data stack without modify that stack.
Parameters:
-
index - The (optional) entry to be retrieved. 1 corresponds to the
"top" of the stack, 2 the next element, etc.
This parameter defaults to 1.
Returns:
-
The element specified from the data stack.
Note:
-
Attempting to access an element deeper than the number of elements
on the stack will fail with an XfOOrthError exception.
72 73 74 75 76 77 78 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 72 def peek(index=1) unless @data_stack.length >= index && index > 0 error "F30: Data Stack Underflow: peek" end @data_stack[-index] end |
#peek?(index = 1) ⇒ Boolean
Read an entry from the data stack as a boolean without modify that stack.
Parameters:
-
index - The (optional) entry to be retrieved. 1 corresponds to the “top”
of the stack, 2 the next element, etc. This parameter defaults to 1.
Returns:
-
The element specified from the data stack as a boolean.
Note:
-
Attempting to access an element deeper than the number of elements on
the stack will fail with an XfOOrthError exception.
99 100 101 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 99 def peek?(index=1) peek(index).to_foorth_b end |
#poke(datum) ⇒ Object
Overwrite the TOS with the supplied data.
Parameters:
-
datum - The data to be placed in the data stack.
Note:
-
Attempting to poke an empty stack will fail with an XfOOrthError exception.
85 86 87 88 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 85 def poke(datum) error "F30: Data Stack Underflow: poke" if @data_stack.empty? @data_stack[-1] = datum end |
#pop ⇒ Object
Remove the “top” entry from the data stack.
Returns:
-
The “top” element of the data stack.
Note:
-
If the stack is empty this will raise an XfOOrthError exception.
31 32 33 34 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 31 def pop error "F30: Data Stack Underflow: pop" if @data_stack.empty? @data_stack.pop end |
#pop? ⇒ Boolean
Remove the “top” entry from the data stack as a boolean.
Returns:
-
The “top” element of the data stack as a boolean
Note:
-
If the stack is empty this will raise an XfOOrthError exception.
58 59 60 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 58 def pop? pop.to_foorth_b end |
#popm(count) ⇒ Object
Remove multiple entries from the “top” of the data stack.
Parameters:
-
count - the number of elements to be returned.
Returns:
-
An array containing the “top” count elements of the data stack.
Note:
-
Raises an XfOOrthError exception if the stack has too few data.
43 44 45 46 47 48 49 50 51 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 43 def popm(count) begin error "F30: Data Stack Underflow: popm" if @data_stack.length < count @data_stack.pop(count) rescue @data_stack = [] raise end end |
#process_console ⇒ Object
Execute code from the interactive console.
61 62 63 64 65 |
# File 'lib/fOOrth/compiler.rb', line 61 def process_console process(console) ensure console.flush end |
#process_file(name) ⇒ Object
Execute a file of code.
73 74 75 76 77 78 79 80 81 |
# File 'lib/fOOrth/compiler.rb', line 73 def process_file(name) source = FileSource.new(name) begin process(source) ensure source.close end end |
#process_string(str) ⇒ Object
Execute a string of code.
68 69 70 |
# File 'lib/fOOrth/compiler.rb', line 68 def process_string(str) process(StringSource.new(str)) end |
#process_text(text) ⇒ Object
Depending on the mode, process the text source code.
Parameters:
-
text - Some text to be executed or deferred.
17 18 19 20 21 22 23 24 |
# File 'lib/fOOrth/compiler/modes.rb', line 17 def process_text(text) if execute_mode? dbg_puts " Code=#{text.inspect}" @context.target.instance_exec(self, &eval("lambda {|vm| #{text} }")) else self << text end end |
#push(datum) ⇒ Object
Add an entry to the data stack.
Parameters:
-
datum - The data to be added to the data stack.
15 16 17 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 15 def push(datum) @data_stack << datum end |
#pushm(datum) ⇒ Object
Add some entries to the data stack.
Parameters:
-
datum - An array of data to be mass added to the data stack.
22 23 24 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 22 def pushm(datum) @data_stack += datum end |
#reinitialize(name) ⇒ Object
Get the vm ready for operation
Parameters:
-
name - A string that describes this virtual machine instance.
57 58 59 60 61 |
# File 'lib/fOOrth/initialize.rb', line 57 def reinitialize(name) @data_stack = @data_stack.clone @name = name @data = @data.full_clone end |
#reset ⇒ Object
Reset the interpreter and the compiler.
64 65 66 67 |
# File 'lib/fOOrth/initialize.rb', line 64 def reset interpreter_reset compiler_reset end |
#resume_buffered_mode(ctrls) ⇒ Object
While compiling and compiling is suspended, resume normal compiling.
Parameters:
-
ctrls - An array of control symbols that could have
suspended the compilation.
Note:
-
Un-nests a context level.
29 30 31 32 33 |
# File 'lib/fOOrth/compiler/modes/suspend.rb', line 29 def resume_buffered_mode(ctrls) dbg_puts " resume_buffered_mode" @context.check_set(:ctrl, ctrls) @context = @context.previous end |
#resume_execute_mode(text, ctrls) ⇒ Object
If execution was previously deferred, resume the previous mode. This is used in words that close off a block action like then, loop, or repeat.
Parameters:
-
text - Some text to append to the buffer before bundling it up.
-
ctrls - An array of control symbols that could have started the deferral.
Note:
-
Un-nests a context level.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 47 def resume_execute_mode(text, ctrls) dbg_puts " resume_execute_mode" check_deferred_mode(text, ctrls) @context = @context.previous if @context[:mode] == :execute source, @buffer = "lambda {|vm| #{@buffer} }", nil instance_exec(self, &eval(source)) end end |
#set_cast(spec) ⇒ Object
Set the method cast.
10 11 12 13 |
# File 'lib/fOOrth/compiler/cast.rb', line 10 def set_cast(spec) error "F12: Multiple methods casts detected." if @cast @cast = spec end |
#squash ⇒ Object
Compress the entire data stack into a single entry.
10 11 12 |
# File 'lib/fOOrth/interpreter/squash.rb', line 10 def squash @data_stack = [@data_stack] end |
#string_parms(token, word) ⇒ Object
Process optional string parameters.
Parameters:
-
token - The token to receive the generated code.
-
word - The text of the word.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/fOOrth/compiler/process/string.rb', line 13 def string_parms(token, word) source = parser.source if word.end_with?('"') string_value = parser.get_string. if source.peek == '*' source.get token.add("vm.push(StringBuffer.new(#{string_value})); ", [:string]) else token.add("vm.push(#{string_value}.freeze); ", [:string]) end end end |
#suspend_buffered_mode(ctrl) ⇒ Object
While compiling, suspend compiling so that some code may be executed.
Parameters:
-
ctrl - The control symbol that suspended the compilation.
Note:
-
Adds a nested context level to be un-nested at a later point.
13 14 15 16 17 18 19 20 21 |
# File 'lib/fOOrth/compiler/modes/suspend.rb', line 13 def suspend_buffered_mode(ctrl) dbg_puts " suspend_buffered_mode" unless buffer_valid? error "F14: The #{ctrl} method is not available in execute mode." end @context = Context.new(@context, mode: :execute, ctrl: ctrl) end |
#suspend_execute_mode(text, ctrl) ⇒ Object
Enter a mode where execution is deferred. If currently in :execute mode, enter :deferred mode else the mode is unchanged. This is used by words that need to group words together to work like if, do, and begin.
Parameters:
-
text - Some text to append to the buffer before proceeding.
-
ctrl - The control symbol that started the deferral.
Notes:
-
Adds a nested context level to be un-nested at a later point.
-
Enters deferred mode only if currently in execute mode. Otherwise
continues in the current mode.
18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 18 def suspend_execute_mode(text, ctrl) dbg_puts " suspend_execute_mode" @context = Context.new(@context, ctrl: ctrl) if execute_mode? @context[:mode] = :deferred @buffer = '' end self << text end |
#swap_pop ⇒ Object
A special operation to support dyadic operators. Swap then pop.
Returns:
-
The second element from the data stack.
Note:
-
If the stack has less than 2 elements, this will raise an
XfOOrthError exception.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/fOOrth/interpreter/data_stack.rb', line 109 def swap_pop begin unless @data_stack.length >= 2 error "F30: Data Stack Underflow: swap_pop" end nos, tos = @data_stack.pop(2) @data_stack << tos nos rescue @data_stack = [] raise end end |
#unnest_mode(text, ctrls) ⇒ Object
Leave a nested context without altering the current mode.
Parameters:
-
text - Some text to append associated with the nested state.
-
ctrls - An array of control symbols that could have started the nest.
Note:
-
Removes a nested context level.
26 27 28 29 30 31 |
# File 'lib/fOOrth/compiler/modes/nested.rb', line 26 def unnest_mode(text, ctrls) dbg_puts " unnest_context" @context.check_set(:ctrl, ctrls) @context = @context.previous process_text(text) if text end |
#unsquash ⇒ Object
Compress all the added entries into a single entry and revive the previous contents of the data stack.
16 17 18 19 20 21 |
# File 'lib/fOOrth/interpreter/squash.rb', line 16 def unsquash previous = @data_stack[0] data = @data_stack[1..-1] @data_stack = previous push(data) end |
#verify_cast(allowed) ⇒ Object
Verify the method cast
21 22 23 24 25 |
# File 'lib/fOOrth/compiler/cast.rb', line 21 def verify_cast(allowed) if @cast && !allowed.include?(@cast) error "F13: Cast of #{@cast.foorth_class_name} not allowed." end end |
#verify_casts_cleared ⇒ Object
Make sure there are no dangling casts.
28 29 30 |
# File 'lib/fOOrth/compiler/cast.rb', line 28 def verify_casts_cleared error "F12: Dangling method cast detected." if @cast end |
#version ⇒ Object
Get the version string for this virtual machine.
Endemic Code Smells
-
:reek:UtilityFunction
51 52 53 |
# File 'lib/fOOrth.rb', line 51 def version XfOOrth.version end |
#vm_do(jloop = [0, 0, 0], &block) ⇒ Object
The runtime implementation of the “do” word.
Parameters:
-
jloop - An optional outer loop value.
-
block - A block of code to be executed as the do loop body.
Block Parameters:
-
iloop - The stack frame of the current loop counter. This
corresponds to the fOOrth 'i' value.
-
jloop - The stack frame of any containing loop counter. This corresponds
to the fOOrth 'j' value. If there is no containing loop, this
will always be a zero frame ie: [0, 0, 0].
Note:
-
Nested loops must be in the same compiler context in order to use this
mechanism. Otherwise, loop index counters must be passed in explicitly.
Endemic Code Smells
-
:reek:FeatureEnvy – false positive
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/fOOrth/interpreter/do_loop.rb', line 24 def vm_do(jloop = [0, 0, 0], &block) #Pop the start and ending values from the stack. start_index, end_index = popm(2) #Construct the loop data frame. iloop = [start_index, end_index - 1, start_index + end_index - 1] #Loop until done! while iloop[0] <= iloop[1] #Yield to the loop. yield iloop, jloop end end |
#vm_do_increment ⇒ Object
The runtime implementation of the “+loop” word.
39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/fOOrth/interpreter/do_loop.rb', line 39 def vm_do_increment inc_raw = self.pop unless (inc_value = inc_raw.to_foorth_n) error "F40: Cannot convert a #{inc_raw.foorth_name} to a Numeric instance" end if inc_value > 0 inc_value else error "F41: Invalid loop increment value: #{inc_value}" end end |