rpiet 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +12 -0
  4. data/bin/color_wheel +84 -0
  5. data/bin/image_gen +39 -0
  6. data/bin/rpiet +68 -11
  7. data/images/counter.txt +7 -0
  8. data/lib/rpiet/asg/graph_interpreter.rb +39 -0
  9. data/lib/rpiet/asg/parser.rb +156 -0
  10. data/lib/rpiet/asg/visitor.rb +66 -0
  11. data/lib/rpiet/asg.rb +336 -0
  12. data/lib/rpiet/codel_chooser.rb +32 -4
  13. data/lib/rpiet/color.rb +70 -25
  14. data/lib/rpiet/cycle.rb +18 -7
  15. data/lib/rpiet/debugger/debugger.rb +298 -0
  16. data/lib/rpiet/debugger/stylesheet.css +88 -0
  17. data/lib/rpiet/direction_pointer.rb +49 -18
  18. data/lib/rpiet/event_handler.rb +62 -7
  19. data/lib/rpiet/group.rb +25 -8
  20. data/lib/rpiet/image/ascii_image.rb +8 -20
  21. data/lib/rpiet/image/image.rb +8 -3
  22. data/lib/rpiet/image/url_image.rb +28 -14
  23. data/lib/rpiet/interpreter.rb +72 -72
  24. data/lib/rpiet/ir/assembler.rb +87 -0
  25. data/lib/rpiet/ir/builder.rb +255 -0
  26. data/lib/rpiet/ir/cfg.rb +494 -0
  27. data/lib/rpiet/ir/instructions.rb +536 -0
  28. data/lib/rpiet/ir/ir_cfg_interpreter.rb +23 -0
  29. data/lib/rpiet/ir/ir_interpreter.rb +101 -0
  30. data/lib/rpiet/ir/ir_native_interpreter.rb +77 -0
  31. data/lib/rpiet/ir/jruby_backend.rb +279 -0
  32. data/lib/rpiet/ir/operands.rb +28 -0
  33. data/lib/rpiet/ir/passes/data_flow_problem.rb +32 -0
  34. data/lib/rpiet/ir/passes/flow_graph_node.rb +76 -0
  35. data/lib/rpiet/ir/passes/peephole.rb +214 -0
  36. data/lib/rpiet/ir/passes/push_pop_elimination_pass.rb +112 -0
  37. data/lib/rpiet/live_machine_state.rb +15 -0
  38. data/lib/rpiet/machine.rb +62 -32
  39. data/lib/rpiet/source.rb +83 -0
  40. data/lib/rpiet/version.rb +1 -1
  41. data/lib/rpiet.rb +2 -2
  42. data/rpiet.gemspec +19 -0
  43. data/spec/asg/visitor_spec.rb +41 -0
  44. data/spec/cycle_spec.rb +34 -34
  45. data/spec/direction_pointer_spec.rb +33 -6
  46. data/spec/group_spec.rb +73 -48
  47. data/spec/interpreter_spec.rb +161 -12
  48. data/spec/ir/assembler_spec.rb +122 -0
  49. data/spec/ir/builder_spec.rb +20 -0
  50. data/spec/ir/cfg_spec.rb +151 -0
  51. data/spec/ir/ir_interpreter_spec.rb +102 -0
  52. data/spec/ir/passes/push_pop_elimination_pass_spec.rb +34 -0
  53. data/spec/machine_spec.rb +5 -3
  54. data/spec/source_spec.rb +69 -0
  55. data/spec/spec_helper.rb +78 -0
  56. metadata +54 -16
  57. data/images/nfib.png +0 -0
data/spec/group_spec.rb CHANGED
@@ -1,57 +1,82 @@
1
- require 'rpiet/group'
2
- require 'rpiet/machine'
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/rpiet/group'
3
+ require_relative '../lib/rpiet/color'
3
4
 
4
5
  describe "Group" do
