furnace 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
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
@@ -3,7 +3,7 @@ module Furnace::AST
3
3
 
4
4
  class Matcher
5
5
  def initialize(&block)
6
- @pattern = self.class.class_exec(&block)
6
+ @pattern = MatcherDSL.new.instance_exec(&block)
7
7
  end
8
8
 
9
9
  def match(object, captures={})
@@ -53,55 +53,42 @@ module Furnace::AST
53
53
  end
54
54
  end
55
55
 
56
- SpecialAny = MatcherSpecial.new(:any)
57
- SpecialSkip = MatcherSpecial.new(:skip)
58
- SpecialSubset = MatcherSpecial.define(:subset)
59
-
60
- class << self
61
- def any
62
- SpecialAny
63
- end
64
-
65
- def skip
66
- SpecialSkip
67
- end
68
-
69
- def subset
70
- SpecialSubset
71
- end
72
-
73
- def capture(name)
74
- MatcherSpecial.new(:capture, name)
75
- end
76
-
77
- def backref(name)
78
- MatcherSpecial.new(:backref, name)
79
- end
80
- end
81
-
82
56
  protected
83
57
 
84
58
  def submatch(array, pattern, captures)
85
59
  matches = true
86
60
  nested_captures = captures.dup
61
+ index = 0
87
62
 
88
- pattern.each_with_index do |nested_pattern, index|
89
- return false if index > array.length
63
+ pattern.each_with_index do |nested_pattern|
64
+ return nil if index > array.length
90
65
 
91
66
  case nested_pattern
92
67
  when Array
93
68
  matches &&= genmatch(array[index], nested_pattern, nested_captures)
94
- when SpecialAny
69
+ index += 1
70
+ when MatcherDSL::SpecialAny
95
71
  # it matches
96
- when SpecialSkip
72
+ index += 1
73
+ when MatcherDSL::SpecialSkip
97
74
  # it matches all remaining elements
98
- break
75
+ index = array.length
99
76
  when MatcherSpecial.kind(:capture)
100
77
  # it matches and captures
101
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
102
84
  when MatcherSpecial.kind(:backref)
103
85
  matches &&= (nested_captures[nested_pattern.param] == array[index])
104
- when MatcherSpecial.kind(:subset)
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)
105
92
  all_submatches = true
106
93
 
107
94
  workset = Set.new array[index..-1]
@@ -122,9 +109,60 @@ module Furnace::AST
122
109
  break unless all_submatches
123
110
  end
124
111
 
112
+ index += 1
125
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
126
163
  else
127
- matches &&= (array[index] == nested_pattern)
164
+ matches &&= (nested_pattern === array[index])
165
+ index += 1
128
166
  end
129
167
 
130
168
  break unless matches
@@ -132,7 +170,7 @@ module Furnace::AST
132
170
 
133
171
  captures.replace(nested_captures) if matches
134
172
 
135
- matches
173
+ index if matches
136
174
  end
137
175
 
138
176
  def genmatch(astlet, pattern, captures)
@@ -144,26 +182,14 @@ module Furnace::AST
144
182
  end
145
183
  end
146
184
 
147
- if pattern.first.is_a?(Symbol)
148
- # Match an astlet
149
- type, *rest = pattern
150
-
151
- if astlet.is_a? Node
152
- if astlet.type == type
153
- submatch(astlet.children, rest, captures)
154
- else
155
- false
156
- end
157
- else
158
- false
159
- end
185
+ if pattern === astlet
186
+ true
187
+ elsif astlet.is_a? Node
188
+ submatch([astlet.type].concat(astlet.children), pattern, captures)
189
+ elsif astlet.is_a? Array
190
+ submatch(astlet, pattern, captures)
160
191
  else
161
- # Match an array
162
- if astlet.is_a? Array
163
- submatch(astlet, pattern, captures)
164
- else
165
- false
166
- end
192
+ false
167
193
  end
168
194
  end
169
195
  end
data/lib/furnace/ast.rb CHANGED
@@ -4,5 +4,6 @@ require "furnace/ast/node"
4
4
  require "furnace/ast/symbolic_node"
5
5
  require "furnace/ast/visitor"
6
6
 
7
- require "furnace/ast/matcher_special"
7
+ require "furnace/ast/matcher/special"
8
+ require "furnace/ast/matcher/dsl"
8
9
  require "furnace/ast/matcher"
@@ -1,3 +1,3 @@
1
1
  module Furnace
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  end
metadata CHANGED
@@ -1,33 +1,25 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: furnace
3
- version: !ruby/object:Gem::Version
4
- hash: 246344429
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 4
10
- version: 0.0.4
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Peter Zotov
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-01-28 00:00:00 Z
12
+ date: 2012-02-17 00:00:00.000000000 Z
19
13
  dependencies: []
20
-
21
- description: Furnace is a static code analysis framework for dynamic languages, aimed at efficient type and behavior inference.
22
- email:
14
+ description: Furnace is a static code analysis framework for dynamic languages, aimed
15
+ at efficient type and behavior inference.
16
+ email:
23
17
  - whitequark@whitequark.org
24
- executables:
18
+ executables:
25
19
  - furnace
26
20
  extensions: []
27
-
28
21
  extra_rdoc_files: []
29
-
30
- files:
22
+ files:
31
23
  - .gitignore
32
24
  - .rvmrc
33
25
  - Gemfile
@@ -44,7 +36,8 @@ files:
44
36
  - lib/furnace/anf/return_node.rb
45
37
  - lib/furnace/ast.rb
46
38
  - lib/furnace/ast/matcher.rb
47
- - lib/furnace/ast/matcher_special.rb
39
+ - lib/furnace/ast/matcher/dsl.rb
40
+ - lib/furnace/ast/matcher/special.rb
48
41
  - lib/furnace/ast/node.rb
49
42
  - lib/furnace/ast/symbolic_node.rb
50
43
  - lib/furnace/ast/visitor.rb
@@ -66,36 +59,27 @@ files:
66
59
  - lib/furnace/version.rb
67
60
  homepage: http://github.com/whitequark/furnace
68
61
  licenses: []
69
-
70
62
  post_install_message:
71
63
  rdoc_options: []
72
-
73
- require_paths:
64
+ require_paths:
74
65
  - lib
75
- required_ruby_version: !ruby/object:Gem::Requirement
66
+ required_ruby_version: !ruby/object:Gem::Requirement
76
67
  none: false
77
- requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- hash: 881230260
81
- segments:
82
- - 0
83
- version: "0"
84
- required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
73
  none: false
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- hash: 881230260
90
- segments:
91
- - 0
92
- version: "0"
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
93
78
  requirements: []
94
-
95
79
  rubyforge_project:
96
- rubygems_version: 1.8.12
80
+ rubygems_version: 1.8.10
97
81
  signing_key:
98
82
  specification_version: 3
99
83
  summary: A static code analysis framework
100
84
  test_files: []
101
-
85
+ has_rdoc: