ruby-decompiler 0.0.1

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,619 @@
1
+ require 'internal/node'
2
+ require 'internal/node/to_a'
3
+ require 'rbconfig'
4
+
5
+ class Node
6
+ public
7
+
8
+ # Return an string describing this node as a single expression. By
9
+ # default, this just returns the name of the node's type, but some
10
+ # node types override this method to produce more meaningful output.
11
+ def as_expression(*args)
12
+ return as_expression_impl(self, *args)
13
+ end
14
+
15
+ # Return a string as with as_expression, but surround it with parens
16
+ # if it is a composite expression, so that it can be used to form more
17
+ # complex expressions.
18
+ def as_paren_expression(*args)
19
+ expr = self.as_expression(*args)
20
+ if not OMIT_PARENS[self.class] then
21
+ expr = "(#{expr})"
22
+ end
23
+ return expr
24
+ end
25
+
26
+ private
27
+
28
+ # default
29
+ def as_expression_impl(node)
30
+ return "<#{node.nd_type.to_s}>"
31
+ end
32
+
33
+ class << self
34
+ def define_expression(klass, &block)
35
+ if const_defined?(klass) then
36
+ const_get(klass).instance_eval { define_method(:as_expression_impl, &block) }
37
+ end
38
+ end
39
+ end
40
+
41
+ define_expression(:LIT) do |node|
42
+ # TODO: #inspect might not give an eval-able expression
43
+ node.lit.inspect
44
+ end
45
+
46
+ define_expression(:FCALL) do |node|
47
+ # args will either be an ARRAY or ARGSCAT
48
+ args = node.args
49
+ "#{node.mid}(#{args ? args.as_expression(false) : ''})"
50
+ end
51
+
52
+ define_expression(:VCALL) do |node|
53
+ node.mid.to_s
54
+ end
55
+
56
+ arithmetic_expressions = [
57
+ :+, :-, :*, :/, :<, :>, :<=, :>=, :==, :===, :<=>, :<<, :>>, :&, :|,
58
+ :^, :%, '!'.intern, '!='.intern
59
+ ]
60
+
61
+ # TODO: there should be a way to detect if the expressions need to be
62
+ # in parens
63
+ define_expression(:CALL) do |node|
64
+ recv_expr = node.recv.as_paren_expression
65
+
66
+ case node.mid
67
+ when *arithmetic_expressions
68
+ args = node.args
69
+ "#{recv_expr} #{node.mid} #{args ? args.as_paren_expression(false) : ''}"
70
+ when :[]
71
+ args = node.args
72
+ "#{recv_expr}[#{args ? args.as_expression(false) : ''}]"
73
+ else
74
+ args = node.args
75
+ "#{recv_expr}.#{node.mid}(#{args ? args.as_expression(false) : ''})"
76
+ end
77
+ end
78
+
79
+ define_expression(:ZSUPER) do |node|
80
+ "super"
81
+ end
82
+
83
+ define_expression(:SUPER) do |node|
84
+ "super(#{node.args ? node.args.as_expression(false) : ''})"
85
+ end
86
+
87
+ define_expression(:REDO) do |node|
88
+ "redo"
89
+ end
90
+
91
+ define_expression(:RETRY) do |node|
92
+ "retry"
93
+ end
94
+
95
+ define_expression(:NOT) do |node|
96
+ "not #{node.body.as_expression}"
97
+ end
98
+
99
+ define_expression(:AND) do |node|
100
+ "#{node.first.as_expression} and #{node.second.as_expression}"
101
+ end
102
+
103
+ define_expression(:OR) do |node|
104
+ "#{node.first.as_expression} or #{node.second.as_expression}"
105
+ end
106
+
107
+ class ARRAY < Node
108
+ def as_expression_impl(node, brackets = true)
109
+ s = brackets ? '[' : ''
110
+ s << (node.to_a.map { |n| n.as_expression }.join(', '))
111
+ s << (brackets ? ']' : '')
112
+ s
113
+ end
114
+ end
115
+
116
+ class ARGSCAT < Node
117
+ def as_expression_impl(node, brackets = true)
118
+ s = brackets ? '[' : ''
119
+ s << node.head.as_expression(false)
120
+ s << ", "
121
+ s << "*#{node.body.as_expression}"
122
+ s << (brackets ? ']' : '')
123
+ s
124
+ end
125
+ end
126
+
127
+ class ZARRAY < Node
128
+ def as_expression_impl(node, brackets = true)
129
+ brackets ? '[]' : ''
130
+ end
131
+ end
132
+
133
+ class BLOCK < Node
134
+ def as_expression_impl(node)
135
+ a = node.to_a
136
+ if a.size == 1 then
137
+ return 'nil'
138
+ end
139
+ d = a[0]
140
+ while d.class == Node::DASGN_CURR do
141
+ d = d.value
142
+ end
143
+ a.shift if not d
144
+ expressions = a.map { |n| n.as_expression }
145
+ expressions.reject! { |e| e.nil? }
146
+ if expressions.nitems == 0 then
147
+ return 'nil'
148
+ else
149
+ return expressions.join('; ')
150
+ end
151
+ end
152
+ end
153
+
154
+ define_expression(:HASH) do |node|
155
+ if not node.head then
156
+ "{}"
157
+ else
158
+ a = node.head.to_a
159
+ elems = []
160
+ i = 0
161
+ while i < a.size do
162
+ elems << "(#{a[i].as_expression})=>(#{a[i+1].as_expression})"
163
+ i += 2
164
+ end
165
+ "{#{elems.join(', ')}}"
166
+ end
167
+ end
168
+
169
+ define_expression(:IF) do |node|
170
+ if Node.const_defined?(:NEWLINE) then
171
+ bodynode = node.body.class == Node::NEWLINE ? node.body.next : node.body
172
+ elsenode = node.else.class == Node::NEWLINE ? node.else.next : node.else
173
+ else
174
+ bodynode = node.body
175
+ elsenode = node.else
176
+ end
177
+ if elsenode then
178
+ "#{node.cond.as_paren_expression} ? " +
179
+ "#{bodynode.as_paren_expression} : " +
180
+ "#{elsenode.as_paren_expression}"
181
+ else
182
+ "#{bodynode.as_paren_expression} if " +
183
+ "#{node.cond.as_paren_expression}"
184
+ end
185
+ end
186
+
187
+ define_expression(:TRUE) do |node|
188
+ "true"
189
+ end
190
+
191
+ define_expression(:FALSE) do |node|
192
+ "false"
193
+ end
194
+
195
+ define_expression(:NIL) do |node|
196
+ "nil"
197
+ end
198
+
199
+ define_expression(:SELF) do |node|
200
+ "self"
201
+ end
202
+
203
+ define_expression(:DOT2) do |node|
204
+ "#{node.beg.as_paren_expression}..#{node.end.as_paren_expression}"
205
+ end
206
+
207
+ define_expression(:DOT3) do |node|
208
+ "#{node.beg.as_paren_expression}...#{node.end.as_paren_expression}"
209
+ end
210
+
211
+ define_expression(:GVAR) do |node|
212
+ "#{node.vid}"
213
+ end
214
+
215
+ define_expression(:IVAR) do |node|
216
+ "#{node.vid}"
217
+ end
218
+
219
+ define_expression(:CVAR) do |node|
220
+ "#{node.vid}"
221
+ end
222
+
223
+ define_expression(:DVAR) do |node|
224
+ "#{node.vid}"
225
+ end
226
+
227
+ define_expression(:NTH_REF) do |node|
228
+ "$#{node.nth}"
229
+ end
230
+
231
+ define_expression(:BACK_REF) do |node|
232
+ "$`"
233
+ end
234
+
235
+ define_expression(:DASGN_CURR) do |node|
236
+ # node.value is unset for MASGN
237
+ node.value ? "#{node.vid} = #{node.value.as_expression}" : "#{node.vid}"
238
+ end
239
+
240
+ define_expression(:DASGN) do |node|
241
+ "#{node.vid} = #{node.value.as_expression}"
242
+ end
243
+
244
+ define_expression(:IASGN) do |node|
245
+ "#{node.vid} = #{node.value.as_expression}"
246
+ end
247
+
248
+ define_expression(:LASGN) do |node|
249
+ "#{node.vid} = #{node.value.as_expression}"
250
+ end
251
+
252
+ define_expression(:MASGN) do |node|
253
+ lhs = node.head.to_a.map { |n| n.as_expression }
254
+ rhs = node.value.to_a.map { |n| n.as_expression }
255
+ "#{lhs.join(', ')} = #{rhs.join(', ')}"
256
+ end
257
+
258
+ define_expression(:OP_ASGN1) do |node|
259
+ # TODO
260
+ raise "Not implemented"
261
+ end
262
+
263
+ define_expression(:OP_ASGN2) do |node|
264
+ recv = node.recv.as_expression
265
+ attr = node.next.vid # TODO: we assume it's the same as aid
266
+ op = case node.next.mid
267
+ when false then '||'
268
+ when nil then '&&'
269
+ else node.next.mid
270
+ end
271
+ value = node.value.as_expression
272
+ "#{recv}.#{attr} #{op}= #{value}"
273
+ end
274
+
275
+ define_expression(:CDECL) do |node|
276
+ "#{node.vid} = #{node.value.as_expression}"
277
+ end
278
+
279
+ define_expression(:CVDECL) do |node|
280
+ "#{node.vid} = #{node.value.as_expression}"
281
+ end
282
+
283
+ define_expression(:CVASGN) do |node|
284
+ "#{node.vid} = #{node.value.as_expression}"
285
+ end
286
+
287
+ define_expression(:ATTRASGN) do |node|
288
+ case node.mid
289
+ when :[]=
290
+ args = node.args.to_a
291
+ attrs = args[1..-2].map { |n| n.as_expression }
292
+ value = args[-1].as_expression
293
+ "#{node.recv.as_paren_expression}[#{attrs.join(', ')}] = #{value}"
294
+ else
295
+ "#{node.recv.as_paren_expression}.#{node.mid}#{node.args.as_expression(false)}"
296
+ end
297
+ end
298
+
299
+ define_expression(:CONST) do |node|
300
+ "#{node.vid}"
301
+ end
302
+
303
+ define_expression(:COLON2) do |node|
304
+ # TODO: shouldn't COLON2 have args if it's a method?
305
+ if node.head then
306
+ "#{node.head.as_expression}::#{node.mid}"
307
+ else
308
+ node.mid.to_s
309
+ end
310
+ end
311
+
312
+ define_expression(:COLON3) do |node|
313
+ "::#{node.mid}"
314
+ end
315
+
316
+ define_expression(:LVAR) do |node|
317
+ "#{node.vid}"
318
+ end
319
+
320
+ define_expression(:NEWLINE) do |node|
321
+ node.next.as_expression
322
+ end
323
+
324
+ define_expression(:STR) do |node|
325
+ "\"#{node.lit.inspect[1..-2]}\""
326
+ end
327
+
328
+ define_expression(:REGX) do |node|
329
+ # TODO: cflag
330
+ "/#{node.lit.inspect[1..-2]}/"
331
+ end
332
+
333
+ define_expression(:REGX_ONCE) do |node|
334
+ # TODO: cflag
335
+ "/#{node.lit.inspect[1..-2]}/o"
336
+ end
337
+
338
+ define_expression(:XSTR) do |node|
339
+ "`#{node.lit.inspect[1..-2]}`"
340
+ end
341
+
342
+ define_expression(:DSTR) do |node|
343
+ a = node.next.to_a
344
+ s = "\"#{node.lit.inspect[1..-2]}"
345
+ a.each do |elem|
346
+ case elem
347
+ when Node::STR then s += elem.lit
348
+ else s += elem.as_expression
349
+ end
350
+ end
351
+ s += "\""
352
+ s
353
+ end
354
+
355
+ define_expression(:DREGX) do |node|
356
+ a = node.next.to_a
357
+ s = "/#{node.lit.inspect[1..-2]}"
358
+ a.each do |elem|
359
+ case elem
360
+ when Node::STR then s += elem.lit
361
+ else s += elem.as_expression
362
+ end
363
+ end
364
+ s += "/"
365
+ # TODO: cflag
366
+ s
367
+ end
368
+
369
+ define_expression(:DREGX_ONCE) do |node|
370
+ a = node.next.to_a
371
+ s = "/#{node.lit.inspect[1..-2]}"
372
+ a.each do |elem|
373
+ case elem
374
+ when Node::STR then s += elem.lit
375
+ else s += elem.as_expression
376
+ end
377
+ end
378
+ s += "/o"
379
+ # TODO: cflag
380
+ s
381
+ end
382
+
383
+ define_expression(:DXSTR) do |node|
384
+ a = node.next.to_a
385
+ s = "`#{node.lit.inspect[1..-2]}"
386
+ a.each do |elem|
387
+ case elem
388
+ when Node::STR then s += elem.lit
389
+ else s += elem.as_expression
390
+ end
391
+ end
392
+ s += "`"
393
+ s
394
+ end
395
+
396
+ major = Config::CONFIG['MAJOR'].to_i
397
+ minor = Config::CONFIG['MINOR'].to_i
398
+ teeny = Config::CONFIG['TEENY'].to_i
399
+ ruby_version_code = major * 100 + minor * 10 + teeny
400
+
401
+ if ruby_version_code >= 180 then
402
+
403
+ define_expression(:EVSTR) do |node|
404
+ "\#\{#{node.body.as_expression}\}"
405
+ end
406
+
407
+ else
408
+
409
+ define_expression(:EVSTR) do |node|
410
+ "\#\{#{node.lit}\}"
411
+ end
412
+
413
+ end
414
+
415
+ define_expression(:ITER) do |node|
416
+ iter = node.iter.as_expression
417
+ body = node.body ? (node.body.as_expression + " ") : ""
418
+ "#{iter} { #{body} }"
419
+ end
420
+
421
+ define_expression(:WHILE) do |node|
422
+ if node.state == 1 then
423
+ "while #{node.cond.as_expression} do; #{node.body.as_expression}; end"
424
+ else
425
+ "begin; #{node.body.as_expression}; end while #{node.cond.as_expression}"
426
+ end
427
+ end
428
+
429
+ define_expression(:UNTIL) do |node|
430
+ if node.state == 1 then
431
+ "until #{node.cond.as_expression} do; #{node.body.as_expression}; end"
432
+ else
433
+ "begin; #{node.body.as_expression}; end until #{node.cond.as_expression}"
434
+ end
435
+ end
436
+
437
+ define_expression(:BREAK) do |node|
438
+ s = "break"
439
+ if node.stts then
440
+ s += " #{node.stts.as_expression}"
441
+ end
442
+ s
443
+ end
444
+
445
+ define_expression(:RETURN) do |node|
446
+ s = "return"
447
+ if node.stts then
448
+ s += " #{node.stts.as_expression}"
449
+ end
450
+ s
451
+ end
452
+
453
+ define_expression(:YIELD) do |node|
454
+ s = "yield"
455
+ if node.stts then
456
+ s += " #{node.stts.as_expression}"
457
+ end
458
+ s
459
+ end
460
+
461
+ define_expression(:BEGIN) do |node|
462
+ if node.body.class == Node::RESCUE or
463
+ node.body.class == Node::ENSURE then
464
+ "begin; #{node.body.as_expression(true)}; end"
465
+ elsif node.body then
466
+ "begin; #{node.body.as_expression}; end"
467
+ else
468
+ "begin; end"
469
+ end
470
+ end
471
+
472
+ define_expression(:ENSURE) do |node, *args|
473
+ begin_ensure = args[0] || false
474
+ if node.head then
475
+ if begin_ensure then
476
+ "#{node.head.as_expression} ensure #{node.ensr.as_expression}"
477
+ else
478
+ "begin; #{node.head.as_expression} ensure #{node.ensr.as_expression}; end"
479
+ end
480
+ else
481
+ if begin_ensure then
482
+ "ensure #{node.ensr.as_expression}"
483
+ else
484
+ "begin; ensure #{node.ensr.as_expression}; end"
485
+ end
486
+ end
487
+ end
488
+
489
+ define_expression(:RESCUE) do |node, *args|
490
+ begin_rescue = args[0] || false
491
+ if node.head then
492
+ if begin_rescue then
493
+ "#{node.head.as_expression}; rescue #{node.resq.as_expression(begin_rescue)}"
494
+ else
495
+ if not node.resq or not node.resq.body then
496
+ "begin; #{node.head.as_expression}; rescue; end"
497
+ else
498
+ "#{node.head.as_paren_expression} rescue #{node.resq.as_expression(begin_rescue)}"
499
+ end
500
+ end
501
+ else
502
+ if not node.resq or not node.resq.body then
503
+ "begin; rescue; end"
504
+ else
505
+ "rescue #{node.resq.as_expression(begin_rescue)}"
506
+ end
507
+ end
508
+ end
509
+
510
+ define_expression(:RESBODY) do |node, *args|
511
+ begin_rescue = args[0] || false
512
+ if begin_rescue then
513
+ if node.args then
514
+ a = node.args.to_a.map { |n| n.as_expression }
515
+ "#{a.join(', ')}; #{node.resq.as_expression}"
516
+ else
517
+ node.body ? "; #{node.body.as_expression}" : ''
518
+ end
519
+ else
520
+ # TODO: assuming node.args is false...
521
+ node.body ? node.body.as_expression : ''
522
+ end
523
+ end
524
+
525
+ define_expression(:CASE) do |node|
526
+ "case #{node.head.as_expression}; #{node.body.as_expression}end"
527
+ end
528
+
529
+ define_expression(:WHEN) do |node|
530
+ args = node.head.to_a.map { |n| n.as_expression }
531
+ s = ''
532
+ if node.body then
533
+ s = "when #{args.join(', ')} then #{node.body.as_expression}; "
534
+ else
535
+ s = "when #{args.join(', ')}; "
536
+ end
537
+ if node.next then
538
+ s += node.next.as_expression
539
+ end
540
+ s
541
+ end
542
+
543
+ define_expression(:ALIAS) do |node|
544
+ "alias #{node.new} #{node.old}"
545
+ end
546
+
547
+ define_expression(:VALIAS) do |node|
548
+ "alias #{node.new} #{node.old}"
549
+ end
550
+
551
+ define_expression(:UNDEF) do |node|
552
+ if defined? node.mid then
553
+ # < 1.8.5
554
+ "undef #{node.mid}"
555
+ else
556
+ # >= 1.8.5
557
+ "undef #{node.body.as_expression}"
558
+ end
559
+ end
560
+
561
+ define_expression(:CLASS) do |node|
562
+ s_super = node.super ? " < #{node.super.as_expression}" : ''
563
+ if node.respond_to?(:cpath) then
564
+ path = node.cpath.as_expression
565
+ else
566
+ path = node.cname
567
+ end
568
+ "class #{path}#{s_super}; #{node.body.as_expression}; end"
569
+ end
570
+
571
+ define_expression(:SCLASS) do |node|
572
+ "class << #{node.recv.as_expression}; #{node.body.as_expression}; end"
573
+ end
574
+
575
+ define_expression(:SCOPE) do |node|
576
+ case node.next
577
+ when nil then ''
578
+ when Node::ARGS then 'nil'
579
+ when Node::BLOCK_ARG then 'nil'
580
+ else node.next.as_expression
581
+ end
582
+ end
583
+
584
+ define_expression(:DEFN) do |node|
585
+ # TODO: what to do about noex?
586
+ "def #{node.mid}; #{node.next.as_expression}; end"
587
+ end
588
+
589
+ define_expression(:DEFS) do |node|
590
+ "def #{node.recv.as_expression}.#{node.mid}; #{node.next.as_expression}; end"
591
+ end
592
+
593
+ define_expression(:DEFINED) do |node|
594
+ "defined?(#{node.head.as_expression})"
595
+ end
596
+
597
+ define_expression(:ARGS) do |node|
598
+ nil
599
+ end
600
+
601
+ define_expression(:BLOCK_ARG) do |node|
602
+ nil
603
+ end
604
+
605
+ # TODO: MATCH3
606
+
607
+ OMIT_PARENS = {
608
+ LVAR => true,
609
+ GVAR => true,
610
+ IVAR => true,
611
+ CVAR => true,
612
+ DVAR => true,
613
+ LIT => true,
614
+ ARRAY => true,
615
+ ZARRAY => true,
616
+ HASH => true,
617
+ }
618
+ end
619
+