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,160 @@
1
+ class Node
2
+ # pre-YARV
3
+ class SCOPE
4
+ include MethodSig
5
+
6
+ def local_vars
7
+ return self.tbl || []
8
+ end
9
+
10
+ def argument_names
11
+ local_vars = self.local_vars
12
+ args = self.args_node
13
+ num_required_args = args.cnt
14
+ num_optional_args = 0
15
+ opt = args.opt
16
+ while opt do
17
+ num_optional_args += 1
18
+ opt = opt.next
19
+ end
20
+ num_args = \
21
+ num_required_args + \
22
+ num_optional_args + \
23
+ (rest_arg ? 1 : 0) + \
24
+ (block_arg ? 1 : 0)
25
+ return local_vars[0...num_args]
26
+ end
27
+
28
+ def args_node
29
+ if self.next.class == Node::ARGS then
30
+ return self.next
31
+ elsif self.next.head.class == Node::ARGS then
32
+ return self.next.head
33
+ else
34
+ raise "Could not find method arguments"
35
+ end
36
+ end
37
+
38
+ def rest_arg
39
+ args_node = args_node()
40
+ rest = args_node.rest()
41
+ if rest.class == Node::LASGN then
42
+ # subtract 2 to account for implicit vars
43
+ return rest.cnt - 2
44
+ elsif not rest
45
+ return nil
46
+ else
47
+ return rest > 0 ? rest - 2 : nil
48
+ end
49
+ end
50
+
51
+ def block_arg
52
+ block = self.next
53
+ if block.class == Node::BLOCK and
54
+ block.next.head.class == Node::BLOCK_ARG then
55
+ # subtract 2 to account for implicit vars
56
+ return block.next.head.cnt - 2
57
+ else
58
+ return nil
59
+ end
60
+ end
61
+
62
+ def set_optional_args(args, args_node, names)
63
+ opt = args_node.opt
64
+ while opt do
65
+ head = opt.head
66
+ if head.class == Node::LASGN then
67
+ args[head.vid] = NodeOptionalArgument.new(
68
+ head.vid, head.value.as_expression, head.value, false, false)
69
+ else
70
+ raise "Unexpected node type: #{opt.class}"
71
+ end
72
+ opt = opt.next
73
+ end
74
+ end
75
+ end
76
+
77
+ # Pre-YARV, I think
78
+ class BMETHOD
79
+ def local_vars
80
+ raise "TODO: Not implemented yet"
81
+ end
82
+
83
+ def argument_names
84
+ return self.cval.arguments.names
85
+ end
86
+
87
+ def arguments
88
+ return self.cval.arguments
89
+ end
90
+
91
+ def args_node
92
+ raise "TODO: Not implemented yet"
93
+ end
94
+
95
+ def rest_arg
96
+ raise "TODO: Not implemented yet"
97
+ end
98
+
99
+ def block_arg
100
+ raise "TODO: Not implemented yet"
101
+ end
102
+
103
+ def set_optional_args(args, args_node, names)
104
+ raise "TODO: Not implemented yet"
105
+ end
106
+ end
107
+
108
+ # YARV up to 1.9.1
109
+ class METHOD
110
+ include MethodSig
111
+
112
+ def local_vars
113
+ iseq = self.body
114
+ local_vars = iseq.local_table
115
+ return local_vars
116
+ end
117
+
118
+ def argument_names
119
+ local_vars = self.local_vars
120
+ iseq = self.body
121
+ opt_args = iseq.arg_opt_table
122
+ opt_args.pop # last arg is a pointer to the start of the code
123
+ num_args = \
124
+ iseq.argc + \
125
+ opt_args.size + \
126
+ (rest_arg ? 1 : 0) + \
127
+ (block_arg ? 1 : 0)
128
+ return local_vars[0...num_args]
129
+ end
130
+
131
+ def args_node
132
+ return nil
133
+ end
134
+
135
+ def rest_arg
136
+ arg_rest = self.body.arg_rest
137
+ return arg_rest >= 0 ? arg_rest : nil
138
+ end
139
+
140
+ def block_arg
141
+ arg_block = self.body.arg_block
142
+ return arg_block >= 0 ? arg_block : nil
143
+ end
144
+
145
+ def set_optional_args(args, args_node, names)
146
+ opt_table = self.body.arg_opt_table
147
+ opt_table.pop
148
+ first_opt_idx =
149
+ names.size -
150
+ opt_table.size -
151
+ (self.rest_arg ? 1 : 0) -
152
+ (self.block_arg ? 1 : 0)
153
+ opt_table.each_with_index do |pc, idx|
154
+ name = names[first_opt_idx + idx]
155
+ args[name] = YarvOptionalArgument.new(name, self.body, pc, idx, false, false)
156
+ end
157
+ end
158
+ end
159
+ end
160
+
@@ -0,0 +1,23 @@
1
+ module MethodSig
2
+ # An abstraction for a method signature.
3
+ class Signature
4
+ attr_reader :origin_class, :name, :arg_names, :args
5
+
6
+ def initialize(origin_class, name, arg_names, args)
7
+ @origin_class = origin_class
8
+ @name = name
9
+ @arg_names = arg_names
10
+ @args = args
11
+ end
12
+
13
+ def to_s
14
+ return "#{@origin_class}\##{@name}(#{param_list})"
15
+ end
16
+
17
+ def param_list
18
+ params = @arg_names.map{ |n| args[n].to_s }
19
+ return params.join(', ')
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,45 @@
1
+ require 'internal/node/as_code'
2
+ require 'internal/module'
3
+
4
+ class Module
5
+ # TODO: it would be nice if we could go back and find the AST
6
+ # for the class instead of recreating the code from the class's
7
+ # current state.
8
+ def as_code(indent=0)
9
+ imethods = self.instance_methods - self.superclass.instance_methods
10
+ cmethods = self.instance_methods - self.superclass.instance_methods
11
+ constants = self.constants - self.superclass.constants
12
+ name = self.name.gsub(/.*::/, '')
13
+
14
+ # TODO: included modules?
15
+ if self.class == Class then
16
+ s = "#{' '*indent}class #{name} < #{self.superclass}\n"
17
+ else
18
+ s = "#{' '*indent}module #{name}\n"
19
+ end
20
+
21
+ constants.each do |constant|
22
+ s += "#{' '*indent} #{constant}=#{self.const_get(constant).as_code}\n"
23
+ end
24
+
25
+ # TODO: protected/private
26
+ imethods.each do |method|
27
+ s += self.instance_method(method).as_code(indent+1)
28
+ s += "\n"
29
+ end
30
+
31
+ cmethods.each do |method|
32
+ s += self.instance_method(method).as_code(indent+1, "self.#{method}")
33
+ s += "\n"
34
+ end
35
+
36
+ # TODO: singleton class constants
37
+ # TODO: class variables
38
+ # TODO: singleton instance variables
39
+
40
+ s += "#{' '*indent}end"
41
+
42
+ return s
43
+ end
44
+ end
45
+
@@ -0,0 +1,233 @@
1
+ require 'internal/node'
2
+ require 'internal/node/as_expression'
3
+ require 'internal/object/as_code'
4
+ require 'rbconfig'
5
+
6
+ class Node
7
+ public
8
+
9
+ def as_code(indent=0, *args)
10
+ return as_code_impl(self, indent, *args)
11
+ end
12
+
13
+ private
14
+
15
+ def as_code_impl(node, indent, *args)
16
+ # default -- most code is just an expression
17
+ expression = node.as_expression(*args)
18
+ if not expression.nil? then
19
+ return "#{' '*indent}#{expression}"
20
+ else
21
+ return nil
22
+ end
23
+ end
24
+
25
+ class << self
26
+ def define_code(klass, &block)
27
+ if const_defined?(klass) then
28
+ const_get(klass).instance_eval { define_method(:as_code_impl, &block) }
29
+ end
30
+ end
31
+ end
32
+
33
+ define_code(:IF) do |node, indent|
34
+ if node.body.class == Node::BLOCK or
35
+ node.else.class == Node::BLOCK then
36
+ s = "#{' '*indent}if #{node.cond.as_expression} then\n"
37
+ s << "#{' '*indent}#{node.body.as_code(indent+1)}\n"
38
+ if node.else then
39
+ s << "#{' '*indent}else\n"
40
+ s << "#{' '*indent}#{node.else.as_code(indent+1)}\n"
41
+ end
42
+ s << "#{' '*indent}end"
43
+ s
44
+ else
45
+ "#{' '*indent}#{node.as_expression}"
46
+ end
47
+ end
48
+
49
+ define_code(:BLOCK) do |node, indent|
50
+ a = node.to_a
51
+ if a[0].class == Node::DASGN_CURR then
52
+ vardefs = a[0]
53
+ while vardefs.class == Node::DASGN_CURR do
54
+ vardefs = vardefs.value
55
+ end
56
+ if not vardefs then
57
+ # ignore variable definitions
58
+ a.shift
59
+ end
60
+ end
61
+ lines = a.map { |n| n.as_code(indent) }
62
+ lines.reject! { |e| e.nil? }
63
+ if lines.size == 0 then
64
+ "#{' '*indent}nil"
65
+ else
66
+ lines.join("\n")
67
+ end
68
+ end
69
+
70
+ define_code(:ITER) do |node, indent|
71
+ "#{' '*indent}#{node.iter.as_expression} {\n" +
72
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
73
+ "#{' '*indent}}"
74
+ end
75
+
76
+ define_code(:WHILE) do |node, indent|
77
+ if node.state == 1 then
78
+ "#{' '*indent}while #{node.cond.as_expression} do\n" +
79
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
80
+ "#{' '*indent}end"
81
+ else
82
+ "#{' '*indent}begin\n" +
83
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
84
+ "#{' '*indent}end while #{node.cond.as_expression}"
85
+ end
86
+ end
87
+
88
+ define_code(:UNTIL) do |node, indent|
89
+ if node.state == 1 then
90
+ "#{' '*indent}until #{node.cond.as_expression} do\n" +
91
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
92
+ "#{' '*indent}end"
93
+ else
94
+ "#{' '*indent}begin\n" +
95
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
96
+ "#{' '*indent}end until #{node.cond.as_expression}"
97
+ end
98
+ end
99
+
100
+ define_code(:BEGIN) do |node, indent|
101
+ if node.body.class == Node::RESCUE or
102
+ node.body.class == Node::ENSURE then
103
+ s = "#{' '*indent}begin\n" +
104
+ "#{node.body.as_code(indent+1, true)}\n" +
105
+ "#{' '*indent}end"
106
+ elsif node.body then
107
+ "#{' '*indent}begin\n" +
108
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
109
+ "#{' '*indent}end"
110
+ else
111
+ "#{' '*indent}begin\n" +
112
+ "#{' '*indent}end\n"
113
+ end
114
+ end
115
+
116
+ def self.begin_end(indent, have_begin)
117
+ s = ''
118
+ if not have_begin then
119
+ s << "#{' '*indent}begin\n"
120
+ indent += 1
121
+ end
122
+ yield s, indent, true
123
+ if not have_begin then
124
+ indent -= 1
125
+ s << "\n#{' '*indent}end"
126
+ end
127
+ return s
128
+ end
129
+
130
+ define_code(:ENSURE) do |node, indent, *args|
131
+ begin_ensure = args[0] || false
132
+ Node.begin_end(indent, begin_ensure) do |s, indent_, begin_ensure|
133
+ if node.head then
134
+ s << "#{node.head.as_code(indent_)}\n"
135
+ end
136
+ s << "#{' '*(indent_-1)}ensure\n"
137
+ s << "#{node.ensr.as_code(indent_)}"
138
+ end
139
+ end
140
+
141
+ define_code(:RESCUE) do |node, indent, *args|
142
+ begin_rescue = args[0] || false
143
+ Node.begin_end(indent, begin_rescue) do |s, indent_, begin_rescue|
144
+ if node.head then
145
+ if begin_rescue then
146
+ s << "#{node.head.as_code(indent_)}\n"
147
+ s << "#{' '*(indent_-1)}rescue #{node.resq.as_code(indent_+1, begin_rescue)}"
148
+ else
149
+ s << "#{node.head.as_expression} rescue #{node.resq.as_expression(begin_rescue)}"
150
+ end
151
+ else
152
+ s << "rescue #{node.resq.as_expression(begin_rescue)}"
153
+ end
154
+ end
155
+ end
156
+
157
+ define_code(:RESBODY) do |node, indent, *args|
158
+ begin_rescue = args[0] || false
159
+ if begin_rescue then
160
+ if node.args then
161
+ a = node.args.to_a.map { |n| n.as_expression }
162
+ "#{a.join(', ')}\n" +
163
+ "#{' '*indent}#{node.body.as_code(indent+1)}"
164
+ else
165
+ node.body ? "\n#{' '*indent}#{node.body.as_code(indent+1)}" : ''
166
+ end
167
+ else
168
+ # TODO: assuming node.args is false...
169
+ node.body ? node.body.as_code : ''
170
+ end
171
+ end
172
+
173
+ define_code(:NEWLINE) do |node, indent|
174
+ node.next.as_code(indent)
175
+ end
176
+
177
+ define_code(:CASE) do |node, indent|
178
+ "#{' '*indent}case #{node.head.as_expression}\n" +
179
+ "#{node.body.as_code(indent)}end"
180
+ end
181
+
182
+ define_code(:WHEN) do |node, indent|
183
+ args = node.head.to_a.map { |n| n.as_expression }
184
+ s = "#{' '*indent}when #{args.join(', ')}\n"
185
+ if node.body then
186
+ s << "#{' '*indent}#{node.body.as_code(indent+1)}; "
187
+ end
188
+ if node.next then
189
+ s << node.next.as_code
190
+ end
191
+ s
192
+ end
193
+
194
+ define_code(:CLASS) do |node, indent|
195
+ s_super = node.super ? " < #{node.super.as_expression}" : ''
196
+ if node.respond_to?(:cpath) then
197
+ path = node.cpath.as_expression
198
+ else
199
+ path = node.cname
200
+ end
201
+ "#{' '*indent}class #{path}#{s_super}\n" +
202
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
203
+ "#{' '*indent}end"
204
+ end
205
+
206
+ define_code(:SCLASS) do |node, indent|
207
+ "#{' '*indent}class << #{node.recv.as_expression}\n" +
208
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
209
+ "#{' '*indent}end"
210
+ end
211
+
212
+ define_code(:DEFN) do |node, indent|
213
+ # TODO: what to do about noex?
214
+ "#{' '*indent}def #{node.mid}\n" +
215
+ "#{' '*indent}#{node.next.as_code(indent+1)}\n" +
216
+ "#{' '*indent}end"
217
+ end
218
+
219
+ define_code(:DEFS) do |node, indent|
220
+ "#{' '*indent}def #{node.recv.as_expression}.#{node.mid}\n" +
221
+ "#{' '*indent}#{node.next.as_code(indent+1)}\n" +
222
+ "#{' '*indent}end"
223
+ end
224
+
225
+ define_code(:SCOPE) do |node, indent|
226
+ case node.next
227
+ when nil then ''
228
+ when Node::ARGS then "#{' '*indent}nil"
229
+ when Node::BLOCK_ARG then "#{' '*indent}nil"
230
+ else node.next.as_code(indent)
231
+ end
232
+ end
233
+ end