5
- before do
6
- @group = RPiet::Group.new('0x0000c0', [0, 3])
7
- [[0, 4], [0, 5], [0, 6], [0, 7], [1, 3], [1, 4], [1, 5],
8
- [1, 6], [2, 3], [2, 4], [2, 5], [2, 6], [3, 3], [3, 4], [3, 5], [3, 6],
9
- [4, 3], [4, 4], [4, 5], [4, 6], [5, 4], [6, 4], [6, 5], [6, 6], [7, 4],
10
- [7, 5], [7, 6], [8, 5], [8, 6]].each do |point|
11
- @group << point
12
- end
13
- @group.finish
14
-
15
- @group2 = RPiet::Group.new('0xff0000', [7, 0])
16
-
17
- [[7, 1], [6, 1], [6, 2], [5, 2], [6, 3], [7, 2],
18
- [7, 3], [8, 0], [8, 1]].each do |point|
19
- @group2 << point
20
- end
21
- @group2.finish
22
-
23
- @pvm = RPiet::Machine.new
6
+ SQUARE = <<-EOS
7
+ .###.
8
+ .###.
9
+ .###.
10
+ EOS
11
+
12
+ WACKY = <<-EOS
13
+ .#.#.
14
+ #####
15
+ .#.#.
16
+ EOS
17
+
18
+ HOOKY = <<-EOS
19
+ .#.#.#
20
+ ######
21
+ .#.#..
22
+ EOS
23
+
24
+
25
+ let(:light_cyan) { RPiet::Color.color_for('0x0000c0') }
26
+ let(:black) { RPiet::Color.color_for('0x000000') }
27
+ let(:blue) { RPiet::Color.color_for('0x0000ff') }
28
+ let(:square_group) { create_group(light_cyan, SQUARE) }
29
+ let(:wacky_group) { create_group(black, WACKY) }
30
+ let(:hooky_group) { create_group(blue, HOOKY) }
31
+
32
+ it "knows its color" do
33
+ expect(square_group.color).to eq light_cyan
34
+ expect(wacky_group.color).to eq black
35
+ expect(hooky_group.color).to eq blue
24
36
  end
25
37
 
26
38
  it "knows its size" do
27
- @group.size.should == 30
39
+ expect(square_group.size).to eq(9)
40
+ expect(wacky_group.size).to eq(9)
41
+ expect(hooky_group.size).to eq(11)
42
+ end
43
+
44
+ it 'picks the right points (wacky)' do
45
+ expect(wacky_group.rr).to eq([4,1])
46
+ expect(wacky_group.rl).to eq([4,1])
47
+ expect(wacky_group.lr).to eq([0,1])
48
+ expect(wacky_group.ll).to eq([0,1])
49
+ expect(wacky_group.dr).to eq([1,2])
50
+ expect(wacky_group.dl).to eq([3,2])
51
+ expect(wacky_group.ur).to eq([3,0])
52
+ expect(wacky_group.ul).to eq([1,0])
53
+ end
54
+
55
+ it 'picks the right points (simple)' do
56
+ expect(square_group.rr).to eq([3,2])
57
+ expect(square_group.rl).to eq([3,0])
58
+ expect(square_group.lr).to eq([1,0])
59
+ expect(square_group.ll).to eq([1,2])
60
+ expect(square_group.dr).to eq([1,2])
61
+ expect(square_group.dl).to eq([3,2])
62
+ expect(square_group.ur).to eq([3,0])
63
+ expect(square_group.ul).to eq([1,0])
64
+ end
65
+
66
+ it 'picks the right points (hooky)' do
67
+ expect(hooky_group.rr).to eq([5,1])
68
+ expect(hooky_group.rl).to eq([5,0])
69
+ expect(hooky_group.lr).to eq([0,1])
70
+ expect(hooky_group.ll).to eq([0,1])
71
+ expect(hooky_group.dr).to eq([1,2])
72
+ expect(hooky_group.dl).to eq([3,2])
73
+ expect(hooky_group.ur).to eq([5,0])
74
+ expect(hooky_group.ul).to eq([1,0])
28
75
  end
29
76
 
