virtual_keywords 0.1.0 → 0.3.0

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