Class: GenText::VM

Inherits:
Object
  • Object
show all
Defined in:
lib/gen_text/vm.rb

Defined Under Namespace

Classes: RescuePoint

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#outIO (readonly)

Returns:



59
60
61
# File 'lib/gen_text/vm.rb', line 59

def out
  @out
end

#pcInteger (readonly)

Returns:

  • (Integer)


56
57
58
# File 'lib/gen_text/vm.rb', line 56

def pc
  @pc
end

Class Method Details

.may_set_out_pos?(program) ⇒ Boolean

Returns true if program may result in calling IO#pos= and false otherwise.

Parameters:

  • program

    Array of [:method_id, *args].

Returns:

  • (Boolean)

    true if program may result in calling IO#pos= and false otherwise.



9
10
11
12
13
# File 'lib/gen_text/vm.rb', line 9

def self.may_set_out_pos?(program)
  program.any? do |instruction|
    [:rescue_, :capture].include? instruction.first
  end
end

Instance Method Details

#call(addr) ⇒ void

This method returns an undefined value.

Parameters:

  • addr (Integer)


244
245
246
247
# File 'lib/gen_text/vm.rb', line 244

def call(addr)
  @stack.push(@pc + 1)
  @pc = addr
end

#capture(binding_, name, discard_output) ⇒ void

