furnace 0.4.0.beta.1 → 0.4.0.beta.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.
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