30
- it "can pick the right points" do
31
- @group.point_for(@pvm).should == [8, 5] # dp: RIGHT cc: LEFT -> UR
32
- @pvm.cc.switch! # LEFT -> RIGHT
33
- @group.point_for(@pvm).should == [8, 6] # dp: RIGHT cc: RIGHT -> LR
34
- @pvm.dp.rotate! # dp: RIGHT -> DOWN
35
- @pvm.cc.switch! # cc: RIGHT -> LEFT
36
- @group.point_for(@pvm).should == [0, 7] # dp: DOWN cc: LEFT -> LR
37
- @pvm.cc.switch! # cc: LEFT -> RIGHT
38
- @group.point_for(@pvm).should == [0, 7] # dp: DOWN cc: RIGHT -> LL
39
- @pvm.dp.rotate! # dp: DOWN -> LEFT
40
- @pvm.cc.switch! # cc: RIGHT -> LEFT
41
- @group.point_for(@pvm).should == [0, 7] # dp: LEFT cc: LEFT -> LL
42
- @pvm.cc.switch! # cc: LEFT -> RIGHT
43
- @group.point_for(@pvm).should == [0, 3] # dp: LEFT cc: RIGHT -> UL
44
- @pvm.dp.rotate! # dp: LEFT -> UP
45
- @pvm.cc.switch!
46
- @group.point_for(@pvm).should == [0, 3] # dp: UP cc: LEFT -> UL
47
- @pvm.cc.switch! # cc: LEFT -> RIGHT
48
- @group.point_for(@pvm).should == [4, 3] # dp: UP cc: RIGHT -> UR
49
-
50
- # Since last group only has single wide bottom let's try another
51
- @pvm.cc.switch! # cc: RIGHT -> LEFT
52
- @pvm.dp.rotate! 2 # dp: UP -> DOWN
53
- @group2.point_for(@pvm).should == [7, 3] # dp: DOWN cc: LEFT -> LR
54
- @pvm.cc.switch! # cc: RIGHT -> LEFT
55
- @group2.point_for(@pvm).should == [6, 3] # dp: DOWN cc: RIGHT -> LL
77
+ it 'has edges' do
78
+ expect(square_group.edges.to_a).to match_array([[1,0,:left], [1,0,:up], [2,0,:up], [3,0,:up], [3,0,:right],
79
+ [1,1,:left], [3,1,:right],
80
+ [1,2,:left], [1,2,:down], [2,2,:down], [3,2,:down],[3,2,:right]])
56
81
  end
57
82
  end
