Class: XfOOrth::VirtualMachine

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

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

#contextObject (readonly)

The current execution/compile context.



30
31
32
# File 'lib/fOOrth/compiler.rb', line 30

def context
  @context
end

#dataObject (readonly)

The thread data associated with this virtual machine.



30
31
32
# File 'lib/fOOrth/initialize.rb', line 30

def data
  @data
end

#data_stackObject

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

#debugObject

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

#fiberObject

The currently active fiber, if any.



15
16
17
# File 'lib/fOOrth/core/virtual_machine.rb', line 15

def fiber
  @fiber
end

#nameObject (readonly)

The descriptive name of this virtual machine.



27
28
29
# File 'lib/fOOrth/initialize.rb', line 27

def name
  @name
end

#parensObject

The level of comment nesting.



36
37
38
# File 'lib/fOOrth/compiler.rb', line 36

def parens
  @parens
end

#parserObject (readonly)

The current compiler parser.



27
28
29
# File 'lib/fOOrth/compiler.rb', line 27

def parser
  @parser
end

#quotesObject

The level of quote nesting.



33
34
35
# File 'lib/fOOrth/compiler.rb', line 33

def quotes
  @quotes
end

#show_stackObject

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_timeObject

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_hashObject

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?

Returns:

  • (Boolean)


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_castObject

Clear the method cast



16
17
18
# File 'lib/fOOrth/compiler/cast.rb', line 16

def clear_cast
  @cast = nil
end

#compiler_resetObject

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_threadObject

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

#consoleObject

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.tags, &@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.

Returns:

  • (Boolean)


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_nameObject

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.tags)
  elsif (value = word.to_foorth_n)
    token.add("vm.push(#{value.foorth_embed}); ", [:numeric])
  else
    error "F10: ?#{word}?"
  end
end

#get_castObject

Get the method cast and clear it.



33
34
35
# File 'lib/fOOrth/compiler/cast.rb', line 33

def get_cast
  @cast
end

#get_infoObject

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_tokenObject

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_resetObject

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.

Returns:

  • (Boolean)


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

#popObject

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.

Returns:

  • (Boolean)


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_consoleObject

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

#resetObject

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

#squashObject

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.foorth_embed

    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_popObject

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

#unsquashObject

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_clearedObject

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

#versionObject

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_incrementObject

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