rpiet 0.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|