This method returns an undefined value.

  • p := #pop;

  • binding_.eval(set variable named name to a substring of #out from p to current position);

  • if discard_output is true then set IO#pos of #out to p.

Parameters:

  • binding_ (Binding)
  • name (String)
  • discard_output (Boolean)


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/gen_text/vm.rb', line 180

def capture(binding_, name, discard_output)
  capture_start_pos = @stack.pop
  capture_end_pos = @out.pos
  captured_string = begin
    @out.pos = capture_start_pos
    @out.read(capture_end_pos - capture_start_pos)
  end
  @out.pos =
    if discard_output then
      capture_start_pos
    else
      capture_end_pos
    end
  binding_.eval("#{name} = #{captured_string.inspect}")
  @pc += 1
end

#decvoid

This method returns an undefined value.



126
127
128
129
# File 'lib/gen_text/vm.rb', line 126

def dec
  @stack[-1] -= 1
  @pc += 1
end

#eval_ruby_code(binding_, ruby_code, file, line) ⇒ void

This method returns an undefined value.

#push(eval(ruby_code, file, line))

Parameters:

  • binding_ (Binding)
  • ruby_code (String)
  • file (String)

    original file of ruby_code.

  • line (Integer)

    original line of ruby_code.



204
205
206
207
# File 'lib/gen_text/vm.rb', line 204

def eval_ruby_code(binding_, ruby_code, file, line)
  @stack.push binding_.eval(ruby_code, file, line)
  @pc += 1
end

#genvoid

This method returns an undefined value.

Writes #pop to #out.



166
167
168
169
# File 'lib/gen_text/vm.rb', line 166

def gen
  @out.write @stack.pop
  @pc += 1
end

#generated_from(*args) ⇒ void

This method returns an undefined value.

NOP



76
77
78
# File 'lib/gen_text/vm.rb', line 76

def generated_from(*args)
  @pc += 1
end

#goto(addr) ⇒ void

This method returns an undefined value.

Parameters:

  • addr (Integer)


159
160
161
# File 'lib/gen_text/vm.rb', line 159

def goto(addr)
  @pc = addr
end

#goto_if(addr) ⇒ void

This method returns an undefined value.

If #pop is true then #pc := addr.

Parameters:

  • addr (Integer)


117
118
119
120
121
122
123
# File 'lib/gen_text/vm.rb', line 117

def goto_if(addr)
  if @stack.pop then
    @pc = addr
  else
    @pc += 1
  end
end

#goto_if_not_0(addr) ⇒ void

This method returns an undefined value.

If the value on the stack != 0 then #goto(+addr).

Parameters:

  • addr (Integer)


135
136
137
138
139
140
141
# File 'lib/gen_text/vm.rb', line 135

def goto_if_not_0(addr)
  if @stack.last != 0 then
    @pc += 1
  else
    @pc = addr
  end
end

#goto_if_rand_gt(v, addr) ⇒ void

This method returns an undefined value.

If rand > v then #goto(addr)

Parameters:

  • v (Numeric)
  • addr (Integer)


149
150
151
152
153
154
155
# File 'lib/gen_text/vm.rb', line 149

def goto_if_rand_gt(v, addr)
  if rand > v then
    @pc = addr
  else
    @pc += 1
  end
end

#haltvoid

This method returns an undefined value.

Sets #halted? to true.



69
70
71
# File 'lib/gen_text/vm.rb', line 69

def halt
  @halted = true
end

#halted?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/gen_text/vm.rb', line 62

def halted?
  @halted
end

#popObject

Pops the value from the stack.

Returns:

  • (Object)

    the popped value.



108
109
110
111
# File 'lib/gen_text/vm.rb', line 108

def pop
  @stack.pop
  @pc += 1
end

#push(o) ⇒ void

This method returns an undefined value.

Pushes o to the stack.

Parameters:

  • o (Object)


84
85
86
87
# File 'lib/gen_text/vm.rb', line 84

def push(o)
  @stack.push o
  @pc += 1
end

#push_dup(o) ⇒ void

This method returns an undefined value.

#push(o.dup)

Parameters:

  • o (Object)


93
94
95
# File 'lib/gen_text/vm.rb', line 93

def push_dup(o)
  push(o.dup)
end

#push_posvoid

This method returns an undefined value.

#push(#out‘s IO#pos)



212
213
214
215
# File 'lib/gen_text/vm.rb', line 212

def push_pos
  @stack.push(@out.pos)
  @pc += 1
end

#push_rand(r = nil) ⇒ void

This method returns an undefined value.

#push(rand(r) if r is specified; rand() otherwise)

Parameters:

  • r (Object, nil) (defaults to: nil)


101
102
103
# File 'lib/gen_text/vm.rb', line 101

def push_rand(r = nil)
  push(if r then rand(r) else rand end)
end

#push_rescue_point(pc = nil) ⇒ void

This method returns an undefined value.

#push(#out‘s IO#pos, #pc as RescuePoint)

Parameters:

  • pc (Integer, nil) (defaults to: nil)

    if specified then it is pushed instead of #pc.



221
222
223
224
# File 'lib/gen_text/vm.rb', line 221

def push_rescue_point(pc = nil)
  @stack.push RescuePoint[(pc or @pc), @out.pos]
  @pc += 1
end

#rescue_(on_failure) ⇒ void

This method returns an undefined value.

#pops until a RescuePoint is found then restore #out and #pc from the RescuePoint.

Parameters:

  • on_failure (Proc)

    is called if no RescuePoint is found



231
232
233
234
235
236
237
238
239
240
# File 'lib/gen_text/vm.rb', line 231

def rescue_(on_failure)
  @stack.pop until @stack.empty? or @stack.last.is_a? RescuePoint
  if @stack.empty? then
    on_failure.()
  else
    rescue_point = @stack.pop
    @pc = rescue_point.pc
    @out.pos = rescue_point.out_pos
  end
end

#retvoid

This method returns an undefined value.



250
251
252
# File 'lib/gen_text/vm.rb', line 250

def ret
  @pc = @stack.pop
end

#run(program, out, do_not_run = false) ⇒ void

This method returns an undefined value.

Executes program.

If program may result in calling IO#pos= (see VM::may_set_out_pos? then after the execution the out may contain garbage after its IO#pos. It is up to the caller to truncate the garbage or to copy the useful data.

Parameters:

  • program

    Array of [:method_id, *args].

  • out (IO)
  • do_not_run (Boolean) (defaults to: false)

    if true then program will not be run (some checks and initializations will be performed only).



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
# File 'lib/gen_text/vm.rb', line 26

def run(program, out, do_not_run = false)
  # 
  if $DEBUG
    STDERR.puts "PROGRAM:"
    program.each_with_index do |instruction, addr|
      STDERR.puts "  #{addr}: #{inspect_instruction(instruction)}"
    end
  end
  #
  return if do_not_run
  # Init.
  @stack = []
  @out = out
  @pc = 0
  @halted = false
  # Run.
  STDERR.puts "RUN TRACE:" if $DEBUG
  until halted?
    instruction = program[@pc]
    method_id, *args = *instruction
    STDERR.puts "  #{@pc}: #{inspect_instruction(instruction)}" if $DEBUG
    self.__send__(method_id, *args)
    if $DEBUG then
      STDERR.puts "    PC: #{@pc}"
      STDERR.puts "    STACK: #{@stack.inspect}"
    end
  end
end

#weighed_choicevoid

This method returns an undefined value.

Let stack contains wa = [[weight1, address1], [weight2, address2], …]. This function:

  1. Picks a random address from wa (the more weight the address has, the more often it is picked);

  2. Deletes the chosen address from wa;

  3. If there was the only address in wa then it does #push(nil); otherwise it does #push_rescue_point;

  4. #goto(the chosen address).



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/gen_text/vm.rb', line 265

def weighed_choice
  weights_and_addresses = @stack.last
  # If no alternatives left...
  if weights_and_addresses.size == 1 then
    _, address = *weights_and_addresses.first
    @stack.push nil
    @pc = address
  # If there are alternatives...
  else
    chosen_weight_and_address = sample_weighed(weights_and_addresses)
    weights_and_addresses.delete chosen_weight_and_address
    _, chosen_address = *chosen_weight_and_address
    push_rescue_point
    @pc = chosen_address
  end
end