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/library/alias_library.rb,
lib/fOOrth/library/stubs_library.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.
Constant Summary collapse
- ALLOWED_ALIAS_TYPES =
{ TosSpec => [TosSpec, SelfSpec], SelfSpec => [TosSpec, SelfSpec], NosSpec => [NosSpec] }
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.
-
#create_exclusive_alias(new_name) ⇒ Object
Create an exclusive method alias.
-
#create_exclusive_stub(name) ⇒ Object
Create an exclusive method stub.
-
#create_shared_alias(new_name) ⇒ Object
Create a shared method alias.
-
#create_shared_stub(name) ⇒ Object
Create a shared method stub.
-
#create_word_alias(new_name) ⇒ Object
Create a virtual machine word method alias.
-
#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 |
#create_exclusive_alias(new_name) ⇒ Object
Create an exclusive method alias
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/fOOrth/library/alias_library.rb', line 62 def create_exclusive_alias(new_name) old_name, target = popm(2) old_spec = get_old_exclusive_spec(target, old_name) target.create_exclusive_method(new_name, get_alias_type(old_spec, new_name), old_spec., &old_spec.does) clear_cast end |
#create_exclusive_stub(name) ⇒ Object
Create an exclusive method stub
39 40 41 42 43 44 45 |
# File 'lib/fOOrth/library/stubs_library.rb', line 39 def create_exclusive_stub(name) target = pop type = XfOOrth.name_to_type(name, self) XfOOrth.validate_type(self, type, name) target.create_exclusive_method(name, type, [:stub]) clear_cast end |
#create_shared_alias(new_name) ⇒ Object
Create a shared method alias
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/fOOrth/library/alias_library.rb', line 45 def create_shared_alias(new_name) old_name, target = popm(2) unless target.is_a?(Class) error "F13: The target of .alias: must be a class" end old_spec = get_old_shared_spec(target, old_name) target.create_shared_method(new_name, get_alias_type(old_spec, new_name), old_spec., &old_spec.does) clear_cast end |
#create_shared_stub(name) ⇒ Object
Create a shared method stub
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/fOOrth/library/stubs_library.rb', line 27 def create_shared_stub(name) unless (target = pop).is_a?(Class) error "F13: The target of .stub: must be a class" end type = XfOOrth.name_to_type(name, self) XfOOrth.validate_type(self, type, name) target.create_shared_method(name, type, [:stub]) clear_cast end |
#create_word_alias(new_name) ⇒ Object
Create a virtual machine word method alias.
33 34 35 36 37 38 39 40 41 42 |
# File 'lib/fOOrth/library/alias_library.rb', line 33 def create_word_alias(new_name) old_name, target = pop, self.class old_spec = get_old_shared_spec(target, old_name) target.create_shared_method(new_name, old_spec.class, old_spec., &old_spec.does) 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.}" 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.}); " 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_with_defaults(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_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 |
# File 'lib/fOOrth/library/introspection/vm.rb', line 10 def get_info results = get_basic_vm_info get_instance_variable_info(results) get_vm_thread_data_info(results) get_exclusive_method_info(results, "Exclusive") 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
49 50 51 |
# File 'lib/fOOrth.rb', line 49 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 |