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

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.



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

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

#forceObject

Is a force compile in effect?



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

def force
  @force
end

#nameObject (readonly)

The descriptive name of this virtual machine.



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

def name
  @name
end

#parserObject (readonly)

The current compiler parser.



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

def parser
  @parser
end

#quotesObject

The level of quote nesting.



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

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

#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_resetObject

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



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_dumpObject

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.foorth_message}"

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



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

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

#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
# 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.foorth_embed}); ")
  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_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

#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