furnace 0.4.0.beta.1 → 0.4.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +6 -0
  3. data/INSTRUMENT.md +250 -0
  4. data/Rakefile +1 -1
  5. data/lib/furnace.rb +10 -6
  6. data/lib/furnace/ast/node.rb +15 -1
  7. data/lib/furnace/awesome_printer.rb +121 -0
  8. data/lib/furnace/context.rb +0 -0
  9. data/lib/furnace/ssa.rb +7 -25
  10. data/lib/furnace/ssa/argument.rb +14 -10
  11. data/lib/furnace/ssa/basic_block.rb +70 -25
  12. data/lib/furnace/ssa/builder.rb +11 -7
  13. data/lib/furnace/ssa/constant.rb +19 -11
  14. data/lib/furnace/ssa/event_stream.rb +145 -0
  15. data/lib/furnace/ssa/function.rb +78 -57
  16. data/lib/furnace/ssa/generic_instruction.rb +12 -5
  17. data/lib/furnace/ssa/instruction.rb +50 -35
  18. data/lib/furnace/ssa/instruction_syntax.rb +9 -25
  19. data/lib/furnace/ssa/instructions/branch.rb +2 -2
  20. data/lib/furnace/ssa/instructions/phi.rb +12 -10
  21. data/lib/furnace/ssa/instructions/return.rb +3 -3
  22. data/lib/furnace/ssa/instructions/return_value.rb +11 -0
  23. data/lib/furnace/ssa/instrumentation.rb +33 -0
  24. data/lib/furnace/ssa/module.rb +5 -1
  25. data/lib/furnace/ssa/named_value.rb +31 -10
  26. data/lib/furnace/ssa/terminator_instruction.rb +6 -6
  27. data/lib/furnace/ssa/types/basic_block.rb +4 -8
  28. data/lib/furnace/ssa/types/function.rb +4 -8
  29. data/lib/furnace/ssa/user.rb +14 -15
  30. data/lib/furnace/ssa/value.rb +9 -5
  31. data/lib/furnace/transform/iterative.rb +20 -4
  32. data/lib/furnace/type.rb +9 -0
  33. data/lib/furnace/type/bottom.rb +11 -0
  34. data/lib/furnace/type/top.rb +72 -0
  35. data/lib/furnace/type/value.rb +13 -0
  36. data/lib/furnace/type/variable.rb +61 -0
  37. data/lib/furnace/version.rb +1 -1
  38. data/test/{test_helper.rb → helper.rb} +28 -3
  39. data/test/{ast_test.rb → test_ast.rb} +13 -1
  40. data/test/test_awesome_printer.rb +148 -0
  41. data/test/{ssa_test.rb → test_ssa.rb} +276 -315
  42. data/test/{transform_test.rb → test_transform.rb} +2 -2
  43. data/test/test_type.rb +138 -0
  44. metadata +83 -105
  45. data/lib/furnace/graphviz.rb +0 -49
  46. data/lib/furnace/ssa/generic_type.rb +0 -16
  47. data/lib/furnace/ssa/pretty_printer.rb +0 -113
  48. data/lib/furnace/ssa/type.rb +0 -27
  49. data/lib/furnace/ssa/types/void.rb +0 -15
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 09c880a785045b6520d037457d92d4c1fb5a5252
4
+ data.tar.gz: 95fe046fd5ae819eca7bc005230e688c7be97647
5
+ SHA512:
6
+ metadata.gz: 432ac773720df277c3c0b8d834f9364176d5245cd84027c1d775a39d05f0107aff5b6bdfbd9fde5df8a2a886ef4db7c9a0a9e9a8f530ad9a3b3152b65317b801
7
+ data.tar.gz: fff823fe2cf09c881a6e827aa160ba8491e25e33d9dc38c4f8053975410290f293020b09d474c3bb9d76875056947e457fe7e886ae72af7b878a95463d336492
@@ -1,4 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.0
4
5
  - jruby-19mode
