thor 0.9.2 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,278 +0,0 @@
1
-
2
- $TESTING ||= false # unless defined $TESTING
3
-
4
- ##
5
- # Sexps are the basic storage mechanism of SexpProcessor. Sexps have
6
- # a +type+ (to be renamed +node_type+) which is the first element of
7
- # the Sexp. The type is used by SexpProcessor to determine whom to
8
- # dispatch the Sexp to for processing.
9
-
10
- class Sexp < Array # ZenTest FULL
11
-
12
- @@array_types = [ :array, :args, ]
13
-
14
- ##
15
- # Create a new Sexp containing +args+.
16
-
17
- def initialize(*args)
18
- super(args)
19
- end
20
-
21
- ##
22
- # Creates a new Sexp for +klass+ or +method+ in +klass+.
23
- #
24
- # If +walk_ancestors+ is true and +method+ is provided, walks the ancestors
25
- # of +klass+ until a method definition is found.
26
-
27
- def self.for(klass, method = nil, walk_ancestors = false)
28
- require 'parse_tree'
29
- sexp = if walk_ancestors and method then
30
- klass.ancestors.each do |klass|
31
- sexp = ParseTree.translate klass, method
32
- break sexp unless sexp == [nil]
33
- end
34
- else
35
- ParseTree.translate klass, method
36
- end
37
-
38
- Sexp.from_array sexp
39
- end
40
-
41
- ##
42
- # Creates a new Sexp from Array +a+, typically from ParseTree::translate.
43
-
44
- def self.from_array(a)
45
- ary = Array === a ? a : [a]
46
-
47
- result = self.new
48
-
49
- ary.each do |x|
50
- case x
51
- when Sexp
52
- result << x
53
- when Array
54
- result << self.from_array(x)
55
- else
56
- result << x
57
- end
58
- end
59
-
60
- result
61
- end
62
-
63
- def ==(obj) # :nodoc:
64
- if obj.class == self.class then
65
- super
66
- else
67
- false
68
- end
69
- end
70
-
71
- ##
72
- # Returns true if this Sexp's pattern matches +sexp+.
73
-
74
- def ===(sexp)
75
- return nil unless Sexp === sexp
76
- pattern = self # this is just for my brain
77
-
78
- return true if pattern == sexp
79
-
80
- sexp.each do |subset|
81
- return true if pattern === subset
82
- end
83
-
84
- return nil
85
- end
86
-
87
- ##
88
- # Returns true if this Sexp matches +pattern+. (Opposite of #===.)
89
-
90
- def =~(pattern)
91
- return pattern === self
92
- end
93
-
94
- ##
95
- # Returns true if the node_type is +array+ or +args+.
96
- #
97
- # REFACTOR: to TypedSexp - we only care when we have units.
98
-
99
- def array_type?
100
- type = self.first
101
- @@array_types.include? type
102
- end
103
-
104
- ##
105
- # Enumeratates the sexp yielding to +b+ when the node_type == +t+.
106
-
107
- def each_of_type(t, &b)
108
- each do | elem |
109
- if Sexp === elem then
110
- elem.each_of_type(t, &b)
111
- b.call(elem) if elem.first == t
112
- end
113
- end
114
- end
115
-
116
- ##
117
- # Replaces all elements whose node_type is +from+ with +to+. Used
118
- # only for the most trivial of rewrites.
119
-
120
- def find_and_replace_all(from, to)
121
- each_with_index do | elem, index |
122
- if Sexp === elem then
123
- elem.find_and_replace_all(from, to)
124
- else
125
- self[index] = to if elem == from
126
- end
127
- end
128
- end
129
-
130
- ##
131
- # Replaces all Sexps matching +pattern+ with Sexp +repl+.
132
-
133
- def gsub(pattern, repl)
134
- return repl if pattern == self
135
-
136
- new = self.map do |subset|
137
- case subset
138
- when Sexp then
139
- subset.gsub(pattern, repl)
140
- else
141
- subset
142
- end
143
- end
144
-
145
- return Sexp.from_array(new)
146
- end
147
-
148
- def inspect # :nodoc:
149
- sexp_str = self.map {|x|x.inspect}.join(', ')
150
- return "s(#{sexp_str})"
151
- end
152
-
153
- ##
154
- # Returns the node named +node+, deleting it if +delete+ is true.
155
-
156
- def method_missing(meth, delete=false)
157
- matches = find_all { | sexp | Sexp === sexp and sexp.first == meth }
158
-
159
- case matches.size
160
- when 0 then
161
- nil
162
- when 1 then
163
- match = matches.first
164
- delete match if delete
165
- match
166
- else
167
- raise NoMethodError, "multiple nodes for #{meth} were found in #{inspect}"
168
- end
169
- end
170
-
171
- def pretty_print(q) # :nodoc:
172
- q.group(1, 's(', ')') do
173
- q.seplist(self) {|v| q.pp v }
174
- end
175
- end
176
-
177
- ##
178
- # Returns the Sexp without the node_type.
179
-
180
- def sexp_body
181
- self[1..-1]
182
- end
183
-
184
- ##
185
- # If run with debug, Sexp will raise if you shift on an empty
186
- # Sexp. Helps with debugging.
187
-
188
- def shift
189
- raise "I'm empty" if self.empty?
190
- super
191
- end if $DEBUG or $TESTING
192
-
193
- ##
194
- # Returns the bare bones structure of the sexp.
195
- # s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))
196
-
197
- def structure
198
- result = self.class.new
199
- if Array === self.first then
200
- result = self.first.structure
201
- else
202
- result << self.first
203
- self.grep(Array).each do |subexp|
204
- result << subexp.structure
205
- end
206
- end
207
- result
208
- end
209
-
210
- ##
211
- # Replaces the Sexp matching +pattern+ with +repl+.
212
-
213
- def sub(pattern, repl)
214
- return repl.dup if pattern == self
215
-
216
- done = false
217
-
218
- new = self.map do |subset|
219
- if done then
220
- subset
221
- else
222
- case subset
223
- when Sexp then
224
- if pattern == subset then
225
- done = true
226
- repl.dup
227
- elsif pattern === subset then
228
- done = true
229
- subset.sub pattern, repl
230
- else
231
- subset
232
- end
233
- else
234
- subset
235
- end
236
- end
237
- end
238
-
239
- return Sexp.from_array(new)
240
- end
241
-
242
- def to_a # :nodoc:
243
- self.map { |o| Sexp === o ? o.to_a : o }
244
- end
245
-
246
- def to_s # :nodoc:
247
- inspect
248
- end
249
-
250
- end
251
-
252
- class SexpMatchSpecial < Sexp; end
253
-
254
- class SexpAny < SexpMatchSpecial
255
- def ==(o)
256
- Sexp === o
257
- end
258
-
259
- def ===(o)
260
- return Sexp === o
261
- end
262
-
263
- def inspect
264
- "ANY"
265
- end
266
- end
267
-
268
- module SexpMatchSpecials
269
- def ANY(); return SexpAny.new; end
270
- end
271
-
272
- ##
273
- # This is just a stupid shortcut to make indentation much cleaner.
274
-
275
- def s(*args)
276
- Sexp.new(*args)
277
- end
278
-
@@ -1,336 +0,0 @@
1
-
2
- $TESTING = false unless defined? $TESTING
3
-
4
- require "vendor/sexp"
5
-
6
- class Object
7
-
8
- ##
9
- # deep_clone is the usual Marshalling hack to make a deep copy.
10
- # It is rather slow, so use it sparingly. Helps with debugging
11
- # SexpProcessors since you usually shift off sexps.
12
-
13
- def deep_clone
14
- Marshal.load(Marshal.dump(self))
15
- end
16
- end
17
-
18
- ##
19
- # SexpProcessor base exception class.
20
-
21
- class SexpProcessorError < StandardError; end
22
-
23
- ##
24
- # Raised by SexpProcessor if it sees a node type listed in its
25
- # unsupported list.
26
-
27
- class UnsupportedNodeError < SexpProcessorError; end
28
-
29
- ##
30
- # Raised by SexpProcessor if it is in strict mode and sees a node for
31
- # which there is no processor available.
32
-
33
- class UnknownNodeError < SexpProcessorError; end
34
-
35
- ##
36
- # Raised by SexpProcessor if a processor did not process every node in
37
- # a sexp and @require_empty is true.
38
-
39
- class NotEmptyError < SexpProcessorError; end
40
-
41
- ##
42
- # Raised if assert_type encounters an unexpected sexp type.
43
-
44
- class SexpTypeError < SexpProcessorError; end
45
-
46
- ##
47
- # SexpProcessor provides a uniform interface to process Sexps.
48
- #
49
- # In order to create your own SexpProcessor subclass you'll need
50
- # to call super in the initialize method, then set any of the
51
- # Sexp flags you want to be different from the defaults.
52
- #
53
- # SexpProcessor uses a Sexp's type to determine which process method
54
- # to call in the subclass. For Sexp <code>s(:lit, 1)</code>
55
- # SexpProcessor will call #process_lit, if it is defined.
56
- #
57
- # You can also specify a default method to call for any Sexp types
58
- # without a process_<type> method or use the default processor provided to
59
- # skip over them.
60
- #
61
- # Here is a simple example:
62
- #
63
- # class MyProcessor < SexpProcessor
64
- # def initialize
65
- # super
66
- # self.strict = false
67
- # end
68
- #
69
- # def process_lit(exp)
70
- # val = exp.shift
71
- # return val
72
- # end
73
- # end
74
-
75
- class SexpProcessor
76
-
77
- ##
78
- # Automatically shifts off the Sexp type before handing the
79
- # Sexp to process_<type>
80
-
81
- attr_accessor :auto_shift_type
82
-
83
- ##
84
- # Return a stack of contexts. Most recent node is first.
85
-
86
- attr_reader :context
87
-
88
- ##
89
- # A Hash of Sexp types and Regexp.
90
- #
91
- # Print a debug message if the Sexp type matches the Hash key
92
- # and the Sexp's #inspect output matches the Regexp.
93
-
94
- attr_accessor :debug
95
-
96
- ##
97
- # A default method to call if a process_<type> method is not found
98
- # for the Sexp type.
99
-
100
- attr_accessor :default_method
101
-
102
- ##
103
- # Expected result class
104
-
105
- attr_accessor :expected
106
-
107
- ##
108
- # Raise an exception if the Sexp is not empty after processing
109
-
110
- attr_accessor :require_empty
111
-
112
- ##
113
- # Raise an exception if no process_<type> method is found for a Sexp.
114
-
115
- attr_accessor :strict
116
-
117
- ##
118
- # An array that specifies node types that are unsupported by this
119
- # processor. SexpProcessor will raise UnsupportedNodeError if you try
120
- # to process one of those node types.
121
-
122
- attr_accessor :unsupported
123
-
124
- ##
125
- # Emit a warning when the method in #default_method is called.
126
-
127
- attr_accessor :warn_on_default
128
-
129
- ##
130
- # Creates a new SexpProcessor. Use super to invoke this
131
- # initializer from SexpProcessor subclasses, then use the
132
- # attributes above to customize the functionality of the
133
- # SexpProcessor
134
-
135
- def initialize
136
- @default_method = nil
137
- @warn_on_default = true
138
- @auto_shift_type = false
139
- @strict = false
140
- @unsupported = [:alloca, :cfunc, :cref, :ifunc, :last, :memo, :newline, :opt_n, :method] # internal nodes that you can't get to
141
- @unsupported_checked = false
142
- @debug = {}
143
- @expected = Sexp
144
- @require_empty = true
145
- @exceptions = {}
146
-
147
- # we do this on an instance basis so we can subclass it for
148
- # different processors.
149
- @processors = {}
150
- @rewriters = {}
151
- @context = []
152
-
153
- public_methods.each do |name|
154
- case name
155
- when /^process_(.*)/ then
156
- @processors[$1.intern] = name.intern
157
- when /^rewrite_(.*)/ then
158
- @rewriters[$1.intern] = name.intern
159
- end
160
- end
161
- end
162
-
163
- def assert_empty(meth, exp, exp_orig)
164
- unless exp.empty? then
165
- msg = "exp not empty after #{self.class}.#{meth} on #{exp.inspect}"
166
- msg += " from #{exp_orig.inspect}" if $DEBUG
167
- raise NotEmptyError, msg
168
- end
169
- end
170
-
171
- def rewrite(exp)
172
- type = exp.first
173
-
174
- self.context.unshift type # FIX: first one doubles up because process already unshifted -- look at moving initial rewrite up above
175
- exp.map! { |sub| Array === sub ? rewrite(sub) : sub }
176
-
177
- begin
178
- meth = @rewriters[type]
179
- exp = self.send(meth, exp) if meth
180
- old_type, type = type, exp.first
181
- end until old_type == type
182
-
183
- self.context.shift
184
-
185
- exp
186
- end
187
-
188
- ##
189
- # Default Sexp processor. Invokes process_<type> methods matching
190
- # the Sexp type given. Performs additional checks as specified by
191
- # the initializer.
192
-
193
- def process(exp)
194
- return nil if exp.nil?
195
-
196
- unless @unsupported_checked then
197
- m = public_methods.grep(/^process_/) { |o| o.sub(/^process_/, '').intern }
198
- supported = m - (m - @unsupported)
199
-
200
- raise UnsupportedNodeError, "#{supported.inspect} shouldn't be in @unsupported" unless supported.empty?
201
-
202
- @unsupported_checked = true
203
- end
204
-
205
- result = self.expected.new
206
-
207
- type = exp.first
208
- raise "type should be a Symbol, not: #{exp.first.inspect}" unless
209
- Symbol === type
210
-
211
- self.context.unshift type
212
-
213
- if @debug.has_key? type then
214
- str = exp.inspect
215
- puts "// DEBUG: #{str}" if str =~ @debug[type]
216
- end
217
-
218
- exp_orig = nil
219
- exp_orig = exp.deep_clone if $DEBUG or
220
- @debug.has_key? type or @exceptions.has_key?(type)
221
-
222
- raise UnsupportedNodeError, "'#{type}' is not a supported node type" if @unsupported.include? type
223
-
224
- exp = self.rewrite(exp) if self.context.size == 1
225
-
226
- if @debug.has_key? type then
227
- str = exp.inspect
228
- puts "// DEBUG (rewritten): #{str}" if str =~ @debug[type]
229
- end
230
-
231
- # now do a pass with the real processor (or generic)
232
- meth = @processors[type] || @default_method
233
- if meth then
234
-
235
- if @warn_on_default and meth == @default_method then
236
- $stderr.puts "WARNING: Using default method #{meth} for #{type}"
237
- end
238
-
239
- exp.shift if @auto_shift_type and meth != @default_method
240
-
241
- result = error_handler(type, exp_orig) do
242
- self.send(meth, exp)
243
- end
244
-
245
- raise SexpTypeError, "Result must be a #{@expected}, was #{result.class}:#{result.inspect}" unless @expected === result
246
-
247
- self.assert_empty(meth, exp, exp_orig) if @require_empty
248
- else
249
- unless @strict then
250
- until exp.empty? do
251
- sub_exp = exp.shift
252
- sub_result = nil
253
- if Array === sub_exp then
254
- sub_result = error_handler(type, exp_orig) do
255
- process(sub_exp)
256
- end
257
- raise "Result is a bad type" unless Array === sub_exp
258
- raise "Result does not have a type in front: #{sub_exp.inspect}" unless Symbol === sub_exp.first unless sub_exp.empty?
259
- else
260
- sub_result = sub_exp
261
- end
262
- result << sub_result
263
- end
264
-
265
- # NOTE: this is costly, but we are in the generic processor
266
- # so we shouldn't hit it too much with RubyToC stuff at least.
267
- #if Sexp === exp and not exp.sexp_type.nil? then
268
- begin
269
- result.sexp_type = exp.sexp_type
270
- rescue Exception
271
- # nothing to do, on purpose
272
- end
273
- else
274
- msg = "Bug! Unknown node-type #{type.inspect} to #{self.class}"
275
- msg += " in #{exp_orig.inspect} from #{caller.inspect}" if $DEBUG
276
- raise UnknownNodeError, msg
277
- end
278
- end
279
-
280
- self.context.shift
281
- result
282
- end
283
-
284
- def generate # :nodoc:
285
- raise NotImplementedError, "not implemented yet"
286
- end
287
-
288
- ##
289
- # Raises unless the Sexp type for +list+ matches +typ+
290
-
291
- def assert_type(list, typ)
292
- raise SexpTypeError, "Expected type #{typ.inspect} in #{list.inspect}" if
293
- not Array === list or list.first != typ
294
- end
295
-
296
- def error_handler(type, exp=nil) # :nodoc:
297
- begin
298
- return yield
299
- rescue StandardError => err
300
- if @exceptions.has_key? type then
301
- return @exceptions[type].call(self, exp, err)
302
- else
303
- $stderr.puts "#{err.class} Exception thrown while processing #{type} for sexp #{exp.inspect} #{caller.inspect}" if $DEBUG
304
- raise
305
- end
306
- end
307
- end
308
- private :error_handler
309
-
310
- ##
311
- # Registers an error handler for +node+
312
-
313
- def on_error_in(node_type, &block)
314
- @exceptions[node_type] = block
315
- end
316
-
317
- ##
318
- # A fairly generic processor for a dummy node. Dummy nodes are used
319
- # when your processor is doing a complicated rewrite that replaces
320
- # the current sexp with multiple sexps.
321
- #
322
- # Bogus Example:
323
- #
324
- # def process_something(exp)
325
- # return s(:dummy, process(exp), s(:extra, 42))
326
- # end
327
-
328
- def process_dummy(exp)
329
- result = @expected.new(:dummy) rescue @expected.new
330
- until exp.empty? do
331
- result << self.process(exp.shift)
332
- end
333
- result
334
- end
335
- end
336
-