furnace 0.2.6 → 0.3.1
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.
- data/.gitignore +3 -2
- data/.yardopts +1 -0
- data/Gemfile +1 -0
- data/Rakefile +23 -1
- data/furnace.gemspec +5 -0
- data/lib/furnace/ast/node.rb +148 -61
- data/lib/furnace/ast/processor.rb +265 -0
- data/lib/furnace/ast/sexp.rb +30 -0
- data/lib/furnace/ast.rb +18 -8
- data/lib/furnace/cfg/algorithms.rb +193 -0
- data/lib/furnace/cfg/graph.rb +5 -185
- data/lib/furnace/cfg.rb +5 -4
- data/lib/furnace/version.rb +1 -1
- data/lib/furnace.rb +19 -9
- data/test/ast_test.rb +185 -0
- data/test/test_helper.rb +36 -0
- metadata +80 -16
- data/lib/furnace/ast/matcher/dsl.rb +0 -50
- data/lib/furnace/ast/matcher/special.rb +0 -20
- data/lib/furnace/ast/matcher.rb +0 -198
- data/lib/furnace/ast/strict_visitor.rb +0 -20
- data/lib/furnace/ast/visitor.rb +0 -50
- data/lib/furnace/code/newline_token.rb +0 -9
- data/lib/furnace/code/nonterminal_token.rb +0 -16
- data/lib/furnace/code/separated_token.rb +0 -17
- data/lib/furnace/code/surrounded_token.rb +0 -21
- data/lib/furnace/code/terminal_token.rb +0 -9
- data/lib/furnace/code/token.rb +0 -73
- data/lib/furnace/code.rb +0 -10
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: furnace
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,8 +9,72 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-
|
|
13
|
-
dependencies:
|
|
12
|
+
date: 2012-12-02 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rake
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: bacon
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ~>
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '1.1'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ~>
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '1.1'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: yard
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: redcarpet
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
type: :development
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
14
78
|
description: Furnace is a static code analysis framework for dynamic languages, aimed
|
|
15
79
|
at efficient type and behavior inference.
|
|
16
80
|
email:
|
|
@@ -20,32 +84,26 @@ extensions: []
|
|
|
20
84
|
extra_rdoc_files: []
|
|
21
85
|
files:
|
|
22
86
|
- .gitignore
|
|
87
|
+
- .yardopts
|
|
23
88
|
- Gemfile
|
|
24
89
|
- LICENSE
|
|
25
90
|
- Rakefile
|
|
26
91
|
- furnace.gemspec
|
|
27
92
|
- lib/furnace.rb
|
|
28
93
|
- lib/furnace/ast.rb
|
|
29
|
-
- lib/furnace/ast/matcher.rb
|
|
30
|
-
- lib/furnace/ast/matcher/dsl.rb
|
|
31
|
-
- lib/furnace/ast/matcher/special.rb
|
|
32
94
|
- lib/furnace/ast/node.rb
|
|
33
|
-
- lib/furnace/ast/
|
|
34
|
-
- lib/furnace/ast/
|
|
95
|
+
- lib/furnace/ast/processor.rb
|
|
96
|
+
- lib/furnace/ast/sexp.rb
|
|
35
97
|
- lib/furnace/cfg.rb
|
|
98
|
+
- lib/furnace/cfg/algorithms.rb
|
|
36
99
|
- lib/furnace/cfg/graph.rb
|
|
37
100
|
- lib/furnace/cfg/node.rb
|
|
38
|
-
- lib/furnace/code.rb
|
|
39
|
-
- lib/furnace/code/newline_token.rb
|
|
40
|
-
- lib/furnace/code/nonterminal_token.rb
|
|
41
|
-
- lib/furnace/code/separated_token.rb
|
|
42
|
-
- lib/furnace/code/surrounded_token.rb
|
|
43
|
-
- lib/furnace/code/terminal_token.rb
|
|
44
|
-
- lib/furnace/code/token.rb
|
|
45
101
|
- lib/furnace/graphviz.rb
|
|
46
102
|
- lib/furnace/transform/iterative_process.rb
|
|
47
103
|
- lib/furnace/transform/pipeline.rb
|
|
48
104
|
- lib/furnace/version.rb
|
|
105
|
+
- test/ast_test.rb
|
|
106
|
+
- test/test_helper.rb
|
|
49
107
|
homepage: http://github.com/whitequark/furnace
|
|
50
108
|
licenses: []
|
|
51
109
|
post_install_message:
|
|
@@ -58,15 +116,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
58
116
|
- - ! '>='
|
|
59
117
|
- !ruby/object:Gem::Version
|
|
60
118
|
version: '0'
|
|
119
|
+
segments:
|
|
120
|
+
- 0
|
|
121
|
+
hash: -2809790994543949274
|
|
61
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
123
|
none: false
|
|
63
124
|
requirements:
|
|
64
125
|
- - ! '>='
|
|
65
126
|
- !ruby/object:Gem::Version
|
|
66
127
|
version: '0'
|
|
128
|
+
segments:
|
|
129
|
+
- 0
|
|
130
|
+
hash: -2809790994543949274
|
|
67
131
|
requirements: []
|
|
68
132
|
rubyforge_project:
|
|
69
|
-
rubygems_version: 1.8.
|
|
133
|
+
rubygems_version: 1.8.23
|
|
70
134
|
signing_key:
|
|
71
135
|
specification_version: 3
|
|
72
136
|
summary: A static code analysis framework
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
module Furnace::AST
|
|
2
|
-
class MatcherDSL
|
|
3
|
-
SpecialAny = MatcherSpecial.new(:any)
|
|
4
|
-
SpecialSkip = MatcherSpecial.new(:skip)
|
|
5
|
-
SpecialEach = MatcherSpecial.define(:each)
|
|
6
|
-
SpecialEither = MatcherSpecial.define(:either)
|
|
7
|
-
SpecialEitherMulti = MatcherSpecial.define(:either_multi)
|
|
8
|
-
SpecialMaybe = MatcherSpecial.define(:maybe)
|
|
9
|
-
|
|
10
|
-
def any
|
|
11
|
-
SpecialAny
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def skip
|
|
15
|
-
SpecialSkip
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def each
|
|
19
|
-
SpecialEach
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def either
|
|
23
|
-
SpecialEither
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def either_multi
|
|
27
|
-
SpecialEitherMulti
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def maybe
|
|
31
|
-
SpecialMaybe
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def map(name)
|
|
35
|
-
->(hash) { MatcherSpecial.new(:map, [name, hash]) }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def capture(name)
|
|
39
|
-
MatcherSpecial.new(:capture, name)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def capture_rest(name)
|
|
43
|
-
MatcherSpecial.new(:capture_rest, name)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def backref(name)
|
|
47
|
-
MatcherSpecial.new(:backref, name)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module Furnace::AST
|
|
2
|
-
class MatcherSpecial
|
|
3
|
-
attr_reader :type, :param
|
|
4
|
-
|
|
5
|
-
def initialize(type, param=nil)
|
|
6
|
-
@type, @param = type, param
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
class << self
|
|
10
|
-
def define(type)
|
|
11
|
-
lambda { |*args| new(type, args) }
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def kind(type)
|
|
15
|
-
@kind_lambdas ||= {}
|
|
16
|
-
@kind_lambdas[type] ||= lambda { |m| m.is_a?(MatcherSpecial) && m.type == type }
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
data/lib/furnace/ast/matcher.rb
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
module Furnace::AST
|
|
2
|
-
class MatcherError < StandardError; end
|
|
3
|
-
|
|
4
|
-
class Matcher
|
|
5
|
-
def initialize(&block)
|
|
6
|
-
@pattern = MatcherDSL.new.instance_exec(&block)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def match(object, captures={})
|
|
10
|
-
if genmatch(object.to_astlet, @pattern, captures)
|
|
11
|
-
captures
|
|
12
|
-
else
|
|
13
|
-
nil
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def find_one(collection, initial_captures={})
|
|
18
|
-
collection.find do |elem|
|
|
19
|
-
result = match elem, initial_captures.dup
|
|
20
|
-
|
|
21
|
-
if block_given? && result
|
|
22
|
-
yield elem, result
|
|
23
|
-
else
|
|
24
|
-
result
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def find_one!(collection, initial_captures={})
|
|
30
|
-
found = nil
|
|
31
|
-
|
|
32
|
-
collection.each do |elem|
|
|
33
|
-
result = match elem, initial_captures.dup
|
|
34
|
-
|
|
35
|
-
if result
|
|
36
|
-
raise MatcherError, "already matched" if found
|
|
37
|
-
|
|
38
|
-
found = elem
|
|
39
|
-
yield elem, result if block_given?
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
raise MatcherError, "no match found" unless found
|
|
44
|
-
|
|
45
|
-
found
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def find_all(collection, initial_captures={})
|
|
49
|
-
collection.select do |elem|
|
|
50
|
-
result = match elem, initial_captures.dup
|
|
51
|
-
yield elem, result if block_given? && result
|
|
52
|
-
result
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
protected
|
|
57
|
-
|
|
58
|
-
def submatch(array, pattern, captures)
|
|
59
|
-
matches = true
|
|
60
|
-
nested_captures = captures.dup
|
|
61
|
-
index = 0
|
|
62
|
-
|
|
63
|
-
pattern.each_with_index do |nested_pattern|
|
|
64
|
-
return nil if index > array.length
|
|
65
|
-
|
|
66
|
-
case nested_pattern
|
|
67
|
-
when Array
|
|
68
|
-
matches &&= genmatch(array[index], nested_pattern, nested_captures)
|
|
69
|
-
index += 1
|
|
70
|
-
when MatcherDSL::SpecialAny
|
|
71
|
-
# it matches
|
|
72
|
-
index += 1
|
|
73
|
-
when MatcherDSL::SpecialSkip
|
|
74
|
-
# it matches all remaining elements
|
|
75
|
-
index = array.length
|
|
76
|
-
when MatcherSpecial.kind(:capture)
|
|
77
|
-
# it matches and captures
|
|
78
|
-
nested_captures[nested_pattern.param] = array[index]
|
|
79
|
-
index += 1
|
|
80
|
-
when MatcherSpecial.kind(:capture_rest)
|
|
81
|
-
# it matches and captures all remaining
|
|
82
|
-
nested_captures[nested_pattern.param] = array[index..-1]
|
|
83
|
-
index = array.length
|
|
84
|
-
when MatcherSpecial.kind(:backref)
|
|
85
|
-
matches &&= (nested_captures[nested_pattern.param] == array[index])
|
|
86
|
-
index += 1
|
|
87
|
-
when MatcherSpecial.kind(:maybe)
|
|
88
|
-
if advance = submatch(array[index..-1], nested_pattern.param, nested_captures)
|
|
89
|
-
index += advance
|
|
90
|
-
end
|
|
91
|
-
when MatcherSpecial.kind(:each)
|
|
92
|
-
all_submatches = true
|
|
93
|
-
|
|
94
|
-
workset = Set.new array[index..-1]
|
|
95
|
-
|
|
96
|
-
nested_pattern.param.each do |subset_pattern|
|
|
97
|
-
sub_matches = false
|
|
98
|
-
|
|
99
|
-
workset.each do |subset_elem|
|
|
100
|
-
sub_matches ||= genmatch(subset_elem, subset_pattern, nested_captures)
|
|
101
|
-
|
|
102
|
-
if sub_matches
|
|
103
|
-
workset.delete subset_elem
|
|
104
|
-
break
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
all_submatches &&= sub_matches
|
|
109
|
-
break unless all_submatches
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
index += 1
|
|
113
|
-
matches &&= all_submatches
|
|
114
|
-
when MatcherSpecial.kind(:either)
|
|
115
|
-
sub_found = false
|
|
116
|
-
|
|
117
|
-
nested_pattern.param.each do |subset_pattern|
|
|
118
|
-
if genmatch(array[index], subset_pattern, nested_captures)
|
|
119
|
-
sub_found = true
|
|
120
|
-
index += 1
|
|
121
|
-
break
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
matches &&= sub_found
|
|
126
|
-
when MatcherSpecial.kind(:either_multi)
|
|
127
|
-
sub_found = false
|
|
128
|
-
|
|
129
|
-
nested_pattern.param.each do |subset_pattern|
|
|
130
|
-
if matched = genmatch(array[index..-1], subset_pattern, nested_captures)
|
|
131
|
-
sub_found = true
|
|
132
|
-
index += matched
|
|
133
|
-
break
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
matches &&= sub_found
|
|
138
|
-
when MatcherSpecial.kind(:map)
|
|
139
|
-
captures_key, patterns = nested_pattern.param
|
|
140
|
-
nested_captures[captures_key] = []
|
|
141
|
-
|
|
142
|
-
while index < array.length
|
|
143
|
-
sub_found = false
|
|
144
|
-
|
|
145
|
-
patterns.each do |subset_key, subset_pattern|
|
|
146
|
-
subset_captures = captures.dup
|
|
147
|
-
|
|
148
|
-
if matched = submatch(array[index..-1], subset_pattern, subset_captures)
|
|
149
|
-
if subset_key
|
|
150
|
-
nested_captures[captures_key].push [subset_key, subset_captures]
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
sub_found = true
|
|
154
|
-
index += matched
|
|
155
|
-
|
|
156
|
-
break
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
matches &&= sub_found
|
|
161
|
-
break unless matches
|
|
162
|
-
end
|
|
163
|
-
else
|
|
164
|
-
matches &&= (nested_pattern === array[index])
|
|
165
|
-
index += 1
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
break unless matches
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
captures.replace(nested_captures) if matches
|
|
172
|
-
|
|
173
|
-
index if matches
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def genmatch(astlet, pattern, captures)
|
|
177
|
-
if $DEBUG
|
|
178
|
-
if astlet.respond_to? :to_sexp
|
|
179
|
-
puts "match #{astlet.to_sexp} of #{pattern}"
|
|
180
|
-
else
|
|
181
|
-
puts "match #{astlet} of #{pattern}"
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
if pattern === astlet
|
|
186
|
-
true
|
|
187
|
-
elsif pattern.is_a? MatcherSpecial
|
|
188
|
-
submatch([astlet], [pattern], captures)
|
|
189
|
-
elsif astlet.is_a? Node
|
|
190
|
-
submatch([astlet.type].concat(astlet.children), pattern, captures)
|
|
191
|
-
elsif astlet.is_a? Array
|
|
192
|
-
submatch(astlet, pattern, captures)
|
|
193
|
-
else
|
|
194
|
-
false
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module Furnace::AST
|
|
2
|
-
module StrictVisitor
|
|
3
|
-
def visit(node)
|
|
4
|
-
# Invoke a specific handler
|
|
5
|
-
on_handler = :"on_#{node.type}"
|
|
6
|
-
if respond_to? on_handler
|
|
7
|
-
new_node = send on_handler, node
|
|
8
|
-
node = new_node if new_node
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
node
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def visit_all(nodes)
|
|
15
|
-
nodes.map do |node|
|
|
16
|
-
visit node
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
data/lib/furnace/ast/visitor.rb
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
module Furnace::AST
|
|
2
|
-
module Visitor
|
|
3
|
-
def visit(node)
|
|
4
|
-
replacements = {}
|
|
5
|
-
|
|
6
|
-
node.children.each_with_index do |child, index|
|
|
7
|
-
if child.is_a? Node
|
|
8
|
-
visit child
|
|
9
|
-
|
|
10
|
-
if child.type == :expand
|
|
11
|
-
replacements[index] = child.children
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
if replacements.any?
|
|
17
|
-
new_children = []
|
|
18
|
-
|
|
19
|
-
node.children.each_with_index do |child, index|
|
|
20
|
-
if replacements[index]
|
|
21
|
-
new_children.concat replacements[index]
|
|
22
|
-
else
|
|
23
|
-
new_children.push child
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
node.children.replace new_children
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
node.children.delete_if do |child|
|
|
31
|
-
if child.is_a? Node
|
|
32
|
-
child.type == :remove
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Invoke a specific handler
|
|
37
|
-
on_handler = :"on_#{node.type}"
|
|
38
|
-
if respond_to? on_handler
|
|
39
|
-
send on_handler, node
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Invoke a generic handler
|
|
43
|
-
if respond_to? :on_any
|
|
44
|
-
send :on_any, node
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
node
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Furnace
|
|
2
|
-
module Code
|
|
3
|
-
class NonterminalToken < Token
|
|
4
|
-
attr_reader :children
|
|
5
|
-
|
|
6
|
-
def initialize(origin, children, options={})
|
|
7
|
-
super(origin, options)
|
|
8
|
-
@children = children.compact
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def to_text
|
|
12
|
-
children.map(&:to_text).join
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Furnace
|
|
2
|
-
module Code
|
|
3
|
-
class SeparatedToken < SurroundedToken
|
|
4
|
-
def text_between
|
|
5
|
-
""
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def to_text
|
|
9
|
-
"#{text_before}#{children.map(&:to_text).join(text_between)}#{text_after}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def to_structure(options={})
|
|
13
|
-
structurize "#{text_before} #{([text_between] * 3).join(" ")} #{text_after}", options
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module Furnace
|
|
2
|
-
module Code
|
|
3
|
-
class SurroundedToken < NonterminalToken
|
|
4
|
-
def text_before
|
|
5
|
-
""
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def text_after
|
|
9
|
-
""
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def to_text
|
|
13
|
-
"#{text_before}#{children.map(&:to_text).join}#{text_after}"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def to_structure(options={})
|
|
17
|
-
structurize "#{text_before} ... #{text_after}", options
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
data/lib/furnace/code/token.rb
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
module Furnace
|
|
2
|
-
module Code
|
|
3
|
-
class Token
|
|
4
|
-
attr_reader :origin
|
|
5
|
-
|
|
6
|
-
def initialize(origin, options={})
|
|
7
|
-
@origin, @options = origin, options
|
|
8
|
-
@waiters = []
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.type
|
|
12
|
-
@type ||= name.sub(/^.*::/, '').sub(/Token$/, '').to_sym
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def type
|
|
16
|
-
self.class.type
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def subscribe(proc)
|
|
20
|
-
@waiters << proc
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def unsubscribe(proc)
|
|
24
|
-
@waiters.delete proc
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def to_text
|
|
28
|
-
raise "Reimplement Token#to_text in a subclass"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def to_structure(options={})
|
|
32
|
-
structurize nil, options
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
protected
|
|
36
|
-
|
|
37
|
-
def indent(code, options=@options)
|
|
38
|
-
unless code.empty?
|
|
39
|
-
code.to_s.gsub(/^/, (options[:indent_with] || ' ') * (options[:level] || 1))
|
|
40
|
-
else
|
|
41
|
-
""
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def structurize(comment, options)
|
|
46
|
-
options = { level: 0 }.merge(options)
|
|
47
|
-
|
|
48
|
-
structure = indent(type, options)
|
|
49
|
-
|
|
50
|
-
if comment
|
|
51
|
-
structure = structure.ljust(options[:describe_at] || 50)
|
|
52
|
-
|
|
53
|
-
if comment =~ /^\s+$/
|
|
54
|
-
structure += " <whitespace>"
|
|
55
|
-
else
|
|
56
|
-
structure += " ; #{comment.gsub(%r{\/\*.*?\*\/}, '').
|
|
57
|
-
gsub(/[ \t]+/, ' ').gsub("\n", '')}"
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
structure += "\n"
|
|
62
|
-
|
|
63
|
-
if @children
|
|
64
|
-
structure += @children.map do |child|
|
|
65
|
-
child.to_structure(options.merge(:level => options[:level] + 1))
|
|
66
|
-
end.join
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
structure
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
data/lib/furnace/code.rb
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
require "set"
|
|
2
|
-
|
|
3
|
-
require "furnace"
|
|
4
|
-
|
|
5
|
-
require "furnace/code/token"
|
|
6
|
-
require "furnace/code/terminal_token"
|
|
7
|
-
require "furnace/code/nonterminal_token"
|
|
8
|
-
require "furnace/code/surrounded_token"
|
|
9
|
-
require "furnace/code/separated_token"
|
|
10
|
-
require "furnace/code/newline_token"
|