virtual_keywords 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/lib/parsetree/History.txt +477 -0
  2. data/lib/parsetree/Manifest.txt +19 -0
  3. data/lib/parsetree/README.txt +97 -0
  4. data/lib/parsetree/Rakefile +37 -0
  5. data/lib/parsetree/bin/parse_tree_abc +89 -0
  6. data/lib/parsetree/bin/parse_tree_audit +28 -0
  7. data/lib/parsetree/bin/parse_tree_deps +62 -0
  8. data/lib/parsetree/bin/parse_tree_show +63 -0
  9. data/lib/parsetree/demo/printer.rb +20 -0
  10. data/lib/parsetree/lib/gauntlet_parsetree.rb +121 -0
  11. data/lib/parsetree/lib/parse_tree.rb +1202 -0
  12. data/lib/parsetree/lib/parse_tree_extensions.rb +59 -0
  13. data/lib/parsetree/lib/unified_ruby.rb +421 -0
  14. data/lib/parsetree/test/something.rb +53 -0
  15. data/lib/parsetree/test/test_parse_tree.rb +2567 -0
  16. data/lib/parsetree/test/test_parse_tree_extensions.rb +107 -0
  17. data/lib/parsetree/test/test_unified_ruby.rb +57 -0
  18. data/lib/parsetree/validate.sh +31 -0
  19. data/lib/sexps/{count_to_ten_sexp.txt → count_to_ten_sexp.rb} +0 -0
  20. data/lib/sexps/{sexps_and.txt → sexps_and.rb} +0 -0
  21. data/lib/sexps/{sexps_case_when.txt → sexps_case_when.rb} +0 -0
  22. data/lib/sexps/{sexps_greet.txt → sexps_greet.rb} +0 -0
  23. data/lib/sexps/sexps_not.rb +24 -0
  24. data/lib/sexps/{sexps_rewritten_keywords.txt → sexps_rewritten_keywords.rb} +0 -0
  25. data/lib/sexps/{sexps_symbolic_and.txt → sexps_symbolic_and.rb} +0 -0
  26. data/lib/sexps/sexps_until.rb +60 -0
  27. data/lib/sexps/{sexps_while.txt → sexps_while.rb} +0 -0
  28. data/lib/spec/class_reflection_spec.rb +64 -0
  29. data/lib/spec/keyword_rewriter_spec.rb +7 -54
  30. data/lib/spec/not_rewriter_spec.rb +25 -0
  31. data/lib/spec/parser_strategy_spec.rb +23 -0
  32. data/lib/spec/sexp_stringifier_spec.rb +19 -0
  33. data/lib/spec/spec_helper.rb +61 -307
  34. data/lib/spec/until_rewriter_spec.rb +26 -0
  35. data/lib/spec/virtualizees/and_user.rb +17 -0
  36. data/lib/spec/virtualizees/case_when_user.rb +20 -0
  37. data/lib/spec/virtualizees/fizzbuzzer.rb +15 -0
  38. data/lib/spec/virtualizees/greeter.rb +127 -0
  39. data/lib/spec/virtualizees/not_user.rb +9 -0
  40. data/lib/spec/virtualizees/operator_user.rb +15 -0
  41. data/lib/spec/virtualizees/or_user.rb +17 -0
  42. data/lib/spec/virtualizees/parents.rb +8 -0
  43. data/lib/spec/virtualizees/until_user.rb +16 -0
  44. data/lib/spec/virtualizees/while_user.rb +16 -0
  45. data/lib/spec/virtualizer_spec.rb +46 -83
  46. data/lib/virtual_keywords/class_reflection.rb +88 -0
  47. data/lib/virtual_keywords/deep_copy_array.rb +12 -0
  48. data/lib/virtual_keywords/keyword_rewriter.rb +54 -0
  49. data/lib/virtual_keywords/parser_strategy.rb +40 -0
  50. data/lib/virtual_keywords/rewritten_keywords.rb +15 -0
  51. data/lib/virtual_keywords/sexp_stringifier.rb +1 -5
  52. data/lib/virtual_keywords/version.rb +1 -1
  53. data/lib/virtual_keywords/virtualizer.rb +30 -115
  54. data/lib/virtual_keywords.rb +31 -5
  55. metadata +117 -90
  56. data/lib/spec/class_mirrorer_spec.rb +0 -18
  57. data/lib/virtual_keywords/class_mirrorer.rb +0 -39