6
+ - rbx-19mode
7
+
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: rbx-19mode
@@ -0,0 +1,250 @@
1
+ Insturmentation stream format
2
+ =============================
3
+
4
+ Instrumentation data is produced by Foundry as streams of events dumped
5
+ as JSON. A stream corresponds to one function.
6
+
7
+ Within a function, entities have names. Entity names are always unique.
8
+ Entity names may change; in this case, all subsequent references are to be
9
+ resolved via updated name.
10
+
11
+ Entities may refer to types. Types are identified with a number, which is
12
+ always unique and does not change.
13
+
14
+ The root of the stream contains a Function.
15
+
16
+ Type
17
+ ----
18
+
19
+ There are several kinds of Types, disambiguated by the field "kind".
20
+
21
+ ### Void type
22
+
23
+ {
24
+ "event": "type",
25
+ "id": <number>,
26
+ "kind": "void",
27
+ }
28
+
29
+ Should render as:
30
+
31
+ void
32
+
33
+ ### Monotypes
34
+
35
+ {
36
+ "event": "type",
37
+ "id": <number>,
38
+ "kind": "monotype",
39
+ "name": <string>
40
+ }
41
+
42
+ Should render as:
43
+
44
+ #{name}
45
+
46
+ ### Parametric types
47
+
48
+ {
49
+ "event": "type",
50
+ "id": <number>,
51
+ "kind": "parametric",
52
+ "name": <string>,
53
+ "parameters": <array of Type>
54
+ }
55
+
56
+ Should render as:
57
+
58
+ #{name}<#{parameters.map(&:render)}>
59
+
60
+ Function
61
+ --------
62
+
63
+ {
64
+ "name": <string>,
65
+ "present": <Boolean>,
66
+ "events": <array of Event>
67
+ }
68
+
69
+ ### Set arguments
70
+
71
+ {
72
+ "event": "set_arguments",
73
+ "arguments": <array of Argument>
74
+ }
75
+
76
+ ### Set return type
77
+
78
+ {
79
+ "event": "set_return_type",
80
+ "return_type": <Type>
81
+ }
82
+
83
+ Argument
84
+ --------
85
+
86
+ {
87
+ "name": <string>,
88
+ "type": <Type>
89
+ }
90
+
91
+ Should render as:
92
+
93
+ #{type} %#{name}
94
+
95
+ Basic block
96
+ -----------
97
+
98
+ Should render as:
99
+
100
+ #{name}:
101
+ #{instructions.map(&:render)}
102
+
103
+ ### Add basic block
104
+
105
+ {
106
+ "event": "add_basic_block",
107
+ "name": <string>
108
+ }
109
+
110
+ ### Remove basic block
111
+
112
+ {
113
+ "event": "remove_basic_block",
114
+ "name": <string>
115
+ }
116
+
117
+ ### Rename basic block
118
+
119
+ {
120
+ "event": "rename_basic_block",
121
+ "name": <string>,
122
+ "new_name": <string>
123
+ }
124
+
125
+ Operand
126
+ -------
127
+
128
+ ### Constant operand
129
+
130
+ {
131
+ "kind": "constant",
132
+ "type": <Type>,
133
+ "value": <string>
134
+ }
135
+
136
+ Should render as:
137
+
138
+ #{type} #{value}
139
+
140
+ ### Argument operand
141
+
142
+ {
143
+ "kind": "argument",
144
+ "name": <string>
145
+ }
146
+
147
+ Should render as:
148
+
149
+ %#{name}
150
+
151
+ ### Instruction operand
152
+
153
+ {
154
+ "kind": "instruction",
155
+ "name": <string>
156
+ }
157
+
158
+ Should render as:
159
+
160
+ %#{name}
161
+
162
+ ### Basic block operand
163
+
164
+ {
165
+ "kind": "basic_block",
166
+ "name": <string>
167
+ }
168
+
169
+ Should render as:
170
+
171
+ label %#{name}
172
+
173
+ Presence of an operand of this type should create an edge in the graph.
174
+
175
+ ### Function operand
176
+
177
+ {
178
+ "kind": "function",
179
+ "name": <string>
180
+ }
181
+
182
+ Should render as:
183
+
184
+ function "#{name}"
185
+
186
+ Presence of an operand of this type should create a cross-reference link.
187
+
188
+ Instruction
189
+ -----------
190
+
191
+ Should render as:
192
+
193
+ 1. If it has non-void type:
194
+
195
+ #{type} %#{name} = #{opcode} #{parameters} #{operands}
196
+
197
+ 2. If it has void type:
198
+
199
+ #{opcode} #{parameters} #{operands}
200
+
201
+ If `opcode` is `phi`, render `operands` comma-separated with each operand as:
202
+
203
+ #{operand[0]} => #{operand[1]}
204
+
205
+ Else, render `operands` as comma-separated operands.
206
+
207
+ ### Add instruction
208
+
209
+ {
210
+ "event": "add_instruction",
211
+ "name": <string>,
212
+ "basic_block": <string>,
213
+ "position": <number>
214
+ }
215
+
216
+ ### Update instruction
217
+
218
+ {
219
+ "event": "update_instruction",
220
+ "opcode": <string>,
221
+ "name": <string>
222
+ "parameters": <string>
223
+ "operands": <array>
224
+ "type": <Type>
225
+ }
226
+
227
+ ### Remove instruction
228
+
229
+ {
230
+ "event": "remove_instruction",
231
+ "name": <string>
232
+ }
233
+
234
+ ### Rename instruction
235
+
236
+ {
237
+ "event": "rename_instruction",
238
+ "name": <string>,
239
+ "new_name": <string>
240
+ }
241
+
242
+ Miscellanea
243
+ -----------
244
+
245
+ ### Transformation start
246
+
247
+ {
248
+ "event": "transform_start",
249
+ "name": <string>
250
+ }
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ task :default => :test
5
5
 
6
6
  desc "Run test suite"
7
7
  task :test do
