furnace 0.0.4 → 0.0.6

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.
@@ -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: