nodewrap 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. data/COPYING +59 -0
  2. data/LEGAL +6 -0
  3. data/LGPL +515 -0
  4. data/LICENSE +6 -0
  5. data/README +31 -0
  6. data/TODO +9 -0
  7. data/example/README +5 -0
  8. data/example/simple_client.rb +12 -0
  9. data/example/simple_server.rb +11 -0
  10. data/example/triangle_client.rb +7 -0
  11. data/example/triangle_server.rb +24 -0
  12. data/ext/MANIFEST +11 -0
  13. data/ext/builtins.h +25 -0
  14. data/ext/cached/ruby-1.6.3/COPYING +340 -0
  15. data/ext/cached/ruby-1.6.3/README +3 -0
  16. data/ext/cached/ruby-1.6.3/classpath.c +3 -0
  17. data/ext/cached/ruby-1.6.3/classpath.h +8 -0
  18. data/ext/cached/ruby-1.6.3/evalinfo.h +62 -0
  19. data/ext/cached/ruby-1.6.3/global_entry.h +15 -0
  20. data/ext/cached/ruby-1.6.3/insns_info.c +40 -0
  21. data/ext/cached/ruby-1.6.3/insns_info.h +19 -0
  22. data/ext/cached/ruby-1.6.3/node_type_descrip.c +150 -0
  23. data/ext/cached/ruby-1.6.3/nodeinfo.c +3182 -0
  24. data/ext/cached/ruby-1.6.3/nodeinfo.h +66 -0
  25. data/ext/cached/ruby-1.6.4/COPYING +340 -0
  26. data/ext/cached/ruby-1.6.4/README +3 -0
  27. data/ext/cached/ruby-1.6.4/classpath.c +3 -0
  28. data/ext/cached/ruby-1.6.4/classpath.h +8 -0
  29. data/ext/cached/ruby-1.6.4/evalinfo.h +62 -0
  30. data/ext/cached/ruby-1.6.4/global_entry.h +15 -0
  31. data/ext/cached/ruby-1.6.4/insns_info.c +40 -0
  32. data/ext/cached/ruby-1.6.4/insns_info.h +19 -0
  33. data/ext/cached/ruby-1.6.4/node_type_descrip.c +150 -0
  34. data/ext/cached/ruby-1.6.4/nodeinfo.c +3182 -0
  35. data/ext/cached/ruby-1.6.4/nodeinfo.h +66 -0
  36. data/ext/cached/ruby-1.6.5/COPYING +56 -0
  37. data/ext/cached/ruby-1.6.5/GPL +340 -0
  38. data/ext/cached/ruby-1.6.5/LEGAL +325 -0
  39. data/ext/cached/ruby-1.6.5/LGPL +504 -0
  40. data/ext/cached/ruby-1.6.5/README +3 -0
  41. data/ext/cached/ruby-1.6.5/classpath.c +3 -0
  42. data/ext/cached/ruby-1.6.5/classpath.h +8 -0
  43. data/ext/cached/ruby-1.6.5/evalinfo.h +63 -0
  44. data/ext/cached/ruby-1.6.5/global_entry.h +15 -0
  45. data/ext/cached/ruby-1.6.5/insns_info.c +40 -0
  46. data/ext/cached/ruby-1.6.5/insns_info.h +19 -0
  47. data/ext/cached/ruby-1.6.5/node_type_descrip.c +150 -0
  48. data/ext/cached/ruby-1.6.5/nodeinfo.c +3182 -0
  49. data/ext/cached/ruby-1.6.5/nodeinfo.h +66 -0
  50. data/ext/cached/ruby-1.6.7/COPYING +56 -0
  51. data/ext/cached/ruby-1.6.7/GPL +340 -0
  52. data/ext/cached/ruby-1.6.7/LEGAL +308 -0
  53. data/ext/cached/ruby-1.6.7/LGPL +504 -0
  54. data/ext/cached/ruby-1.6.7/README +3 -0
  55. data/ext/cached/ruby-1.6.7/classpath.c +3 -0
  56. data/ext/cached/ruby-1.6.7/classpath.h +8 -0
  57. data/ext/cached/ruby-1.6.7/evalinfo.h +63 -0
  58. data/ext/cached/ruby-1.6.7/global_entry.h +15 -0
  59. data/ext/cached/ruby-1.6.7/insns_info.c +40 -0
  60. data/ext/cached/ruby-1.6.7/insns_info.h +19 -0
  61. data/ext/cached/ruby-1.6.7/node_type_descrip.c +150 -0
  62. data/ext/cached/ruby-1.6.7/nodeinfo.c +3182 -0
  63. data/ext/cached/ruby-1.6.7/nodeinfo.h +66 -0
  64. data/ext/cached/ruby-1.6.8/COPYING +56 -0
  65. data/ext/cached/ruby-1.6.8/GPL +340 -0
  66. data/ext/cached/ruby-1.6.8/LEGAL +308 -0
  67. data/ext/cached/ruby-1.6.8/LGPL +504 -0
  68. data/ext/cached/ruby-1.6.8/README +3 -0
  69. data/ext/cached/ruby-1.6.8/classpath.c +3 -0
  70. data/ext/cached/ruby-1.6.8/classpath.h +8 -0
  71. data/ext/cached/ruby-1.6.8/evalinfo.h +63 -0
  72. data/ext/cached/ruby-1.6.8/global_entry.h +15 -0
  73. data/ext/cached/ruby-1.6.8/insns_info.c +40 -0
  74. data/ext/cached/ruby-1.6.8/insns_info.h +19 -0
  75. data/ext/cached/ruby-1.6.8/node_type_descrip.c +150 -0
  76. data/ext/cached/ruby-1.6.8/nodeinfo.c +3182 -0
  77. data/ext/cached/ruby-1.6.8/nodeinfo.h +66 -0
  78. data/ext/cached/ruby-1.8.0/COPYING +56 -0
  79. data/ext/cached/ruby-1.8.0/GPL +340 -0
  80. data/ext/cached/ruby-1.8.0/LEGAL +371 -0
  81. data/ext/cached/ruby-1.8.0/LGPL +504 -0
  82. data/ext/cached/ruby-1.8.0/README +3 -0
  83. data/ext/cached/ruby-1.8.0/classpath.c +27 -0
  84. data/ext/cached/ruby-1.8.0/classpath.h +14 -0
  85. data/ext/cached/ruby-1.8.0/evalinfo.h +65 -0
  86. data/ext/cached/ruby-1.8.0/global_entry.h +10 -0
  87. data/ext/cached/ruby-1.8.0/insns_info.c +40 -0
  88. data/ext/cached/ruby-1.8.0/insns_info.h +19 -0
  89. data/ext/cached/ruby-1.8.0/node_type_descrip.c +150 -0
  90. data/ext/cached/ruby-1.8.0/nodeinfo.c +3199 -0
  91. data/ext/cached/ruby-1.8.0/nodeinfo.h +66 -0
  92. data/ext/cached/ruby-1.8.1/COPYING +56 -0
  93. data/ext/cached/ruby-1.8.1/GPL +340 -0
  94. data/ext/cached/ruby-1.8.1/LEGAL +371 -0
  95. data/ext/cached/ruby-1.8.1/LGPL +504 -0
  96. data/ext/cached/ruby-1.8.1/README +3 -0
  97. data/ext/cached/ruby-1.8.1/classpath.c +27 -0
  98. data/ext/cached/ruby-1.8.1/classpath.h +14 -0
  99. data/ext/cached/ruby-1.8.1/evalinfo.h +59 -0
  100. data/ext/cached/ruby-1.8.1/global_entry.h +10 -0
  101. data/ext/cached/ruby-1.8.1/insns_info.c +40 -0
  102. data/ext/cached/ruby-1.8.1/insns_info.h +19 -0
  103. data/ext/cached/ruby-1.8.1/node_type_descrip.c +150 -0
  104. data/ext/cached/ruby-1.8.1/nodeinfo.c +3199 -0
  105. data/ext/cached/ruby-1.8.1/nodeinfo.h +66 -0
  106. data/ext/cached/ruby-1.8.2/COPYING +56 -0
  107. data/ext/cached/ruby-1.8.2/GPL +340 -0
  108. data/ext/cached/ruby-1.8.2/LEGAL +371 -0
  109. data/ext/cached/ruby-1.8.2/LGPL +504 -0
  110. data/ext/cached/ruby-1.8.2/README +3 -0
  111. data/ext/cached/ruby-1.8.2/classpath.c +45 -0
  112. data/ext/cached/ruby-1.8.2/classpath.h +17 -0
  113. data/ext/cached/ruby-1.8.2/evalinfo.h +60 -0
  114. data/ext/cached/ruby-1.8.2/global_entry.h +10 -0
  115. data/ext/cached/ruby-1.8.2/insns_info.c +40 -0
  116. data/ext/cached/ruby-1.8.2/insns_info.h +19 -0
  117. data/ext/cached/ruby-1.8.2/node_type_descrip.c +150 -0
  118. data/ext/cached/ruby-1.8.2/nodeinfo.c +3199 -0
  119. data/ext/cached/ruby-1.8.2/nodeinfo.h +66 -0
  120. data/ext/cached/ruby-1.8.3/COPYING +56 -0
  121. data/ext/cached/ruby-1.8.3/GPL +340 -0
  122. data/ext/cached/ruby-1.8.3/LEGAL +370 -0
  123. data/ext/cached/ruby-1.8.3/LGPL +504 -0
  124. data/ext/cached/ruby-1.8.3/README +3 -0
  125. data/ext/cached/ruby-1.8.3/classpath.c +45 -0
  126. data/ext/cached/ruby-1.8.3/classpath.h +17 -0
  127. data/ext/cached/ruby-1.8.3/evalinfo.h +61 -0
  128. data/ext/cached/ruby-1.8.3/global_entry.h +10 -0
  129. data/ext/cached/ruby-1.8.3/insns_info.c +40 -0
  130. data/ext/cached/ruby-1.8.3/insns_info.h +19 -0
  131. data/ext/cached/ruby-1.8.3/node_type_descrip.c +150 -0
  132. data/ext/cached/ruby-1.8.3/nodeinfo.c +3199 -0
  133. data/ext/cached/ruby-1.8.3/nodeinfo.h +66 -0
  134. data/ext/cached/ruby-1.8.4/COPYING +56 -0
  135. data/ext/cached/ruby-1.8.4/GPL +340 -0
  136. data/ext/cached/ruby-1.8.4/LEGAL +370 -0
  137. data/ext/cached/ruby-1.8.4/LGPL +504 -0
  138. data/ext/cached/ruby-1.8.4/README +3 -0
  139. data/ext/cached/ruby-1.8.4/classpath.c +45 -0
  140. data/ext/cached/ruby-1.8.4/classpath.h +17 -0
  141. data/ext/cached/ruby-1.8.4/evalinfo.h +61 -0
  142. data/ext/cached/ruby-1.8.4/global_entry.h +10 -0
  143. data/ext/cached/ruby-1.8.4/insns_info.c +40 -0
  144. data/ext/cached/ruby-1.8.4/insns_info.h +19 -0
  145. data/ext/cached/ruby-1.8.4/node_type_descrip.c +150 -0
  146. data/ext/cached/ruby-1.8.4/nodeinfo.c +3199 -0
  147. data/ext/cached/ruby-1.8.4/nodeinfo.h +66 -0
  148. data/ext/cached/ruby-1.8.5/COPYING +56 -0
  149. data/ext/cached/ruby-1.8.5/GPL +340 -0
  150. data/ext/cached/ruby-1.8.5/LEGAL +370 -0
  151. data/ext/cached/ruby-1.8.5/LGPL +504 -0
  152. data/ext/cached/ruby-1.8.5/README +3 -0
  153. data/ext/cached/ruby-1.8.5/classpath.c +45 -0
  154. data/ext/cached/ruby-1.8.5/classpath.h +17 -0
  155. data/ext/cached/ruby-1.8.5/evalinfo.h +61 -0
  156. data/ext/cached/ruby-1.8.5/global_entry.h +10 -0
  157. data/ext/cached/ruby-1.8.5/insns_info.c +40 -0
  158. data/ext/cached/ruby-1.8.5/insns_info.h +19 -0
  159. data/ext/cached/ruby-1.8.5/node_type_descrip.c +150 -0
  160. data/ext/cached/ruby-1.8.5/nodeinfo.c +3187 -0
  161. data/ext/cached/ruby-1.8.5/nodeinfo.h +64 -0
  162. data/ext/cached/ruby-1.8.6/COPYING +56 -0
  163. data/ext/cached/ruby-1.8.6/GPL +340 -0
  164. data/ext/cached/ruby-1.8.6/LEGAL +370 -0
  165. data/ext/cached/ruby-1.8.6/LGPL +504 -0
  166. data/ext/cached/ruby-1.8.6/README +3 -0
  167. data/ext/cached/ruby-1.8.6/classpath.c +45 -0
  168. data/ext/cached/ruby-1.8.6/classpath.h +17 -0
  169. data/ext/cached/ruby-1.8.6/evalinfo.h +61 -0
  170. data/ext/cached/ruby-1.8.6/global_entry.h +10 -0
  171. data/ext/cached/ruby-1.8.6/insns_info.c +40 -0
  172. data/ext/cached/ruby-1.8.6/insns_info.h +19 -0
  173. data/ext/cached/ruby-1.8.6/node_type_descrip.c +150 -0
  174. data/ext/cached/ruby-1.8.6/nodeinfo.c +3187 -0
  175. data/ext/cached/ruby-1.8.6/nodeinfo.h +64 -0
  176. data/ext/classpath.c +42 -0
  177. data/ext/classpath.c.rpp +28 -0
  178. data/ext/classpath.h +17 -0
  179. data/ext/classpath.h.rpp +35 -0
  180. data/ext/evalinfo.h +21 -0
  181. data/ext/evalinfo.h.rpp +49 -0
  182. data/ext/extconf.rb +68 -0
  183. data/ext/generate.rb +201 -0
  184. data/ext/generate_cached.rb +49 -0
  185. data/ext/global_entry.h +10 -0
  186. data/ext/global_entry.h.rpp +25 -0
  187. data/ext/insns_info.c +6079 -0
  188. data/ext/insns_info.c.rpp +210 -0
  189. data/ext/insns_info.h +819 -0
  190. data/ext/insns_info.h.rpp +50 -0
  191. data/ext/node_type_descrip.c +148 -0
  192. data/ext/node_type_descrip.c.rpp +72 -0
  193. data/ext/node_type_descrip.h +17 -0
  194. data/ext/node_type_descrip.rb +169 -0
  195. data/ext/nodeinfo.c +3164 -0
  196. data/ext/nodeinfo.c.rpp +519 -0
  197. data/ext/nodeinfo.h +67 -0
  198. data/ext/nodeinfo.h.rpp +27 -0
  199. data/ext/nodewrap.c +2576 -0
  200. data/ext/nodewrap.h +20 -0
  201. data/ext/read_node_h.rb +19 -0
  202. data/ext/ruby_source_dir.rb +15 -0
  203. data/ext/ruby_version.h +12 -0
  204. data/ext/ruby_version_code.rb +16 -0
  205. data/ext/rubypp.rb +97 -0
  206. data/ext/test.rb +15 -0
  207. data/generate_rdoc.rb +33 -0
  208. data/install.rb +1022 -0
  209. data/lib/as_code.rb +347 -0
  210. data/lib/as_expression.rb +657 -0
  211. data/lib/bytedecoder.rb +848 -0
  212. data/lib/classtree.rb +54 -0
  213. data/lib/methodsig.rb +266 -0
  214. data/lib/node_to_a.rb +34 -0
  215. data/lib/nodepp.rb +71 -0
  216. data/lib/nwdebug.rb +18 -0
  217. data/lib/nwdump.rb +53 -0
  218. data/lib/nwobfusc.rb +57 -0
  219. data/lib/procsig.rb +182 -0
  220. data/lib/test.rb +8 -0
  221. data/metaconfig +10 -0
  222. data/post-config.rb +53 -0
  223. data/post-setup.rb +9 -0
  224. data/pre-config.rb +1 -0
  225. data/run_tests.rb +48 -0
  226. data/test/expression_samples.rb +158 -0
  227. data/test/node_samples.rb +122 -0
  228. data/test/test.rb +39 -0
  229. data/test/test2.rb +7 -0
  230. data/test/test3.rb +5 -0
  231. data/test/test4.rb +5 -0
  232. data/test/test_as_code.rb +249 -0
  233. data/test/test_as_expression.rb +222 -0
  234. data/test/test_methodsig.rb +189 -0
  235. data/test/test_nodewrap.rb +369 -0
  236. metadata +286 -0