8
- sh "bacon test/*_test.rb"
8
+ sh "bacon -a"
9
9
  end
10
10
 
11
11
  PAGES_REPO = 'git@github.com:whitequark/furnace'
@@ -2,22 +2,26 @@
2
2
  # static analyzers--any programs which read, manipulate or transform
3
3
  # other programs.
4
4
  #
5
- # Currently it provides three independent modules, grouped by the main
6
- # data structure being used:
5
+ # Currently it provides four loosely coupled modules, each operating
6
+ # upon a single kind of entity:
7
7
  #
8
8
  # * Abstract syntax trees: {AST}
9
+ # * Parametric types: {Type}
9
10
  # * Static single assignment representation: {SSA}
10
11
  # * Transformations: {Transform}
11
12
  #
12
- # Additionally, a simple {Graphviz} adapter is provided.
13
+ # Additionally, a custom pretty printing module {AwesomePrinter} is
14
+ # provided which has built-in knowledge of {Type}s.
15
+ #
13
16
  module Furnace
14
17
  require "furnace/version"
15
18
 
19
+ require "furnace/awesome_printer"
20
+
16
21
  require "furnace/ast"
22
+ require "furnace/type"
17
23
  require "furnace/ssa"
18
24
 
19
25
  require "furnace/transform/pipeline"
20
26
  require "furnace/transform/iterative"
21
-
22
- require "furnace/graphviz"
23
- end
27
+ end
@@ -123,6 +123,20 @@ module Furnace::AST
123
123
  end
124
124
  end
125
125
 
126
+ # Concatenates `array` with `children` and returns the resulting node.
127
+ #
128
+ # @return [AST::Node]
129
+ def +(array)
130
+ updated(nil, @children + array.to_a)
131
+ end
132
+
133
+ # Appends `element` to `children` and returns the resulting node.
134
+ #
135
+ # @return [AST::Node]
136
+ def <<(element)
137
+ updated(nil, @children + [element])
138
+ end
139
+
126
140
  # Converts `self` to a concise s-expression, omitting any children.
127
141
  #
128
142
  # @return [String]
@@ -198,4 +212,4 @@ module Furnace::AST
198
212
  @type.to_s.gsub('_', '-')
199
213
  end
200
214
  end
201
- end
215
+ end
@@ -0,0 +1,121 @@
1
+ require 'ansi'
2
+
3
+ module Furnace
4
+ class AwesomePrinter
5
+ @colorize = true
6
+
7
+ class << self
8
+ attr_accessor :colorize
9
+ end
10
+
11
+ def initialize(colorize=self.class.colorize,
12
+ annotator=Type::Variable::Annotator.new)
13
+ @colorize = colorize
14
+ @annotator = annotator
15
+
16
+ @buffer = ""
17
+ @need_space = false
18
+
19
+ yield self if block_given?
20
+ end
21
+
22
+ def to_s
23
+ @buffer
24
+ end
25
+
26
+ alias to_str to_s
27
+
28
+ def ==(other)
29
+ to_s == other
30
+ end
31
+
32
+ def =~(other)
33
+ to_s =~ other
34
+ end
35
+
36
+ def append(what)
37
+ @need_space = false
38
+ @buffer << what.to_s
39
+
40
+ self
41
+ end
42
+
43
+ def text(what)
44
+ ensure_space { append what }
45
+ end
46
+
47
+ def newline
48
+ append "\n"
49
+ end
50
+
51
+ def nest(what, &block)
52
+ if what
53
+ if what.respond_to? :awesome_print
54
+ what.awesome_print(self)
55
+ else
56
+ text what.to_s
57
+ end
58
+ end
59
+
60
+ self
61
+ end
62
+
63
+ def name(what)
64
+ text "%#{what}"
65
+ end
66
+
67
+ def type(what)
68
+ text with_ansi(:green) { what }
69
+ end
70
+
71
+ def type_variable(what)
72
+ text with_ansi(:bright, :magenta) { "~#{@annotator.annotate(what)}" }
73
+ end
74
+
75
+ def keyword(what)
76
+ text with_ansi(:bright, :white) { what }
77
+ end
78
+
79
+ def collection(left='', separator='', right='', what, &block)
80
+ return self if what.empty?
81
+
82
+ ensure_space do
83
+ append left
84
+
85
+ what.each.with_index do |element, index|
86
+ if index > 0
87
+ append separator
88
+ end
89
+
90
+ if block_given?
91
+ yield element
92
+ else
93
+ nest element
94
+ end
95
+ end
96
+
97
+ append right
98
+ end
99
+ end
100
+
101
+ protected
102
+
103
+ def with_ansi(*colors)
104
+ if @colorize
105
+ ANSI::Code.ansi(yield.to_s, *colors)
106
+ else
107
+ yield
108
+ end
109
+ end
110
+
111
+ def ensure_space
112
+ append " " if @need_space
113
+
114
+ yield
115
+
116
+ @need_space = true
117
+
118
+ self
119
+ end
120
+ end
121
+ end