@@ -1,14 +1,163 @@
1
- require 'rpiet/interpreter'
2
- require 'rpiet/image/ascii_image'
3
-
4
- describe "RPiet::Interpreter" do
5
- it "Can push" do
6
- source = RPiet::Image::AsciiImage.new "nb db ++\nnb ++ ++\n++ ++ ++\n"
7
- interpreter = RPiet::Interpreter.new(source)
8
-
9
- interpreter.next_step
10
- interpreter.pvm.stack.should == [2]
11
- interpreter.next_step
12
- interpreter.pvm.stack.should == []
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/rpiet/asg/graph_interpreter'
3
+ require_relative '../lib/rpiet/interpreter'
4
+
5
+ describe "RPiet Runtimes" do
6
+
7
+ let(:push_pop) do # [push 2, pop]*
8
+ create_image <<-EOS
9
+ nb db ++
10
+ nb ++ ++
11
+ ++ ++ ++
12
+ EOS
13
+ end
14
+
15
+ let(:push_add) do # [push 2, push 1, add, ...]
16
+ create_image <<-EOS
17
+ nb db lb lm ++
18
+ nb ++ ++ lm ++
19
+ ++ ++ ++ ++ ++
20
+ EOS
21
+ end
22
+
23
+ let(:push_subtract) do # [push 2, push 1, subtract, ...]
24
+ create_image <<-EOS
25
+ nb db lb nm ++
26
+ nb ++ ++ nm ++
27
+ ++ ++ ++ ++ ++
28
+ EOS
29
+ end
30
+
31
+ let(:push_multiply) do # [push 2, push 2, multiply, ...]
32
+ create_image <<-EOS
33
+ nb db lb dm ++
34
+ nb db ++ dm ++
35
+ ++ ++ ++ ++ ++
36
+ EOS
37
+ end
38
+
39
+ let(:push_divide) do # [push 2, push 2, divide, ...]
40
+ create_image <<-EOS
41
+ nb db lb lr ++
42
+ nb db ++ lr ++
43
+ ++ ++ ++ ++ ++
44
+ EOS
45
+ end
46
+
47
+ let(:divide_by_zero) do # [push 2, push 1, push 1, subtract, divide]
48
+ create_image <<-EOS
49
+ nb db lb nb dm dy ++
50
+ nb ++ ++ ++ ++ dy ++
51
+ ++ ++ ++ ++ ++ ++ ++
52
+ EOS
53
+ end
54
+
55
+ let(:push_mod) do # [push 2, push 2, mod, ...]
56
+ create_image <<-EOS
57
+ nb db lb nr ++
58
+ nb db ++ nr ++
59
+ ++ ++ ++ ++ ++
60
+ EOS
61
+ end
62
+
63
+ let(:push_not) do # [push 2, push 2, mod, not, ...]
64
+ create_image <<-EOS
65
+ nb db lb nr lg ++
66
+ nb db ++ nr lg ++
67
+ ++ ++ ++ ++ ++ ++
68
+ EOS
69
+ end
70
+
71
+ let(:skip_white) do
72
+ create_image <<-EOS
73
+ nb .. .. db ++
74
+ nb .. .. ++ ++
75
+ ++ .. .. ++ ++
76
+ EOS
77
+ end
78
+
79
+ [RPiet::Interpreter, RPiet::ASG::GraphInterpreter].each do |runtime|
80
+ describe runtime do
81
+ it "Can push and pop" do
82
+ interpreter = runtime.new push_pop
83
+ interpreter.reset
84
+ interpreter.next_step
85
+ expect(interpreter.stack).to eq [2]
86
+ interpreter.next_step
87
+ expect(interpreter.stack).to eq []
88
+ end
89
+
90
+ it "Can push and add" do
91
+ interpreter = runtime.new push_add
92
+ interpreter.reset
93
+ 2.times { interpreter.next_step }
94
+ expect(interpreter.stack).to eq [2, 1]
95
+ interpreter.next_step
96
+ expect(interpreter.stack).to eq [3]
97
+ end
98
+
99
+ it "Can push and subtract" do
100
+ interpreter = runtime.new push_subtract
101
+ interpreter.reset
102
+ 2.times { interpreter.next_step }
103
+ expect(interpreter.stack).to eq [2, 1]
104
+ interpreter.next_step
105
+ expect(interpreter.stack).to eq [1]
106
+ end
107
+
108
+ it "Can push and multiply" do
109
+ interpreter = runtime.new push_multiply
110
+ interpreter.reset
111
+ 2.times { interpreter.next_step }
112
+ expect(interpreter.stack).to eq [2, 2]
113
+ interpreter.next_step
114
+ expect(interpreter.stack).to eq [4]
115
+ end
116
+
117
+ it "Can push and divide" do
118
+ interpreter = runtime.new push_divide
119
+ interpreter.reset
120
+ 2.times { interpreter.next_step }
121
+ expect(interpreter.stack).to eq [2, 2]
122
+ interpreter.next_step
123
+ expect(interpreter.stack).to eq [1]
124
+ end
125
+
126
+ it "Can divide by zero" do
127
+ interpreter = runtime.new divide_by_zero
128
+ interpreter.reset
129
+ 4.times { interpreter.next_step }
130
+ expect(interpreter.stack).to eq [2, 0]
131
+ interpreter.next_step
132
+ expect(interpreter.stack).to eq [99999999]
133
+ end
134
+
135
+ it "Can push and mod" do
136
+ interpreter = runtime.new push_mod
137
+ interpreter.reset
138
+ 2.times { interpreter.next_step }
139
+ expect(interpreter.stack).to eq [2, 2]
140
+ interpreter.next_step
141
+ expect(interpreter.stack).to eq [0]
142
+ end
143
+
144
+ it "Can push and not" do
145
+ interpreter = runtime.new push_not
146
+ interpreter.reset
147
+ 2.times { interpreter.next_step }
148
+ expect(interpreter.stack).to eq [2, 2]
149
+ 2.times { interpreter.next_step }
150
+ expect(interpreter.stack).to eq [1]
151
+ end
152
+
153
+ it "Can skip white and push and pop" do
154
+ interpreter = runtime.new push_pop
155
+ interpreter.reset
156
+ interpreter.next_step
157
+ expect(interpreter.stack).to eq [2]
158
+ interpreter.next_step
159
+ expect(interpreter.stack).to eq []
160
+ end
161
+ end
13
162
  end