@@ -0,0 +1,347 @@
1
+ require 'nodewrap'
2
+ require 'rbconfig'
3
+ require 'as_expression'
4
+
5
+ if defined?(VM::InstructionSequence) then
6
+ require 'bytedecoder'
7
+
8
+ class VM
9
+ class InstructionSequence
10
+ def as_code(indent=0)
11
+ env = Nodewrap::ByteDecoder::Environment.new(local_table())
12
+ opt_pc = self.opt_pc
13
+ self.bytedecode(env, opt_pc)
14
+ expressions = env.expressions + env.stack
15
+ if expressions.length == 0 then
16
+ return nil
17
+ elsif expressions.length == 1 and
18
+ expressions[0].is_a?(Nodewrap::ByteDecoder::Expression::Literal) and
19
+ expressions[0].value == nil then
20
+ return nil
21
+ else
22
+ expressions.map! { |e| "#{' '*indent}#{e}" }
23
+ return expressions.join("\n")
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class Node
31
+ public
32
+
33
+ def as_code(indent=0, *args)
34
+ return as_code_impl(self, indent, *args)
35
+ end
36
+
37
+ private
38
+
39
+ def as_code_impl(node, indent, *args)
40
+ # default -- most code is just an expression
41
+ expression = node.as_expression(*args)
42
+ if not expression.nil? then
43
+ return "#{' '*indent}#{expression}"
44
+ else
45
+ return nil
46
+ end
47
+ end
48
+
49
+ class << self
50
+ def define_code(klass, &block)
51
+ if const_defined?(klass) then
52
+ const_get(klass).instance_eval { define_method(:as_code_impl, &block) }
53
+ end
54
+ end
55
+ end
56
+
57
+ define_code(:IF) do |node, indent|
58
+ if node.body.class == Node::BLOCK or
59
+ node.else.class == Node::BLOCK then
60
+ s = "#{' '*indent}if #{node.cond.as_expression} then\n"
61
+ s << "#{' '*indent}#{node.body.as_code(indent+1)}\n"
62
+ if node.else then
63
+ s << "#{' '*indent}else\n"
64
+ s << "#{' '*indent}#{node.else.as_code(indent+1)}\n"
65
+ end
66
+ s << "#{' '*indent}end"
67
+ s
68
+ else
69
+ "#{' '*indent}#{node.as_expression}"
70
+ end
71
+ end
72
+
73
+ define_code(:BLOCK) do |node, indent|
74
+ a = node.to_a
75
+ if a[0].class == Node::DASGN_CURR and not a[0].value
76
+ # ignore variable definitions
77
+ a.shift
78
+ end
79
+ lines = a.map { |n| n.as_code(indent) }
80
+ lines.reject! { |e| e.nil? }
81
+ if lines.size == 0 then
82
+ "#{' '*indent}nil"
83
+ else
84
+ lines.join("\n")
85
+ end
86
+ end
87
+
88
+ define_code(:ITER) do |node, indent|
89
+ "#{' '*indent}#{node.iter.as_expression} {\n" +
90
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
91
+ "#{' '*indent}}"
92
+ end
93
+
94
+ define_code(:WHILE) do |node, indent|
95
+ if node.state == 1 then
96
+ "#{' '*indent}while #{node.cond.as_expression} do\n" +
97
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
98
+ "#{' '*indent}end"
99
+ else
100
+ "#{' '*indent}begin\n" +
101
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
102
+ "#{' '*indent}end while #{node.cond.as_expression}"
103
+ end
104
+ end
105
+
106
+ define_code(:UNTIL) do |node, indent|
107
+ if node.state == 1 then
108
+ "#{' '*indent}until #{node.cond.as_expression} do\n" +
109
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
110
+ "#{' '*indent}end"
111
+ else
112
+ "#{' '*indent}begin\n" +
113
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
114
+ "#{' '*indent}end until #{node.cond.as_expression}"
115
+ end
116
+ end
117
+
118
+ define_code(:BEGIN) do |node, indent|
119
+ if node.body.class == Node::RESCUE or
120
+ node.body.class == Node::ENSURE then
121
+ s = "#{' '*indent}begin\n" +
122
+ "#{node.body.as_code(indent+1, true)}\n" +
123
+ "#{' '*indent}end"
124
+ elsif node.body then
125
+ "#{' '*indent}begin\n" +
126
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
127
+ "#{' '*indent}end"
128
+ else
129
+ "#{' '*indent}begin\n" +
130
+ "#{' '*indent}end\n"
131
+ end
132
+ end
133
+
134
+ def self.begin_end(indent, have_begin)
135
+ s = ''
136
+ if not have_begin then
137
+ s << "#{' '*indent}begin\n"
138
+ indent += 1
139
+ end
140
+ yield s, indent, true
141
+ if not have_begin then
142
+ indent -= 1
143
+ s << "\n#{' '*indent}end"
144
+ end
145
+ return s
146
+ end
147
+
148
+ define_code(:ENSURE) do |node, indent, *args|
149
+ begin_ensure = args[0] || false
150
+ s = ''
151
+ Node.begin_end(indent, begin_ensure) do |s, indent, begin_ensure|
152
+ if node.head then
153
+ s << "#{node.head.as_code(indent)}\n"
154
+ end
155
+ s << "#{' '*(indent-1)}ensure\n"
156
+ s << "#{node.ensr.as_code(indent)}"
157
+ end
158
+ end
159
+
160
+ define_code(:RESCUE) do |node, indent, *args|
161
+ begin_rescue = args[0] || false
162
+ Node.begin_end(indent, begin_rescue) do |s, indent, begin_rescue|
163
+ if node.head then
164
+ if begin_rescue then
165
+ s << "#{node.head.as_code(indent)}\n"
166
+ s << "#{' '*(indent-1)}rescue #{node.resq.as_code(indent+1, begin_rescue)}"
167
+ else
168
+ s << "#{node.head.as_expression} rescue #{node.resq.as_expression(begin_rescue)}"
169
+ end
170
+ else
171
+ s << "rescue #{node.resq.as_expression(begin_rescue)}"
172
+ end
173
+ end
174
+ end
175
+
176
+ define_code(:RESBODY) do |node, indent, *args|
177
+ begin_rescue = args[0] || false
178
+ if begin_rescue then
179
+ if node.ensr then
180
+ a = node.ensr.to_a.map { |n| n.as_expression }
181
+ "#{a.join(', ')}\n" +
182
+ "#{' '*indent}#{node.resq.as_code(indent+1)}"
183
+ else
184
+ node.resq ? "\n#{' '*indent}#{node.resq.as_code(indent+1)}" : ''
185
+ end
186
+ else
187
+ # TODO: assuming node.ensr is false...
188
+ node.resq ? node.resq.as_code : ''
189
+ end
190
+ end
191
+
192
+ define_code(:NEWLINE) do |node, indent|
193
+ node.next.as_code(indent)
194
+ end
195
+
196
+ define_code(:CASE) do |node, indent|
197
+ "#{' '*indent}case #{node.head.as_expression}\n" +
198
+ "#{node.body.as_code(indent)}end"
199
+ end
200
+
201
+ define_code(:WHEN) do |node, indent|
202
+ args = node.head.to_a.map { |n| n.as_expression }
203
+ s = "#{' '*indent}when #{args.join(', ')}\n"
204
+ if node.body then
205
+ s << "#{' '*indent}#{node.body.as_code(indent+1)}; "
206
+ end
207
+ if node.next then
208
+ s << node.next.as_code
209
+ end
210
+ s
211
+ end
212
+
213
+ define_code(:CLASS) do |node, indent|
214
+ s_super = node.super ? " < #{node.super.as_expression}" : ''
215
+ if node.respond_to?(:cpath) then
216
+ path = node.cpath.as_expression
217
+ else
218
+ path = node.cname
219
+ end
220
+ "#{' '*indent}class #{path}#{s_super}\n" +
221
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
222
+ "#{' '*indent}end"
223
+ end
224
+
225
+ define_code(:SCLASS) do |node, indent|
226
+ "#{' '*indent}class << #{node.recv.as_expression}\n" +
227
+ "#{' '*indent}#{node.body.as_code(indent+1)}\n" +
228
+ "#{' '*indent}end"
229
+ end
230
+
231
+ define_code(:DEFN) do |node, indent|
232
+ # TODO: what to do about noex?
233
+ "#{' '*indent}def #{node.mid}\n" +
234
+ "#{' '*indent}#{node.next.as_code(indent+1)}\n" +
235
+ "#{' '*indent}end"
236
+ end
237
+
238
+ define_code(:DEFS) do |node, indent|
239
+ "#{' '*indent}def #{node.recv.as_expression}.#{node.mid}\n" +
240
+ "#{' '*indent}#{node.next.as_code(indent+1)}\n" +
241
+ "#{' '*indent}end"
242
+ end
243
+
244
+ define_code(:SCOPE) do |node, indent|
245
+ case node.next
246
+ when nil then ''
247
+ when Node::ARGS then "#{' '*indent}nil"
248
+ when Node::BLOCK_ARG then "#{' '*indent}nil"
249
+ else node.next.as_code(indent)
250
+ end
251
+ end
252
+ end
253
+
254
+ module MethodAsCode
255
+ def as_code(indent=0, name=nil)
256
+ sig = self.signature
257
+ if self.body.respond_to?(:body) then
258
+ # YARV
259
+ body_expression = self.body.body.as_code(indent+1)
260
+ else
261
+ # pre-YARV
262
+ body_expression = self.body ? self.body.as_code(indent+1) : ''
263
+ end
264
+ name ||= sig.name
265
+ s = "#{' '*indent}def #{name}(#{sig.param_list})\n"
266
+ if body_expression then
267
+ s += "#{body_expression}\n"
268
+ end
269
+ s += "#{' '*indent}end"
270
+ return s
271
+ end
272
+ end
273
+
274
+ class Method
275
+ include MethodAsCode
276
+ end
277
+
278
+ class UnboundMethod
279
+ include MethodAsCode
280
+ end
281
+
282
+ class Proc
283
+ def as_code(indent=0)
284
+ sig = self.signature
285
+ body_expression = self.body ? self.body.as_code(indent+1) : nil
286
+ s = "#{' '*indent}proc do"
287
+ if not sig.args.unspecified then
288
+ s += " #{sig}"
289
+ end
290
+ s += "\n"
291
+ if body_expression then
292
+ s += "#{body_expression}\n"
293
+ end
294
+ s += "#{' '*indent}end"
295
+ return s
296
+ end
297
+ end
298
+
299
+ class Module
300
+ # TODO: it would be nice if we could go back and find the AST
301
+ # for the class instead of recreating the code from the class's
302
+ # current state.
303
+ def as_code(indent=0)
304
+ imethods = self.instance_methods - self.superclass.instance_methods
305
+ cmethods = self.instance_methods - self.superclass.instance_methods
306
+ constants = self.constants - self.superclass.constants
307
+ name = self.name.gsub(/.*::/, '')
308
+
309
+ # TODO: included modules?
310
+ if self.class == Class then
311
+ s = "#{' '*indent}class #{name} < #{self.superclass}\n"
312
+ else
313
+ s = "#{' '*indent}module #{name}\n"
314
+ end
315
+
316
+ constants.each do |constant|
317
+ s += "#{' '*indent} #{constant}=#{self.const_get(constant).as_code}\n"
318
+ end
319
+
320
+ # TODO: protected/private
321
+ imethods.each do |method|
322
+ s += self.instance_method(method).as_code(indent+1)
323
+ s += "\n"
324
+ end
325
+
326
+ cmethods.each do |method|
327
+ s += self.instance_method(method).as_code(indent+1, "self.#{method}")
328
+ s += "\n"
329
+ end
330
+
331
+ # TODO: singleton class constants
332
+ # TODO: class variables
333
+ # TODO: singleton instance variables
334
+
335
+ s += "#{' '*indent}end"
336
+
337
+ return s
338
+ end
339
+ end
340
+
341
+ class Object
342
+ def as_code(indent=0)
343
+ # TODO: this won't work for many objects
344
+ "#{' '*indent}#{self.inspect}"
345
+ end
346
+ end
347
+
@@ -0,0 +1,657 @@
1
+ require 'nodewrap'
2
+ require 'methodsig'
3
+ require 'procsig'
4
+ require 'node_to_a'
5
+ require 'rbconfig'
6
+
7
+ if defined?(VM::InstructionSequence) then
8
+ require 'bytedecoder'
9
+
10
+ class VM
11
+ class InstructionSequence
12
+ def as_expression
13
+ env = Nodewrap::ByteDecoder::Environment.new(local_table())
14
+ opt_pc = self.opt_pc
15
+ self.bytedecode(env, opt_pc)
16
+ expressions = env.expressions + env.stack
17
+ if expressions.length == 0 then
18
+ return nil
19
+ elsif expressions.length == 1 and
20
+ expressions[0].is_a?(Nodewrap::ByteDecoder::Expression::Literal) and
21
+ expressions[0].value == nil then
22
+ return nil
23
+ else
24
+ return expressions.join('; ')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ class Node
32
+ public
33
+
34
+ # Return an string describing this node as a single expression. By
35
+ # default, this just returns the name of the node's type, but some
36
+ # node types override this method to produce more meaningful output.
37
+ def as_expression(*args)
38
+ return as_expression_impl(self, *args)
39
+ end
40
+
41
+ # Return a string as with as_expression, but surround it with parens
42
+ # if it is a composite expression, so that it can be used to form more
43
+ # complex expressions.
44
+ def as_paren_expression(*args)
45
+ expr = self.as_expression(*args)
46
+ if not OMIT_PARENS[self.class] then
47
+ expr = "(#{expr})"
48
+ end
49
+ return expr
50
+ end
51
+
52
+ private
53
+
54
+ # default
55
+ def as_expression_impl(node)
56
+ return "<#{node.nd_type.to_s}>"
57
+ end
58
+
59
+ class << self
60
+ def define_expression(klass, &block)
61
+ if const_defined?(klass) then
62
+ const_get(klass).instance_eval { define_method(:as_expression_impl, &block) }
63
+ end
64
+ end
65
+ end
66
+
67
+ define_expression(:LIT) do |node|
68
+ # TODO: #inspect might not give an eval-able expression
69
+ node.lit.inspect
70
+ end
71
+
72
+ define_expression(:FCALL) do |node|
73
+ # args with either be an ARRAY or ARGSCAT
74
+ args = node.args
75
+ "#{node.mid}(#{args ? args.as_expression(false) : ''})"
76
+ end
77
+
78
+ define_expression(:VCALL) do |node|
79
+ node.mid.to_s
80
+ end
81
+
82
+ arithmetic_expressions = [
83
+ :+, :-, :*, :/, :<, :>, :<=, :>=, :==, :===, :<=>, :<<, :>>, :&, :|,
84
+ :^, :%, '!'.intern, '!='.intern
85
+ ]
86
+
87
+ # TODO: there should be a way to detect if the expressions need to be
88
+ # in parens
89
+ define_expression(:CALL) do |node|
90
+ recv_expr = node.recv.as_paren_expression
91
+
92
+ case node.mid
93
+ when *arithmetic_expressions
94
+ args = node.args
95
+ "#{recv_expr} #{node.mid} #{args ? args.as_paren_expression(false) : ''}"
96
+ when :[]
97
+ args = node.args
98
+ "#{recv_expr}[#{args ? args.as_expression(false) : ''}]"
99
+ else
100
+ args = node.args
101
+ "#{recv_expr}.#{node.mid}(#{args ? args.as_expression(false) : ''})"
102
+ end
103
+ end
104
+
105
+ define_expression(:ZSUPER) do |node|
106
+ "super"
107
+ end
108
+
109
+ define_expression(:SUPER) do |node|
110
+ "super(#{node.args ? node.args.as_expression(false) : ''})"
111
+ end
112
+
113
+ define_expression(:REDO) do |node|
114
+ "redo"
115
+ end
116
+
117
+ define_expression(:RETRY) do |node|
118
+ "retry"
119
+ end
120
+
121
+ define_expression(:NOT) do |node|
122
+ "not #{node.body.as_expression}"
123
+ end
124
+
125
+ define_expression(:AND) do |node|
126
+ "#{node.first.as_expression} and #{node.second.as_expression}"
127
+ end
128
+
129
+ define_expression(:OR) do |node|
130
+ "#{node.first.as_expression} or #{node.second.as_expression}"
131
+ end
132
+
133
+ class ARRAY < Node
134
+ def as_expression_impl(node, brackets = true)
135
+ s = brackets ? '[' : ''
136
+ s << (node.to_a.map { |n| n.as_expression }.join(', '))
137
+ s << (brackets ? ']' : '')
138
+ s
139
+ end
140
+ end
141
+
142
+ class ARGSCAT < Node
143
+ def as_expression_impl(node, brackets = true)
144
+ s = brackets ? '[' : ''
145
+ s << node.head.as_expression(false)
146
+ s << ", "
147
+ s << "*#{node.body.as_expression}"
148
+ s << (brackets ? ']' : '')
149
+ s
150
+ end
151
+ end
152
+
153
+ class ZARRAY < Node
154
+ def as_expression_impl(node, brackets = true)
155
+ brackets ? '[]' : ''
156
+ end
157
+ end
158
+
159
+ class BLOCK < Node
160
+ def as_expression_impl(node)
161
+ a = node.to_a
162
+ if a.size == 1 then
163
+ return 'nil'
164
+ end
165
+ d = a[0]
166
+ while d.class == Node::DASGN_CURR do
167
+ d = d.value
168
+ end
169
+ a.shift if not d
170
+ expressions = a.map { |n| n.as_expression }
171
+ expressions.reject! { |e| e.nil? }
172
+ if expressions.nitems == 0 then
173
+ return 'nil'
174
+ else
175
+ return expressions.join('; ')
176
+ end
177
+ end
178
+ end
179
+
180
+ define_expression(:HASH) do |node|
181
+ if not node.head then
182
+ "{}"
183
+ else
184
+ a = node.head.to_a
185
+ elems = []
186
+ i = 0
187
+ while i < a.size do
188
+ elems << "(#{a[i].as_expression})=>(#{a[i+1].as_expression})"
189
+ i += 2
190
+ end
191
+ "{#{elems.join(', ')}}"
192
+ end
193
+ end
194
+
195
+ define_expression(:IF) do |node|
196
+ if Node.const_defined?(:NEWLINE) then
197
+ bodynode = node.body.class == Node::NEWLINE ? node.body.next : node.body
198
+ elsenode = node.else.class == Node::NEWLINE ? node.else.next : node.else
199
+ else
200
+ bodynode = node.body
201
+ elsenode = node.else
202
+ end
203
+ if elsenode then
204
+ "#{node.cond.as_paren_expression} ? " +
205
+ "#{bodynode.as_paren_expression} : " +
206
+ "#{elsenode.as_paren_expression}"
207
+ else
208
+ "#{bodynode.as_paren_expression} if " +
209
+ "#{node.cond.as_paren_expression}"
210
+ end
211
+ end
212
+
213
+ define_expression(:TRUENODE) do |node|
214
+ "true"
215
+ end
216
+
217
+ define_expression(:FALSENODE) do |node|
218
+ "false"
219
+ end
220
+
221
+ define_expression(:NILNODE) do |node|
222
+ "nil"
223
+ end
224
+
225
+ define_expression(:SELF) do |node|
226
+ "self"
227
+ end
228
+
229
+ define_expression(:DOT2) do |node|
230
+ "#{node.beg.as_paren_expression}..#{node.end.as_paren_expression}"
231
+ end
232
+
233
+ define_expression(:DOT3) do |node|
234
+ "#{node.beg.as_paren_expression}...#{node.end.as_paren_expression}"
235
+ end
236
+
237
+ define_expression(:GVAR) do |node|
238
+ "#{node.vid}"
239
+ end
240
+
241
+ define_expression(:IVAR) do |node|
242
+ "#{node.vid}"
243
+ end
244
+
245
+ define_expression(:CVAR) do |node|
246
+ "#{node.vid}"
247
+ end
248
+
249
+ define_expression(:DVAR) do |node|
250
+ "#{node.vid}"
251
+ end
252
+
253
+ define_expression(:NTH_REF) do |node|
254
+ "$#{node.nth}"
255
+ end
256
+
257
+ define_expression(:BACK_REF) do |node|
258
+ "$`"
259
+ end
260
+
261
+ define_expression(:DASGN_CURR) do |node|
262
+ node.value ? "#{node.vid} = #{node.value.as_expression}" : ''
263
+ end
264
+
265
+ define_expression(:DASGN) do |node|
266
+ "#{node.vid} = #{node.value.as_expression}"
267
+ end
268
+
269
+ define_expression(:IASGN) do |node|
270
+ "#{node.vid} = #{node.value.as_expression}"
271
+ end
272
+
273
+ define_expression(:LASGN) do |node|
274
+ "#{node.vid} = #{node.value.as_expression}"
275
+ end
276
+
277
+ define_expression(:MASGN) do |node|
278
+ lhs = node.head.to_a.map { |n| n.as_expression }
279
+ rhs = node.value.to_a.map { |n| n.as_expression }
280
+ "#{lhs.join(', ')} = #{rhs.join(', ')}"
281
+ end
282
+
283
+ define_expression(:CDECL) do |node|
284
+ "#{node.vid} = #{node.value.as_expression}"
285
+ end
286
+
287
+ define_expression(:CVDECL) do |node|
288
+ "#{node.vid} = #{node.value.as_expression}"
289
+ end
290
+
291
+ define_expression(:CVASGN) do |node|
292
+ "#{node.vid} = #{node.value.as_expression}"
293
+ end
294
+
295
+ define_expression(:ATTRASGN) do |node|
296
+ case node.mid
297
+ when :[]=
298
+ args = node.args.to_a
299
+ attrs = args[1..-2].map { |n| n.as_expression }
300
+ value = args[-1].as_expression
301
+ "#{node.recv.as_paren_expression}[#{attrs.join(', ')}] = #{value}"
302
+ else
303
+ "#{node.recv.as_paren_expression}.#{node.mid}#{node.args.as_expression(false)}"
304
+ end
305
+ end
306
+
307
+ define_expression(:CONST) do |node|
308
+ "#{node.vid}"
309
+ end
310
+
311
+ define_expression(:COLON2) do |node|
312
+ if node.head then
313
+ "#{node.head.as_expression}::#{node.mid}"
314
+ else
315
+ node.mid.to_s
316
+ end
317
+ end
318
+
319
+ define_expression(:COLON3) do |node|
320
+ "::#{node.mid}"
321
+ end
322
+
323
+ define_expression(:LVAR) do |node|
324
+ "#{node.vid}"
325
+ end
326
+
327
+ define_expression(:NEWLINE) do |node|
328
+ node.next.as_expression
329
+ end
330
+
331
+ define_expression(:STR) do |node|
332
+ "\"#{node.lit.inspect[1..-2]}\""
333
+ end
334
+
335
+ define_expression(:REGX) do |node|
336
+ # TODO: cflag
337
+ "/#{node.lit.inspect[1..-2]}/"
338
+ end
339
+
340
+ define_expression(:REGX_ONCE) do |node|
341
+ # TODO: cflag
342
+ "/#{node.lit.inspect[1..-2]}/o"
343
+ end
344
+
345
+ define_expression(:XSTR) do |node|
346
+ "`#{node.lit.inspect[1..-2]}`"
347
+ end
348
+
349
+ define_expression(:DSTR) do |node|
350
+ a = node.next.to_a
351
+ s = "\"#{node.lit.inspect[1..-2]}"
352
+ a.each do |elem|
353
+ case elem
354
+ when Node::STR then s += elem.lit
355
+ else s += elem.as_expression
356
+ end
357
+ end
358
+ s += "\""
359
+ s
360
+ end
361
+
362
+ define_expression(:DREGX) do |node|
363
+ a = node.next.to_a
364
+ s = "/#{node.lit.inspect[1..-2]}"
365
+ a.each do |elem|
366
+ case elem
367
+ when Node::STR then s += elem.lit
368
+ else s += elem.as_expression
369
+ end
370
+ end
371
+ s += "/"
372
+ # TODO: cflag
373
+ s
374
+ end
375
+
376
+ define_expression(:DREGX_ONCE) do |node|
377
+ a = node.next.to_a
378
+ s = "/#{node.lit.inspect[1..-2]}"
379
+ a.each do |elem|
380
+ case elem
381
+ when Node::STR then s += elem.lit
382
+ else s += elem.as_expression
383
+ end
384
+ end
385
+ s += "/o"
386
+ # TODO: cflag
387
+ s
388
+ end
389
+
390
+ define_expression(:DXSTR) do |node|
391
+ a = node.next.to_a
392
+ s = "`#{node.lit.inspect[1..-2]}"
393
+ a.each do |elem|
394
+ case elem
395
+ when Node::STR then s += elem.lit
396
+ else s += elem.as_expression
397
+ end
398
+ end
399
+ s += "`"
400
+ s
401
+ end
402
+
403
+ major = Config::CONFIG['MAJOR'].to_i
404
+ minor = Config::CONFIG['MINOR'].to_i
405
+ teeny = Config::CONFIG['TEENY'].to_i
406
+ ruby_version_code = major * 100 + minor * 10 + teeny
407
+
408
+ if ruby_version_code >= 180 then
409
+
410
+ define_expression(:EVSTR) do |node|
411
+ "\#\{#{node.body.as_expression}\}"
412
+ end
413
+
414
+ else
415
+
416
+ define_expression(:EVSTR) do |node|
417
+ "\#\{#{node.lit}\}"
418
+ end
419
+
420
+ end
421
+
422
+ define_expression(:ITER) do |node|
423
+ "#{node.iter.as_expression} { #{node.body.as_expression} }"
424
+ end
425
+
426
+ define_expression(:WHILE) do |node|
427
+ if node.state == 1 then
428
+ "while #{node.cond.as_expression} do; #{node.body.as_expression}; end"
429
+ else
430
+ "begin; #{node.body.as_expression}; end while #{node.cond.as_expression}"
431
+ end
432
+ end
433
+
434
+ define_expression(:UNTIL) do |node|
435
+ if node.state == 1 then
436
+ "until #{node.cond.as_expression} do; #{node.body.as_expression}; end"
437
+ else
438
+ "begin; #{node.body.as_expression}; end until #{node.cond.as_expression}"
439
+ end
440
+ end
441
+
442
+ define_expression(:BREAK) do |node|
443
+ s = "break"
444
+ if node.stts then
445
+ s += " #{node.stts.as_expression}"
446
+ end
447
+ s
448
+ end
449
+
450
+ define_expression(:RETURN) do |node|
451
+ s = "return"
452
+ if node.stts then
453
+ s += " #{node.stts.as_expression}"
454
+ end
455
+ s
456
+ end
457
+
458
+ define_expression(:YIELD) do |node|
459
+ s = "yield"
460
+ if node.stts then
461
+ s += " #{node.stts.as_expression}"
462
+ end
463
+ s
464
+ end
465
+
466
+ define_expression(:BEGIN) do |node|
467
+ if node.body.class == Node::RESCUE or
468
+ node.body.class == Node::ENSURE then
469
+ "begin; #{node.body.as_expression(true)}; end"
470
+ elsif node.body then
471
+ "begin; #{node.body.as_expression}; end"
472
+ else
473
+ "begin; end"
474
+ end
475
+ end
476
+
477
+ define_expression(:ENSURE) do |node, *args|
478
+ begin_ensure = args[0] || false
479
+ if node.head then
480
+ if begin_ensure then
481
+ "#{node.head.as_expression} ensure #{node.ensr.as_expression}"
482
+ else
483
+ "begin; #{node.head.as_expression} ensure #{node.ensr.as_expression}; end"
484
+ end
485
+ else
486
+ if begin_ensure then
487
+ "ensure #{node.ensr.as_expression}"
488
+ else
489
+ "begin; ensure #{node.ensr.as_expression}; end"
490
+ end
491
+ end
492
+ end
493
+
494
+ define_expression(:RESCUE) do |node, *args|
495
+ begin_rescue = args[0] || false
496
+ if node.head then
497
+ if begin_rescue then
498
+ "#{node.head.as_expression}; rescue #{node.resq.as_expression(begin_rescue)}"
499
+ else
500
+ if not node.resq or not node.resq.resq then
501
+ "begin; #{node.head.as_expression}; rescue; end"
502
+ else
503
+ "#{node.head.as_paren_expression} rescue #{node.resq.as_expression(begin_rescue)}"
504
+ end
505
+ end
506
+ else
507
+ if not node.resq or not node.resq.resq then
508
+ "begin; rescue; end"
509
+ else
510
+ "rescue #{node.resq.as_expression(begin_rescue)}"
511
+ end
512
+ end
513
+ end
514
+
515
+ define_expression(:RESBODY) do |node, *args|
516
+ begin_rescue = args[0] || false
517
+ if begin_rescue then
518
+ if node.ensr then
519
+ a = node.ensr.to_a.map { |n| n.as_expression }
520
+ "#{a.join(', ')}; #{node.resq.as_expression}"
521
+ else
522
+ node.resq ? "; #{node.resq.as_expression}" : ''
523
+ end
524
+ else
525
+ # TODO: assuming node.ensr is false...
526
+ node.resq ? node.resq.as_expression : ''
527
+ end
528
+ end
529
+
530
+ define_expression(:CASE) do |node|
531
+ "case #{node.head.as_expression}; #{node.body.as_expression}end"
532
+ end
533
+
534
+ define_expression(:WHEN) do |node|
535
+ args = node.head.to_a.map { |n| n.as_expression }
536
+ s = ''
537
+ if node.body then
538
+ s = "when #{args.join(', ')} then #{node.body.as_expression}; "
539
+ else
540
+ s = "when #{args.join(', ')}; "
541
+ end
542
+ if node.next then
543
+ s += node.next.as_expression
544
+ end
545
+ s
546
+ end
547
+
548
+ define_expression(:ALIAS) do |node|
549
+ "alias #{node.new} #{node.old}"
550
+ end
551
+
552
+ define_expression(:VALIAS) do |node|
553
+ "alias #{node.new} #{node.old}"
554
+ end
555
+
556
+ define_expression(:UNDEF) do |node|
557
+ "alias #{node.mid}"
558
+ end
559
+
560
+ define_expression(:CLASS) do |node|
561
+ s_super = node.super ? " < #{node.super.as_expression}" : ''
562
+ if node.respond_to?(:cpath) then
563
+ path = node.cpath.as_expression
564
+ else
565
+ path = node.cname
566
+ end
567
+ "class #{path}#{s_super}; #{node.body.as_expression}; end"
568
+ end
569
+
570
+ define_expression(:SCLASS) do |node|
571
+ "class << #{node.recv.as_expression}; #{node.body.as_expression}; end"
572
+ end
573
+
574
+ define_expression(:SCOPE) do |node|
575
+ case node.next
576
+ when nil then ''
577
+ when Node::ARGS then 'nil'
578
+ when Node::BLOCK_ARG then 'nil'
579
+ else node.next.as_expression
580
+ end
581
+ end
582
+
583
+ define_expression(:DEFN) do |node|
584
+ # TODO: what to do about noex?
585
+ "def #{node.mid}; #{node.next.as_expression}; end"
586
+ end
587
+
588
+ define_expression(:DEFS) do |node|
589
+ "def #{node.recv.as_expression}.#{node.mid}; #{node.next.as_expression}; end"
590
+ end
591
+
592
+ define_expression(:DEFINED) do |node|
593
+ "defined?(#{node.head.as_expression})"
594
+ end
595
+
596
+ define_expression(:ARGS) do |node|
597
+ nil
598
+ end
599
+
600
+ define_expression(:BLOCK_ARG) do |node|
601
+ nil
602
+ end
603
+
604
+ # TODO: MATCH3
605
+
606
+ OMIT_PARENS = {
607
+ LVAR => true,
608
+ GVAR => true,
609
+ IVAR => true,
610
+ CVAR => true,
611
+ DVAR => true,
612
+ LIT => true,
613
+ ARRAY => true,
614
+ ZARRAY => true,
615
+ HASH => true,
616
+ }
617
+ end
618
+
619
+ module MethodAsExpression
620
+ # It doesn't entirely make sense to have Method#as_expression, because
621
+ # a method definition isn't an expression. We have one anyway, to be
622
+ # consistent with Proc.
623
+ def as_expression
624
+ sig = self.signature
625
+ if self.body.respond_to?(:body) then
626
+ # YARV
627
+ body_expression = self.body.body.as_expression
628
+ else
629
+ # pre-YARV
630
+ body_expression = self.body.as_expression
631
+ end
632
+ if body_expression then
633
+ return "def #{sig.name}(#{sig.param_list}); #{body_expression}; end"
634
+ else
635
+ return "def #{sig.name}(#{sig.param_list}); end"
636
+ end
637
+ end
638
+ end
639
+
640
+ class Method
641
+ include MethodAsExpression
642
+ end
643
+
644
+ class UnboundMethod
645
+ include MethodAsExpression
646
+ end
647
+
648
+ class Proc
649
+ def as_expression
650
+ sig = self.signature
651
+ body_expression = self.body ? self.body.as_expression : nil
652
+ s = sig.args.unspecified ? "" : sig.to_s + ' '
653
+ b = body_expression ? body_expression + ' ' : ''
654
+ return "proc { #{s}#{b}}"
655
+ end
656
+ end
657
+