Class: XfOOrth::VirtualMachine
- Defined in:
- lib/fOOrth.rb,
lib/fOOrth/compiler.rb,
lib/fOOrth/initialize.rb,
lib/fOOrth/interpreter.rb,
lib/fOOrth/debug/vm_dump.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/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.
-
#force ⇒ Object
Is a force compile in effect?.
-
#name ⇒ Object
readonly
The descriptive name of this virtual machine.
-
#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.
-
#check_deferred_mode(text, ctrls) ⇒ Object
Verify the deferred execution state.
-
#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.
-
#debug_dump ⇒ Object
Dump the virtual machine to the console for debug.
-
#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_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_compile_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.
-
#squash ⇒ Object
Compress the entire data stack into a single entry.
-
#string_parms(token, word) ⇒ Object
Process optional string parameters.
-
#suspend_compile_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.
-
#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.
29 30 31 |
# File 'lib/fOOrth/compiler.rb', line 29 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 |
#force ⇒ Object
Is a force compile in effect?
35 36 37 |
# File 'lib/fOOrth/compiler.rb', line 35 def force @force 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 |
#parser ⇒ Object (readonly)
The current compiler parser.
26 27 28 |
# File 'lib/fOOrth/compiler.rb', line 26 def parser @parser end |
#quotes ⇒ Object
The level of quote nesting.
32 33 34 |
# File 'lib/fOOrth/compiler.rb', line 32 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.create_foorth_subclass)." 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 |
# File 'lib/fOOrth/compiler.rb', line 48 def <<(text) dbg_puts " Append=#{text.inspect}" @buffer << text 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 |
#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.
33 34 35 36 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 33 def check_deferred_mode(text, ctrls) @context.check_set(:ctrl, ctrls) self << text end |
#compiler_reset ⇒ Object
Return the compiler to a known state.
38 39 40 41 42 43 44 45 |
# File 'lib/fOOrth/compiler.rb', line 38 def compiler_reset @buffer = nil @parser = nil @quotes = 0 @force = false @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
21 22 23 |
# File 'lib/fOOrth/compiler.rb', line 21 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 |
#debug_dump ⇒ Object
Dump the virtual machine to the console for debug.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/fOOrth/debug/vm_dump.rb', line 10 def debug_dump source = @parser && @parser.source puts "\n#{self.foorth_name}" \ "\n Ruby = #{self.to_s}" \ "\n Stack = #{@data_stack.inspect}" \ "\n Nesting = #{@context.depth}" \ "\n Quotes = #{@quotes}" \ "\n Debug = #{@debug}" \ "\n Show = #{@show_stack}" \ "\n Force = #{@force}" \ "\n Start = #{@start_time}" \ "\n Source = #{source && source.source_name}" \ "\n Buffer = #{source && source.read_buffer.inspect}" 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 27 28 29 30 31 32 |
# File 'lib/fOOrth/debug/display_abort.rb', line 13 def display_abort(exception) puts "\n#{exception.}" if debug puts "Data Stack Contents: #{data_stack.inspect}" if @context @context.debug_dump(self) else puts "Error: No context is available!" end 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.}); " 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.}); ", [:numeric]) else error "F10: ?#{word}?" end 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.
54 55 56 57 58 |
# File 'lib/fOOrth/compiler.rb', line 54 def process_console process(console) ensure console.flush end |
#process_file(name) ⇒ Object
Execute a file of code.
66 67 68 69 70 71 72 73 74 |
# File 'lib/fOOrth/compiler.rb', line 66 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.
61 62 63 |
# File 'lib/fOOrth/compiler.rb', line 61 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.recvr.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_compile_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.
25 26 27 28 29 |
# File 'lib/fOOrth/compiler/modes/suspend.rb', line 25 def resume_compile_mode(ctrls) dbg_puts " resume_compile_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.
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 45 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 |
#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 |
# File 'lib/fOOrth/compiler/process/string.rb', line 13 def string_parms(token, word) if word.end_with?('"') token.add("vm.push(#{parser.get_string.}); ") end end |
#suspend_compile_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 |
# File 'lib/fOOrth/compiler/modes/suspend.rb', line 13 def suspend_compile_mode(ctrl) dbg_puts " suspend_compile_mode" @context.check_set(:mode, [:compile]) @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.
Note:
-
Adds a nested context level to be un-nested at a later point.
16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/fOOrth/compiler/modes/deferred.rb', line 16 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 |
#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 |