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/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

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

#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.tags,
                                 &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.tags,
                              &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.tags,
                              &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.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_with_defaults(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
# 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_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



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_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