nodewrap 0.5.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 (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
+