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
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'jrubyfx'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
# FIXME : JRubyFX is not implementing add correctly.
|
5
|
+
class Java::JavafxSceneControl::ScrollPane
|
6
|
+
def add(child)
|
7
|
+
set_content(child)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module RPiet
|
12
|
+
|
13
|
+
class Debugger < JRubyFX::Application
|
14
|
+
include JRubyFX
|
15
|
+
|
16
|
+
attr_reader :stage
|
17
|
+
|
18
|
+
DEFAULT_DELAY = 0.25 # seconds
|
19
|
+
SIZE = 30
|
20
|
+
NORMAL = Java::javafx.scene.paint.Color.web("0x222222")
|
21
|
+
CANDIDATE = Java::javafx.scene.paint.Color::YELLOW
|
22
|
+
BREAKPOINT = Java::javafx.scene.paint.Color::RED
|
23
|
+
CURRENT = Java::javafx.scene.paint.Color::CADETBLUE
|
24
|
+
WHITE = Java::javafx.scene.paint.Color::WHITE
|
25
|
+
|
26
|
+
ARROW = [2, 9, 11, 9, 10, 4, 18, 10, 10, 16, 11, 11, 2, 11].to_java(:double)
|
27
|
+
|
28
|
+
def self.instance
|
29
|
+
@@instance
|
30
|
+
end
|
31
|
+
|
32
|
+
def break_point?(x,y)
|
33
|
+
@break_points["#{x}x#{y}"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_directions(start_x, start_y, end_x, end_y)
|
37
|
+
stage["#connector"].tap do |connector|
|
38
|
+
connector.start_x = SIZE/2 + codel2pixels(start_x)
|
39
|
+
connector.start_y = SIZE/2 + codel2pixels(start_y)
|
40
|
+
connector.end_x = SIZE/2 + codel2pixels(end_x)
|
41
|
+
connector.end_y = SIZE/2 + codel2pixels(end_y)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def codel2pixels(codel_offset)
|
46
|
+
(codel_offset + 1) * SIZE
|
47
|
+
end
|
48
|
+
|
49
|
+
def begin_session
|
50
|
+
update_directions(-1, 0, 0, 0)
|
51
|
+
end
|
52
|
+
|
53
|
+
def highlight_candidate(runtime, edge_x, edge_y, next_x, next_y, valid)
|
54
|
+
update_directions(edge_x, edge_y, next_x, next_y)
|
55
|
+
# Replace with black edge in debugger later
|
56
|
+
if next_x < 0 || next_y < 0 || next_x >= runtime.source.cols || next_y >= runtime.source.rows
|
57
|
+
puts "OUT OF BOUNDS #{next_x} #{next_y} #{runtime.source.rows} #{runtime.source.cols}"
|
58
|
+
return
|
59
|
+
end
|
60
|
+
run_later do
|
61
|
+
stage["\##{next_x}x#{next_y}"].stroke = CANDIDATE
|
62
|
+
if @lastc_x
|
63
|
+
color = break_point?(@lastc_x, @lastc_y) ? BREAKPOINT : NORMAL
|
64
|
+
if color == NORMAL && stage["\##{@lastc_x}x#{@lastc_y}"].stroke != CURRENT
|
65
|
+
stage["\##{@lastc_x}x#{@lastc_y}"].stroke = color
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@lastc_x, @lastc_y = next_x, next_y
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def highlight(runtime, x, y)
|
73
|
+
run_later do
|
74
|
+
stage["\##{x}x#{y}"].stroke = CURRENT
|
75
|
+
if @last_x
|
76
|
+
color = break_point?(@last_x, @last_y) ? BREAKPOINT : NORMAL
|
77
|
+
stage["\##{@last_x}x#{@last_y}"].stroke = color
|
78
|
+
end
|
79
|
+
@last_x, @last_y = x, y
|
80
|
+
|
81
|
+
#@stage["#connector"].visible = false
|
82
|
+
stage["#dp-arrow"].rotate = @rpiet.pvm.dp.degrees
|
83
|
+
stage["#cc-arrow"].rotate = @rpiet.pvm.cc.degrees(@rpiet.pvm.dp)
|
84
|
+
stage["#cc-text"].text = @rpiet.pvm.cc.to_s
|
85
|
+
|
86
|
+
percent_y = y.to_f / (@rpiet.source.rows + 2)
|
87
|
+
percent_x = x.to_f / (@rpiet.source.cols + 2)
|
88
|
+
virtual_w = (@rpiet.source.cols + 2) * SIZE
|
89
|
+
virtual_h = (@rpiet.source.rows + 2) * SIZE
|
90
|
+
sb = stage['#scrollbar']
|
91
|
+
real_x, real_y = x * 43, y * 43 # I lay out 30x30 but they end up 43x43 on screen?
|
92
|
+
real_w, real_h = sb.width, sb.height
|
93
|
+
s_x, s_y = sb.hvalue * virtual_w, sb.vvalue * virtual_h
|
94
|
+
|
95
|
+
# FIXME: Add x,y offset guides on out of bound blocks so scrolling is less confusing
|
96
|
+
# FIXME: Clean this up and use a clamp so we do not exceed scroll bounds
|
97
|
+
a_x = real_x - s_x
|
98
|
+
if a_x > real_w
|
99
|
+
sb.hvalue += 0.1
|
100
|
+
elsif a_x < 0
|
101
|
+
sb.hvalue -= 0.1
|
102
|
+
end
|
103
|
+
|
104
|
+
a_y = real_y - s_y
|
105
|
+
if a_y > real_h
|
106
|
+
sb.vvalue += 0.1
|
107
|
+
elsif a_y < 0
|
108
|
+
sb.vvalue -= 0.1
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# puts "VirtW: #{virtual_w}, REAL_W: #{real_w}"
|
113
|
+
# puts "S_X: #{(sb.hvalue * virtual_w).to_i} #{x * 43}"
|
114
|
+
# puts "V: #{percent_y} #{sb.vmax} #{sb.vvalue} H: #{percent_x} #{sb.hmax} #{sb.hvalue}"
|
115
|
+
runtime.pause if break_point?(x, y)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def operation(runtime, oper)
|
120
|
+
run_later do
|
121
|
+
puts "operation"
|
122
|
+
stage['#oper'].text = "oper: " + oper.to_s
|
123
|
+
stage['#stack'].text = "stack: " + runtime.pvm.stack.inspect
|
124
|
+
stage['#bv'].text = "value: " + runtime.pvm.block_value.inspect
|
125
|
+
stage['#state-values'].visible = true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# JavaFX has some caching so we cheat the cache by using file: uri and varying the uri by adding a time param.
|
130
|
+
def reload_stylesheet(scene)
|
131
|
+
run_later do
|
132
|
+
scene.stylesheets.clear
|
133
|
+
scene.stylesheets.add(File.join('file:' + File.dirname(__FILE__), (@odd_load_css ? '/./' : '') + "stylesheet.css"))
|
134
|
+
@odd_load_css = !@odd_load_css
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def watch_stylesheet(scene)
|
139
|
+
file = File.join(File.dirname(__FILE__), "stylesheet.css")
|
140
|
+
last_time = File.mtime(file)
|
141
|
+
Thread.new do
|
142
|
+
loop do
|
143
|
+
mtime = File.mtime(file)
|
144
|
+
|
145
|
+
if mtime != last_time
|
146
|
+
reload_stylesheet(scene)
|
147
|
+
last_time = mtime
|
148
|
+
else
|
149
|
+
sleep 1
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end.run
|
153
|
+
end
|
154
|
+
|
155
|
+
def start(stage)
|
156
|
+
@rpiet = $rpiet # how does jrubyfx pass params before start is called?
|
157
|
+
@break_points = break_points = {}
|
158
|
+
@stage = stage
|
159
|
+
debugger = self
|
160
|
+
@rpiet.delay = DEFAULT_DELAY
|
161
|
+
|
162
|
+
# FIXME: Move into convenience module near top of JRubyFX hier. Maybe make a feature for these
|
163
|
+
::Kernel.instance_eval {
|
164
|
+
define_method(:codel) { |i=1| SIZE * i}
|
165
|
+
define_method(:half_codel) { SIZE/2 }
|
166
|
+
}
|
167
|
+
rows, cols, pixels = @rpiet.source.rows, @rpiet.source.cols, @rpiet.source.pixels
|
168
|
+
rpiet = @rpiet
|
169
|
+
stroke_width = SIZE / 10
|
170
|
+
with(stage, title: "RPiet", width: 800, height: 600) do
|
171
|
+
layout_scene do
|
172
|
+
vbox(id: 'main') do
|
173
|
+
border_pane do
|
174
|
+
top(menu_bar! do
|
175
|
+
menu("File") do
|
176
|
+
menu_item("Quit") do
|
177
|
+
set_on_action do |event|
|
178
|
+
rpiet.abort
|
179
|
+
Platform.exit
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
menu("View") do
|
184
|
+
menu_item("Reload Stylesheet") { set_on_action { |_| debugger.reload_stylesheet(stage.scene) } }
|
185
|
+
menu_item("Pause (0.025s)") { set_on_action { |_| rpiet.delay = 0.025 } }
|
186
|
+
menu_item("Pause (0.1s)") { set_on_action { |_| rpiet.delay = 0.1 } }
|
187
|
+
menu_item("Pause (#{DEFAULT_DELAY}s)") { set_on_action { |_| rpiet.delay = DEFAULT_DELAY } }
|
188
|
+
end
|
189
|
+
end)
|
190
|
+
left(hbox(id: 'state') do
|
191
|
+
label("DP", id: 'dp-label')
|
192
|
+
polygon(ARROW, id: 'dp-arrow')
|
193
|
+
label("CC:", id: 'cc-label')
|
194
|
+
polygon(ARROW, id: 'cc-arrow')
|
195
|
+
label(rpiet.pvm.cc.to_s, id: 'cc-text')
|
196
|
+
hbox(id: 'state-values') do
|
197
|
+
label("oper:", id: 'oper')
|
198
|
+
label("value: ", id: 'bv')
|
199
|
+
label("stack:", id: 'stack')
|
200
|
+
end
|
201
|
+
end)
|
202
|
+
right(hbox do
|
203
|
+
get_style_class.add "controls"
|
204
|
+
button("restart") do
|
205
|
+
get_style_class.add "control"
|
206
|
+
set_on_action { |_| rpiet.restart }
|
207
|
+
end
|
208
|
+
button("pause") do
|
209
|
+
get_style_class.add "control"
|
210
|
+
set_on_action { |_| rpiet.pause }
|
211
|
+
end
|
212
|
+
button("resume") do
|
213
|
+
get_style_class.add "control"
|
214
|
+
set_on_action { |_| rpiet.resume }
|
215
|
+
end
|
216
|
+
button("step") do
|
217
|
+
get_style_class.add "control"
|
218
|
+
set_on_action { |_| rpiet.advance }
|
219
|
+
end
|
220
|
+
end)
|
221
|
+
end
|
222
|
+
scroll_pane(id: 'scrollbar') do |sp|
|
223
|
+
sp.set_content(group() do
|
224
|
+
Java::javafx.scene.layout.VBox.setVgrow(sp, Java::javafx.scene.layout.Priority::ALWAYS)
|
225
|
+
|
226
|
+
# Horizontal top and bottom border
|
227
|
+
(rpiet.source.cols + 2).times do |i|
|
228
|
+
rectangle(codel(i), 0, codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
|
229
|
+
get_style_class.add "out-of-bounds"
|
230
|
+
end
|
231
|
+
text(codel(i) + half_codel, half_codel, (i-1).to_s) if i != 0 && i != cols + 1
|
232
|
+
|
233
|
+
rectangle(codel(i), codel(rpiet.source.rows + 1), codel-1, codel-1,
|
234
|
+
stroke_type: :inside, stroke: NORMAL) do
|
235
|
+
get_style_class.add "out-of-bounds"
|
236
|
+
end
|
237
|
+
text(codel(i) + half_codel, codel(rows + 1) + half_codel, (i-1).to_s) if i != 0 && i != cols + 1
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
# Left and right vertical border
|
242
|
+
group do
|
243
|
+
rpiet.source.rows.times do |j|
|
244
|
+
rectangle(0, codel(j + 1), codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
|
245
|
+
get_style_class.add "out-of-bounds"
|
246
|
+
end
|
247
|
+
text(half_codel, codel(j + 1) + half_codel, j.to_s)
|
248
|
+
|
249
|
+
rectangle(codel(cols + 1), codel(j + 1), codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
|
250
|
+
get_style_class.add "out-of-bounds"
|
251
|
+
end
|
252
|
+
text(codel(cols + 1) + half_codel, codel(j + 1) + half_codel, j.to_s)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# Main codels
|
257
|
+
pixels.each_with_index do |row, i|
|
258
|
+
row.each_with_index do |piet_pixel, j|
|
259
|
+
color = Java::javafx.scene.paint.Color.web(piet_pixel.rgb)
|
260
|
+
ident = "#{i}x#{j}"
|
261
|
+
rectangle(codel(i+1), codel(j+1), codel-1, codel-1, fill: color,
|
262
|
+
stroke_type: :inside, stroke_width: stroke_width,
|
263
|
+
stroke: NORMAL, stroke_line_join: :round, id: ident) do
|
264
|
+
get_style_class.add "codel"
|
265
|
+
set_on_mouse_clicked do |event|
|
266
|
+
new_color = if event.source.stroke == BREAKPOINT
|
267
|
+
break_points[ident] = nil
|
268
|
+
NORMAL
|
269
|
+
else
|
270
|
+
break_points[ident] = event.source
|
271
|
+
BREAKPOINT
|
272
|
+
end
|
273
|
+
event.source.stroke = new_color
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
# FIXME: stroke_width must be derived but I feel I need to add scrolling and a minimum
|
279
|
+
# codel display SIZE before I can do this.
|
280
|
+
line(start_x: half_codel, start_y: codel + half_codel,
|
281
|
+
end_x: codel + half_codel, end_y: codel + half_codel, stroke_width: 10, id: 'connector')
|
282
|
+
end)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end.show
|
287
|
+
|
288
|
+
stage.set_on_close_request {
|
289
|
+
rpiet.abort
|
290
|
+
Platform.exit
|
291
|
+
}
|
292
|
+
$event_handler.debugger_started self
|
293
|
+
begin_session
|
294
|
+
reload_stylesheet(stage.scene)
|
295
|
+
watch_stylesheet(stage.scene)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#bv {
|
2
|
+
-fx-text-fill: #ffffff;
|
3
|
+
-fx-padding: 3;
|
4
|
+
}
|
5
|
+
|
6
|
+
#cc-arrow {
|
7
|
+
-fx-fill: #ffffff;
|
8
|
+
-fx-padding: 3;
|
9
|
+
-fx-stroke_width: 6;
|
10
|
+
}
|
11
|
+
|
12
|
+
#cc-label {
|
13
|
+
-fx-text-fill: #ffffff;
|
14
|
+
-fx-padding: 3;
|
15
|
+
-fx-font-size: 28;
|
16
|
+
}
|
17
|
+
|
18
|
+
#cc-text {
|
19
|
+
-fx-text-fill: #ffffff;
|
20
|
+
-fx-font-size: 28;
|
21
|
+
}
|
22
|
+
|
23
|
+
.codel {
|
24
|
+
-fx-arc-width: 1;
|
25
|
+
-fx-arc-width: 1;
|
26
|
+
-fx-stroke-width: 2;
|
27
|
+
-fx-background-color: #444455;
|
28
|
+
}
|
29
|
+
|
30
|
+
#connector {
|
31
|
+
-fx-fill: #999999;
|
32
|
+
-fx-stroke-width: 4;
|
33
|
+
}
|
34
|
+
|
35
|
+
.controls {
|
36
|
+
-fx-padding: 10;
|
37
|
+
-fx-text-fill: #000000;
|
38
|
+
}
|
39
|
+
|
40
|
+
.control {
|
41
|
+
-fx-text-fill: #000000;
|
42
|
+
}
|
43
|
+
|
44
|
+
#dp {
|
45
|
+
-fx-spacing: 20;
|
46
|
+
}
|
47
|
+
|
48
|
+
#dp-arrow {
|
49
|
+
-fx-fill: #ffffff;
|
50
|
+
}
|
51
|
+
|
52
|
+
#dp-label {
|
53
|
+
-fx-text-fill: #ffffff;
|
54
|
+
-fx-font-size: 28;
|
55
|
+
}
|
56
|
+
|
57
|
+
#main {
|
58
|
+
-fx-background-color: #444455;
|
59
|
+
}
|
60
|
+
|
61
|
+
#oper {
|
62
|
+
-fx-text-fill: #ffffff;
|
63
|
+
-fx-padding: 3;
|
64
|
+
}
|
65
|
+
|
66
|
+
.out-of-bounds {
|
67
|
+
-fx-arc-width: 1;
|
68
|
+
-fx-arc-width: 1;
|
69
|
+
-fx-stroke-width: 0;
|
70
|
+
-fx-fill: #999999;
|
71
|
+
}
|
72
|
+
|
73
|
+
#stack {
|
74
|
+
-fx-text-fill: #ffffff;
|
75
|
+
-fx-padding: 3;
|
76
|
+
}
|
77
|
+
|
78
|
+
#state {
|
79
|
+
-fx-padding: 40;
|
80
|
+
}
|
81
|
+
|
82
|
+
#state-values {
|
83
|
+
}
|
84
|
+
|
85
|
+
#value {
|
86
|
+
-fx-text-fill: #ffffff;
|
87
|
+
-fx-padding: 3;
|
88
|
+
}
|
@@ -1,39 +1,70 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'cycle'
|
2
|
+
require_relative 'codel_chooser'
|
3
3
|
|
4
4
|
module RPiet
|
5
5
|
extend RPiet::CycleMethod
|
6
6
|
cycle :Direction, :RIGHT, :DOWN, :LEFT, :UP
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
module DirectionExtras
|
9
|
+
def next_point(x, y)
|
10
|
+
dx, dy = deltas
|
11
|
+
[x + dx, y + dy]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << Direction::RIGHT
|
16
|
+
include DirectionExtras
|
17
|
+
def deltas = [1, 0]
|
18
|
+
end
|
19
|
+
|
20
|
+
class << Direction::DOWN
|
21
|
+
include DirectionExtras
|
22
|
+
def deltas = [0, 1]
|
23
|
+
end
|
24
|
+
|
25
|
+
class << Direction::LEFT
|
26
|
+
include DirectionExtras
|
27
|
+
def deltas = [-1, 0]
|
28
|
+
end
|
29
|
+
|
30
|
+
class << Direction::UP
|
31
|
+
include DirectionExtras
|
32
|
+
def deltas = [0, -1]
|
33
|
+
end
|
12
34
|
|
13
35
|
class DirectionPointer
|
14
|
-
|
36
|
+
attr_accessor :direction
|
37
|
+
|
38
|
+
def initialize(value=nil)
|
39
|
+
@direction = value ? RPiet::Direction::RIGHT.abs(value) : RPiet::Direction::RIGHT
|
40
|
+
end
|
15
41
|
|
16
|
-
def
|
17
|
-
@direction
|
42
|
+
def ==(other)
|
43
|
+
@direction == other.direction
|
18
44
|
end
|
19
45
|
|
20
46
|
def rotate!(amount = 1)
|
21
47
|
@direction = @direction.incr amount
|
48
|
+
self
|
22
49
|
end
|
23
50
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
51
|
+
def degrees = @direction.value * 90
|
52
|
+
|
53
|
+
def from_ordinal!(ordinal)
|
54
|
+
@direction = @direction.abs(ordinal)
|
55
|
+
self
|
27
56
|
end
|
28
57
|
|
58
|
+
def as_constant = %w[RIGHT DOWN LEFT UP][ordinal]
|
59
|
+
|
60
|
+
def next_possible(x, y) = @direction.next_point(x, y)
|
61
|
+
|
62
|
+
def ordinal = @direction.value
|
63
|
+
|
29
64
|
ASCII_ARROWS = ['>', 'v', '<', '^']
|
30
|
-
def ascii
|
31
|
-
ASCII_ARROWS[@direction.value]
|
32
|
-
end
|
65
|
+
def ascii = ASCII_ARROWS[@direction.value]
|
33
66
|
|
34
|
-
def inspect
|
35
|
-
@direction.inspect
|
36
|
-
end
|
67
|
+
def inspect = ordinal.to_s
|
37
68
|
alias :to_s :inspect
|
38
69
|
end
|
39
70
|
end
|
data/lib/rpiet/event_handler.rb
CHANGED
@@ -7,7 +7,10 @@ module RPiet
|
|
7
7
|
def initialized(runtime)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def next_possible(runtime, edge_x, edge_y, next_x, next_y, valid)
|
11
|
+
end
|
12
|
+
|
13
|
+
def step_begin(runtime, ex, ey)
|
11
14
|
end
|
12
15
|
|
13
16
|
def trying_again(runtime, ex, ey)
|
@@ -19,7 +22,10 @@ module RPiet
|
|
19
22
|
def execution_completed(runtime)
|
20
23
|
end
|
21
24
|
|
22
|
-
def operation(runtime, operation)
|
25
|
+
def operation(runtime, step, operation)
|
26
|
+
end
|
27
|
+
|
28
|
+
def instruction(runtime, instruction)
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
@@ -33,10 +39,11 @@ module RPiet
|
|
33
39
|
|
34
40
|
def initialized(runtime)
|
35
41
|
dmesg "codel_size: #{runtime.source.codel_size}"
|
42
|
+
dmesg "size: #{runtime.source.cols}x#{runtime.source.rows}"
|
36
43
|
end
|
37
44
|
|
38
|
-
def step_begin(runtime)
|
39
|
-
dmesg "step \##{runtime.step} -- #{runtime.pvm}"
|
45
|
+
def step_begin(runtime, ex, ey)
|
46
|
+
dmesg "step \##{runtime.step} at #{ex} #{ey} -- #{runtime.pvm}"
|
40
47
|
end
|
41
48
|
|
42
49
|
def trying_again(runtime, ex, ey)
|
@@ -51,16 +58,64 @@ module RPiet
|
|
51
58
|
dmesg "Execution trapped, program terminates"
|
52
59
|
end
|
53
60
|
|
54
|
-
def
|
55
|
-
dmesg "
|
61
|
+
def instruction(runtime, instruction)
|
62
|
+
dmesg " instr: #{instruction}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def operation(runtime, step, operation)
|
66
|
+
dmesg "exec: step: \##{step} oper: #{operation}, #{runtime}"
|
56
67
|
end
|
57
68
|
end
|
58
69
|
|
59
70
|
class ComplexAsciiOutput < SimpleAsciiOutput
|
60
|
-
def step_begin(runtime)
|
71
|
+
def step_begin(runtime, ex, ey)
|
61
72
|
super
|
62
73
|
dmesg runtime.source.ascii(runtime.groups[runtime.x][runtime.y])
|
63
74
|
end
|
64
75
|
end
|
76
|
+
|
77
|
+
class Graphical < SimpleAsciiOutput
|
78
|
+
def initialized(runtime)
|
79
|
+
unless $event_handler
|
80
|
+
require 'rpiet/debugger/debugger'
|
81
|
+
$rpiet = runtime
|
82
|
+
$event_handler = self
|
83
|
+
Thread.new { RPiet::Debugger.launch }.run
|
84
|
+
else
|
85
|
+
@debugger.begin_session
|
86
|
+
end
|
87
|
+
runtime.pause
|
88
|
+
end
|
89
|
+
|
90
|
+
def debugger_started(debugger)
|
91
|
+
@debugger = debugger
|
92
|
+
end
|
93
|
+
|
94
|
+
def step_begin(runtime, ex, ey)
|
95
|
+
@debugger.highlight(runtime, ex, ey)
|
96
|
+
if @debugger.break_point?(ex, ey)
|
97
|
+
puts "Break point at #{ex}, #{ey}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
alias :trying_again :step_begin
|
101
|
+
|
102
|
+
# edge of current group to potential entry point of next group (valid is if next is a valid group).
|
103
|
+
def next_possible(runtime, edge_x, edge_y, next_x, next_y, valid)
|
104
|
+
@debugger.highlight_candidate(runtime, edge_x, edge_y, next_x, next_y, valid)
|
105
|
+
end
|
106
|
+
|
107
|
+
def operation(runtime, step, operation)
|
108
|
+
# FIXME: display step in debugger
|
109
|
+
@debugger.operation(runtime, operation)
|
110
|
+
end
|
111
|
+
|
112
|
+
def seen_white(runtime)
|
113
|
+
puts "SEEN WHITE"
|
114
|
+
end
|
115
|
+
|
116
|
+
def trying_again(runtime, ex, ey)
|
117
|
+
@debugger.highlight(runtime, ex, ey)
|
118
|
+
end
|
119
|
+
end
|
65
120
|
end
|
66
121
|
end
|
data/lib/rpiet/group.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'set'
|
2
|
+
require_relative 'direction_pointer'
|
3
|
+
require_relative 'codel_chooser'
|
3
4
|
|
4
5
|
module RPiet
|
5
6
|
class Group
|
6
7
|
include RPiet::Direction
|
7
|
-
attr_reader :
|
8
|
+
attr_reader :color, :points
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
# represents significant corners in a group based on the dp and cc.
|
11
|
+
# First letter is the dp: {r-ight, l-eft, d-own, u-p}.
|
12
|
+
# The second letter is the codel chooser: {l-eft, r-ight}.
|
13
|
+
attr_reader :rl, :rr, :lr, :ll, :ul, :ur, :dr, :dl
|
14
|
+
|
15
|
+
def initialize(color, *points)
|
16
|
+
@color, @points = color, []
|
11
17
|
@max = { RIGHT => [], LEFT => [], UP => [], DOWN => [] }
|
12
18
|
|
13
|
-
self << point
|
19
|
+
points.each { |point| self << point}
|
14
20
|
end
|
15
21
|
|
16
22
|
def point_for(pvm)
|
@@ -35,11 +41,22 @@ module RPiet
|
|
35
41
|
@points << point
|
36
42
|
end
|
37
43
|
|
44
|
+
def edges
|
45
|
+
edges = Set.new
|
46
|
+
@points.each do |x, y|
|
47
|
+
edges.add [x, y, :up] unless @points.include?(UP.next_point(x, y))
|
48
|
+
edges.add [x, y, :down] unless @points.include? DOWN.next_point(x, y)
|
49
|
+
edges.add [x, y, :left] unless @points.include?(LEFT.next_point(x, y))
|
50
|
+
edges.add [x, y, :right] unless @points.include? RIGHT.next_point(x, y)
|
51
|
+
end
|
52
|
+
edges
|
53
|
+
end
|
54
|
+
|
38
55
|
def include?(point)
|
39
56
|
@points.include? point
|
40
57
|
end
|
41
58
|
|
42
|
-
def
|
59
|
+
def calculate_corners
|
43
60
|
@rl, @rr = ends(@max[RIGHT].sort { |a, b| a[1] <=> b[1] })
|
44
61
|
@lr, @ll = ends(@max[LEFT].sort { |a, b| a[1] <=> b[1] })
|
45
62
|
@ul, @ur = ends(@max[UP].sort { |a, b| a[0] <=> b[0] })
|
@@ -99,7 +116,7 @@ module RPiet
|
|
99
116
|
end
|
100
117
|
|
101
118
|
def inspect
|
102
|
-
"Group #{
|
119
|
+
"Group #{color}: Size: #{size} Points: #{@points.inspect}\n" +
|
103
120
|
"rr #@rr rl #@rl lr #@lr ll #@ll ur #@ur ul #@ul dr #@dr dl #@dl"
|
104
121
|
end
|
105
122
|
alias :to_s :inspect
|
@@ -4,25 +4,15 @@ module RPiet
|
|
4
4
|
module Image
|
5
5
|
class AsciiImage < RPiet::Image::Image
|
6
6
|
def initialize(string, codel_size=1)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
lines.each do |line|
|
11
|
-
@data << line.split(/\s+/).map { |e| str_to_rgb(e) }
|
7
|
+
super codel_size
|
8
|
+
@data = string.each_line(chomp: true).map do |line|
|
9
|
+
line.split(/\s+/).map { |e| str_to_rgb(e) }
|
12
10
|
end
|
13
11
|
end
|
14
12
|
|
15
|
-
def raw_pixel(x, y)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def raw_height
|
20
|
-
@data.length
|
21
|
-
end
|
22
|
-
|
23
|
-
def raw_width
|
24
|
-
@data[0].length
|
25
|
-
end
|
13
|
+
def raw_pixel(x, y) = @data[y][x]
|
14
|
+
def raw_height = @data.length
|
15
|
+
def raw_width = @data[0].length
|
26
16
|
|
27
17
|
STR2RGB = {
|
28
18
|
'lr' => [0xff, 0xc0, 0xc0],
|
@@ -33,7 +23,7 @@ module RPiet
|
|
33
23
|
'lm' => [0xff, 0xc0, 0xff],
|
34
24
|
'nr' => [0xff, 0x00, 0x00],
|
35
25
|
'ny' => [0xff, 0xff, 0x00],
|
36
|
-
'ng' => [
|
26
|
+
'ng' => [0x00, 0xff, 0x00],
|
37
27
|
'nc' => [0x00, 0xff, 0xff],
|
38
28
|
'nb' => [0x00, 0x00, 0xff],
|
39
29
|
'nm' => [0xff, 0x00, 0xff],
|
@@ -47,9 +37,7 @@ module RPiet
|
|
47
37
|
'++' => [0x00, 0x00, 0x00]
|
48
38
|
}
|
49
39
|
|
50
|
-
def str_to_rgb(str)
|
51
|
-
STR2RGB[str]
|
52
|
-
end
|
40
|
+
def str_to_rgb(str) = STR2RGB[str]
|
53
41
|
end
|
54
42
|
end
|
55
43
|
end
|