14
163
  end
@@ -0,0 +1,122 @@
1
+ require_relative '../spec_helper'
2
+
3
+ include RPiet::IR::Instructions
4
+
5
+ describe "RPiet::IR::Assembler" do
6
+ context "individual instructions" do
7
+ it "can load copy" do
8
+ instr = assemble("v1 = copy 1\n").first
9
+ expect(instr.operation).to eq(:copy)
10
+ expect(instr.operand).to be_numeric_operand(1)
11
+ expect(instr.result).to be_variable_operand("v1")
12
+ end
13
+
14
+ it "can load push" do
15
+ instr = assemble("push 10\n").first
16
+ expect(instr.operation).to eq(:push)
17
+ expect(instr.operand).to be_numeric_operand(10)
18
+ end
19
+
20
+ it "can load pop" do
21
+ instr = assemble("v1 = pop\n").first
22
+ expect(instr.operation).to eq(:pop)
23
+ expect(instr.result).to be_variable_operand("v1")
24
+ end
25
+
26
+ it "can load nout" do
27
+ instr = assemble("nout 12\n").first
28
+ expect(instr.operation).to eq(:nout)
29
+ expect(instr.operand).to be_numeric_operand(12)
30
+ end
31
+
32
+ it "can load cout" do
33
+ instr = assemble("cout 'a'\n").first
34
+ expect(instr.operation).to eq(:cout)
35
+ expect(instr.operand).to be_string_operand("a")
36
+ end
37
+
38
+ it "can load nin" do
39
+ instr = assemble("v1 = nin\n").first
40
+ expect(instr.operation).to eq(:nin)
41
+ expect(instr.result).to be_variable_operand("v1")
42
+ end
43
+
44
+ it "can load roll" do
45
+ instr = assemble("roll 1 10\n").first
46
+ expect(instr.operation).to eq(:roll)
47
+ expect(instr.depth).to be_numeric_operand(1)
48
+ expect(instr.num).to be_numeric_operand(10)
49
+ end
50
+
51
+ it "can load label" do
52
+ instr = assemble("label foo\n").first
53
+ expect(instr.operation).to eq(:label)
54
+ expect(instr.operand).to be_label_operand(:jump_reduction)
55
+ end
56
+
57
+ it "cannot load label with non-label operand" do
58
+ expect { assemble("label 1\n") }.to raise_error(ArgumentError)
59
+ expect { assemble("label 'a'\n") }.to raise_error(ArgumentError)
60
+ expect { assemble("v1 = copy 1\nlabel v1\n") }.to raise_error(ArgumentError)
61
+ end
62
+
63
+ context "can load infix math" do
64
+ %w[+ - * / % **].zip(%i[add sub mult div mod pow]).each do |oper, type|
65
+ it "can load #{oper}" do
66
+ instr = assemble("v1 = copy 2\nv2 = 1 #{oper} v1\n")[1]
67
+ expect(instr.operation).to eq(type)
68
+ expect(instr.operand1).to be_numeric_operand(1)
69
+ expect(instr.operand2).to be_variable_operand("v1")
70
+ expect(instr.result).to be_variable_operand("v2")
71
+ end
72
+
73
+ it "cannot load non-numeric/variable operands" do
74
+ expect { assemble("v1 = 10 #{oper} label\n")}.to raise_error(ArgumentError)
75
+ expect { assemble("v1 = 10 #{oper} 'a'\n")}.to raise_error(ArgumentError)
76
+ end
77
+ end
78
+ end
79
+
80
+ it "can process gt(>)" do
81
+ instr = assemble("v1 = 1 > 2\n").first
82
+ expect(instr.operation).to eq(:gt)
83
+ expect(instr.result).to be_variable_operand("v1")
84
+ expect(instr.operand1).to be_numeric_operand(1)
85
+ expect(instr.operand2).to be_numeric_operand(2)
86
+ end
87
+
88
+ context "can process branches" do
89
+ %w[!= ==].zip(%i[bne beq]).each do |oper, type|
90
+ it "can load #{oper}" do
91
+ instr = assemble("1 #{oper} 2 label\n").first
92
+ expect(instr.operation).to eq(type)
93
+ expect(instr.operand1).to be_numeric_operand(1)
94
+ expect(instr.operand2).to be_numeric_operand(2)
95
+ expect(instr.label).to be_label_operand(:label)
96
+ end
97
+ end
98
+ end
99
+
100
+ it "can load jump" do
101
+ instr = assemble("jump label\n").first
102
+ expect(instr.operation).to eq(:jump)
103
+ expect(instr.label).to be_label_operand(:label)
104
+ end
105
+
106
+ it "can load multiple instructions" do
107
+ instrs = assemble("push 10\nv1 = pop\n")
108
+ expect(instrs.size).to eq(2)
109
+ expect(instrs[0].operation).to eq(:push)
110
+ expect(instrs[1].operation).to eq(:pop)
111
+ end
112
+
113
+ it "is in single-static-assignment form (SSA)" do
114
+ expect { assemble("v1 = pop\nv2 = pop\nv1 = pop\n") }.to raise_error(ArgumentError)
115
+ expect { assemble("push v1\n") }.to raise_error(ArgumentError)
116
+ end
117
+
118
+ it "cannot use a non-variable as a result" do
119
+ expect { assemble("10 = pop\n")}.to raise_error(ArgumentError)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/rpiet/asg/parser'
3
+ require_relative '../../lib/rpiet/ir/builder'
4
+
5
+ describe "RPiet::Builder" do
6
+ let(:cycle) do
7
+ create_image <<-EOS
8
+ nb db nb
9
+ db ++ nb
10
+ db db db
11
+ EOS
12
+ end
13
+
14
+ it "can visit all nodes once plus one extra visit for a cycle" do
15
+ graph = RPiet::ASG::Parser.new(cycle).run
16
+ builder = RPiet::Builder.new
17
+ builder.run graph
18
+ #p builder.instructions
19
+ end
20
+ end
@@ -0,0 +1,151 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/rpiet/asg/parser'
3
+ require_relative '../../lib/rpiet/ir/builder'
4
+ require_relative '../../lib/rpiet/ir/cfg'
5
+
6
+
7
+ describe "RPiet::IR::CFG" do
8
+ let(:push_divide) {
9
+ assemble("push 10\npush 2\nv1 = pop\nv2 = pop\nv3 = v2 / v1; push v3")
10
+ }
11
+
12
+ let(:gtr) {
13
+ assemble <<~EOS
14
+ 10 != 2 true
15
+ push 0
16
+ jump end
17
+ label true
18
+ push 1
19
+ label end
20
+ exit
21
+ EOS
22
+ }
23
+
24
+ let(:pntr) {
25
+ assemble <<~EOS
26
+ dpset 0
27
+ push 2
28
+ v25 = pop
29
+ v26 = dpget
30
+ v27 = v26 + v25
31
+ v28 = v27 % 4
32
+ dpset v28
33
+ v28 != 0 pntr[0]43
34
+ push 0
35
+ jump re.4008
36
+ label pntr[0]43
37
+ v28 != 1 pntr[1]43
38
+ push 1
39
+ jump re.4008
40
+ label pntr[1]43
41
+ v28 != 2 pntr[2]43
42
+ push 2
43
+ jump re.4008
44
+ label pntr[2]43
45
+ v28 != 3 re.4008
46
+ push 3
47
+ label re.4008
48
+ v29 = pop
49
+ exit
50
+ EOS
51
+ }
52
+
53
+ let(:diamond) {
54
+ assemble <<~EOS
55
+ push 10
56
+ push 5
57
+ 10 != 2 true
58
+ push 0
59
+ jump end
60
+ label true
61
+ push 1
62
+ label end
63
+ v1 = pop
64
+ v2 = pop
65
+ v3 = pop
66
+ v4 = v3 / v2
67
+ push v4
68
+ exit
69
+ EOS
70
+ }
71
+
72
+ let(:graph1) {
73
+ assemble <<~EOS
74
+ push 10
75
+ push 5
76
+ 10 != 2 true
77
+ label foo
78
+ push 0
79
+ jump end
80
+ label true
81
+ push 1
82
+ label end
83
+ v1 = pop
84
+ v2 = pop
85
+ v3 = pop
86
+ v4 = v3 / v2
87
+ push v4
88
+ 1 != 2 foo
89
+ push 1
90
+ exit
91
+ EOS
92
+ }
93
+
94
+ context "outgoing_edges" do
95
+ it "can see all edges in a simple graph" do
96
+ cfg = RPiet::IR::CFG.new(gtr)
97
+
98
+ entry_bb = cfg.entry_bb
99
+ fall_through = cfg.outgoing_target(entry_bb, :fall_through)
100
+ expect(fall_through.label).to start_with("fall_thru_")
101
+
102
+ jump = cfg.outgoing_target(entry_bb, :jump)
103
+ expect(jump.label).to eq(:true)
104
+
105
+ end_bb = cfg.outgoing_target(jump, :fall_through)
106
+ expect(end_bb.label).to eq(:end)
107
+
108
+ end_bb2 = cfg.outgoing_target(fall_through, :jump)
109
+ expect(end_bb.label).to eq(:end)
110
+
111
+ expect(end_bb).to eq(end_bb2)
112
+ end
113
+
114
+ it "can remove an edge" do
115
+ cfg = RPiet::IR::CFG.new(gtr)
116
+
117
+ entry_bb = cfg.entry_bb
118
+ jump = cfg.outgoing_target(entry_bb, :jump)
119
+ expect(cfg.outgoing_targets(entry_bb).size).to eq(2)
120
+ cfg.remove_edge(entry_bb, jump)
121
+ expect(cfg.outgoing_targets(entry_bb).size).to eq(1)
122
+ end
123
+
124
+ it "can see see outgoing edges with a block" do
125
+ cfg = RPiet::IR::CFG.new(gtr)
126
+
127
+ entry_bb = cfg.entry_bb
128
+ results = []
129
+ cfg.outgoing_edges(entry_bb) do |edge|
130
+ results << edge.target.label.to_s
131
+ end
132
+ results.sort!
133
+ expect(results[0]).to start_with("fall_thru_")
134
+ expect(results[1]).to eq("true")
135
+ end
136
+
137
+ it "can generate postorder traversal" do
138
+ cfg = RPiet::IR::CFG.new(diamond)
139
+ puts cfg.postorder_bbs.map { |bb| bb.label }.join(", ")
140
+ puts cfg.preorder_bbs.map { |bb| bb.label }.join(", ")
141
+ end
142
+
143
+ it "can generate postorder traversal" do
144
+ cfg = RPiet::IR::CFG.new(graph1)
145
+ cfg.write_to_dot_file
146
+ puts cfg.postorder_bbs.map { |bb| bb.label }.join(", ")
147
+ puts cfg.preorder_bbs.map { |bb| bb.label }.join(", ")
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,102 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe "RPiet::IR::IRInterpreter" do
4
+ it "can exec push" do
5
+ interp = ir_interp(assemble("push 10\n"))
6
+ expect(interp.stack).to eq([])
7
+ interp.next_step
8
+ expect(interp.stack).to eq([10])
9
+ end
10
+
11
+ it "can exec pop" do
12
+ interp = ir_interp(assemble("push 10\nv1 = pop\n"))
13
+ interp.next_step
14
+ expect(interp.stack).to eq([10])
15
+ interp.next_step
16
+ expect(interp.stack).to eq([])
17
+ end
18
+
19
+ it "can exec add" do
20
+ interp = ir_interp(assemble("v1 = 10 + 2\npush v1\n"))
21
+ 2.times { interp.next_step }
22
+ expect(interp.stack).to eq([12])
23
+ end
24
+
25
+ it "can exec add with variable" do
26
+ interp = ir_interp(assemble("v1 = copy 10\nv2 = v1 + 2\npush v2\n"))
27
+ 3.times { interp.next_step }
28
+ expect(interp.stack).to eq([12])
29
+ end
30
+
31
+ it "can exec sub" do
32
+ interp = ir_interp(assemble("v1 = 10 - 2\npush v1\n"))
33
+ 2.times { interp.next_step }
34
+ expect(interp.stack).to eq([8])
35
+ end
36
+
37
+ it "can exec mult" do
38
+ interp = ir_interp(assemble("v1 = 10 * 2\npush v1\n"))
39
+ 2.times { interp.next_step }
40
+ expect(interp.stack).to eq([20])
41
+ end
42
+
43
+ it "can exec div" do
44
+ interp = ir_interp(assemble("v1 = 10 / 2\npush v1\n"))
45
+ 2.times { interp.next_step }
46
+ expect(interp.stack).to eq([5])
47
+ end
48
+
49
+ it "can exec mod" do
50
+ interp = ir_interp(assemble("v1 = 10 % 2\npush v1\n"))
51
+ 2.times { interp.next_step }
52
+ expect(interp.stack).to eq([0])
53
+ end
54
+
55
+ it "can exec pow" do
56
+ interp = ir_interp(assemble("v1 = 10 ** 2\npush v1\n"))
57
+ 2.times { interp.next_step }
58
+ expect(interp.stack).to eq([100])
59
+ end
60
+
61
+ it "can exec jump" do
62
+ interp = ir_interp(assemble("jump label\npush 1\nlabel label\npush 0\n"))
63
+ 2.times { interp.next_step }
64
+ expect(interp.stack).to eq([0])
65
+ end
66
+
67
+ it "can exec bne" do
68
+ interp = ir_interp(assemble("1 != 2 label\npush 1\nlabel label\npush 2\n"))
69
+ 2.times { interp.next_step }
70
+ expect(interp.stack).to eq([2])
71
+ end
72
+
73
+ it "can exec beq" do
74
+ interp = ir_interp(assemble("1 == 1 label\npush 1\nlabel label\npush 2\n"))
75
+ 2.times { interp.next_step }
76
+ expect(interp.stack).to eq([2])
77
+ end
78
+
79
+ it "can exec gt" do
80
+ interp = ir_interp(assemble("v1 = 2 > 1\npush v1\n"))
81
+ 2.times { interp.next_step }
82
+ expect(interp.stack).to eq([1])
83
+ end
84
+
85
+ it "can exec roll" do
86
+ interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 3\npush 1\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
87
+ 9.times { interp.next_step }
88
+ expect(interp.stack).to eq([1, 4, 2, 3]) # <- [1,2,3,4] roll 3, 1
89
+
90
+ interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 3\npush 2\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
91
+ 9.times { interp.next_step }
92
+ expect(interp.stack).to eq([1, 3, 4, 2]) # <- [1,2,3,4] roll 3, 2
93
+
94
+ interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 4\npush -1\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
95
+ 9.times { interp.next_step; p interp.stack }
96
+ expect(interp.stack).to eq([2, 3, 4, 1]) # <- [1,2,3,4] roll 4, -1
97
+
98
+ interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 4\npush -2\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
99
+ 9.times { interp.next_step; p interp.stack }
100
+ expect(interp.stack).to eq([3, 4, 1, 2]) # <- [1,2,3,4] roll 4, -2
101
+ end
102
+ end