@@ -0,0 +1,59 @@
1
+ class Method
2
+ def with_class_and_method_name
3
+ if self.inspect =~ /<Method: (.*)\#(.*)>/ then
4
+ klass = eval $1
5
+ method = $2.intern
6
+ raise "Couldn't determine class from #{self.inspect}" if klass.nil?
7
+ return yield(klass, method)
8
+ else
9
+ raise "Can't parse signature: #{self.inspect}"
10
+ end
11
+ end
12
+
13
+ def to_sexp
14
+ require 'parse_tree'
15
+ require 'unified_ruby'
16
+ parser = ParseTree.new(false)
17
+ unifier = Unifier.new
18
+ with_class_and_method_name do |klass, method|
19
+ old_sexp = parser.parse_tree_for_method(klass, method)
20
+ unifier.process(old_sexp)
21
+ end
22
+ end
23
+
24
+ def to_ruby
25
+ sexp = self.to_sexp
26
+ Ruby2Ruby.new.process sexp
27
+ end
28
+ end
29
+
30
+ class ProcStoreTmp
31
+ @@n = 0
32
+ def self.new_name
33
+ @@n += 1
34
+ return :"myproc#{@@n}"
35
+ end
36
+ end
37
+
38
+ class UnboundMethod
39
+ def to_ruby
40
+ name = ProcStoreTmp.new_name
41
+ ProcStoreTmp.send(:define_method, name, self)
42
+ m = ProcStoreTmp.new.method(name)
43
+ result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
44
+ 'proc { |\1|').sub(/end\Z/, '}')
45
+ return result
46
+ end
47
+ end
48
+
49
+ class Proc
50
+ def to_sexp
51
+ pt = ParseTree.new(false)
52
+ sexp = pt.parse_tree_for_proc(self)
53
+ Unifier.new.process(sexp)
54
+ end
55
+
56
+ def to_ruby
57
+ Ruby2Ruby.new.process(self.to_sexp).sub(/^\Aproc do/, 'proc {').sub(/end\Z/, '}')
58
+ end
59
+ end
@@ -0,0 +1,421 @@
1
+ require 'sexp_processor'
2
+ require 'composite_sexp_processor'
3
+
4
+ $TESTING ||= false
5
+
6
+ module UnifiedRuby
7
+ def process exp
8
+ exp = Sexp.from_array exp unless Sexp === exp or exp.nil?
9
+ super
10
+ end
11
+
12
+ def rewrite_argscat exp
13
+ _, ary, val = exp
14
+ ary = s(:array, ary) unless ary.first == :array
15
+ ary << s(:splat, val)
16
+ end
17
+
18
+ def rewrite_argspush exp
19
+ exp[0] = :arglist
20
+ exp
21
+ end
22
+
23
+ def rewrite_attrasgn(exp)
24
+ last = exp.last
25
+
26
+ if Sexp === last then
27
+ last[0] = :arglist if last[0] == :array
28
+ else
29
+ exp << s(:arglist)
30
+ end
31
+
32
+ exp
33
+ end
34
+
35
+ def rewrite_begin(exp)
36
+ raise "wtf: #{exp.inspect}" if exp.size > 2
37
+ exp.last
38
+ end
39
+
40
+ def rewrite_block_pass exp
41
+ case exp.size
42
+ when 2 then
43
+ _, block = exp
44
+ case block.first
45
+ when :lasgn then
46
+ block[-1] = :"&#{block[-1]}"
47
+ exp = block
48
+ else
49
+ raise "huh?: #{block.inspect}"
50
+ end
51
+ when 3 then
52
+ _, block, recv = exp
53
+ case recv.first
54
+ when :super then
55
+ recv << s(:block_pass, block)
56
+ exp = recv
57
+ when :call then
58
+ recv.last << s(:block_pass, block)
59
+ exp = recv
60
+ when :masgn then
61
+ block[-1] = :"&#{block[-1]}"
62
+ recv.last << block
63
+ exp = recv
64
+ else
65
+ raise "huh?: #{recv.inspect}"
66
+ end
67
+ end
68
+
69
+ exp
70
+ end
71
+
72
+ def rewrite_bmethod(exp)
73
+ _, args, body = exp
74
+
75
+ args ||= s(:array)
76
+ body ||= s(:block)
77
+
78
+ args = s(:args, args) unless args[0] == :array
79
+
80
+ args = args[1] if args[1] && args[1][0] == :masgn # TODO: clean up
81
+ args = args[1] if args[1] && args[1][0] == :array
82
+ args[0] = :args
83
+
84
+ # this is ugly because rewriters are depth first.
85
+ # TODO: maybe we could come up with some way to do both forms of rewriting.
86
+ args.map! { |s|
87
+ if Sexp === s
88
+ case s[0]
89
+ when :lasgn then
90
+ s[1]
91
+ when :splat then
92
+ :"*#{s[1][1]}"
93
+ else
94
+ raise "huh?: #{s.inspect}"
95
+ end
96
+ else
97
+ s
98
+ end
99
+ }
100
+
101
+ body = s(:block, body) unless body[0] == :block
102
+ body.insert 1, args
103
+
104
+ s(:scope, body)
105
+ end
106
+
107
+ def rewrite_iter(exp)
108
+ t, recv, args, body = exp
109
+
110
+ # unwrap masgn args if there is only 1 thing to assign and it isn't splat
111
+ if Sexp === args and args.sexp_type == :masgn and args.array.size == 2 then
112
+ if args.array.last.sexp_type != :splat then
113
+ args = args.array.last
114
+ end
115
+ end
116
+
117
+ r = s(t, recv, args, body)
118
+ r.delete_at 3 unless body # HACK omg this sucks
119
+ r
120
+ end
121
+
122
+ def rewrite_call(exp)
123
+ args = exp.last
124
+ case args
125
+ when nil
126
+ exp.pop
127
+ when Array
128
+ case args.first
129
+ when :array, :arglist then
130
+ args[0] = :arglist
131
+ when :argscat, :splat then
132
+ exp[-1] = s(:arglist, args)
133
+ else
134
+ raise "unknown type in call #{args.first.inspect} in #{exp.inspect}"
135
+ end
136
+ return exp
137
+ end
138
+
139
+ exp << s(:arglist)
140
+
141
+ exp
142
+ end
143
+
144
+ def rewrite_dasgn(exp)
145
+ exp[0] = :lasgn
146
+ exp
147
+ end
148
+
149
+ alias :rewrite_dasgn_curr :rewrite_dasgn
150
+
151
+ ##
152
+ # :defn is one of the most complex of all the ASTs in ruby. We do
153
+ # one of 3 different translations:
154
+ #
155
+ # 1) From:
156
+ #
157
+ # s(:defn, :name, s(:scope, s(:block, s(:args, ...), ...)))
158
+ # s(:defn, :name, s(:bmethod, s(:masgn, s(:dasgn_curr, :args)), s(:block, ...)))
159
+ # s(:defn, :name, s(:fbody, s(:bmethod, s(:masgn, s(:dasgn_curr, :splat)), s(:block, ...))))
160
+ #
161
+ # to:
162
+ #
163
+ # s(:defn, :name, s(:args, ...), s(:scope, s:(block, ...)))
164
+ #
165
+ # 2) From:
166
+ #
167
+ # s(:defn, :writer=, s(:attrset, :@name))
168
+ #
169
+ # to:
170
+ #
171
+ # s(:defn, :writer=, s(:args), s(:attrset, :@name))
172
+ #
173
+ # 3) From:
174
+ #
175
+ # s(:defn, :reader, s(:ivar, :@name))
176
+ #
177
+ # to:
178
+ #
179
+ # s(:defn, :reader, s(:args), s(:ivar, :@name))
180
+ #
181
+
182
+ def rewrite_defn(exp)
183
+ weirdo = exp.ivar || exp.attrset
184
+ fbody = exp.fbody(true)
185
+
186
+ weirdo ||= fbody.cfunc if fbody
187
+
188
+ exp.push(fbody.scope) if fbody unless weirdo
189
+
190
+ args = exp.scope.block.args(true) unless weirdo if exp.scope
191
+ exp.insert 2, args if args
192
+
193
+ # move block_arg up and in
194
+ block_arg = exp.scope.block.block_arg(true) rescue nil
195
+ if block_arg
196
+ block = args.block(true)
197
+ args << :"&#{block_arg.last}"
198
+ args << block if block
199
+ end
200
+
201
+ # patch up attr_accessor methods
202
+ if weirdo then
203
+ case
204
+ when fbody && fbody.cfunc then
205
+ exp.insert 2, s(:args, :"*args")
206
+ when exp.ivar then
207
+ exp.insert 2, s(:args)
208
+ when exp.attrset then
209
+ exp.insert 2, s(:args, :arg)
210
+ else
211
+ raise "unknown wierdo: #{wierdo.inpsect}"
212
+ end
213
+ end
214
+
215
+ exp
216
+ end
217
+
218
+ def rewrite_defs(exp)
219
+ receiver = exp.delete_at 1
220
+
221
+ # TODO: I think this would be better as rewrite_scope, but that breaks others
222
+ exp = s(exp.shift, exp.shift,
223
+ s(:scope,
224
+ s(:block, exp.scope.args))) if exp.scope && exp.scope.args
225
+
226
+ result = rewrite_defn(exp)
227
+ result.insert 1, receiver
228
+
229
+ result
230
+ end
231
+
232
+ def rewrite_dmethod(exp)
233
+ exp.shift # type
234
+ exp.shift # dmethod name
235
+ exp.shift # scope / block / body
236
+ end
237
+
238
+ def rewrite_dvar(exp)
239
+ exp[0] = :lvar
240
+ exp
241
+ end
242
+
243
+ def rewrite_fcall(exp)
244
+ exp[0] = :call
245
+ exp.insert 1, nil
246
+
247
+ rewrite_call(exp)
248
+ end
249
+
250
+ def rewrite_flip2(exp)
251
+ # from:
252
+ # s(:flip2,
253
+ # s(:call, s(:lit, 1), :==, s(:arglist, s(:gvar, :$.))),
254
+ # s(:call, s(:lit, 2), :a?, s(:arglist, s(:call, nil, :b, s(:arglist)))))
255
+ # to:
256
+ # s(:flip2,
257
+ # s(:lit, 1),
258
+ # s(:call, s(:lit, 2), :a?, s(:arglist, s(:call, nil, :b, s(:arglist)))))
259
+ exp[1] = exp[1][1] if exp[1][0] == :call && exp[1][1][0] == :lit
260
+ exp
261
+ end
262
+
263
+ alias :rewrite_flip3 :rewrite_flip2
264
+
265
+ def rewrite_masgn(exp)
266
+ t, lhs, lhs_splat, rhs = exp
267
+
268
+ lhs ||= s(:array)
269
+
270
+ if lhs_splat then
271
+ case lhs_splat.first
272
+ when :array then
273
+ lhs_splat = lhs_splat.last if lhs_splat.last.first == :splat
274
+ when :splat then
275
+ # do nothing
276
+ else
277
+ lhs_splat = s(:splat, lhs_splat)
278
+ end
279
+ lhs << lhs_splat
280
+ end
281
+
282
+ # unwrap RHS from array IF it is only a splat node
283
+ rhs = rhs.last if rhs && # TODO: rhs.structure =~ s(:array, s(:splat))
284
+ rhs.size == 2 && rhs.structure.flatten.first(2) == [:array, :splat]
285
+
286
+ s(t, lhs, rhs).compact
287
+ end
288
+
289
+ def rewrite_op_asgn1(exp)
290
+ exp[2][0] = :arglist # if exp[2][0] == :array
291
+ exp
292
+ end
293
+
294
+ def rewrite_resbody(exp)
295
+ exp[1] ||= s(:array) # no args
296
+
297
+ body = exp[2]
298
+ if body then
299
+ case body.first
300
+ when :lasgn, :iasgn then
301
+ exp[1] << exp.delete_at(2) if body[-1] == s(:gvar, :$!)
302
+ when :block then
303
+ exp[1] << body.delete_at(1) if [:lasgn, :iasgn].include?(body[1][0]) &&
304
+ body[1][-1] == s(:gvar, :$!)
305
+ end
306
+ end
307
+
308
+ exp << nil if exp.size == 2 # no body
309
+
310
+ exp
311
+ end
312
+
313
+ def rewrite_rescue(exp)
314
+ # SKETCHY HACK return exp if exp.size > 4
315
+ ignored = exp.shift
316
+ body = exp.shift unless exp.first.first == :resbody
317
+ resbody = exp.shift
318
+ els = exp.shift unless exp.first.first == :resbody unless exp.empty?
319
+ rest = exp.empty? ? nil : exp # graceful re-rewriting (see rewrite_begin)
320
+
321
+ resbodies = []
322
+
323
+ unless rest then
324
+ while resbody do
325
+ resbodies << resbody
326
+ resbody = resbody.resbody(true)
327
+ end
328
+
329
+ resbodies.each do |resbody|
330
+ if resbody[2] && resbody[2][0] == :block && resbody[2].size == 2 then
331
+ resbody[2] = resbody[2][-1]
332
+ end
333
+ end
334
+ else
335
+ resbodies = [resbody] + rest
336
+ end
337
+
338
+ resbodies << els if els
339
+
340
+ s(:rescue, body, *resbodies).compact
341
+ end
342
+
343
+ def rewrite_splat(exp)
344
+ good = [:arglist, :argspush, :array, :svalue, :yield, :super].include? context.first
345
+ exp = s(:array, exp) unless good
346
+ exp
347
+ end
348
+
349
+ def rewrite_super(exp)
350
+ return exp if exp.structure.flatten.first(3) == [:super, :array, :splat]
351
+ exp.push(*exp.pop[1..-1]) if exp.size == 2 && exp.last.first == :array
352
+ exp
353
+ end
354
+
355
+ def rewrite_vcall(exp)
356
+ exp.push nil
357
+ rewrite_fcall(exp)
358
+ end
359
+
360
+ def rewrite_yield(exp)
361
+ real_array = exp.pop if exp.size == 3
362
+
363
+ if exp.size == 2 then
364
+ if real_array then
365
+ exp[-1] = s(:array, exp[-1]) if exp[-1][0] != :array
366
+ else
367
+ exp.push(*exp.pop[1..-1]) if exp.last.first == :array
368
+ end
369
+ end
370
+
371
+ exp
372
+ end
373
+
374
+ def rewrite_zarray(exp)
375
+ exp[0] = :array
376
+ exp
377
+ end
378
+ end
379
+
380
+ class PreUnifier < SexpProcessor
381
+ def initialize
382
+ super
383
+ @unsupported.delete :newline
384
+ end
385
+
386
+ def rewrite_call exp
387
+ exp << s(:arglist) if exp.size < 4
388
+ exp.last[0] = :arglist if exp.last.first == :array
389
+ exp
390
+ end
391
+
392
+ def rewrite_fcall exp
393
+ exp << s(:arglist) if exp.size < 3
394
+ if exp[-1][0] == :array then
395
+ has_splat = exp[-1].find { |s| Array === s && s.first == :splat }
396
+ exp[-1] = s(:arglist, exp[-1]) if has_splat
397
+ exp[-1][0] = :arglist
398
+ end
399
+ exp
400
+ end
401
+ end
402
+
403
+ class PostUnifier < SexpProcessor
404
+ include UnifiedRuby
405
+
406
+ def initialize
407
+ super
408
+ @unsupported.delete :newline
409
+ end
410
+ end
411
+
412
+ ##
413
+ # Quick and easy SexpProcessor that unified the sexp structure.
414
+
415
+ class Unifier < CompositeSexpProcessor
416
+ def initialize
417
+ super
418
+ self << PreUnifier.new
419
+ self << PostUnifier.new
420
+ end
421
+ end
@@ -0,0 +1,53 @@
1
+
2
+ class Something
3
+
4
+ def self.classmethod
5
+ 1 + 1
6
+ end
7
+
8
+ # Other edge cases:
9
+
10
+ def opt_args(arg1, arg2 = 42, *args)
11
+ arg3 = arg1 * arg2 * 7
12
+ puts(arg3.to_s)
13
+ return "foo"
14
+ end
15
+
16
+ def multi_args(arg1, arg2)
17
+ arg3 = arg1 * arg2 * 7
18
+ puts(arg3.to_s)
19
+ return "foo"
20
+ end
21
+
22
+ def unknown_args(arg1, arg2)
23
+ # does nothing
24
+ return arg1
25
+ end
26
+
27
+ def determine_args
28
+ 5 == unknown_args(4, "known")
29
+ end
30
+
31
+ # TODO: sort list
32
+ def bbegin
33
+ begin
34
+ 1
35
+ rescue SyntaxError => e1
36
+ 2
37
+ rescue Exception => e2
38
+ 3
39
+ else
40
+ 4
41
+ ensure
42
+ 5
43
+ end
44
+ end
45
+
46
+ def bbegin_no_exception
47
+ begin
48
+ 5
49
+ rescue
50
+ 6
51
+ end
52
+ end
53
+ end