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.
- checksums.yaml +7 -0
- data/.travis.yml +6 -0
- data/INSTRUMENT.md +250 -0
- data/Rakefile +1 -1
- data/lib/furnace.rb +10 -6
- data/lib/furnace/ast/node.rb +15 -1
- data/lib/furnace/awesome_printer.rb +121 -0
- data/lib/furnace/context.rb +0 -0
- data/lib/furnace/ssa.rb +7 -25
- data/lib/furnace/ssa/argument.rb +14 -10
- data/lib/furnace/ssa/basic_block.rb +70 -25
- data/lib/furnace/ssa/builder.rb +11 -7
- data/lib/furnace/ssa/constant.rb +19 -11
- data/lib/furnace/ssa/event_stream.rb +145 -0
- data/lib/furnace/ssa/function.rb +78 -57
- data/lib/furnace/ssa/generic_instruction.rb +12 -5
- data/lib/furnace/ssa/instruction.rb +50 -35
- data/lib/furnace/ssa/instruction_syntax.rb +9 -25
- data/lib/furnace/ssa/instructions/branch.rb +2 -2
- data/lib/furnace/ssa/instructions/phi.rb +12 -10
- data/lib/furnace/ssa/instructions/return.rb +3 -3
- data/lib/furnace/ssa/instructions/return_value.rb +11 -0
- data/lib/furnace/ssa/instrumentation.rb +33 -0
- data/lib/furnace/ssa/module.rb +5 -1
- data/lib/furnace/ssa/named_value.rb +31 -10
- data/lib/furnace/ssa/terminator_instruction.rb +6 -6
- data/lib/furnace/ssa/types/basic_block.rb +4 -8
- data/lib/furnace/ssa/types/function.rb +4 -8
- data/lib/furnace/ssa/user.rb +14 -15
- data/lib/furnace/ssa/value.rb +9 -5
- data/lib/furnace/transform/iterative.rb +20 -4
- data/lib/furnace/type.rb +9 -0
- data/lib/furnace/type/bottom.rb +11 -0
- data/lib/furnace/type/top.rb +72 -0
- data/lib/furnace/type/value.rb +13 -0
- data/lib/furnace/type/variable.rb +61 -0
- data/lib/furnace/version.rb +1 -1
- data/test/{test_helper.rb → helper.rb} +28 -3
- data/test/{ast_test.rb → test_ast.rb} +13 -1
- data/test/test_awesome_printer.rb +148 -0
- data/test/{ssa_test.rb → test_ssa.rb} +276 -315
- data/test/{transform_test.rb → test_transform.rb} +2 -2
- data/test/test_type.rb +138 -0
- metadata +83 -105
- data/lib/furnace/graphviz.rb +0 -49
- data/lib/furnace/ssa/generic_type.rb +0 -16
- data/lib/furnace/ssa/pretty_printer.rb +0 -113
- data/lib/furnace/ssa/type.rb +0 -27
- data/lib/furnace/ssa/types/void.rb +0 -15
data/test/test_type.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
describe Type do
|
4
|
+
describe Type::Top do
|
5
|
+
before do
|
6
|
+
@type = Type::Top.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'converts to type' do
|
10
|
+
@type.to_type.should.be.equal @type
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is a singleton' do
|
14
|
+
@type.should.be.equal @type
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should be ==, eql?, subtype_of? and have the same hash as itself' do
|
18
|
+
@type.should == @type
|
19
|
+
@type.should.be.eql @type
|
20
|
+
@type.should.be.subtype_of @type
|
21
|
+
@type.hash.should == @type.hash
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can replace itself' do
|
25
|
+
@type.replace_type_with(@type, Type::Bottom.new).
|
26
|
+
should == Type::Bottom.new
|
27
|
+
@type.replace_type_with(Type::Bottom.new, nil).
|
28
|
+
should == @type
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can specialize only itself' do
|
32
|
+
@type.specialize(@type).should == {}
|
33
|
+
-> { @type.specialize(Type::Bottom.new) }.should.raise(ArgumentError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'pretty prints' do
|
37
|
+
@type.awesome_print.should == 'top'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Type::Bottom do
|
42
|
+
before do
|
43
|
+
@type = Type::Bottom.new
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'converts to string' do
|
47
|
+
@type.to_s.should == 'bottom'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'pretty prints' do
|
51
|
+
@type.awesome_print.should == 'bottom'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe Type::Value do
|
56
|
+
before do
|
57
|
+
@type = Type::Value.new(1)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'allows to retrieve value' do
|
61
|
+
@type.value.should == 1
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'is a singleton' do
|
65
|
+
@type.should.be.equal Type::Value.new(1)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'converts to string as \'value' do
|
69
|
+
@type.to_s.should == %{'1}
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'pretty prints' do
|
73
|
+
@type.awesome_print.should == '\'1'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Type::Variable do
|
78
|
+
before do
|
79
|
+
@var = Type::Variable.new
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'allocates distinct instances' do
|
83
|
+
Type::Variable.new.
|
84
|
+
should.not.equal? Type::Variable.new
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'converts to type' do
|
88
|
+
@var.to_type.should.equal? @var
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'is a subtype of itself' do
|
92
|
+
@var.should.be.subtype_of @var
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'is a supertype of itself' do
|
96
|
+
@var.should.be.supertype_of @var
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'compares by identity' do
|
100
|
+
@var.should == @var
|
101
|
+
@var.should.not == Type::Variable.new
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'can replace itself' do
|
105
|
+
@var.replace_type_with(@var, Type::Bottom.new).
|
106
|
+
should == Type::Bottom.new
|
107
|
+
@var.replace_type_with(Type::Bottom.new, nil).
|
108
|
+
should == @var
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'specializes' do
|
112
|
+
@var.specialize(Type::Top.new).
|
113
|
+
should == { @var => Type::Top.new }
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'pretty prints' do
|
117
|
+
@var.awesome_print.should == '~a'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe Type::Variable::Annotator do
|
122
|
+
before do
|
123
|
+
@annotator = Type::Variable::Annotator.new
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'annotates variables with successive letters' do
|
127
|
+
var1, var2 = 2.times.map { Type::Variable.new }
|
128
|
+
|
129
|
+
@annotator.annotate(var1).should == 'a'
|
130
|
+
@annotator.annotate(var1).should == 'a'
|
131
|
+
@annotator.annotate(var2).should == 'b'
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'only annotates type variables' do
|
135
|
+
-> { @annotator.annotate(:foo) }.should.raise(ArgumentError)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
metadata
CHANGED
@@ -1,149 +1,126 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: furnace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.4.0.beta.1
|
4
|
+
version: 0.4.0.beta.2
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Peter Zotov
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-03-31 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: ansi
|
16
|
-
version_requirements: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: !binary |-
|
21
|
-
MA==
|
22
|
-
none: false
|
23
15
|
requirement: !ruby/object:Gem::Requirement
|
24
16
|
requirements:
|
25
|
-
- -
|
17
|
+
- - '>='
|
26
18
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
28
|
-
MA==
|
29
|
-
none: false
|
30
|
-
prerelease: false
|
19
|
+
version: '0'
|
31
20
|
type: :runtime
|
32
|
-
|
33
|
-
name: rake
|
21
|
+
prerelease: false
|
34
22
|
version_requirements: !ruby/object:Gem::Requirement
|
35
23
|
requirements:
|
36
|
-
- -
|
24
|
+
- - '>='
|
37
25
|
- !ruby/object:Gem::Version
|
38
|
-
version: '
|
39
|
-
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
40
29
|
requirement: !ruby/object:Gem::Requirement
|
41
30
|
requirements:
|
42
|
-
- -
|
31
|
+
- - ~>
|
43
32
|
- !ruby/object:Gem::Version
|
44
33
|
version: '10.0'
|
45
|
-
none: false
|
46
|
-
prerelease: false
|
47
34
|
type: :development
|
48
|
-
|
49
|
-
name: bacon
|
35
|
+
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
|
-
- -
|
38
|
+
- - ~>
|
53
39
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
55
|
-
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bacon
|
56
43
|
requirement: !ruby/object:Gem::Requirement
|
57
44
|
requirements:
|
58
|
-
- -
|
45
|
+
- - ~>
|
59
46
|
- !ruby/object:Gem::Version
|
60
47
|
version: '1.2'
|
61
|
-
none: false
|
62
|
-
prerelease: false
|
63
48
|
type: :development
|
64
|
-
|
65
|
-
name: bacon-colored_output
|
49
|
+
prerelease: false
|
66
50
|
version_requirements: !ruby/object:Gem::Requirement
|
67
51
|
requirements:
|
68
|
-
- -
|
52
|
+
- - ~>
|
69
53
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
71
|
-
|
72
|
-
|
54
|
+
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bacon-colored_output
|
73
57
|
requirement: !ruby/object:Gem::Requirement
|
74
58
|
requirements:
|
75
|
-
- -
|
59
|
+
- - '>='
|
76
60
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
78
|
-
MA==
|
79
|
-
none: false
|
80
|
-
prerelease: false
|
61
|
+
version: '0'
|
81
62
|
type: :development
|
82
|
-
|
83
|
-
name: simplecov
|
63
|
+
prerelease: false
|
84
64
|
version_requirements: !ruby/object:Gem::Requirement
|
85
65
|
requirements:
|
86
|
-
- -
|
66
|
+
- - '>='
|
87
67
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
89
|
-
|
90
|
-
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
91
71
|
requirement: !ruby/object:Gem::Requirement
|
92
72
|
requirements:
|
93
|
-
- -
|
73
|
+
- - '>='
|
94
74
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
96
|
-
MA==
|
97
|
-
none: false
|
98
|
-
prerelease: false
|
75
|
+
version: '0'
|
99
76
|
type: :development
|
100
|
-
|
101
|
-
name: yard
|
77
|
+
prerelease: false
|
102
78
|
version_requirements: !ruby/object:Gem::Requirement
|
103
79
|
requirements:
|
104
|
-
- -
|
80
|
+
- - '>='
|
105
81
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
107
|
-
|
108
|
-
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
109
85
|
requirement: !ruby/object:Gem::Requirement
|
110
86
|
requirements:
|
111
|
-
- -
|
87
|
+
- - '>='
|
112
88
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
114
|
-
MA==
|
115
|
-
none: false
|
116
|
-
prerelease: false
|
89
|
+
version: '0'
|
117
90
|
type: :development
|
118
|
-
|
119
|
-
name: kramdown
|
91
|
+
prerelease: false
|
120
92
|
version_requirements: !ruby/object:Gem::Requirement
|
121
93
|
requirements:
|
122
|
-
- -
|
94
|
+
- - '>='
|
123
95
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
125
|
-
|
126
|
-
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: kramdown
|
127
99
|
requirement: !ruby/object:Gem::Requirement
|
128
100
|
requirements:
|
129
|
-
- -
|
101
|
+
- - '>='
|
130
102
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
132
|
-
MA==
|
133
|
-
none: false
|
134
|
-
prerelease: false
|
103
|
+
version: '0'
|
135
104
|
type: :development
|
136
|
-
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Furnace is a static code analysis framework for dynamic languages, aimed
|
112
|
+
at efficient type and behavior inference.
|
137
113
|
email:
|
138
114
|
- whitequark@whitequark.org
|
139
115
|
executables: []
|
140
116
|
extensions: []
|
141
117
|
extra_rdoc_files: []
|
142
118
|
files:
|
143
|
-
-
|
144
|
-
-
|
145
|
-
-
|
119
|
+
- .gitignore
|
120
|
+
- .travis.yml
|
121
|
+
- .yardopts
|
146
122
|
- Gemfile
|
123
|
+
- INSTRUMENT.md
|
147
124
|
- LICENSE.MIT
|
148
125
|
- Rakefile
|
149
126
|
- furnace.gemspec
|
@@ -152,65 +129,66 @@ files:
|
|
152
129
|
- lib/furnace/ast/node.rb
|
153
130
|
- lib/furnace/ast/processor.rb
|
154
131
|
- lib/furnace/ast/sexp.rb
|
155
|
-
- lib/furnace/
|
132
|
+
- lib/furnace/awesome_printer.rb
|
133
|
+
- lib/furnace/context.rb
|
156
134
|
- lib/furnace/ssa.rb
|
157
135
|
- lib/furnace/ssa/argument.rb
|
158
136
|
- lib/furnace/ssa/basic_block.rb
|
159
137
|
- lib/furnace/ssa/builder.rb
|
160
138
|
- lib/furnace/ssa/constant.rb
|
139
|
+
- lib/furnace/ssa/event_stream.rb
|
161
140
|
- lib/furnace/ssa/function.rb
|
162
141
|
- lib/furnace/ssa/generic_instruction.rb
|
163
|
-
- lib/furnace/ssa/generic_type.rb
|
164
142
|
- lib/furnace/ssa/instruction.rb
|
165
143
|
- lib/furnace/ssa/instruction_syntax.rb
|
166
144
|
- lib/furnace/ssa/instructions/branch.rb
|
167
145
|
- lib/furnace/ssa/instructions/phi.rb
|
168
146
|
- lib/furnace/ssa/instructions/return.rb
|
147
|
+
- lib/furnace/ssa/instructions/return_value.rb
|
148
|
+
- lib/furnace/ssa/instrumentation.rb
|
169
149
|
- lib/furnace/ssa/module.rb
|
170
150
|
- lib/furnace/ssa/named_value.rb
|
171
|
-
- lib/furnace/ssa/pretty_printer.rb
|
172
151
|
- lib/furnace/ssa/terminator_instruction.rb
|
173
|
-
- lib/furnace/ssa/type.rb
|
174
152
|
- lib/furnace/ssa/types/basic_block.rb
|
175
153
|
- lib/furnace/ssa/types/function.rb
|
176
|
-
- lib/furnace/ssa/types/void.rb
|
177
154
|
- lib/furnace/ssa/user.rb
|
178
155
|
- lib/furnace/ssa/value.rb
|
179
156
|
- lib/furnace/transform/iterative.rb
|
180
157
|
- lib/furnace/transform/pipeline.rb
|
158
|
+
- lib/furnace/type.rb
|
159
|
+
- lib/furnace/type/bottom.rb
|
160
|
+
- lib/furnace/type/top.rb
|
161
|
+
- lib/furnace/type/value.rb
|
162
|
+
- lib/furnace/type/variable.rb
|
181
163
|
- lib/furnace/version.rb
|
182
|
-
- test/
|
183
|
-
- test/
|
184
|
-
- test/
|
185
|
-
- test/
|
164
|
+
- test/helper.rb
|
165
|
+
- test/test_ast.rb
|
166
|
+
- test/test_awesome_printer.rb
|
167
|
+
- test/test_ssa.rb
|
168
|
+
- test/test_transform.rb
|
169
|
+
- test/test_type.rb
|
186
170
|
homepage: http://github.com/whitequark/furnace
|
187
171
|
licenses: []
|
188
|
-
|
172
|
+
metadata: {}
|
173
|
+
post_install_message:
|
189
174
|
rdoc_options: []
|
190
175
|
require_paths:
|
191
176
|
- lib
|
192
177
|
required_ruby_version: !ruby/object:Gem::Requirement
|
193
178
|
requirements:
|
194
|
-
- -
|
179
|
+
- - '>='
|
195
180
|
- !ruby/object:Gem::Version
|
196
|
-
|
197
|
-
- 0
|
198
|
-
hash: 2
|
199
|
-
version: !binary |-
|
200
|
-
MA==
|
201
|
-
none: false
|
181
|
+
version: '0'
|
202
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
183
|
requirements:
|
204
|
-
- -
|
205
|
-
Pg==
|
184
|
+
- - '>'
|
206
185
|
- !ruby/object:Gem::Version
|
207
186
|
version: 1.3.1
|
208
|
-
none: false
|
209
187
|
requirements: []
|
210
|
-
rubyforge_project:
|
211
|
-
rubygems_version:
|
212
|
-
signing_key:
|
213
|
-
specification_version:
|
188
|
+
rubyforge_project:
|
189
|
+
rubygems_version: 2.0.0
|
190
|
+
signing_key:
|
191
|
+
specification_version: 4
|
214
192
|
summary: A static code analysis framework
|
215
193
|
test_files: []
|
216
|
-
has_rdoc:
|
194
|
+
has_rdoc:
|
data/lib/furnace/graphviz.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'furnace'
|
2
|
-
|
3
|
-
class Furnace::Graphviz
|
4
|
-
def initialize
|
5
|
-
@code = "digraph {\n"
|
6
|
-
@code << "node [labeljust=l,nojustify=true,fontname=monospace];"
|
7
|
-
@code << "rankdir=TB;\n"
|
8
|
-
|
9
|
-
yield self
|
10
|
-
|
11
|
-
@code << "}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def node(name, content, options={})
|
15
|
-
content.gsub!("&", "&")
|
16
|
-
content.gsub!(">", ">")
|
17
|
-
content.gsub!("<", "<")
|
18
|
-
content.gsub!(/\*\*(.+?)\*\*/, '<b>\1</b>')
|
19
|
-
content = content.lines.map { |l| %Q{<tr><td align="left">#{l}</td></tr>} }.join
|
20
|
-
|
21
|
-
if content.empty?
|
22
|
-
label = "<<empty>>"
|
23
|
-
else
|
24
|
-
label = "<<table border=\"0\">#{content}</table>>"
|
25
|
-
end
|
26
|
-
|
27
|
-
options = options.merge({
|
28
|
-
shape: 'box',
|
29
|
-
label: label
|
30
|
-
})
|
31
|
-
|
32
|
-
@code << %Q{"#{name.inspect}" #{graphviz_options(options)};\n}
|
33
|
-
end
|
34
|
-
|
35
|
-
def edge(from, to, label="", options={})
|
36
|
-
options = options.merge({
|
37
|
-
label: label.inspect
|
38
|
-
})
|
39
|
-
@code << %Q{"#{from.inspect}" -> "#{to.inspect}" #{graphviz_options(options)};\n}
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_s
|
43
|
-
@code
|
44
|
-
end
|
45
|
-
|
46
|
-
def graphviz_options(options)
|
47
|
-
"[#{options.map { |k,v| "#{k}=#{v}" }.join(",")}]"
|
48
|
-
end
|
49
|
-
end
|