rpiet 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +12 -0
- data/bin/color_wheel +84 -0
- data/bin/image_gen +39 -0
- data/bin/rpiet +68 -11
- data/images/counter.txt +7 -0
- data/lib/rpiet/asg/graph_interpreter.rb +39 -0
- data/lib/rpiet/asg/parser.rb +156 -0
- data/lib/rpiet/asg/visitor.rb +66 -0
- data/lib/rpiet/asg.rb +336 -0
- data/lib/rpiet/codel_chooser.rb +32 -4
- data/lib/rpiet/color.rb +70 -25
- data/lib/rpiet/cycle.rb +18 -7
- data/lib/rpiet/debugger/debugger.rb +298 -0
- data/lib/rpiet/debugger/stylesheet.css +88 -0
- data/lib/rpiet/direction_pointer.rb +49 -18
- data/lib/rpiet/event_handler.rb +62 -7
- data/lib/rpiet/group.rb +25 -8
- data/lib/rpiet/image/ascii_image.rb +8 -20
- data/lib/rpiet/image/image.rb +8 -3
- data/lib/rpiet/image/url_image.rb +28 -14
- data/lib/rpiet/interpreter.rb +72 -72
- data/lib/rpiet/ir/assembler.rb +87 -0
- data/lib/rpiet/ir/builder.rb +255 -0
- data/lib/rpiet/ir/cfg.rb +494 -0
- data/lib/rpiet/ir/instructions.rb +536 -0
- data/lib/rpiet/ir/ir_cfg_interpreter.rb +23 -0
- data/lib/rpiet/ir/ir_interpreter.rb +101 -0
- data/lib/rpiet/ir/ir_native_interpreter.rb +77 -0
- data/lib/rpiet/ir/jruby_backend.rb +279 -0
- data/lib/rpiet/ir/operands.rb +28 -0
- data/lib/rpiet/ir/passes/data_flow_problem.rb +32 -0
- data/lib/rpiet/ir/passes/flow_graph_node.rb +76 -0
- data/lib/rpiet/ir/passes/peephole.rb +214 -0
- data/lib/rpiet/ir/passes/push_pop_elimination_pass.rb +112 -0
- data/lib/rpiet/live_machine_state.rb +15 -0
- data/lib/rpiet/machine.rb +62 -32
- data/lib/rpiet/source.rb +83 -0
- data/lib/rpiet/version.rb +1 -1
- data/lib/rpiet.rb +2 -2
- data/rpiet.gemspec +19 -0
- data/spec/asg/visitor_spec.rb +41 -0
- data/spec/cycle_spec.rb +34 -34
- data/spec/direction_pointer_spec.rb +33 -6
- data/spec/group_spec.rb +73 -48
- data/spec/interpreter_spec.rb +161 -12
- data/spec/ir/assembler_spec.rb +122 -0
- data/spec/ir/builder_spec.rb +20 -0
- data/spec/ir/cfg_spec.rb +151 -0
- data/spec/ir/ir_interpreter_spec.rb +102 -0
- data/spec/ir/passes/push_pop_elimination_pass_spec.rb +34 -0
- data/spec/machine_spec.rb +5 -3
- data/spec/source_spec.rb +69 -0
- data/spec/spec_helper.rb +78 -0
- metadata +54 -16
- data/images/nfib.png +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f899ca8b426c587720e0f92d070276e4f4290f6c06129768d7ce76f0f4c8aa44
|
4
|
+
data.tar.gz: a595f1cd225d3bfe78212e9d637023fd88edad148ce5376b0e57bea27f3d4844
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 494ead01ba5971cf780765a0527bd5be690897701a9e025a94943b3e3bc1a07a63bdd98ba0b4ee4455935de44b56c0b462c8c8de0ddaf49ab9fc700f5345dd39
|
7
|
+
data.tar.gz: 9d65d740f440808d57854cceceede0a8e07b7713833501ae8bf14c0b5680515188e7e7b4e1b4ca767c8cc0bc5fec123b260ab41af3fd34ceea1bc692ca9eec9b
|
data/.gitignore
CHANGED
data/Gemfile
ADDED
data/bin/color_wheel
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
require 'rpiet/color'
|
3
|
+
require 'rpiet/image/ascii_image'
|
4
|
+
|
5
|
+
|
6
|
+
def die(message)
|
7
|
+
puts message
|
8
|
+
exit -1
|
9
|
+
end
|
10
|
+
|
11
|
+
def decode(item)
|
12
|
+
item, dimensions = item.split(':') if item.include? ':'
|
13
|
+
|
14
|
+
if dimensions
|
15
|
+
if dimensions.include? 'x'
|
16
|
+
rows, cols = dimensions.split('x').map &:to_i
|
17
|
+
else
|
18
|
+
rows, cols = 1, dimensions.to_i
|
19
|
+
end
|
20
|
+
else
|
21
|
+
rows, cols = 1, 1
|
22
|
+
end
|
23
|
+
|
24
|
+
[item, rows, cols]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Starting color
|
28
|
+
color_name = ARGV.shift
|
29
|
+
commands = ARGV
|
30
|
+
color_name, rows, cols = decode(color_name)
|
31
|
+
|
32
|
+
rgb = RPiet::Image::AsciiImage::STR2RGB[color_name]
|
33
|
+
die "Invalid color name: '#{color_name}'" unless rgb
|
34
|
+
|
35
|
+
color = RPiet::Color.color_for(format "0x%02x%02x%02x" % rgb)
|
36
|
+
|
37
|
+
CHANGES = {
|
38
|
+
noop: [0, 0],
|
39
|
+
push: [0, 1],
|
40
|
+
pop: [0, 2],
|
41
|
+
add: [1, 0],
|
42
|
+
sub: [1, 1],
|
43
|
+
mult: [1, 2],
|
44
|
+
div: [2, 0],
|
45
|
+
mod: [2, 1],
|
46
|
+
not: [2, 2],
|
47
|
+
gtr: [3, 0],
|
48
|
+
pntr: [3, 1],
|
49
|
+
swch: [3, 2],
|
50
|
+
dup: [4, 0],
|
51
|
+
roll: [4, 1],
|
52
|
+
nin: [4, 2],
|
53
|
+
cin: [5, 0],
|
54
|
+
nout: [5, 1],
|
55
|
+
cout: [5, 2]
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
total_rows, total_cols = rows, cols
|
60
|
+
groups = [[color, rows, cols]]
|
61
|
+
commands.each do |command|
|
62
|
+
command, rows, cols = decode command
|
63
|
+
deltas = CHANGES[command.to_sym]
|
64
|
+
die "Invalid command: '#{command}'" unless deltas
|
65
|
+
color = color.color_from(hue_delta: deltas[0], lightness_delta: deltas[1])
|
66
|
+
groups << [color, rows, cols]
|
67
|
+
total_rows = rows if rows > total_rows
|
68
|
+
total_cols += cols
|
69
|
+
end
|
70
|
+
|
71
|
+
image = Array.new(total_rows) { Array.new(total_cols) {'++'} }
|
72
|
+
|
73
|
+
col_index, row_index = 0, 0
|
74
|
+
groups.each do |color, rows, cols|
|
75
|
+
id = color.to_initial
|
76
|
+
rows.times do |j|
|
77
|
+
cols.times do |i|
|
78
|
+
image[row_index + j][col_index + i] = id
|
79
|
+
end
|
80
|
+
end
|
81
|
+
col_index += cols
|
82
|
+
end
|
83
|
+
|
84
|
+
image.each { |rows| puts rows.join(' ') }
|
data/bin/image_gen
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'rpiet/image/ascii_image'
|
5
|
+
require 'image_voodoo'
|
6
|
+
|
7
|
+
input_codel_size = 1
|
8
|
+
output_codel_size = input_codel_size
|
9
|
+
image_type = "png"
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.on("-i", "--input-codel-size w", "size of input codel") { |w| input_codel_size = w.to_i }
|
12
|
+
opts.on("-o", "--output-odel-size w", "size of output codel") { |w| output_codel_size = w.to_i }
|
13
|
+
opts.on("-t", "--image-type suffix", "image format") { |t| image_type = t }
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.parse!(ARGV)
|
17
|
+
unless ARGV.first
|
18
|
+
puts "You need to supply a source image filename."
|
19
|
+
puts opts
|
20
|
+
exit -1
|
21
|
+
end
|
22
|
+
|
23
|
+
filename = ARGV.first
|
24
|
+
file_contents = filename == '-' ? $stdin.read(nil) : File.read(filename)
|
25
|
+
|
26
|
+
image = RPiet::Image::AsciiImage.new(file_contents, input_codel_size)
|
27
|
+
width, height = image.size
|
28
|
+
|
29
|
+
canvas = ImageVoodoo.canvas(output_codel_size * width, output_codel_size * height, 'ffffff')
|
30
|
+
|
31
|
+
image.each do |i, j, color|
|
32
|
+
canvas.rect i * output_codel_size, j * output_codel_size, output_codel_size, output_codel_size, color.rgb[2..-1]
|
33
|
+
end
|
34
|
+
|
35
|
+
if filename == '-'
|
36
|
+
$stdout.write canvas.bytes('png')
|
37
|
+
else
|
38
|
+
canvas.save(File.basename(filename, ".txt") + "." + image_type)
|
39
|
+
end
|
data/bin/rpiet
CHANGED
@@ -2,29 +2,86 @@
|
|
2
2
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'rpiet'
|
5
|
-
require 'rpiet/image/url_image'
|
6
5
|
|
6
|
+
run = :chowder
|
7
|
+
time_execution = false
|
7
8
|
codel_size = 1
|
8
9
|
|
9
|
-
|
10
|
+
dump = nil
|
11
|
+
|
12
|
+
log = nil
|
10
13
|
opts = OptionParser.new do |opts|
|
11
14
|
opts.banner = "Usage: #{__FILE__} -d image_file"
|
12
15
|
|
16
|
+
opts.on("-t", "--time", "time execution") { time_execution = true }
|
17
|
+
opts.on("-r", "--runtime runtime") do |runtime|
|
18
|
+
run = case runtime
|
19
|
+
when 'native' then :native
|
20
|
+
when 'graph' then :graph
|
21
|
+
when 'ir' then :ir
|
22
|
+
when 'cfg' then :cfg
|
23
|
+
when 'chowder' then :chowder
|
24
|
+
else raise ArgumentError.new("invalid runtime specified: #{runtime}")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
opts.on("-I", "--dump-ir", "Dump image as IR instructions") { dump = :ir }
|
13
29
|
opts.on("-d", "--debug style", "turn on debugging") do |style|
|
14
30
|
log = case style
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
31
|
+
when 'simple' then RPiet::Logger::SimpleAsciiOutput.new
|
32
|
+
when 'complex' then RPiet::Logger::ComplexAsciiOutput.new
|
33
|
+
when 'graphical' then RPiet::Logger::Graphical.new
|
34
|
+
else raise ArgumentError.new("invalid logger specified: #{style}")
|
35
|
+
end
|
20
36
|
end
|
21
37
|
opts.on("-c", "--codel-size w", "size of codel") { |w| codel_size = w.to_i }
|
22
38
|
end
|
23
39
|
|
24
40
|
opts.parse!(ARGV)
|
25
|
-
|
41
|
+
unless ARGV.first
|
42
|
+
puts "You need to supply a source image filename."
|
43
|
+
puts opts
|
44
|
+
exit -1
|
45
|
+
end
|
26
46
|
|
27
47
|
filename = ARGV.first
|
28
|
-
|
29
|
-
|
30
|
-
|
48
|
+
|
49
|
+
if filename =~ /.txt/
|
50
|
+
require 'rpiet/image/ascii_image'
|
51
|
+
image = RPiet::Image::AsciiImage.new(File.read(filename), codel_size)
|
52
|
+
elsif filename == '-'
|
53
|
+
require 'rpiet/image/ascii_image'
|
54
|
+
image = RPiet::Image::AsciiImage.new($stdin.gets(nil), codel_size)
|
55
|
+
else
|
56
|
+
filename = 'file:' + filename if File.exist? filename
|
57
|
+
require 'rpiet/image/url_image'
|
58
|
+
image = RPiet::Image::URLImage.new(filename, codel_size)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
runner = case run
|
63
|
+
when :graph
|
64
|
+
require 'rpiet/asg/graph_interpreter'
|
65
|
+
RPiet::ASG::GraphInterpreter.new(image, log)
|
66
|
+
when :ir
|
67
|
+
require 'rpiet/ir/ir_interpreter'
|
68
|
+
RPiet::IR::IRInterpreter.new(image, log)
|
69
|
+
when :cfg
|
70
|
+
require 'rpiet/ir/ir_cfg_interpreter'
|
71
|
+
RPiet::IR::IRCFGInterpreter.new(image, log)
|
72
|
+
when :native
|
73
|
+
require 'rpiet/ir/ir_native_interpreter'
|
74
|
+
RPiet::IR::IRNativeInterpreter.new(image, log)
|
75
|
+
else
|
76
|
+
RPiet::Interpreter.new(image, log)
|
77
|
+
end
|
78
|
+
|
79
|
+
if dump && (run == :ir || run == :cfg)
|
80
|
+
puts runner.disasm
|
81
|
+
else
|
82
|
+
start = Time.now if time_execution
|
83
|
+
runner.run
|
84
|
+
puts "time: #{Time.now - start}s" if time_execution
|
85
|
+
end
|
86
|
+
|
87
|
+
exit 0
|
data/images/counter.txt
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../asg'
|
2
|
+
require_relative 'parser'
|
3
|
+
|
4
|
+
module RPiet
|
5
|
+
module ASG
|
6
|
+
class GraphInterpreter
|
7
|
+
include LiveMachineState
|
8
|
+
|
9
|
+
def initialize(image, event_handler = nil)
|
10
|
+
Node.handle_event_handler(@event_handler = event_handler)
|
11
|
+
# FIXME: need a way to debug parser conditionally from command line
|
12
|
+
@graph = Parser.new(image).run
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
reset_machine()
|
17
|
+
@node = @graph
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_step
|
21
|
+
while @node && @node.hidden?
|
22
|
+
@node = @node.exec self
|
23
|
+
end
|
24
|
+
@node = @node.exec self if @node
|
25
|
+
end
|
26
|
+
|
27
|
+
def running?
|
28
|
+
@node
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
reset
|
33
|
+
while running? do
|
34
|
+
next_step
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative '../color'
|
2
|
+
require_relative '../machine'
|
3
|
+
require_relative '../source'
|
4
|
+
require_relative '../event_handler'
|
5
|
+
require_relative '../asg'
|
6
|
+
|
7
|
+
module RPiet
|
8
|
+
module ASG
|
9
|
+
class Parser
|
10
|
+
##
|
11
|
+
# Represents the transition to the next possible group from
|
12
|
+
# the current group. The direction is directed by the cc
|
13
|
+
# and dp values. The node passed in is the previously created
|
14
|
+
# node. The result of this translation will get pointed to by
|
15
|
+
# the supplied node.
|
16
|
+
class Transition
|
17
|
+
attr_reader :group, :cc_ordinal, :dp_ordinal
|
18
|
+
attr_accessor :node
|
19
|
+
|
20
|
+
def initialize(group, cc_ordinal, dp_ordinal, node)
|
21
|
+
@group, @cc_ordinal, @dp_ordinal, @node = group, cc_ordinal, dp_ordinal, node
|
22
|
+
end
|
23
|
+
|
24
|
+
def eql?(other)
|
25
|
+
other.group == @group && other.cc_ordinal == @cc_ordinal && other.dp_ordinal == @dp_ordinal
|
26
|
+
end
|
27
|
+
|
28
|
+
def hash
|
29
|
+
@cc_ordinal ^ @group.hash ^ @dp_ordinal
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"#{group}: #{@cc_ordinal}=#{@dp_ordinal}"
|
34
|
+
end
|
35
|
+
|
36
|
+
alias :to_s :inspect
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :pvm, :source, :pixels, :x, :y, :step
|
40
|
+
|
41
|
+
def initialize(image, event_handler = RPiet::Logger::NoOutput.new)
|
42
|
+
@source, @event_handler = RPiet::Source.new(image), event_handler
|
43
|
+
@x, @y, @pvm, @step = 0, 0, RPiet::Machine.new, 1
|
44
|
+
@work_list = []
|
45
|
+
@already_visited = {} # state => node
|
46
|
+
@graph = Node.create(@step, @x, @y, :noop)
|
47
|
+
@nodes = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
@work_list.push Transition.new(@source.group_at(@x, @y), @pvm.cc.ordinal, @pvm.dp.ordinal, @graph)
|
52
|
+
while !@work_list.empty?
|
53
|
+
restore_state(@work_list.pop)
|
54
|
+
next_step
|
55
|
+
end
|
56
|
+
@graph
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Add state to graph. If we have seen it we link to it otherwise we add to worklist.
|
61
|
+
def add_state(state)
|
62
|
+
if @already_visited[state]
|
63
|
+
state.node.add_path @already_visited[state], state.cc_ordinal, state.dp_ordinal
|
64
|
+
elsif !@work_list.include?(state)
|
65
|
+
@work_list.push state
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def restore_state(state)
|
70
|
+
@x, @y = state.group.rl
|
71
|
+
@pvm.cc.from_ordinal! state.cc_ordinal
|
72
|
+
@pvm.dp.from_ordinal! state.dp_ordinal
|
73
|
+
@current_state = state
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_node(step, x, y, operation, block_value)
|
77
|
+
node = Node.create(step, x, y, operation, block_value)
|
78
|
+
return @nodes[node] if @nodes[node]
|
79
|
+
@nodes[node] = node
|
80
|
+
node
|
81
|
+
end
|
82
|
+
|
83
|
+
def next_step
|
84
|
+
@pvm.block_value = @source.group_at(@x, @y).size
|
85
|
+
attempt = 1
|
86
|
+
seen_white = false
|
87
|
+
ex, ey = @source.group_at(@x, @y).point_for(@pvm) # Exit point from group
|
88
|
+
@event_handler.step_begin(self, ex, ey)
|
89
|
+
while attempt <= 8 do
|
90
|
+
nx, ny = @pvm.next_possible(ex, ey) # where we enter Next group
|
91
|
+
valid = @source.valid?(nx, ny)
|
92
|
+
@event_handler.next_possible(self, ex, ey, nx, ny, valid)
|
93
|
+
|
94
|
+
if !valid
|
95
|
+
@pvm.orient_elsewhere(attempt)
|
96
|
+
attempt += 1
|
97
|
+
|
98
|
+
ex, ey = @source.group_at(@x, @y).point_for(@pvm) if !seen_white
|
99
|
+
@event_handler.trying_again(self, ex, ey)
|
100
|
+
elsif @source.pixels[nx][ny] == RPiet::Color::WHITE
|
101
|
+
if !seen_white
|
102
|
+
seen_white = true
|
103
|
+
attempt = 1
|
104
|
+
@event_handler.seen_white(self)
|
105
|
+
end
|
106
|
+
ex, ey = nx, ny
|
107
|
+
else
|
108
|
+
if !seen_white
|
109
|
+
operation = @pvm.calculate_operation @source.pixels[nx][ny], @source.pixels[@x][@y]
|
110
|
+
else
|
111
|
+
operation = :noop
|
112
|
+
end
|
113
|
+
|
114
|
+
@step += 1
|
115
|
+
|
116
|
+
if @current_state.dp_ordinal != @pvm.dp.ordinal
|
117
|
+
node = Node.create(@step, nx, ny, :dp, @pvm.cc.ordinal, @pvm.dp.ordinal)
|
118
|
+
@current_state.node.add_path(node, @current_state.cc_ordinal, @current_state.dp_ordinal)
|
119
|
+
@current_state.node = node
|
120
|
+
@already_visited[@current_state] = node
|
121
|
+
end
|
122
|
+
if @current_state.cc_ordinal != @pvm.cc.ordinal
|
123
|
+
node = Node.create(@step, nx, ny, :cc, @pvm.cc.ordinal, @pvm.dp.ordinal)
|
124
|
+
@current_state.node.add_path(node, @current_state.cc_ordinal, @current_state.dp_ordinal)
|
125
|
+
@current_state.node = node
|
126
|
+
@already_visited[@current_state] = node unless @already_visited[@current_state]
|
127
|
+
end
|
128
|
+
|
129
|
+
node = create_node(@step, nx, ny, operation, @pvm.block_value)
|
130
|
+
@current_state.node.add_path(node, @current_state.cc_ordinal, @current_state.dp_ordinal)
|
131
|
+
@already_visited[@current_state] = node unless @already_visited[@current_state]
|
132
|
+
|
133
|
+
@x, @y = nx, ny
|
134
|
+
group = @source.group_at(@x, @y)
|
135
|
+
|
136
|
+
case operation
|
137
|
+
when :swch
|
138
|
+
add_state Transition.new(group, -1, @pvm.dp.ordinal, node)
|
139
|
+
add_state Transition.new(group, 1, @pvm.dp.ordinal, node)
|
140
|
+
when :pntr
|
141
|
+
add_state Transition.new(group, @pvm.cc.ordinal, 0, node)
|
142
|
+
add_state Transition.new(group, @pvm.cc.ordinal, 1, node)
|
143
|
+
add_state Transition.new(group, @pvm.cc.ordinal, 2, node)
|
144
|
+
add_state Transition.new(group, @pvm.cc.ordinal, 3, node)
|
145
|
+
else
|
146
|
+
add_state Transition.new(group, @pvm.cc.ordinal, @pvm.dp.ordinal, node)
|
147
|
+
end
|
148
|
+
return
|
149
|
+
end
|
150
|
+
end
|
151
|
+
@current_state.node.add_path(ExitNode.new(step, x, y))
|
152
|
+
@event_handler.execution_completed(self)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module RPiet
|
4
|
+
# Generic visitor for visiting all nodes in the graph once but
|
5
|
+
# then also visiting all nodes which complete a cycle a second time.
|
6
|
+
class Visitor
|
7
|
+
def initialize
|
8
|
+
@visited = Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(root)
|
12
|
+
worklist = [root]
|
13
|
+
|
14
|
+
visit worklist
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit(worklist)
|
18
|
+
while !worklist.empty?
|
19
|
+
node = worklist.pop
|
20
|
+
next unless node
|
21
|
+
already_visited = @visited.include? node
|
22
|
+
|
23
|
+
if already_visited
|
24
|
+
visit_again node
|
25
|
+
else
|
26
|
+
@visited.add node
|
27
|
+
if node # child of nil means exit
|
28
|
+
if node.operation == :pntr
|
29
|
+
work_items = visit_first_pntr node, worklist
|
30
|
+
elsif node.operation == :swch
|
31
|
+
work_items = visit_first_swch node, worklist
|
32
|
+
else
|
33
|
+
work_items = visit_first node
|
34
|
+
end
|
35
|
+
worklist.concat work_items if work_items && !work_items.empty?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
break if worklist.empty?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_children(node)
|
43
|
+
node.paths.each do |next_node|
|
44
|
+
next_node.visit self if next_node
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def visit_first(node)
|
49
|
+
node.paths
|
50
|
+
end
|
51
|
+
|
52
|
+
# First time we encounter an individual swch node
|
53
|
+
def visit_first_swch(node, worklist=nil)
|
54
|
+
node.paths
|
55
|
+
end
|
56
|
+
|
57
|
+
# First time we encounter an individual pntr node
|
58
|
+
def visit_first_pntr(node, worklist=nil)
|
59
|
+
node.paths
|
60
|
+
end
|
61
|
+
|
62
|
+
# Second time we encounter any ndoe
|
63
|
+
def visit_again(node)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|